OmxPlatformLayer.cpp (10113B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim:set ts=2 sw=2 sts=2 et cindent: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "OmxPlatformLayer.h" 8 9 #include "OMX_Component.h" 10 #include "OMX_VideoExt.h" // For VP8. 11 #include "OmxDataDecoder.h" 12 13 #ifdef MOZ_OMX 14 # include "PureOmxPlatformLayer.h" 15 #endif 16 17 #include "VPXDecoder.h" 18 19 #ifdef LOG 20 # undef LOG 21 #endif 22 23 #define LOG(arg, ...) \ 24 MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, \ 25 ("OmxPlatformLayer -- %s: " arg, __func__, ##__VA_ARGS__)) 26 27 #define RETURN_IF_ERR(err) \ 28 if (err != OMX_ErrorNone) { \ 29 LOG("error: 0x%08x", err); \ 30 return err; \ 31 } 32 33 // Common OMX decoder configuration code. 34 namespace mozilla { 35 36 // This helper class encapsulates the details of component parameters setting 37 // for different OMX audio & video codecs. 38 template <typename ParamType> 39 class OmxConfig { 40 public: 41 virtual ~OmxConfig() = default; 42 // Subclasses should implement this method to configure the codec. 43 virtual OMX_ERRORTYPE Apply(OmxPlatformLayer& aOmx, 44 const ParamType& aParam) = 0; 45 }; 46 47 typedef OmxConfig<AudioInfo> OmxAudioConfig; 48 typedef OmxConfig<VideoInfo> OmxVideoConfig; 49 50 template <typename ConfigType> 51 UniquePtr<ConfigType> ConfigForMime(const nsACString&); 52 53 static OMX_ERRORTYPE ConfigAudioOutputPort(OmxPlatformLayer& aOmx, 54 const AudioInfo& aInfo) { 55 OMX_PARAM_PORTDEFINITIONTYPE def; 56 InitOmxParameter(&def); 57 def.nPortIndex = aOmx.OutputPortIndex(); 58 OMX_ERRORTYPE err = 59 aOmx.GetParameter(OMX_IndexParamPortDefinition, &def, sizeof(def)); 60 RETURN_IF_ERR(err); 61 62 def.format.audio.eEncoding = OMX_AUDIO_CodingPCM; 63 err = aOmx.SetParameter(OMX_IndexParamPortDefinition, &def, sizeof(def)); 64 RETURN_IF_ERR(err); 65 66 OMX_AUDIO_PARAM_PCMMODETYPE pcmParams; 67 InitOmxParameter(&pcmParams); 68 pcmParams.nPortIndex = def.nPortIndex; 69 err = 70 aOmx.GetParameter(OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams)); 71 RETURN_IF_ERR(err); 72 73 pcmParams.nChannels = aInfo.mChannels; 74 pcmParams.eNumData = OMX_NumericalDataSigned; 75 pcmParams.bInterleaved = OMX_TRUE; 76 pcmParams.nBitPerSample = 16; 77 pcmParams.nSamplingRate = aInfo.mRate; 78 pcmParams.ePCMMode = OMX_AUDIO_PCMModeLinear; 79 err = 80 aOmx.SetParameter(OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams)); 81 RETURN_IF_ERR(err); 82 83 LOG("Config OMX_IndexParamAudioPcm, channel %lu, sample rate %lu", 84 pcmParams.nChannels, pcmParams.nSamplingRate); 85 86 return OMX_ErrorNone; 87 } 88 89 class OmxAacConfig : public OmxAudioConfig { 90 public: 91 OMX_ERRORTYPE Apply(OmxPlatformLayer& aOmx, const AudioInfo& aInfo) override { 92 OMX_AUDIO_PARAM_AACPROFILETYPE aacProfile; 93 InitOmxParameter(&aacProfile); 94 aacProfile.nPortIndex = aOmx.InputPortIndex(); 95 OMX_ERRORTYPE err = aOmx.GetParameter(OMX_IndexParamAudioAac, &aacProfile, 96 sizeof(aacProfile)); 97 RETURN_IF_ERR(err); 98 99 aacProfile.nChannels = aInfo.mChannels; 100 aacProfile.nSampleRate = aInfo.mRate; 101 aacProfile.eAACProfile = 102 static_cast<OMX_AUDIO_AACPROFILETYPE>(aInfo.mProfile); 103 err = aOmx.SetParameter(OMX_IndexParamAudioAac, &aacProfile, 104 sizeof(aacProfile)); 105 RETURN_IF_ERR(err); 106 107 LOG("Config OMX_IndexParamAudioAac, channel %lu, sample rate %lu, profile " 108 "%d", 109 aacProfile.nChannels, aacProfile.nSampleRate, aacProfile.eAACProfile); 110 111 return ConfigAudioOutputPort(aOmx, aInfo); 112 } 113 }; 114 115 class OmxMp3Config : public OmxAudioConfig { 116 public: 117 OMX_ERRORTYPE Apply(OmxPlatformLayer& aOmx, const AudioInfo& aInfo) override { 118 OMX_AUDIO_PARAM_MP3TYPE mp3Param; 119 InitOmxParameter(&mp3Param); 120 mp3Param.nPortIndex = aOmx.InputPortIndex(); 121 OMX_ERRORTYPE err = 122 aOmx.GetParameter(OMX_IndexParamAudioMp3, &mp3Param, sizeof(mp3Param)); 123 RETURN_IF_ERR(err); 124 125 mp3Param.nChannels = aInfo.mChannels; 126 mp3Param.nSampleRate = aInfo.mRate; 127 err = 128 aOmx.SetParameter(OMX_IndexParamAudioMp3, &mp3Param, sizeof(mp3Param)); 129 RETURN_IF_ERR(err); 130 131 LOG("Config OMX_IndexParamAudioMp3, channel %lu, sample rate %lu", 132 mp3Param.nChannels, mp3Param.nSampleRate); 133 134 return ConfigAudioOutputPort(aOmx, aInfo); 135 } 136 }; 137 138 enum OmxAmrSampleRate { 139 kNarrowBand = 8000, 140 kWideBand = 16000, 141 }; 142 143 template <OmxAmrSampleRate R> 144 class OmxAmrConfig : public OmxAudioConfig { 145 public: 146 OMX_ERRORTYPE Apply(OmxPlatformLayer& aOmx, const AudioInfo& aInfo) override { 147 OMX_AUDIO_PARAM_AMRTYPE def; 148 InitOmxParameter(&def); 149 def.nPortIndex = aOmx.InputPortIndex(); 150 OMX_ERRORTYPE err = 151 aOmx.GetParameter(OMX_IndexParamAudioAmr, &def, sizeof(def)); 152 RETURN_IF_ERR(err); 153 154 def.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF; 155 err = aOmx.SetParameter(OMX_IndexParamAudioAmr, &def, sizeof(def)); 156 RETURN_IF_ERR(err); 157 158 MOZ_ASSERT(aInfo.mChannels == 1); 159 MOZ_ASSERT(aInfo.mRate == R); 160 161 return ConfigAudioOutputPort(aOmx, aInfo); 162 } 163 }; 164 165 template <> 166 UniquePtr<OmxAudioConfig> ConfigForMime(const nsACString& aMimeType) { 167 UniquePtr<OmxAudioConfig> conf; 168 169 if (OmxPlatformLayer::SupportsMimeType(aMimeType)) { 170 if (aMimeType.EqualsLiteral("audio/mp4a-latm")) { 171 conf.reset(new OmxAacConfig()); 172 } else if (aMimeType.EqualsLiteral("audio/mp3") || 173 aMimeType.EqualsLiteral("audio/mpeg")) { 174 conf.reset(new OmxMp3Config()); 175 } else if (aMimeType.EqualsLiteral("audio/3gpp")) { 176 conf.reset(new OmxAmrConfig<OmxAmrSampleRate::kNarrowBand>()); 177 } else if (aMimeType.EqualsLiteral("audio/amr-wb")) { 178 conf.reset(new OmxAmrConfig<OmxAmrSampleRate::kWideBand>()); 179 } 180 } 181 return conf; 182 } 183 184 // There should be a better way to calculate it. 185 #define MIN_VIDEO_INPUT_BUFFER_SIZE 64 * 1024 186 187 class OmxCommonVideoConfig : public OmxVideoConfig { 188 public: 189 explicit OmxCommonVideoConfig() : OmxVideoConfig() {} 190 191 OMX_ERRORTYPE Apply(OmxPlatformLayer& aOmx, const VideoInfo& aInfo) override { 192 OMX_ERRORTYPE err = OMX_ErrorNone; 193 OMX_PARAM_PORTDEFINITIONTYPE def; 194 195 // Set up in/out port definition. 196 nsTArray<uint32_t> ports; 197 aOmx.GetPortIndices(ports); 198 for (auto idx : ports) { 199 InitOmxParameter(&def); 200 def.nPortIndex = idx; 201 err = aOmx.GetParameter(OMX_IndexParamPortDefinition, &def, sizeof(def)); 202 RETURN_IF_ERR(err); 203 204 def.format.video.nFrameWidth = aInfo.mDisplay.width; 205 def.format.video.nFrameHeight = aInfo.mDisplay.height; 206 def.format.video.nStride = aInfo.mImage.width; 207 def.format.video.nSliceHeight = aInfo.mImage.height; 208 209 if (def.eDir == OMX_DirInput) { 210 def.format.video.eCompressionFormat = aOmx.CompressionFormat(); 211 def.format.video.eColorFormat = OMX_COLOR_FormatUnused; 212 if (def.nBufferSize < MIN_VIDEO_INPUT_BUFFER_SIZE) { 213 def.nBufferSize = aInfo.mImage.width * aInfo.mImage.height; 214 LOG("Change input buffer size to %lu", def.nBufferSize); 215 } 216 } else { 217 def.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused; 218 } 219 220 err = aOmx.SetParameter(OMX_IndexParamPortDefinition, &def, sizeof(def)); 221 } 222 return err; 223 } 224 }; 225 226 template <> 227 UniquePtr<OmxVideoConfig> ConfigForMime(const nsACString& aMimeType) { 228 UniquePtr<OmxVideoConfig> conf; 229 230 if (OmxPlatformLayer::SupportsMimeType(aMimeType)) { 231 conf.reset(new OmxCommonVideoConfig()); 232 } 233 return conf; 234 } 235 236 OMX_ERRORTYPE 237 OmxPlatformLayer::Config() { 238 MOZ_ASSERT(mInfo); 239 240 OMX_PORT_PARAM_TYPE portParam; 241 InitOmxParameter(&portParam); 242 if (mInfo->IsAudio()) { 243 GetParameter(OMX_IndexParamAudioInit, &portParam, sizeof(portParam)); 244 mStartPortNumber = portParam.nStartPortNumber; 245 UniquePtr<OmxAudioConfig> conf( 246 ConfigForMime<OmxAudioConfig>(mInfo->mMimeType)); 247 MOZ_RELEASE_ASSERT(conf.get()); 248 return conf->Apply(*this, *(mInfo->GetAsAudioInfo())); 249 } else if (mInfo->IsVideo()) { 250 GetParameter(OMX_IndexParamVideoInit, &portParam, sizeof(portParam)); 251 UniquePtr<OmxVideoConfig> conf( 252 ConfigForMime<OmxVideoConfig>(mInfo->mMimeType)); 253 MOZ_RELEASE_ASSERT(conf.get()); 254 return conf->Apply(*this, *(mInfo->GetAsVideoInfo())); 255 } else { 256 MOZ_ASSERT_UNREACHABLE("non-AV data (text?) is not supported."); 257 return OMX_ErrorNotImplemented; 258 } 259 } 260 261 OMX_VIDEO_CODINGTYPE 262 OmxPlatformLayer::CompressionFormat() { 263 MOZ_ASSERT(mInfo); 264 265 if (mInfo->mMimeType.EqualsLiteral("video/avc")) { 266 return OMX_VIDEO_CodingAVC; 267 } else if (mInfo->mMimeType.EqualsLiteral("video/mp4v-es") || 268 mInfo->mMimeType.EqualsLiteral("video/mp4")) { 269 return OMX_VIDEO_CodingMPEG4; 270 } else if (mInfo->mMimeType.EqualsLiteral("video/3gpp")) { 271 return OMX_VIDEO_CodingH263; 272 } else if (VPXDecoder::IsVP8(mInfo->mMimeType)) { 273 return static_cast<OMX_VIDEO_CODINGTYPE>(OMX_VIDEO_CodingVP8); 274 } else { 275 MOZ_ASSERT_UNREACHABLE("Unsupported compression format"); 276 return OMX_VIDEO_CodingUnused; 277 } 278 } 279 280 // Implementations for different platforms will be defined in their own files. 281 #if defined(MOZ_OMX) 282 283 bool OmxPlatformLayer::SupportsMimeType(const nsACString& aMimeType) { 284 return PureOmxPlatformLayer::SupportsMimeType(aMimeType); 285 } 286 287 OmxPlatformLayer* OmxPlatformLayer::Create( 288 OmxDataDecoder* aDataDecoder, OmxPromiseLayer* aPromiseLayer, 289 TaskQueue* aTaskQueue, layers::ImageContainer* aImageContainer) { 290 return new PureOmxPlatformLayer(aDataDecoder, aPromiseLayer, aTaskQueue, 291 aImageContainer); 292 } 293 294 #else // For platforms without OMX IL support. 295 296 bool OmxPlatformLayer::SupportsMimeType(const nsACString& aMimeType) { 297 return false; 298 } 299 300 OmxPlatformLayer* OmxPlatformLayer::Create( 301 OmxDataDecoder* aDataDecoder, OmxPromiseLayer* aPromiseLayer, 302 TaskQueue* aTaskQueue, layers::ImageContainer* aImageContainer) { 303 return nullptr; 304 } 305 306 #endif 307 } // namespace mozilla