mpeg2: fix construction of reference frames list (SNB, IVB).
authorGwenole Beauchesne <gwenole.beauchesne@intel.com>
Thu, 15 Mar 2012 13:41:47 +0000 (14:41 +0100)
committerGwenole Beauchesne <gwenole.beauchesne@intel.com>
Sun, 18 Mar 2012 08:10:11 +0000 (09:10 +0100)
Fix construction of reference frames list for interlaced streams.
In this case, the array is indexed by frame store ID >> 1 where
bit 0 of frame store ID represents top (0) or bottom (1) field.

Besides, current render target can also be used as a reference
while decoding the second field.

Signed-off-by: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
src/gen6_mfd.c
src/gen7_mfd.c
src/i965_decoder_utils.c
src/i965_decoder_utils.h
src/i965_defines.h

index 367294f..51426ba 100644 (file)
@@ -1084,30 +1084,17 @@ gen6_mfd_mpeg2_decode_init(VADriverContextP ctx,
     VAPictureParameterBufferMPEG2 *pic_param;
     struct i965_driver_data *i965 = i965_driver_data(ctx);
     struct object_surface *obj_surface;
-    int i;
     dri_bo *bo;
 
     assert(decode_state->pic_param && decode_state->pic_param->buffer);
     pic_param = (VAPictureParameterBufferMPEG2 *)decode_state->pic_param->buffer;
 
-    /* reference picture */
-    obj_surface = SURFACE(pic_param->forward_reference_picture);
-
-    if (obj_surface && obj_surface->bo)
-        gen6_mfd_context->reference_surface[0].surface_id = pic_param->forward_reference_picture;
-    else
-        gen6_mfd_context->reference_surface[0].surface_id = VA_INVALID_ID;
-
-    obj_surface = SURFACE(pic_param->backward_reference_picture);
-
-    if (obj_surface && obj_surface->bo)
-        gen6_mfd_context->reference_surface[1].surface_id = pic_param->backward_reference_picture;
-    else
-        gen6_mfd_context->reference_surface[1].surface_id = gen6_mfd_context->reference_surface[0].surface_id;
-
-    /* must do so !!! */
-    for (i = 2; i < ARRAY_ELEMS(gen6_mfd_context->reference_surface); i++)
-        gen6_mfd_context->reference_surface[i].surface_id = gen6_mfd_context->reference_surface[i % 2].surface_id;
+    mpeg2_set_reference_surfaces(
+        ctx,
+        gen6_mfd_context->reference_surface,
+        decode_state,
+        pic_param
+    );
 
     /* Current decoded picture */
     obj_surface = SURFACE(decode_state->current_render_target);
index 6318ab9..6d3e044 100644 (file)
@@ -1032,30 +1032,17 @@ gen7_mfd_mpeg2_decode_init(VADriverContextP ctx,
     VAPictureParameterBufferMPEG2 *pic_param;
     struct i965_driver_data *i965 = i965_driver_data(ctx);
     struct object_surface *obj_surface;
-    int i;
     dri_bo *bo;
 
     assert(decode_state->pic_param && decode_state->pic_param->buffer);
     pic_param = (VAPictureParameterBufferMPEG2 *)decode_state->pic_param->buffer;
 
-    /* reference picture */
-    obj_surface = SURFACE(pic_param->forward_reference_picture);
-
-    if (obj_surface && obj_surface->bo)
-        gen7_mfd_context->reference_surface[0].surface_id = pic_param->forward_reference_picture;
-    else
-        gen7_mfd_context->reference_surface[0].surface_id = VA_INVALID_ID;
-
-    obj_surface = SURFACE(pic_param->backward_reference_picture);
-
-    if (obj_surface && obj_surface->bo)
-        gen7_mfd_context->reference_surface[1].surface_id = pic_param->backward_reference_picture;
-    else
-        gen7_mfd_context->reference_surface[1].surface_id = gen7_mfd_context->reference_surface[0].surface_id;
-
-    /* must do so !!! */
-    for (i = 2; i < ARRAY_ELEMS(gen7_mfd_context->reference_surface); i++)
-        gen7_mfd_context->reference_surface[i].surface_id = gen7_mfd_context->reference_surface[i % 2].surface_id;
+    mpeg2_set_reference_surfaces(
+        ctx,
+        gen7_mfd_context->reference_surface,
+        decode_state,
+        pic_param
+    );
 
     /* Current decoded picture */
     obj_surface = SURFACE(decode_state->current_render_target);
index 6985c36..047fa62 100644 (file)
 #include "i965_drv_video.h"
 #include "i965_defines.h"
 
+/* Set reference surface if backing store exists */
+static inline int
+set_ref_frame(
+    struct i965_driver_data *i965,
+    GenFrameStore           *ref_frame,
+    VASurfaceID              va_surface
+)
+{
+    struct object_surface *obj_surface;
+
+    if (va_surface == VA_INVALID_ID)
+        return 0;
+
+    obj_surface = SURFACE(va_surface);
+    if (!obj_surface || !obj_surface->bo)
+        return 0;
+
+    ref_frame->surface_id = va_surface;
+    return 1;
+}
+
 /* Check wether codec layer incorrectly fills in slice_vertical_position */
 int
 mpeg2_wa_slice_vertical_position(
@@ -70,6 +91,71 @@ mpeg2_wa_slice_vertical_position(
     return 0;
 }
 
+/* Build MPEG-2 reference frames array */
+void
+mpeg2_set_reference_surfaces(
+    VADriverContextP               ctx,
+    GenFrameStore                  ref_frames[MAX_GEN_REFERENCE_FRAMES],
+    struct decode_state           *decode_state,
+    VAPictureParameterBufferMPEG2 *pic_param
+)
+{
+    struct i965_driver_data * const i965 = i965_driver_data(ctx);
+    VASurfaceID va_surface;
+    unsigned pic_structure, is_second_field, n = 0;
+
+    pic_structure = pic_param->picture_coding_extension.bits.picture_structure;
+    is_second_field = pic_structure != MPEG_FRAME &&
+        !pic_param->picture_coding_extension.bits.is_first_field;
+
+    /* Reference frames are indexed by frame store ID  (0:top, 1:bottom) */
+    switch (pic_param->picture_coding_type) {
+    case MPEG_P_PICTURE:
+        if (is_second_field && pic_structure == MPEG_BOTTOM_FIELD) {
+            va_surface = decode_state->current_render_target;
+            n += set_ref_frame(i965, &ref_frames[n], va_surface);
+        }
+        va_surface = pic_param->forward_reference_picture;
+        n += set_ref_frame(i965, &ref_frames[n], va_surface);
+        break;
+
+    case MPEG_B_PICTURE:
+        va_surface = pic_param->forward_reference_picture;
+        n += set_ref_frame(i965, &ref_frames[n], va_surface);
+        va_surface = pic_param->backward_reference_picture;
+        n += set_ref_frame(i965, &ref_frames[n], va_surface);
+        break;
+    }
+
+    while (n != 2)
+        ref_frames[n++].surface_id = VA_INVALID_ID;
+
+    if (pic_param->picture_coding_extension.bits.progressive_frame)
+        return;
+
+    /* Bottom field pictures used as reference */
+    switch (pic_param->picture_coding_type) {
+    case MPEG_P_PICTURE:
+        if (is_second_field && pic_structure == MPEG_TOP_FIELD) {
+            va_surface = decode_state->current_render_target;
+            n += set_ref_frame(i965, &ref_frames[n], va_surface);
+        }
+        va_surface = pic_param->forward_reference_picture;
+        n += set_ref_frame(i965, &ref_frames[n], va_surface);
+        break;
+
+    case MPEG_B_PICTURE:
+        va_surface = pic_param->forward_reference_picture;
+        n += set_ref_frame(i965, &ref_frames[n], va_surface);
+        va_surface = pic_param->backward_reference_picture;
+        n += set_ref_frame(i965, &ref_frames[n], va_surface);
+        break;
+    }
+
+    while (n != 4)
+        ref_frames[n++].surface_id = VA_INVALID_ID;
+}
+
 /* Generate flat scaling matrices for H.264 decoding */
 void
 avc_gen_default_iq_matrix(VAIQMatrixBufferH264 *iq_matrix)
index 1c624c0..0d86523 100644 (file)
@@ -36,6 +36,14 @@ mpeg2_wa_slice_vertical_position(
 );
 
 void
+mpeg2_set_reference_surfaces(
+    VADriverContextP               ctx,
+    GenFrameStore                  ref_frames[MAX_GEN_REFERENCE_FRAMES],
+    struct decode_state           *decode_state,
+    VAPictureParameterBufferMPEG2 *pic_param
+);
+
+void
 avc_gen_default_iq_matrix(VAIQMatrixBufferH264 *iq_matrix);
 
 unsigned int
index d530a5b..b58260a 100644 (file)
 #define MFX_SURFACE_PLANAR_422_8        6
 #define MFX_SURFACE_MONOCHROME          12
 
+#define MPEG_I_PICTURE          1
+#define MPEG_P_PICTURE          2
+#define MPEG_B_PICTURE          3
+
 #define MPEG_TOP_FIELD         1
 #define MPEG_BOTTOM_FIELD      2
 #define MPEG_FRAME             3