diff --git a/ChangeLog b/ChangeLog index b8f2cd9a2..53976b957 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2003-11-15 Moritz Bunkus + + * mkvmerge: bug fix: Reworked the audio sychronization which did + not work correctly for Matroska source files. + 2003-11-13 Moritz Bunkus * mkvmerge: bug fix: Increased the size of the space reserved for diff --git a/src/cluster_helper.cpp b/src/cluster_helper.cpp index 31a289bea..1c3075666 100644 --- a/src/cluster_helper.cpp +++ b/src/cluster_helper.cpp @@ -593,8 +593,6 @@ int cluster_helper_c::render() { return 1; } -#define iabs(a) ((a) < 0 ? (-1 * (a)) : (a)) - ch_contents_t *cluster_helper_c::find_packet_cluster(int64_t ref_timecode, void *source) { int i, k; diff --git a/src/common/common.h b/src/common/common.h index 837ea17e6..493570667 100644 --- a/src/common/common.h +++ b/src/common/common.h @@ -64,6 +64,8 @@ using namespace libebml; #define TYPEREAL 14 #define TYPEQTMP4 15 +#define iabs(a) ((a) < 0 ? (-1 * (a)) : (a)) + #define FOURCC(a, b, c, d) (uint32_t)((((unsigned char)a) << 24) + \ (((unsigned char)b) << 16) + \ (((unsigned char)c) << 8) + \ diff --git a/src/output/p_aac.cpp b/src/output/p_aac.cpp index d42705e48..1d200f205 100644 --- a/src/output/p_aac.cpp +++ b/src/output/p_aac.cpp @@ -74,21 +74,17 @@ unsigned char *aac_packetizer_c::get_aac_packet(unsigned long *header, if ((pos + aacheader->bytes) > size) return NULL; - pims = ((double)aacheader->bytes) * 1000.0 / - ((double)aacheader->bit_rate / 8.0); + pims = 1024000.0 / samples_per_sec; - if (ti->async.displacement < 0) { + if (needs_negative_displacement(pims)) { /* * AAC audio synchronization. displacement < 0 means skipping an * appropriate number of packets at the beginning. */ - ti->async.displacement += (int)pims; - if (ti->async.displacement > -(pims / 2)) - ti->async.displacement = 0; - + displace(-pims); byte_buffer.remove(pos + aacheader->bytes); - return 0; + return NULL; } if (verbose && (pos > 0)) @@ -120,7 +116,7 @@ unsigned char *aac_packetizer_c::get_aac_packet(unsigned long *header, } } - if (ti->async.displacement > 0) { + if (needs_positive_displacement(pims)) { /* * AAC audio synchronization. displacement > 0 is solved by duplicating * the very first AAC packet as often as necessary. I cannot create @@ -128,9 +124,8 @@ unsigned char *aac_packetizer_c::get_aac_packet(unsigned long *header, * settings the packet's values to 0 does not work as the AAC header * contains a CRC of its data. */ - ti->async.displacement -= (int)pims; - if (ti->async.displacement < (pims / 2)) - ti->async.displacement = 0; + mxinfo("displacing for %f\n", pims); + displace(pims); return buf; } @@ -177,7 +172,7 @@ int aac_packetizer_c::process(unsigned char *buf, int size, unsigned char *packet; unsigned long header; aac_header_t aacheader; - int64_t my_timecode; + int64_t my_timecode, duration; debug_enter("aac_packetizer_c::process"); @@ -185,25 +180,34 @@ int aac_packetizer_c::process(unsigned char *buf, int size, if (timecode != -1) my_timecode = timecode; else - my_timecode = (int64_t)(1000.0 * packetno * 1024 * ti->async.linear / - samples_per_sec); - add_packet(buf, size, my_timecode, - (int64_t)(1000.0 * 1024 * ti->async.linear / samples_per_sec)); + die("aac_packetizer_c::process: headerless && timecode == -1\n"); + duration = (int64_t)(1000.0 * 1024 * ti->async.linear / samples_per_sec); + + if (needs_negative_displacement(duration)) { + displace(-duration); + return EMOREDATA; + } + while (needs_positive_displacement(duration)) { + add_packet(buf, size, my_timecode + ti->async.displacement, duration); + displace(duration); + } + + my_timecode = (int64_t)((my_timecode + ti->async.displacement) * + ti->async.linear); + add_packet(buf, size, my_timecode, duration); debug_leave("aac_packetizer_c::process"); return EMOREDATA; } - if (timecode != -1) - my_timecode = timecode; - byte_buffer.add(buf, size); while ((packet = get_aac_packet(&header, &aacheader)) != NULL) { if (timecode == -1) - my_timecode = (int64_t)(1000.0 * packetno * 1024 * ti->async.linear / - samples_per_sec); - + my_timecode = (int64_t)(1000.0 * packetno * 1024 / samples_per_sec); + else + my_timecode = timecode + ti->async.displacement; + my_timecode = (int64_t)(my_timecode * ti->async.linear); add_packet(packet, aacheader.data_byte_size, my_timecode, (int64_t)(1000.0 * 1024 * ti->async.linear / samples_per_sec)); packetno++; diff --git a/src/output/p_ac3.cpp b/src/output/p_ac3.cpp index d3c2477f0..e91a48ff3 100644 --- a/src/output/p_ac3.cpp +++ b/src/output/p_ac3.cpp @@ -72,18 +72,14 @@ unsigned char *ac3_packetizer_c::get_ac3_packet(unsigned long *header, if ((pos + ac3header->bytes) > size) return NULL; - pims = ((double)ac3header->bytes) * 1000.0 / - ((double)ac3header->bit_rate / 8.0); + pims = 1536000.0 / samples_per_sec; - if (ti->async.displacement < 0) { + if (needs_negative_displacement(pims)) { /* * AC3 audio synchronization. displacement < 0 means skipping an * appropriate number of packets at the beginning. */ - ti->async.displacement += (int)pims; - if (ti->async.displacement > -(pims / 2)) - ti->async.displacement = 0; - + displace(-pims); byte_buffer.remove(pos + ac3header->bytes); return NULL; @@ -98,7 +94,7 @@ unsigned char *ac3_packetizer_c::get_ac3_packet(unsigned long *header, else buf = (unsigned char *)safememdup(packet_buffer + pos, ac3header->bytes); - if (ti->async.displacement > 0) { + if (needs_positive_displacement(pims)) { /* * AC3 audio synchronization. displacement > 0 is solved by duplicating * the very first AC3 packet as often as necessary. I cannot create @@ -106,10 +102,7 @@ unsigned char *ac3_packetizer_c::get_ac3_packet(unsigned long *header, * settings the packet's values to 0 does not work as the AC3 header * contains a CRC of its data. */ - ti->async.displacement -= (int)pims; - if (ti->async.displacement < (pims / 2)) - ti->async.displacement = 0; - + displace(pims); return buf; } @@ -141,15 +134,13 @@ int ac3_packetizer_c::process(unsigned char *buf, int size, debug_enter("ac3_packetizer_c::process"); - if (timecode != -1) - my_timecode = timecode; - add_to_buffer(buf, size); while ((packet = get_ac3_packet(&header, &ac3header)) != NULL) { if (timecode == -1) - my_timecode = (int64_t)(1000.0 * packetno * 1536 * ti->async.linear / - samples_per_sec); - + my_timecode = (int64_t)(1000.0 * packetno * 1536 / samples_per_sec); + else + my_timecode = timecode + initial_displacement; + my_timecode = (int64_t)(my_timecode * ti->async.linear); add_packet(packet, ac3header.bytes, my_timecode, (int64_t)(1000.0 * 1536 * ti->async.linear / samples_per_sec)); packetno++; diff --git a/src/output/p_dts.cpp b/src/output/p_dts.cpp index 77f1f9a7c..e3f760933 100644 --- a/src/output/p_dts.cpp +++ b/src/output/p_dts.cpp @@ -168,15 +168,12 @@ unsigned char *dts_packetizer_c::get_dts_packet(dts_header_t &dtsheader) { pims = get_dts_packet_length_in_milliseconds(&dtsheader); - if (ti->async.displacement < 0) { + if (needs_negative_displacement(pims)) { /* * DTS audio synchronization. displacement < 0 means skipping an * appropriate number of packets at the beginning. */ - ti->async.displacement += (int)pims; - if (ti->async.displacement > -(pims / 2)) - ti->async.displacement = 0; - + displace(-pims); remove_dts_packet(pos, dtsheader.frame_byte_size); return 0; @@ -190,7 +187,7 @@ unsigned char *dts_packetizer_c::get_dts_packet(dts_header_t &dtsheader) { buf = (unsigned char *)safememdup(packet_buffer + pos, dtsheader.frame_byte_size); - if (ti->async.displacement > 0) { + if (needs_positive_displacement(pims)) { /* * DTS audio synchronization. displacement > 0 is solved by duplicating * the very first DTS packet as often as necessary. I cannot create @@ -198,10 +195,7 @@ unsigned char *dts_packetizer_c::get_dts_packet(dts_header_t &dtsheader) { * settings the packet's values to 0 does not work as the DTS header * contains a CRC of its data. */ - ti->async.displacement -= (int)pims; - if (ti->async.displacement < (pims / 2)) - ti->async.displacement = 0; - + displace(pims); return buf; } @@ -237,11 +231,13 @@ int dts_packetizer_c::process(unsigned char *buf, int size, (int64_t)get_dts_packet_length_in_milliseconds(&dtsheader); if (timecode == -1) - my_timecode = (int64_t)(((double)samples_written*1000.0) / + my_timecode = (int64_t)(((double)samples_written * 1000.0) / ((double)dtsheader.core_sampling_frequency)); - + else + my_timecode = timecode + initial_displacement; + my_timecode = (int64_t)(my_timecode * ti->async.linear); add_packet(packet, dtsheader.frame_byte_size, my_timecode, - packet_len_in_ms); + (int64_t)(packet_len_in_ms * ti->async.linear)); bytes_written += dtsheader.frame_byte_size; samples_written += get_dts_packet_length_in_core_samples(&dtsheader); diff --git a/src/output/p_mp3.cpp b/src/output/p_mp3.cpp index 4547e8361..10eca21b1 100644 --- a/src/output/p_mp3.cpp +++ b/src/output/p_mp3.cpp @@ -43,10 +43,8 @@ mp3_packetizer_c::mp3_packetizer_c(generic_reader_c *nreader, spf = 1152; set_track_type(track_audio); - if (use_durations) - set_track_default_duration_ns((int64_t)(1152000000000.0 * - ti->async.linear / - samples_per_sec)); + set_track_default_duration_ns((int64_t)(1152000000000.0 * ti->async.linear / + samples_per_sec)); duplicate_data_on_add(false); } @@ -84,7 +82,7 @@ unsigned char *mp3_packetizer_c::get_mp3_packet(mp3_header_t *mp3header) { codec_id[codec_id.length() - 1] = (char)(mp3header->layer + '0'); *(static_cast (&GetChild(*track_entry))) = codec_id; - if ((spf != 1152) && use_durations) { + if (spf != 1152) { set_track_default_duration_ns((int64_t)(1000000000.0 * spf * ti->async.linear / samples_per_sec)); @@ -100,45 +98,44 @@ unsigned char *mp3_packetizer_c::get_mp3_packet(mp3_header_t *mp3header) { pims = 1000.0 * (float)spf / mp3header->sampling_frequency; - if (ti->async.displacement < 0) { + if (needs_negative_displacement(pims)) { /* * MP3 audio synchronization. displacement < 0 means skipping an * appropriate number of packets at the beginning. */ - ti->async.displacement += (int)pims; - if (ti->async.displacement > -(pims / 2)) - ti->async.displacement = 0; - + displace(-pims); byte_buffer.remove(mp3header->framesize + pos); return NULL; } - if ((verbose > 1) && (pos > 1)) - mxwarn("mp3_packetizer: skipping %d bytes (no valid MP3 header found).\n", - pos); + if (pos > 0) { + if (verbose) + mxwarn("mp3_packetizer: skipping %d bytes (no valid MP3 header found)." + "\n", pos); + byte_buffer.remove(pos); + pos = 0; + } if (fast_mode) buf = (unsigned char *)safemalloc(mp3header->framesize); else - buf = (unsigned char *)safememdup(byte_buffer.get_buffer() + pos, + buf = (unsigned char *)safememdup(byte_buffer.get_buffer(), mp3header->framesize); - if (ti->async.displacement > 0) { + if (needs_positive_displacement(pims)) { /* * MP3 audio synchronization. displacement > 0 is solved by creating * silent MP3 packets and repeating it over and over again (well only as * often as necessary of course. Wouldn't want to spoil your movie by * providing a silent MP3 stream ;)). */ - ti->async.displacement -= (int)pims; - if (ti->async.displacement < (pims / 2)) - ti->async.displacement = 0; + displace(pims); memset(buf + 4, 0, mp3header->framesize - 4); return buf; } - byte_buffer.remove(mp3header->framesize + pos); + byte_buffer.remove(mp3header->framesize); return buf; } @@ -155,28 +152,24 @@ int mp3_packetizer_c::process(unsigned char *buf, int size, int64_t timecode, int64_t, int64_t, int64_t) { unsigned char *packet; mp3_header_t mp3header; - int64_t my_timecode, old_packetno; + int64_t my_timecode; debug_enter("mp3_packetizer_c::process"); - if (timecode != -1) - my_timecode = timecode; - byte_buffer.add(buf, size); while ((packet = get_mp3_packet(&mp3header)) != NULL) { - old_packetno = packetno; - packetno++; - #ifdef DEBUG dump_packet(packet, mp3header.framesize); #endif if (timecode == -1) - my_timecode = (int64_t)(1000.0 * old_packetno * spf * ti->async.linear / - samples_per_sec); - + my_timecode = (int64_t)(1000.0 * packetno * spf / samples_per_sec); + else + my_timecode = timecode + ti->async.displacement; + my_timecode = (int64_t)(my_timecode * ti->async.linear); add_packet(packet, mp3header.framesize, my_timecode, (int64_t)(1000.0 * spf * ti->async.linear / samples_per_sec)); + packetno++; } debug_leave("mp3_packetizer_c::process"); diff --git a/src/output/p_passthrough.cpp b/src/output/p_passthrough.cpp index b4c298eb3..c0be5a43e 100644 --- a/src/output/p_passthrough.cpp +++ b/src/output/p_passthrough.cpp @@ -50,7 +50,25 @@ int passthrough_packetizer_c::process(unsigned char *buf, int size, packets_processed++; bytes_processed += size; + if (needs_negative_displacement(duration)) { + displace(-duration); + sync_to_keyframe = true; + return EMOREDATA; + } + while (needs_positive_displacement(duration)) { + add_packet(buf, size, (int64_t)((timecode + ti->async.displacement) * + ti->async.linear), bref, fref); + displace(duration); + } + if (sync_to_keyframe && (bref != -1)) { + if (!duplicate_data) + safefree(buf); + return EMOREDATA; + } + sync_to_keyframe = false; + timecode = (int64_t)((timecode + ti->async.displacement) * ti->async.linear); + duration = (int64_t)(duration * ti->async.linear); add_packet(buf, size, timecode, duration, false, bref, fref); debug_leave("passthrough_packetizer_c::process"); diff --git a/src/output/p_passthrough.h b/src/output/p_passthrough.h index b9aadc202..8e362fed8 100644 --- a/src/output/p_passthrough.h +++ b/src/output/p_passthrough.h @@ -29,6 +29,7 @@ class passthrough_packetizer_c: public generic_packetizer_c { private: int64_t packets_processed, bytes_processed; + bool sync_to_keyframe; public: passthrough_packetizer_c(generic_reader_c *nreader, track_info_t *nti) diff --git a/src/output/p_pcm.cpp b/src/output/p_pcm.cpp index f5ddecea8..24014910a 100644 --- a/src/output/p_pcm.cpp +++ b/src/output/p_pcm.cpp @@ -85,20 +85,20 @@ int pcm_packetizer_c::process(unsigned char *buf, int size, new_buf = buf; - if (ti->async.displacement != 0) { - if (ti->async.displacement > 0) { + if (initial_displacement != 0) { + if (initial_displacement > 0) { // Add silence. int pad_size; - pad_size = bps * ti->async.displacement / 1000; + pad_size = bps * initial_displacement / 1000; new_buf = (unsigned char *)safemalloc(size + pad_size); memset(new_buf, 0, pad_size); memcpy(&new_buf[pad_size], buf, size); size += pad_size; } else // Skip bytes. - remaining_sync = -1 * bps * ti->async.displacement / 1000; - ti->async.displacement = 0; + remaining_sync = -1 * bps * initial_displacement / 1000; + initial_displacement = 0; } if (remaining_sync > 0) { diff --git a/src/output/p_textsubs.cpp b/src/output/p_textsubs.cpp index 584deceec..2cb74dd12 100644 --- a/src/output/p_textsubs.cpp +++ b/src/output/p_textsubs.cpp @@ -75,9 +75,9 @@ int textsubs_packetizer_c::process(unsigned char *_subs, int, int64_t start, end = start + length; // Adjust the start and end values according to the audio adjustment. - start += ti->async.displacement; + start += initial_displacement; start = (int64_t)(ti->async.linear * start); - end += ti->async.displacement; + end += initial_displacement; end = (int64_t)(ti->async.linear * end); if (end < 0) diff --git a/src/output/p_vobsub.cpp b/src/output/p_vobsub.cpp index 4fa931324..a551076e2 100644 --- a/src/output/p_vobsub.cpp +++ b/src/output/p_vobsub.cpp @@ -72,10 +72,10 @@ void vobsub_packetizer_c::set_headers() { track_entry->EnableLacing(false); } -#define TIMECODE (timecode - ti->async.displacement) / 60 / 60 / 1000, \ - ((timecode - ti->async.displacement) / 60 / 1000) % 60, \ - ((timecode - ti->async.displacement) / 1000) % 60, \ - (timecode - ti->async.displacement) % 1000 +#define TIMECODE (timecode - initial_displacement) / 60 / 60 / 1000, \ + ((timecode - initial_displacement) / 60 / 1000) % 60, \ + ((timecode - initial_displacement) / 1000) % 60, \ + (timecode - initial_displacement) % 1000 #define FMT_TIMECODE "%02lld:%02lld:%02lld.%03lld" int vobsub_packetizer_c::extract_duration(unsigned char *data, int buf_size, @@ -156,7 +156,7 @@ int vobsub_packetizer_c::process(unsigned char *srcbuf, int size, packet_num++; - timecode += ti->async.displacement; + timecode += initial_displacement; if (timecode < 0) return EMOREDATA; diff --git a/src/output/p_vorbis.cpp b/src/output/p_vorbis.cpp index 4c0086dac..d6a349f82 100644 --- a/src/output/p_vorbis.cpp +++ b/src/output/p_vorbis.cpp @@ -71,6 +71,7 @@ vorbis_packetizer_c::vorbis_packetizer_c(generic_reader_c *nreader, if (use_durations) set_track_default_duration_ns((int64_t)(1024000000000.0 * ti->async.linear / vi.rate)); + ti->async.displacement = initial_displacement; } vorbis_packetizer_c::~vorbis_packetizer_c() { @@ -142,12 +143,8 @@ int vorbis_packetizer_c::process(unsigned char *data, int size, debug_enter("vorbis_packetizer_c::process"); - // Recalculate the timecode if needed. - if (timecode == -1) - timecode = samples * 1000 / vi.rate; - // Positive displacement, first packet? Well then lets create silence. - if ((packetno == 0) && (ti->async.displacement > 0)) { + if ((packetno == 0) && (initial_displacement > 0)) { // Create a fake packet so we can use vorbis_packet_blocksize(). zero[0] = 0; zero[1] = 0; @@ -156,7 +153,7 @@ int vorbis_packetizer_c::process(unsigned char *data, int size, op.bytes = 2; // Calculate how many samples we have to create. - samples_needed = vi.rate * ti->async.displacement / 1000; + samples_needed = vi.rate * initial_displacement / 1000; this_bs = vorbis_packet_blocksize(&vi, &op); samples_here = (this_bs + last_bs) / 4; @@ -167,8 +164,6 @@ int vorbis_packetizer_c::process(unsigned char *data, int size, add_packet(zero, 2, samples * 1000 / vi.rate, samples_here * 1000 / vi.rate); } - - ti->async.displacement = 0; } // Update the number of samples we have processed so that we can @@ -180,8 +175,14 @@ int vorbis_packetizer_c::process(unsigned char *data, int size, samples += samples_here; last_bs = this_bs; - // Handle the displacement. - timecode += ti->async.displacement; + // Recalculate the timecode if needed. + if (timecode == -1) { + if (initial_displacement > 0) + timecode = samples * 1000 / vi.rate; + else + timecode = samples * 1000 / vi.rate + initial_displacement; + } else + timecode += initial_displacement; // Handle the linear sync - simply multiply with the given factor. timecode = (int64_t)((double)timecode * ti->async.linear); diff --git a/src/pr_generic.cpp b/src/pr_generic.cpp index 12b3d56e4..12f6dd24d 100644 --- a/src/pr_generic.cpp +++ b/src/pr_generic.cpp @@ -51,6 +51,7 @@ generic_packetizer_c::generic_packetizer_c(generic_reader_c *nreader, ti = duplicate_track_info(nti); free_refs = -1; enqueued_bytes = 0; + safety_last_timecode = 0; // Let's see if the user specified audio sync for this track. found = false; @@ -66,6 +67,8 @@ generic_packetizer_c::generic_packetizer_c(generic_reader_c *nreader, ti->async.linear = 1.0; ti->async.displacement = 0; } + initial_displacement = ti->async.displacement; + ti->async.displacement = 0; // Let's see if the user has specified which cues he wants for this track. ti->cues = CUES_UNSPECIFIED; @@ -598,9 +601,14 @@ void generic_packetizer_c::add_packet(unsigned char *data, int length, if (data == NULL) return; - if (timecode < 0) - die("pr_generic.cpp/generic_packetizer_c::add_packet(): timecode < 0 " - "(%lld)", timecode); + if (timecode < 0) { + drop_packet(data); + return; + } + if (timecode < safety_last_timecode) + die("pr_generic.cpp/generic_packetizer_c::add_packet(): timecode < " + "last_timecode (%lld < %lld)", timecode, safety_last_timecode); + safety_last_timecode = timecode; pack = (packet_t *)safemalloc(sizeof(packet_t)); memset(pack, 0, sizeof(packet_t)); @@ -631,6 +639,11 @@ void generic_packetizer_c::add_packet(unsigned char *data, int length, enqueued_bytes += pack->length; } +void generic_packetizer_c::drop_packet(unsigned char *data) { + if (!duplicate_data) + safefree(data); +} + packet_t *generic_packetizer_c::get_packet() { packet_t *pack; @@ -842,6 +855,27 @@ int64_t generic_packetizer_c::get_next_timecode(int64_t timecode) { return new_timecode; } +bool generic_packetizer_c::needs_negative_displacement(float duration) { + return ((initial_displacement < 0) && + (ti->async.displacement > initial_displacement)); +} + +bool generic_packetizer_c::needs_positive_displacement(float duration) { + return ((initial_displacement > 0) && + (iabs(ti->async.displacement - initial_displacement) > + (duration / 2))); +} + +void generic_packetizer_c::displace(float by_ms) { + ti->async.displacement += (int64_t)by_ms; + if (initial_displacement < 0) { + if (ti->async.displacement < initial_displacement) + initial_displacement = 0; + } else if (iabs(initial_displacement - ti->async.displacement) < + (by_ms / 2)) + initial_displacement = 0; +} + //-------------------------------------------------------------------- generic_reader_c::generic_reader_c(track_info_t *nti) { diff --git a/src/pr_generic.h b/src/pr_generic.h index 79829e5f8..35ed758ad 100644 --- a/src/pr_generic.h +++ b/src/pr_generic.h @@ -145,7 +145,8 @@ protected: bool duplicate_data; track_info_t *ti; - int64_t free_refs, enqueued_bytes; + int64_t initial_displacement; + int64_t free_refs, enqueued_bytes, safety_last_timecode; KaxTrackEntry *track_entry; @@ -189,6 +190,7 @@ public: int64_t duration, bool duration_mandatory = false, int64_t bref = -1, int64_t fref = -1, int ref_priority = -1); + virtual void drop_packet(unsigned char *data); virtual packet_t *get_packet(); virtual int packet_available(); virtual int64_t get_smallest_timecode(); @@ -246,6 +248,10 @@ public: virtual int64_t get_next_timecode(int64_t timecode); virtual void parse_ext_timecode_file(const char *name); + virtual bool needs_negative_displacement(float duration); + virtual bool needs_positive_displacement(float duration); + virtual void displace(float by_ms); + protected: virtual void dump_packet(const void *buffer, int size); };