diff --git a/ChangeLog b/ChangeLog index feddf94e8..7399238b5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2014-10-07 Moritz Bunkus + + * mkvmerge: bug fix: probing MPEG transport streams with certain + types of broken MPEG-2 inside caused mkvmerge to exit with an + error message. Such tracks are now ignored instead. + 2014-09-29 Moritz Bunkus * mkvmerge, mmg's chapter editor: fixed the default value for the diff --git a/src/input/r_mpeg_ts.cpp b/src/input/r_mpeg_ts.cpp index 6907b0804..9beb68b8b 100644 --- a/src/input/r_mpeg_ts.cpp +++ b/src/input/r_mpeg_ts.cpp @@ -116,6 +116,7 @@ mpeg_ts_track_c::new_stream_v_mpeg_1_2() { if (!m_m2v_parser) { m_m2v_parser = std::shared_ptr(new M2VParser); m_m2v_parser->SetProbeMode(); + m_m2v_parser->SetThrowOnError(true); } m_m2v_parser->WriteData(pes_payload->get_buffer(), pes_payload->get_size()); @@ -973,40 +974,50 @@ mpeg_ts_reader_c::parse_packet(unsigned char *buf) { return true; } +int +mpeg_ts_reader_c::determine_track_parameters(mpeg_ts_track_ptr const &track) { + if (track->type == PAT_TYPE) + return parse_pat(track->pes_payload->get_buffer()); + + else if (track->type == PMT_TYPE) + return parse_pmt(track->pes_payload->get_buffer()); + + else if (track->type == ES_VIDEO_TYPE) { + if (track->codec.is(CT_V_MPEG12)) + return track->new_stream_v_mpeg_1_2(); + else if (track->codec.is(CT_V_MPEG4_P10)) + return track->new_stream_v_avc(); + else if (track->codec.is(CT_V_VC1)) + return track->new_stream_v_vc1(); + + track->pes_payload->set_chunk_size(512 * 1024); + + } else if (track->type != ES_AUDIO_TYPE) + return -1; + + if (track->codec.is(CT_A_MP3)) + return track->new_stream_a_mpeg(); + else if (track->codec.is(CT_A_AAC)) + return track->new_stream_a_aac(); + else if (track->codec.is(CT_A_AC3)) + return track->new_stream_a_ac3(); + else if (track->codec.is(CT_A_DTS)) + return track->new_stream_a_dts(); + else if (track->codec.is(CT_A_PCM)) + return track->new_stream_a_pcm(); + else if (track->codec.is(CT_A_TRUEHD)) + return track->new_stream_a_truehd(); + + return -1; +} + void mpeg_ts_reader_c::probe_packet_complete(mpeg_ts_track_ptr &track) { int result = -1; - if (track->type == PAT_TYPE) - result = parse_pat(track->pes_payload->get_buffer()); - - else if (track->type == PMT_TYPE) - result = parse_pmt(track->pes_payload->get_buffer()); - - else if (track->type == ES_VIDEO_TYPE) { - if (track->codec.is(CT_V_MPEG12)) - result = track->new_stream_v_mpeg_1_2(); - else if (track->codec.is(CT_V_MPEG4_P10)) - result = track->new_stream_v_avc(); - else if (track->codec.is(CT_V_VC1)) - result = track->new_stream_v_vc1(); - - track->pes_payload->set_chunk_size(512 * 1024); - - } else if (track->type == ES_AUDIO_TYPE) { - if (track->codec.is(CT_A_MP3)) - result = track->new_stream_a_mpeg(); - else if (track->codec.is(CT_A_AAC)) - result = track->new_stream_a_aac(); - else if (track->codec.is(CT_A_AC3)) - result = track->new_stream_a_ac3(); - else if (track->codec.is(CT_A_DTS)) - result = track->new_stream_a_dts(); - else if (track->codec.is(CT_A_PCM)) - result = track->new_stream_a_pcm(); - else if (track->codec.is(CT_A_TRUEHD)) - result = track->new_stream_a_truehd(); - + try { + result = determine_track_parameters(track); + } catch (...) { } track->pes_payload->remove(track->pes_payload->get_size()); diff --git a/src/input/r_mpeg_ts.h b/src/input/r_mpeg_ts.h index 4c8a4cc0d..58fbe750b 100644 --- a/src/input/r_mpeg_ts.h +++ b/src/input/r_mpeg_ts.h @@ -414,6 +414,7 @@ private: int parse_pmt(unsigned char *pmt); bool parse_start_unit_packet(mpeg_ts_track_ptr &track, mpeg_ts_packet_header_t *ts_packet_header, unsigned char *&ts_payload, unsigned char &ts_payload_size); void probe_packet_complete(mpeg_ts_track_ptr &track); + int determine_track_parameters(mpeg_ts_track_ptr const &track); file_status_e finish(); int send_to_packetizer(mpeg_ts_track_ptr &track); diff --git a/src/mpegparser/M2VParser.cpp b/src/mpegparser/M2VParser.cpp index e3d8a4d50..bbcc1c215 100644 --- a/src/mpegparser/M2VParser.cpp +++ b/src/mpegparser/M2VParser.cpp @@ -102,8 +102,9 @@ void M2VParser::DumpQueues(){ } } -M2VParser::M2VParser(){ - +M2VParser::M2VParser() + : throwOnError{} +{ mpgBuf = new MPEGVideoBuffer(BUFF_SIZE); notReachedFirstGOP = true; @@ -237,7 +238,10 @@ int32_t M2VParser::OrderFrame(MPEGFrame* frame){ bool flushQueue = false; if (waitSecondField && (p->pictureStructure == MPEG2_PICTURE_TYPE_FRAME)){ - mxerror(Y("Unexpected picture frame after single field frame. Fix the MPEG2 video stream before attempting to multiplex it.\n")); + auto error = Y("Unexpected picture frame after single field frame. Fix the MPEG2 video stream before attempting to multiplex it.\n"); + if (throwOnError) + throw error; + mxerror(error); } if((p->timecode == queueTime) && waitQueue.empty()){ @@ -389,7 +393,10 @@ int32_t M2VParser::FillQueues(){ gopNum++; /* Perform some sanity checks */ if(waitSecondField){ - mxerror(Y("Single field frame before GOP header detected. Fix the MPEG2 video stream before attempting to multiplex it.\n")); + auto error = Y("Single field frame before GOP header detected. Fix the MPEG2 video stream before attempting to multiplex it.\n"); + if (throwOnError) + throw error; + mxerror(error); } // There are too many broken videos to do the following so ReferenceBlock will be wrong for broken videos. /* @@ -433,8 +440,12 @@ int32_t M2VParser::FillQueues(){ break; default: //B-frames if(firstRef == -1 || secondRef == -1){ - if(!m_gopHdr.closedGOP && !m_gopHdr.brokenLink && (0 < gopNum)) - mxerror(Y("Found B frame without second reference in a non closed GOP. Fix the MPEG2 video stream before attempting to multiplex it.\n")); + if(!m_gopHdr.closedGOP && !m_gopHdr.brokenLink && (0 < gopNum)) { + auto error = Y("Found B frame without second reference in a non closed GOP. Fix the MPEG2 video stream before attempting to multiplex it.\n"); + if (throwOnError) + throw error; + mxerror(error); + } invisible = true; } PrepareFrame(chunk, myTime, picHdr); @@ -468,3 +479,8 @@ M2VParser::AddTimecode(int64_t timecode) { idx++; m_timecodes.insert(idx, timecode); } + +void +M2VParser::SetThrowOnError(bool doThrow) { + throwOnError = doThrow; +} diff --git a/src/mpegparser/M2VParser.h b/src/mpegparser/M2VParser.h index 20500faf8..ec41b8797 100644 --- a/src/mpegparser/M2VParser.h +++ b/src/mpegparser/M2VParser.h @@ -90,6 +90,7 @@ private: MPEG2ParserState_e parserState; MPEGVideoBuffer * mpgBuf; std::list m_timecodes; + bool throwOnError; int32_t InitParser(); void DumpQueues(); @@ -146,6 +147,8 @@ public: } void AddTimecode(int64_t timecode); + + void SetThrowOnError(bool doThrow); };