summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Dröge <sebastian@centricular.com>2016-09-29 15:35:01 +0300
committerSebastian Dröge <sebastian@centricular.com>2016-11-01 20:42:52 +0200
commit5e61a8999fd7367cc02ff7f080d33d824af78474 (patch)
tree4be8d391488ee041232bb2d34fdeb40717533e71
parentd2e65754b35474aff4e9bb2bcd309bfc6ea37857 (diff)
downloadgst-libav-5e61a8999fd7367cc02ff7f080d33d824af78474.tar.gz
avviddec: Use interlaced-mode=interleaved and set field-order if possible
https://bugzilla.gnome.org/show_bug.cgi?id=771376
-rw-r--r--ext/libav/gstavviddec.c68
-rw-r--r--ext/libav/gstavviddec.h3
2 files changed, 65 insertions, 6 deletions
diff --git a/ext/libav/gstavviddec.c b/ext/libav/gstavviddec.c
index 604c8a3..6ccb82a 100644
--- a/ext/libav/gstavviddec.c
+++ b/ext/libav/gstavviddec.c
@@ -433,6 +433,9 @@ gst_ffmpegviddec_set_format (GstVideoDecoder * decoder,
ffmpegdec->pic_height = 0;
ffmpegdec->pic_par_n = 0;
ffmpegdec->pic_par_d = 0;
+ ffmpegdec->pic_interlaced = 0;
+ ffmpegdec->pic_field_order = 0;
+ ffmpegdec->pic_field_order_changed = FALSE;
ffmpegdec->ctx_ticks = 0;
ffmpegdec->ctx_time_n = 0;
ffmpegdec->ctx_time_d = 0;
@@ -881,12 +884,22 @@ no_frame:
static gboolean
picture_changed (GstFFMpegVidDec * ffmpegdec, AVFrame * picture)
{
+ gint pic_field_order = 0;
+
+ if (picture->interlaced_frame) {
+ if (picture->repeat_pict)
+ pic_field_order |= GST_VIDEO_BUFFER_FLAG_RFF;
+ if (picture->top_field_first)
+ pic_field_order |= GST_VIDEO_BUFFER_FLAG_TFF;
+ }
+
return !(ffmpegdec->pic_width == picture->width
&& ffmpegdec->pic_height == picture->height
&& ffmpegdec->pic_pix_fmt == picture->format
&& ffmpegdec->pic_par_n == picture->sample_aspect_ratio.num
&& ffmpegdec->pic_par_d == picture->sample_aspect_ratio.den
- && ffmpegdec->pic_interlaced == picture->interlaced_frame);
+ && ffmpegdec->pic_interlaced == picture->interlaced_frame
+ && ffmpegdec->pic_field_order == pic_field_order);
}
static gboolean
@@ -901,6 +914,15 @@ static gboolean
update_video_context (GstFFMpegVidDec * ffmpegdec, AVCodecContext * context,
AVFrame * picture)
{
+ gint pic_field_order = 0;
+
+ if (picture->interlaced_frame) {
+ if (picture->repeat_pict)
+ pic_field_order |= GST_VIDEO_BUFFER_FLAG_RFF;
+ if (picture->top_field_first)
+ pic_field_order |= GST_VIDEO_BUFFER_FLAG_TFF;
+ }
+
if (!picture_changed (ffmpegdec, picture)
&& !context_changed (ffmpegdec, context))
return FALSE;
@@ -921,7 +943,21 @@ update_video_context (GstFFMpegVidDec * ffmpegdec, AVCodecContext * context,
ffmpegdec->pic_height = picture->height;
ffmpegdec->pic_par_n = picture->sample_aspect_ratio.num;
ffmpegdec->pic_par_d = picture->sample_aspect_ratio.den;
+
+ /* Remember if we have interlaced content and the field order changed
+ * at least once. If that happens, we must be interlaced-mode=mixed
+ */
+ if (ffmpegdec->pic_field_order_changed ||
+ (ffmpegdec->pic_field_order != pic_field_order &&
+ ffmpegdec->pic_interlaced))
+ ffmpegdec->pic_field_order_changed = TRUE;
+
+ ffmpegdec->pic_field_order = pic_field_order;
ffmpegdec->pic_interlaced = picture->interlaced_frame;
+
+ if (!ffmpegdec->pic_interlaced)
+ ffmpegdec->pic_field_order_changed = FALSE;
+
ffmpegdec->ctx_ticks = context->ticks_per_frame;
ffmpegdec->ctx_time_n = context->time_base.num;
ffmpegdec->ctx_time_d = context->time_base.den;
@@ -1032,13 +1068,27 @@ gst_ffmpegviddec_negotiate (GstFFMpegVidDec * ffmpegdec,
out_info = &ffmpegdec->output_state->info;
/* set the interlaced flag */
- if (ffmpegdec->pic_interlaced)
- out_info->interlace_mode = GST_VIDEO_INTERLACE_MODE_MIXED;
- else
- out_info->interlace_mode = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
-
in_s = gst_caps_get_structure (ffmpegdec->input_state->caps, 0);
+ if (!gst_structure_has_field (in_s, "interlace-mode")) {
+ if (ffmpegdec->pic_interlaced) {
+ if (ffmpegdec->pic_field_order_changed ||
+ (ffmpegdec->pic_field_order & GST_VIDEO_BUFFER_FLAG_RFF)) {
+ out_info->interlace_mode = GST_VIDEO_INTERLACE_MODE_MIXED;
+ } else {
+ out_info->interlace_mode = GST_VIDEO_INTERLACE_MODE_INTERLEAVED;
+ if ((ffmpegdec->pic_field_order & GST_VIDEO_BUFFER_FLAG_TFF))
+ GST_VIDEO_INFO_FIELD_ORDER (out_info) =
+ GST_VIDEO_FIELD_ORDER_TOP_FIELD_FIRST;
+ else
+ GST_VIDEO_INFO_FIELD_ORDER (out_info) =
+ GST_VIDEO_FIELD_ORDER_BOTTOM_FIELD_FIRST;
+ }
+ } else {
+ out_info->interlace_mode = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
+ }
+ }
+
if (!gst_structure_has_field (in_s, "chroma-site")) {
switch (context->chroma_sample_location) {
case AVCHROMA_LOC_LEFT:
@@ -1224,6 +1274,9 @@ negotiate_failed:
ffmpegdec->pic_height = 0;
ffmpegdec->pic_par_n = 0;
ffmpegdec->pic_par_d = 0;
+ ffmpegdec->pic_interlaced = 0;
+ ffmpegdec->pic_field_order = 0;
+ ffmpegdec->pic_field_order_changed = FALSE;
ffmpegdec->ctx_ticks = 0;
ffmpegdec->ctx_time_n = 0;
ffmpegdec->ctx_time_d = 0;
@@ -1841,6 +1894,9 @@ gst_ffmpegviddec_stop (GstVideoDecoder * decoder)
ffmpegdec->pic_height = 0;
ffmpegdec->pic_par_n = 0;
ffmpegdec->pic_par_d = 0;
+ ffmpegdec->pic_interlaced = 0;
+ ffmpegdec->pic_field_order = 0;
+ ffmpegdec->pic_field_order_changed = FALSE;
ffmpegdec->ctx_ticks = 0;
ffmpegdec->ctx_time_n = 0;
ffmpegdec->ctx_time_d = 0;
diff --git a/ext/libav/gstavviddec.h b/ext/libav/gstavviddec.h
index 68faf96..1c4375f 100644
--- a/ext/libav/gstavviddec.h
+++ b/ext/libav/gstavviddec.h
@@ -47,6 +47,9 @@ struct _GstFFMpegVidDec
gint pic_par_n;
gint pic_par_d;
gint pic_interlaced;
+ /* GST_VIDEO_BUFFER_FLAG_RFF | GST_VIDEO_BUFFER_FLAG_TFF */
+ gint pic_field_order;
+ gboolean pic_field_order_changed;
/* current context */
gint ctx_ticks;
gint ctx_time_d;