diff --git a/src/common/ac3_common.cpp b/src/common/ac3_common.cpp index a52adb561..a47bd4c24 100644 --- a/src/common/ac3_common.cpp +++ b/src/common/ac3_common.cpp @@ -16,6 +16,7 @@ #include #include "ac3_common.h" +#include "common.h" /* AC3 Header: @@ -33,7 +34,7 @@ */ int -find_ac3_header(unsigned char *buf, +find_ac3_header(const unsigned char *buf, int size, ac3_header_t *ac3_header) { static int rate[] = { 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, @@ -111,3 +112,53 @@ find_ac3_header(unsigned char *buf, return -1; } + +int +find_consecutive_ac3_headers(const unsigned char *buf, + int size, + int num) { + int i, pos, base, offset; + ac3_header_t ac3header, new_header; + + pos = find_ac3_header(&buf[base], size - base, &ac3header); + if (pos < 0) + return -1; + mxverb(2, "ac3_reader: Found tag at %d size %d\n", base + pos, + ac3header.bytes); + base = pos + 1; + + if (num == 1) + return pos; + + do { + mxverb(2, "find_cons_ac3_h: starting with base at %d\n", base); + offset = ac3header.bytes; + for (i = 0; i < (num - 1); i++) { + if ((size - base - offset) < 4) + break; + pos = find_ac3_header(&buf[base + offset], size - base - offset, + &new_header); + if (pos == 0) { + if ((new_header.bsid == ac3header.bsid) && + (new_header.channels == ac3header.channels) && + (new_header.sample_rate == ac3header.sample_rate)) { + mxverb(2, "find_cons_ac3_h: found good header %d\n", i); + offset += new_header.bytes; + continue; + } else + break; + } else + break; + } + if (i == (num - 1)) + return base; + base++; + offset = 0; + pos = find_ac3_header(&buf[base], size - base, &ac3header); + if (pos == -1) + return -1; + base += pos; + } while (base < (size - 5)); + + return -1; +} diff --git a/src/common/ac3_common.h b/src/common/ac3_common.h index ceb48f723..0e684ff32 100644 --- a/src/common/ac3_common.h +++ b/src/common/ac3_common.h @@ -42,7 +42,9 @@ typedef struct { int bsid; } ac3_header_t; -int MTX_DLL_API find_ac3_header(unsigned char *buf, int size, +int MTX_DLL_API find_ac3_header(const unsigned char *buf, int size, ac3_header_t *ac3_header); +int MTX_DLL_API find_consecutive_ac3_headers(const unsigned char *buf, + int size, int num); #endif // __AC3COMMON_H diff --git a/src/input/r_ac3.cpp b/src/input/r_ac3.cpp index 4869fba19..90f0e6237 100644 --- a/src/input/r_ac3.cpp +++ b/src/input/r_ac3.cpp @@ -28,35 +28,12 @@ extern "C" { #include "r_ac3.h" #include "p_ac3.h" -#define PROBESIZE 8192 - int ac3_reader_c::probe_file(mm_io_c *mm_io, - int64_t size) { - unsigned char buf[PROBESIZE]; - int pos; - ac3_header_t ac3header; - - if (size < PROBESIZE) - return 0; - try { - mm_io->setFilePointer(0, seek_beginning); - if (mm_io->read(buf, PROBESIZE) != PROBESIZE) - return 0; - mm_io->setFilePointer(0, seek_beginning); - } catch (exception &ex) { - return 0; - } - - pos = find_ac3_header(buf, PROBESIZE, &ac3header); - if ((pos < 0) || ((pos + ac3header.bytes) >= PROBESIZE)) - return 0; - pos = find_ac3_header(&buf[pos + ac3header.bytes], PROBESIZE - pos - - ac3header.bytes, &ac3header); - if (pos != 0) - return 0; - - return 1; + int64_t size, + int64_t probe_size, + int num_headers) { + return (find_valid_headers(mm_io, probe_size, num_headers) != -1) ? 1 : 0; } ac3_reader_c::ac3_reader_c(track_info_c *nti) @@ -136,3 +113,23 @@ void ac3_reader_c::identify() { mxinfo("File '%s': container: AC3\nTrack ID 0: audio (AC3)\n", ti->fname); } + +int +ac3_reader_c::find_valid_headers(mm_io_c *mm_io, + int64_t probe_range, + int num_headers) { + unsigned char *buf; + int pos, nread; + + try { + mm_io->setFilePointer(0, seek_beginning); + buf = (unsigned char *)safemalloc(probe_range); + nread = mm_io->read(buf, probe_range); + pos = find_consecutive_ac3_headers(buf, nread, num_headers); + safefree(buf); + mm_io->setFilePointer(0, seek_beginning); + return pos; + } catch (...) { + return -1; + } +} diff --git a/src/input/r_ac3.h b/src/input/r_ac3.h index b8d118d09..7e9d129a4 100644 --- a/src/input/r_ac3.h +++ b/src/input/r_ac3.h @@ -43,7 +43,12 @@ public: virtual void identify(); virtual void create_packetizer(int64_t id); - static int probe_file(mm_io_c *mm_io, int64_t size); + static int probe_file(mm_io_c *mm_io, int64_t size, int64_t probe_size, + int num_headers); + +protected: + static int find_valid_headers(mm_io_c *mm_io, int64_t probe_range, + int num_headers); }; #endif // __R_AC3_H diff --git a/src/input/r_mp3.cpp b/src/input/r_mp3.cpp index 17f6c7f03..1354a310d 100644 --- a/src/input/r_mp3.cpp +++ b/src/input/r_mp3.cpp @@ -27,8 +27,10 @@ int mp3_reader_c::probe_file(mm_io_c *mm_io, - int64_t) { - return (find_valid_headers(mm_io) != -1) ? 1 : 0; + int64_t, + int64_t probe_range, + int num_headers) { + return (find_valid_headers(mm_io, probe_range, num_headers) != -1) ? 1 : 0; } mp3_reader_c::mp3_reader_c(track_info_c *nti) @@ -41,7 +43,7 @@ mp3_reader_c::mp3_reader_c(track_info_c *nti) mm_io = new mm_io_c(ti->fname, MODE_READ); size = mm_io->get_size(); - pos = find_valid_headers(mm_io); + pos = find_valid_headers(mm_io, 2 * 1024 * 1024, 5); if (pos < 0) throw error_c("Could not find a valid MP3 packet."); mm_io->setFilePointer(pos, seek_beginning); @@ -116,15 +118,17 @@ mp3_reader_c::identify() { } int -mp3_reader_c::find_valid_headers(mm_io_c *mm_io) { +mp3_reader_c::find_valid_headers(mm_io_c *mm_io, + int64_t probe_range, + int num_headers) { unsigned char *buf; int pos, nread; try { mm_io->setFilePointer(0, seek_beginning); - buf = (unsigned char *)safemalloc(2 * 1024 * 1024); - nread = mm_io->read(buf, 2 * 1024 * 1024); - pos = find_consecutive_mp3_headers(buf, nread, 5); + buf = (unsigned char *)safemalloc(probe_range); + nread = mm_io->read(buf, probe_range); + pos = find_consecutive_mp3_headers(buf, nread, num_headers); safefree(buf); mm_io->setFilePointer(0, seek_beginning); return pos; diff --git a/src/input/r_mp3.h b/src/input/r_mp3.h index 033c95cea..29867900b 100644 --- a/src/input/r_mp3.h +++ b/src/input/r_mp3.h @@ -44,10 +44,12 @@ public: virtual int display_priority(); virtual void display_progress(bool final = false); - static int probe_file(mm_io_c *mm_io, int64_t size); + static int probe_file(mm_io_c *mm_io, int64_t size, int64_t probe_range, + int num_headers = 5); protected: - static int find_valid_headers(mm_io_c *mm_io); + static int find_valid_headers(mm_io_c *mm_io, int64_t probe_range, + int num_headers); }; #endif // __R_MP3_H diff --git a/src/mkvmerge.cpp b/src/mkvmerge.cpp index 6e9301da8..75514864f 100644 --- a/src/mkvmerge.cpp +++ b/src/mkvmerge.cpp @@ -455,7 +455,9 @@ get_type(char *filename) { mm_io_c *mm_io; mm_text_io_c *mm_text_io; uint64_t size; - int type; + int type, i; + const int probe_sizes[] = {16 * 1024, 32 * 1024, 64 * 1024, 128 * 1024, + 256 * 1024, 0}; mm_io = NULL; mm_text_io = NULL; @@ -471,6 +473,7 @@ get_type(char *filename) { filename); } + type = TYPEUNKNOWN; if (avi_reader_c::probe_file(mm_io, size)) type = TYPEAVI; else if (kax_reader_c::probe_file(mm_io, size)) @@ -487,10 +490,17 @@ get_type(char *filename) { type = TYPEQTMP4; else if (tta_reader_c::probe_file(mm_io, size)) type = TYPETTA; - else if (mp3_reader_c::probe_file(mm_io, size)) + else { + for (i = 0; (probe_sizes[i] != 0) && (type == TYPEUNKNOWN); i++) + if (mp3_reader_c::probe_file(mm_io, size, probe_sizes[i], 5)) + type = TYPEMP3; + else if (ac3_reader_c::probe_file(mm_io, size, probe_sizes[i], 5)) + type = TYPEAC3; + } + if (type != TYPEUNKNOWN) + ; + else if (mp3_reader_c::probe_file(mm_io, size, 2 * 1024 * 1024, 10)) type = TYPEMP3; - else if (ac3_reader_c::probe_file(mm_io, size)) - type = TYPEAC3; else if (dts_reader_c::probe_file(mm_io, size)) type = TYPEDTS; else if (aac_reader_c::probe_file(mm_io, size)) diff --git a/tests/results.txt b/tests/results.txt index add8d6c87..3ddd40281 100644 --- a/tests/results.txt +++ b/tests/results.txt @@ -29,4 +29,5 @@ T_028compression:f6c15855e42e5a0e80d22a2060ae13e8:passed:20040825-234348 T_029link:b3076d997bcdb4202de374ba77a2a5c6:passed:20040825-235039 T_032cues:2d852a5c1ee169ddc713318c86a0b616:passed:20040825-235040 T_033timecode_scale:ba6bc8dff27d7d9fd433670067fa716d-d54414d993caad6cea47ef7913cb13db:passed:20040825-235040 +T_034ac3misdetected_as_mp2:f6765afb6d86ae09e0859f32ba65ced4:passed:20040920-100447 T_200mp2_from_mp4:d8b1beaaec801d787389ff210b605948:passed:20040917-185156 diff --git a/tests/test-034ac3misdetected_as_mp2.rb b/tests/test-034ac3misdetected_as_mp2.rb new file mode 100644 index 000000000..5ab312e17 --- /dev/null +++ b/tests/test-034ac3misdetected_as_mp2.rb @@ -0,0 +1,13 @@ +#!/usr/bin/ruby -w + +class T_034ac3misdetected_as_mp2 < Test + def description + return "mkvmerge / AC3 misdetected as MP2 / in(AC3)" + end + + def run + merge("data/simple/misdetected_as_mp2.ac3") + return hash_tmp + end +end +