gboolean
_gst_vaapi_surface_deassociate_subpicture (GstVaapiSurface * surface,
    GstVaapiSubpicture * subpicture)
{
  GstVaapiDisplay *display;
  VASurfaceID surface_id;
  VAStatus status;

  display = GST_VAAPI_OBJECT_DISPLAY (surface);
  if (!display)
    return FALSE;

  surface_id = GST_VAAPI_OBJECT_ID (surface);
  if (surface_id == VA_INVALID_SURFACE)
    return FALSE;

  GST_VAAPI_DISPLAY_LOCK (display);
  status = vaDeassociateSubpicture (GST_VAAPI_DISPLAY_VADISPLAY (display),
      GST_VAAPI_OBJECT_ID (subpicture), &surface_id, 1);
  GST_VAAPI_DISPLAY_UNLOCK (display);
  if (!vaapi_check_status (status, "vaDeassociateSubpicture()"))
    return FALSE;

  return TRUE;
}
static gboolean
gst_vaapi_surface_create (GstVaapiSurface * surface,
    GstVaapiChromaType chroma_type, guint width, guint height)
{
  GstVaapiDisplay *const display = GST_VAAPI_OBJECT_DISPLAY (surface);
  VASurfaceID surface_id;
  VAStatus status;
  guint va_chroma_format;

  va_chroma_format = from_GstVaapiChromaType (chroma_type);
  if (!va_chroma_format)
    goto error_unsupported_chroma_type;

  GST_VAAPI_DISPLAY_LOCK (display);
  status = vaCreateSurfaces (GST_VAAPI_DISPLAY_VADISPLAY (display),
      width, height, va_chroma_format, 1, &surface_id);
  GST_VAAPI_DISPLAY_UNLOCK (display);
  if (!vaapi_check_status (status, "vaCreateSurfaces()"))
    return FALSE;

  surface->format = GST_VIDEO_FORMAT_UNKNOWN;
  surface->chroma_type = chroma_type;
  surface->width = width;
  surface->height = height;

  GST_DEBUG ("surface %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS (surface_id));
  GST_VAAPI_OBJECT_ID (surface) = surface_id;
  return TRUE;

  /* ERRORS */
error_unsupported_chroma_type:
  GST_ERROR ("unsupported chroma-type %u", chroma_type);
  return FALSE;
}
static void
gst_vaapi_subpicture_destroy (GstVaapiSubpicture * subpicture)
{
  GstVaapiDisplay *const display = GST_VAAPI_OBJECT_DISPLAY (subpicture);
  VASubpictureID subpicture_id;
  VAStatus status;

  subpicture_id = GST_VAAPI_OBJECT_ID (subpicture);
  GST_DEBUG ("subpicture %" GST_VAAPI_ID_FORMAT,
      GST_VAAPI_ID_ARGS (subpicture_id));

  if (subpicture_id != VA_INVALID_ID) {
    if (display) {
      GST_VAAPI_DISPLAY_LOCK (display);
      status = vaDestroySubpicture (GST_VAAPI_DISPLAY_VADISPLAY (display),
          subpicture_id);
      GST_VAAPI_DISPLAY_UNLOCK (display);
      if (!vaapi_check_status (status, "vaDestroySubpicture()"))
        g_warning ("failed to destroy subpicture %" GST_VAAPI_ID_FORMAT,
            GST_VAAPI_ID_ARGS (subpicture_id));
    }
    GST_VAAPI_OBJECT_ID (subpicture) = VA_INVALID_ID;
  }
  gst_vaapi_object_replace (&subpicture->image, NULL);
}
/**
 * gst_vaapi_surface_derive_image:
 * @surface: a #GstVaapiSurface
 *
 * Derives a #GstVaapiImage from the @surface. This image buffer can
 * then be mapped/unmapped for direct CPU access. This operation is
 * only possible if the underlying implementation supports direct
 * rendering capabilities and internal surface formats that can be
 * represented with a #GstVaapiImage.
 *
 * When the operation is not possible, the function returns %NULL and
 * the user should then fallback to using gst_vaapi_surface_get_image()
 * or gst_vaapi_surface_put_image() to accomplish the same task in an
 * indirect manner (additional copy).
 *
 * An image created with gst_vaapi_surface_derive_image() should be
 * unreferenced when it's no longer needed. The image and image buffer
 * data structures will be destroyed. However, the surface contents
 * will remain unchanged until destroyed through the last call to
 * gst_vaapi_object_unref().
 *
 * Return value: the newly allocated #GstVaapiImage object, or %NULL
 *   on failure
 */
GstVaapiImage *
gst_vaapi_surface_derive_image (GstVaapiSurface * surface)
{
  GstVaapiDisplay *display;
  VAImage va_image;
  VAStatus status;
  GstVaapiImage *image;

  g_return_val_if_fail (surface != NULL, NULL);

  display = GST_VAAPI_OBJECT_DISPLAY (surface);
  va_image.image_id = VA_INVALID_ID;
  va_image.buf = VA_INVALID_ID;

  GST_VAAPI_DISPLAY_LOCK (display);
  status = vaDeriveImage (GST_VAAPI_DISPLAY_VADISPLAY (display),
      GST_VAAPI_OBJECT_ID (surface), &va_image);
  GST_VAAPI_DISPLAY_UNLOCK (display);
  if (!vaapi_check_status (status, "vaDeriveImage()"))
    return NULL;
  if (va_image.image_id == VA_INVALID_ID || va_image.buf == VA_INVALID_ID)
    return NULL;

  image = gst_vaapi_image_new_with_image (display, &va_image);
  if (!image)
    vaDestroyImage (GST_VAAPI_DISPLAY_VADISPLAY (display), va_image.image_id);
  return image;
}
Beispiel #5
0
gboolean
_gst_vaapi_image_unmap(GstVaapiImage *image)
{
    GstVaapiDisplay *display;
    VAStatus status;

    if (!_gst_vaapi_image_is_mapped(image))
        return FALSE;

    display = GST_VAAPI_OBJECT_DISPLAY(image);
    if (!display)
        return FALSE;

    GST_VAAPI_DISPLAY_LOCK(display);
    status = vaUnmapBuffer(
        GST_VAAPI_DISPLAY_VADISPLAY(display),
        image->priv->image.buf
    );
    GST_VAAPI_DISPLAY_UNLOCK(display);
    if (!vaapi_check_status(status, "vaUnmapBuffer()"))
        return FALSE;

    image->priv->image_data = NULL;
    return TRUE;
}
/**
 * gst_vaapi_subpicture_set_global_alpha:
 * @subpicture: a #GstVaapiSubpicture
 * @global_alpha: value for global-alpha (range: 0.0 to 1.0, inclusive)
 *
 * Sets the global_alpha value of @subpicture. This function calls
 * vaSetSubpictureGlobalAlpha() if the format of @subpicture, i.e.
 * the current VA driver supports it.
 *
 * Return value: %TRUE if global_alpha could be set, %FALSE otherwise
 */
gboolean
gst_vaapi_subpicture_set_global_alpha (GstVaapiSubpicture * subpicture,
    gfloat global_alpha)
{
  GstVaapiDisplay *display;
  VAStatus status;

  g_return_val_if_fail (subpicture != NULL, FALSE);

  if (!(subpicture->flags & GST_VAAPI_SUBPICTURE_FLAG_GLOBAL_ALPHA))
    return FALSE;

  if (subpicture->global_alpha == global_alpha)
    return TRUE;

  display = GST_VAAPI_OBJECT_DISPLAY (subpicture);

  GST_VAAPI_DISPLAY_LOCK (display);
  status = vaSetSubpictureGlobalAlpha (GST_VAAPI_DISPLAY_VADISPLAY (display),
      GST_VAAPI_OBJECT_ID (subpicture), global_alpha);
  GST_VAAPI_DISPLAY_UNLOCK (display);
  if (!vaapi_check_status (status, "vaSetSubpictureGlobalAlpha()"))
    return FALSE;

  subpicture->global_alpha = global_alpha;
  return TRUE;
}
/**
 * gst_vaapi_surface_put_image:
 * @surface: a #GstVaapiSurface
 * @image: a #GstVaapiImage
 *
 * Copies data from a #GstVaapiImage into a @surface. The @image must
 * have a format supported by the @surface.
 *
 * Return value: %TRUE on success
 */
gboolean
gst_vaapi_surface_put_image (GstVaapiSurface * surface, GstVaapiImage * image)
{
  GstVaapiDisplay *display;
  VAImageID image_id;
  VAStatus status;
  guint width, height;

  g_return_val_if_fail (surface != NULL, FALSE);
  g_return_val_if_fail (image != NULL, FALSE);

  display = GST_VAAPI_OBJECT_DISPLAY (surface);
  if (!display)
    return FALSE;

  width = GST_VAAPI_IMAGE_WIDTH (image);
  height = GST_VAAPI_IMAGE_HEIGHT (image);
  if (width != surface->width || height != surface->height)
    return FALSE;

  image_id = GST_VAAPI_OBJECT_ID (image);
  if (image_id == VA_INVALID_ID)
    return FALSE;

  GST_VAAPI_DISPLAY_LOCK (display);
  status = vaPutImage (GST_VAAPI_DISPLAY_VADISPLAY (display),
      GST_VAAPI_OBJECT_ID (surface), image_id, 0, 0, width, height,
      0, 0, width, height);
  GST_VAAPI_DISPLAY_UNLOCK (display);
  if (!vaapi_check_status (status, "vaPutImage()"))
    return FALSE;

  return TRUE;
}
Beispiel #8
0
static gboolean
_gst_vaapi_image_create(GstVaapiImage *image, GstVaapiImageFormat format)
{
    GstVaapiDisplay * const display = GST_VAAPI_OBJECT_DISPLAY(image);
    GstVaapiImagePrivate * const priv = image->priv;
    const VAImageFormat *va_format;
    VAStatus status;

    if (!gst_vaapi_display_has_image_format(display, format))
        return FALSE;

    va_format = gst_vaapi_image_format_get_va_format(format);
    if (!va_format)
        return FALSE;

    GST_VAAPI_DISPLAY_LOCK(display);
    status = vaCreateImage(
        GST_VAAPI_DISPLAY_VADISPLAY(display),
        (VAImageFormat *)va_format,
        priv->width,
        priv->height,
        &priv->internal_image
    );
    GST_VAAPI_DISPLAY_UNLOCK(display);
    if (status != VA_STATUS_SUCCESS ||
        priv->internal_image.format.fourcc != va_format->fourcc)
        return FALSE;

    priv->internal_format = format;
    return TRUE;
}
static void
gst_vaapi_surface_destroy (GstVaapiSurface * surface)
{
  GstVaapiDisplay *const display = GST_VAAPI_OBJECT_DISPLAY (surface);
  VASurfaceID surface_id;
  VAStatus status;

  surface_id = GST_VAAPI_OBJECT_ID (surface);
  GST_DEBUG ("surface %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS (surface_id));

  gst_vaapi_surface_destroy_subpictures (surface);
  gst_vaapi_surface_set_parent_context (surface, NULL);

  if (surface_id != VA_INVALID_SURFACE) {
    GST_VAAPI_DISPLAY_LOCK (display);
    status = vaDestroySurfaces (GST_VAAPI_DISPLAY_VADISPLAY (display),
        &surface_id, 1);
    GST_VAAPI_DISPLAY_UNLOCK (display);
    if (!vaapi_check_status (status, "vaDestroySurfaces()"))
      g_warning ("failed to destroy surface %" GST_VAAPI_ID_FORMAT,
          GST_VAAPI_ID_ARGS (surface_id));
    GST_VAAPI_OBJECT_ID (surface) = VA_INVALID_SURFACE;
  }
  gst_vaapi_buffer_proxy_replace (&surface->extbuf_proxy, NULL);
}
Beispiel #10
0
gboolean
_gst_vaapi_surface_associate_subpicture(
    GstVaapiSurface         *surface,
    GstVaapiSubpicture      *subpicture,
    const GstVaapiRectangle *src_rect,
    const GstVaapiRectangle *dst_rect
)
{
    GstVaapiDisplay *display;
    GstVaapiRectangle src_rect_default, dst_rect_default;
    GstVaapiImage *image;
    VASurfaceID surface_id;
    VAStatus status;

    display = GST_VAAPI_OBJECT_DISPLAY(surface);
    if (!display)
        return FALSE;

    surface_id = GST_VAAPI_OBJECT_ID(surface);
    if (surface_id == VA_INVALID_SURFACE)
        return FALSE;

    if (!src_rect) {
        image = gst_vaapi_subpicture_get_image(subpicture);
        if (!image)
            return FALSE;
        src_rect                = &src_rect_default;
        src_rect_default.x      = 0;
        src_rect_default.y      = 0;
        gst_vaapi_image_get_size(
            image,
            &src_rect_default.width,
            &src_rect_default.height
        );
    }

    if (!dst_rect) {
        dst_rect                = &dst_rect_default;
        dst_rect_default.x      = 0;
        dst_rect_default.y      = 0;
        dst_rect_default.width  = surface->priv->width;
        dst_rect_default.height = surface->priv->height;
    }

    GST_VAAPI_DISPLAY_LOCK(display);
    status = vaAssociateSubpicture(
        GST_VAAPI_DISPLAY_VADISPLAY(display),
        GST_VAAPI_OBJECT_ID(subpicture),
        &surface_id, 1,
        src_rect->x, src_rect->y, src_rect->width, src_rect->height,
        dst_rect->x, dst_rect->y, dst_rect->width, dst_rect->height,
        0
    );
    GST_VAAPI_DISPLAY_UNLOCK(display);
    if (!vaapi_check_status(status, "vaAssociateSubpicture()"))
        return FALSE;

    return TRUE;
}
static void
gst_vaapi_display_x11_flush (GstVaapiDisplay * display)
{
  GstVaapiDisplayX11Private *const priv =
      GST_VAAPI_DISPLAY_X11_PRIVATE (display);

  if (priv->x11_display) {
    GST_VAAPI_DISPLAY_LOCK (display);
    XFlush (priv->x11_display);
    GST_VAAPI_DISPLAY_UNLOCK (display);
  }
}
static void
gst_vaapi_display_x11_sync(GstVaapiDisplay *display)
{
    GstVaapiDisplayX11Private * const priv =
        GST_VAAPI_DISPLAY_X11(display)->priv;

    if (priv->x11_display) {
        GST_VAAPI_DISPLAY_LOCK(display);
        XSync(priv->x11_display, False);
        GST_VAAPI_DISPLAY_UNLOCK(display);
    }
}
/* Set synchronous behavious on the underlying X11 display */
static void
set_synchronous (GstVaapiDisplayX11 * display, gboolean synchronous)
{
  GstVaapiDisplayX11Private *const priv = display->priv;

  if (priv->synchronous != synchronous) {
    priv->synchronous = synchronous;
    if (priv->x11_display) {
      GST_VAAPI_DISPLAY_LOCK (display);
      XSynchronize (priv->x11_display, synchronous);
      GST_VAAPI_DISPLAY_UNLOCK (display);
    }
  }
}
static void
coded_buffer_destroy (GstVaapiCodedBuffer * buf)
{
  GstVaapiDisplay *const display = GST_VAAPI_OBJECT_DISPLAY (buf);
  VABufferID buf_id;

  buf_id = GST_VAAPI_OBJECT_ID (buf);
  GST_DEBUG ("coded buffer %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS (buf_id));

  if (buf_id != VA_INVALID_ID) {
    GST_VAAPI_DISPLAY_LOCK (display);
    vaapi_destroy_buffer (GST_VAAPI_DISPLAY_VADISPLAY (display), &buf_id);
    GST_VAAPI_DISPLAY_UNLOCK (display);
    GST_VAAPI_OBJECT_ID (buf) = VA_INVALID_ID;
  }
}
/**
 * gst_vaapi_texture_glx_new_wrapped:
 * @display: a #GstVaapiDisplay
 * @texture_id: the foreign GL texture name to use
 * @target: the target to which the texture is bound
 * @format: the format of the pixel data
 *
 * Creates a texture from an existing GL texture, with the specified
 * @target and @format. Note that only GL_TEXTURE_2D @target and
 * GL_RGBA or GL_BGRA formats are supported at this time. The
 * dimensions will be retrieved from the @texture_id.
 *
 * The application shall maintain the live GL context itself. That is,
 * gst_vaapi_window_glx_make_current() must be called beforehand, or
 * any other function like glXMakeCurrent() if the context is managed
 * outside of this library.
 *
 * Return value: the newly created #GstVaapiTexture object
 */
GstVaapiTexture *
gst_vaapi_texture_glx_new_wrapped (GstVaapiDisplay * display,
    guint texture_id, guint target, guint format)
{
  guint width, height, border_width = 0;
  GLTextureState ts = { 0, };
  gboolean success;
  GstVaapiGLApi gl_api;

  g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_GLX (display), NULL);
  g_return_val_if_fail (texture_id != GL_NONE, NULL);
  g_return_val_if_fail (target == GL_TEXTURE_2D, NULL);
  g_return_val_if_fail (format == GL_RGBA || format == GL_BGRA, NULL);

  gl_api = gl_get_curent_api_once ();
  if (gl_api != GST_VAAPI_GL_API_OPENGL && gl_api != GST_VAAPI_GL_API_OPENGL3)
    return NULL;

  /* Check texture dimensions */
  GST_VAAPI_DISPLAY_LOCK (display);
  if (gl_api == GST_VAAPI_GL_API_OPENGL)
    success = gl_bind_texture (&ts, target, texture_id);
  else
    success = gl3_bind_texture_2d (&ts, target, texture_id);

  if (success) {
    if (!gl_get_texture_param (target, GL_TEXTURE_WIDTH, &width) ||
        !gl_get_texture_param (target, GL_TEXTURE_HEIGHT, &height))
      success = FALSE;
    if (success && gl_api == GST_VAAPI_GL_API_OPENGL)
      success = gl_get_texture_param (target, GL_TEXTURE_BORDER, &border_width);
    gl_unbind_texture (&ts);
  }
  GST_VAAPI_DISPLAY_UNLOCK (display);
  if (!success)
    return NULL;

  width -= 2 * border_width;
  height -= 2 * border_width;
  g_return_val_if_fail (width > 0, NULL);
  g_return_val_if_fail (height > 0, NULL);

  return gst_vaapi_texture_new_internal (GST_VAAPI_TEXTURE_CLASS
      (gst_vaapi_texture_glx_class ()), display, texture_id, target, format,
      width, height);
}
static gboolean
coded_buffer_create (GstVaapiCodedBuffer * buf, guint buf_size,
    GstVaapiContext * context)
{
  GstVaapiDisplay *const display = GST_VAAPI_OBJECT_DISPLAY (buf);
  VABufferID buf_id;
  gboolean success;

  GST_VAAPI_DISPLAY_LOCK (display);
  success = vaapi_create_buffer (GST_VAAPI_DISPLAY_VADISPLAY (display),
      GST_VAAPI_OBJECT_ID (context), VAEncCodedBufferType, buf_size, NULL,
      &buf_id, NULL);
  GST_VAAPI_DISPLAY_UNLOCK (display);
  if (!success)
    return FALSE;

  GST_DEBUG ("coded buffer %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS (buf_id));
  GST_VAAPI_OBJECT_ID (buf) = buf_id;
  return TRUE;
}
Beispiel #17
0
gboolean
_gst_vaapi_image_map(GstVaapiImage *image, GstVaapiImageRaw *raw_image)
{
    GstVaapiImagePrivate * const priv = image->priv;
    GstVaapiDisplay *display;
    void *image_data;
    VAStatus status;
    guint i;

    if (_gst_vaapi_image_is_mapped(image))
        return TRUE;

    display = GST_VAAPI_OBJECT_DISPLAY(image);
    if (!display)
        return FALSE;

    GST_VAAPI_DISPLAY_LOCK(display);
    status = vaMapBuffer(
        GST_VAAPI_DISPLAY_VADISPLAY(display),
        image->priv->image.buf,
        &image_data
    );
    GST_VAAPI_DISPLAY_UNLOCK(display);
    if (!vaapi_check_status(status, "vaMapBuffer()"))
        return FALSE;

    image->priv->image_data = image_data;

    if (raw_image) {
        const VAImage * const va_image = &priv->image;
        raw_image->format     = priv->format;
        raw_image->width      = va_image->width;
        raw_image->height     = va_image->height;
        raw_image->num_planes = va_image->num_planes;
        for (i = 0; i < raw_image->num_planes; i++) {
            raw_image->pixels[i] = (guchar *)image_data + va_image->offsets[i];
            raw_image->stride[i] = va_image->pitches[i];
        }
    }
    return TRUE;
}
static gboolean
gst_vaapi_subpicture_create (GstVaapiSubpicture * subpicture,
    GstVaapiImage * image)
{
  GstVaapiDisplay *const display = GST_VAAPI_OBJECT_DISPLAY (subpicture);
  VASubpictureID subpicture_id;
  VAStatus status;

  GST_VAAPI_DISPLAY_LOCK (display);
  status = vaCreateSubpicture (GST_VAAPI_DISPLAY_VADISPLAY (display),
      GST_VAAPI_OBJECT_ID (image), &subpicture_id);
  GST_VAAPI_DISPLAY_UNLOCK (display);
  if (!vaapi_check_status (status, "vaCreateSubpicture()"))
    return FALSE;

  GST_DEBUG ("subpicture %" GST_VAAPI_ID_FORMAT,
      GST_VAAPI_ID_ARGS (subpicture_id));
  GST_VAAPI_OBJECT_ID (subpicture) = subpicture_id;
  subpicture->image = gst_vaapi_object_ref (image);
  return TRUE;
}
/**
 * gst_vaapi_surface_sync:
 * @surface: a #GstVaapiSurface
 *
 * Blocks until all pending operations on the @surface have been
 * completed.
 *
 * Return value: %TRUE on success
 */
gboolean
gst_vaapi_surface_sync (GstVaapiSurface * surface)
{
  GstVaapiDisplay *display;
  VAStatus status;

  g_return_val_if_fail (surface != NULL, FALSE);

  display = GST_VAAPI_OBJECT_DISPLAY (surface);
  if (!display)
    return FALSE;

  GST_VAAPI_DISPLAY_LOCK (display);
  status = vaSyncSurface (GST_VAAPI_DISPLAY_VADISPLAY (display),
      GST_VAAPI_OBJECT_ID (surface));
  GST_VAAPI_DISPLAY_UNLOCK (display);
  if (!vaapi_check_status (status, "vaSyncSurface()"))
    return FALSE;

  return TRUE;
}
Beispiel #20
0
static gboolean
gst_vaapi_surface_create(GstVaapiSurface *surface)
{
    GstVaapiDisplay * const display = GST_VAAPI_OBJECT_DISPLAY(surface);
    GstVaapiSurfacePrivate * const priv = surface->priv;
    VASurfaceID surface_id;
    VAStatus status;
    guint format;

    switch (priv->chroma_type) {
    case GST_VAAPI_CHROMA_TYPE_YUV420:
        format = VA_RT_FORMAT_YUV420;
        break;
    case GST_VAAPI_CHROMA_TYPE_YUV422:
        format = VA_RT_FORMAT_YUV422;
        break;
    case GST_VAAPI_CHROMA_TYPE_YUV444:
        format = VA_RT_FORMAT_YUV444;
        break;
    default:
        GST_DEBUG("unsupported chroma-type %u\n", priv->chroma_type);
        return FALSE;
    }

    GST_VAAPI_DISPLAY_LOCK(display);
    status = vaCreateSurfaces(
        GST_VAAPI_DISPLAY_VADISPLAY(display),
        priv->width,
        priv->height,
        format,
        1, &surface_id
    );
    GST_VAAPI_DISPLAY_UNLOCK(display);
    if (!vaapi_check_status(status, "vaCreateSurfaces()"))
        return FALSE;

    GST_DEBUG("surface %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS(surface_id));
    GST_VAAPI_OBJECT_ID(surface) = surface_id;
    return TRUE;
}
Beispiel #21
0
static void
gst_vaapi_image_destroy(GstVaapiImage *image)
{
    GstVaapiDisplay * const display = GST_VAAPI_OBJECT_DISPLAY(image);
    VAImageID image_id;
    VAStatus status;

    _gst_vaapi_image_unmap(image);

    image_id = GST_VAAPI_OBJECT_ID(image);
    GST_DEBUG("image %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS(image_id));

    if (image_id != VA_INVALID_ID) {
        GST_VAAPI_DISPLAY_LOCK(display);
        status = vaDestroyImage(GST_VAAPI_DISPLAY_VADISPLAY(display), image_id);
        GST_VAAPI_DISPLAY_UNLOCK(display);
        if (!vaapi_check_status(status, "vaDestroyImage()"))
            g_warning("failed to destroy image %" GST_VAAPI_ID_FORMAT,
                      GST_VAAPI_ID_ARGS(image_id));
        GST_VAAPI_OBJECT_ID(image) = VA_INVALID_ID;
    }
}
static gboolean
ensure_pix_fmts (GstVaapiDisplayX11 * display)
{
  GstVaapiDisplayX11Private *const priv =
      GST_VAAPI_DISPLAY_X11_PRIVATE (display);
  XPixmapFormatValues *pix_fmts;
  int i, n, num_pix_fmts;

  if (priv->pixmap_formats)
    return TRUE;

  GST_VAAPI_DISPLAY_LOCK (display);
  pix_fmts = XListPixmapFormats (GST_VAAPI_DISPLAY_XDISPLAY (display),
      &num_pix_fmts);
  GST_VAAPI_DISPLAY_UNLOCK (display);
  if (!pix_fmts)
    return FALSE;

  priv->pixmap_formats = g_array_sized_new (FALSE, FALSE,
      sizeof (GstVaapiPixmapFormatX11), num_pix_fmts);
  if (!priv->pixmap_formats) {
    XFree (pix_fmts);
    return FALSE;
  }

  for (i = 0, n = 0; i < num_pix_fmts; i++) {
    GstVaapiPixmapFormatX11 *const pix_fmt =
        &g_array_index (priv->pixmap_formats, GstVaapiPixmapFormatX11, n);

    pix_fmt->depth = pix_fmts[i].depth;
    pix_fmt->bpp = pix_fmts[i].bits_per_pixel;
    pix_fmt->format = pix_fmt_to_video_format (pix_fmt->depth, pix_fmt->bpp);
    if (pix_fmt->format != GST_VIDEO_FORMAT_UNKNOWN)
      n++;
  }
  priv->pixmap_formats->len = n;
  return TRUE;
}
/**
 * gst_vaapi_get_config_attribute:
 * @display: a #GstVaapiDisplay
 * @profile: a VA profile
 * @entrypoint: a VA entrypoint
 * @type: a VA config attribute type
 * @out_value_ptr: return location for the config attribute value
 *
 * Determines the value for the VA config attribute @type and the
 * given @profile/@entrypoint pair. If @out_value_ptr is %NULL, then
 * this functions acts as a way to query whether the underlying VA
 * driver supports the specified attribute @type, no matter the
 * returned value.
 *
 * Note: this function only returns success if the VA driver does
 * actually know about this config attribute type and that it returned
 * a valid value for it.
 *
 * Return value: %TRUE if the VA driver knows about the requested
 *   config attribute and returned a valid value, %FALSE otherwise
 */
gboolean
gst_vaapi_get_config_attribute (GstVaapiDisplay * display, VAProfile profile,
    VAEntrypoint entrypoint, VAConfigAttribType type, guint * out_value_ptr)
{
  VAConfigAttrib attrib;
  VAStatus status;

  g_return_val_if_fail (display != NULL, FALSE);

  GST_VAAPI_DISPLAY_LOCK (display);
  attrib.type = type;
  status = vaGetConfigAttributes (GST_VAAPI_DISPLAY_VADISPLAY (display),
      profile, entrypoint, &attrib, 1);
  GST_VAAPI_DISPLAY_UNLOCK (display);
  if (!vaapi_check_status (status, "vaGetConfigAttributes()"))
    return FALSE;
  if (attrib.value == VA_ATTRIB_NOT_SUPPORTED)
    return FALSE;

  if (out_value_ptr)
    *out_value_ptr = attrib.value;
  return TRUE;
}
static GstVaapiDecoderStatus
decode_frame(GstVaapiDecoderFfmpeg *ffdecoder, guchar *buf, guint buf_size)
{
    GstVaapiDecoderFfmpegPrivate * const priv = ffdecoder->priv;
    GstVaapiDisplay * const display = GST_VAAPI_DECODER_DISPLAY(ffdecoder);
    GstVaapiSurface *surface;
    int bytes_read, got_picture = 0;
    AVPacket avpkt;

    GST_VAAPI_DISPLAY_LOCK(display);
    av_init_packet(&avpkt);
    avpkt.data = buf;
    avpkt.size = buf_size;
    bytes_read = avcodec_decode_video2(
        priv->avctx,
        priv->frame,
        &got_picture,
	&avpkt
    );
    GST_VAAPI_DISPLAY_UNLOCK(display);
    if (!got_picture)
        return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
    if (bytes_read < 0)
        return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;

    surface = gst_vaapi_context_find_surface_by_id(
        GST_VAAPI_DECODER_CONTEXT(ffdecoder),
        GPOINTER_TO_UINT(priv->frame->data[3])
    );
    if (!surface)
        return GST_VAAPI_DECODER_STATUS_ERROR_INVALID_SURFACE;

    if (!gst_vaapi_decoder_push_surface(GST_VAAPI_DECODER_CAST(ffdecoder),
                                        surface, priv->frame->pts))
        return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
    return GST_VAAPI_DECODER_STATUS_SUCCESS;
}
Beispiel #25
0
/**
 * gst_vaapi_surface_get_image
 * @surface: a #GstVaapiSurface
 * @image: a #GstVaapiImage
 *
 * Retrieves surface data into a #GstVaapiImage. The @image must have
 * a format supported by the @surface.
 *
 * Return value: %TRUE on success
 */
gboolean
gst_vaapi_surface_get_image(GstVaapiSurface *surface, GstVaapiImage *image)
{
    GstVaapiDisplay *display;
    VAImageID image_id;
    VAStatus status;
    guint width, height;

    g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), FALSE);
    g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);

    display = GST_VAAPI_OBJECT_DISPLAY(surface);
    if (!display)
        return FALSE;

    gst_vaapi_image_get_size(image, &width, &height);
    if (width != surface->priv->width || height != surface->priv->height)
        return FALSE;

    image_id = GST_VAAPI_OBJECT_ID(image);
    if (image_id == VA_INVALID_ID)
        return FALSE;

    GST_VAAPI_DISPLAY_LOCK(display);
    status = vaGetImage(
        GST_VAAPI_DISPLAY_VADISPLAY(display),
        GST_VAAPI_OBJECT_ID(surface),
        0, 0, width, height,
        image_id
    );
    GST_VAAPI_DISPLAY_UNLOCK(display);
    if (!vaapi_check_status(status, "vaGetImage()"))
        return FALSE;

    return TRUE;
}
static gboolean
gst_vaapi_decoder_ffmpeg_open(GstVaapiDecoderFfmpeg *ffdecoder, GstBuffer *buffer)
{
    GstVaapiDecoderFfmpegPrivate * const priv = ffdecoder->priv;
    GstVaapiDisplay * const display = GST_VAAPI_DECODER_DISPLAY(ffdecoder);
    GstBuffer * const codec_data = GST_VAAPI_DECODER_CODEC_DATA(ffdecoder);
    GstVaapiCodec codec = GST_VAAPI_DECODER_CODEC(ffdecoder);
    enum CodecID codec_id;
    AVCodec *ffcodec;
    gboolean try_parser, need_parser;
    int ret;

    gst_vaapi_decoder_ffmpeg_close(ffdecoder);

    if (codec_data) {
        const guchar *data = GST_BUFFER_DATA(codec_data);
        const guint   size = GST_BUFFER_SIZE(codec_data);
        if (!set_codec_data(priv->avctx, data, size))
            return FALSE;
    }

    codec_id = get_codec_id_from_codec(codec);
    if (codec_id == CODEC_ID_NONE)
        return FALSE;

    ffcodec = avcodec_find_decoder(codec_id);
    if (!ffcodec)
        return FALSE;

    switch (codec_id) {
    case CODEC_ID_H264:
        /* For AVC1 formats, sequence headers are in extradata and
           input encoded buffers represent the whole NAL unit */
        try_parser  = priv->avctx->extradata_size == 0;
        need_parser = try_parser;
        break;
    case CODEC_ID_WMV3:
        /* There is no WMV3 parser in FFmpeg */
        try_parser  = FALSE;
        need_parser = FALSE;
        break;
    case CODEC_ID_VC1:
        /* For VC-1, sequence headers ae in extradata and input encoded
           buffers represent the whole slice */
        try_parser  = priv->avctx->extradata_size == 0;
        need_parser = FALSE;
        break;
    default:
        try_parser  = TRUE;
        need_parser = TRUE;
        break;
    }

    if (try_parser) {
        priv->pctx = av_parser_init(codec_id);
        if (!priv->pctx && need_parser)
            return FALSE;
    }

    /* XXX: av_find_stream_info() does this and some codecs really
       want hard an extradata buffer for initialization (e.g. VC-1) */
    if (!priv->avctx->extradata && priv->pctx && priv->pctx->parser->split) {
        const guchar *buf = GST_BUFFER_DATA(buffer);
        guint buf_size = GST_BUFFER_SIZE(buffer);
        buf_size = priv->pctx->parser->split(priv->avctx, buf, buf_size);
        if (buf_size > 0 && !set_codec_data(priv->avctx, buf, buf_size))
            return FALSE;
    }

    if (priv->pctx && !need_parser) {
        av_parser_close(priv->pctx);
        priv->pctx = NULL;
    }

    /* Use size information from the demuxer, whenever available */
    priv->avctx->coded_width  = GST_VAAPI_DECODER_WIDTH(ffdecoder);
    priv->avctx->coded_height = GST_VAAPI_DECODER_HEIGHT(ffdecoder);

    GST_VAAPI_DISPLAY_LOCK(display);
    ret = avcodec_open(priv->avctx, ffcodec);
    GST_VAAPI_DISPLAY_UNLOCK(display);
    if (ret < 0)
        return FALSE;
    return TRUE;
}
/**
 * gst_vaapi_get_surface_formats:
 * @display: a #GstVaapiDisplay
 * @config: a #VAConfigID
 *
 * Gets surface formats for the supplied config.
 *
 * This function will query for all the supported formats for the
 * supplied VA @config.
 *
 * Return value: (transfer full): a #GArray of #GstVideoFormats or %NULL
 */
GArray *
gst_vaapi_get_surface_formats (GstVaapiDisplay * display, VAConfigID config)
{
  VASurfaceAttrib *surface_attribs = NULL;
  guint i, num_surface_attribs = 0;
  VAStatus va_status;
  GArray *formats;

  if (config == VA_INVALID_ID)
    return NULL;

  GST_VAAPI_DISPLAY_LOCK (display);
  va_status = vaQuerySurfaceAttributes (GST_VAAPI_DISPLAY_VADISPLAY (display),
      config, NULL, &num_surface_attribs);
  GST_VAAPI_DISPLAY_UNLOCK (display);
  if (!vaapi_check_status (va_status, "vaQuerySurfaceAttributes()"))
    return NULL;

  surface_attribs = g_malloc (num_surface_attribs * sizeof (*surface_attribs));
  if (!surface_attribs)
    return NULL;

  GST_VAAPI_DISPLAY_LOCK (display);
  va_status = vaQuerySurfaceAttributes (GST_VAAPI_DISPLAY_VADISPLAY (display),
      config, surface_attribs, &num_surface_attribs);
  GST_VAAPI_DISPLAY_UNLOCK (display);
  if (!vaapi_check_status (va_status, "vaQuerySurfaceAttributes()"))
    return NULL;

  formats = g_array_sized_new (FALSE, FALSE, sizeof (GstVideoFormat),
      num_surface_attribs);
  if (!formats)
    goto error;

  for (i = 0; i < num_surface_attribs; i++) {
    const VASurfaceAttrib *const attrib = &surface_attribs[i];
    GstVideoFormat fmt;

    if (attrib->type != VASurfaceAttribPixelFormat)
      continue;
    if (!(attrib->flags & VA_SURFACE_ATTRIB_SETTABLE))
      continue;

    fmt = gst_vaapi_video_format_from_va_fourcc (attrib->value.value.i);
    if (fmt == GST_VIDEO_FORMAT_UNKNOWN)
      continue;
    g_array_append_val (formats, fmt);
  }

  if (formats->len == 0) {
    g_array_unref (formats);
    formats = NULL;
  }

  g_free (surface_attribs);
  return formats;

  /* ERRORS */
error:
  {
    g_free (surface_attribs);
  }
  return NULL;
}
static gboolean
gst_vaapi_surface_create_full (GstVaapiSurface * surface,
    const GstVideoInfo * vip, guint flags)
{
#if VA_CHECK_VERSION(0,34,0)
  GstVaapiDisplay *const display = GST_VAAPI_OBJECT_DISPLAY (surface);
  const GstVideoFormat format = GST_VIDEO_INFO_FORMAT (vip);
  VASurfaceID surface_id;
  VAStatus status;
  guint chroma_type, va_chroma_format, i;
  const VAImageFormat *va_format;
  VASurfaceAttrib attribs[3], *attrib;
  VASurfaceAttribExternalBuffers extbuf;
  gboolean extbuf_needed = FALSE;

  va_format = gst_vaapi_video_format_to_va_format (format);
  if (!va_format)
    goto error_unsupported_format;

  chroma_type = gst_vaapi_video_format_get_chroma_type (format);
  if (!chroma_type)
    goto error_unsupported_format;

  va_chroma_format = from_GstVaapiChromaType (chroma_type);
  if (!va_chroma_format)
    goto error_unsupported_format;

  memset (&extbuf, 0, sizeof (extbuf));
  extbuf.pixel_format = va_format->fourcc;
  extbuf.width = GST_VIDEO_INFO_WIDTH (vip);
  extbuf.height = GST_VIDEO_INFO_HEIGHT (vip);
  extbuf_needed = ! !(flags & GST_VAAPI_SURFACE_ALLOC_FLAG_LINEAR_STORAGE);

  extbuf.num_planes = GST_VIDEO_INFO_N_PLANES (vip);
  if (flags & GST_VAAPI_SURFACE_ALLOC_FLAG_FIXED_STRIDES) {
    for (i = 0; i < extbuf.num_planes; i++)
      extbuf.pitches[i] = GST_VIDEO_INFO_PLANE_STRIDE (vip, i);
    extbuf_needed = TRUE;
  }
  if (flags & GST_VAAPI_SURFACE_ALLOC_FLAG_FIXED_OFFSETS) {
    for (i = 0; i < extbuf.num_planes; i++)
      extbuf.offsets[i] = GST_VIDEO_INFO_PLANE_OFFSET (vip, i);
    extbuf_needed = TRUE;
  }

  attrib = attribs;
  attrib->flags = VA_SURFACE_ATTRIB_SETTABLE;
  attrib->type = VASurfaceAttribPixelFormat;
  attrib->value.type = VAGenericValueTypeInteger;
  attrib->value.value.i = va_format->fourcc;
  attrib++;

  if (extbuf_needed) {
    attrib->flags = VA_SURFACE_ATTRIB_SETTABLE;
    attrib->type = VASurfaceAttribMemoryType;
    attrib->value.type = VAGenericValueTypeInteger;
    attrib->value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_VA;
    attrib++;

    attrib->flags = VA_SURFACE_ATTRIB_SETTABLE;
    attrib->type = VASurfaceAttribExternalBufferDescriptor;
    attrib->value.type = VAGenericValueTypePointer;
    attrib->value.value.p = &extbuf;
    attrib++;
  }

  GST_VAAPI_DISPLAY_LOCK (display);
  status = vaCreateSurfaces (GST_VAAPI_DISPLAY_VADISPLAY (display),
      va_chroma_format, extbuf.width, extbuf.height, &surface_id, 1,
      attribs, attrib - attribs);
  GST_VAAPI_DISPLAY_UNLOCK (display);
  if (!vaapi_check_status (status, "vaCreateSurfaces()"))
    return FALSE;

  surface->format = format;
  surface->chroma_type = chroma_type;
  surface->width = extbuf.width;
  surface->height = extbuf.height;

  GST_DEBUG ("surface %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS (surface_id));
  GST_VAAPI_OBJECT_ID (surface) = surface_id;
  return TRUE;

  /* ERRORS */
error_unsupported_format:
  GST_ERROR ("unsupported format %s",
      gst_vaapi_video_format_to_string (format));
  return FALSE;
#else
  return FALSE;
#endif
}
static gboolean
gst_vaapi_surface_create_from_buffer_proxy (GstVaapiSurface * surface,
    GstVaapiBufferProxy * proxy, const GstVideoInfo * vip)
{
#if VA_CHECK_VERSION (0,36,0)
  GstVaapiDisplay *const display = GST_VAAPI_OBJECT_DISPLAY (surface);
  GstVideoFormat format;
  VASurfaceID surface_id;
  VAStatus status;
  guint chroma_type, va_chroma_format;
  const VAImageFormat *va_format;
  VASurfaceAttrib attribs[2], *attrib;
  VASurfaceAttribExternalBuffers extbuf;
  unsigned long extbuf_handle;
  guint i, width, height;

  format = GST_VIDEO_INFO_FORMAT (vip);
  width = GST_VIDEO_INFO_WIDTH (vip);
  height = GST_VIDEO_INFO_HEIGHT (vip);

  gst_vaapi_buffer_proxy_replace (&surface->extbuf_proxy, proxy);

  va_format = gst_vaapi_video_format_to_va_format (format);
  if (!va_format)
    goto error_unsupported_format;

  chroma_type = gst_vaapi_video_format_get_chroma_type (format);
  if (!chroma_type)
    goto error_unsupported_format;

  va_chroma_format = from_GstVaapiChromaType (chroma_type);
  if (!va_chroma_format)
    goto error_unsupported_format;

  extbuf_handle = GST_VAAPI_BUFFER_PROXY_HANDLE (proxy);
  extbuf.pixel_format = va_format->fourcc;
  extbuf.width = width;
  extbuf.height = height;
  extbuf.data_size = GST_VAAPI_BUFFER_PROXY_SIZE (proxy);
  extbuf.num_planes = GST_VIDEO_INFO_N_PLANES (vip);
  for (i = 0; i < extbuf.num_planes; i++) {
    extbuf.pitches[i] = GST_VIDEO_INFO_PLANE_STRIDE (vip, i);
    extbuf.offsets[i] = GST_VIDEO_INFO_PLANE_OFFSET (vip, i);
  }
  extbuf.buffers = &extbuf_handle;
  extbuf.num_buffers = 1;
  extbuf.flags = 0;
  extbuf.private_data = NULL;

  attrib = attribs;
  attrib->type = VASurfaceAttribExternalBufferDescriptor;
  attrib->flags = VA_SURFACE_ATTRIB_SETTABLE;
  attrib->value.type = VAGenericValueTypePointer;
  attrib->value.value.p = &extbuf;
  attrib++;
  attrib->type = VASurfaceAttribMemoryType;
  attrib->flags = VA_SURFACE_ATTRIB_SETTABLE;
  attrib->value.type = VAGenericValueTypeInteger;
  attrib->value.value.i =
      from_GstVaapiBufferMemoryType (GST_VAAPI_BUFFER_PROXY_TYPE (proxy));
  attrib++;

  GST_VAAPI_DISPLAY_LOCK (display);
  status = vaCreateSurfaces (GST_VAAPI_DISPLAY_VADISPLAY (display),
      va_chroma_format, width, height, &surface_id, 1, attribs,
      attrib - attribs);
  GST_VAAPI_DISPLAY_UNLOCK (display);
  if (!vaapi_check_status (status, "vaCreateSurfaces()"))
    return FALSE;

  surface->format = format;
  surface->chroma_type = chroma_type;
  surface->width = width;
  surface->height = height;

  GST_DEBUG ("surface %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS (surface_id));
  GST_VAAPI_OBJECT_ID (surface) = surface_id;
  return TRUE;

  /* ERRORS */
error_unsupported_format:
  GST_ERROR ("unsupported format %s",
      gst_vaapi_video_format_to_string (format));
  return FALSE;
#else
  return FALSE;
#endif
}