/**
 * 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;
}
Пример #2
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;
}
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_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);
}
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 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);
}
Пример #7
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;
}
/**
 * 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;
}
/**
 * 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;
}
Пример #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;
}
Пример #11
0
static gboolean
gst_vaapi_display_egl_get_display_info (GstVaapiDisplay * base_display,
    GstVaapiDisplayInfo * info)
{
  GstVaapiDisplayEGL *display = GST_VAAPI_DISPLAY_EGL (base_display);
  GstVaapiDisplayClass *const klass =
      GST_VAAPI_DISPLAY_GET_CLASS (display->display);

  info->va_display = GST_VAAPI_DISPLAY_VADISPLAY (display->display);

  if (klass->get_display && !klass->get_display (display->display, info))
    return FALSE;
  return TRUE;
}
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;
  }
}
/** Ensures VA context is correctly set up for the current FFmpeg context */
static GstVaapiContext *
get_context(AVCodecContext *avctx)
{
    GstVaapiContextFfmpeg * const vactx = avctx->hwaccel_context;
    GstVaapiDecoder * const decoder = GST_VAAPI_DECODER(vactx->decoder);
    GstVaapiDisplay *display;
    GstVaapiContext *context;
    gboolean success;

    if (!avctx->coded_width || !avctx->coded_height)
        return NULL;

    gst_vaapi_decoder_set_framerate(
        decoder,
        avctx->time_base.den / avctx->ticks_per_frame,
        avctx->time_base.num
    );

    gst_vaapi_decoder_set_pixel_aspect_ratio(
        decoder,
        avctx->sample_aspect_ratio.num,
        avctx->sample_aspect_ratio.den
    );

    success = gst_vaapi_decoder_ensure_context(
        decoder,
        vactx->profile,
        vactx->entrypoint,
        avctx->coded_width,
        avctx->coded_height
    );
    if (!success) {
        GST_DEBUG("failed to reset VA context:");
        GST_DEBUG("  profile 0x%08x", vactx->profile);
        GST_DEBUG("  entrypoint %d", vactx->entrypoint);
        GST_DEBUG("  surface size %dx%d", avctx->width, avctx->height);
        return NULL;
    }
    display                = GST_VAAPI_DECODER_DISPLAY(decoder);
    context                = GST_VAAPI_DECODER_CONTEXT(decoder);
    vactx->base.display    = GST_VAAPI_DISPLAY_VADISPLAY(display);
    vactx->base.context_id = GST_VAAPI_OBJECT_ID(context);
    return context;
}
Пример #14
0
static void
gst_vaapi_display_egl_finalize (GObject * object)
{
  GstVaapiDisplayEGL *dpy = GST_VAAPI_DISPLAY_EGL (object);

  if (dpy->texture_map)
    gst_object_unref (dpy->texture_map);

  /* HACK to avoid to call twice vaTerminate() since this and the
   * proxied display share the same vaDisplay */
  GST_VAAPI_DISPLAY_VADISPLAY (object) = NULL;

  egl_object_replace (&dpy->egl_display, NULL);
  egl_object_replace (&dpy->egl_context, NULL);

  gst_vaapi_display_replace (&dpy->display, NULL);

  G_OBJECT_CLASS (gst_vaapi_display_egl_parent_class)->finalize (object);
}
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;
}
Пример #16
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;
}
/**
 * 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;
}
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;
}
Пример #19
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;
}
Пример #20
0
static gboolean
gst_vaapi_decoder_init (GstVaapiDecoder * decoder, GstVaapiDisplay * display,
    GstCaps * caps)
{
  const GstVaapiDecoderClass *const klass =
      GST_VAAPI_DECODER_GET_CLASS (decoder);
  GstVideoCodecState *codec_state;
  guint sub_size;

  parser_state_init (&decoder->parser_state);

  codec_state = g_slice_new0 (GstVideoCodecState);
  codec_state->ref_count = 1;
  gst_video_info_init (&codec_state->info);

  decoder->user_data = NULL;
  decoder->display = gst_vaapi_display_ref (display);
  decoder->va_display = GST_VAAPI_DISPLAY_VADISPLAY (display);
  decoder->context = NULL;
  decoder->va_context = VA_INVALID_ID;
  decoder->codec = 0;
  decoder->codec_state = codec_state;
  decoder->codec_state_changed_func = NULL;
  decoder->codec_state_changed_data = NULL;

  decoder->buffers = g_async_queue_new_full ((GDestroyNotify) gst_buffer_unref);
  decoder->frames = g_async_queue_new_full ((GDestroyNotify)
      gst_video_codec_frame_unref);

  if (!set_caps (decoder, caps))
    return FALSE;

  sub_size = GST_VAAPI_MINI_OBJECT_CLASS (klass)->size - sizeof (*decoder);
  if (sub_size > 0)
    memset (((guchar *) decoder) + sizeof (*decoder), 0, sub_size);

  if (klass->create && !klass->create (decoder))
    return FALSE;
  return TRUE;
}
Пример #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;
    }
}
Пример #22
0
/**
 * 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;
}
Пример #23
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_window_wayland_render(
    GstVaapiWindow          *window,
    GstVaapiSurface         *surface,
    const GstVaapiRectangle *src_rect,
    const GstVaapiRectangle *dst_rect,
    guint                    flags
)
{
    GstVaapiWindowWaylandPrivate * const priv =
        GST_VAAPI_WINDOW_WAYLAND(window)->priv;
    GstVaapiDisplay * const display = GST_VAAPI_OBJECT_DISPLAY(window);
    struct wl_display * const wl_display = GST_VAAPI_OBJECT_WL_DISPLAY(window);
    struct wl_buffer *buffer;
    struct wl_callback *callback;
    guint width, height, va_flags;
    VASurfaceID surface_id;
    VAStatus status;

    /* XXX: use VPP to support unusual source and destination rectangles */
    gst_vaapi_surface_get_size(surface, &width, &height);
    if (src_rect->x      != 0     ||
            src_rect->y      != 0     ||
            src_rect->width  != width ||
            src_rect->height != height) {
        GST_ERROR("unsupported source rectangle for rendering");
        return FALSE;
    }

    if (0 && (dst_rect->width != width || dst_rect->height != height)) {
        GST_ERROR("unsupported target rectangle for rendering");
        return FALSE;
    }

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

    GST_VAAPI_OBJECT_LOCK_DISPLAY(window);

    /* Wait for the previous frame to complete redraw */
    if (priv->redraw_pending)
        wl_display_iterate(wl_display, WL_DISPLAY_READABLE);

    /* XXX: use VA/VPP for other filters */
    va_flags = from_GstVaapiSurfaceRenderFlags(flags);
    status = vaGetSurfaceBufferWl(
                 GST_VAAPI_DISPLAY_VADISPLAY(display),
                 surface_id,
                 va_flags & (VA_TOP_FIELD|VA_BOTTOM_FIELD),
                 &buffer
             );
    if (status == VA_STATUS_ERROR_FLAG_NOT_SUPPORTED) {
        /* XXX: de-interlacing flags not supported, try with VPP? */
        status = vaGetSurfaceBufferWl(
                     GST_VAAPI_DISPLAY_VADISPLAY(display),
                     surface_id,
                     VA_FRAME_PICTURE,
                     &buffer
                 );
    }
    if (!vaapi_check_status(status, "vaGetSurfaceBufferWl()"))
        return FALSE;

    /* XXX: attach to the specified target rectangle */
    wl_surface_attach(priv->surface, buffer, 0, 0);
    wl_surface_damage(priv->surface, 0, 0, width, height);

    wl_display_iterate(wl_display, WL_DISPLAY_WRITABLE);
    priv->redraw_pending = TRUE;
    priv->buffer = buffer;

    callback = wl_surface_frame(priv->surface);
    wl_callback_add_listener(callback, &frame_callback_listener, priv);
    GST_VAAPI_OBJECT_UNLOCK_DISPLAY(window);
    return TRUE;
}
static gboolean
gst_vaapi_window_wayland_render (GstVaapiWindow * window,
                                 GstVaapiSurface * surface,
                                 const GstVaapiRectangle * src_rect,
                                 const GstVaapiRectangle * dst_rect, guint flags)
{
    GstVaapiWindowWaylandPrivate *const priv =
        GST_VAAPI_WINDOW_WAYLAND_GET_PRIVATE (window);
    GstVaapiDisplay *const display = GST_VAAPI_OBJECT_DISPLAY (window);
    struct wl_display *const wl_display =
        GST_VAAPI_OBJECT_NATIVE_DISPLAY (window);
    struct wl_buffer *buffer;
    FrameState *frame;
    guint width, height, va_flags;
    VAStatus status;
    gboolean need_vpp = FALSE;

    /* Check that we don't need to crop source VA surface */
    gst_vaapi_surface_get_size (surface, &width, &height);
    if (src_rect->x != 0 || src_rect->y != 0)
        need_vpp = TRUE;
    if (src_rect->width != width || src_rect->height != height)
        need_vpp = TRUE;

    /* Check that we don't render to a subregion of this window */
    if (dst_rect->x != 0 || dst_rect->y != 0)
        need_vpp = TRUE;
    if (dst_rect->width != window->width || dst_rect->height != window->height)
        need_vpp = TRUE;

    /* Try to construct a Wayland buffer from VA surface as is (without VPP) */
    if (!need_vpp) {
        GST_VAAPI_OBJECT_LOCK_DISPLAY (window);
        va_flags = from_GstVaapiSurfaceRenderFlags (flags);
        status = vaGetSurfaceBufferWl (GST_VAAPI_DISPLAY_VADISPLAY (display),
                                       GST_VAAPI_OBJECT_ID (surface),
                                       va_flags & (VA_TOP_FIELD | VA_BOTTOM_FIELD), &buffer);
        GST_VAAPI_OBJECT_UNLOCK_DISPLAY (window);
        if (status == VA_STATUS_ERROR_FLAG_NOT_SUPPORTED)
            need_vpp = TRUE;
        else if (!vaapi_check_status (status, "vaGetSurfaceBufferWl()"))
            return FALSE;
    }

    /* Try to construct a Wayland buffer with VPP */
    if (need_vpp) {
        if (priv->use_vpp) {
            GstVaapiSurface *const vpp_surface =
                vpp_convert (window, surface, src_rect, dst_rect, flags);
            if (G_UNLIKELY (!vpp_surface))
                need_vpp = FALSE;
            else {
                surface = vpp_surface;
                width = window->width;
                height = window->height;
            }
        }

        GST_VAAPI_OBJECT_LOCK_DISPLAY (window);
        status = vaGetSurfaceBufferWl (GST_VAAPI_DISPLAY_VADISPLAY (display),
                                       GST_VAAPI_OBJECT_ID (surface), VA_FRAME_PICTURE, &buffer);
        GST_VAAPI_OBJECT_UNLOCK_DISPLAY (window);
        if (!vaapi_check_status (status, "vaGetSurfaceBufferWl()"))
            return FALSE;
    }

    /* Wait for the previous frame to complete redraw */
    if (!gst_vaapi_window_wayland_sync (window)) {
        wl_buffer_destroy (buffer);
        return !priv->sync_failed;
    }

    frame = frame_state_new (window);
    if (!frame)
        return FALSE;
    g_atomic_pointer_set (&priv->last_frame, frame);
    g_atomic_int_inc (&priv->num_frames_pending);

    if (need_vpp && priv->use_vpp) {
        frame->surface = surface;
        frame->surface_pool = gst_vaapi_video_pool_ref (priv->surface_pool);
    }

    /* XXX: attach to the specified target rectangle */
    GST_VAAPI_OBJECT_LOCK_DISPLAY (window);
    wl_surface_attach (priv->surface, buffer, 0, 0);
    wl_surface_damage (priv->surface, 0, 0, width, height);

    if (priv->opaque_region) {
        wl_surface_set_opaque_region (priv->surface, priv->opaque_region);
        wl_region_destroy (priv->opaque_region);
        priv->opaque_region = NULL;
    }

    wl_proxy_set_queue ((struct wl_proxy *) buffer, priv->event_queue);
    wl_buffer_add_listener (buffer, &frame_buffer_listener, frame);

    frame->callback = wl_surface_frame (priv->surface);
    wl_callback_add_listener (frame->callback, &frame_callback_listener, frame);

    wl_surface_commit (priv->surface);
    wl_display_flush (wl_display);
    GST_VAAPI_OBJECT_UNLOCK_DISPLAY (window);
    return TRUE;
}
Пример #26
0
/**
 * 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
}