Bug 1070703: Enable MP4 decoding in Mac OS 10.6 and 10.7. r=rillian, a=lmandel
authorJean-Yves Avenard <jyavenard@mozilla.com>
Tue, 23 Sep 2014 22:58:00 -0700
changeset 225231 c8ca7d751f8dd89beb895fbb7dd9810a8cf2fc95
parent 225230 4ff49aa322130bdc90fddfe2f8e0f2b9533fda2f
child 225232 3a4cf022fefae2db787d5ab12529888b4ce878e1
push id3979
push userraliiev@mozilla.com
push dateMon, 13 Oct 2014 16:35:44 +0000
treeherdermozilla-beta@30f2cc610691 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrillian, lmandel
bugs1070703, 1068455, 1068597, 1067697
milestone34.0a2
Bug 1070703: Enable MP4 decoding in Mac OS 10.6 and 10.7. r=rillian, a=lmandel This commit is made of backports extracted from bugs 1068455, 1068597 and 1067697
content/media/fmp4/apple/AppleCMFunctions.h
content/media/fmp4/apple/AppleCMLinker.cpp
content/media/fmp4/apple/AppleCMLinker.h
content/media/fmp4/apple/AppleVTDecoder.cpp
content/media/fmp4/apple/AppleVTLinker.cpp
content/media/test/test_can_play_type_mpeg.html
--- a/content/media/fmp4/apple/AppleCMFunctions.h
+++ b/content/media/fmp4/apple/AppleCMFunctions.h
@@ -1,12 +1,12 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // Construct references to each of the CoreMedia symbols we use.
 
-LINK_FUNC(CMVideoFormatDescriptionCreate)
-LINK_FUNC(CMBlockBufferCreateWithMemoryBlock)
-LINK_FUNC(CMSampleBufferCreate)
-LINK_FUNC(CMTimeMake)
+LINK_FUNC(VideoFormatDescriptionCreate)
+LINK_FUNC(BlockBufferCreateWithMemoryBlock)
+LINK_FUNC(SampleBufferCreate)
+LINK_FUNC(TimeMake)
--- a/content/media/fmp4/apple/AppleCMLinker.cpp
+++ b/content/media/fmp4/apple/AppleCMLinker.cpp
@@ -3,16 +3,18 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <dlfcn.h>
 
 #include "AppleCMLinker.h"
 #include "MainThreadUtils.h"
+#include "mozilla/ArrayUtils.h"
+#include "nsCocoaFeatures.h"
 #include "nsDebug.h"
 
 #ifdef PR_LOGGING
 PRLogModuleInfo* GetAppleMediaLog();
 #define LOG(...) PR_LOG(GetAppleMediaLog(), PR_LOG_DEBUG, (__VA_ARGS__))
 #else
 #define LOG(...)
 #endif
@@ -20,48 +22,71 @@ PRLogModuleInfo* GetAppleMediaLog();
 namespace mozilla {
 
 AppleCMLinker::LinkStatus
 AppleCMLinker::sLinkStatus = LinkStatus_INIT;
 
 void* AppleCMLinker::sLink = nullptr;
 nsrefcnt AppleCMLinker::sRefCount = 0;
 
-#define LINK_FUNC(func) typeof(func) func;
+#define LINK_FUNC(func) typeof(CM ## func) CM ## func;
 #include "AppleCMFunctions.h"
 #undef LINK_FUNC
 
 /* static */ bool
 AppleCMLinker::Link()
 {
   // Bump our reference count every time we're called.
   // Add a lock or change the thread assertion if
   // you need to call this off the main thread.
   MOZ_ASSERT(NS_IsMainThread());
   ++sRefCount;
 
   if (sLinkStatus) {
     return sLinkStatus == LinkStatus_SUCCEEDED;
   }
 
-  const char* dlname =
-    "/System/Library/Frameworks/CoreMedia.framework/CoreMedia";
-  if (!(sLink = dlopen(dlname, RTLD_NOW | RTLD_LOCAL))) {
+  const char* dlnames[] =
+    { "/System/Library/Frameworks/CoreMedia.framework/CoreMedia",
+      "/System/Library/PrivateFrameworks/CoreMedia.framework/CoreMedia" };
+  bool dlfound = false;
+  for (size_t i = 0; i < ArrayLength(dlnames); i++) {
+    if ((sLink = dlopen(dlnames[i], RTLD_NOW | RTLD_LOCAL))) {
+      dlfound = true;
+      break;
+    }
+  }
+  if (!dlfound) {
     NS_WARNING("Couldn't load CoreMedia framework");
     goto fail;
   }
 
-#define LINK_FUNC(func)                                        \
+  if (nsCocoaFeatures::OnLionOrLater()) {
+#define LINK_FUNC2(func)                                       \
   func = (typeof(func))dlsym(sLink, #func);                    \
   if (!func) {                                                 \
-    NS_WARNING("Couldn't load CoreMedia function " #func ); \
+    NS_WARNING("Couldn't load CoreMedia function " #func );    \
     goto fail;                                                 \
   }
+#define LINK_FUNC(func) LINK_FUNC2(CM ## func)
 #include "AppleCMFunctions.h"
 #undef LINK_FUNC
+#undef LINK_FUNC2
+  } else {
+#define LINK_FUNC2(cm, fig)                                    \
+  cm = (typeof(cm))dlsym(sLink, #fig);                         \
+  if (!cm) {                                                   \
+    NS_WARNING("Couldn't load CoreMedia function " #fig );     \
+    goto fail;                                                 \
+  }
+#define LINK_FUNC(func) LINK_FUNC2(CM ## func, Fig ## func)
+#include "AppleCMFunctions.h"
+#undef LINK_FUNC
+#undef LINK_FUNC2
+  }
 
   LOG("Loaded CoreMedia framework.");
   sLinkStatus = LinkStatus_SUCCEEDED;
   return true;
 
 fail:
   Unlink();
 
--- a/content/media/fmp4/apple/AppleCMLinker.h
+++ b/content/media/fmp4/apple/AppleCMLinker.h
@@ -29,15 +29,15 @@ private:
 
   static enum LinkStatus {
     LinkStatus_INIT = 0,
     LinkStatus_FAILED,
     LinkStatus_SUCCEEDED
   } sLinkStatus;
 };
 
-#define LINK_FUNC(func) extern typeof(func)* func;
+#define LINK_FUNC(func) extern typeof(CM ## func)* CM ## func;
 #include "AppleCMFunctions.h"
 #undef LINK_FUNC
 
 } // namespace mozilla
 
 #endif // AppleCMLinker_h
--- a/content/media/fmp4/apple/AppleVTDecoder.cpp
+++ b/content/media/fmp4/apple/AppleVTDecoder.cpp
@@ -12,16 +12,17 @@
 #include "MP4Decoder.h"
 #include "nsAutoPtr.h"
 #include "nsThreadUtils.h"
 #include "AppleCMLinker.h"
 #include "AppleVTDecoder.h"
 #include "AppleVTLinker.h"
 #include "prlog.h"
 #include "MediaData.h"
+#include "mozilla/ArrayUtils.h"
 #include "VideoUtils.h"
 
 #ifdef PR_LOGGING
 PRLogModuleInfo* GetAppleMediaLog();
 #define LOG(...) PR_LOG(GetAppleMediaLog(), PR_LOG_DEBUG, (__VA_ARGS__))
 //#define LOG_MEDIA_SHA1
 #else
 #define LOG(...)
@@ -458,21 +459,41 @@ AppleVTDecoder::InitializeSession()
         CFStringCreateWithCString(NULL, "EnableHardwareAcceleratedVideoDecoder",
             kCFStringEncodingUTF8);
 
   CFDictionarySetValue(spec,
       kVTVideoDecoderSpecification_EnableHardwareAcceleratedVideoDecoder,
       kCFBooleanTrue);
 #endif
 
+  // Contruct output configuration.
+  SInt32 PixelFormatTypeValue = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange;
+  AutoCFRelease<CFNumberRef> PixelFormatTypeNumber =
+    CFNumberCreate(kCFAllocatorDefault,
+                   kCFNumberSInt32Type,
+                   &PixelFormatTypeValue);
+
+  const void* outputKeys[] = { kCVPixelBufferPixelFormatTypeKey };
+  const void* outputValues[] = { PixelFormatTypeNumber };
+  static_assert(ArrayLength(outputKeys) == ArrayLength(outputValues),
+                "Non matching keys/values array size");
+
+  AutoCFRelease<CFDictionaryRef> outputConfiguration =
+    CFDictionaryCreate(kCFAllocatorDefault,
+                       outputKeys,
+                       outputValues,
+                       ArrayLength(outputKeys),
+                       &kCFTypeDictionaryKeyCallBacks,
+                       &kCFTypeDictionaryValueCallBacks);
+
   VTDecompressionOutputCallbackRecord cb = { PlatformCallback, this };
   rv = VTDecompressionSessionCreate(NULL, // Allocator.
                                     mFormat,
                                     spec, // Video decoder selection.
-                                    NULL, // Output video format.
+                                    outputConfiguration, // Output video format.
                                     &cb,
                                     &mSession);
   if (rv != noErr) {
     NS_ERROR("Couldn't create decompression session!");
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
--- a/content/media/fmp4/apple/AppleVTLinker.cpp
+++ b/content/media/fmp4/apple/AppleVTLinker.cpp
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <dlfcn.h>
 
 #include "AppleVTLinker.h"
 #include "MainThreadUtils.h"
+#include "mozilla/ArrayUtils.h"
 #include "nsDebug.h"
 
 #ifdef PR_LOGGING
 PRLogModuleInfo* GetAppleMediaLog();
 #define LOG(...) PR_LOG(GetAppleMediaLog(), PR_LOG_DEBUG, (__VA_ARGS__))
 #else
 #define LOG(...)
 #endif
@@ -37,19 +38,27 @@ AppleVTLinker::Link()
   // you need to call this off the main thread.
   MOZ_ASSERT(NS_IsMainThread());
   ++sRefCount;
 
   if (sLinkStatus) {
     return sLinkStatus == LinkStatus_SUCCEEDED;
   }
 
-  const char* dlname =
-    "/System/Library/Frameworks/VideoToolbox.framework/VideoToolbox";
-  if (!(sLink = dlopen(dlname, RTLD_NOW | RTLD_LOCAL))) {
+  const char* dlnames[] =
+    { "/System/Library/Frameworks/VideoToolbox.framework/VideoToolbox",
+      "/System/Library/PrivateFrameworks/VideoToolbox.framework/VideoToolbox" };
+  bool dlfound = false;
+  for (size_t i = 0; i < ArrayLength(dlnames); i++) {
+    if ((sLink = dlopen(dlnames[i], RTLD_NOW | RTLD_LOCAL))) {
+      dlfound = true;
+      break;
+    }
+  }
+  if (!dlfound) {
     NS_WARNING("Couldn't load VideoToolbox framework");
     goto fail;
   }
 
 #define LINK_FUNC(func)                                        \
   func = (typeof(func))dlsym(sLink, #func);                    \
   if (!func) {                                                 \
     NS_WARNING("Couldn't load VideoToolbox function " #func ); \
--- a/content/media/test/test_can_play_type_mpeg.html
+++ b/content/media/test/test_can_play_type_mpeg.html
@@ -94,25 +94,25 @@ function check_mp3(v, enabled) {
 }
 
 function IsWindowsVistaOrLater() {
   var re = /Windows NT (\d+\.\d)/;
   var winver = navigator.userAgent.match(re);
   return winver && winver.length == 2 && parseFloat(winver[1]) >= 6.0;
 }
 
-function IsMacOSLionOrLater() {
+function IsMacOSSnowLeopardOrLater() {
   var re = /Mac OS X (\d+)\.(\d+)/;
   var ver = navigator.userAgent.match(re);
   if (!ver || ver.length != 3) {
     return false;
   }
   var major = ver[1] | 0;
   var minor = ver[2] | 0;
-  return major == 10 && minor >= 7;
+  return major == 10 && minor >= 6;
 }
 
 function getPref(name) {
   var pref = false;
   try {
     pref = SpecialPowers.getBoolPref(name);
   } catch(ex) { }
   return pref;
@@ -122,17 +122,17 @@ function IsLinuxGStreamer() {
   return /Linux/.test(navigator.userAgent) &&
          getPref("media.gstreamer.enabled");
 }
 
 // Check whether we should expect the new MP4Reader-based support to work.
 function IsMP4ReaderAvailable() {
   var prefs = getPref("media.fragmented-mp4.enabled") &&
               getPref("media.fragmented-mp4.exposed");
-  return prefs && (IsWindowsVistaOrLater() || IsMacOSLionOrLater());
+  return prefs && (IsWindowsVistaOrLater() || IsMacOSSnowLeopardOrLater());
 }
 
 var haveMp4 = (getPref("media.windows-media-foundation.enabled") && IsWindowsVistaOrLater()) ||
                getPref("media.omx.enabled") ||
                getPref("media.gstreamer.enabled") ||
                IsMP4ReaderAvailable();
 // TODO:  Add "getPref("media.plugins.enabled")" once MP4 works on Gingerbread.