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 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 56 DescribeColorFormatParams::DescribeColorFormatParams(const DescribeColorFormat2Params ¶ms) { 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 68 void DescribeColorFormat2Params::initFromV1(const DescribeColorFormatParams ¶ms) { 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 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 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 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 209 bool DescribeDefaultColorFormat(DescribeColorFormat2Params ¶ms) { 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 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 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 dummy values 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