decoder: h264: fix detection of top-field-first (TFF) flag.

Use the SEI pic_timing() message to track the pic_struct variable when
present, or infer it from the regular slice header flags field_pic_flag
and bottom_field_flag. This fixes temporal sequence ordering when the
output pictures are to be displayed.

https://bugzilla.gnome.org/show_bug.cgi?id=739291
This commit is contained in:
Gwenole Beauchesne 2014-11-13 15:00:21 +01:00
parent c4f42114b4
commit 415d5df7ee

View file

@ -369,7 +369,9 @@ gst_vaapi_frame_store_split_fields(GstVaapiFrameStore *fs)
g_return_val_if_fail(fs->num_buffers == 1, FALSE); g_return_val_if_fail(fs->num_buffers == 1, FALSE);
first_field->base.structure = GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD; first_field->base.structure = GST_VAAPI_PICTURE_IS_TFF(first_field) ?
GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD :
GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD;
GST_VAAPI_PICTURE_FLAG_SET(first_field, GST_VAAPI_PICTURE_FLAG_INTERLACED); GST_VAAPI_PICTURE_FLAG_SET(first_field, GST_VAAPI_PICTURE_FLAG_INTERLACED);
second_field = gst_vaapi_picture_h264_new_field(first_field); second_field = gst_vaapi_picture_h264_new_field(first_field);
@ -490,6 +492,7 @@ struct _GstVaapiDecoderH264Private {
guint nal_length_size; guint nal_length_size;
guint mb_width; guint mb_width;
guint mb_height; guint mb_height;
guint pic_structure; // pic_struct (from SEI pic_timing() or inferred)
gint32 field_poc[2]; // 0:TopFieldOrderCnt / 1:BottomFieldOrderCnt gint32 field_poc[2]; // 0:TopFieldOrderCnt / 1:BottomFieldOrderCnt
gint32 poc_msb; // PicOrderCntMsb gint32 poc_msb; // PicOrderCntMsb
gint32 poc_lsb; // pic_order_cnt_lsb (from slice_header()) gint32 poc_lsb; // pic_order_cnt_lsb (from slice_header())
@ -1490,6 +1493,7 @@ decode_current_picture(GstVaapiDecoderH264 *decoder)
if (!is_valid_state(priv->decoder_state, GST_H264_VIDEO_STATE_VALID_PICTURE)) if (!is_valid_state(priv->decoder_state, GST_H264_VIDEO_STATE_VALID_PICTURE))
goto drop_frame; goto drop_frame;
priv->decoder_state = 0; priv->decoder_state = 0;
priv->pic_structure = GST_H264_SEI_PIC_STRUCT_FRAME;
if (!picture) if (!picture)
return GST_VAAPI_DECODER_STATUS_SUCCESS; return GST_VAAPI_DECODER_STATUS_SUCCESS;
@ -1510,6 +1514,7 @@ error:
drop_frame: drop_frame:
priv->decoder_state = 0; priv->decoder_state = 0;
priv->pic_structure = GST_H264_SEI_PIC_STRUCT_FRAME;
return GST_VAAPI_DECODER_STATUS_DROP_FRAME; return GST_VAAPI_DECODER_STATUS_DROP_FRAME;
} }
@ -1705,6 +1710,34 @@ decode_pps(GstVaapiDecoderH264 *decoder, GstVaapiDecoderUnit *unit)
return GST_VAAPI_DECODER_STATUS_SUCCESS; return GST_VAAPI_DECODER_STATUS_SUCCESS;
} }
static GstVaapiDecoderStatus
decode_sei(GstVaapiDecoderH264 *decoder, GstVaapiDecoderUnit *unit)
{
GstVaapiDecoderH264Private * const priv = &decoder->priv;
GstVaapiParserInfoH264 * const pi = unit->parsed_info;
guint i;
GST_DEBUG("decode SEI messages");
for (i = 0; i < pi->data.sei->len; i++) {
const GstH264SEIMessage * const sei =
&g_array_index(pi->data.sei, GstH264SEIMessage, i);
switch (sei->payloadType) {
case GST_H264_SEI_PIC_TIMING: {
const GstH264PicTiming * const pic_timing =
&sei->payload.pic_timing;
if (pic_timing->pic_struct_present_flag)
priv->pic_structure = pic_timing->pic_struct;
break;
}
default:
break;
}
}
return GST_VAAPI_DECODER_STATUS_SUCCESS;
}
static GstVaapiDecoderStatus static GstVaapiDecoderStatus
decode_sequence_end(GstVaapiDecoderH264 *decoder) decode_sequence_end(GstVaapiDecoderH264 *decoder)
{ {
@ -2881,14 +2914,28 @@ init_picture(
} }
/* Initialize picture structure */ /* Initialize picture structure */
if (!slice_hdr->field_pic_flag) if (slice_hdr->field_pic_flag) {
base_picture->structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME;
else {
GST_VAAPI_PICTURE_FLAG_SET(picture, GST_VAAPI_PICTURE_FLAG_INTERLACED); GST_VAAPI_PICTURE_FLAG_SET(picture, GST_VAAPI_PICTURE_FLAG_INTERLACED);
if (!slice_hdr->bottom_field_flag) priv->pic_structure = slice_hdr->bottom_field_flag ?
base_picture->structure = GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD; GST_H264_SEI_PIC_STRUCT_BOTTOM_FIELD :
else GST_H264_SEI_PIC_STRUCT_TOP_FIELD;
base_picture->structure = GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD; }
base_picture->structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME;
switch (priv->pic_structure) {
case GST_H264_SEI_PIC_STRUCT_TOP_FIELD:
base_picture->structure = GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD;
if (GST_VAAPI_PICTURE_IS_FIRST_FIELD(picture))
GST_VAAPI_PICTURE_FLAG_SET(picture, GST_VAAPI_PICTURE_FLAG_TFF);
break;
case GST_H264_SEI_PIC_STRUCT_BOTTOM_FIELD:
base_picture->structure = GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD;
break;
case GST_H264_SEI_PIC_STRUCT_TOP_BOTTOM_TOP:
case GST_H264_SEI_PIC_STRUCT_TOP_BOTTOM:
if (GST_VAAPI_PICTURE_IS_FIRST_FIELD(picture))
GST_VAAPI_PICTURE_FLAG_SET(picture, GST_VAAPI_PICTURE_FLAG_TFF);
break;
} }
picture->structure = base_picture->structure; picture->structure = base_picture->structure;
@ -3781,7 +3828,7 @@ decode_unit(GstVaapiDecoderH264 *decoder, GstVaapiDecoderUnit *unit)
status = decode_sequence_end(decoder); status = decode_sequence_end(decoder);
break; break;
case GST_H264_NAL_SEI: case GST_H264_NAL_SEI:
status = GST_VAAPI_DECODER_STATUS_SUCCESS; status = decode_sei(decoder, unit);
break; break;
default: default:
GST_WARNING("unsupported NAL unit type %d", pi->nalu.type); GST_WARNING("unsupported NAL unit type %d", pi->nalu.type);