diff --git a/subprojects/gst-libav/ext/libav/gstavviddec.c b/subprojects/gst-libav/ext/libav/gstavviddec.c index b957d22ea0..61edfd2e92 100644 --- a/subprojects/gst-libav/ext/libav/gstavviddec.c +++ b/subprojects/gst-libav/ext/libav/gstavviddec.c @@ -1101,6 +1101,8 @@ gst_ffmpegviddec_update_par (GstFFMpegVidDec * ffmpegdec, gboolean decoder_par_set = FALSE; gint demuxer_num = 1, demuxer_denom = 1; gint decoder_num = 1, decoder_denom = 1; + GstVideoCodecFrame *out_frame; + GstFFMpegVidDecVideoFrame *out_dframe; if (in_info->par_n && in_info->par_d) { demuxer_num = in_info->par_n; @@ -1127,14 +1129,38 @@ gst_ffmpegviddec_update_par (GstFFMpegVidDec * ffmpegdec, if (decoder_par_set && !demuxer_par_set) 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 * the two PARs is 1:1 and the other one is not, use the one * 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; + } - if (decoder_num == decoder_denom && demuxer_num != demuxer_denom) + if (decoder_num == decoder_denom && demuxer_num != demuxer_denom) { goto use_demuxer_par; + } /* Both PARs are non-1:1, so use the PAR provided by the demuxer */ goto use_demuxer_par; diff --git a/subprojects/gst-plugins-bad/gst/videoparsers/gsth265parse.c b/subprojects/gst-plugins-bad/gst/videoparsers/gsth265parse.c index 2eb902d546..953174ab90 100644 --- a/subprojects/gst-plugins-bad/gst/videoparsers/gsth265parse.c +++ b/subprojects/gst-plugins-bad/gst/videoparsers/gsth265parse.c @@ -2086,6 +2086,7 @@ gst_h265_parse_update_src_caps (GstH265Parse * h265parse, GstCaps * caps) gboolean modified = FALSE; GstBuffer *buf = NULL; GstStructure *s = NULL; + gint width, height; if (G_UNLIKELY (!gst_pad_has_current_caps (GST_BASE_PARSE_SRC_PAD (h265parse)))) @@ -2242,7 +2243,6 @@ gst_h265_parse_update_src_caps (GstH265Parse * h265parse, GstCaps * caps) if (G_UNLIKELY (modified || h265parse->update_caps)) { gint fps_num = h265parse->fps_num; gint fps_den = h265parse->fps_den; - gint width, height; GstClockTime latency = 0; 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); if (par_n != 0 && par_d != 0 && (!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, - par_n, par_d, NULL); + par_n, new_par_d, NULL); } /* set profile and level in caps */ diff --git a/subprojects/gst-plugins-base/gst-libs/gst/video/video.c b/subprojects/gst-plugins-base/gst-libs/gst/video/video.c index cf8e184c23..6c3e913bcf 100644 --- a/subprojects/gst-plugins-base/gst-libs/gst/video/video.c +++ b/subprojects/gst-plugins-base/gst-libs/gst/video/video.c @@ -183,6 +183,44 @@ gst_video_guess_framerate (GstClockTime duration, gint * dest_n, gint * dest_d) 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: diff --git a/subprojects/gst-plugins-base/gst-libs/gst/video/video.h b/subprojects/gst-plugins-base/gst-libs/gst/video/video.h index a31562a09b..e70b99103a 100644 --- a/subprojects/gst-plugins-base/gst-libs/gst/video/video.h +++ b/subprojects/gst-plugins-base/gst-libs/gst/video/video.h @@ -149,6 +149,9 @@ GST_VIDEO_API gboolean gst_video_guess_framerate (GstClockTime duration, 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 */ typedef void (*GstVideoConvertSampleCallback) (GstSample * sample, GError *error, gpointer user_data);