1 /*
2 * Copyright (C) 2011 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 #include <utils/Log.h>
19 #include <utils/misc.h>
20 //#include "OMX_VideoExt.h"
21
22 #define DEBUG 0
23 #if DEBUG
24 #define DDD(...) ALOGD(__VA_ARGS__)
25 #else
26 #define DDD(...) ((void)0)
27 #endif
28
29 #include "GoldfishVPX.h"
30
31 #include <media/stagefright/foundation/ADebug.h>
32 #include <media/stagefright/MediaDefs.h>
33
34 #include <OMX_VideoExt.h>
35 #include <inttypes.h>
36
37 #include <nativebase/nativebase.h>
38
39 #include <android/hardware/graphics/allocator/3.0/IAllocator.h>
40 #include <android/hardware/graphics/mapper/3.0/IMapper.h>
41 #include <hidl/LegacySupport.h>
42
43 using ::android::hardware::graphics::common::V1_0::BufferUsage;
44 using ::android::hardware::graphics::common::V1_2::PixelFormat;
45
46 namespace android {
47
48 // Only need to declare the highest supported profile and level here.
49 static const CodecProfileLevel kVP9ProfileLevels[] = {
50 { OMX_VIDEO_VP9Profile0, OMX_VIDEO_VP9Level5 },
51 { OMX_VIDEO_VP9Profile2, OMX_VIDEO_VP9Level5 },
52 { OMX_VIDEO_VP9Profile2HDR, OMX_VIDEO_VP9Level5 },
53 { OMX_VIDEO_VP9Profile2HDR10Plus, OMX_VIDEO_VP9Level5 },
54 };
55
GoldfishVPX(const char * name,const char * componentRole,OMX_VIDEO_CODINGTYPE codingType,const OMX_CALLBACKTYPE * callbacks,OMX_PTR appData,OMX_COMPONENTTYPE ** component,RenderMode renderMode)56 GoldfishVPX::GoldfishVPX(const char* name,
57 const char* componentRole,
58 OMX_VIDEO_CODINGTYPE codingType,
59 const OMX_CALLBACKTYPE* callbacks,
60 OMX_PTR appData,
61 OMX_COMPONENTTYPE** component,
62 RenderMode renderMode)
63 : GoldfishVideoDecoderOMXComponent(
64 name,
65 componentRole,
66 codingType,
67 codingType == OMX_VIDEO_CodingVP8 ? NULL : kVP9ProfileLevels,
68 codingType == OMX_VIDEO_CodingVP8 ? 0 : NELEM(kVP9ProfileLevels),
69 320 /* width */,
70 240 /* height */,
71 callbacks,
72 appData,
73 component),
74 mMode(codingType == OMX_VIDEO_CodingVP8 ? MODE_VP8 : MODE_VP9),
75 mRenderMode(renderMode),
76 mEOSStatus(INPUT_DATA_AVAILABLE),
77 mCtx(NULL),
78 mFrameParallelMode(true),
79 mTimeStampIdx(0),
80 mImg(NULL) {
81 // arbitrary from avc/hevc as vpx does not specify a min compression ratio
82 const size_t kMinCompressionRatio = mMode == MODE_VP8 ? 2 : 4;
83 const char* mime = mMode == MODE_VP8 ? MEDIA_MIMETYPE_VIDEO_VP8
84 : MEDIA_MIMETYPE_VIDEO_VP9;
85 const size_t kMaxOutputBufferSize = 3840 * 2160 * 3 / 2; // 4k
86 initPorts(kNumBuffers,
87 kMaxOutputBufferSize / kMinCompressionRatio /* inputBufferSize */,
88 kNumBuffers, mime, kMinCompressionRatio);
89 ALOGI("calling constructor of GoldfishVPX");
90 // wait till later
91 // CHECK_EQ(initDecoder(), (status_t)OK);
92 }
93
~GoldfishVPX()94 GoldfishVPX::~GoldfishVPX() {
95 ALOGI("calling destructor of GoldfishVPX");
96 destroyDecoder();
97 }
98
supportDescribeHdrStaticInfo()99 bool GoldfishVPX::supportDescribeHdrStaticInfo() {
100 return true;
101 }
102
supportDescribeHdr10PlusInfo()103 bool GoldfishVPX::supportDescribeHdr10PlusInfo() {
104 return true;
105 }
106
initDecoder()107 status_t GoldfishVPX::initDecoder() {
108 mCtx = new vpx_codec_ctx_t;
109 mCtx->vpversion = mMode == MODE_VP8 ? 8 : 9;
110
111 mCtx->version = mEnableAndroidNativeBuffers ? 200 : 100;
112
113 int vpx_err = 0;
114 if ((vpx_err = vpx_codec_dec_init(mCtx))) {
115 ALOGE("vpx decoder failed to initialize. (%d)", vpx_err);
116 delete mCtx;
117 mCtx = NULL;
118 return UNKNOWN_ERROR;
119 }
120
121 ALOGI("calling init GoldfishVPX ctx %p", mCtx);
122 return OK;
123 }
124
destroyDecoder()125 status_t GoldfishVPX::destroyDecoder() {
126 if (mCtx) {
127 ALOGI("calling destroying GoldfishVPX ctx %p", mCtx);
128 vpx_codec_destroy(mCtx);
129 delete mCtx;
130 mCtx = NULL;
131 }
132 return OK;
133 }
134
setup_ctx_parameters(vpx_codec_ctx_t * ctx,int hostColorBufferId)135 void GoldfishVPX::setup_ctx_parameters(vpx_codec_ctx_t* ctx,
136 int hostColorBufferId) {
137 ctx->width = mWidth;
138 ctx->height = mHeight;
139 ctx->hostColorBufferId = hostColorBufferId;
140 ctx->outputBufferWidth = outputBufferWidth();
141 ctx->outputBufferHeight = outputBufferHeight();
142 OMX_PARAM_PORTDEFINITIONTYPE *outDef = &editPortInfo(kOutputPortIndex)->mDef;
143 int32_t bpp = (outDef->format.video.eColorFormat == OMX_COLOR_FormatYUV420Planar16) ? 2 : 1;
144 ctx->bpp = bpp;
145 }
146
outputBuffers(bool flushDecoder,bool display,bool eos,bool * portWillReset)147 bool GoldfishVPX::outputBuffers(bool flushDecoder, bool display, bool eos, bool *portWillReset) {
148 List<BufferInfo *> &outQueue = getPortQueue(1);
149 BufferInfo *outInfo = NULL;
150 OMX_BUFFERHEADERTYPE *outHeader = NULL;
151 DDD("%s %d", __func__, __LINE__);
152
153 if (flushDecoder && mFrameParallelMode) {
154 // Flush decoder by passing NULL data ptr and 0 size.
155 // Ideally, this should never fail.
156 if (vpx_codec_flush(mCtx)) {
157 ALOGE("Failed to flush on2 decoder.");
158 return false;
159 }
160 }
161
162 if (!display) {
163 if (!flushDecoder) {
164 ALOGE("Invalid operation.");
165 return false;
166 }
167 // Drop all the decoded frames in decoder.
168 // TODO: move this to host, with something like
169 // vpx_codec_drop_all_frames(mCtx);
170 setup_ctx_parameters(mCtx);
171 while ((mImg = vpx_codec_get_frame(mCtx))) {
172 }
173 return true;
174 }
175
176 while (!outQueue.empty()) {
177 DDD("%s %d", __func__, __LINE__);
178 outInfo = *outQueue.begin();
179 outHeader = outInfo->mHeader;
180 if (mImg == NULL) {
181 setup_ctx_parameters(mCtx, getHostColorBufferId(outHeader));
182 mImg = vpx_codec_get_frame(mCtx);
183 if (mImg == NULL) {
184 break;
185 }
186 }
187 uint32_t width = mImg->d_w;
188 uint32_t height = mImg->d_h;
189 CHECK(mImg->fmt == VPX_IMG_FMT_I420 || mImg->fmt == VPX_IMG_FMT_I42016);
190 OMX_COLOR_FORMATTYPE outputColorFormat = OMX_COLOR_FormatYUV420Planar;
191 int32_t bpp = 1;
192 if (mImg->fmt == VPX_IMG_FMT_I42016) {
193 outputColorFormat = OMX_COLOR_FormatYUV420Planar16;
194 bpp = 2;
195 }
196 handlePortSettingsChange(portWillReset, width, height, outputColorFormat);
197 if (*portWillReset) {
198 return true;
199 }
200
201 outHeader->nOffset = 0;
202 outHeader->nFlags = 0;
203 outHeader->nFilledLen = (outputBufferWidth() * outputBufferHeight() * bpp * 3) / 2;
204 PrivInfo *privInfo = (PrivInfo *)mImg->user_priv;
205 outHeader->nTimeStamp = privInfo->mTimeStamp;
206 if (privInfo->mHdr10PlusInfo != nullptr) {
207 queueOutputFrameConfig(privInfo->mHdr10PlusInfo);
208 }
209
210 if (outputBufferSafe(outHeader) &&
211 getHostColorBufferId(outHeader) < 0) {
212 uint8_t *dst = outHeader->pBuffer;
213 memcpy(dst, mCtx->dst, outHeader->nFilledLen);
214 } else {
215 // outHeader->nFilledLen = 0;
216 }
217
218 mImg = NULL;
219 outInfo->mOwnedByUs = false;
220 outQueue.erase(outQueue.begin());
221 outInfo = NULL;
222 notifyFillBufferDone(outHeader);
223 outHeader = NULL;
224 }
225
226 if (!eos) {
227 return true;
228 }
229
230 if (!outQueue.empty()) {
231 outInfo = *outQueue.begin();
232 outQueue.erase(outQueue.begin());
233 outHeader = outInfo->mHeader;
234 outHeader->nTimeStamp = 0;
235 outHeader->nFilledLen = 0;
236 outHeader->nFlags = OMX_BUFFERFLAG_EOS;
237 outInfo->mOwnedByUs = false;
238 notifyFillBufferDone(outHeader);
239 mEOSStatus = OUTPUT_FRAMES_FLUSHED;
240 }
241 return true;
242 }
243
outputBufferSafe(OMX_BUFFERHEADERTYPE * outHeader)244 bool GoldfishVPX::outputBufferSafe(OMX_BUFFERHEADERTYPE *outHeader) {
245 DDD("%s %d", __func__, __LINE__);
246 uint32_t width = outputBufferWidth();
247 uint32_t height = outputBufferHeight();
248 uint64_t nFilledLen = width;
249 nFilledLen *= height;
250 if (nFilledLen > UINT32_MAX / 3) {
251 ALOGE("b/29421675, nFilledLen overflow %llu w %u h %u",
252 (unsigned long long)nFilledLen, width, height);
253 android_errorWriteLog(0x534e4554, "29421675");
254 return false;
255 } else if (outHeader->nAllocLen < outHeader->nFilledLen) {
256 ALOGE("b/27597103, buffer too small");
257 android_errorWriteLog(0x534e4554, "27597103");
258 return false;
259 }
260
261 return true;
262 }
263
onQueueFilled(OMX_U32)264 void GoldfishVPX::onQueueFilled(OMX_U32 /* portIndex */) {
265 DDD("%s %d", __func__, __LINE__);
266 if (mOutputPortSettingsChange != NONE || mEOSStatus == OUTPUT_FRAMES_FLUSHED) {
267 return;
268 }
269
270 if (mCtx == nullptr) {
271 if (OK != initDecoder()) {
272 ALOGE("Failed to initialize decoder");
273 notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL);
274 return;
275 }
276 }
277
278 List<BufferInfo *> &inQueue = getPortQueue(0);
279 List<BufferInfo *> &outQueue = getPortQueue(1);
280 bool EOSseen = false;
281 bool portWillReset = false;
282
283 while ((mEOSStatus == INPUT_EOS_SEEN || !inQueue.empty())
284 && !outQueue.empty()) {
285 // Output the pending frames that left from last port reset or decoder flush.
286 if (mEOSStatus == INPUT_EOS_SEEN || mImg != NULL) {
287 if (!outputBuffers(
288 mEOSStatus == INPUT_EOS_SEEN, true /* display */,
289 mEOSStatus == INPUT_EOS_SEEN, &portWillReset)) {
290 ALOGE("on2 decoder failed to output frame.");
291 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
292 return;
293 }
294 if (portWillReset || mEOSStatus == OUTPUT_FRAMES_FLUSHED ||
295 mEOSStatus == INPUT_EOS_SEEN) {
296 return;
297 }
298 // Continue as outQueue may be empty now.
299 continue;
300 }
301
302 BufferInfo *inInfo = *inQueue.begin();
303 OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
304
305 // Software VP9 Decoder does not need the Codec Specific Data (CSD)
306 // (specified in http://www.webmproject.org/vp9/profiles/). Ignore it if
307 // it was passed.
308 if (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
309 // Only ignore CSD buffer for VP9.
310 if (mMode == MODE_VP9) {
311 inQueue.erase(inQueue.begin());
312 inInfo->mOwnedByUs = false;
313 notifyEmptyBufferDone(inHeader);
314 continue;
315 } else {
316 // Tolerate the CSD buffer for VP8. This is a workaround
317 // for b/28689536.
318 ALOGW("WARNING: Got CSD buffer for VP8.");
319 }
320 }
321
322 mPrivInfo[mTimeStampIdx].mTimeStamp = inHeader->nTimeStamp;
323
324 if (inInfo->mFrameConfig) {
325 mPrivInfo[mTimeStampIdx].mHdr10PlusInfo = dequeueInputFrameConfig();
326 } else {
327 mPrivInfo[mTimeStampIdx].mHdr10PlusInfo.clear();
328 }
329
330 if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
331 mEOSStatus = INPUT_EOS_SEEN;
332 EOSseen = true;
333 }
334
335 if (inHeader->nFilledLen > 0) {
336 int err = vpx_codec_decode(mCtx, inHeader->pBuffer + inHeader->nOffset,
337 inHeader->nFilledLen, &mPrivInfo[mTimeStampIdx], 0);
338 if (err == VPX_CODEC_OK) {
339 inInfo->mOwnedByUs = false;
340 inQueue.erase(inQueue.begin());
341 inInfo = NULL;
342 notifyEmptyBufferDone(inHeader);
343 inHeader = NULL;
344 } else {
345 ALOGE("on2 decoder failed to decode frame. err: %d", err);
346 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
347 return;
348 }
349 }
350
351 mTimeStampIdx = (mTimeStampIdx + 1) % kNumBuffers;
352
353 if (!outputBuffers(
354 EOSseen /* flushDecoder */, true /* display */, EOSseen, &portWillReset)) {
355 ALOGE("on2 decoder failed to output frame.");
356 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
357 return;
358 }
359 if (portWillReset) {
360 return;
361 }
362 }
363 }
364
onPortFlushCompleted(OMX_U32 portIndex)365 void GoldfishVPX::onPortFlushCompleted(OMX_U32 portIndex) {
366 DDD("%s %d", __func__, __LINE__);
367 if (portIndex == kInputPortIndex) {
368 bool portWillReset = false;
369 if (!outputBuffers(
370 true /* flushDecoder */, false /* display */, false /* eos */, &portWillReset)) {
371 ALOGE("Failed to flush decoder.");
372 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
373 return;
374 }
375 mEOSStatus = INPUT_DATA_AVAILABLE;
376 }
377 }
378
onReset()379 void GoldfishVPX::onReset() {
380 DDD("%s %d", __func__, __LINE__);
381 bool portWillReset = false;
382 if (!outputBuffers(
383 true /* flushDecoder */, false /* display */, false /* eos */, &portWillReset)) {
384 ALOGW("Failed to flush decoder. Try to hard reset decoder");
385 destroyDecoder();
386 initDecoder();
387 }
388 mEOSStatus = INPUT_DATA_AVAILABLE;
389 }
390
getHostColorBufferId(void * header)391 int GoldfishVPX::getHostColorBufferId(void* header) {
392 DDD("%s %d", __func__, __LINE__);
393 if (mNWBuffers.find(header) == mNWBuffers.end()) {
394 DDD("cannot find color buffer for header %p", header);
395 return -1;
396 }
397 sp<ANativeWindowBuffer> nBuf = mNWBuffers[header];
398 cb_handle_t* handle = (cb_handle_t*)nBuf->handle;
399 DDD("found color buffer for header %p --> %d", header, handle->hostHandle);
400 return handle->hostHandle;
401 }
402
internalGetParameter(OMX_INDEXTYPE index,OMX_PTR params)403 OMX_ERRORTYPE GoldfishVPX::internalGetParameter(OMX_INDEXTYPE index,
404 OMX_PTR params) {
405 const int32_t indexFull = index;
406 switch (indexFull) {
407 case kGetAndroidNativeBufferUsageIndex: {
408 DDD("calling kGetAndroidNativeBufferUsageIndex");
409 GetAndroidNativeBufferUsageParams* nativeBuffersUsage =
410 (GetAndroidNativeBufferUsageParams*)params;
411 nativeBuffersUsage->nUsage =
412 (unsigned int)(BufferUsage::GPU_DATA_BUFFER);
413 return OMX_ErrorNone;
414 }
415
416 default:
417 return GoldfishVideoDecoderOMXComponent::internalGetParameter(
418 index, params);
419 }
420 }
421
internalSetParameter(OMX_INDEXTYPE index,const OMX_PTR params)422 OMX_ERRORTYPE GoldfishVPX::internalSetParameter(OMX_INDEXTYPE index,
423 const OMX_PTR params) {
424 // Include extension index OMX_INDEXEXTTYPE.
425 const int32_t indexFull = index;
426
427 switch (indexFull) {
428 case kEnableAndroidNativeBuffersIndex: {
429 DDD("calling kEnableAndroidNativeBuffersIndex");
430 EnableAndroidNativeBuffersParams* enableNativeBuffers =
431 (EnableAndroidNativeBuffersParams*)params;
432 if (enableNativeBuffers) {
433 mEnableAndroidNativeBuffers = enableNativeBuffers->enable;
434 if (mEnableAndroidNativeBuffers == false) {
435 mNWBuffers.clear();
436 DDD("disabled kEnableAndroidNativeBuffersIndex");
437 } else {
438 DDD("enabled kEnableAndroidNativeBuffersIndex");
439 }
440 }
441 return OMX_ErrorNone;
442 }
443
444 case kUseAndroidNativeBufferIndex: {
445 if (mEnableAndroidNativeBuffers == false) {
446 ALOGE("Error: not enabled Android Native Buffers");
447 return OMX_ErrorBadParameter;
448 }
449 UseAndroidNativeBufferParams* use_buffer_params =
450 (UseAndroidNativeBufferParams*)params;
451 if (use_buffer_params) {
452 sp<ANativeWindowBuffer> nBuf = use_buffer_params->nativeBuffer;
453 cb_handle_t* handle = (cb_handle_t*)nBuf->handle;
454 void* dst = NULL;
455 DDD("kUseAndroidNativeBufferIndex with handle %p host color "
456 "handle %d "
457 "calling usebuffer",
458 handle, handle->hostHandle);
459 useBufferCallerLockedAlready(use_buffer_params->bufferHeader,
460 use_buffer_params->nPortIndex,
461 use_buffer_params->pAppPrivate,
462 handle->allocatedSize(),
463 (OMX_U8*)dst);
464 mNWBuffers[*(use_buffer_params->bufferHeader)] =
465 use_buffer_params->nativeBuffer;
466 ;
467 }
468 return OMX_ErrorNone;
469 }
470
471 default:
472 return GoldfishVideoDecoderOMXComponent::internalSetParameter(
473 index, params);
474 }
475 }
476
getExtensionIndex(const char * name,OMX_INDEXTYPE * index)477 OMX_ERRORTYPE GoldfishVPX::getExtensionIndex(const char* name,
478 OMX_INDEXTYPE* index) {
479 if (mRenderMode == RenderMode::RENDER_BY_HOST_GPU) {
480 if (!strcmp(name,
481 "OMX.google.android.index.enableAndroidNativeBuffers")) {
482 DDD("calling getExtensionIndex for enable ANB");
483 *(int32_t*)index = kEnableAndroidNativeBuffersIndex;
484 return OMX_ErrorNone;
485 } else if (!strcmp(name,
486 "OMX.google.android.index.useAndroidNativeBuffer")) {
487 *(int32_t*)index = kUseAndroidNativeBufferIndex;
488 return OMX_ErrorNone;
489 } else if (!strcmp(name,
490 "OMX.google.android.index."
491 "getAndroidNativeBufferUsage")) {
492 *(int32_t*)index = kGetAndroidNativeBufferUsageIndex;
493 return OMX_ErrorNone;
494 }
495 }
496 return GoldfishVideoDecoderOMXComponent::getExtensionIndex(name, index);
497 }
498
499 } // namespace android
500
createGoldfishOMXComponent(const char * name,const OMX_CALLBACKTYPE * callbacks,OMX_PTR appData,OMX_COMPONENTTYPE ** component)501 android::GoldfishOMXComponent *createGoldfishOMXComponent(
502 const char *name, const OMX_CALLBACKTYPE *callbacks,
503 OMX_PTR appData, OMX_COMPONENTTYPE **component) {
504 DDD("%s %d", __func__, __LINE__);
505 // only support vp9 to use host hardware decoder, for now
506 if (!strncmp("OMX.android.goldfish.vp9.decoder", name, 32)) {
507 return new android::GoldfishVPX(
508 name, "video_decoder.vp9", OMX_VIDEO_CodingVP9, callbacks,
509 appData, component, RenderMode::RENDER_BY_HOST_GPU);
510 }
511 if (!strncmp("OMX.android.goldfish.vp8.decoder", name, 32)) {
512 return new android::GoldfishVPX(
513 name, "video_decoder.vp8", OMX_VIDEO_CodingVP8, callbacks,
514 appData, component, RenderMode::RENDER_BY_HOST_GPU);
515 }
516 if (!strncmp("OMX.google.goldfish.vp9.decoder", name, 30)) {
517 return new android::GoldfishVPX(
518 name, "video_decoder.vp9", OMX_VIDEO_CodingVP9, callbacks,
519 appData, component, RenderMode::RENDER_BY_GUEST_CPU);
520 }
521 if (!strncmp("OMX.google.goldfish.vp8.decoder", name, 30)) {
522 return new android::GoldfishVPX(
523 name, "video_decoder.vp8", OMX_VIDEO_CodingVP8, callbacks,
524 appData, component, RenderMode::RENDER_BY_GUEST_CPU);
525 }
526 { CHECK(!"Unknown component"); }
527 return NULL;
528 }
529