Add VA decoder helpers.
authorGwenole Beauchesne <gwenole.beauchesne@intel.com>
Fri, 5 Aug 2011 09:53:50 +0000 (11:53 +0200)
committerGwenole Beauchesne <gwenole.beauchesne@intel.com>
Mon, 16 Jan 2012 10:40:50 +0000 (11:40 +0100)
gst-libs/gst/vaapi/gstvaapidecoder.c
gst-libs/gst/vaapi/gstvaapidecoder_priv.h

index fead8f0..e1b45df 100644 (file)
@@ -26,7 +26,6 @@
  */
 
 #include "config.h"
-#include <assert.h>
 #include <string.h>
 #include "gstvaapicompat.h"
 #include "gstvaapidecoder.h"
@@ -44,6 +43,7 @@ enum {
 
     PROP_DISPLAY,
     PROP_CAPS,
+    PROP_CODEC_INFO,
 };
 
 static void
@@ -202,6 +202,20 @@ set_caps(GstVaapiDecoder *decoder, GstCaps *caps)
         set_codec_data(decoder, gst_value_get_buffer(v_codec_data));
 }
 
+static inline void
+set_codec_info(GstVaapiDecoder *decoder, GstVaapiCodecInfo *codec_info)
+{
+    GstVaapiDecoderPrivate * const priv = decoder->priv;
+
+    if (codec_info) {
+        priv->codec_info = *codec_info;
+        if (!priv->codec_info.pic_size)
+            priv->codec_info.pic_size = sizeof(GstVaapiPicture);
+        if (!priv->codec_info.slice_size)
+            priv->codec_info.slice_size = sizeof(GstVaapiSlice);
+    }
+}
+
 static void
 clear_queue(GQueue *q, GDestroyNotify destroy)
 {
@@ -225,6 +239,7 @@ gst_vaapi_decoder_finalize(GObject *object)
     if (priv->context) {
         g_object_unref(priv->context);
         priv->context = NULL;
+        priv->va_context = VA_INVALID_ID;
     }
  
     if (priv->buffers) {
@@ -242,6 +257,7 @@ gst_vaapi_decoder_finalize(GObject *object)
     if (priv->display) {
         g_object_unref(priv->display);
         priv->display = NULL;
+        priv->va_display = NULL;
     }
 
     G_OBJECT_CLASS(gst_vaapi_decoder_parent_class)->finalize(object);
@@ -261,10 +277,17 @@ gst_vaapi_decoder_set_property(
     switch (prop_id) {
     case PROP_DISPLAY:
         priv->display = g_object_ref(g_value_get_object(value));
+        if (priv->display)
+            priv->va_display = gst_vaapi_display_get_display(priv->display);
+        else
+            priv->va_display = NULL;
         break;
     case PROP_CAPS:
         set_caps(decoder, g_value_get_pointer(value));
         break;
+    case PROP_CODEC_INFO:
+        set_codec_info(decoder, g_value_get_pointer(value));
+        break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
         break;
@@ -326,6 +349,14 @@ gst_vaapi_decoder_class_init(GstVaapiDecoderClass *klass)
                               "Decoder caps",
                               "The decoder caps",
                               G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
+
+    g_object_class_install_property
+        (object_class,
+         PROP_CODEC_INFO,
+         g_param_spec_pointer("codec-info",
+                              "Codec info",
+                              "The codec info",
+                              G_PARAM_WRITABLE|G_PARAM_CONSTRUCT_ONLY));
 }
 
 static void
@@ -334,7 +365,10 @@ gst_vaapi_decoder_init(GstVaapiDecoder *decoder)
     GstVaapiDecoderPrivate *priv = GST_VAAPI_DECODER_GET_PRIVATE(decoder);
 
     decoder->priv               = priv;
+    priv->display               = NULL;
+    priv->va_display            = NULL;
     priv->context               = NULL;
+    priv->va_context            = VA_INVALID_ID;
     priv->caps                  = NULL;
     priv->codec                 = 0;
     priv->codec_data            = NULL;
@@ -527,7 +561,11 @@ gst_vaapi_decoder_ensure_context(
         width,
         height
     );
-    return priv->context != NULL;
+    if (!priv->context)
+        return FALSE;
+
+    priv->va_context = gst_vaapi_context_get_id(priv->context);
+    return TRUE;
 }
 
 gboolean
@@ -573,3 +611,281 @@ gst_vaapi_decoder_push_surface_proxy(
 {
     return push_surface(decoder, g_object_ref(proxy), timestamp);
 }
+
+static void
+destroy_iq_matrix(GstVaapiDecoder *decoder, GstVaapiIqMatrix *iq_matrix);
+
+static void
+destroy_slice(GstVaapiDecoder *decoder, GstVaapiSlice *slice);
+
+static void
+destroy_slice_cb(gpointer data, gpointer user_data)
+{
+    GstVaapiDecoder * const decoder = GST_VAAPI_DECODER(user_data);
+    GstVaapiSlice * const   slice   = data;
+
+    destroy_slice(decoder, slice);
+}
+
+static void
+destroy_picture(GstVaapiDecoder *decoder, GstVaapiPicture *picture)
+{
+    GstVaapiDecoderPrivate * const priv = decoder->priv;
+
+    if (picture->slices) {
+        g_ptr_array_foreach(picture->slices, destroy_slice_cb, decoder);
+        g_ptr_array_free(picture->slices, TRUE);
+        picture->slices = NULL;
+    }
+
+    if (picture->iq_matrix) {
+        destroy_iq_matrix(decoder, picture->iq_matrix);
+        picture->iq_matrix = NULL;
+    }
+
+    picture->surface = NULL;
+    picture->surface_id = VA_INVALID_ID;
+
+    vaapi_destroy_buffer(priv->va_display, &picture->param_id);
+    picture->param = NULL;
+    g_slice_free1(priv->codec_info.pic_size, picture);
+}
+
+static GstVaapiPicture *
+create_picture(GstVaapiDecoder *decoder)
+{
+    GstVaapiDecoderPrivate * const priv = decoder->priv;
+    GstVaapiPicture *picture;
+
+    picture = g_slice_alloc(priv->codec_info.pic_size);
+    if (!picture)
+        return NULL;
+
+    picture->type       = GST_VAAPI_PICTURE_TYPE_NONE;
+    picture->flags      = 0;
+    picture->surface_id = VA_INVALID_ID;
+    picture->surface    = NULL;
+    picture->param_id   = VA_INVALID_ID;
+    picture->param      = NULL;
+    picture->slices     = NULL;
+    picture->iq_matrix  = NULL;
+    picture->pts        = GST_CLOCK_TIME_NONE;
+
+    picture->surface = gst_vaapi_context_get_surface(priv->context);
+    if (!picture->surface)
+        goto error;
+    picture->surface_id = gst_vaapi_surface_get_id(picture->surface);
+
+    picture->param = vaapi_create_buffer(
+        priv->va_display,
+        priv->va_context,
+        VAPictureParameterBufferType,
+        priv->codec_info.pic_param_size,
+        &picture->param_id
+    );
+    if (!picture->param)
+        goto error;
+
+    picture->slices = g_ptr_array_new();
+    if (!picture->slices)
+        goto error;
+    return picture;
+
+error:
+    destroy_picture(priv->va_display, picture);
+    return NULL;
+}
+
+GstVaapiPicture *
+gst_vaapi_decoder_new_picture(GstVaapiDecoder *decoder)
+{
+    return create_picture(decoder);
+}
+
+void
+gst_vaapi_decoder_free_picture(GstVaapiDecoder *decoder, GstVaapiPicture *picture)
+{
+    destroy_picture(decoder, picture);
+}
+
+static void
+destroy_iq_matrix(GstVaapiDecoder *decoder, GstVaapiIqMatrix *iq_matrix)
+{
+    GstVaapiDecoderPrivate * const priv = decoder->priv;
+
+    vaapi_destroy_buffer(priv->va_display, &iq_matrix->param_id);
+    iq_matrix->param = NULL;
+    g_slice_free(GstVaapiIqMatrix, iq_matrix);
+}
+
+static GstVaapiIqMatrix *
+create_iq_matrix(GstVaapiDecoder *decoder)
+{
+    GstVaapiDecoderPrivate * const priv = decoder->priv;
+    GstVaapiIqMatrix *iq_matrix;
+
+    iq_matrix = g_slice_new(GstVaapiIqMatrix);
+    if (!iq_matrix)
+        return NULL;
+
+    iq_matrix->param_id = VA_INVALID_ID;
+
+    iq_matrix->param = vaapi_create_buffer(
+        priv->va_display,
+        priv->va_context,
+        VAIQMatrixBufferType,
+        priv->codec_info.iq_matrix_size,
+        &iq_matrix->param_id
+    );
+    if (!iq_matrix->param)
+        goto error;
+    return iq_matrix;
+
+error:
+    destroy_iq_matrix(decoder, iq_matrix);
+    return NULL;
+}
+
+GstVaapiIqMatrix *
+gst_vaapi_decoder_new_iq_matrix(GstVaapiDecoder *decoder)
+{
+    return create_iq_matrix(decoder);
+}
+
+static void
+destroy_slice(GstVaapiDecoder *decoder, GstVaapiSlice *slice)
+{
+    GstVaapiDecoderPrivate * const priv = decoder->priv;
+
+    vaapi_destroy_buffer(priv->va_display, &slice->data_id);
+    vaapi_destroy_buffer(priv->va_display, &slice->param_id);
+    slice->param = NULL;
+    g_slice_free1(priv->codec_info.slice_size, slice);
+}
+
+static GstVaapiSlice *
+create_slice(GstVaapiDecoder *decoder, guchar *buf, guint buf_size)
+{
+    GstVaapiDecoderPrivate * const priv = decoder->priv;
+    GstVaapiSlice *slice;
+    VASliceParameterBufferBase *slice_param;
+    guchar *data;
+
+    slice = g_slice_alloc(priv->codec_info.slice_size);
+    if (!slice)
+        return NULL;
+
+    slice->data_id  = VA_INVALID_ID;
+    slice->param_id = VA_INVALID_ID;
+
+    data = vaapi_create_buffer(
+        priv->va_display,
+        priv->va_context,
+        VASliceDataBufferType,
+        buf_size,
+        &slice->data_id
+    );
+    if (!data)
+        goto error;
+    memcpy(data, buf, buf_size);
+    vaapi_unmap_buffer(priv->va_display, slice->data_id, NULL);
+
+    slice->param = vaapi_create_buffer(
+        priv->va_display,
+        priv->va_context,
+        VASliceParameterBufferType,
+        priv->codec_info.slice_param_size,
+        &slice->param_id
+    );
+    if (!slice->param)
+        goto error;
+
+    slice_param                    = slice->param;
+    slice_param->slice_data_size   = buf_size;
+    slice_param->slice_data_offset = 0;
+    slice_param->slice_data_flag   = VA_SLICE_DATA_FLAG_ALL;
+    return slice;
+
+error:
+    destroy_slice(decoder, slice);
+    return NULL;
+}
+
+GstVaapiSlice *
+gst_vaapi_decoder_new_slice(
+    GstVaapiDecoder *decoder,
+    GstVaapiPicture *picture,
+    guchar          *buf,
+    guint            buf_size
+)
+{
+    GstVaapiSlice *slice;
+
+    slice = create_slice(decoder, buf, buf_size);
+    if (!slice)
+        return NULL;
+    g_ptr_array_add(picture->slices, slice);
+    return slice;
+}
+
+gboolean
+gst_vaapi_decoder_decode_picture(
+    GstVaapiDecoder *decoder,
+    GstVaapiPicture *picture
+)
+{
+    GstVaapiDecoderPrivate * const priv = decoder->priv;
+    GstVaapiIqMatrix * const iq_matrix = picture->iq_matrix;
+    GstVaapiSlice *slice;
+    VABufferID va_buffers[3];
+    guint i, n_va_buffers = 0;
+    VAStatus status;
+
+    GST_DEBUG("decode picture 0x%08x", gst_vaapi_surface_get_id(picture->surface));
+
+    vaapi_unmap_buffer(priv->va_display, picture->param_id, &picture->param);
+    va_buffers[n_va_buffers++] = picture->param_id;
+
+    if (iq_matrix) {
+        vaapi_unmap_buffer(priv->va_display, iq_matrix->param_id, &iq_matrix->param);
+        va_buffers[n_va_buffers++] = iq_matrix->param_id;
+    }
+
+    status = vaBeginPicture(
+        priv->va_display,
+        priv->va_context,
+        picture->surface_id
+    );
+    if (!vaapi_check_status(status, "vaBeginPicture()"))
+        return FALSE;
+
+    status = vaRenderPicture(
+        priv->va_display,
+        priv->va_context,
+        va_buffers, n_va_buffers
+    );
+    if (!vaapi_check_status(status, "vaRenderPicture()"))
+        return FALSE;
+
+    for (i = 0; i < picture->slices->len; i++) {
+        slice = g_ptr_array_index(picture->slices, i);
+
+        vaapi_unmap_buffer(priv->va_display, slice->param_id, NULL);
+        va_buffers[0] = slice->param_id;
+        va_buffers[1] = slice->data_id;
+        n_va_buffers  = 2;
+
+        status = vaRenderPicture(
+            priv->va_display,
+            priv->va_context,
+            va_buffers, n_va_buffers
+        );
+        if (!vaapi_check_status(status, "vaRenderPicture()"))
+            return FALSE;
+    }
+
+    status = vaEndPicture(priv->va_display, priv->va_context);
+    if (!vaapi_check_status(status, "vaEndPicture()"))
+        return FALSE;
+    return TRUE;
+}
index d6e696f..d4cb9bb 100644 (file)
@@ -108,12 +108,74 @@ G_BEGIN_DECLS
                                  GST_VAAPI_TYPE_DECODER,        \
                                  GstVaapiDecoderPrivate))
 
+typedef enum _GstVaapiPictureType       GstVaapiPictureType;
+typedef struct _GstVaapiCodecInfo       GstVaapiCodecInfo;
+typedef struct _GstVaapiPicture         GstVaapiPicture;
+typedef struct _GstVaapiSlice           GstVaapiSlice;
+typedef struct _GstVaapiIqMatrix        GstVaapiIqMatrix;
+
+enum _GstVaapiPictureType {
+    GST_VAAPI_PICTURE_TYPE_NONE = 0,        // Undefined
+    GST_VAAPI_PICTURE_TYPE_I,               // Intra
+    GST_VAAPI_PICTURE_TYPE_P,               // Predicted
+    GST_VAAPI_PICTURE_TYPE_B,               // Bi-directional predicted
+    GST_VAAPI_PICTURE_TYPE_S,               // S(GMC)-VOP (MPEG-4)
+    GST_VAAPI_PICTURE_TYPE_SI,              // Switching Intra
+    GST_VAAPI_PICTURE_TYPE_SP,              // Switching Predicted
+    GST_VAAPI_PICTURE_TYPE_BI,              // BI type (VC-1)
+};
+
+enum {
+    GST_VAAPI_PICTURE_SKIPPED   = 1 << 0,   // Skipped frame
+    GST_VAAPI_PICTURE_REFERENCE = 1 << 1,   // Reference frame
+};
+
+#define GST_VAAPI_PICTURE(picture) \
+    ((GstVaapiPicture *)(picture))
+
+#define GST_VAAPI_PICTURE_IS_REFERENCE(picture) \
+    ((GST_VAAPI_PICTURE(picture)->flags & GST_VAAPI_PICTURE_REFERENCE) != 0)
+
+struct _GstVaapiCodecInfo {
+    guint               pic_size;           // GstVaapiPicture size
+    guint               slice_size;         // GstVaapiSlice size
+    guint               pic_param_size;     // VAPictureParameterBuffer size
+    guint               slice_param_size;   // VASliceParameterBuffer size
+    guint               iq_matrix_size;     // VAIQMatrixBuffer size
+};
+
+struct _GstVaapiPicture {
+    GstVaapiPictureType type;
+    guint               flags;
+    VASurfaceID         surface_id;
+    GstVaapiSurface    *surface;
+    VABufferID          param_id;
+    void               *param;
+    GPtrArray          *slices;
+    GstVaapiIqMatrix   *iq_matrix;
+    GstClockTime        pts;
+};
+
+struct _GstVaapiSlice {
+    VABufferID          param_id;
+    void               *param;
+    VABufferID          data_id;
+};
+
+struct _GstVaapiIqMatrix {
+    VABufferID          param_id;
+    void               *param;
+};
+
 struct _GstVaapiDecoderPrivate {
     GstVaapiDisplay    *display;
+    VADisplay           va_display;
     GstVaapiContext    *context;
+    VAContextID         va_context;
     GstCaps            *caps;
     GstVaapiCodec       codec;
     GstBuffer          *codec_data;
+    GstVaapiCodecInfo   codec_info;
     guint               width;
     guint               height;
     guint               fps_n;
@@ -176,6 +238,32 @@ gst_vaapi_decoder_push_surface_proxy(
     GstClockTime          timestamp
 ) attribute_hidden;
 
+GstVaapiPicture *
+gst_vaapi_decoder_new_picture(GstVaapiDecoder *decoder)
+    attribute_hidden;
+
+void
+gst_vaapi_decoder_free_picture(GstVaapiDecoder *decoder, GstVaapiPicture *picture)
+    attribute_hidden;
+
+GstVaapiIqMatrix *
+gst_vaapi_decoder_new_iq_matrix(GstVaapiDecoder *decoder)
+    attribute_hidden;
+
+GstVaapiSlice *
+gst_vaapi_decoder_new_slice(
+    GstVaapiDecoder *decoder,
+    GstVaapiPicture *picture,
+    guchar          *buf,
+    guint            buf_size
+) attribute_hidden;
+
+gboolean
+gst_vaapi_decoder_decode_picture(
+    GstVaapiDecoder *decoder,
+    GstVaapiPicture *picture
+) attribute_hidden;
+
 G_END_DECLS
 
 #endif /* GST_VAAPI_DECODER_PRIV_H */