MPEG TS: don't exit on MPEG-1/2 errors

This commit is contained in:
Moritz Bunkus 2014-10-07 15:01:11 +02:00
parent 3c9a9c4737
commit 60dfa439e1
5 changed files with 73 additions and 36 deletions

View File

@ -1,3 +1,9 @@
2014-10-07 Moritz Bunkus <moritz@bunkus.org>
* 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 <moritz@bunkus.org>
* mkvmerge, mmg's chapter editor: fixed the default value for the

View File

@ -116,6 +116,7 @@ mpeg_ts_track_c::new_stream_v_mpeg_1_2() {
if (!m_m2v_parser) {
m_m2v_parser = std::shared_ptr<M2VParser>(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());

View File

@ -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);

View File

@ -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;
}

View File

@ -90,6 +90,7 @@ private:
MPEG2ParserState_e parserState;
MPEGVideoBuffer * mpgBuf;
std::list<int64_t> m_timecodes;
bool throwOnError;
int32_t InitParser();
void DumpQueues();
@ -146,6 +147,8 @@ public:
}
void AddTimecode(int64_t timecode);
void SetThrowOnError(bool doThrow);
};