content/media/plugins/MediaPluginHost.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/content/media/plugins/MediaPluginHost.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,330 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim:set ts=2 sw=2 sts=2 et cindent: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this file,
     1.8 + * You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +#include "mozilla/Preferences.h"
    1.10 +#include "mozilla/dom/TimeRanges.h"
    1.11 +#include "MediaResource.h"
    1.12 +#include "mozilla/dom/HTMLMediaElement.h"
    1.13 +#include "MediaPluginHost.h"
    1.14 +#include "nsXPCOMStrings.h"
    1.15 +#include "nsISeekableStream.h"
    1.16 +#include "MediaPluginReader.h"
    1.17 +#include "nsIGfxInfo.h"
    1.18 +#include "gfxCrashReporterUtils.h"
    1.19 +#include "prmem.h"
    1.20 +#include "prlink.h"
    1.21 +#include "MediaResourceServer.h"
    1.22 +#include "nsServiceManagerUtils.h"
    1.23 +
    1.24 +#include "MPAPI.h"
    1.25 +
    1.26 +#include "nsIPropertyBag2.h"
    1.27 +
    1.28 +#if defined(ANDROID) || defined(MOZ_WIDGET_GONK)
    1.29 +#include "android/log.h"
    1.30 +#define ALOG(args...)  __android_log_print(ANDROID_LOG_INFO, "MediaPluginHost" , ## args)
    1.31 +#else
    1.32 +#define ALOG(args...) /* do nothing */
    1.33 +#endif
    1.34 +
    1.35 +using namespace MPAPI;
    1.36 +
    1.37 +Decoder::Decoder() :
    1.38 +  mResource(nullptr), mPrivate(nullptr)
    1.39 +{
    1.40 +}
    1.41 +
    1.42 +namespace mozilla {
    1.43 +
    1.44 +static char* GetResource(Decoder *aDecoder)
    1.45 +{
    1.46 +  return static_cast<char*>(aDecoder->mResource);
    1.47 +}
    1.48 +
    1.49 +class GetIntPrefEvent : public nsRunnable {
    1.50 +public:
    1.51 +  GetIntPrefEvent(const char* aPref, int32_t* aResult)
    1.52 +    : mPref(aPref), mResult(aResult) {}
    1.53 +  NS_IMETHOD Run() {
    1.54 +    return Preferences::GetInt(mPref, mResult);
    1.55 +  }
    1.56 +private:
    1.57 +  const char* mPref;
    1.58 +  int32_t*    mResult;
    1.59 +};
    1.60 +
    1.61 +static bool GetIntPref(const char* aPref, int32_t* aResult)
    1.62 +{
    1.63 +  // GetIntPref() is called on the decoder thread, but the Preferences API
    1.64 +  // can only be called on the main thread. Post a runnable and wait.
    1.65 +  NS_ENSURE_TRUE(aPref, false);
    1.66 +  NS_ENSURE_TRUE(aResult, false);
    1.67 +  nsCOMPtr<nsIRunnable> event = new GetIntPrefEvent(aPref, aResult);
    1.68 +  return NS_SUCCEEDED(NS_DispatchToMainThread(event, NS_DISPATCH_SYNC));
    1.69 +}
    1.70 +
    1.71 +static bool
    1.72 +GetSystemInfoString(const char *aKey, char *aResult, size_t aResultLength)
    1.73 +{
    1.74 +  NS_ENSURE_TRUE(aKey, false);
    1.75 +  NS_ENSURE_TRUE(aResult, false);
    1.76 +
    1.77 +  nsCOMPtr<nsIPropertyBag2> infoService = do_GetService("@mozilla.org/system-info;1");
    1.78 +  NS_ASSERTION(infoService, "Could not find a system info service");
    1.79 +
    1.80 +  nsAutoCString key(aKey);
    1.81 +  nsAutoCString info;
    1.82 +  nsresult rv = infoService->GetPropertyAsACString(NS_ConvertUTF8toUTF16(key),
    1.83 +                                                  info);
    1.84 +
    1.85 +  NS_ENSURE_SUCCESS(rv, false);
    1.86 +
    1.87 +  strncpy(aResult, info.get(), aResultLength);
    1.88 +
    1.89 +  return true;
    1.90 +}
    1.91 +
    1.92 +static PluginHost sPluginHost = {
    1.93 +  nullptr,
    1.94 +  nullptr,
    1.95 +  nullptr,
    1.96 +  nullptr,
    1.97 +  GetIntPref,
    1.98 +  GetSystemInfoString
    1.99 +};
   1.100 +
   1.101 +// Return true if Omx decoding is supported on the device. This checks the
   1.102 +// built in whitelist/blacklist and preferences to see if that is overridden.
   1.103 +static bool IsOmxSupported()
   1.104 +{
   1.105 +  bool forceEnabled =
   1.106 +      Preferences::GetBool("stagefright.force-enabled", false);
   1.107 +  bool disabled =
   1.108 +      Preferences::GetBool("stagefright.disabled", false);
   1.109 +
   1.110 +  if (disabled) {
   1.111 +    NS_WARNING("XXX stagefright disabled\n");
   1.112 +    return false;
   1.113 +  }
   1.114 +
   1.115 +  ScopedGfxFeatureReporter reporter("Stagefright", forceEnabled);
   1.116 +
   1.117 +  if (!forceEnabled) {
   1.118 +    nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
   1.119 +    if (gfxInfo) {
   1.120 +      int32_t status;
   1.121 +      if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_STAGEFRIGHT, &status))) {
   1.122 +        if (status != nsIGfxInfo::FEATURE_NO_INFO) {
   1.123 +          NS_WARNING("XXX stagefright blacklisted\n");
   1.124 +          return false;
   1.125 +        }
   1.126 +      }
   1.127 +    }
   1.128 +  }
   1.129 +
   1.130 +  reporter.SetSuccessful();
   1.131 +  return true;
   1.132 +}
   1.133 +
   1.134 +// Return the name of the shared library that implements Omx based decoding. This varies
   1.135 +// depending on libstagefright version installed on the device and whether it is B2G vs Android.
   1.136 +// nullptr is returned if Omx decoding is not supported on the device,
   1.137 +static const char* GetOmxLibraryName()
   1.138 +{
   1.139 +#if defined(ANDROID) && !defined(MOZ_WIDGET_GONK)
   1.140 +  nsCOMPtr<nsIPropertyBag2> infoService = do_GetService("@mozilla.org/system-info;1");
   1.141 +  NS_ASSERTION(infoService, "Could not find a system info service");
   1.142 +
   1.143 +  int32_t version;
   1.144 +  nsresult rv = infoService->GetPropertyAsInt32(NS_LITERAL_STRING("version"), &version);
   1.145 +  if (NS_SUCCEEDED(rv)) {
   1.146 +    ALOG("Android Version is: %d", version);
   1.147 +  }
   1.148 +
   1.149 +  nsAutoString release_version;
   1.150 +  rv = infoService->GetPropertyAsAString(NS_LITERAL_STRING("release_version"), release_version);
   1.151 +  if (NS_SUCCEEDED(rv)) {
   1.152 +    ALOG("Android Release Version is: %s", NS_LossyConvertUTF16toASCII(release_version).get());
   1.153 +  }
   1.154 +
   1.155 +  nsAutoString device;
   1.156 +  rv = infoService->GetPropertyAsAString(NS_LITERAL_STRING("device"), device);
   1.157 +  if (NS_SUCCEEDED(rv)) {
   1.158 +    ALOG("Android Device is: %s", NS_LossyConvertUTF16toASCII(device).get());
   1.159 +  }
   1.160 +
   1.161 +  nsAutoString manufacturer;
   1.162 +  rv = infoService->GetPropertyAsAString(NS_LITERAL_STRING("manufacturer"), manufacturer);
   1.163 +  if (NS_SUCCEEDED(rv)) {
   1.164 +    ALOG("Android Manufacturer is: %s", NS_LossyConvertUTF16toASCII(manufacturer).get());
   1.165 +  }
   1.166 +
   1.167 +  nsAutoString hardware;
   1.168 +  rv = infoService->GetPropertyAsAString(NS_LITERAL_STRING("hardware"), hardware);
   1.169 +  if (NS_SUCCEEDED(rv)) {
   1.170 +    ALOG("Android Hardware is: %s", NS_LossyConvertUTF16toASCII(hardware).get());
   1.171 +  }
   1.172 +#endif
   1.173 +
   1.174 +  if (!IsOmxSupported())
   1.175 +    return nullptr;
   1.176 +
   1.177 +#if defined(ANDROID) && !defined(MOZ_WIDGET_GONK)
   1.178 +  if (version >= 17) {
   1.179 +    return "libomxpluginkk.so";
   1.180 +  }
   1.181 +  else if (version == 13 || version == 12 || version == 11) {
   1.182 +    return "libomxpluginhc.so";
   1.183 +  }
   1.184 +  else if (version == 10 && release_version >= NS_LITERAL_STRING("2.3.6")) {
   1.185 +    // Gingerbread versions from 2.3.6 and above have a different DataSource
   1.186 +    // layout to those on 2.3.5 and below.
   1.187 +    return "libomxplugingb.so";
   1.188 +  }
   1.189 +  else if (version == 10 && release_version >= NS_LITERAL_STRING("2.3.4") &&
   1.190 +           device.Find("HTC") == 0) {
   1.191 +    // HTC devices running Gingerbread 2.3.4+ (HTC Desire HD, HTC Evo Design, etc) seem to
   1.192 +    // use a newer version of Gingerbread libstagefright than other 2.3.4 devices.
   1.193 +    return "libomxplugingb.so";
   1.194 +  }
   1.195 +  else if (version == 9 || (version == 10 && release_version <= NS_LITERAL_STRING("2.3.5"))) {
   1.196 +    // Gingerbread versions from 2.3.5 and below have a different DataSource
   1.197 +    // than 2.3.6 and above.
   1.198 +    return "libomxplugingb235.so";
   1.199 +  }
   1.200 +  else if (version == 8) {
   1.201 +    // Froyo
   1.202 +    return "libomxpluginfroyo.so";
   1.203 +  }
   1.204 +  else if (version < 8) {
   1.205 +    // Below Froyo not supported
   1.206 +    return nullptr;
   1.207 +  }
   1.208 +
   1.209 +  // Ice Cream Sandwich and Jellybean
   1.210 +  return "libomxplugin.so";
   1.211 +
   1.212 +#elif defined(ANDROID) && defined(MOZ_WIDGET_GONK)
   1.213 +  return "libomxplugin.so";
   1.214 +#else
   1.215 +  return nullptr;
   1.216 +#endif
   1.217 +}
   1.218 +
   1.219 +MediaPluginHost::MediaPluginHost() {
   1.220 +  MOZ_COUNT_CTOR(MediaPluginHost);
   1.221 +
   1.222 +  mResourceServer = MediaResourceServer::Start();
   1.223 +
   1.224 +  const char* name = GetOmxLibraryName();
   1.225 +  ALOG("Loading OMX Plugin: %s", name ? name : "nullptr");
   1.226 +  if (name) {
   1.227 +    char *path = PR_GetLibraryFilePathname("libxul.so", (PRFuncPtr) GetOmxLibraryName);
   1.228 +    PRLibrary *lib = nullptr;
   1.229 +    if (path) {
   1.230 +      nsAutoCString libpath(path);
   1.231 +      PR_Free(path);
   1.232 +      int32_t slash = libpath.RFindChar('/');
   1.233 +      if (slash != kNotFound) {
   1.234 +        libpath.Truncate(slash + 1);
   1.235 +        libpath.Append(name);
   1.236 +        lib = PR_LoadLibrary(libpath.get());
   1.237 +      }
   1.238 +    }
   1.239 +    if (!lib)
   1.240 +      lib = PR_LoadLibrary(name);
   1.241 +
   1.242 +    if (lib) {
   1.243 +      Manifest *manifest = static_cast<Manifest *>(PR_FindSymbol(lib, "MPAPI_MANIFEST"));
   1.244 +      if (manifest) {
   1.245 +        mPlugins.AppendElement(manifest);
   1.246 +        ALOG("OMX plugin successfully loaded");
   1.247 +     }
   1.248 +    }
   1.249 +  }
   1.250 +}
   1.251 +
   1.252 +MediaPluginHost::~MediaPluginHost() {
   1.253 +  mResourceServer->Stop();
   1.254 +  MOZ_COUNT_DTOR(MediaPluginHost);
   1.255 +}
   1.256 +
   1.257 +bool MediaPluginHost::FindDecoder(const nsACString& aMimeType, const char* const** aCodecs)
   1.258 +{
   1.259 +  const char *chars;
   1.260 +  size_t len = NS_CStringGetData(aMimeType, &chars, nullptr);
   1.261 +  for (size_t n = 0; n < mPlugins.Length(); ++n) {
   1.262 +    Manifest *plugin = mPlugins[n];
   1.263 +    const char* const *codecs;
   1.264 +    if (plugin->CanDecode(chars, len, &codecs)) {
   1.265 +      if (aCodecs)
   1.266 +        *aCodecs = codecs;
   1.267 +      return true;
   1.268 +    }
   1.269 +  }
   1.270 +  return false;
   1.271 +}
   1.272 +
   1.273 +MPAPI::Decoder *MediaPluginHost::CreateDecoder(MediaResource *aResource, const nsACString& aMimeType)
   1.274 +{
   1.275 +  NS_ENSURE_TRUE(aResource, nullptr);
   1.276 +
   1.277 +  nsAutoPtr<Decoder> decoder(new Decoder());
   1.278 +  if (!decoder) {
   1.279 +    return nullptr;
   1.280 +  }
   1.281 +
   1.282 +  const char *chars;
   1.283 +  size_t len = NS_CStringGetData(aMimeType, &chars, nullptr);
   1.284 +  for (size_t n = 0; n < mPlugins.Length(); ++n) {
   1.285 +    Manifest *plugin = mPlugins[n];
   1.286 +    const char* const *codecs;
   1.287 +    if (!plugin->CanDecode(chars, len, &codecs)) {
   1.288 +      continue;
   1.289 +    }
   1.290 +
   1.291 +    nsCString url;
   1.292 +    nsresult rv = mResourceServer->AddResource(aResource, url);
   1.293 +    if (NS_FAILED (rv)) continue;
   1.294 +
   1.295 +    decoder->mResource = strdup(url.get());
   1.296 +    if (plugin->CreateDecoder(&sPluginHost, decoder, chars, len)) {
   1.297 +      aResource->AddRef();
   1.298 +      return decoder.forget();
   1.299 +    }
   1.300 +  }
   1.301 +
   1.302 +  return nullptr;
   1.303 +}
   1.304 +
   1.305 +void MediaPluginHost::DestroyDecoder(Decoder *aDecoder)
   1.306 +{
   1.307 +  aDecoder->DestroyDecoder(aDecoder);
   1.308 +  char* resource = GetResource(aDecoder);
   1.309 +  if (resource) {
   1.310 +    // resource *shouldn't* be null, but check anyway just in case the plugin
   1.311 +    // decoder does something stupid.
   1.312 +    mResourceServer->RemoveResource(nsCString(resource));
   1.313 +    free(resource);
   1.314 +  }
   1.315 +  delete aDecoder;
   1.316 +}
   1.317 +
   1.318 +MediaPluginHost *sMediaPluginHost = nullptr;
   1.319 +MediaPluginHost *GetMediaPluginHost()
   1.320 +{
   1.321 +  if (!sMediaPluginHost) {
   1.322 +    sMediaPluginHost = new MediaPluginHost();
   1.323 +  }
   1.324 +  return sMediaPluginHost;
   1.325 +}
   1.326 +
   1.327 +void MediaPluginHost::Shutdown()
   1.328 +{
   1.329 +  delete sMediaPluginHost;
   1.330 +  sMediaPluginHost = nullptr;
   1.331 +}
   1.332 +
   1.333 +} // namespace mozilla

mercurial