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