mirror of
https://gitlab.com/mbunkus/mkvtoolnix.git
synced 2024-12-23 03:21:35 +00:00
MPEG-2 parser: re-write timestamping code not to rely on exact sequence number progression
The old code was calculating an expected sequence number. As soon as that sequence number was matched with frames, all previous frames would be timestamped. This method is problematic if the actual sequence numbers don't follow the expected progression. The new code is much simpler. As soon as an I frame is encountered (or at the end of the file) the queued frames are first sorted by their sequence number, then timestamped, and lastly sorted back into their decoding order. This fixes #1162 and most likely others (see #1145, #1099 et. al.).
This commit is contained in:
parent
de9470bae2
commit
8696db7e11
@ -1,5 +1,11 @@
|
||||
2015-04-11 Moritz Bunkus <moritz@bunkus.org>
|
||||
|
||||
* mkvmerge: bug fix: MPEG-1/2 parser: fixed a long-standing issue
|
||||
that prevented mkvmerge from recognizing certain MPEG-1/2 video
|
||||
tracks and files if the frame's sequence numbers didn't follow a
|
||||
certain expected pattern. Fixes #1162 and probably others like
|
||||
#1145 or #1099.
|
||||
|
||||
* MKVToolNix GUI: merge tool enhancement: Implemented adding and
|
||||
append files and adding files as additional parts via drag & drop
|
||||
from external applications.
|
||||
|
@ -602,19 +602,26 @@ mpeg_ps_reader_c::new_stream_v_mpeg_1_2(mpeg_ps_id_t id,
|
||||
|
||||
bool found_i_frame = false;
|
||||
bool found_non_b_frame = false;
|
||||
bool flushed = false;
|
||||
MPEG2SequenceHeader seq_hdr;
|
||||
|
||||
while ( (MPV_PARSER_STATE_EOS != state)
|
||||
&& (MPV_PARSER_STATE_ERROR != state)
|
||||
&& (PS_PROBE_SIZE >= m_in->getFilePointer())) {
|
||||
if (!find_next_packet_for_id(id, PS_PROBE_SIZE))
|
||||
if (find_next_packet_for_id(id, PS_PROBE_SIZE)) {
|
||||
auto packet = parse_packet(id);
|
||||
if (!packet)
|
||||
break;
|
||||
|
||||
m2v_parser->WriteData(packet.m_buffer->get_buffer(), packet.m_length);
|
||||
|
||||
} else if (flushed)
|
||||
break;
|
||||
|
||||
auto packet = parse_packet(id);
|
||||
if (!packet)
|
||||
break;
|
||||
|
||||
m2v_parser->WriteData(packet.m_buffer->get_buffer(), packet.m_length);
|
||||
else {
|
||||
m2v_parser->SetEOS();
|
||||
flushed = true;
|
||||
}
|
||||
|
||||
state = m2v_parser->GetState();
|
||||
|
||||
|
@ -64,6 +64,7 @@ void M2VParser::SetEOS(){
|
||||
c = mpgBuf->ReadChunk();
|
||||
if(c) chunks.push_back(c);
|
||||
FillQueues();
|
||||
TimestampWaitingFrames();
|
||||
m_eos = true;
|
||||
}
|
||||
|
||||
@ -117,7 +118,6 @@ M2VParser::M2VParser()
|
||||
notReachedFirstGOP = true;
|
||||
previousTimecode = 0;
|
||||
previousDuration = 0;
|
||||
queueTime = 0;
|
||||
waitExpectedTime = 0;
|
||||
probing = false;
|
||||
b_frame_warning_printed = false;
|
||||
@ -205,12 +205,15 @@ MPEG2ParserState_e M2VParser::GetState(){
|
||||
void M2VParser::FlushWaitQueue(){
|
||||
waitSecondField = false;
|
||||
|
||||
while(!waitQueue.empty()){
|
||||
delete waitQueue.front();
|
||||
waitQueue.pop();
|
||||
if (!m_timecodes.empty())
|
||||
m_timecodes.pop_front();
|
||||
for (auto const &frame : waitQueue)
|
||||
delete frame;
|
||||
while (!buffers.empty()) {
|
||||
delete buffers.front();
|
||||
buffers.pop();
|
||||
}
|
||||
|
||||
waitQueue.clear();
|
||||
m_timecodes.clear();
|
||||
}
|
||||
|
||||
void M2VParser::StampFrame(MPEGFrame* frame){
|
||||
@ -248,7 +251,8 @@ void M2VParser::UpdateFrame(MPEGFrame* frame){
|
||||
|
||||
int32_t M2VParser::OrderFrame(MPEGFrame* frame){
|
||||
MPEGFrame *p = frame;
|
||||
bool flushQueue = false;
|
||||
|
||||
// mxinfo(boost::format("picStr %1% frame type %2% qt tc %3%\n") % p->timecode % static_cast<int>(p->pictureStructure) % p->frameType);
|
||||
|
||||
if (waitSecondField && (p->pictureStructure == MPEG2_PICTURE_TYPE_FRAME)){
|
||||
auto error = Y("Unexpected picture frame after single field frame. Fix the MPEG2 video stream before attempting to multiplex it.\n");
|
||||
@ -257,86 +261,38 @@ int32_t M2VParser::OrderFrame(MPEGFrame* frame){
|
||||
mxerror(error);
|
||||
}
|
||||
|
||||
/* While the refs of a frame are set in SetFrameRef, the actual final timecodes are possibly derived later.
|
||||
* Based on display order, a dependent frame (below: "DEP") can be located after or before a ref frame (below: "REF").
|
||||
* This leads to the following behaviour:
|
||||
*
|
||||
* ***** case "after" => REF takes branch 1 below *****
|
||||
* - REF: ShoveRef/StampFrame set both frame pointer and timecode at M2VParser::refs.
|
||||
* - DEP: SetFrameRef already derives the timecode.
|
||||
*
|
||||
* ***** case "before" => REF takes branch 2 below *****
|
||||
* - REF: ShoveRef sets the frame pointer at M2VParser::refs.
|
||||
* - DEP: SetFrameRef derives that pointer in the first place.
|
||||
* Later, while queue flushing:
|
||||
* - REF: StampFrame sets the timecode.
|
||||
* - DEP: UpdateFrame derives the timecode via frame pointer.
|
||||
* The queue frames are in decoding order, therefore DEP's UpdateFrame happens before REF's StampFrame.
|
||||
* In addition, tmpForwardQueue ensures that the pointed to ref frame is still available.
|
||||
*/
|
||||
SetFrameRef(p);
|
||||
ShoveRef(p);
|
||||
|
||||
/*
|
||||
* Process incoming frames (being in decoding order) and ensure correct stamping (in display order) - output again happens in decoding order.
|
||||
* - branch 1: not waiting; forward frame, which has consecutive sequence number
|
||||
* - branch 2: not waiting; queue frame, which has preceding frames (regarding display order) + start waiting for that intermediate frames
|
||||
* - branch 3: waiting: queue frame (if last intermediate frame, finish waiting by invoking flush)
|
||||
* - branch 4: waiting; queue frame - sequence number beyond expected range (this can only occur at defective streams!)
|
||||
*/
|
||||
if ((p->timecode == queueTime) && waitQueue.empty()) { // branch 1
|
||||
if ((p->pictureStructure == MPEG2_PICTURE_TYPE_FRAME) || waitSecondField)
|
||||
queueTime++;
|
||||
StampFrame(p);
|
||||
UpdateFrame(p);
|
||||
buffers.push(p);
|
||||
} else if ((p->timecode > queueTime) && waitQueue.empty()) { // branch 2
|
||||
waitExpectedTime = p->timecode - 1;
|
||||
waitQueue.push(p);
|
||||
} else if (p->timecode <= waitExpectedTime) { // branch 3
|
||||
if ((p->timecode == waitExpectedTime) && ((p->pictureStructure == MPEG2_PICTURE_TYPE_FRAME) || waitSecondField))
|
||||
flushQueue = true;
|
||||
StampFrame(p);
|
||||
waitQueue.push(p);
|
||||
} else // branch 4
|
||||
waitQueue.push(p);
|
||||
if (('I' == p->frameType) && !waitQueue.empty())
|
||||
TimestampWaitingFrames();
|
||||
|
||||
if(flushQueue){
|
||||
int i,l;
|
||||
waitSecondField = false;
|
||||
|
||||
l = waitQueue.size();
|
||||
for(i=0;i<l;i++){
|
||||
p = waitQueue.front();
|
||||
waitQueue.pop();
|
||||
if(!p->stamped) {
|
||||
StampFrame(p);
|
||||
}
|
||||
UpdateFrame(p);
|
||||
|
||||
// temporarily cache all frames, to ensure that all needed ref frames are still available while UpdateFrame (see above)
|
||||
tmpForwardQueue.push(p);
|
||||
}
|
||||
for (i = 0; i < l; i++) {
|
||||
p = tmpForwardQueue.front();
|
||||
tmpForwardQueue.pop();
|
||||
|
||||
if((p->pictureStructure == MPEG2_PICTURE_TYPE_FRAME) || waitSecondField){
|
||||
queueTime++;
|
||||
}
|
||||
if(p->pictureStructure != MPEG2_PICTURE_TYPE_FRAME)
|
||||
waitSecondField = !waitSecondField;
|
||||
|
||||
buffers.push(p);
|
||||
}
|
||||
waitSecondField = false;
|
||||
}else if (p->pictureStructure != MPEG2_PICTURE_TYPE_FRAME){
|
||||
waitSecondField = !waitSecondField;
|
||||
}
|
||||
waitQueue.push_back(p);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
M2VParser::TimestampWaitingFrames() {
|
||||
// mxinfo(boost::format(" flushing %1%\n") % waitQueue.size());
|
||||
|
||||
for (std::size_t idx = 0, numFrames = waitQueue.size(); idx < numFrames; ++idx)
|
||||
waitQueue[idx]->decodingOrder = idx;
|
||||
|
||||
brng::sort(waitQueue, [](MPEGFrame *a, MPEGFrame *b) { return a->timecode < b->timecode; });
|
||||
|
||||
for (auto const &frame : waitQueue)
|
||||
StampFrame(frame);
|
||||
for (auto const &frame : waitQueue)
|
||||
UpdateFrame(frame);
|
||||
|
||||
brng::sort(waitQueue, [](MPEGFrame *a, MPEGFrame *b) { return a->decodingOrder < b->decodingOrder; });
|
||||
|
||||
for (auto const &frame : waitQueue)
|
||||
buffers.push(frame);
|
||||
waitQueue.clear();
|
||||
}
|
||||
|
||||
int32_t M2VParser::PrepareFrame(MPEGChunk* chunk, MediaTime timecode, MPEG2PictureHeader picHdr){
|
||||
MPEGFrame* outBuf;
|
||||
bool bCopy = true;
|
||||
|
@ -61,6 +61,7 @@ public:
|
||||
MediaTime duration;
|
||||
char frameType;
|
||||
MediaTime timecode; // before stamping: sequence number; after stamping: real timecode
|
||||
unsigned int decodingOrder;
|
||||
MediaTime refs[2];
|
||||
MPEGFrameRef tmpRefs[2];
|
||||
bool stamped;
|
||||
@ -78,8 +79,7 @@ public:
|
||||
class M2VParser {
|
||||
private:
|
||||
std::vector<MPEGChunk*> chunks; //Hold the chunks until we can order them
|
||||
std::queue<MPEGFrame*> waitQueue; //Holds unstamped buffers until we can stamp them.
|
||||
std::queue<MPEGFrame*> tmpForwardQueue; //Temporarily holds stamped buffers until we can forward them.
|
||||
std::vector<MPEGFrame*> waitQueue; //Holds unstamped buffers until we can stamp them.
|
||||
std::queue<MPEGFrame*> buffers; //Holds stamped buffers until they are requested.
|
||||
MediaTime previousTimecode;
|
||||
MediaTime previousDuration;
|
||||
@ -87,7 +87,6 @@ private:
|
||||
MPEGChunk* seqHdrChunk, *gopChunk;
|
||||
MPEG2SequenceHeader m_seqHdr; //current sequence header
|
||||
MPEG2GOPHeader m_gopHdr; //current GOP header
|
||||
MediaTime queueTime;
|
||||
MediaTime waitExpectedTime;
|
||||
bool waitSecondField;
|
||||
bool probing;
|
||||
@ -168,6 +167,8 @@ public:
|
||||
void AddTimecode(int64_t timecode);
|
||||
|
||||
void SetThrowOnError(bool doThrow);
|
||||
|
||||
void TimestampWaitingFrames();
|
||||
};
|
||||
|
||||
|
||||
|
@ -94,7 +94,7 @@ T_244iconv_missing_character:b0cea35ff7be939dc13b0e373657695a:passed:20081004-21
|
||||
T_245srt_timecode_formats:ce80ae14afb44f507cfe4226944d1266-ce80ae14afb44f507cfe4226944d1266:passed:20081202-141604:0.255023139
|
||||
T_246theora_pixel_aspect_ratio:2067abd2dc972e76ec7b1080927cbe8e:passed:20081205-174857:0.061985381
|
||||
T_247attachment_selection:04e4c3afcde00ea879132481a68d1478-9c6b5c11674833d484f9a3465c42f4bd-6e3afba12988ca0d66b15096002dcaa3-04a48cc0da545825357249eace746de8+7aba76631fef5d8be295411dd12ccc9e:passed:20090228-191612:0.113510024
|
||||
T_248mpeg2:c11e561110cebaa7268be5c7991ccbf3-00db43954883d06d2805a81d277ecc10:passed:20090531-132819:8.128150931
|
||||
T_248mpeg2:326006565ffe36597085992dccbe19ac-00db43954883d06d2805a81d277ecc10:passed:20090531-132819:8.128150931
|
||||
T_249mpeg2_no_codecprivate:9a338fc21ac14764bc63cbdde68d7f2b:passed:20090531-132821:1.45695982
|
||||
T_250tag_selection:9df21986c4523e8d83533391e9d3a3dd-d1b4cc27362894ef70176a4e42ce88b7-59ee8324b57552b1b63b7c8a6866efae-0411dd08be9cc75d7ac861782af4150b-ee207fb3cb5933299d2bc80919c2d7f4-ee207fb3cb5933299d2bc80919c2d7f4-09c92b6792730887038da4c7e25ebc9f:passed:20090531-205640:1.287172749
|
||||
T_251vc1_truehd_eac3_from_evo:74614cfa6328f70b12b2327277f5f61e:passed:20090606-220945:1.173449174
|
||||
@ -171,7 +171,7 @@ T_322propedit_track_headers:785209f2dc35ad6177bea2ca6e43198f-3e9ff1255235f31945c
|
||||
T_323propedit_segment_info:785209f2dc35ad6177bea2ca6e43198f-0baf1cb46e7d365580b51aa4452551d6-d6cd21681b8544aa730744f128d46fd7:passed:20111203-152845:0.425794709
|
||||
T_324propedit_chapters:785209f2dc35ad6177bea2ca6e43198f-a9255d40de93e2731aaead0a746e582f-493859725ffbe8bf65cfd397e26a7c90-ae788bbd0580dd01d10672a46e3be84d-9ff842a7f02fe26ef95313b626be83b3-b6aafbfe2bc4902f3187031a71730f8d-3057bf142672a2c86657c64f4e4d189a-48614f8c72edb5d3e23115e1998f5997-8594e3734741654285cc5ce5e48f3e29-d41d8cd98f00b204e9800998ecf8427e:passed:20111203-154502:0.736303091
|
||||
T_325propedit_tags:785209f2dc35ad6177bea2ca6e43198f-26ad4ab0491d76d9fb6f57b4a4b35400-2d6bc3c519e65853430cd53e64d46386-52322241c33de4f7b56ede7a4764f72f-2d6bc3c519e65853430cd53e64d46386-52322241c33de4f7b56ede7a4764f72f-ddb1f5475eca068a3e4b6ad8df1dea7e-591a65deb231cb0150a4da224d5f3415-e657d1255b0b7a1a1610bda7460dc318-438f0a8ce757e03b77c084bd593cb196-e657d1255b0b7a1a1610bda7460dc318-438f0a8ce757e03b77c084bd593cb196-6f60e83c7d351a25ad6af4545ce3dff6-5a8f05d63ffe9d53046abf40ec30e42a-e126ac5e6a97297f4ee14cfd648e1e33-d41d8cd98f00b204e9800998ecf8427e:passed:20111203-160727:1.314514241
|
||||
T_326mpeg_ps_mpeg_audio_layer4:92c7507e54caf041d729c2e9e97c775f:passed:20111207-224511:1.505513342
|
||||
T_326mpeg_ps_mpeg_audio_layer4:fca2d489ec0cd9ade511f3145187464b:passed:20111207-224511:1.505513342
|
||||
T_327vp8_frame_type:da02f5873c366315b4594e34a04966e8:passed:20111207-233304:0.089263543
|
||||
T_328dts_detected_as_ac3:6cadc1ac331dda8e80eae3abfeca1358:passed:20111229-192324:0.090561076
|
||||
T_329X_timecodes_v2:dadc36ce79c1c4b281f8f1f865746598-049cdc2d9226fac8c61d193d803bfc1f-3720aac3f16b66ec3308ffa7bf913c6e-6469e2522a4b48b7b20bae93f5d9086d-1ff091abfcb0938d6ac7fd0495e899b3-049cdc2d9226fac8c61d193d803bfc1f-d172a9340cbf2802690479e396879d1e-bf76c5886cc7c18cc7e6ee796c3406b4-b3f9d126c31505c22f292a1d2bdffba2-4bd97467fac0ac0b561d68b8b15a79dd:passed:20120105-202451:1.376047868
|
||||
@ -206,7 +206,7 @@ T_357segment_info:c734542adcdeca270db3b6e41fd85ffc-61d4730547bcd79e9a692caa4c214
|
||||
T_358usf:13cc323a8e690b4e1c236010938e1ee3:passed:20120329-142144:0.051754089
|
||||
T_359split_parts:bc2ff718d54847937b9f6b4f2e38036d+49341e4669faff0225236af4eda8eb09+ok-5efda882c230b3ff5a044af4148f8d1c+ok-b1619e39ba9194cf2ef3187991f6ed18+ok-497448adf872f4050f5e34d9aacf5fa0+4f25451d573042cfdff4809a28638e93+782db07154db9054ff9f0ef3bf1235c6+f129ab41e298b6358fc0197c92c3da5f+91120826bea5d0462090d54416a571b1+ad267ff44bf21e0acee2a0dc009908d6+1586ba9b356c823bd58566c58e635889+ok-32b1d647cec6dc843b31f3030daf9ee7+ok-a72d22cdc1ab54c605930259a9953aff+ok:passed:20120331-133448:2.321768368
|
||||
T_360X_chapters_hex_format:87a60c81c05fb0a153a2e041485ae2cb-3853793b0d88fc10efadb146ca948833:passed:20120404-152038:0.047282116
|
||||
T_361file_concatenation:68b5608e9ff344d493fdcbbdc24b821b-35c3e616631e24ef8df17c8cfb0b35d0-35c3e616631e24ef8df17c8cfb0b35d0-98fd5ee77c40d1de6244c7afca3cfa15-98fd5ee77c40d1de6244c7afca3cfa15-98fd5ee77c40d1de6244c7afca3cfa15-2b0cde47d9cff1d464c78f2e158582f1-2b64e3421c5553b1dcd8675f69c0b6cc-740607972d7bb60c595835efdb9d880d-740607972d7bb60c595835efdb9d880d-740607972d7bb60c595835efdb9d880d-740607972d7bb60c595835efdb9d880d-09ffbb6cd3ce4f4947f1f2e782be6cdd-d7039c2d63d417c29d4ba7bf623563e5-80e456901895bd509cc8f2f6ed10d587-80e456901895bd509cc8f2f6ed10d587:passed:20120406-144928:18.646532342
|
||||
T_361file_concatenation:68b5608e9ff344d493fdcbbdc24b821b-ed5c6fbaedc5f24c2a8321c306baff41-ed5c6fbaedc5f24c2a8321c306baff41-98fd5ee77c40d1de6244c7afca3cfa15-98fd5ee77c40d1de6244c7afca3cfa15-98fd5ee77c40d1de6244c7afca3cfa15-2b0cde47d9cff1d464c78f2e158582f1-2b64e3421c5553b1dcd8675f69c0b6cc-740607972d7bb60c595835efdb9d880d-740607972d7bb60c595835efdb9d880d-740607972d7bb60c595835efdb9d880d-740607972d7bb60c595835efdb9d880d-09ffbb6cd3ce4f4947f1f2e782be6cdd-d7039c2d63d417c29d4ba7bf623563e5-80e456901895bd509cc8f2f6ed10d587-80e456901895bd509cc8f2f6ed10d587:passed:20120406-144928:18.646532342
|
||||
T_362xtr_avc:abc9dd7b4579a2e14783271d1d64d486-49ae33bdb1e43de90886bc2ac6410c35:passed:20120416-153515:1.811589633
|
||||
T_363srt_colon_decimal_separator:d75be97f27797c8b3fc62e5d39a8d7ea:passed:20120520-180625:0.032379535
|
||||
T_364qtmp4_track_with_empty_chunkmap_table:f7837ed142ed9a5cca5d2fbc5788d597:passed:20120605-223925:0.168392001
|
||||
@ -234,7 +234,7 @@ T_385split_parts_frames:bc2ff718d54847937b9f6b4f2e38036d+49341e4669faff0225236af
|
||||
T_386flv_vp6f:06bccf045351fc4946cb24c4990d396c:passed:20130121-223417:0.187881106
|
||||
T_387mp4_free_invalid_size:6a338e059717d57b89efa683031ee3c6:passed:20130216-003333:0.04107827
|
||||
T_388split_parts_and_chapters:8d2a65e53a0d3c8ed6050fc8d4679538-7d1a25c6a3c78c7f1469d1dcf637af4f-0e101a08e2be05f0247b09e93635b1de:passed:20130216-203522:0.690018077
|
||||
T_389mpeg1_in_ps_misdetected_as_avc:276be21585918359788a0bf47dbf8502:passed:20130224-132738:1.205560654
|
||||
T_389mpeg1_in_ps_misdetected_as_avc:566aeaa72d47e30589f3227555bf24d3:passed:20130224-132738:1.205560654
|
||||
T_390timecode_info_on_resync:ok+ok:passed:20130318-185621:0.115461517
|
||||
T_391fix_bitstream_frame_rate:6d71f661ca5682143eddaf0842435952:passed:20130329-114522:0.460370742
|
||||
T_392avi_audio_chunk_size_0:77f8ab45d16202e5e0a4bdabc7f616f0:passed:20130331-134751:0.893777097
|
||||
@ -283,7 +283,7 @@ T_434mkvpropedit_no_track_uid:99631d7c0f79faf45a37696dae506b21-ab7b3ff004b7ed5a1
|
||||
T_435mp4_edit_list_duration_uses_global_time_scale:eba0b6ddc51c05e4a97f39a3bb350b01:passed:20140905-183027:0.096674624
|
||||
T_436extract_ssa_extradata_after_events:8be4c4af0a2d65826071aee718ec44e8:passed:20140906-090602:0.054263072
|
||||
T_437ac3_from_avi_with_garbage:dd5b3c1593cdccac26d2b8e8c6694893:passed:20140908-144311:0.075599921
|
||||
T_438pcm_in_vob:09b8c5d3ca0f0224f3ccc9f0ca4f5930:passed:20140917-213731:1.216717009
|
||||
T_438pcm_in_vob:f39c9585f8fe45d89073a4531dc69d9d:passed:20140917-213731:1.216717009
|
||||
T_439pcm_in_m2ts:e508ff1185855b9454c4b15ca6278790-fae839a729cd17480f7f88d6736df0e4:passed:20140917-222633:4.736872644
|
||||
T_440chapter_display_language_default_value:6dd844972d790ee741c58f5de5ff1555:passed:20140929-142306:0.021103552
|
||||
T_441mkvmerge_mp4_big_endian_pcm:ddd27c5fa93e1e4fe610707e8b050365:passed:20141104-190420:0.278181073
|
||||
@ -335,3 +335,4 @@ T_486m2ts_eac3_with_extension_in_own_packet:265d8436497eb50f49b24805a08cd39a:pas
|
||||
T_487matroska_version_and_read_version_with_opus:4+2-4+2-4+2-4+1-4+2-4+1-4+1-4+1:passed:20150329-213811:0.670610463
|
||||
T_488hevc_conformance_window_with_cropping:71d84f56384c2d25fe55477766b7604d:passed:20150329-220212:0.705828455
|
||||
T_489dts_es:6f9fb5e7a5144060ce4b19ee146bb03a-0770ee503180e4d8cfd57335e684921d-99ccde4d9e7b1cd0ff711edfe9cdad1e:passed:20150403-115948:1.604769748
|
||||
T_490sequence_numbers_no_0_in_first_gop:10a0cc2f79acd8cb520661b45721e652:new:20150411-142423:0.832402022
|
||||
|
5
tests/test-490sequence_numbers_no_0_in_first_gop.rb
Executable file
5
tests/test-490sequence_numbers_no_0_in_first_gop.rb
Executable file
@ -0,0 +1,5 @@
|
||||
#!/usr/bin/ruby -w
|
||||
|
||||
# T_490sequence_numbers_no_0_in_first_gop
|
||||
describe "mkvmerge / MPEG-2 ES without a sequence number == 0 in the first GOP"
|
||||
test_merge "data/mpeg12/sequence_numbers_no_0_in_first_gop.m2v"
|
Loading…
Reference in New Issue
Block a user