content/media/plugins/MediaPluginHost.cpp

Fri, 16 Jan 2015 04:50:19 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 04:50:19 +0100
branch
TOR_BUG_9701
changeset 13
44a2da4a2ab2
permissions
-rw-r--r--

Replace accessor implementation with direct member state manipulation, by
request https://trac.torproject.org/projects/tor/ticket/9701#comment:32

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
michael@0 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6 #include "mozilla/Preferences.h"
michael@0 7 #include "mozilla/dom/TimeRanges.h"
michael@0 8 #include "MediaResource.h"
michael@0 9 #include "mozilla/dom/HTMLMediaElement.h"
michael@0 10 #include "MediaPluginHost.h"
michael@0 11 #include "nsXPCOMStrings.h"
michael@0 12 #include "nsISeekableStream.h"
michael@0 13 #include "MediaPluginReader.h"
michael@0 14 #include "nsIGfxInfo.h"
michael@0 15 #include "gfxCrashReporterUtils.h"
michael@0 16 #include "prmem.h"
michael@0 17 #include "prlink.h"
michael@0 18 #include "MediaResourceServer.h"
michael@0 19 #include "nsServiceManagerUtils.h"
michael@0 20
michael@0 21 #include "MPAPI.h"
michael@0 22
michael@0 23 #include "nsIPropertyBag2.h"
michael@0 24
michael@0 25 #if defined(ANDROID) || defined(MOZ_WIDGET_GONK)
michael@0 26 #include "android/log.h"
michael@0 27 #define ALOG(args...) __android_log_print(ANDROID_LOG_INFO, "MediaPluginHost" , ## args)
michael@0 28 #else
michael@0 29 #define ALOG(args...) /* do nothing */
michael@0 30 #endif
michael@0 31
michael@0 32 using namespace MPAPI;
michael@0 33
michael@0 34 Decoder::Decoder() :
michael@0 35 mResource(nullptr), mPrivate(nullptr)
michael@0 36 {
michael@0 37 }
michael@0 38
michael@0 39 namespace mozilla {
michael@0 40
michael@0 41 static char* GetResource(Decoder *aDecoder)
michael@0 42 {
michael@0 43 return static_cast<char*>(aDecoder->mResource);
michael@0 44 }
michael@0 45
michael@0 46 class GetIntPrefEvent : public nsRunnable {
michael@0 47 public:
michael@0 48 GetIntPrefEvent(const char* aPref, int32_t* aResult)
michael@0 49 : mPref(aPref), mResult(aResult) {}
michael@0 50 NS_IMETHOD Run() {
michael@0 51 return Preferences::GetInt(mPref, mResult);
michael@0 52 }
michael@0 53 private:
michael@0 54 const char* mPref;
michael@0 55 int32_t* mResult;
michael@0 56 };
michael@0 57
michael@0 58 static bool GetIntPref(const char* aPref, int32_t* aResult)
michael@0 59 {
michael@0 60 // GetIntPref() is called on the decoder thread, but the Preferences API
michael@0 61 // can only be called on the main thread. Post a runnable and wait.
michael@0 62 NS_ENSURE_TRUE(aPref, false);
michael@0 63 NS_ENSURE_TRUE(aResult, false);
michael@0 64 nsCOMPtr<nsIRunnable> event = new GetIntPrefEvent(aPref, aResult);
michael@0 65 return NS_SUCCEEDED(NS_DispatchToMainThread(event, NS_DISPATCH_SYNC));
michael@0 66 }
michael@0 67
michael@0 68 static bool
michael@0 69 GetSystemInfoString(const char *aKey, char *aResult, size_t aResultLength)
michael@0 70 {
michael@0 71 NS_ENSURE_TRUE(aKey, false);
michael@0 72 NS_ENSURE_TRUE(aResult, false);
michael@0 73
michael@0 74 nsCOMPtr<nsIPropertyBag2> infoService = do_GetService("@mozilla.org/system-info;1");
michael@0 75 NS_ASSERTION(infoService, "Could not find a system info service");
michael@0 76
michael@0 77 nsAutoCString key(aKey);
michael@0 78 nsAutoCString info;
michael@0 79 nsresult rv = infoService->GetPropertyAsACString(NS_ConvertUTF8toUTF16(key),
michael@0 80 info);
michael@0 81
michael@0 82 NS_ENSURE_SUCCESS(rv, false);
michael@0 83
michael@0 84 strncpy(aResult, info.get(), aResultLength);
michael@0 85
michael@0 86 return true;
michael@0 87 }
michael@0 88
michael@0 89 static PluginHost sPluginHost = {
michael@0 90 nullptr,
michael@0 91 nullptr,
michael@0 92 nullptr,
michael@0 93 nullptr,
michael@0 94 GetIntPref,
michael@0 95 GetSystemInfoString
michael@0 96 };
michael@0 97
michael@0 98 // Return true if Omx decoding is supported on the device. This checks the
michael@0 99 // built in whitelist/blacklist and preferences to see if that is overridden.
michael@0 100 static bool IsOmxSupported()
michael@0 101 {
michael@0 102 bool forceEnabled =
michael@0 103 Preferences::GetBool("stagefright.force-enabled", false);
michael@0 104 bool disabled =
michael@0 105 Preferences::GetBool("stagefright.disabled", false);
michael@0 106
michael@0 107 if (disabled) {
michael@0 108 NS_WARNING("XXX stagefright disabled\n");
michael@0 109 return false;
michael@0 110 }
michael@0 111
michael@0 112 ScopedGfxFeatureReporter reporter("Stagefright", forceEnabled);
michael@0 113
michael@0 114 if (!forceEnabled) {
michael@0 115 nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
michael@0 116 if (gfxInfo) {
michael@0 117 int32_t status;
michael@0 118 if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_STAGEFRIGHT, &status))) {
michael@0 119 if (status != nsIGfxInfo::FEATURE_NO_INFO) {
michael@0 120 NS_WARNING("XXX stagefright blacklisted\n");
michael@0 121 return false;
michael@0 122 }
michael@0 123 }
michael@0 124 }
michael@0 125 }
michael@0 126
michael@0 127 reporter.SetSuccessful();
michael@0 128 return true;
michael@0 129 }
michael@0 130
michael@0 131 // Return the name of the shared library that implements Omx based decoding. This varies
michael@0 132 // depending on libstagefright version installed on the device and whether it is B2G vs Android.
michael@0 133 // nullptr is returned if Omx decoding is not supported on the device,
michael@0 134 static const char* GetOmxLibraryName()
michael@0 135 {
michael@0 136 #if defined(ANDROID) && !defined(MOZ_WIDGET_GONK)
michael@0 137 nsCOMPtr<nsIPropertyBag2> infoService = do_GetService("@mozilla.org/system-info;1");
michael@0 138 NS_ASSERTION(infoService, "Could not find a system info service");
michael@0 139
michael@0 140 int32_t version;
michael@0 141 nsresult rv = infoService->GetPropertyAsInt32(NS_LITERAL_STRING("version"), &version);
michael@0 142 if (NS_SUCCEEDED(rv)) {
michael@0 143 ALOG("Android Version is: %d", version);
michael@0 144 }
michael@0 145
michael@0 146 nsAutoString release_version;
michael@0 147 rv = infoService->GetPropertyAsAString(NS_LITERAL_STRING("release_version"), release_version);
michael@0 148 if (NS_SUCCEEDED(rv)) {
michael@0 149 ALOG("Android Release Version is: %s", NS_LossyConvertUTF16toASCII(release_version).get());
michael@0 150 }
michael@0 151
michael@0 152 nsAutoString device;
michael@0 153 rv = infoService->GetPropertyAsAString(NS_LITERAL_STRING("device"), device);
michael@0 154 if (NS_SUCCEEDED(rv)) {
michael@0 155 ALOG("Android Device is: %s", NS_LossyConvertUTF16toASCII(device).get());
michael@0 156 }
michael@0 157
michael@0 158 nsAutoString manufacturer;
michael@0 159 rv = infoService->GetPropertyAsAString(NS_LITERAL_STRING("manufacturer"), manufacturer);
michael@0 160 if (NS_SUCCEEDED(rv)) {
michael@0 161 ALOG("Android Manufacturer is: %s", NS_LossyConvertUTF16toASCII(manufacturer).get());
michael@0 162 }
michael@0 163
michael@0 164 nsAutoString hardware;
michael@0 165 rv = infoService->GetPropertyAsAString(NS_LITERAL_STRING("hardware"), hardware);
michael@0 166 if (NS_SUCCEEDED(rv)) {
michael@0 167 ALOG("Android Hardware is: %s", NS_LossyConvertUTF16toASCII(hardware).get());
michael@0 168 }
michael@0 169 #endif
michael@0 170
michael@0 171 if (!IsOmxSupported())
michael@0 172 return nullptr;
michael@0 173
michael@0 174 #if defined(ANDROID) && !defined(MOZ_WIDGET_GONK)
michael@0 175 if (version >= 17) {
michael@0 176 return "libomxpluginkk.so";
michael@0 177 }
michael@0 178 else if (version == 13 || version == 12 || version == 11) {
michael@0 179 return "libomxpluginhc.so";
michael@0 180 }
michael@0 181 else if (version == 10 && release_version >= NS_LITERAL_STRING("2.3.6")) {
michael@0 182 // Gingerbread versions from 2.3.6 and above have a different DataSource
michael@0 183 // layout to those on 2.3.5 and below.
michael@0 184 return "libomxplugingb.so";
michael@0 185 }
michael@0 186 else if (version == 10 && release_version >= NS_LITERAL_STRING("2.3.4") &&
michael@0 187 device.Find("HTC") == 0) {
michael@0 188 // HTC devices running Gingerbread 2.3.4+ (HTC Desire HD, HTC Evo Design, etc) seem to
michael@0 189 // use a newer version of Gingerbread libstagefright than other 2.3.4 devices.
michael@0 190 return "libomxplugingb.so";
michael@0 191 }
michael@0 192 else if (version == 9 || (version == 10 && release_version <= NS_LITERAL_STRING("2.3.5"))) {
michael@0 193 // Gingerbread versions from 2.3.5 and below have a different DataSource
michael@0 194 // than 2.3.6 and above.
michael@0 195 return "libomxplugingb235.so";
michael@0 196 }
michael@0 197 else if (version == 8) {
michael@0 198 // Froyo
michael@0 199 return "libomxpluginfroyo.so";
michael@0 200 }
michael@0 201 else if (version < 8) {
michael@0 202 // Below Froyo not supported
michael@0 203 return nullptr;
michael@0 204 }
michael@0 205
michael@0 206 // Ice Cream Sandwich and Jellybean
michael@0 207 return "libomxplugin.so";
michael@0 208
michael@0 209 #elif defined(ANDROID) && defined(MOZ_WIDGET_GONK)
michael@0 210 return "libomxplugin.so";
michael@0 211 #else
michael@0 212 return nullptr;
michael@0 213 #endif
michael@0 214 }
michael@0 215
michael@0 216 MediaPluginHost::MediaPluginHost() {
michael@0 217 MOZ_COUNT_CTOR(MediaPluginHost);
michael@0 218
michael@0 219 mResourceServer = MediaResourceServer::Start();
michael@0 220
michael@0 221 const char* name = GetOmxLibraryName();
michael@0 222 ALOG("Loading OMX Plugin: %s", name ? name : "nullptr");
michael@0 223 if (name) {
michael@0 224 char *path = PR_GetLibraryFilePathname("libxul.so", (PRFuncPtr) GetOmxLibraryName);
michael@0 225 PRLibrary *lib = nullptr;
michael@0 226 if (path) {
michael@0 227 nsAutoCString libpath(path);
michael@0 228 PR_Free(path);
michael@0 229 int32_t slash = libpath.RFindChar('/');
michael@0 230 if (slash != kNotFound) {
michael@0 231 libpath.Truncate(slash + 1);
michael@0 232 libpath.Append(name);
michael@0 233 lib = PR_LoadLibrary(libpath.get());
michael@0 234 }
michael@0 235 }
michael@0 236 if (!lib)
michael@0 237 lib = PR_LoadLibrary(name);
michael@0 238
michael@0 239 if (lib) {
michael@0 240 Manifest *manifest = static_cast<Manifest *>(PR_FindSymbol(lib, "MPAPI_MANIFEST"));
michael@0 241 if (manifest) {
michael@0 242 mPlugins.AppendElement(manifest);
michael@0 243 ALOG("OMX plugin successfully loaded");
michael@0 244 }
michael@0 245 }
michael@0 246 }
michael@0 247 }
michael@0 248
michael@0 249 MediaPluginHost::~MediaPluginHost() {
michael@0 250 mResourceServer->Stop();
michael@0 251 MOZ_COUNT_DTOR(MediaPluginHost);
michael@0 252 }
michael@0 253
michael@0 254 bool MediaPluginHost::FindDecoder(const nsACString& aMimeType, const char* const** aCodecs)
michael@0 255 {
michael@0 256 const char *chars;
michael@0 257 size_t len = NS_CStringGetData(aMimeType, &chars, nullptr);
michael@0 258 for (size_t n = 0; n < mPlugins.Length(); ++n) {
michael@0 259 Manifest *plugin = mPlugins[n];
michael@0 260 const char* const *codecs;
michael@0 261 if (plugin->CanDecode(chars, len, &codecs)) {
michael@0 262 if (aCodecs)
michael@0 263 *aCodecs = codecs;
michael@0 264 return true;
michael@0 265 }
michael@0 266 }
michael@0 267 return false;
michael@0 268 }
michael@0 269
michael@0 270 MPAPI::Decoder *MediaPluginHost::CreateDecoder(MediaResource *aResource, const nsACString& aMimeType)
michael@0 271 {
michael@0 272 NS_ENSURE_TRUE(aResource, nullptr);
michael@0 273
michael@0 274 nsAutoPtr<Decoder> decoder(new Decoder());
michael@0 275 if (!decoder) {
michael@0 276 return nullptr;
michael@0 277 }
michael@0 278
michael@0 279 const char *chars;
michael@0 280 size_t len = NS_CStringGetData(aMimeType, &chars, nullptr);
michael@0 281 for (size_t n = 0; n < mPlugins.Length(); ++n) {
michael@0 282 Manifest *plugin = mPlugins[n];
michael@0 283 const char* const *codecs;
michael@0 284 if (!plugin->CanDecode(chars, len, &codecs)) {
michael@0 285 continue;
michael@0 286 }
michael@0 287
michael@0 288 nsCString url;
michael@0 289 nsresult rv = mResourceServer->AddResource(aResource, url);
michael@0 290 if (NS_FAILED (rv)) continue;
michael@0 291
michael@0 292 decoder->mResource = strdup(url.get());
michael@0 293 if (plugin->CreateDecoder(&sPluginHost, decoder, chars, len)) {
michael@0 294 aResource->AddRef();
michael@0 295 return decoder.forget();
michael@0 296 }
michael@0 297 }
michael@0 298
michael@0 299 return nullptr;
michael@0 300 }
michael@0 301
michael@0 302 void MediaPluginHost::DestroyDecoder(Decoder *aDecoder)
michael@0 303 {
michael@0 304 aDecoder->DestroyDecoder(aDecoder);
michael@0 305 char* resource = GetResource(aDecoder);
michael@0 306 if (resource) {
michael@0 307 // resource *shouldn't* be null, but check anyway just in case the plugin
michael@0 308 // decoder does something stupid.
michael@0 309 mResourceServer->RemoveResource(nsCString(resource));
michael@0 310 free(resource);
michael@0 311 }
michael@0 312 delete aDecoder;
michael@0 313 }
michael@0 314
michael@0 315 MediaPluginHost *sMediaPluginHost = nullptr;
michael@0 316 MediaPluginHost *GetMediaPluginHost()
michael@0 317 {
michael@0 318 if (!sMediaPluginHost) {
michael@0 319 sMediaPluginHost = new MediaPluginHost();
michael@0 320 }
michael@0 321 return sMediaPluginHost;
michael@0 322 }
michael@0 323
michael@0 324 void MediaPluginHost::Shutdown()
michael@0 325 {
michael@0 326 delete sMediaPluginHost;
michael@0 327 sMediaPluginHost = nullptr;
michael@0 328 }
michael@0 329
michael@0 330 } // namespace mozilla

mercurial