Bug 986947 - Make MP3 contained in MP4 playback again on Windows with WMF backend. r=padenot
authorChris Pearce <cpearce@mozilla.com>
Fri, 04 Apr 2014 10:39:42 +1300
changeset 177052 904297de3d1e7120e117cc3ce05bc81ba98cd8ad
parent 177051 9c208ea4d63c6a5a96948a5147e63896a1bc6f0c
child 177053 18cf30214a10beeb563a6448ef91df0b0005a47b
push id26541
push userryanvm@gmail.com
push dateFri, 04 Apr 2014 18:50:44 +0000
treeherdermozilla-central@2a069087bed1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspadenot
bugs986947
milestone31.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 986947 - Make MP3 contained in MP4 playback again on Windows with WMF backend. r=padenot Report that we can play MP3 inside MP4 on Windows Vista and later in HTMLMediaElement.canPlayType. Chrome and IE on Windows match this behaviour. Add a test file with MP3 contained inside MP4. Note the B2G emulator can't play this file, so I added a codecs parameter to the file's mime type so that decoder backends have to opt-in to testing with it. Enable playback of MP3 inside MP4 in WMFReader. Change from reporting the IMFSourceReader's duration inside WMFReader, to instead report the IMFSourceReader's duration as the media "end time". This is needed because the MP3-contained-in-MP4 file's first sample output by the IMFSourceReader has a non-zero timestamp, and the MediaDecoderStateMachine assumes that the media samples will be in the range [$firstSampleStartTime, $firstSampleStartTime+$reportedDuration]. But that's not the case here, the IMFSourceReader seems to output samples in the range [0,$reportedDuration]. This assumption mismatch means on the MP3-contained-in-MP4 file we end up trying to seek after what the IMFSourceReader assumes is the end of the file, which fails and causes test failures.
content/media/DecoderTraits.cpp
content/media/test/manifest.js
content/media/test/mochitest.ini
content/media/test/small-shot-mp3.mp4
content/media/test/small-shot-mp3.mp4^headers^
content/media/wmf/WMFDecoder.cpp
content/media/wmf/WMFReader.cpp
--- a/content/media/DecoderTraits.cpp
+++ b/content/media/DecoderTraits.cpp
@@ -399,31 +399,33 @@ DecoderTraits::CanHandleMediaType(const 
     result = CANPLAY_MAYBE;
     if (nsDependentCString(aMIMEType).EqualsASCII("audio/mpeg")) {
       codecList = gMpegAudioCodecs;
     } else {
       codecList = gH264Codecs;
     }
   }
 #endif
+#ifdef MOZ_DIRECTSHOW
+  // Note: DirectShow should come before WMF, so that we prefer DirectShow's
+  // MP3 support over WMF's.
+  if (DirectShowDecoder::GetSupportedCodecs(nsDependentCString(aMIMEType), &codecList)) {
+    result = CANPLAY_MAYBE;
+  }
+#endif
 #ifdef MOZ_WMF
   if (IsWMFSupportedType(nsDependentCString(aMIMEType))) {
     if (!aHaveRequestedCodecs) {
       return CANPLAY_MAYBE;
     }
     return WMFDecoder::CanPlayType(nsDependentCString(aMIMEType),
                                    aRequestedCodecs)
            ? CANPLAY_YES : CANPLAY_NO;
   }
 #endif
-#ifdef MOZ_DIRECTSHOW
-  if (DirectShowDecoder::GetSupportedCodecs(nsDependentCString(aMIMEType), &codecList)) {
-    result = CANPLAY_MAYBE;
-  }
-#endif
 #ifdef MOZ_APPLEMEDIA
   if (IsAppleMediaSupportedType(nsDependentCString(aMIMEType), &codecList)) {
     result = CANPLAY_MAYBE;
   }
 #endif
 #ifdef MOZ_MEDIA_PLUGINS
   if (MediaDecoder::IsMediaPluginsEnabled() &&
       GetMediaPluginHost()->FindDecoder(nsDependentCString(aMIMEType), &codecList))
@@ -518,18 +520,18 @@ InstantiateDecoder(const nsACString& aTy
 #endif
 #ifdef MOZ_WEBM
   if (IsWebMType(aType)) {
     decoder = new WebMDecoder();
     return decoder.forget();
   }
 #endif
 #ifdef MOZ_DIRECTSHOW
-  // Note: DirectShow decoder must come before WMFDecoder, else the pref
-  // "media.directshow.preferred" won't be honored.
+  // Note: DirectShow should come before WMF, so that we prefer DirectShow's
+  // MP3 support over WMF's.
   if (IsDirectShowSupportedType(aType)) {
     decoder = new DirectShowDecoder();
     return decoder.forget();
   }
 #endif
 #ifdef MOZ_FMP4
   if (IsMP4SupportedType(aType)) {
     decoder = new MP4Decoder();
--- a/content/media/test/manifest.js
+++ b/content/media/test/manifest.js
@@ -3,16 +3,17 @@
 // "bogus/duh" in each list.
 
 // These are small test files, good for just seeing if something loads. We
 // really only need one test file per backend here.
 var gSmallTests = [
   { name:"small-shot.ogg", type:"audio/ogg", duration:0.276 },
   { name:"small-shot.m4a", type:"audio/mp4", duration:0.29 },
   { name:"small-shot.mp3", type:"audio/mpeg", duration:0.27 },
+  { name:"small-shot-mp3.mp4", type:"audio/mp4; codecs=mp3", duration:0.34 },
   { name:"r11025_s16_c1.wav", type:"audio/x-wav", duration:1.0 },
   { name:"320x240.ogv", type:"video/ogg", width:320, height:240, duration:0.266 },
   { name:"seek.webm", type:"video/webm", width:320, height:240, duration:3.966 },
   { name:"vp9.webm", type:"video/webm", width:320, height:240, duration:4 },
   { name:"detodos.opus", type:"audio/ogg; codecs=opus", duration:2.9135 },
   { name:"gizmo.mp4", type:"video/mp4", duration:5.56 },
   { name:"bogus.duh", type:"bogus/duh" }
 ];
--- a/content/media/test/mochitest.ini
+++ b/content/media/test/mochitest.ini
@@ -221,16 +221,18 @@ support-files =
   seek6.js
   seek7.js
   seek8.js
   seek9.js
   seekLies.sjs
   seek_with_sound.ogg^headers^
   short-video.ogv
   short-video.ogv^headers^
+  small-shot-mp3.mp4
+  small-shot-mp3.mp4^headers^
   small-shot.m4a
   small-shot.mp3
   small-shot.mp3^headers^
   small-shot.ogg
   small-shot.ogg^headers^
   sound.ogg
   sound.ogg^headers^
   spacestorm-1000Hz-100ms.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..61fe0ac719166a3c5c85ae0e3f4b16b2a13a5c68
GIT binary patch
literal 7491
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
Dy#}qc
new file mode 100644
--- /dev/null
+++ b/content/media/test/small-shot-mp3.mp4^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
--- a/content/media/wmf/WMFDecoder.cpp
+++ b/content/media/wmf/WMFDecoder.cpp
@@ -24,31 +24,28 @@ MediaDecoderStateMachine* WMFDecoder::Cr
   return new MediaDecoderStateMachine(this, new WMFReader(this));
 }
 
 /* static */
 bool
 WMFDecoder::IsMP3Supported()
 {
   MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
-#ifdef MOZ_DIRECTSHOW
-  if (DirectShowDecoder::IsEnabled()) {
-    // DirectShowDecoder is enabled, we use that in preference to the WMF
-    // backend.
-    return false;
-  }
-#endif
   if (!MediaDecoder::IsWMFEnabled()) {
     return false;
   }
+  // MP3 works fine in WMF on Windows Vista and Windows 8.
   if (!IsWin7OrLater()) {
     return true;
   }
-  // MP3 support is disabled if we're on Windows 7 and no service pack
-  // is installed, as it's crashy on Win7 SP0.
+  // MP3 support is disabled if we're on Windows 7 and no service packs are
+  // installed, since it's crashy. Win7 with service packs is not so crashy,
+  // so we enable it there. Note we prefer DirectShow for MP3 playback, but
+  // we still support MP3 in MP4 via WMF, or MP3 in WMF if DirectShow is
+  // disabled.
   return IsWin7SP1OrLater();
 }
 
 static bool
 IsSupportedH264Codec(const nsAString& aCodec)
 {
   // According to the WMF documentation:
   // http://msdn.microsoft.com/en-us/library/windows/desktop/dd797815%28v=vs.85%29.aspx
@@ -104,33 +101,36 @@ WMFDecoder::CanPlayType(const nsACString
   // we know should be supported by Windows Media Foundation.
   if ((aType.EqualsASCII("audio/mpeg") || aType.EqualsASCII("audio/mp3")) &&
       IsMP3Supported()) {
     // Note: We block MP3 playback on Window 7 SP0 since it seems to crash
     // in some circumstances.
     return !aCodecs.Length() || aCodecs.EqualsASCII("mp3");
   }
 
-  // AAC-LC in M4A.
+  // AAC-LC or MP3 in M4A.
   if (aType.EqualsASCII("audio/mp4") || aType.EqualsASCII("audio/x-m4a")) {
-    return !aCodecs.Length() || aCodecs.EqualsASCII("mp4a.40.2");
+    return !aCodecs.Length() ||
+           aCodecs.EqualsASCII("mp4a.40.2") ||
+           aCodecs.EqualsASCII("mp3");
   }
 
   if (!aType.EqualsASCII("video/mp4")) {
     return false;
   }
 
   // H.264 + AAC in MP4. Verify that all the codecs specifed are ones that
   // we expect that we can play.
   nsCharSeparatedTokenizer tokenizer(aCodecs, ',');
   bool expectMoreTokens = false;
   while (tokenizer.hasMoreTokens()) {
     const nsSubstring& token = tokenizer.nextToken();
     expectMoreTokens = tokenizer.separatorAfterCurrentToken();
     if (token.EqualsASCII("mp4a.40.2") || // AAC-LC
+        token.EqualsASCII("mp3") ||
         IsSupportedH264Codec(token)) {
       continue;
     }
     return false;
   }
   if (expectMoreTokens) {
     // Last codec name was empty
     return false;
--- a/content/media/wmf/WMFReader.cpp
+++ b/content/media/wmf/WMFReader.cpp
@@ -531,17 +531,17 @@ WMFReader::ReadMetadata(MediaInfo* aInfo
   // Abort if both video and audio failed to initialize.
   NS_ENSURE_TRUE(mInfo.HasValidMedia(), NS_ERROR_FAILURE);
 
   // Get the duration, and report it to the decoder if we have it.
   int64_t duration = 0;
   hr = GetSourceReaderDuration(mSourceReader, duration);
   if (SUCCEEDED(hr)) {
     ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
-    mDecoder->SetMediaDuration(duration);
+    mDecoder->SetMediaEndTime(duration);
   }
   // We can seek if we get a duration *and* the reader reports that it's
   // seekable.
   bool canSeek = false;
   if (FAILED(hr) ||
       FAILED(GetSourceReaderCanSeek(mSourceReader, canSeek)) ||
       !canSeek) {
     mDecoder->SetMediaSeekable(false);