codecs: mpeg2decoder: drain() only when significant sequence changes.

There are a lot of info in the mpeg2's sequence(also including ext
display_ext and scalable_ext). We need to notify the subclass about
its change, but not all the changes should trigger a drain(), which
may change the output picture order. For example, the matrix changes
in sequence header does not change the decoder context and so no need
to trigger a drain().

Fixes: #899
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1375>
This commit is contained in:
He Junyan 2021-11-23 13:30:17 +08:00 committed by GStreamer Marge Bot
parent 2a17618dcc
commit d867180b4e

View file

@ -246,6 +246,8 @@ struct _GstMpeg2DecoderPrivate
/* some sequence info changed after last new_sequence () */ /* some sequence info changed after last new_sequence () */
gboolean seq_changed; gboolean seq_changed;
/* whether we need to drain before new_sequence () */
gboolean need_to_drain;
GstMpegVideoGop gop; GstMpegVideoGop gop;
GstMpegVideoQuantMatrixExt quant_matrix; GstMpegVideoQuantMatrixExt quant_matrix;
GstMpegVideoPictureHdr pic_hdr; GstMpegVideoPictureHdr pic_hdr;
@ -512,8 +514,11 @@ gst_mpeg2_decoder_handle_sequence (GstMpeg2Decoder * decoder,
priv->seq_hdr = seq_hdr; priv->seq_hdr = seq_hdr;
priv->seq_changed = TRUE; priv->seq_changed = TRUE;
if (priv->width != seq_hdr.width || priv->height != seq_hdr.height) {
priv->need_to_drain = TRUE;
priv->width = seq_hdr.width; priv->width = seq_hdr.width;
priv->height = seq_hdr.height; priv->height = seq_hdr.height;
}
priv->display_width = priv->width; priv->display_width = priv->width;
priv->display_height = priv->height; priv->display_height = priv->height;
@ -551,8 +556,6 @@ gst_mpeg2_decoder_handle_sequence_ext (GstMpeg2Decoder * decoder,
priv->seq_ext = seq_ext; priv->seq_ext = seq_ext;
priv->seq_changed = TRUE; priv->seq_changed = TRUE;
priv->progressive = seq_ext.progressive;
if (seq_ext.fps_n_ext && seq_ext.fps_d_ext) { if (seq_ext.fps_n_ext && seq_ext.fps_d_ext) {
guint fps_n = priv->tsg.fps_n; guint fps_n = priv->tsg.fps_n;
guint fps_d = priv->tsg.fps_d; guint fps_d = priv->tsg.fps_d;
@ -564,11 +567,20 @@ gst_mpeg2_decoder_handle_sequence_ext (GstMpeg2Decoder * decoder,
width = (priv->width & 0x0fff) | ((guint32) seq_ext.horiz_size_ext << 12); width = (priv->width & 0x0fff) | ((guint32) seq_ext.horiz_size_ext << 12);
height = (priv->height & 0x0fff) | ((guint32) seq_ext.vert_size_ext << 12); height = (priv->height & 0x0fff) | ((guint32) seq_ext.vert_size_ext << 12);
GST_DEBUG_OBJECT (decoder, "video resolution %ux%u", width, height);
if (priv->width != width || priv->height != height ||
priv->profile != seq_ext.profile ||
priv->progressive != seq_ext.progressive) {
priv->need_to_drain = TRUE;
priv->width = width; priv->width = width;
priv->height = height; priv->height = height;
priv->profile = seq_ext.profile; priv->profile = seq_ext.profile;
priv->progressive = seq_ext.progressive;
GST_DEBUG_OBJECT (decoder, "video resolution %ux%u, profile %d,"
" progressive %d", priv->width, priv->height, priv->profile,
priv->progressive);
}
priv->state |= GST_MPEG2_DECODER_STATE_GOT_SEQ_EXT; priv->state |= GST_MPEG2_DECODER_STATE_GOT_SEQ_EXT;
@ -734,16 +746,27 @@ gst_mpeg2_decoder_handle_picture (GstMpeg2Decoder * decoder,
return GST_FLOW_ERROR; return GST_FLOW_ERROR;
} }
/* If need_to_drain, we must have sequence changed. */
g_assert (priv->need_to_drain ? priv->seq_changed : TRUE);
/* 6.1.1.6: Conversely if no sequence_xxx_extension() occurs between /* 6.1.1.6: Conversely if no sequence_xxx_extension() occurs between
the first sequence_header() and the first picture_header() then the first sequence_header() and the first picture_header() then
sequence_xxx_extension() shall not occur in the bitstream. */ sequence_xxx_extension() shall not occur in the bitstream. */
if (priv->seq_changed) { if (priv->seq_changed) {
GstFlowReturn ret; GstFlowReturn ret;
/* There are a lot of info in the mpeg2's sequence(also including ext
display_ext and scalable_ext). We need to notify the subclass about
its change, but not all the changes should trigger a drain(), which
may change the output picture order. */
if (priv->need_to_drain) {
ret = gst_mpeg2_decoder_drain (GST_VIDEO_DECODER (decoder)); ret = gst_mpeg2_decoder_drain (GST_VIDEO_DECODER (decoder));
if (ret != GST_FLOW_OK) if (ret != GST_FLOW_OK)
return ret; return ret;
priv->need_to_drain = FALSE;
}
if (klass->get_preferred_output_delay) if (klass->get_preferred_output_delay)
priv->preferred_output_delay = priv->preferred_output_delay =
klass->get_preferred_output_delay (decoder, priv->is_live); klass->get_preferred_output_delay (decoder, priv->is_live);