diff --git a/ChangeLog b/ChangeLog index 6f396f01c..a2e2501d2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2009-04-25 Moritz Bunkus + + * mkvmerge: bug fix: Made the AAC detection code stricter in what + it accepts. This results in fewer mis-detections. Fix for bugs 373 + and 374. + 2009-04-16 Moritz Bunkus * mkvmerge: bug fix: Splitting without the option "--engage diff --git a/src/common/aac_common.cpp b/src/common/aac_common.cpp index 727d9e4da..c284cab30 100644 --- a/src/common/aac_common.cpp +++ b/src/common/aac_common.cpp @@ -23,8 +23,8 @@ const int aac_sampling_freq[16] = {96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 0, 0, 0, 0}; // filling -bool -parse_aac_adif_header_internal(unsigned char *buf, +static bool +parse_aac_adif_header_internal(const unsigned char *buf, int size, aac_header_t *aac_header) { int i, k; @@ -93,7 +93,7 @@ parse_aac_adif_header_internal(unsigned char *buf, } bool -parse_aac_adif_header(unsigned char *buf, +parse_aac_adif_header(const unsigned char *buf, int size, aac_header_t *aac_header) { try { @@ -104,7 +104,7 @@ parse_aac_adif_header(unsigned char *buf, } static bool -is_adts_header(unsigned char *buf, +is_adts_header(const unsigned char *buf, int size, aac_header_t *aac_header, bool emphasis_present) { @@ -128,6 +128,8 @@ is_adts_header(unsigned char *buf, bc.skip_bits(2); // emphasis, MPEG-4 only bc.skip_bits(1 + 1); // copyright_id_bit & copyright_id_start frame_length = bc.get_bits(13); + if (0 == frame_length) + return false; bc.skip_bits(11); // adts_buffer_fullness bc.skip_bits(2); // no_raw_blocks_in_frame if (!protection_absent) @@ -153,7 +155,7 @@ is_adts_header(unsigned char *buf, } int -find_aac_header(unsigned char *buf, +find_aac_header(const unsigned char *buf, int size, aac_header_t *aac_header, bool emphasis_present) { @@ -184,7 +186,7 @@ get_aac_sampling_freq_idx(int sampling_freq) { } bool -parse_aac_data(unsigned char *data, +parse_aac_data(const unsigned char *data, int size, int &profile, int &channels, @@ -273,3 +275,66 @@ create_aac_data(unsigned char *data, } return 2; } + +int +find_consecutive_aac_headers(const unsigned char *buf, + int size, + int num) { + aac_header_t aac_header, new_header; + + int base = 0; + int pos = find_aac_header(&buf[base], size - base, &aac_header, false); + + if (0 > pos) + return -1; + + if (1 == num) + return pos; + base += pos; + + do { + mxverb(4, boost::format("find_cons_aac_h: starting with base at %1%\n") % base); + + int offset = aac_header.bytes; + int i; + for (i = 0; (num - 1) > i; ++i) { + if ((size - base - offset) < 2) + break; + + pos = find_aac_header(&buf[base + offset], size - base - offset, &new_header, false); + if (0 == pos) { + if (new_header == aac_header) { + mxverb(4, boost::format("find_cons_aac_h: found good header %1%\n") % i); + offset += new_header.bytes; + continue; + } else + break; + } else + break; + } + + if (i == (num - 1)) + return base; + + ++base; + offset = 0; + pos = find_aac_header(&buf[base], size - base, &aac_header, false); + + if (-1 == pos) + return -1; + + base += pos; + } while (base < (size - 5)); + + return -1; +} + +bool +operator ==(const aac_header_t &h1, + const aac_header_t &h2) { + return (h1.sample_rate == h2.sample_rate) + && (h1.bit_rate == h2.bit_rate) + && (h1.channels == h2.channels) + && (h1.id == h2.id) + && (h1.profile == h2.profile); +} diff --git a/src/common/aac_common.h b/src/common/aac_common.h index e42f70e2c..36e7de618 100644 --- a/src/common/aac_common.h +++ b/src/common/aac_common.h @@ -45,12 +45,15 @@ typedef struct { int header_bit_size, header_byte_size, data_byte_size; } aac_header_t; -bool MTX_DLL_API parse_aac_adif_header(unsigned char *buf, int size, aac_header_t *aac_header); -int MTX_DLL_API find_aac_header(unsigned char *buf, int size, aac_header_t *aac_header, bool emphasis_present); +bool MTX_DLL_API operator ==(const aac_header_t &h1, const aac_header_t &h2); + +bool MTX_DLL_API parse_aac_adif_header(const unsigned char *buf, int size, aac_header_t *aac_header); +int MTX_DLL_API find_aac_header(const unsigned char *buf, int size, aac_header_t *aac_header, bool emphasis_present); +int MTX_DLL_API find_consecutive_aac_headers(const unsigned char *buf, int size, int num); int MTX_DLL_API get_aac_sampling_freq_idx(int sampling_freq); -bool MTX_DLL_API parse_aac_data(unsigned char *data, int size, int &profile, int &channels, int &sample_rate, int &output_sample_rate, bool &sbr); +bool MTX_DLL_API parse_aac_data(const unsigned char *data, int size, int &profile, int &channels, int &sample_rate, int &output_sample_rate, bool &sbr); int MTX_DLL_API create_aac_data(unsigned char *data, int profile, int channels, int sample_rate, int output_sample_rate, bool sbr); bool MTX_DLL_API parse_aac_codec_id(const string &codec_id, int &id, int &profile); diff --git a/src/input/r_aac.cpp b/src/input/r_aac.cpp index beb42ceb5..922226f2a 100644 --- a/src/input/r_aac.cpp +++ b/src/input/r_aac.cpp @@ -22,49 +22,15 @@ #include "p_aac.h" #include "output_control.h" -#define PROBESIZE 8192 - int aac_reader_c::probe_file(mm_io_c *io, - int64_t size) { - unsigned char buf[PROBESIZE]; - aac_header_t aacheader; - int pos; - - if (size < PROBESIZE) - return 0; - try { - io->setFilePointer(0, seek_beginning); - skip_id3v2_tag(*io); - if (io->read(buf, PROBESIZE) != PROBESIZE) - io->setFilePointer(0, seek_beginning); - io->setFilePointer(0, seek_beginning); - } catch (...) { - return 0; - } - - if (parse_aac_adif_header(buf, PROBESIZE, &aacheader)) - return 1; - - pos = find_aac_header(buf, PROBESIZE, &aacheader, false); - if ((0 > pos) || ((pos + aacheader.bytes) >= PROBESIZE)) { - pos = find_aac_header(buf, PROBESIZE, &aacheader, true); - if ((0 > pos) || ((pos + aacheader.bytes) >= PROBESIZE)) - return 0; - pos = find_aac_header(&buf[pos + aacheader.bytes], PROBESIZE - pos - aacheader.bytes, &aacheader, true); - if (0 != pos) - return 0; - } - - pos = find_aac_header(&buf[pos + aacheader.bytes], PROBESIZE - pos - aacheader.bytes, &aacheader, false); - if (0 != pos) - return 0; - - return 1; + int64_t size, + int64_t probe_range, + int num_headers) { + return (find_valid_headers(io, probe_range, num_headers) != -1) ? 1 : 0; } -#define INITCHUNKSIZE 16384 -#define SINITCHUNKSIZE "16384" +#define INITCHUNKSIZE 16384 aac_reader_c::aac_reader_c(track_info_c &_ti) throw (error_c): @@ -219,3 +185,20 @@ aac_reader_c::identify() { id_result_container("AAC"); id_result_track(0, ID_RESULT_TRACK_AUDIO, "AAC", verbose_info); } + +int +aac_reader_c::find_valid_headers(mm_io_c *io, + int64_t probe_range, + int num_headers) { + try { + io->setFilePointer(0, seek_beginning); + memory_cptr buf = memory_c::alloc(probe_range); + int num_read = io->read(buf->get(), probe_range); + int pos = find_consecutive_aac_headers(buf->get(), num_read, num_headers); + io->setFilePointer(0, seek_beginning); + + return pos; + } catch (...) { + return -1; + } +} diff --git a/src/input/r_aac.h b/src/input/r_aac.h index 119887398..4b008a1af 100644 --- a/src/input/r_aac.h +++ b/src/input/r_aac.h @@ -42,10 +42,11 @@ public: virtual int get_progress(); virtual void create_packetizer(int64_t id); - static int probe_file(mm_io_c *io, int64_t size); + static int probe_file(mm_io_c *io, int64_t size, int64_t probe_range, int num_headers); protected: virtual void guess_adts_version(); + static int find_valid_headers(mm_io_c *io, int64_t probe_range, int num_headers); }; #endif // __R_AAC_H diff --git a/src/merge/output_control.cpp b/src/merge/output_control.cpp index 8312cfbd4..5dadb500c 100644 --- a/src/merge/output_control.cpp +++ b/src/merge/output_control.cpp @@ -353,6 +353,8 @@ get_file_type(filelist_t &file) { type = FILE_TYPE_MP3; else if (ac3_reader_c::probe_file(io, size, probe_sizes[i], 5)) type = FILE_TYPE_AC3; + else if (aac_reader_c::probe_file(io, size, probe_sizes[i], 5)) + type = FILE_TYPE_AAC; } // More file types with detection issues. if (type != FILE_TYPE_IS_UNKNOWN) @@ -363,8 +365,6 @@ get_file_type(filelist_t &file) { type = FILE_TYPE_MP3; else if (dts_reader_c::probe_file(io, size)) type = FILE_TYPE_DTS; - else if (aac_reader_c::probe_file(io, size)) - type = FILE_TYPE_AAC; else if (vobbtn_reader_c::probe_file(io, size)) type = FILE_TYPE_VOBBTN; else if (avc_es_reader_c::probe_file(io, size))