diff --git a/NEWS.md b/NEWS.md index 02d40dba9..9b17d6705 100644 --- a/NEWS.md +++ b/NEWS.md @@ -52,6 +52,9 @@ * mkvmerge: fixed an endless loop in certain circumstances when splitting by `parts` or `parts-frames` and the start of the file is discarded. Fixes #1944. +* mkvmerge: AVC/h.264 parser: mkvmerge will now ignore bogus timing + information in the sequence parameter sets (values indicating more than + 100000 progressive frames per second). Fixes #1946. ## Build system changes diff --git a/src/common/mpeg4_p10.cpp b/src/common/mpeg4_p10.cpp index 4c347896b..b360333eb 100644 --- a/src/common/mpeg4_p10.cpp +++ b/src/common/mpeg4_p10.cpp @@ -265,6 +265,14 @@ mpeg4::p10::timing_info_t::default_duration() return 1000000000ll * num_units_in_tick / time_scale; } +bool +mpeg4::p10::timing_info_t::is_valid() + const { + return is_present + && (0 != num_units_in_tick) + && (0 != time_scale); +} + void mpeg4::p10::sps_info_t::dump() { mxinfo(boost::format("sps_info dump:\n" @@ -327,9 +335,7 @@ mpeg4::p10::sps_info_t::dump() { bool mpeg4::p10::sps_info_t::timing_info_valid() const { - return timing_info.is_present - && (0 != timing_info.num_units_in_tick) - && (0 != timing_info.time_scale); + return timing_info.is_valid(); } void @@ -563,6 +569,15 @@ mpeg4::p10::parse_sps(memory_cptr const &buffer, sps.timing_info.num_units_in_tick = r.get_bits(32); sps.timing_info.time_scale = r.get_bits(32); sps.timing_info.fixed_frame_rate = r.get_bit(); + + if ( sps.timing_info.is_valid() + && (sps.timing_info.default_duration() < 5'000ll)) { + mxdebug_if(s_debug_fix_bistream_timing_info, + boost::format("timing info present && bogus values detected (#units %2% time_scale %3%); defaulting to 25 FPS (default duration 20'000'000)\n") + % sps.timing_info.is_present % sps.timing_info.num_units_in_tick % sps.timing_info.time_scale); + sps.timing_info.num_units_in_tick = 1; + sps.timing_info.time_scale = 50; + } } mxdebug_if(s_debug_fix_bistream_timing_info, @@ -1307,7 +1322,7 @@ mpeg4::p10::avc_es_parser_c::handle_nalu(memory_cptr const &nalu, int type = *(nalu->get_buffer()) & 0x1f; - mxdebug_if(m_debug_nalu_types, boost::format("NALU type 0x%|1$02x| (%2%) size %3%\n") % type % get_nalu_type_name(type) % nalu->get_size()); + mxdebug_if(m_debug_nalu_types, boost::format("NALU type 0x%|1$02x| (%2%) at %3% size %4%\n") % type % get_nalu_type_name(type) % nalu_pos % nalu->get_size()); switch (type) { case NALU_TYPE_SEQ_PARAM: diff --git a/src/common/mpeg4_p10.h b/src/common/mpeg4_p10.h index 7a8ee0bb7..afe1644d5 100644 --- a/src/common/mpeg4_p10.h +++ b/src/common/mpeg4_p10.h @@ -56,6 +56,7 @@ struct timing_info_t { bool is_present, fixed_frame_rate; int64_t default_duration() const; + bool is_valid() const; }; struct sps_info_t { diff --git a/tests/results.txt b/tests/results.txt index 1016a1956..adce85447 100644 --- a/tests/results.txt +++ b/tests/results.txt @@ -440,3 +440,4 @@ T_591hevc_wrong_number_of_parameter_sets:cc0ff46884d832c3b7234136f963bc39:passed T_592mpeg_ts_aac_wrong_track_parameters_detected:25116993128e73fe9251dc7161ae8030:passed:20170412-225238:0.044257474 T_593flac_with_picture_metadata:c5779b653e274bbb49d3ddf0a274c63c-c58da16285f056972ce09e617e0bd19e-998802dac83743b286c37a681742f296-7cda56d8aceb15753fc915338f1c0fbb-0e4d2b364f8e535d64286ea154948709:passed:20170415-182414:0.302331784 T_594hevc_split_parts_discarding_start_endless_loop:9728cf3f10e0c0aa187f4f7f55a4b7b6:passed:20170416-073513:0.635225717 +T_595h264_bogus_timing_info:78c27e10b35f3bfea09d8c005dead342:passed:20170417-200233:0.368456672 diff --git a/tests/test-595h264_bogus_timing_info.rb b/tests/test-595h264_bogus_timing_info.rb new file mode 100755 index 000000000..6f8e2c398 --- /dev/null +++ b/tests/test-595h264_bogus_timing_info.rb @@ -0,0 +1,5 @@ +#!/usr/bin/ruby -w + +# T_595h264_bogus_timing_info +describe "mkvmerge / h.264 files created by x264 with bogus timing information values" +test_merge "data/h264/bogus_timing_info.h264"