Bug 865553 - Handle MPEG version 2 packet lengths. r=padenot
authorRalph Giles <giles@mozilla.com>
Fri, 09 Aug 2013 10:27:00 -0700
changeset 141895 1f5c5635e8752803c89ceeb83c3471a97626cda6
parent 141894 8ba04505ce739d880bd9670e8b68c5cf66d9ff23
child 141896 c1f4bf03306a7145c7fe3eaeb345797b2fe03865
push id32271
push userrgiles@mozilla.com
push dateFri, 09 Aug 2013 17:43:00 +0000
treeherdermozilla-inbound@1f5c5635e875 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspadenot
bugs865553
milestone26.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 865553 - Handle MPEG version 2 packet lengths. r=padenot Previous code didn't adjust bitrate and scale factors correctly for computing frame sizes on mpeg 2 and 2.5 files. See http://blog.coryhill.net/2009/06/calculating-mp3-frame-length.html for the extra factor of two. Removes a case for handling length calculation for layer-1 files, which we don't support. Adds a tagless mpeg-2 test case for the new sniffer code. Previous code didn't adjust bitrate and scale factors correctly for computing frame sizes on mpeg 2 and 2.5 files. See http://blog.coryhill.net/2009/06/calculating-mp3-frame-length.html for the extra factor of two. Removes a case for handling length calculation for layer-1 files, which we don't support. Adds a tagless mpeg-2 test case for the new sniffer code.
toolkit/components/mediasniffer/mp3sniff.c
toolkit/components/mediasniffer/test/unit/data/detodos.mp3
toolkit/components/mediasniffer/test/unit/test_mediasniffer_ext.js
--- a/toolkit/components/mediasniffer/mp3sniff.c
+++ b/toolkit/components/mediasniffer/mp3sniff.c
@@ -22,59 +22,62 @@ typedef struct {
   int copyright;
   int original;
   int emphasis;
 } mp3_header;
 
 /* Parse the 4-byte header in p and fill in the header struct. */
 static void mp3_parse(const uint8_t *p, mp3_header *header)
 {
-  const int bitrates[16] =
+  const int bitrates[2][16] = {
+        /* MPEG version 1 layer 3 bitrates. */
 	{0,  32000,  40000,  48000,  56000,  64000,  80000,  96000,
-         112000, 128000, 160000, 192000, 224000, 256000, 320000, 0};
+         112000, 128000, 160000, 192000, 224000, 256000, 320000, 0},
+        /* MPEG Version 2 and 2.5 layer 3 bitrates */
+        {0, 8000, 16000, 24000, 32000, 40000, 48000, 56000, 64000,
+         80000, 96000, 112000, 128000, 144000, 160000, 0} };
   const int samplerates[4] = {44100, 48000, 32000, 0};
 
-  header->version = (p[1] & 0x08) >> 3;
+  header->version = (p[1] & 0x18) >> 3;
   header->layer = 4 - ((p[1] & 0x06) >> 1);
   header->errp = (p[1] & 0x01);
 
-  header->bitrate = bitrates[(p[2] & 0xf0) >> 4];
+  header->bitrate = bitrates[(header->version & 1) ? 0 : 1][(p[2] & 0xf0) >> 4];
   header->freq = samplerates[(p[2] & 0x0c) >> 2];
+  if (header->version == 2) header->freq >>= 1;
+  else if (header->version == 0) header->freq >>= 2;
   header->pad = (p[2] & 0x02) >> 1;
   header->priv = (p[2] & 0x01);
 
   header->mode = (p[3] & 0xc0) >> 6;
   header->modex = (p[3] & 0x30) >> 4;
   header->copyright = (p[3] & 0x08) >> 3;
   header->original = (p[3] & 0x04) >> 2;
   header->emphasis = (p[3] & 0x03);
 }
 
 /* calculate the size of an mp3 frame from its header */
 static int mp3_framesize(mp3_header *header)
 {
   int size;
   int scale;
 
-  if (header->layer == 1) scale = 48;
+  if ((header->version & 1) == 0) scale = 72;
   else scale = 144;
-
   size = header->bitrate * scale / header->freq;
-  /* divide by an extra factor of 2 for MPEG-2? */
-
   if (header->pad) size += 1;
 
   return size;
 }
 
 static int is_mp3(const uint8_t *p, long length) {
   /* Do we have enough room to see a 4 byte header? */
   if (length < 4) return 0;
   /* Do we have a sync pattern? */
-  if (p[0] == 0xff && (p[1]&0xe0) == 0xe0) {
+  if (p[0] == 0xff && (p[1] & 0xe0) == 0xe0) {
     /* Do we have any illegal field values? */
     if (((p[1] & 0x06) >> 1) == 0) return 0;  /* No layer 4 */
     if (((p[2] & 0xf0) >> 4) == 15) return 0; /* Bitrate can't be 1111 */
     if (((p[2] & 0x0c) >> 2) == 3) return 0;  /* Samplerate can't be 11 */
     /* Looks like a header. */
     if ((4 - ((p[1] & 0x06) >> 1)) != 3) return 0; /* Only want level 3 */
     return 1;
   }
@@ -126,17 +129,17 @@ int mp3_sniff(const uint8_t *buf, long l
     if (is_id3(p, avail)) {
       /* Skip over any id3 tags */
       skip = id3_framesize(p, avail);
       p += skip;
       avail -= skip;
     } else if (is_mp3(p, avail)) {
       mp3_parse(p, &header);
       skip = mp3_framesize(&header);
-      if (skip < 4 || skip + 4 > avail) {
+      if (skip < 4 || skip + 4 >= avail) {
         return 0;
       }
       p += skip;
       avail -= skip;
       /* Check for a second header at the expected offset. */
       if (is_mp3(p, avail)) {
         /* Looks like mp3. */
         return 1;
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..12e3f89c2000a528d73b5c09c905024c8d86764d
GIT binary patch
literal 512
zc$@(M0{{L0^FYJ^3xTQ>JOD=QFp}JWZ~4Ff|KVSVNQhb@aT1%mx$hC({VYe^I2ahY
z3G(mZ{19{y|Nkg(P9Jaa=3g%|KfQAA<sRv-s98354Bo1S9mT>{Q=_Lv6r;v>3~WVc
zutsN6k>8;I^FqWe5((lQ5(tMxmFQ8M#-w@8LrBPm7*L#JY8vHAA~%0^<{sp#26coE
zW}1naO9NX`Pb`5u$UWF({es7w`sP-44X`Ar*dj9+EkvA}?s49b_jI3Dbkx<Ib#1n>
zksjcX!A5k+|MNh^Kocr<6c7l-gd|lUVoov+3^iO%+?`+G2_OILl#|zi<jwDunFX}L
z$mp?mU@*wZcy8<<m5fE8);@R5)FOgIrka_IlKmiriU3QQ6>$uK6s%I%y676jqM{v3
zvP05UIW-|w|MNn`P7-nU925vfoDB>Yryg_2=JNSvxuKTG{!0=%ALS-;md5V9hdU_-
zLfF|=mseFKh8@z>WjI;0ampLzmvv@&HKq&N>~v&?^3=2CjL%kQiZ3wKoYj4LPVj>S
z6%&_R5FEex>HqUU#9$TDP7nwHMhOnWs~jdGC`iB;ag>OQB^du@k_?(9V`pr9dTsIZ
zXXEeB7gI49QXiD?zp=OT>t4S7L_DO;vW{!MT9qI|2&{oUljFhXzRJ^^?TnQ_bScFn
C6Z|Fs
--- a/toolkit/components/mediasniffer/test/unit/test_mediasniffer_ext.js
+++ b/toolkit/components/mediasniffer/test/unit/test_mediasniffer_ext.js
@@ -22,16 +22,18 @@ const tests = [
   // Real webm and mkv files truncated to 512 bytes.
   { path: "data/file.webm", expected: "video/webm" },
   { path: "data/file.mkv", expected: "application/octet-stream" },
   // MP3 files with and without id3 headers truncated to 512 bytes.
   // NB these have 208/209 byte frames, but mp3 can require up to
   // 1445 bytes to detect with our method.
   { path: "data/id3tags.mp3", expected: "audio/mpeg" },
   { path: "data/notags.mp3", expected: "audio/mpeg" },
+  // MPEG-2 mp3 files.
+  { path: "data/detodos.mp3", expected: "audio/mpeg" },
   // Padding bit flipped in the first header: sniffing should fail.
   { path: "data/notags-bad.mp3", expected: "application/octet-stream" },
   // Garbage before header: sniffing should fail.
   { path: "data/notags-scan.mp3", expected: "application/octet-stream" },
   // VBR from the layer III test patterns. We can't sniff this.
   { path: "data/he_free.mp3", expected: "application/octet-stream" },
   // Make sure we reject mp2, which has a similar header.
   { path: "data/fl10.mp2", expected: "application/octet-stream" },