Detect and handle the absence of comment packets in non-native streams (aka "AVI compatibility mode streams").

This commit is contained in:
Moritz Bunkus 2004-05-31 18:37:40 +00:00
parent f29ec94254
commit ce0c8a6986
3 changed files with 73 additions and 32 deletions

View File

@ -1,3 +1,8 @@
2004-05-31 Moritz Bunkus <moritz@bunkus.org>
* mkvmerge: bug fix: Improved handling for OGM files. Streams that
are lacking the comment packet are handled better.
2004-05-29 Moritz Bunkus <moritz@bunkus.org>
* mkvmerge: bug fix: Some MP3 streams are padded in the front with

View File

@ -690,6 +690,16 @@ ogm_reader_c::packet_available() {
return 1;
}
void
ogm_reader_c::handle_new_stream_and_packets(ogg_page *og) {
ogm_demuxer_t *dmx;
handle_new_stream(og);
dmx = find_demuxer(ogg_page_serialno(og));
if (dmx != NULL)
process_header_packets(dmx);
}
/*
* The page is the beginning of a new stream. Check the contents for known
* stream headers. If it is a known stream and the user has requested that
@ -794,6 +804,7 @@ ogm_reader_c::handle_new_stream(ogg_page *og) {
dmx->serial = ogg_page_serialno(og);
memcpy(&dmx->os, &new_oss, sizeof(ogg_stream_state));
dmx->sid = nvstreams;
dmx->native_mode = false;
add_new_demuxer(dmx);
if (video_fps < 0)
video_fps = 10000000.0 / (float)get_uint64(&sth->time_unit);
@ -832,6 +843,7 @@ ogm_reader_c::handle_new_stream(ogg_page *og) {
dmx->serial = ogg_page_serialno(og);
memcpy(&dmx->os, &new_oss, sizeof(ogg_stream_state));
dmx->sid = nastreams;
dmx->native_mode = false;
add_new_demuxer(dmx);
return;
@ -850,6 +862,7 @@ ogm_reader_c::handle_new_stream(ogg_page *og) {
dmx->serial = ogg_page_serialno(og);
memcpy(&dmx->os, &new_oss, sizeof(ogg_stream_state));
dmx->sid = ntstreams;
dmx->native_mode = false;
add_new_demuxer(dmx);
return;
@ -880,10 +893,10 @@ void
ogm_reader_c::process_page(ogg_page *og) {
ogm_demuxer_t *dmx;
ogg_packet op;
int hdrlen, eos, i;
long lenbytes;
int duration_len, eos, i;
long duration;
lenbytes = 0;
duration = 0;
dmx = find_demuxer(ogg_page_serialno(og));
if (dmx == NULL)
return;
@ -891,6 +904,13 @@ ogm_reader_c::process_page(ogg_page *og) {
debug_enter("ogm_reader_c::process_page");
ogg_stream_pagein(&dmx->os, og);
if (dmx->skip_first_data_page) {
while (ogg_stream_packetout(&dmx->os, &op) == 1)
;
dmx->skip_first_data_page = false;
return;
}
while (ogg_stream_packetout(&dmx->os, &op) == 1) {
eos = op.e_o_s;
@ -924,32 +944,35 @@ ogm_reader_c::process_page(ogg_page *og) {
}
#endif
hdrlen = (*op.packet & PACKET_LEN_BITS01) >> 6;
hdrlen |= (*op.packet & PACKET_LEN_BITS2) << 1;
if ((hdrlen > 0) && (op.bytes >= (hdrlen + 1)))
for (i = 0, lenbytes = 0; i < hdrlen; i++) {
lenbytes = lenbytes << 8;
lenbytes += *((unsigned char *)op.packet + hdrlen - i);
duration_len = (*op.packet & PACKET_LEN_BITS01) >> 6;
duration_len |= (*op.packet & PACKET_LEN_BITS2) << 1;
if ((duration_len > 0) && (op.bytes >= (duration_len + 1)))
for (i = 0, duration = 0; i < duration_len; i++) {
duration = duration << 8;
duration += *((unsigned char *)op.packet + duration_len - i);
}
if (((*op.packet & 3) != PACKET_TYPE_HEADER) &&
((*op.packet & 3) != PACKET_TYPE_COMMENT)) {
if (dmx->stype == OGM_STREAM_TYPE_VIDEO) {
memory_c mem(&op.packet[hdrlen + 1], op.bytes - 1 - hdrlen, false);
memory_c mem(&op.packet[duration_len + 1], op.bytes - 1 -
duration_len, false);
PTZR(dmx->ptzr)->process(mem, -1, -1,
(*op.packet & PACKET_IS_SYNCPOINT ?
VFT_IFRAME : VFT_PFRAMEAUTOMATIC));
dmx->units_processed += (hdrlen > 0 ? lenbytes : 1);
dmx->units_processed += (duration_len > 0 ? duration : 1);
} else if (dmx->stype == OGM_STREAM_TYPE_TEXT) {
dmx->units_processed++;
if (((op.bytes - 1 - hdrlen) > 2) ||
((op.packet[hdrlen + 1] != ' ') &&
(op.packet[hdrlen + 1] != 0) && !iscr(op.packet[hdrlen + 1]))) {
memory_c mem(&op.packet[hdrlen + 1], op.bytes - 1 - hdrlen, false);
if (((op.bytes - 1 - duration_len) > 2) ||
((op.packet[duration_len + 1] != ' ') &&
(op.packet[duration_len + 1] != 0) &&
!iscr(op.packet[duration_len + 1]))) {
memory_c mem(&op.packet[duration_len + 1], op.bytes - 1 -
duration_len, false);
PTZR(dmx->ptzr)->process(mem, ogg_page_granulepos(og) * 1000000,
(int64_t)lenbytes * 1000000);
(int64_t)duration * 1000000);
}
} else if (dmx->stype == OGM_STREAM_TYPE_VORBIS) {
@ -957,7 +980,8 @@ ogm_reader_c::process_page(ogg_page *og) {
PTZR(dmx->ptzr)->process(mem);
} else {
memory_c mem(&op.packet[hdrlen + 1], op.bytes - 1 - hdrlen, false);
memory_c mem(&op.packet[duration_len + 1], op.bytes - 1 -
duration_len, false);
PTZR(dmx->ptzr)->process(mem);
dmx->units_processed += op.bytes - 1;
}
@ -973,26 +997,33 @@ ogm_reader_c::process_page(ogg_page *og) {
debug_leave("ogm_reader_c::process_page");
}
/*
* Search and store additional headers for the Vorbis streams.
*/
void
ogm_reader_c::process_header_page(ogg_page *og) {
ogm_demuxer_t *dmx;
ogg_packet op;
dmx = find_demuxer(ogg_page_serialno(og));
if (dmx == NULL)
return;
if (dmx->headers_read)
return;
ogg_stream_pagein(&dmx->os, og);
process_header_packets(dmx);
}
/*
* Search and store additional headers for the Ogg streams.
*/
void
ogm_reader_c::process_header_packets(ogm_demuxer_t *dmx) {
ogg_packet op;
if (dmx->headers_read)
return;
if (dmx->stype == OGM_STREAM_TYPE_FLAC) {
#if defined HAVE_FLAC_FORMAT_H
ogg_stream_pagein(&dmx->os, og);
while ((dmx->packet_data.size() < dmx->flac_header_packets) &&
(ogg_stream_packetout(&dmx->os, &op) == 1)) {
// while (ogg_stream_packetout(&dmx->os, &op) == 1) {
dmx->packet_data.push_back((unsigned char *)
safememdup(op.packet, op.bytes));
dmx->packet_sizes.push_back(op.bytes);
@ -1010,13 +1041,15 @@ ogm_reader_c::process_header_page(ogg_page *og) {
return;
}
ogg_stream_pagein(&dmx->os, og);
while (ogg_stream_packetout(&dmx->os, &op) == 1) {
if ((dmx->stype != OGM_STREAM_TYPE_VORBIS) &&
if (((dmx->stype != OGM_STREAM_TYPE_VORBIS) || !dmx->native_mode) &&
((op.packet[0] & PACKET_TYPE_BITS) != 1)) {
mxverb(2, "ogm_reader: Missing header/comment packets for %d.\n",
dmx->serial);
mxwarn("ogm_reader: Missing header/comment packets for stream %d in "
"'%s'. This file is broken but should be muxed correctly. If "
"not please contact the author Moritz Bunkus "
"<moritz@bunkus.org>.\n", dmx->serial, ti->fname);
dmx->headers_read = true;
dmx->skip_first_data_page = true;
return;
}
dmx->packet_data.push_back((unsigned char *)
@ -1049,7 +1082,7 @@ ogm_reader_c::read_headers() {
// Is this the first page of a new stream?
if (ogg_page_bos(&og))
handle_new_stream(&og);
handle_new_stream_and_packets(&og);
else { // No, so check if it's still a header page.
bos_pages_read = 1;
process_header_page(&og);

View File

@ -73,7 +73,7 @@ struct ogm_demuxer_t {
bool headers_set;
int sid, stype, serial, eos;
int units_processed, vorbis_rate;
bool headers_read;
bool headers_read, native_mode, skip_first_data_page;
char *language, *title;
vector<unsigned char *> packet_data, nh_packet_data;
vector<int> packet_sizes, nh_packet_sizes;
@ -85,7 +85,8 @@ struct ogm_demuxer_t {
ogm_demuxer_t():
ptzr(-1), sid(0), stype(0), serial(0), eos(0), units_processed(0),
vorbis_rate(0), headers_read(false), language(NULL), title(NULL) {
vorbis_rate(0), headers_read(false), native_mode(true),
skip_first_data_page(false), language(NULL), title(NULL) {
memset(&os, 0, sizeof(ogg_stream_state));
}
~ogm_demuxer_t() {
@ -124,10 +125,12 @@ private:
virtual int read_page(ogg_page *);
virtual void add_new_demuxer(ogm_demuxer_t *);
virtual void handle_new_stream(ogg_page *);
virtual void process_page(ogg_page *);
virtual void handle_new_stream_and_packets(ogg_page *);
virtual void process_page(ogg_page *);
virtual int packet_available();
virtual int read_headers();
virtual void process_header_page(ogg_page *);
virtual void process_header_page(ogg_page *pg);
virtual void process_header_packets(ogm_demuxer_t *dmx);
virtual void create_packetizers();
virtual void create_packetizer(int64_t tid);
virtual void free_demuxer(int);