• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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