Exemplo n.º 1
0
static gboolean
ensure_sinkpad_allocator (GstVaapiPluginBase * plugin, GstCaps * caps,
    guint * size)
{
  GstVideoInfo vinfo;
  const GstVideoInfo *image_info;
  GstVaapiImageUsageFlags usage_flag =
      GST_VAAPI_IMAGE_USAGE_FLAG_NATIVE_FORMATS;

  if (!gst_video_info_from_caps (&vinfo, caps))
    goto error_invalid_caps;

  if (!reset_allocator (plugin->sinkpad_allocator, &vinfo))
    goto bail;

  if (has_dmabuf_capable_peer (plugin, plugin->sinkpad)) {
    plugin->sinkpad_allocator =
        gst_vaapi_dmabuf_allocator_new (plugin->display, &vinfo,
        GST_VAAPI_SURFACE_ALLOC_FLAG_LINEAR_STORAGE, GST_PAD_SINK);
    goto bail;
  }

  /* enable direct upload if upstream requests raw video */
  if (gst_caps_is_video_raw (caps)) {
    usage_flag = GST_VAAPI_IMAGE_USAGE_FLAG_DIRECT_UPLOAD;
    GST_INFO_OBJECT (plugin, "enabling direct upload in sink allocator");
  }
  plugin->sinkpad_allocator =
      gst_vaapi_video_allocator_new (plugin->display, &vinfo, 0, usage_flag);

bail:
  if (!plugin->sinkpad_allocator)
    goto error_create_allocator;

  image_info =
      gst_allocator_get_vaapi_video_info (plugin->sinkpad_allocator, NULL);
  g_assert (image_info);        /* allocator ought set its image info */

  /* update the size with the one generated by the allocator */
  *size = GST_VIDEO_INFO_SIZE (image_info);

  return TRUE;

  /* ERRORS */
error_invalid_caps:
  {
    GST_ERROR_OBJECT (plugin, "invalid caps %" GST_PTR_FORMAT, caps);
    return FALSE;
  }
error_create_allocator:
  {
    GST_ERROR_OBJECT (plugin, "failed to create sink pad's allocator");
    return FALSE;
  }
}
Exemplo n.º 2
0
static inline gboolean
reset_allocator (GstAllocator * allocator, GstVideoInfo * vinfo)
{
  const GstVideoInfo *orig_vi;

  if (!allocator)
    return TRUE;

  orig_vi = gst_allocator_get_vaapi_video_info (allocator, NULL);
  if (!gst_video_info_changed (orig_vi, vinfo))
    return FALSE;

  gst_object_unref (allocator);
  return TRUE;
}
Exemplo n.º 3
0
static gboolean
ensure_srcpad_allocator (GstVaapiPluginBase * plugin, GstVideoInfo * vinfo,
    GstCaps * caps)
{
  gboolean different_caps;
  GstVideoInfo vi;
  GstVaapiImageUsageFlags usage_flag =
      GST_VAAPI_IMAGE_USAGE_FLAG_NATIVE_FORMATS;

  /* the received caps are the "allocation caps" which may be
   * different from the "negotiation caps". In this case, we should
   * indicate the allocator to store the negotiation caps since they
   * are the one should be used for frame mapping with GstVideoMeta */
  different_caps = GST_IS_VIDEO_DECODER (plugin) && plugin->srcpad_caps &&
      !gst_caps_is_strictly_equal (plugin->srcpad_caps, caps);

  if (different_caps) {
    vi = plugin->srcpad_info;
  } else {
    vi = *vinfo;
  }

  if (!reset_allocator (plugin->srcpad_allocator, &vi))
    return TRUE;

  plugin->srcpad_allocator = NULL;
  if (caps && gst_caps_is_video_raw (caps)) {
    if (plugin->srcpad_can_dmabuf) {
      if (GST_IS_VIDEO_DECODER (plugin) || GST_IS_BASE_TRANSFORM (plugin)) {
        plugin->srcpad_allocator =
            gst_vaapi_dmabuf_allocator_new (plugin->display, vinfo,
            get_dmabuf_surface_allocation_flags (), GST_PAD_SRC);
      }
    } else if (plugin->enable_direct_rendering) {
      usage_flag = GST_VAAPI_IMAGE_USAGE_FLAG_DIRECT_RENDER;
      GST_INFO_OBJECT (plugin, "enabling direct rendering in source allocator");
    }
  }

  if (!plugin->srcpad_allocator) {
    plugin->srcpad_allocator =
        gst_vaapi_video_allocator_new (plugin->display, vinfo, 0, usage_flag);
  }

  if (!plugin->srcpad_allocator)
    goto error_create_allocator;

  if (different_caps) {
    guint i, flags = 0;
    const GstVideoInfo *alloc_vi =
        gst_allocator_get_vaapi_video_info (plugin->srcpad_allocator, &flags);
    /* update the planes and the size with the allocator image info,
     * but not the resolution */
    if (alloc_vi) {
      for (i = 0; i < GST_VIDEO_INFO_N_PLANES (alloc_vi); i++) {
        GST_VIDEO_INFO_PLANE_OFFSET (&vi, i) =
            GST_VIDEO_INFO_PLANE_OFFSET (alloc_vi, i);
        GST_VIDEO_INFO_PLANE_STRIDE (&vi, i) =
            GST_VIDEO_INFO_PLANE_STRIDE (alloc_vi, i);
      }
      GST_VIDEO_INFO_SIZE (&vi) = GST_VIDEO_INFO_SIZE (alloc_vi);
      gst_allocator_set_vaapi_video_info (plugin->srcpad_allocator, &vi, flags);
    }
  }

  return TRUE;

  /* ERRORS */
error_create_allocator:
  {
    GST_ERROR_OBJECT (plugin, "failed to create src pad's allocator");
    return FALSE;
  }
}
static gboolean
gst_vaapi_video_buffer_pool_set_config (GstBufferPool * pool,
    GstStructure * config)
{
  GstVaapiVideoBufferPoolPrivate *const priv =
      GST_VAAPI_VIDEO_BUFFER_POOL (pool)->priv;
  GstCaps *caps;
  GstVideoInfo new_allocation_vinfo;
  const GstVideoInfo *allocator_vinfo;
  const GstVideoInfo *negotiated_vinfo;
  GstVideoAlignment align;
  GstAllocator *allocator;
  gboolean ret, updated = FALSE;
  guint size, min_buffers, max_buffers;
  guint surface_alloc_flags;

  GST_DEBUG_OBJECT (pool, "config %" GST_PTR_FORMAT, config);

  caps = NULL;
  if (!gst_buffer_pool_config_get_params (config, &caps, &size, &min_buffers,
          &max_buffers))
    goto error_invalid_config;
  if (!caps)
    goto error_no_caps;
  if (!gst_video_info_from_caps (&new_allocation_vinfo, caps))
    goto error_invalid_caps;

  allocator = NULL;
  if (!gst_buffer_pool_config_get_allocator (config, &allocator, NULL))
    goto error_invalid_allocator;

  /* it is a valid allocator? */
  if (allocator
      && (g_strcmp0 (allocator->mem_type, GST_VAAPI_VIDEO_MEMORY_NAME) != 0
          && g_strcmp0 (allocator->mem_type,
              GST_VAAPI_DMABUF_ALLOCATOR_NAME) != 0))
    allocator = NULL;

  /* get the allocator properties */
  if (allocator) {
    priv->use_dmabuf_memory = gst_vaapi_is_dmabuf_allocator (allocator);
    negotiated_vinfo =
        gst_allocator_get_vaapi_negotiated_video_info (allocator);
    allocator_vinfo =
        gst_allocator_get_vaapi_video_info (allocator, &surface_alloc_flags);
  } else {
    priv->use_dmabuf_memory = FALSE;
    negotiated_vinfo = NULL;
    allocator_vinfo = NULL;
    surface_alloc_flags = 0;
  }

  /* reset or update the allocator if video resolution changed */
  if (allocator_vinfo
      && gst_video_info_changed (allocator_vinfo, &new_allocation_vinfo)) {
    gst_object_replace ((GstObject **) & priv->allocator, NULL);

    if (allocator && priv->use_dmabuf_memory) {
      gst_allocator_set_vaapi_video_info (allocator, &new_allocation_vinfo,
          surface_alloc_flags);
    } else {
      allocator = NULL;
    }
  }

  if (!gst_buffer_pool_config_has_option (config,
          GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META))
    goto error_no_vaapi_video_meta_option;

  /* create a new allocator if needed */
  if (!allocator) {
    if (priv->use_dmabuf_memory) {
      allocator = gst_vaapi_dmabuf_allocator_new (priv->display,
          &new_allocation_vinfo, /* FIXME: */ 0, GST_PAD_SRC);
    } else {
      allocator = gst_vaapi_video_allocator_new (priv->display,
          &new_allocation_vinfo, surface_alloc_flags, 0);
    }

    if (!allocator)
      goto error_no_allocator;

    if (negotiated_vinfo) {
      gst_allocator_set_vaapi_negotiated_video_info (allocator,
          negotiated_vinfo);
    }

    GST_INFO_OBJECT (pool, "created new allocator %" GST_PTR_FORMAT, allocator);
    gst_buffer_pool_config_set_allocator (config, allocator, NULL);
    gst_object_unref (allocator);
  }

  /* use the allocator and set the video info for the vmeta */
  if (allocator) {
    if (priv->allocator)
      gst_object_unref (priv->allocator);
    if ((priv->allocator = allocator))
      gst_object_ref (allocator);

    negotiated_vinfo =
        gst_allocator_get_vaapi_negotiated_video_info (priv->allocator);
    allocator_vinfo = gst_allocator_get_vaapi_video_info (allocator, NULL);
    priv->vmeta_vinfo = (negotiated_vinfo) ?
        *negotiated_vinfo : *allocator_vinfo;

    /* last resource to set the correct buffer size */
    if (GST_VIDEO_INFO_SIZE (allocator_vinfo) != size) {
      gst_buffer_pool_config_set_params (config, caps,
          GST_VIDEO_INFO_SIZE (allocator_vinfo), min_buffers, max_buffers);
    }
  }
  if (!priv->allocator)
    goto error_no_allocator;

  priv->options = 0;
  if (gst_buffer_pool_config_has_option (config,
          GST_BUFFER_POOL_OPTION_VIDEO_META)) {
    priv->options |= GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_META;
  } else {
    gint i;
    for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&new_allocation_vinfo); i++) {
      if (GST_VIDEO_INFO_PLANE_OFFSET (&new_allocation_vinfo, i) !=
          GST_VIDEO_INFO_PLANE_OFFSET (&priv->vmeta_vinfo, i) ||
          GST_VIDEO_INFO_PLANE_STRIDE (&new_allocation_vinfo, i) !=
          GST_VIDEO_INFO_PLANE_STRIDE (&priv->vmeta_vinfo, i)) {
        priv->options |= GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_META;
        gst_buffer_pool_config_add_option (config,
            GST_BUFFER_POOL_OPTION_VIDEO_META);
        updated = TRUE;
        break;
      }
    }
  }

  if (gst_buffer_pool_config_has_option (config,
          GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT)) {
    fill_video_alignment (GST_VAAPI_VIDEO_BUFFER_POOL (pool), &align);
    gst_buffer_pool_config_set_video_alignment (config, &align);
  }

  if (!priv->use_dmabuf_memory && gst_buffer_pool_config_has_option (config,
          GST_BUFFER_POOL_OPTION_VIDEO_GL_TEXTURE_UPLOAD_META))
    priv->options |= GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_GL_TEXTURE_UPLOAD;

  ret =
      GST_BUFFER_POOL_CLASS
      (gst_vaapi_video_buffer_pool_parent_class)->set_config (pool, config);
  return !updated && ret;

  /* ERRORS */
error_invalid_config:
  {
    GST_ERROR_OBJECT (pool, "invalid config");
    return FALSE;
  }
error_no_caps:
  {
    GST_ERROR_OBJECT (pool, "no caps in config");
    return FALSE;
  }
error_invalid_caps:
  {
    GST_ERROR_OBJECT (pool, "invalid caps %" GST_PTR_FORMAT, caps);
    return FALSE;
  }
error_invalid_allocator:
  {
    GST_ERROR_OBJECT (pool, "no allocator in config");
    return FALSE;
  }
error_no_vaapi_video_meta_option:
  {
    GST_ERROR_OBJECT (pool, "no GstVaapiVideoMeta option in config");
    return FALSE;
  }
error_no_allocator:
  {
    GST_ERROR_OBJECT (pool, "no allocator defined");
    return FALSE;
  }
}
GstMemory *
gst_vaapi_dmabuf_memory_new (GstAllocator * allocator, GstVaapiVideoMeta * meta)
{
  GstMemory *mem;
  GstVaapiDisplay *display;
  GstVaapiSurface *surface;
  GstVaapiSurfaceProxy *proxy;
  GstVaapiBufferProxy *dmabuf_proxy;
  gint dmabuf_fd;
  const GstVideoInfo *vip;
  guint flags;

  g_return_val_if_fail (allocator != NULL, NULL);
  g_return_val_if_fail (meta != NULL, NULL);

  vip = gst_allocator_get_vaapi_video_info (allocator, &flags);
  if (!vip)
    return NULL;

  display = gst_vaapi_video_meta_get_display (meta);
  if (!meta)
    return NULL;

  surface = gst_vaapi_surface_new_full (display, vip, flags);
  if (!surface)
    goto error_create_surface;

  proxy = gst_vaapi_surface_proxy_new (surface);
  if (!proxy)
    goto error_create_surface_proxy;

  dmabuf_proxy = gst_vaapi_surface_get_dma_buf_handle (surface);
  gst_vaapi_object_unref (surface);
  if (!dmabuf_proxy)
    goto error_create_dmabuf_proxy;

  gst_vaapi_video_meta_set_surface_proxy (meta, proxy);
  gst_vaapi_surface_proxy_unref (proxy);

  dmabuf_fd = gst_vaapi_buffer_proxy_get_handle (dmabuf_proxy);
  if (dmabuf_fd < 0 || (dmabuf_fd = dup (dmabuf_fd)) < 0)
    goto error_create_dmabuf_handle;

  mem = gst_dmabuf_allocator_alloc (allocator, dmabuf_fd,
      gst_vaapi_buffer_proxy_get_size (dmabuf_proxy));
  if (!mem)
    goto error_create_dmabuf_memory;

  gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (mem),
      GST_VAAPI_BUFFER_PROXY_QUARK, dmabuf_proxy,
      (GDestroyNotify) gst_vaapi_buffer_proxy_unref);
  return mem;

  /* ERRORS */
error_create_surface:
  {
    GST_ERROR ("failed to create VA surface (format:%s size:%ux%u)",
        gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (vip)),
        GST_VIDEO_INFO_WIDTH (vip), GST_VIDEO_INFO_HEIGHT (vip));
    return NULL;
  }
error_create_surface_proxy:
  {
    GST_ERROR ("failed to create VA surface proxy");
    gst_vaapi_object_unref (surface);
    return NULL;
  }
error_create_dmabuf_proxy:
  {
    GST_ERROR ("failed to export VA surface to DMABUF");
    gst_vaapi_surface_proxy_unref (proxy);
    return NULL;
  }
error_create_dmabuf_handle:
  {
    GST_ERROR ("failed to duplicate DMABUF handle");
    gst_vaapi_buffer_proxy_unref (dmabuf_proxy);
    return NULL;
  }
error_create_dmabuf_memory:
  {
    GST_ERROR ("failed to create DMABUF memory");
    gst_vaapi_buffer_proxy_unref (dmabuf_proxy);
    return NULL;
  }
}
Exemplo n.º 6
0
static gboolean
ensure_srcpad_allocator (GstVaapiPluginBase * plugin, GstVideoInfo * vinfo,
    GstCaps * caps)
{
  gboolean different_caps;
  const GstVideoInfo *image_info;
  GstVaapiImageUsageFlags usage_flag =
      GST_VAAPI_IMAGE_USAGE_FLAG_NATIVE_FORMATS;

  if (!reset_allocator (plugin->srcpad_allocator, vinfo))
    goto valid_allocator;

  plugin->srcpad_allocator = NULL;
  if (caps && gst_caps_is_video_raw (caps)) {
    GstAllocator *allocator = create_dmabuf_srcpad_allocator (plugin, vinfo,
        !plugin->srcpad_can_dmabuf);
    if (!allocator && plugin->enable_direct_rendering) {
      usage_flag = GST_VAAPI_IMAGE_USAGE_FLAG_DIRECT_RENDER;
      GST_INFO_OBJECT (plugin, "enabling direct rendering in source allocator");
    }
    plugin->srcpad_allocator = allocator;
  } else if (caps && gst_vaapi_caps_feature_contains (caps,
          GST_VAAPI_CAPS_FEATURE_DMABUF)) {
    plugin->srcpad_allocator =
        create_dmabuf_srcpad_allocator (plugin, vinfo, FALSE);
    if (!plugin->srcpad_allocator)
      goto error_create_allocator;
  }

  if (!plugin->srcpad_allocator) {
    plugin->srcpad_allocator =
        gst_vaapi_video_allocator_new (plugin->display, vinfo, 0, usage_flag);
  }

  if (!plugin->srcpad_allocator)
    goto error_create_allocator;

valid_allocator:
  image_info =
      gst_allocator_get_vaapi_video_info (plugin->srcpad_allocator, NULL);
  g_assert (image_info);        /* both allocators ought set its image
                                 * info */

  /* update the size with the one generated by the allocator */
  GST_VIDEO_INFO_SIZE (vinfo) = GST_VIDEO_INFO_SIZE (image_info);

  /* the received caps are the "allocation caps" which may be
   * different from the "negotiation caps". In this case, we should
   * indicate the allocator to store the negotiation caps since they
   * are the one should be used for frame mapping with GstVideoMeta */
  different_caps = GST_IS_VIDEO_DECODER (plugin) && plugin->srcpad_caps &&
      !gst_caps_is_strictly_equal (plugin->srcpad_caps, caps);

  if (different_caps) {
    guint i;
    GstVideoInfo vi = plugin->srcpad_info;

    /* update the planes and the size with the allocator image/surface
     * info, but not the resolution */
    for (i = 0; i < GST_VIDEO_INFO_N_PLANES (image_info); i++) {
      GST_VIDEO_INFO_PLANE_OFFSET (&vi, i) =
          GST_VIDEO_INFO_PLANE_OFFSET (image_info, i);
      GST_VIDEO_INFO_PLANE_STRIDE (&vi, i) =
          GST_VIDEO_INFO_PLANE_STRIDE (image_info, i);
    }
    GST_VIDEO_INFO_SIZE (&vi) = GST_VIDEO_INFO_SIZE (image_info);
    gst_allocator_set_vaapi_negotiated_video_info (plugin->srcpad_allocator,
        &vi);
  }

  return TRUE;

  /* ERRORS */
error_create_allocator:
  {
    GST_ERROR_OBJECT (plugin, "failed to create src pad's allocator");
    return FALSE;
  }
}
static gboolean
gst_vaapi_video_buffer_pool_set_config (GstBufferPool * pool,
    GstStructure * config)
{
  GstVaapiVideoBufferPoolPrivate *const priv =
      GST_VAAPI_VIDEO_BUFFER_POOL (pool)->priv;
  GstCaps *caps = NULL;
  GstVideoInfo *const cur_vip = &priv->video_info[priv->video_info_index];
  GstVideoInfo *const new_vip = &priv->video_info[!priv->video_info_index];
  GstVideoAlignment align;
  GstAllocator *allocator;
  gboolean changed_caps, use_dmabuf_memory, ret, updated = FALSE;

  if (!gst_buffer_pool_config_get_params (config, &caps, NULL, NULL, NULL))
    goto error_invalid_config;
  if (!caps || !gst_video_info_from_caps (new_vip, caps))
    goto error_no_caps;

  use_dmabuf_memory = gst_buffer_pool_config_has_option (config,
      GST_BUFFER_POOL_OPTION_DMABUF_MEMORY);
  if (priv->use_dmabuf_memory != use_dmabuf_memory) {
    priv->use_dmabuf_memory = use_dmabuf_memory;
    g_clear_object (&priv->allocator);
  }

  changed_caps = !priv->allocator ||
      GST_VIDEO_INFO_FORMAT (cur_vip) != GST_VIDEO_INFO_FORMAT (new_vip) ||
      GST_VIDEO_INFO_WIDTH (cur_vip) != GST_VIDEO_INFO_WIDTH (new_vip) ||
      GST_VIDEO_INFO_HEIGHT (cur_vip) != GST_VIDEO_INFO_HEIGHT (new_vip);

  if (changed_caps) {
    const GstVideoInfo *alloc_vip;
    guint flags = 0;

    if (use_dmabuf_memory) {
      /* XXX: also needs fixed strides/offsets */
      flags |= GST_VAAPI_SURFACE_ALLOC_FLAG_LINEAR_STORAGE;
      allocator =
          gst_vaapi_dmabuf_allocator_new (priv->display, new_vip, flags);
    } else {
      allocator = gst_vaapi_video_allocator_new (priv->display, new_vip, 0);
    }
    if (!allocator)
      goto error_create_allocator;
    gst_object_replace ((GstObject **) & priv->allocator,
        GST_OBJECT_CAST (allocator));
    gst_object_unref (allocator);
    priv->video_info_index ^= 1;

    alloc_vip = gst_allocator_get_vaapi_video_info (allocator, NULL);
    if (!alloc_vip)
      goto error_create_allocator_info;
    priv->alloc_info = *alloc_vip;
  }

  if (!gst_buffer_pool_config_has_option (config,
          GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META))
    goto error_no_vaapi_video_meta_option;

  priv->has_video_meta = gst_buffer_pool_config_has_option (config,
      GST_BUFFER_POOL_OPTION_VIDEO_META);
  if (!priv->has_video_meta) {
    gint i;
    for (i = 0; i < GST_VIDEO_INFO_N_PLANES (new_vip); i++) {
      if (GST_VIDEO_INFO_PLANE_OFFSET (new_vip, i) !=
          GST_VIDEO_INFO_PLANE_OFFSET (&priv->alloc_info, i) ||
          GST_VIDEO_INFO_PLANE_STRIDE (new_vip, i) !=
          GST_VIDEO_INFO_PLANE_STRIDE (&priv->alloc_info, i)) {
        priv->has_video_meta = TRUE;
        gst_buffer_pool_config_add_option (config,
            GST_BUFFER_POOL_OPTION_VIDEO_META);
        updated = TRUE;
        break;
      }
    }
  }

  priv->has_video_alignment = gst_buffer_pool_config_has_option (config,
      GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT);
  if (priv->has_video_alignment) {
    fill_video_alignment (GST_VAAPI_VIDEO_BUFFER_POOL (pool), &align);
    gst_buffer_pool_config_set_video_alignment (config, &align);
  }

  priv->has_texture_upload_meta = gst_buffer_pool_config_has_option (config,
      GST_BUFFER_POOL_OPTION_VIDEO_GL_TEXTURE_UPLOAD_META);

  ret =
      GST_BUFFER_POOL_CLASS
      (gst_vaapi_video_buffer_pool_parent_class)->set_config (pool, config);
  return !updated && ret;

  /* ERRORS */
error_invalid_config:
  {
    GST_ERROR ("invalid config");
    return FALSE;
  }
error_no_caps:
  {
    GST_ERROR ("no valid caps in config");
    return FALSE;
  }
error_create_allocator:
  {
    GST_ERROR ("failed to create GstVaapiVideoAllocator object");
    return FALSE;
  }
error_create_allocator_info:
  {
    GST_ERROR ("failed to create GstVaapiVideoAllocator `video-info'");
    return FALSE;
  }
error_no_vaapi_video_meta_option:
  {
    GST_ERROR ("no GstVaapiVideoMeta option");
    return FALSE;
  }
}