Bug 953394 - Force OMXCodec to output a sane colour format on Android 4.4 and above. r=doublec, a=bajaj
authorEdwin Flores <edwin>
Mon, 06 Jan 2014 19:58:00 -0500
changeset 169566 e5785687c13ade03c5ce85f56be0bebfd6a85d46
parent 169565 6da6f218ba170ee5f849b3a1a7a1b8386a0c9d72
child 169567 00262fd30bb02d7e298e99053ddcd78906601554
push id5096
push userryanvm@gmail.com
push dateWed, 29 Jan 2014 02:52:12 +0000
treeherdermozilla-aurora@00262fd30bb0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdoublec, bajaj
bugs953394
milestone28.0a2
Bug 953394 - Force OMXCodec to output a sane colour format on Android 4.4 and above. r=doublec, a=bajaj
content/media/plugins/MediaPluginHost.cpp
media/omx-plugin/OmxPlugin.cpp
media/omx-plugin/kk/Makefile.in
media/omx-plugin/kk/OmxPluginKitKat.cpp
media/omx-plugin/kk/moz.build
--- a/content/media/plugins/MediaPluginHost.cpp
+++ b/content/media/plugins/MediaPluginHost.cpp
@@ -147,17 +147,20 @@ static const char* GetOmxLibraryName()
     ALOG("Android Hardware is: %s", NS_LossyConvertUTF16toASCII(hardware).get());
   }
 #endif
 
   if (!IsOmxSupported())
     return nullptr;
 
 #if defined(ANDROID) && !defined(MOZ_WIDGET_GONK)
-  if (version == 13 || version == 12 || version == 11) {
+  if (version >= 19) {
+    return "libomxpluginkk.so";
+  }
+  else if (version == 13 || version == 12 || version == 11) {
     return "libomxpluginhc.so";
   }
   else if (version == 10 && release_version >= NS_LITERAL_STRING("2.3.6")) {
     // Gingerbread versions from 2.3.6 and above have a different DataSource
     // layout to those on 2.3.5 and below.
     return "libomxplugingb.so";
   }
   else if (version == 10 && release_version >= NS_LITERAL_STRING("2.3.4") &&
@@ -175,17 +178,17 @@ static const char* GetOmxLibraryName()
     // Froyo
     return "libomxpluginfroyo.so";
   }
   else if (version < 8) {
     // Below Froyo not supported
     return nullptr;
   }
 
-  // Default libomxplugin for non-gingerbread devices
+  // KitKat
   return "libomxplugin.so";
 
 #elif defined(ANDROID) && defined(MOZ_WIDGET_GONK)
   return "libomxplugin.so";
 #else
   return nullptr;
 #endif
 }
--- a/media/omx-plugin/OmxPlugin.cpp
+++ b/media/omx-plugin/OmxPlugin.cpp
@@ -18,16 +18,19 @@
 #include <algorithm>
 
 #include "mozilla/Assertions.h"
 #include "mozilla/Types.h"
 #include "MPAPI.h"
 
 #include "android/log.h"
 
+#define MAX_DECODER_NAME_LEN 256
+#define AVC_MIME_TYPE "video/avc"
+
 #if !defined(MOZ_ANDROID_FROYO)
 #define DEFAULT_STAGEFRIGHT_FLAGS OMXCodec::kClientNeedsFramebuffer
 #else
 #define DEFAULT_STAGEFRIGHT_FLAGS 0
 #endif
 
 #undef LOG
 #define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "OmxPlugin" , ## args)
@@ -234,62 +237,140 @@ static uint32_t GetVideoCreationFlags(Pl
   }
 
   flags |= DEFAULT_STAGEFRIGHT_FLAGS;
 
   return static_cast<uint32_t>(flags);
 #endif
 }
 
-static bool
+enum ColorFormatSupport {
+  ColorFormatNotSupported = 0,
+  ColorFormatSupportOK,
+  ColorFormatSupportPreferred,
+};
+
+static ColorFormatSupport
 IsColorFormatSupported(OMX_COLOR_FORMATTYPE aColorFormat)
 {
   switch (aColorFormat) {
     case OMX_COLOR_FormatCbYCrY:
     case OMX_COLOR_FormatYUV420Planar:
     case OMX_COLOR_FormatYUV420SemiPlanar:
     case OMX_QCOM_COLOR_FormatYVU420PackedSemiPlanar32m4ka:
     case OMX_QCOM_COLOR_FormatYVU420SemiPlanar:
     case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar:
       LOG("Colour format %#x supported natively.", aColorFormat);
-      return true;
+      // Prefer natively supported colour formats over formats that need another
+      // slow software conversion.
+      return ColorFormatSupportPreferred;
     default:
       break;
   }
 
+  // These formats are okay if we can't find a better one; Android provides a
+  // software conversion to a sane colour format.
 #if !defined(MOZ_ANDROID_HC)
   if (ColorConverter(aColorFormat, OMX_COLOR_Format16bitRGB565).isValid()) {
     LOG("Colour format %#x supported by Android ColorConverter.", aColorFormat);
-    return true;
+    return ColorFormatSupportOK;
   }
 #endif
 
 #if defined(MOZ_ANDROID_V4_OR_ABOVE)
   I420ColorConverter yuvConverter;
 
   if (yuvConverter.isLoaded() &&
       yuvConverter.getDecoderOutputFormat() == aColorFormat) {
     LOG("Colour format %#x supported by Android I420ColorConverter.", aColorFormat);
-    return true;
+    return ColorFormatSupportOK;
   }
 #endif
 
+  return ColorFormatNotSupported;
+}
+
+#if defined(MOZ_ANDROID_KK)
+/**
+ * Look for a decoder that supports a colour format that we support.
+ */
+static bool
+FindPreferredDecoderAndColorFormat(const sp<IOMX>& aOmx,
+                                   char *decoderName,
+                                   OMX_COLOR_FORMATTYPE *colorFormat)
+{
+  Vector<CodecCapabilities> codecs;
+
+  // Get all AVC decoder/colour format pairs that this device supports.
+  QueryCodecs(aOmx, AVC_MIME_TYPE, true /* queryDecoders */, &codecs);
+
+  // We assume that faster (hardware accelerated) decoders come first in the
+  // list, so we choose the first decoder with a colour format we can use.
+  for (uint32_t i = 0; i < codecs.size(); i++) {
+    const CodecCapabilities &caps = codecs[i];
+    const Vector<OMX_U32> &colors = caps.mColorFormats;
+
+    bool found = false;
+    for (uint32_t j = 0; j < colors.size(); j++) {
+      OMX_COLOR_FORMATTYPE color = (OMX_COLOR_FORMATTYPE)colors[j];
+
+      LOG("Decoder %s can output colour format %#x.\n",
+          caps.mComponentName.string(), color);
+
+      ColorFormatSupport supported = IsColorFormatSupported(color);
+
+      if (supported) {
+        strncpy(decoderName, caps.mComponentName.string(), MAX_DECODER_NAME_LEN);
+        *colorFormat = (OMX_COLOR_FORMATTYPE)color;
+        found = true;
+      }
+
+      if (supported == ColorFormatSupportPreferred) {
+        // The colour format is natively supported -- that's as good as we're
+        // going to get.
+        break;
+      }
+    }
+
+    if (found) {
+      return true;
+    }
+  }
+
   return false;
 }
+#endif
 
 static sp<MediaSource> CreateVideoSource(PluginHost* aPluginHost,
                                          const sp<IOMX>& aOmx,
                                          const sp<MediaSource>& aVideoTrack)
 {
   uint32_t flags = GetVideoCreationFlags(aPluginHost);
 
+  char decoderName[MAX_DECODER_NAME_LEN] = "";
+  sp<MetaData> videoFormat = aVideoTrack->getFormat();
+
+#if defined(MOZ_ANDROID_KK)
+  OMX_COLOR_FORMATTYPE colorFormat = (OMX_COLOR_FORMATTYPE)0;
+  if (FindPreferredDecoderAndColorFormat(aOmx, decoderName, &colorFormat)) {
+    // We found a colour format that we can handle. Tell OMXCodec to use it in
+    // case it isn't the default.
+    videoFormat->setInt32(kKeyColorFormat, colorFormat);
+
+    LOG("Found compatible decoder %s with colour format %#x.\n",
+        decoderName, colorFormat);
+  }
+#endif
+
   if (flags == DEFAULT_STAGEFRIGHT_FLAGS) {
     // Let Stagefright choose hardware or software decoder.
-    sp<MediaSource> videoSource = OMXCodec::Create(aOmx, aVideoTrack->getFormat(),
-                                                   false, aVideoTrack, nullptr, flags);
+    sp<MediaSource> videoSource = OMXCodec::Create(aOmx, videoFormat,
+                                                   false, aVideoTrack,
+                                                   decoderName[0] ? decoderName : nullptr,
+                                                   flags);
     if (videoSource == nullptr)
       return nullptr;
 
     // Now that OMXCodec has parsed the video's AVCDecoderConfigurationRecord,
     // check whether we know how to decode this video.
     int32_t videoColorFormat;
     if (videoSource->getFormat()->findInt32(kKeyColorFormat, &videoColorFormat)) {
 
@@ -732,17 +813,16 @@ bool OmxDecoder::ToVideoFrame_I420ColorC
 
   ARect crop = { mVideoCropLeft, mVideoCropTop, mVideoCropRight, mVideoCropBottom };
   int result = yuvConverter.convertDecoderOutputToI420(aData,
                                                        mVideoWidth,
                                                        mVideoHeight,
                                                        crop,
                                                        buffer);
 
-  // result is 0 on success, -1 otherwise.
   if (result == OK) {
     aFrame->mTimeUs = aTimeUs;
     aFrame->mSize = mVideoWidth * mVideoHeight * 3 / 2;
   }
 
   return result == OK;
 #else
   return false;
new file mode 100644
--- /dev/null
+++ b/media/omx-plugin/kk/Makefile.in
@@ -0,0 +1,31 @@
+# Copyright 2012 Mozilla Foundation and Mozilla contributors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Don't use STL wrappers; this isn't Gecko code
+STL_FLAGS =
+
+# must link statically with the CRT; this isn't Gecko code
+USE_STATIC_LIBS = 1
+
+include $(topsrcdir)/config/rules.mk
+
+EXTRA_DSO_LDOPTS += \
+		-L$(DEPTH)/media/omx-plugin/lib/ics/libutils \
+		-lutils \
+		-L$(DEPTH)/media/omx-plugin/lib/ics/libstagefright \
+		-lstagefright \
+		-L$(DEPTH)/media/omx-plugin/lib/ics/libvideoeditorplayer \
+		-lvideoeditorplayer \
+		$(NULL)
+
new file mode 100644
--- /dev/null
+++ b/media/omx-plugin/kk/OmxPluginKitKat.cpp
@@ -0,0 +1,8 @@
+/* -*- 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/. */
+#define MOZ_STAGEFRIGHT_OFF_T off64_t
+#define MOZ_ANDROID_KK
+#include "../OmxPlugin.cpp"
new file mode 100644
--- /dev/null
+++ b/media/omx-plugin/kk/moz.build
@@ -0,0 +1,20 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+SOURCES += [
+    'OmxPluginKitKat.cpp',
+]
+
+LIBRARY_NAME = 'omxpluginkk'
+
+FORCE_SHARED_LIB = True
+
+LOCAL_INCLUDES += [
+    '../../../content/media/plugins',
+    '../include/ics',
+    '../include/ics/media/stagefright/openmax',
+]
+