Bug 1079747 - Follow WhatWG's MIMESniff spec for MP4 more closely. r=cpearce, a=sledru
authorMatthew Gregan <kinetik@flim.org>
Wed, 15 Oct 2014 13:57:38 +1300
changeset 225726 f752e25f4c42
parent 225725 bb851de524c2
child 225727 3a24d0c65745
push id3992
push userryanvm@gmail.com
push date2014-10-17 13:09 +0000
treeherdermozilla-beta@f752e25f4c42 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscpearce, sledru
bugs1079747
milestone34.0
Bug 1079747 - Follow WhatWG's MIMESniff spec for MP4 more closely. r=cpearce, a=sledru
toolkit/components/mediasniffer/nsMediaSniffer.cpp
toolkit/components/mediasniffer/test/unit/data/bug1079747.mp4
toolkit/components/mediasniffer/test/unit/test_mediasniffer_ext.js
toolkit/components/mediasniffer/test/unit/xpcshell.ini
--- a/toolkit/components/mediasniffer/nsMediaSniffer.cpp
+++ b/toolkit/components/mediasniffer/nsMediaSniffer.cpp
@@ -33,16 +33,36 @@ nsMediaSniffer::nsMediaSnifferEntry nsMe
   // The string OggS, followed by the null byte.
   PATTERN_ENTRY("\xFF\xFF\xFF\xFF\xFF", "OggS", APPLICATION_OGG),
   // The string RIFF, followed by four bytes, followed by the string WAVE
   PATTERN_ENTRY("\xFF\xFF\xFF\xFF\x00\x00\x00\x00\xFF\xFF\xFF\xFF", "RIFF\x00\x00\x00\x00WAVE", AUDIO_WAV),
   // mp3 with ID3 tags, the string "ID3".
   PATTERN_ENTRY("\xFF\xFF\xFF", "ID3", AUDIO_MP3)
 };
 
+static bool MatchesMP4orISOBrand(const uint8_t aData[4])
+{
+  // Return true if aData contains the string "mp4" (last byte ignored).
+  if (aData[0] == 0x6D &&
+      aData[1] == 0x70 &&
+      aData[2] == 0x34) {
+    return true;
+  }
+
+  // Return true if aData contains the string "isom", or "iso2".
+  if (aData[0] == 0x69 &&
+      aData[1] == 0x73 &&
+      aData[2] == 0x6F &&
+      (aData[3] == 0x6D || aData[3] == 0x32)) {
+    return true;
+  }
+
+  return false;
+}
+
 // This function implements mp4 sniffing algorithm, described at
 // http://mimesniff.spec.whatwg.org/#signature-for-mp4
 static bool MatchesMP4(const uint8_t* aData, const uint32_t aLength)
 {
   if (aLength <= MP4_MIN_BYTES_COUNT) {
     return false;
   }
   // Conversion from big endian to host byte order.
@@ -54,34 +74,28 @@ static bool MatchesMP4(const uint8_t* aD
   }
   // The string "ftyp".
   if (aData[4] != 0x66 ||
       aData[5] != 0x74 ||
       aData[6] != 0x79 ||
       aData[7] != 0x70) {
     return false;
   }
-  for (uint32_t i = 2; i <= boxSize / 4 - 1 ; i++) {
-    if (i == 3) {
-      continue;
-    }
-    // The string "mp42" or "mp41".
-    if (aData[4*i]   == 0x6D &&
-        aData[4*i+1] == 0x70 &&
-        aData[4*i+2] == 0x34) {
+  if (MatchesMP4orISOBrand(&aData[8])) {
+    return true;
+  }
+  // Skip minor_version (bytes 12-15).
+  uint32_t bytesRead = 16;
+  while (bytesRead < boxSize) {
+    if (MatchesMP4orISOBrand(&aData[bytesRead])) {
       return true;
     }
-    // The string "isom" or "iso2".
-    if (aData[4*i]   == 0x69 &&
-        aData[4*i+1] == 0x73 &&
-        aData[4*i+2] == 0x6F &&
-        (aData[4*i+3] == 0x6D || aData[4*i+3] == 0x32)) {
-      return true;
-    }
+    bytesRead += 4;
   }
+
   return false;
 }
 
 static bool MatchesWebM(const uint8_t* aData, const uint32_t aLength)
 {
 #ifdef MOZ_WEBM
   return nestegg_sniff((uint8_t*)aData, aLength) ? true : false;
 #else
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..f00731d7e2719eef6ba82f4f88f946d73f3a2289
GIT binary patch
literal 512
zc${NkU|>iqsVqoIEC#X|GK=%g63dbea|=uiRj(viS6(^)cm{vky`DAePB1VW$@Xyb
z)oJb6$<UIUpI-)4pOagbkpj|qCZXI3gc%s)CxG}2j9`QSC>%__0|Q>b1jHJ-WvLZF
zTA`!}Ov6k;Gl}s<Nl{`pkP*Yc0CpQQ+-+dBtlM5KG3#49?^zcPyNGZp<0>HW0W8^)
zo06Fba#d~$_K*lY0@kLRk&;scGovgsB^BAsFd#qQBQY-}Cl#cIQ9m~`FAd00NrBKZ
sDMhJiNY3FYEy_`Vvfme%B;^3<$;BnbDM)IXLGg&gOCS$?VDJDk0Nof;J^%m!
--- a/toolkit/components/mediasniffer/test/unit/test_mediasniffer_ext.js
+++ b/toolkit/components/mediasniffer/test/unit/test_mediasniffer_ext.js
@@ -34,16 +34,18 @@ const tests = [
   // 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" },
   // Truncated ff installer regression test for bug 875769.
   { path: "data/ff-inst.exe", expected: "application/octet-stream" },
+  // MP4 with invalid box size (0) for "ftyp".
+  { path: "data/bug1079747.mp4", expected: "application/octet-stream" },
 ];
 
 // A basic listener that reads checks the if we sniffed properly.
 var listener = {
   onStartRequest: function(request, context) {
     do_print("Sniffing " + tests[testRan].path);
     do_check_eq(request.QueryInterface(Ci.nsIChannel).contentType, tests[testRan].expected);
   },
--- a/toolkit/components/mediasniffer/test/unit/xpcshell.ini
+++ b/toolkit/components/mediasniffer/test/unit/xpcshell.ini
@@ -1,13 +1,14 @@
 [DEFAULT]
 head =
 tail =
 skip-if = toolkit == 'android' || toolkit == 'gonk'
 support-files =
+  data/bug1079747.mp4
   data/detodos.mp3
   data/ff-inst.exe
   data/file.mkv
   data/file.webm
   data/fl10.mp2
   data/he_free.mp3
   data/id3tags.mp3
   data/notags-bad.mp3