mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-26 19:51:11 +00:00
avviddec, video.c, h265parse: Workaround for broken field-based interlaced encoders
Some encoders (e.g. Makito) have H265 field-based interlacing, but then also specify an 1:2 pixel aspect ratio. That makes it kind-of work with decoders that don't properly support field-based decoding, but makes us end up with the wrong aspect ratio if we implement everything properly. As a workaround, detect 1:2 pixel aspect ratio for field-based interlacing, and check if making that 1:1 would make the new display aspect ratio common. In that case, we override it with 1:1. Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2577>
This commit is contained in:
parent
936143599c
commit
b90d02741e
4 changed files with 85 additions and 5 deletions
|
@ -1101,6 +1101,8 @@ gst_ffmpegviddec_update_par (GstFFMpegVidDec * ffmpegdec,
|
||||||
gboolean decoder_par_set = FALSE;
|
gboolean decoder_par_set = FALSE;
|
||||||
gint demuxer_num = 1, demuxer_denom = 1;
|
gint demuxer_num = 1, demuxer_denom = 1;
|
||||||
gint decoder_num = 1, decoder_denom = 1;
|
gint decoder_num = 1, decoder_denom = 1;
|
||||||
|
GstVideoCodecFrame *out_frame;
|
||||||
|
GstFFMpegVidDecVideoFrame *out_dframe;
|
||||||
|
|
||||||
if (in_info->par_n && in_info->par_d) {
|
if (in_info->par_n && in_info->par_d) {
|
||||||
demuxer_num = in_info->par_n;
|
demuxer_num = in_info->par_n;
|
||||||
|
@ -1127,14 +1129,38 @@ gst_ffmpegviddec_update_par (GstFFMpegVidDec * ffmpegdec,
|
||||||
if (decoder_par_set && !demuxer_par_set)
|
if (decoder_par_set && !demuxer_par_set)
|
||||||
goto use_decoder_par;
|
goto use_decoder_par;
|
||||||
|
|
||||||
|
/* Special case for some encoders which provide an 1:2 pixel aspect ratio
|
||||||
|
* for HEVC interlaced content, possibly to work around decoders that don't
|
||||||
|
* support field-based interlacing. Add some defensive checks to check for
|
||||||
|
* a "common" aspect ratio. */
|
||||||
|
out_dframe = ffmpegdec->picture->opaque;
|
||||||
|
out_frame = out_dframe->frame;
|
||||||
|
|
||||||
|
if (demuxer_num == 1 && demuxer_denom == 1 &&
|
||||||
|
decoder_num == 1 && decoder_denom == 2 &&
|
||||||
|
GST_BUFFER_FLAG_IS_SET (out_frame->input_buffer,
|
||||||
|
GST_VIDEO_BUFFER_FLAG_ONEFIELD) &&
|
||||||
|
gst_video_is_common_aspect_ratio (ffmpegdec->pic_width,
|
||||||
|
ffmpegdec->pic_height, 1, 2) &&
|
||||||
|
!gst_video_is_common_aspect_ratio (ffmpegdec->pic_width,
|
||||||
|
ffmpegdec->pic_height, 1, 1)) {
|
||||||
|
GST_WARNING_OBJECT (ffmpegdec,
|
||||||
|
"PAR 1/2 makes the aspect ratio of "
|
||||||
|
"a %d x %d frame uncommon. Switching to 1/1",
|
||||||
|
ffmpegdec->pic_width, ffmpegdec->pic_height);
|
||||||
|
goto use_demuxer_par;
|
||||||
|
}
|
||||||
|
|
||||||
/* Both the demuxer and the decoder provide a PAR. If one of
|
/* Both the demuxer and the decoder provide a PAR. If one of
|
||||||
* the two PARs is 1:1 and the other one is not, use the one
|
* the two PARs is 1:1 and the other one is not, use the one
|
||||||
* that is not 1:1. */
|
* that is not 1:1. */
|
||||||
if (demuxer_num == demuxer_denom && decoder_num != decoder_denom)
|
if (demuxer_num == demuxer_denom && decoder_num != decoder_denom) {
|
||||||
goto use_decoder_par;
|
goto use_decoder_par;
|
||||||
|
}
|
||||||
|
|
||||||
if (decoder_num == decoder_denom && demuxer_num != demuxer_denom)
|
if (decoder_num == decoder_denom && demuxer_num != demuxer_denom) {
|
||||||
goto use_demuxer_par;
|
goto use_demuxer_par;
|
||||||
|
}
|
||||||
|
|
||||||
/* Both PARs are non-1:1, so use the PAR provided by the demuxer */
|
/* Both PARs are non-1:1, so use the PAR provided by the demuxer */
|
||||||
goto use_demuxer_par;
|
goto use_demuxer_par;
|
||||||
|
|
|
@ -2086,6 +2086,7 @@ gst_h265_parse_update_src_caps (GstH265Parse * h265parse, GstCaps * caps)
|
||||||
gboolean modified = FALSE;
|
gboolean modified = FALSE;
|
||||||
GstBuffer *buf = NULL;
|
GstBuffer *buf = NULL;
|
||||||
GstStructure *s = NULL;
|
GstStructure *s = NULL;
|
||||||
|
gint width, height;
|
||||||
|
|
||||||
if (G_UNLIKELY (!gst_pad_has_current_caps (GST_BASE_PARSE_SRC_PAD
|
if (G_UNLIKELY (!gst_pad_has_current_caps (GST_BASE_PARSE_SRC_PAD
|
||||||
(h265parse))))
|
(h265parse))))
|
||||||
|
@ -2242,7 +2243,6 @@ gst_h265_parse_update_src_caps (GstH265Parse * h265parse, GstCaps * caps)
|
||||||
if (G_UNLIKELY (modified || h265parse->update_caps)) {
|
if (G_UNLIKELY (modified || h265parse->update_caps)) {
|
||||||
gint fps_num = h265parse->fps_num;
|
gint fps_num = h265parse->fps_num;
|
||||||
gint fps_den = h265parse->fps_den;
|
gint fps_den = h265parse->fps_den;
|
||||||
gint width, height;
|
|
||||||
GstClockTime latency = 0;
|
GstClockTime latency = 0;
|
||||||
|
|
||||||
caps = gst_caps_copy (sink_caps);
|
caps = gst_caps_copy (sink_caps);
|
||||||
|
@ -2345,9 +2345,22 @@ gst_h265_parse_update_src_caps (GstH265Parse * h265parse, GstCaps * caps)
|
||||||
gst_h265_parse_get_par (h265parse, &par_n, &par_d);
|
gst_h265_parse_get_par (h265parse, &par_n, &par_d);
|
||||||
if (par_n != 0 && par_d != 0 &&
|
if (par_n != 0 && par_d != 0 &&
|
||||||
(!s || !gst_structure_has_field (s, "pixel-aspect-ratio"))) {
|
(!s || !gst_structure_has_field (s, "pixel-aspect-ratio"))) {
|
||||||
GST_INFO_OBJECT (h265parse, "PAR %d/%d", par_n, par_d);
|
gint new_par_d = par_d;
|
||||||
|
/* Special case for some encoders which provide an 1:2 pixel aspect ratio
|
||||||
|
* for HEVC interlaced content, possibly to work around decoders that don't
|
||||||
|
* support field-based interlacing. Add some defensive checks to check for
|
||||||
|
* a "common" aspect ratio. */
|
||||||
|
if (par_n == 1 && par_d == 2
|
||||||
|
&& gst_h265_parse_is_field_interlaced (h265parse)
|
||||||
|
&& !gst_video_is_common_aspect_ratio (width, height, par_n, par_d)
|
||||||
|
&& gst_video_is_common_aspect_ratio (width, height, 1, 1)) {
|
||||||
|
GST_WARNING_OBJECT (h265parse, "PAR 1/2 makes the aspect ratio of "
|
||||||
|
"a %d x %d frame uncommon. Switching to 1/1", width, height);
|
||||||
|
new_par_d = 1;
|
||||||
|
}
|
||||||
|
GST_INFO_OBJECT (h265parse, "PAR %d/%d", par_n, new_par_d);
|
||||||
gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
|
gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
|
||||||
par_n, par_d, NULL);
|
par_n, new_par_d, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set profile and level in caps */
|
/* set profile and level in caps */
|
||||||
|
|
|
@ -183,6 +183,44 @@ gst_video_guess_framerate (GstClockTime duration, gint * dest_n, gint * dest_d)
|
||||||
return (best_error != G_MAXUINT64);
|
return (best_error != G_MAXUINT64);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_video_is_common_aspect_ratio:
|
||||||
|
* @width: Width of the video frame
|
||||||
|
* @height: Height of the video frame
|
||||||
|
* @par_n: Pixel aspect ratio numerator
|
||||||
|
* @par_d: Pixel aspect ratio denominator
|
||||||
|
*
|
||||||
|
* Given a frame's dimensions and pixel aspect ratio, this function will
|
||||||
|
* calculate the frame's aspect ratio and compare it against a set of
|
||||||
|
* common well-known "standard" aspect ratios.
|
||||||
|
*
|
||||||
|
* Returns: %TRUE if a known "standard" aspect ratio was
|
||||||
|
* recognised, and %FALSE otherwise.
|
||||||
|
*
|
||||||
|
* Since: 1.22
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
gst_video_is_common_aspect_ratio (gint width, gint height, gint par_n,
|
||||||
|
gint par_d)
|
||||||
|
{
|
||||||
|
gint dar_n, dar_d;
|
||||||
|
|
||||||
|
gst_util_fraction_multiply (width, height, par_n, par_d, &dar_n, &dar_d);
|
||||||
|
|
||||||
|
if (dar_n == 16 && dar_d == 9)
|
||||||
|
return TRUE;
|
||||||
|
if (dar_n == 4 && dar_d == 3)
|
||||||
|
return TRUE;
|
||||||
|
if (dar_n == 14 && dar_d == 9)
|
||||||
|
return TRUE;
|
||||||
|
if (dar_n == 8 && dar_d == 5)
|
||||||
|
return TRUE;
|
||||||
|
if (dar_n == 21 && dar_d == 11)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_video_alignment_reset:
|
* gst_video_alignment_reset:
|
||||||
|
|
|
@ -149,6 +149,9 @@ GST_VIDEO_API
|
||||||
gboolean gst_video_guess_framerate (GstClockTime duration,
|
gboolean gst_video_guess_framerate (GstClockTime duration,
|
||||||
gint * dest_n, gint * dest_d);
|
gint * dest_n, gint * dest_d);
|
||||||
|
|
||||||
|
GST_VIDEO_API
|
||||||
|
gboolean gst_video_is_common_aspect_ratio (gint width, gint height, gint par_n, gint par_d);
|
||||||
|
|
||||||
/* convert/encode video sample from one format to another */
|
/* convert/encode video sample from one format to another */
|
||||||
|
|
||||||
typedef void (*GstVideoConvertSampleCallback) (GstSample * sample, GError *error, gpointer user_data);
|
typedef void (*GstVideoConvertSampleCallback) (GstSample * sample, GError *error, gpointer user_data);
|
||||||
|
|
Loading…
Reference in a new issue