summaryrefslogtreecommitdiffstats
path: root/dom/media/platforms/omx/OmxPlatformLayer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/media/platforms/omx/OmxPlatformLayer.cpp')
-rw-r--r--dom/media/platforms/omx/OmxPlatformLayer.cpp307
1 files changed, 307 insertions, 0 deletions
diff --git a/dom/media/platforms/omx/OmxPlatformLayer.cpp b/dom/media/platforms/omx/OmxPlatformLayer.cpp
new file mode 100644
index 0000000000..dc3ccc0979
--- /dev/null
+++ b/dom/media/platforms/omx/OmxPlatformLayer.cpp
@@ -0,0 +1,307 @@
+/* -*- 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/. */
+
+#include "OmxPlatformLayer.h"
+
+#include "OmxDataDecoder.h"
+#include "OMX_Component.h"
+#include "OMX_VideoExt.h" // For VP8.
+
+#ifdef MOZ_OMX
+# include "PureOmxPlatformLayer.h"
+#endif
+
+#include "VPXDecoder.h"
+
+#ifdef LOG
+# undef LOG
+#endif
+
+#define LOG(arg, ...) \
+ MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, \
+ ("OmxPlatformLayer -- %s: " arg, __func__, ##__VA_ARGS__))
+
+#define RETURN_IF_ERR(err) \
+ if (err != OMX_ErrorNone) { \
+ LOG("error: 0x%08x", err); \
+ return err; \
+ }
+
+// Common OMX decoder configuration code.
+namespace mozilla {
+
+// This helper class encapsulates the details of component parameters setting
+// for different OMX audio & video codecs.
+template <typename ParamType>
+class OmxConfig {
+ public:
+ virtual ~OmxConfig() = default;
+ // Subclasses should implement this method to configure the codec.
+ virtual OMX_ERRORTYPE Apply(OmxPlatformLayer& aOmx,
+ const ParamType& aParam) = 0;
+};
+
+typedef OmxConfig<AudioInfo> OmxAudioConfig;
+typedef OmxConfig<VideoInfo> OmxVideoConfig;
+
+template <typename ConfigType>
+UniquePtr<ConfigType> ConfigForMime(const nsACString&);
+
+static OMX_ERRORTYPE ConfigAudioOutputPort(OmxPlatformLayer& aOmx,
+ const AudioInfo& aInfo) {
+ OMX_PARAM_PORTDEFINITIONTYPE def;
+ InitOmxParameter(&def);
+ def.nPortIndex = aOmx.OutputPortIndex();
+ OMX_ERRORTYPE err =
+ aOmx.GetParameter(OMX_IndexParamPortDefinition, &def, sizeof(def));
+ RETURN_IF_ERR(err);
+
+ def.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
+ err = aOmx.SetParameter(OMX_IndexParamPortDefinition, &def, sizeof(def));
+ RETURN_IF_ERR(err);
+
+ OMX_AUDIO_PARAM_PCMMODETYPE pcmParams;
+ InitOmxParameter(&pcmParams);
+ pcmParams.nPortIndex = def.nPortIndex;
+ err =
+ aOmx.GetParameter(OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
+ RETURN_IF_ERR(err);
+
+ pcmParams.nChannels = aInfo.mChannels;
+ pcmParams.eNumData = OMX_NumericalDataSigned;
+ pcmParams.bInterleaved = OMX_TRUE;
+ pcmParams.nBitPerSample = 16;
+ pcmParams.nSamplingRate = aInfo.mRate;
+ pcmParams.ePCMMode = OMX_AUDIO_PCMModeLinear;
+ err =
+ aOmx.SetParameter(OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
+ RETURN_IF_ERR(err);
+
+ LOG("Config OMX_IndexParamAudioPcm, channel %lu, sample rate %lu",
+ pcmParams.nChannels, pcmParams.nSamplingRate);
+
+ return OMX_ErrorNone;
+}
+
+class OmxAacConfig : public OmxAudioConfig {
+ public:
+ OMX_ERRORTYPE Apply(OmxPlatformLayer& aOmx, const AudioInfo& aInfo) override {
+ OMX_AUDIO_PARAM_AACPROFILETYPE aacProfile;
+ InitOmxParameter(&aacProfile);
+ aacProfile.nPortIndex = aOmx.InputPortIndex();
+ OMX_ERRORTYPE err = aOmx.GetParameter(OMX_IndexParamAudioAac, &aacProfile,
+ sizeof(aacProfile));
+ RETURN_IF_ERR(err);
+
+ aacProfile.nChannels = aInfo.mChannels;
+ aacProfile.nSampleRate = aInfo.mRate;
+ aacProfile.eAACProfile =
+ static_cast<OMX_AUDIO_AACPROFILETYPE>(aInfo.mProfile);
+ err = aOmx.SetParameter(OMX_IndexParamAudioAac, &aacProfile,
+ sizeof(aacProfile));
+ RETURN_IF_ERR(err);
+
+ LOG("Config OMX_IndexParamAudioAac, channel %lu, sample rate %lu, profile "
+ "%d",
+ aacProfile.nChannels, aacProfile.nSampleRate, aacProfile.eAACProfile);
+
+ return ConfigAudioOutputPort(aOmx, aInfo);
+ }
+};
+
+class OmxMp3Config : public OmxAudioConfig {
+ public:
+ OMX_ERRORTYPE Apply(OmxPlatformLayer& aOmx, const AudioInfo& aInfo) override {
+ OMX_AUDIO_PARAM_MP3TYPE mp3Param;
+ InitOmxParameter(&mp3Param);
+ mp3Param.nPortIndex = aOmx.InputPortIndex();
+ OMX_ERRORTYPE err =
+ aOmx.GetParameter(OMX_IndexParamAudioMp3, &mp3Param, sizeof(mp3Param));
+ RETURN_IF_ERR(err);
+
+ mp3Param.nChannels = aInfo.mChannels;
+ mp3Param.nSampleRate = aInfo.mRate;
+ err =
+ aOmx.SetParameter(OMX_IndexParamAudioMp3, &mp3Param, sizeof(mp3Param));
+ RETURN_IF_ERR(err);
+
+ LOG("Config OMX_IndexParamAudioMp3, channel %lu, sample rate %lu",
+ mp3Param.nChannels, mp3Param.nSampleRate);
+
+ return ConfigAudioOutputPort(aOmx, aInfo);
+ }
+};
+
+enum OmxAmrSampleRate {
+ kNarrowBand = 8000,
+ kWideBand = 16000,
+};
+
+template <OmxAmrSampleRate R>
+class OmxAmrConfig : public OmxAudioConfig {
+ public:
+ OMX_ERRORTYPE Apply(OmxPlatformLayer& aOmx, const AudioInfo& aInfo) override {
+ OMX_AUDIO_PARAM_AMRTYPE def;
+ InitOmxParameter(&def);
+ def.nPortIndex = aOmx.InputPortIndex();
+ OMX_ERRORTYPE err =
+ aOmx.GetParameter(OMX_IndexParamAudioAmr, &def, sizeof(def));
+ RETURN_IF_ERR(err);
+
+ def.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
+ err = aOmx.SetParameter(OMX_IndexParamAudioAmr, &def, sizeof(def));
+ RETURN_IF_ERR(err);
+
+ MOZ_ASSERT(aInfo.mChannels == 1);
+ MOZ_ASSERT(aInfo.mRate == R);
+
+ return ConfigAudioOutputPort(aOmx, aInfo);
+ }
+};
+
+template <>
+UniquePtr<OmxAudioConfig> ConfigForMime(const nsACString& aMimeType) {
+ UniquePtr<OmxAudioConfig> conf;
+
+ if (OmxPlatformLayer::SupportsMimeType(aMimeType)) {
+ if (aMimeType.EqualsLiteral("audio/mp4a-latm")) {
+ conf.reset(new OmxAacConfig());
+ } else if (aMimeType.EqualsLiteral("audio/mp3") ||
+ aMimeType.EqualsLiteral("audio/mpeg")) {
+ conf.reset(new OmxMp3Config());
+ } else if (aMimeType.EqualsLiteral("audio/3gpp")) {
+ conf.reset(new OmxAmrConfig<OmxAmrSampleRate::kNarrowBand>());
+ } else if (aMimeType.EqualsLiteral("audio/amr-wb")) {
+ conf.reset(new OmxAmrConfig<OmxAmrSampleRate::kWideBand>());
+ }
+ }
+ return conf;
+}
+
+// There should be a better way to calculate it.
+#define MIN_VIDEO_INPUT_BUFFER_SIZE 64 * 1024
+
+class OmxCommonVideoConfig : public OmxVideoConfig {
+ public:
+ explicit OmxCommonVideoConfig() : OmxVideoConfig() {}
+
+ OMX_ERRORTYPE Apply(OmxPlatformLayer& aOmx, const VideoInfo& aInfo) override {
+ OMX_ERRORTYPE err = OMX_ErrorNone;
+ OMX_PARAM_PORTDEFINITIONTYPE def;
+
+ // Set up in/out port definition.
+ nsTArray<uint32_t> ports;
+ aOmx.GetPortIndices(ports);
+ for (auto idx : ports) {
+ InitOmxParameter(&def);
+ def.nPortIndex = idx;
+ err = aOmx.GetParameter(OMX_IndexParamPortDefinition, &def, sizeof(def));
+ RETURN_IF_ERR(err);
+
+ def.format.video.nFrameWidth = aInfo.mDisplay.width;
+ def.format.video.nFrameHeight = aInfo.mDisplay.height;
+ def.format.video.nStride = aInfo.mImage.width;
+ def.format.video.nSliceHeight = aInfo.mImage.height;
+
+ if (def.eDir == OMX_DirInput) {
+ def.format.video.eCompressionFormat = aOmx.CompressionFormat();
+ def.format.video.eColorFormat = OMX_COLOR_FormatUnused;
+ if (def.nBufferSize < MIN_VIDEO_INPUT_BUFFER_SIZE) {
+ def.nBufferSize = aInfo.mImage.width * aInfo.mImage.height;
+ LOG("Change input buffer size to %lu", def.nBufferSize);
+ }
+ } else {
+ def.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused;
+ }
+
+ err = aOmx.SetParameter(OMX_IndexParamPortDefinition, &def, sizeof(def));
+ }
+ return err;
+ }
+};
+
+template <>
+UniquePtr<OmxVideoConfig> ConfigForMime(const nsACString& aMimeType) {
+ UniquePtr<OmxVideoConfig> conf;
+
+ if (OmxPlatformLayer::SupportsMimeType(aMimeType)) {
+ conf.reset(new OmxCommonVideoConfig());
+ }
+ return conf;
+}
+
+OMX_ERRORTYPE
+OmxPlatformLayer::Config() {
+ MOZ_ASSERT(mInfo);
+
+ OMX_PORT_PARAM_TYPE portParam;
+ InitOmxParameter(&portParam);
+ if (mInfo->IsAudio()) {
+ GetParameter(OMX_IndexParamAudioInit, &portParam, sizeof(portParam));
+ mStartPortNumber = portParam.nStartPortNumber;
+ UniquePtr<OmxAudioConfig> conf(
+ ConfigForMime<OmxAudioConfig>(mInfo->mMimeType));
+ MOZ_RELEASE_ASSERT(conf.get());
+ return conf->Apply(*this, *(mInfo->GetAsAudioInfo()));
+ } else if (mInfo->IsVideo()) {
+ GetParameter(OMX_IndexParamVideoInit, &portParam, sizeof(portParam));
+ UniquePtr<OmxVideoConfig> conf(
+ ConfigForMime<OmxVideoConfig>(mInfo->mMimeType));
+ MOZ_RELEASE_ASSERT(conf.get());
+ return conf->Apply(*this, *(mInfo->GetAsVideoInfo()));
+ } else {
+ MOZ_ASSERT_UNREACHABLE("non-AV data (text?) is not supported.");
+ return OMX_ErrorNotImplemented;
+ }
+}
+
+OMX_VIDEO_CODINGTYPE
+OmxPlatformLayer::CompressionFormat() {
+ MOZ_ASSERT(mInfo);
+
+ if (mInfo->mMimeType.EqualsLiteral("video/avc")) {
+ return OMX_VIDEO_CodingAVC;
+ } else if (mInfo->mMimeType.EqualsLiteral("video/mp4v-es") ||
+ mInfo->mMimeType.EqualsLiteral("video/mp4")) {
+ return OMX_VIDEO_CodingMPEG4;
+ } else if (mInfo->mMimeType.EqualsLiteral("video/3gpp")) {
+ return OMX_VIDEO_CodingH263;
+ } else if (VPXDecoder::IsVP8(mInfo->mMimeType)) {
+ return static_cast<OMX_VIDEO_CODINGTYPE>(OMX_VIDEO_CodingVP8);
+ } else {
+ MOZ_ASSERT_UNREACHABLE("Unsupported compression format");
+ return OMX_VIDEO_CodingUnused;
+ }
+}
+
+// Implementations for different platforms will be defined in their own files.
+#if defined(MOZ_OMX)
+
+bool OmxPlatformLayer::SupportsMimeType(const nsACString& aMimeType) {
+ return PureOmxPlatformLayer::SupportsMimeType(aMimeType);
+}
+
+OmxPlatformLayer* OmxPlatformLayer::Create(
+ OmxDataDecoder* aDataDecoder, OmxPromiseLayer* aPromiseLayer,
+ TaskQueue* aTaskQueue, layers::ImageContainer* aImageContainer) {
+ return new PureOmxPlatformLayer(aDataDecoder, aPromiseLayer, aTaskQueue,
+ aImageContainer);
+}
+
+#else // For platforms without OMX IL support.
+
+bool OmxPlatformLayer::SupportsMimeType(const nsACString& aMimeType) {
+ return false;
+}
+
+OmxPlatformLayer* OmxPlatformLayer::Create(
+ OmxDataDecoder* aDataDecoder, OmxPromiseLayer* aPromiseLayer,
+ TaskQueue* aTaskQueue, layers::ImageContainer* aImageContainer) {
+ return nullptr;
+}
+
+#endif
+} // namespace mozilla