vc1: fix bitplanes decoding.
authorGwenole Beauchesne <gwenole.beauchesne@intel.com>
Tue, 4 Oct 2011 15:51:51 +0000 (17:51 +0200)
committerGwenole Beauchesne <gwenole.beauchesne@intel.com>
Mon, 16 Jan 2012 10:40:51 +0000 (11:40 +0100)
gst-libs/gst/vaapi/gstvaapidecoder.c
gst-libs/gst/vaapi/gstvaapidecoder_priv.h
gst-libs/gst/vaapi/gstvaapidecoder_vc1.c

index e1b45df..adb1b18 100644 (file)
@@ -616,6 +616,9 @@ static void
 destroy_iq_matrix(GstVaapiDecoder *decoder, GstVaapiIqMatrix *iq_matrix);
 
 static void
+destroy_bitplane(GstVaapiDecoder *decoder, GstVaapiBitPlane *bitplane);
+
+static void
 destroy_slice(GstVaapiDecoder *decoder, GstVaapiSlice *slice);
 
 static void
@@ -643,6 +646,11 @@ destroy_picture(GstVaapiDecoder *decoder, GstVaapiPicture *picture)
         picture->iq_matrix = NULL;
     }
 
+    if (picture->bitplane) {
+        destroy_bitplane(decoder, picture->bitplane);
+        picture->bitplane = NULL;
+    }
+
     picture->surface = NULL;
     picture->surface_id = VA_INVALID_ID;
 
@@ -669,6 +677,7 @@ create_picture(GstVaapiDecoder *decoder)
     picture->param      = NULL;
     picture->slices     = NULL;
     picture->iq_matrix  = NULL;
+    picture->bitplane   = NULL;
     picture->pts        = GST_CLOCK_TIME_NONE;
 
     picture->surface = gst_vaapi_context_get_surface(priv->context);
@@ -753,6 +762,50 @@ gst_vaapi_decoder_new_iq_matrix(GstVaapiDecoder *decoder)
 }
 
 static void
+destroy_bitplane(GstVaapiDecoder *decoder, GstVaapiBitPlane *bitplane)
+{
+    GstVaapiDecoderPrivate * const priv = decoder->priv;
+
+    vaapi_destroy_buffer(priv->va_display, &bitplane->data_id);
+    bitplane->data = NULL;
+    g_slice_free(GstVaapiBitPlane, bitplane);
+}
+
+static GstVaapiBitPlane *
+create_bitplane(GstVaapiDecoder *decoder, guint size)
+{
+    GstVaapiDecoderPrivate * const priv = decoder->priv;
+    GstVaapiBitPlane *bitplane;
+
+    bitplane = g_slice_new(GstVaapiBitPlane);
+    if (!bitplane)
+        return NULL;
+
+    bitplane->data_id = VA_INVALID_ID;
+
+    bitplane->data = vaapi_create_buffer(
+        priv->va_display,
+        priv->va_context,
+        VABitPlaneBufferType,
+        size,
+        &bitplane->data_id
+    );
+    if (!bitplane->data)
+        goto error;
+    return bitplane;
+
+error:
+    destroy_bitplane(decoder, bitplane);
+    return NULL;
+}
+
+GstVaapiBitPlane *
+gst_vaapi_decoder_new_bitplane(GstVaapiDecoder *decoder, guint size)
+{
+    return create_bitplane(decoder, size);
+}
+
+static void
 destroy_slice(GstVaapiDecoder *decoder, GstVaapiSlice *slice)
 {
     GstVaapiDecoderPrivate * const priv = decoder->priv;
@@ -836,6 +889,7 @@ gst_vaapi_decoder_decode_picture(
 {
     GstVaapiDecoderPrivate * const priv = decoder->priv;
     GstVaapiIqMatrix * const iq_matrix = picture->iq_matrix;
+    GstVaapiBitPlane * const bitplane = picture->bitplane;
     GstVaapiSlice *slice;
     VABufferID va_buffers[3];
     guint i, n_va_buffers = 0;
@@ -851,6 +905,11 @@ gst_vaapi_decoder_decode_picture(
         va_buffers[n_va_buffers++] = iq_matrix->param_id;
     }
 
+    if (bitplane) {
+        vaapi_unmap_buffer(priv->va_display, bitplane->data_id, (void **)&bitplane->data);
+        va_buffers[n_va_buffers++] = bitplane->data_id;
+    }
+
     status = vaBeginPicture(
         priv->va_display,
         priv->va_context,
index d4cb9bb..478daa8 100644 (file)
@@ -113,6 +113,7 @@ typedef struct _GstVaapiCodecInfo       GstVaapiCodecInfo;
 typedef struct _GstVaapiPicture         GstVaapiPicture;
 typedef struct _GstVaapiSlice           GstVaapiSlice;
 typedef struct _GstVaapiIqMatrix        GstVaapiIqMatrix;
+typedef struct _GstVaapiBitPlane        GstVaapiBitPlane;
 
 enum _GstVaapiPictureType {
     GST_VAAPI_PICTURE_TYPE_NONE = 0,        // Undefined
@@ -153,6 +154,7 @@ struct _GstVaapiPicture {
     void               *param;
     GPtrArray          *slices;
     GstVaapiIqMatrix   *iq_matrix;
+    GstVaapiBitPlane   *bitplane;
     GstClockTime        pts;
 };
 
@@ -167,6 +169,11 @@ struct _GstVaapiIqMatrix {
     void               *param;
 };
 
+struct _GstVaapiBitPlane {
+    VABufferID          data_id;
+    guint8             *data;
+};
+
 struct _GstVaapiDecoderPrivate {
     GstVaapiDisplay    *display;
     VADisplay           va_display;
@@ -250,6 +257,10 @@ GstVaapiIqMatrix *
 gst_vaapi_decoder_new_iq_matrix(GstVaapiDecoder *decoder)
     attribute_hidden;
 
+GstVaapiBitPlane *
+gst_vaapi_decoder_new_bitplane(GstVaapiDecoder *decoder, guint size)
+    attribute_hidden;
+
 GstVaapiSlice *
 gst_vaapi_decoder_new_slice(
     GstVaapiDecoder *decoder,
index a96251d..a344610 100644 (file)
@@ -54,6 +54,7 @@ struct _GstVaapiDecoderVC1Private {
     GstVC1SeqHdr                seq_hdr;
     GstVC1EntryPointHdr         entrypoint_hdr;
     GstVC1FrameHdr              frame_hdr;
+    GstVC1BitPlanes            *bitplanes;
     GstVaapiPicture            *current_picture;
     GstVaapiPicture            *next_picture;
     GstVaapiPicture            *prev_picture;
@@ -117,6 +118,11 @@ gst_vaapi_decoder_vc1_close(GstVaapiDecoderVC1 *decoder)
         priv->sub_buffer = NULL;
     }
 
+    if (priv->bitplanes) {
+        gst_vc1_bitplanes_free(priv->bitplanes);
+        priv->bitplanes = NULL;
+    }
+
     if (priv->tsb) {
         gst_vaapi_tsb_destroy(priv->tsb);
         priv->tsb = NULL;
@@ -133,6 +139,10 @@ gst_vaapi_decoder_vc1_open(GstVaapiDecoderVC1 *decoder, GstBuffer *buffer)
     priv->tsb = gst_vaapi_tsb_new();
     if (!priv->tsb)
         return FALSE;
+
+    priv->bitplanes = gst_vc1_bitplanes_new();
+    if (!priv->bitplanes)
+        return FALSE;
     return TRUE;
 }
 
@@ -584,6 +594,22 @@ has_OVERFLAGS_bitplane(GstVaapiDecoderVC1 *decoder)
             pic->condover == GST_VC1_CONDOVER_SELECT);
 }
 
+static inline void
+pack_bitplanes(GstVaapiBitPlane *bitplane, guint n, const guint8 *bitplanes[3], guint x, guint y, guint stride)
+{
+    const guint dst_index = n / 2;
+    const guint src_index = y * stride + x;
+    guint8 v = 0;
+
+    if (bitplanes[0])
+        v |= bitplanes[0][src_index];
+    if (bitplanes[1])
+        v |= bitplanes[1][src_index] << 1;
+    if (bitplanes[2])
+        v |= bitplanes[2][src_index] << 2;
+    bitplane->data[dst_index] = (bitplane->data[dst_index] << 4) | v;
+}
+
 static gboolean
 fill_picture_structc(GstVaapiDecoderVC1 *decoder, GstVaapiPicture *picture)
 {
@@ -701,6 +727,7 @@ fill_picture_advanced(GstVaapiDecoderVC1 *decoder, GstVaapiPicture *picture)
 static gboolean
 fill_picture(GstVaapiDecoderVC1 *decoder, GstVaapiPicture *picture)
 {
+    GstVaapiDecoder * const base_decoder = GST_VAAPI_DECODER(decoder);
     GstVaapiDecoderVC1Private * const priv = decoder->priv;
     VAPictureParameterBufferVC1 * const pic_param = picture->param;
     GstVC1SeqHdr * const seq_hdr = &priv->seq_hdr;
@@ -759,6 +786,49 @@ fill_picture(GstVaapiDecoderVC1 *decoder, GstVaapiPicture *picture)
     default:
         break;
     }
+
+    if (pic_param->bitplane_present.value) {
+        const guint8 *bitplanes[3];
+        guint x, y, n;
+
+        switch (picture->type) {
+        case GST_VAAPI_PICTURE_TYPE_P:
+            bitplanes[0] = pic_param->bitplane_present.flags.bp_direct_mb  ? priv->bitplanes->directmb  : NULL;
+            bitplanes[1] = pic_param->bitplane_present.flags.bp_skip_mb    ? priv->bitplanes->skipmb    : NULL;
+            bitplanes[2] = pic_param->bitplane_present.flags.bp_mv_type_mb ? priv->bitplanes->mvtypemb  : NULL;
+            break;
+        case GST_VAAPI_PICTURE_TYPE_B:
+            bitplanes[0] = pic_param->bitplane_present.flags.bp_direct_mb  ? priv->bitplanes->directmb  : NULL;
+            bitplanes[1] = pic_param->bitplane_present.flags.bp_skip_mb    ? priv->bitplanes->skipmb    : NULL;
+            bitplanes[2] = NULL; /* XXX: interlaced frame (FORWARD plane) */
+            break;
+        case GST_VAAPI_PICTURE_TYPE_BI:
+        case GST_VAAPI_PICTURE_TYPE_I:
+            bitplanes[0] = NULL; /* XXX: interlaced frame (FIELDTX plane) */
+            bitplanes[1] = pic_param->bitplane_present.flags.bp_ac_pred    ? priv->bitplanes->acpred    : NULL;
+            bitplanes[2] = pic_param->bitplane_present.flags.bp_overflags  ? priv->bitplanes->overflags : NULL;
+            break;
+        default:
+            bitplanes[0] = NULL;
+            bitplanes[1] = NULL;
+            bitplanes[2] = NULL;
+            break;
+        }
+
+        picture->bitplane = gst_vaapi_decoder_new_bitplane(
+            base_decoder,
+            (seq_hdr->mb_width * seq_hdr->mb_height + 1) / 2
+        );
+        if (!picture->bitplane)
+            return FALSE;
+
+        n = 0;
+        for (y = 0; y < seq_hdr->mb_height; y++)
+            for (x = 0; x < seq_hdr->mb_width; x++, n++)
+                pack_bitplanes(picture->bitplane, n, bitplanes, x, y, seq_hdr->mb_stride);
+        if (n & 1) /* move last nibble to the high order */
+            picture->bitplane->data[n/2] <<= 4;
+    }
     return TRUE;
 }
 
@@ -794,8 +864,18 @@ decode_frame(GstVaapiDecoderVC1 *decoder, guchar *buf, guint buf_size)
     }
     picture = priv->current_picture;
 
+    if (!gst_vc1_bitplanes_ensure_size(priv->bitplanes, seq_hdr)) {
+        GST_DEBUG("failed to allocate bitplanes");
+        return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+    }
+
     memset(frame_hdr, 0, sizeof(*frame_hdr));
-    result = gst_vc1_parse_frame_header(buf, buf_size, frame_hdr, seq_hdr, NULL);
+    result = gst_vc1_parse_frame_header(
+        buf, buf_size,
+        frame_hdr,
+        seq_hdr,
+        priv->bitplanes
+    );
     if (result != GST_VC1_PARSER_OK) {
         GST_DEBUG("failed to parse frame layer");
         return get_status(result);