Bug 1079747 - Follow WhatWG's MIMESniff spec for MP4 more closely. r=cpearce
authorMatthew Gregan <kinetik@flim.org>
Wed, 15 Oct 2014 13:57:38 +1300
changeset 210404 5f0732a51004
parent 210403 5a6c10740344
child 210405 edabc76c30f5
push id50433
push usermgregan@mozilla.com
push dateWed, 15 Oct 2014 00:58:30 +0000
treeherdermozilla-inbound@5f0732a51004 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscpearce
bugs1079747
milestone36.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 1079747 - Follow WhatWG's MIMESniff spec for MP4 more closely. r=cpearce
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