Bug 1027875 - Add MP4 support to MSE; r=kinetik
authorAnthony Jones <ajones@mozilla.com>
Fri, 04 Jul 2014 20:31:20 +1200
changeset 192366 bd855ca58b41aa5393c7faea87a2e94afaf57d5c
parent 192365 00b90bfadaa25b12097f87c12cf90dcedca7e528
child 192367 00a68fd085d5682d3f15877973c2d9c4887825d2
push id45810
push userajones@mozilla.com
push dateFri, 04 Jul 2014 08:31:44 +0000
treeherdermozilla-inbound@00a68fd085d5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskinetik
bugs1027875
milestone33.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 1027875 - Add MP4 support to MSE; r=kinetik
content/media/mediasource/MediaSource.cpp
content/media/mediasource/SourceBuffer.cpp
content/media/mediasource/SourceBufferResource.h
--- a/content/media/mediasource/MediaSource.cpp
+++ b/content/media/mediasource/MediaSource.cpp
@@ -56,16 +56,19 @@ static const char* const gMediaSourceTyp
 };
 
 static nsresult
 IsTypeSupported(const nsAString& aType)
 {
   if (aType.IsEmpty()) {
     return NS_ERROR_DOM_INVALID_ACCESS_ERR;
   }
+  if (Preferences::GetBool("media.mediasource.ignore_codecs", false)) {
+    return NS_OK;
+  }
   // TODO: Further restrict this to formats in the spec.
   nsContentTypeParser parser(aType);
   nsAutoString mimeType;
   nsresult rv = parser.GetType(mimeType);
   if (NS_FAILED(rv)) {
     return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
   }
   bool found = false;
@@ -73,19 +76,16 @@ IsTypeSupported(const nsAString& aType)
     if (mimeType.EqualsASCII(gMediaSourceTypes[i])) {
       found = true;
       break;
     }
   }
   if (!found) {
     return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
   }
-  if (Preferences::GetBool("media.mediasource.ignore_codecs", false)) {
-    return NS_OK;
-  }
   // Check aType against HTMLMediaElement list of MIME types.  Since we've
   // already restricted the container format, this acts as a specific check
   // of any specified "codecs" parameter of aType.
   if (dom::HTMLMediaElement::GetCanPlay(aType) == CANPLAY_NO) {
     return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
   }
   return NS_OK;
 }
--- a/content/media/mediasource/SourceBuffer.cpp
+++ b/content/media/mediasource/SourceBuffer.cpp
@@ -5,16 +5,17 @@
 
 #include "SourceBuffer.h"
 
 #include "AsyncEventRunner.h"
 #include "DecoderTraits.h"
 #include "MediaDecoder.h"
 #include "MediaSourceDecoder.h"
 #include "SourceBufferResource.h"
+#include "mozilla/Endian.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/dom/MediaSourceBinding.h"
 #include "mozilla/dom/TimeRanges.h"
 #include "nsError.h"
 #include "nsIEventTarget.h"
 #include "nsIRunnable.h"
 #include "nsThreadUtils.h"
@@ -147,24 +148,45 @@ public:
     if (aLength >= 4 &&
         aData[0] == 0x1a && aData[1] == 0x45 && aData[2] == 0xdf && aData[3] == 0xa3) {
       return true;
     }
     return false;
   }
 };
 
+class MP4ContainerParser : public ContainerParser {
+public:
+  bool IsInitSegmentPresent(const uint8_t* aData, uint32_t aLength)
+  {
+    // Each MP4 atom has a chunk size and chunk type. The root chunk in an MP4
+    // file is the 'ftyp' atom followed by a file type. We just check for a
+    // vaguely valid 'ftyp' atom.
+
+    if (aLength < 8) {
+      return false;
+    }
+
+    uint32_t chunk_size = BigEndian::readUint32(aData);
+    return chunk_size > 8 && aData[4] == 'f' && aData[5] == 't' &&
+      aData[6] == 'y' && aData[7] == 'p';
+  }
+};
+
+
 /*static*/ ContainerParser*
 ContainerParser::CreateForMIMEType(const nsACString& aType)
 {
   if (aType.LowerCaseEqualsLiteral("video/webm") || aType.LowerCaseEqualsLiteral("audio/webm")) {
     return new WebMContainerParser();
   }
 
-  // XXX: Plug in parsers for MPEG4, etc. here.
+  if (aType.LowerCaseEqualsLiteral("video/mp4") || aType.LowerCaseEqualsLiteral("audio/mp4")) {
+    return new MP4ContainerParser();
+  }
   return new ContainerParser();
 }
 
 namespace dom {
 
 void
 SourceBuffer::SetMode(SourceBufferAppendMode aMode, ErrorResult& aRv)
 {
--- a/content/media/mediasource/SourceBufferResource.h
+++ b/content/media/mediasource/SourceBufferResource.h
@@ -228,17 +228,17 @@ public:
   virtual nsresult Seek(int32_t aWhence, int64_t aOffset) MOZ_OVERRIDE;
   virtual void StartSeekingForMetadata() MOZ_OVERRIDE { }
   virtual void EndSeekingForMetadata() MOZ_OVERRIDE {}
   virtual int64_t Tell() MOZ_OVERRIDE { return mOffset; }
   virtual void Pin() MOZ_OVERRIDE {}
   virtual void Unpin() MOZ_OVERRIDE {}
   virtual double GetDownloadRate(bool* aIsReliable) MOZ_OVERRIDE { return 0; }
   virtual int64_t GetLength() MOZ_OVERRIDE { return mInputBuffer.GetLength(); }
-  virtual int64_t GetNextCachedData(int64_t aOffset) MOZ_OVERRIDE { return aOffset; }
+  virtual int64_t GetNextCachedData(int64_t aOffset) MOZ_OVERRIDE { return GetLength() == aOffset ? -1 : aOffset; }
   virtual int64_t GetCachedDataEnd(int64_t aOffset) MOZ_OVERRIDE { return GetLength(); }
   virtual bool IsDataCachedToEndOfResource(int64_t aOffset) MOZ_OVERRIDE { return false; }
   virtual bool IsSuspendedByCache() MOZ_OVERRIDE { return false; }
   virtual bool IsSuspended() MOZ_OVERRIDE { return false; }
   virtual nsresult ReadFromCache(char* aBuffer, int64_t aOffset, uint32_t aCount) MOZ_OVERRIDE;
   virtual bool IsTransportSeekable() MOZ_OVERRIDE { return true; }
   virtual nsresult Open(nsIStreamListener** aStreamListener) MOZ_OVERRIDE { return NS_ERROR_FAILURE; }