mirror of
https://gitlab.com/mbunkus/mkvtoolnix.git
synced 2024-12-23 19:31:44 +00:00
Support for parsing MPEG-2 PS streams.
This commit is contained in:
parent
dfc5132ac9
commit
37a9a6457d
@ -28,6 +28,7 @@
|
||||
#include "r_mpeg.h"
|
||||
#include "smart_pointers.h"
|
||||
#include "p_ac3.h"
|
||||
#include "p_dts.h"
|
||||
#include "p_mp3.h"
|
||||
#include "p_video.h"
|
||||
|
||||
@ -265,16 +266,16 @@ mpeg_ps_reader_c::mpeg_ps_reader_c(track_info_c *nti)
|
||||
try {
|
||||
uint32_t header;
|
||||
uint8_t byte;
|
||||
bool streams_found[256], done;
|
||||
bool done;
|
||||
int i;
|
||||
|
||||
mm_io = new mm_file_io_c(ti->fname);
|
||||
size = mm_io->get_size();
|
||||
file_done = false;
|
||||
|
||||
bytes_processed = 0;
|
||||
|
||||
memset(streams_found, 0, sizeof(bool) * 256);
|
||||
for (i = 0; i < 256; i++)
|
||||
for (i = 0; i < 512; i++)
|
||||
id2idx[i] = -1;
|
||||
header = mm_io->read_uint32_be();
|
||||
done = mm_io->eof();
|
||||
@ -334,9 +335,9 @@ mpeg_ps_reader_c::mpeg_ps_reader_c(track_info_c *nti)
|
||||
}
|
||||
|
||||
stream_id = header & 0xff;
|
||||
if (!streams_found[stream_id])
|
||||
found_new_stream(stream_id);
|
||||
streams_found[stream_id] = true;
|
||||
mm_io->save_pos();
|
||||
found_new_stream(stream_id);
|
||||
mm_io->restore_pos();
|
||||
pes_packet_length = mm_io->read_uint16_be();
|
||||
mxverb(3, "mpeg_ps: id 0x%02x len %u at %lld\n", stream_id,
|
||||
pes_packet_length, mm_io->getFilePointer() - 4 - 2);
|
||||
@ -351,11 +352,35 @@ mpeg_ps_reader_c::mpeg_ps_reader_c(track_info_c *nti)
|
||||
done |= mm_io->eof() || (mm_io->getFilePointer() >= PS_PROBE_SIZE);
|
||||
} // while (!done)
|
||||
|
||||
mxverb(3, "mpeg_ps: Streams found: ");
|
||||
mxverb(2, "mpeg_ps: Streams found: ");
|
||||
for (i = 0; i < 256; i++)
|
||||
if (streams_found[i])
|
||||
mxverb(3, "%02x ", i);
|
||||
mxverb(3, "\n");
|
||||
if (id2idx[i] != -1)
|
||||
mxverb(2, "%02x ", i);
|
||||
for (i = 256 ; i < 512; i++)
|
||||
if (id2idx[i] != -1)
|
||||
mxverb(2, "bd(%02x) ", i - 256);
|
||||
mxverb(2, "\n");
|
||||
|
||||
// Calculate by how much the timecodes have to be offset
|
||||
if (tracks.size() > 0) {
|
||||
int64_t min_timecode;
|
||||
|
||||
min_timecode = tracks[0]->timecode_offset;
|
||||
for (i = 1; i < tracks.size(); i++)
|
||||
if (tracks[i]->timecode_offset < min_timecode)
|
||||
min_timecode = tracks[i]->timecode_offset;
|
||||
for (i = 0; i < tracks.size(); i++)
|
||||
tracks[i]->timecode_offset -= min_timecode;
|
||||
|
||||
mxverb(2, "mpeg_ps: Timecode offset: min was %lld ", min_timecode);
|
||||
for (i = 0; i < tracks.size(); i++)
|
||||
if (tracks[i]->id > 0xff)
|
||||
mxverb(2, "bd(%d)=%lld ", tracks[i]->id - 256,
|
||||
tracks[i]->timecode_offset);
|
||||
else
|
||||
mxverb(2, "%d=%lld ", tracks[i]->id, tracks[i]->timecode_offset);
|
||||
mxverb(2, "\n");
|
||||
}
|
||||
|
||||
mm_io->setFilePointer(0, seek_beginning);
|
||||
|
||||
@ -390,7 +415,8 @@ mpeg_ps_reader_c::read_timestamp(int c,
|
||||
bool
|
||||
mpeg_ps_reader_c::parse_packet(int id,
|
||||
int64_t ×tamp,
|
||||
int &length) {
|
||||
int &length,
|
||||
int &aid) {
|
||||
uint8_t c;
|
||||
|
||||
length = mm_io->read_uint16_be();
|
||||
@ -404,6 +430,8 @@ mpeg_ps_reader_c::parse_packet(int id,
|
||||
if (length == 0)
|
||||
return false;
|
||||
|
||||
aid = -1;
|
||||
|
||||
c = 0;
|
||||
// Skip stuFFing bytes
|
||||
while (length > 0) {
|
||||
@ -436,7 +464,59 @@ mpeg_ps_reader_c::parse_packet(int id,
|
||||
length -= 5;
|
||||
|
||||
} else if ((c & 0xc0) == 0x80) {
|
||||
mxerror("mpeg_ps_reader: System-2 (VOB) streams are not supported yet.\n");
|
||||
int pts_flags;
|
||||
int hdrlen;
|
||||
|
||||
if ((c & 0x30) != 0x00)
|
||||
mxerror(FMT_FN "Reading encrypted VOBs is not supported.\n",
|
||||
ti->fname.c_str());
|
||||
pts_flags = mm_io->read_uint8() >> 6;
|
||||
hdrlen = mm_io->read_uint8();
|
||||
length -= 2;
|
||||
if (hdrlen > length)
|
||||
return false;
|
||||
|
||||
if ((pts_flags & 2) == 2) {
|
||||
if (hdrlen < 5)
|
||||
return false;
|
||||
c = mm_io->read_uint8();
|
||||
if (!read_timestamp(c, timestamp))
|
||||
return false;
|
||||
length -= 5;
|
||||
hdrlen -= 5;
|
||||
|
||||
}
|
||||
if (pts_flags == 3) {
|
||||
if (hdrlen < 5)
|
||||
return false;
|
||||
mm_io->skip(5);
|
||||
length -= 5;
|
||||
hdrlen -= 5;
|
||||
}
|
||||
|
||||
if (hdrlen > 0) {
|
||||
length -= hdrlen;
|
||||
mm_io->skip(hdrlen);
|
||||
}
|
||||
|
||||
if (id == 0xbd) { // DVD audio substream
|
||||
if (length < 4)
|
||||
return false;
|
||||
aid = mm_io->read_uint8();
|
||||
length--;
|
||||
|
||||
if ((aid >= 0x80) && (aid <= 0xbf)) {
|
||||
mm_io->skip(3); // number of frames, startpos
|
||||
length -= 3;
|
||||
|
||||
if (aid >= 0xa0) { // LPCM
|
||||
if (length < 3)
|
||||
return false;
|
||||
mm_io->skip(3);
|
||||
length -= 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else if (c != 0x0f)
|
||||
return false;
|
||||
@ -449,23 +529,44 @@ mpeg_ps_reader_c::parse_packet(int id,
|
||||
|
||||
void
|
||||
mpeg_ps_reader_c::found_new_stream(int id) {
|
||||
if ((id < 0xc0) || (id > 0xef))
|
||||
if (((id < 0xc0) || (id > 0xef)) && (id != 0xbd))
|
||||
return;
|
||||
|
||||
mm_io->save_pos();
|
||||
|
||||
try {
|
||||
int64_t timecode;
|
||||
int length;
|
||||
int length, aid;
|
||||
unsigned char *buf;
|
||||
|
||||
if (!parse_packet(id, timecode, length))
|
||||
if (!parse_packet(id, timecode, length, aid))
|
||||
throw false;
|
||||
|
||||
mpeg_ps_track_ptr track(new mpeg_ps_track_t);
|
||||
track->first_timecode = timecode;
|
||||
if ((id == 0xbd) && (aid == -1))
|
||||
return;
|
||||
|
||||
if (id < 0xe0) {
|
||||
if (id == 0xbd) // DVD audio substream
|
||||
id = 256 + aid;
|
||||
|
||||
if (id2idx[id] != -1)
|
||||
return;
|
||||
|
||||
mpeg_ps_track_ptr track(new mpeg_ps_track_t);
|
||||
track->timecode_offset = timecode;
|
||||
|
||||
if (id > 0xff) {
|
||||
if ((aid >= 0x20) && (aid <= 0x3f)) {
|
||||
track->type = 's';
|
||||
track->fourcc = FOURCC('V', 'S', 'U', 'B');
|
||||
} else if ((aid >= 0x80) && (aid <= 0x87)) {
|
||||
track->type = 'a';
|
||||
track->fourcc = FOURCC('A', 'C', '3', ' ');
|
||||
} else if ((aid >= 0x88) && (aid <= 0x90)) {
|
||||
track->type = 'a';
|
||||
track->fourcc = FOURCC('D', 'T', 'S', ' ');
|
||||
} else if ((aid >= 0xa0) && (aid <= 0xa8)) {
|
||||
track->type = 'a';
|
||||
track->fourcc = FOURCC('P', 'C', 'M', ' ');
|
||||
}
|
||||
} else if (id < 0xe0) {
|
||||
track->type = 'a';
|
||||
track->fourcc = FOURCC('M', 'P', '2', ' ');
|
||||
} else {
|
||||
@ -473,6 +574,9 @@ mpeg_ps_reader_c::found_new_stream(int id) {
|
||||
track->fourcc = FOURCC('m', 'p', 'g', '0' + version);
|
||||
}
|
||||
|
||||
if (track->type == '?')
|
||||
return;
|
||||
|
||||
autofree_ptr<unsigned char> af_buf(safemalloc(length));
|
||||
buf = af_buf;
|
||||
if (mm_io->read(buf, length) != length)
|
||||
@ -493,7 +597,7 @@ mpeg_ps_reader_c::found_new_stream(int id) {
|
||||
if (!find_next_packet_for_id(id))
|
||||
throw false;
|
||||
|
||||
if (!parse_packet(id, timecode, length))
|
||||
if (!parse_packet(id, timecode, length, aid))
|
||||
throw false;
|
||||
autofree_ptr<unsigned char> new_buf(safemalloc(length));
|
||||
if (mm_io->read(new_buf, length) != length)
|
||||
@ -527,14 +631,11 @@ mpeg_ps_reader_c::found_new_stream(int id) {
|
||||
}
|
||||
track->fourcc = FOURCC('m', 'p', 'g', '0' + track->v_version);
|
||||
|
||||
} else { // if (track->fourcc == ...)
|
||||
} else // if (track->fourcc == ...)
|
||||
// Unsupported video track type
|
||||
mm_io->restore_pos();
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
} else { // if (track->type == 'v')
|
||||
} else if (track->type == 'a') { // if (track->type == 'v')
|
||||
if (track->fourcc == FOURCC('M', 'P', '2', ' ')) {
|
||||
mp3_header_t header;
|
||||
|
||||
@ -554,17 +655,20 @@ mpeg_ps_reader_c::found_new_stream(int id) {
|
||||
track->a_sample_rate = header.sample_rate;
|
||||
track->a_bsid = header.bsid;
|
||||
|
||||
// } else if (track->fourcc == FOURCC('D', 'T', 'S', ' ')) {
|
||||
} else if (track->fourcc == FOURCC('D', 'T', 'S', ' ')) {
|
||||
if (find_dts_header(buf, length, &track->dts_header) != 0)
|
||||
throw "Error parsing the first DTS audio frame.";
|
||||
|
||||
// } else if (track->fourcc == FOURCC('P', 'C', 'M', ' ')) {
|
||||
|
||||
} else {
|
||||
} else
|
||||
// Unsupported audio track type
|
||||
mm_io->restore_pos();
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else
|
||||
// Unsupported track type
|
||||
return;
|
||||
|
||||
track->id = id;
|
||||
id2idx[id] = tracks.size();
|
||||
tracks.push_back(track);
|
||||
} catch(const char *msg) {
|
||||
@ -574,8 +678,6 @@ mpeg_ps_reader_c::found_new_stream(int id) {
|
||||
"header reading phase. This stream seems to be badly damaged.\n",
|
||||
ti->fname.c_str());
|
||||
}
|
||||
|
||||
mm_io->restore_pos();
|
||||
}
|
||||
|
||||
bool
|
||||
@ -678,8 +780,15 @@ mpeg_ps_reader_c::create_packetizer(int64_t id) {
|
||||
track->a_channels,
|
||||
track->a_bsid, ti));
|
||||
if (verbose)
|
||||
mxinfo(FMT_TID "Using the AC3 output module.\n",
|
||||
ti->fname.c_str(), id);
|
||||
mxinfo(FMT_TID "Using the AC3 output module.\n", ti->fname.c_str(),
|
||||
id);
|
||||
|
||||
} else if (track->fourcc == FOURCC('D', 'T', 'S', ' ')) {
|
||||
track->ptzr =
|
||||
add_packetizer(new dts_packetizer_c(this, track->dts_header, ti));
|
||||
if (verbose)
|
||||
mxinfo(FMT_TID "Using the DTS output module.\n", ti->fname.c_str(),
|
||||
id);
|
||||
|
||||
} else
|
||||
mxerror("mpeg_ps_reader: Should not have happened #1. %s", BUGMSG);
|
||||
@ -721,26 +830,43 @@ file_status_e
|
||||
mpeg_ps_reader_c::read(generic_packetizer_c *,
|
||||
bool) {
|
||||
int64_t timecode, packet_pos;
|
||||
int new_id, length;
|
||||
int new_id, length, aid;
|
||||
unsigned char *buf;
|
||||
|
||||
if (file_done)
|
||||
return FILE_STATUS_DONE;
|
||||
|
||||
try {
|
||||
while (find_next_packet(new_id)) {
|
||||
if ((id2idx[new_id] == -1) ||
|
||||
(tracks[id2idx[new_id]]->ptzr == -1)) {
|
||||
if ((new_id != 0xbd) &&
|
||||
((id2idx[new_id] == -1) ||
|
||||
(tracks[id2idx[new_id]]->ptzr == -1))) {
|
||||
mm_io->skip(mm_io->read_uint16_be());
|
||||
continue;
|
||||
}
|
||||
packet_pos = mm_io->getFilePointer() - 4;
|
||||
if (!parse_packet(new_id, timecode, length))
|
||||
return FILE_STATUS_DONE;
|
||||
|
||||
mxverb(2, "mpeg_ps: packet for %d length %d at %lld\n", new_id, length,
|
||||
packet_pos = mm_io->getFilePointer() - 4;
|
||||
if (!parse_packet(new_id, timecode, length, aid)) {
|
||||
file_done = true;
|
||||
return FILE_STATUS_DONE;
|
||||
}
|
||||
|
||||
if (new_id == 0xbd)
|
||||
new_id = 256 + aid;
|
||||
|
||||
if ((id2idx[new_id] == -1) ||
|
||||
(tracks[id2idx[new_id]]->ptzr == -1)) {
|
||||
mm_io->skip(length);
|
||||
continue;
|
||||
}
|
||||
|
||||
mxverb(3, "mpeg_ps: packet for %d length %d at %lld\n", new_id, length,
|
||||
packet_pos);
|
||||
|
||||
buf = (unsigned char *)safemalloc(length);
|
||||
if (mm_io->read(buf, length) != length) {
|
||||
safefree(buf);
|
||||
file_done = true;
|
||||
return FILE_STATUS_DONE;
|
||||
}
|
||||
|
||||
@ -751,6 +877,7 @@ mpeg_ps_reader_c::read(generic_packetizer_c *,
|
||||
}
|
||||
} catch(...) {
|
||||
}
|
||||
file_done = true;
|
||||
return FILE_STATUS_DONE;
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
#include "os.h"
|
||||
|
||||
#include "dts_common.h"
|
||||
#include "smart_pointers.h"
|
||||
#include "pr_generic.h"
|
||||
#include "M2VParser.h"
|
||||
@ -54,9 +55,10 @@ struct mpeg_ps_track_t {
|
||||
int ptzr;
|
||||
|
||||
char type; // 'v' for video, 'a' for audio, 's' for subs
|
||||
int id;
|
||||
uint32_t fourcc;
|
||||
|
||||
int64_t first_timecode;
|
||||
int64_t timecode_offset;
|
||||
|
||||
int v_version, v_width, v_height, v_dwidth, v_dheight;
|
||||
double v_frame_rate, v_aspect_ratio;
|
||||
@ -64,9 +66,10 @@ struct mpeg_ps_track_t {
|
||||
int raw_seq_hdr_size;
|
||||
|
||||
int a_channels, a_sample_rate, a_bits_per_sample, a_bsid;
|
||||
dts_header_t dts_header;
|
||||
|
||||
mpeg_ps_track_t():
|
||||
ptzr(-1), type(0), fourcc(0),
|
||||
ptzr(-1), type(0), fourcc(0), timecode_offset(-1),
|
||||
v_version(0), v_width(0), v_height(0), v_dwidth(0), v_dheight(0),
|
||||
v_frame_rate(0), v_aspect_ratio(0),
|
||||
raw_seq_hdr(NULL), raw_seq_hdr_size(0),
|
||||
@ -84,8 +87,9 @@ private:
|
||||
mm_io_c *mm_io;
|
||||
int64_t bytes_processed, size, duration;
|
||||
|
||||
int id2idx[256];
|
||||
int id2idx[512];
|
||||
int version;
|
||||
bool file_done;
|
||||
|
||||
vector<mpeg_ps_track_ptr> tracks;
|
||||
|
||||
@ -102,7 +106,7 @@ public:
|
||||
virtual void found_new_stream(int id);
|
||||
|
||||
virtual bool read_timestamp(int c, int64_t ×tamp);
|
||||
virtual bool parse_packet(int id, int64_t ×tamp, int &size);
|
||||
virtual bool parse_packet(int id, int64_t ×tamp, int &size, int &aid);
|
||||
virtual bool find_next_packet(int &id);
|
||||
virtual bool find_next_packet_for_id(int id);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user