1 /*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "OMXUtils"
19
20 #include <string.h>
21
22 #include <media/hardware/HardwareAPI.h>
23 #include <media/stagefright/foundation/ADebug.h>
24 #include <media/stagefright/foundation/AUtils.h>
25 #include <media/stagefright/MediaErrors.h>
26 #include <media/MediaDefs.h>
27 #include "OMXUtils.h"
28
29 namespace android {
30
StatusFromOMXError(OMX_ERRORTYPE err)31 status_t StatusFromOMXError(OMX_ERRORTYPE err) {
32 switch (err) {
33 case OMX_ErrorNone:
34 return OK;
35 case OMX_ErrorNoMore:
36 return NOT_ENOUGH_DATA;
37 case OMX_ErrorUnsupportedSetting:
38 case OMX_ErrorUnsupportedIndex:
39 return ERROR_UNSUPPORTED; // this is a media specific error
40 case OMX_ErrorBadParameter:
41 return BAD_VALUE;
42 case OMX_ErrorInsufficientResources:
43 return NO_MEMORY;
44 case OMX_ErrorInvalidComponentName:
45 case OMX_ErrorComponentNotFound:
46 return NAME_NOT_FOUND;
47 default:
48 return UNKNOWN_ERROR;
49 }
50 }
51
52 /**************************************************************************************************/
53
DescribeColorFormatParams(const DescribeColorFormat2Params & params)54 DescribeColorFormatParams::DescribeColorFormatParams(const DescribeColorFormat2Params ¶ms) {
55 InitOMXParams(this);
56
57 eColorFormat = params.eColorFormat;
58 nFrameWidth = params.nFrameWidth;
59 nFrameHeight = params.nFrameHeight;
60 nStride = params.nStride;
61 nSliceHeight = params.nSliceHeight;
62 bUsingNativeBuffers = params.bUsingNativeBuffers;
63 // we don't copy media images as this conversion is only used pre-query
64 };
65
initFromV1(const DescribeColorFormatParams & params)66 void DescribeColorFormat2Params::initFromV1(const DescribeColorFormatParams ¶ms) {
67 InitOMXParams(this);
68
69 eColorFormat = params.eColorFormat;
70 nFrameWidth = params.nFrameWidth;
71 nFrameHeight = params.nFrameHeight;
72 nStride = params.nStride;
73 nSliceHeight = params.nSliceHeight;
74 bUsingNativeBuffers = params.bUsingNativeBuffers;
75 sMediaImage.initFromV1(params.sMediaImage);
76 };
77
initFromV1(const MediaImage & image)78 void MediaImage2::initFromV1(const MediaImage &image) {
79 memset(this, 0, sizeof(*this));
80
81 if (image.mType != MediaImage::MEDIA_IMAGE_TYPE_YUV) {
82 mType = MediaImage2::MEDIA_IMAGE_TYPE_UNKNOWN;
83 return;
84 }
85
86 for (size_t ix = 0; ix < image.mNumPlanes; ++ix) {
87 if (image.mPlane[ix].mHorizSubsampling > INT32_MAX
88 || image.mPlane[ix].mVertSubsampling > INT32_MAX) {
89 mType = MediaImage2::MEDIA_IMAGE_TYPE_UNKNOWN;
90 return;
91 }
92 }
93
94 mType = (MediaImage2::Type)image.mType;
95 mNumPlanes = image.mNumPlanes;
96 mWidth = image.mWidth;
97 mHeight = image.mHeight;
98 mBitDepth = image.mBitDepth;
99 mBitDepthAllocated = 8;
100 for (size_t ix = 0; ix < image.mNumPlanes; ++ix) {
101 mPlane[ix].mOffset = image.mPlane[ix].mOffset;
102 mPlane[ix].mColInc = image.mPlane[ix].mColInc;
103 mPlane[ix].mRowInc = image.mPlane[ix].mRowInc;
104 mPlane[ix].mHorizSubsampling = (int32_t)image.mPlane[ix].mHorizSubsampling;
105 mPlane[ix].mVertSubsampling = (int32_t)image.mPlane[ix].mVertSubsampling;
106 }
107 }
108
109 /**************************************************************************************************/
110
GetComponentRole(bool isEncoder,const char * mime)111 const char *GetComponentRole(bool isEncoder, const char *mime) {
112 struct MimeToRole {
113 const char *mime;
114 const char *decoderRole;
115 const char *encoderRole;
116 };
117
118 static const MimeToRole kMimeToRole[] = {
119 { MEDIA_MIMETYPE_AUDIO_MPEG,
120 "audio_decoder.mp3", "audio_encoder.mp3" },
121 { MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I,
122 "audio_decoder.mp1", "audio_encoder.mp1" },
123 { MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II,
124 "audio_decoder.mp2", "audio_encoder.mp2" },
125 { MEDIA_MIMETYPE_AUDIO_AMR_NB,
126 "audio_decoder.amrnb", "audio_encoder.amrnb" },
127 { MEDIA_MIMETYPE_AUDIO_AMR_WB,
128 "audio_decoder.amrwb", "audio_encoder.amrwb" },
129 { MEDIA_MIMETYPE_AUDIO_AAC,
130 "audio_decoder.aac", "audio_encoder.aac" },
131 { MEDIA_MIMETYPE_AUDIO_VORBIS,
132 "audio_decoder.vorbis", "audio_encoder.vorbis" },
133 { MEDIA_MIMETYPE_AUDIO_OPUS,
134 "audio_decoder.opus", "audio_encoder.opus" },
135 { MEDIA_MIMETYPE_AUDIO_G711_MLAW,
136 "audio_decoder.g711mlaw", "audio_encoder.g711mlaw" },
137 { MEDIA_MIMETYPE_AUDIO_G711_ALAW,
138 "audio_decoder.g711alaw", "audio_encoder.g711alaw" },
139 { MEDIA_MIMETYPE_VIDEO_AVC,
140 "video_decoder.avc", "video_encoder.avc" },
141 { MEDIA_MIMETYPE_VIDEO_HEVC,
142 "video_decoder.hevc", "video_encoder.hevc" },
143 { MEDIA_MIMETYPE_VIDEO_MPEG4,
144 "video_decoder.mpeg4", "video_encoder.mpeg4" },
145 { MEDIA_MIMETYPE_VIDEO_H263,
146 "video_decoder.h263", "video_encoder.h263" },
147 { MEDIA_MIMETYPE_VIDEO_VP8,
148 "video_decoder.vp8", "video_encoder.vp8" },
149 { MEDIA_MIMETYPE_VIDEO_VP9,
150 "video_decoder.vp9", "video_encoder.vp9" },
151 { MEDIA_MIMETYPE_AUDIO_RAW,
152 "audio_decoder.raw", "audio_encoder.raw" },
153 { MEDIA_MIMETYPE_VIDEO_DOLBY_VISION,
154 "video_decoder.dolby-vision", "video_encoder.dolby-vision" },
155 { MEDIA_MIMETYPE_AUDIO_FLAC,
156 "audio_decoder.flac", "audio_encoder.flac" },
157 { MEDIA_MIMETYPE_AUDIO_MSGSM,
158 "audio_decoder.gsm", "audio_encoder.gsm" },
159 { MEDIA_MIMETYPE_VIDEO_MPEG2,
160 "video_decoder.mpeg2", "video_encoder.mpeg2" },
161 { MEDIA_MIMETYPE_AUDIO_AC3,
162 "audio_decoder.ac3", "audio_encoder.ac3" },
163 { MEDIA_MIMETYPE_AUDIO_EAC3,
164 "audio_decoder.eac3", "audio_encoder.eac3" },
165 };
166
167 static const size_t kNumMimeToRole =
168 sizeof(kMimeToRole) / sizeof(kMimeToRole[0]);
169
170 size_t i;
171 for (i = 0; i < kNumMimeToRole; ++i) {
172 if (!strcasecmp(mime, kMimeToRole[i].mime)) {
173 break;
174 }
175 }
176
177 if (i == kNumMimeToRole) {
178 return NULL;
179 }
180
181 return isEncoder ? kMimeToRole[i].encoderRole
182 : kMimeToRole[i].decoderRole;
183 }
184
SetComponentRole(const sp<IOMXNode> & omxNode,const char * role)185 status_t SetComponentRole(const sp<IOMXNode> &omxNode, const char *role) {
186 OMX_PARAM_COMPONENTROLETYPE roleParams;
187 InitOMXParams(&roleParams);
188
189 strncpy((char *)roleParams.cRole,
190 role, OMX_MAX_STRINGNAME_SIZE - 1);
191
192 roleParams.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
193
194 return omxNode->setParameter(
195 OMX_IndexParamStandardComponentRole,
196 &roleParams, sizeof(roleParams));
197 }
198
DescribeDefaultColorFormat(DescribeColorFormat2Params & params)199 bool DescribeDefaultColorFormat(DescribeColorFormat2Params ¶ms) {
200 MediaImage2 &image = params.sMediaImage;
201 memset(&image, 0, sizeof(image));
202
203 image.mType = MediaImage2::MEDIA_IMAGE_TYPE_UNKNOWN;
204 image.mNumPlanes = 0;
205
206 const OMX_COLOR_FORMATTYPE fmt = params.eColorFormat;
207 image.mWidth = params.nFrameWidth;
208 image.mHeight = params.nFrameHeight;
209
210 // only supporting YUV420
211 if (fmt != OMX_COLOR_FormatYUV420Planar &&
212 fmt != OMX_COLOR_FormatYUV420PackedPlanar &&
213 fmt != OMX_COLOR_FormatYUV420SemiPlanar &&
214 fmt != OMX_COLOR_FormatYUV420PackedSemiPlanar &&
215 fmt != (OMX_COLOR_FORMATTYPE)HAL_PIXEL_FORMAT_YV12) {
216 ALOGW("do not know color format 0x%x = %d", fmt, fmt);
217 return false;
218 }
219
220 // TEMPORARY FIX for some vendors that advertise sliceHeight as 0
221 if (params.nStride != 0 && params.nSliceHeight == 0) {
222 ALOGW("using sliceHeight=%u instead of what codec advertised (=0)",
223 params.nFrameHeight);
224 params.nSliceHeight = params.nFrameHeight;
225 }
226
227 // we need stride and slice-height to be non-zero and sensible. These values were chosen to
228 // prevent integer overflows further down the line, and do not indicate support for
229 // 32kx32k video.
230 if (params.nStride == 0 || params.nSliceHeight == 0
231 || params.nStride > 32768 || params.nSliceHeight > 32768) {
232 ALOGW("cannot describe color format 0x%x = %d with stride=%u and sliceHeight=%u",
233 fmt, fmt, params.nStride, params.nSliceHeight);
234 return false;
235 }
236
237 // set-up YUV format
238 image.mType = MediaImage2::MEDIA_IMAGE_TYPE_YUV;
239 image.mNumPlanes = 3;
240 image.mBitDepth = 8;
241 image.mBitDepthAllocated = 8;
242 image.mPlane[image.Y].mOffset = 0;
243 image.mPlane[image.Y].mColInc = 1;
244 image.mPlane[image.Y].mRowInc = params.nStride;
245 image.mPlane[image.Y].mHorizSubsampling = 1;
246 image.mPlane[image.Y].mVertSubsampling = 1;
247
248 switch ((int)fmt) {
249 case HAL_PIXEL_FORMAT_YV12:
250 if (params.bUsingNativeBuffers) {
251 size_t ystride = align(params.nStride, 16);
252 size_t cstride = align(params.nStride / 2, 16);
253 image.mPlane[image.Y].mRowInc = ystride;
254
255 image.mPlane[image.V].mOffset = ystride * params.nSliceHeight;
256 image.mPlane[image.V].mColInc = 1;
257 image.mPlane[image.V].mRowInc = cstride;
258 image.mPlane[image.V].mHorizSubsampling = 2;
259 image.mPlane[image.V].mVertSubsampling = 2;
260
261 image.mPlane[image.U].mOffset = image.mPlane[image.V].mOffset
262 + (cstride * params.nSliceHeight / 2);
263 image.mPlane[image.U].mColInc = 1;
264 image.mPlane[image.U].mRowInc = cstride;
265 image.mPlane[image.U].mHorizSubsampling = 2;
266 image.mPlane[image.U].mVertSubsampling = 2;
267 break;
268 } else {
269 // fall through as YV12 is used for YUV420Planar by some codecs
270 }
271
272 case OMX_COLOR_FormatYUV420Planar:
273 case OMX_COLOR_FormatYUV420PackedPlanar:
274 image.mPlane[image.U].mOffset = params.nStride * params.nSliceHeight;
275 image.mPlane[image.U].mColInc = 1;
276 image.mPlane[image.U].mRowInc = params.nStride / 2;
277 image.mPlane[image.U].mHorizSubsampling = 2;
278 image.mPlane[image.U].mVertSubsampling = 2;
279
280 image.mPlane[image.V].mOffset = image.mPlane[image.U].mOffset
281 + (params.nStride * params.nSliceHeight / 4);
282 image.mPlane[image.V].mColInc = 1;
283 image.mPlane[image.V].mRowInc = params.nStride / 2;
284 image.mPlane[image.V].mHorizSubsampling = 2;
285 image.mPlane[image.V].mVertSubsampling = 2;
286 break;
287
288 case OMX_COLOR_FormatYUV420SemiPlanar:
289 // FIXME: NV21 for sw-encoder, NV12 for decoder and hw-encoder
290 case OMX_COLOR_FormatYUV420PackedSemiPlanar:
291 // NV12
292 image.mPlane[image.U].mOffset = params.nStride * params.nSliceHeight;
293 image.mPlane[image.U].mColInc = 2;
294 image.mPlane[image.U].mRowInc = params.nStride;
295 image.mPlane[image.U].mHorizSubsampling = 2;
296 image.mPlane[image.U].mVertSubsampling = 2;
297
298 image.mPlane[image.V].mOffset = image.mPlane[image.U].mOffset + 1;
299 image.mPlane[image.V].mColInc = 2;
300 image.mPlane[image.V].mRowInc = params.nStride;
301 image.mPlane[image.V].mHorizSubsampling = 2;
302 image.mPlane[image.V].mVertSubsampling = 2;
303 break;
304
305 default:
306 TRESPASS();
307 }
308 return true;
309 }
310
DescribeColorFormat(const sp<IOMXNode> & omxNode,DescribeColorFormat2Params & describeParams)311 bool DescribeColorFormat(
312 const sp<IOMXNode> &omxNode,
313 DescribeColorFormat2Params &describeParams)
314 {
315 OMX_INDEXTYPE describeColorFormatIndex;
316 if (omxNode->getExtensionIndex(
317 "OMX.google.android.index.describeColorFormat",
318 &describeColorFormatIndex) == OK) {
319 DescribeColorFormatParams describeParamsV1(describeParams);
320 if (omxNode->getParameter(
321 describeColorFormatIndex,
322 &describeParamsV1, sizeof(describeParamsV1)) == OK) {
323 describeParams.initFromV1(describeParamsV1);
324 return describeParams.sMediaImage.mType != MediaImage2::MEDIA_IMAGE_TYPE_UNKNOWN;
325 }
326 } else if (omxNode->getExtensionIndex(
327 "OMX.google.android.index.describeColorFormat2", &describeColorFormatIndex) == OK
328 && omxNode->getParameter(
329 describeColorFormatIndex, &describeParams, sizeof(describeParams)) == OK) {
330 return describeParams.sMediaImage.mType != MediaImage2::MEDIA_IMAGE_TYPE_UNKNOWN;
331 }
332
333 return DescribeDefaultColorFormat(describeParams);
334 }
335
336 // static
IsFlexibleColorFormat(const sp<IOMXNode> & omxNode,uint32_t colorFormat,bool usingNativeBuffers,OMX_U32 * flexibleEquivalent)337 bool IsFlexibleColorFormat(
338 const sp<IOMXNode> &omxNode,
339 uint32_t colorFormat, bool usingNativeBuffers, OMX_U32 *flexibleEquivalent) {
340 DescribeColorFormat2Params describeParams;
341 InitOMXParams(&describeParams);
342 describeParams.eColorFormat = (OMX_COLOR_FORMATTYPE)colorFormat;
343 // reasonable dummy values
344 describeParams.nFrameWidth = 128;
345 describeParams.nFrameHeight = 128;
346 describeParams.nStride = 128;
347 describeParams.nSliceHeight = 128;
348 describeParams.bUsingNativeBuffers = (OMX_BOOL)usingNativeBuffers;
349
350 CHECK(flexibleEquivalent != NULL);
351
352 if (!DescribeColorFormat(omxNode, describeParams)) {
353 return false;
354 }
355
356 const MediaImage2 &img = describeParams.sMediaImage;
357 if (img.mType == MediaImage2::MEDIA_IMAGE_TYPE_YUV) {
358 if (img.mNumPlanes != 3
359 || img.mPlane[img.Y].mHorizSubsampling != 1
360 || img.mPlane[img.Y].mVertSubsampling != 1) {
361 return false;
362 }
363
364 // YUV 420
365 if (img.mPlane[img.U].mHorizSubsampling == 2
366 && img.mPlane[img.U].mVertSubsampling == 2
367 && img.mPlane[img.V].mHorizSubsampling == 2
368 && img.mPlane[img.V].mVertSubsampling == 2) {
369 // possible flexible YUV420 format
370 if (img.mBitDepth <= 8) {
371 *flexibleEquivalent = OMX_COLOR_FormatYUV420Flexible;
372 return true;
373 }
374 }
375 }
376 return false;
377 }
378
379 } // namespace android
380
381