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