diff --git a/ChangeLog b/ChangeLog index 89261f442..9025f1f13 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2004-05-31 Moritz Bunkus + + * mkvmerge: bug fix: Improved handling for OGM files. Streams that + are lacking the comment packet are handled better. + 2004-05-29 Moritz Bunkus * mkvmerge: bug fix: Some MP3 streams are padded in the front with diff --git a/src/input/r_ogm.cpp b/src/input/r_ogm.cpp index aa35b6aa6..284251bc2 100644 --- a/src/input/r_ogm.cpp +++ b/src/input/r_ogm.cpp @@ -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 " + ".\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); diff --git a/src/input/r_ogm.h b/src/input/r_ogm.h index 9e551a5bb..c2a225fe7 100644 --- a/src/input/r_ogm.h +++ b/src/input/r_ogm.h @@ -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 packet_data, nh_packet_data; vector 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);