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