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