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