1 /*
2 * Copyright 2015 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
20 #include "GoldfishAVCDec.h"
21
22 #include <media/stagefright/foundation/ADebug.h>
23 #include <media/stagefright/MediaDefs.h>
24 #include <OMX_VideoExt.h>
25 #include <inttypes.h>
26
27 #include <nativebase/nativebase.h>
28
29 #include <android/hardware/graphics/allocator/3.0/IAllocator.h>
30 #include <android/hardware/graphics/mapper/3.0/IMapper.h>
31 #include <hidl/LegacySupport.h>
32
33 using ::android::hardware::graphics::common::V1_2::PixelFormat;
34 using ::android::hardware::graphics::common::V1_0::BufferUsage;
35
36 namespace android {
37
38 #define componentName "video_decoder.avc"
39 #define codingType OMX_VIDEO_CodingAVC
40 #define CODEC_MIME_TYPE MEDIA_MIMETYPE_VIDEO_AVC
41
42 /** Function and structure definitions to keep code similar for each codec */
43 #define ivdec_api_function ih264d_api_function
44 #define ivdext_create_ip_t ih264d_create_ip_t
45 #define ivdext_create_op_t ih264d_create_op_t
46 #define ivdext_delete_ip_t ih264d_delete_ip_t
47 #define ivdext_delete_op_t ih264d_delete_op_t
48 #define ivdext_ctl_set_num_cores_ip_t ih264d_ctl_set_num_cores_ip_t
49 #define ivdext_ctl_set_num_cores_op_t ih264d_ctl_set_num_cores_op_t
50
51 #define IVDEXT_CMD_CTL_SET_NUM_CORES \
52 (IVD_CONTROL_API_COMMAND_TYPE_T)IH264D_CMD_CTL_SET_NUM_CORES
53
54 static const CodecProfileLevel kProfileLevels[] = {
55 { OMX_VIDEO_AVCProfileConstrainedBaseline, OMX_VIDEO_AVCLevel52 },
56
57 { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel52 },
58
59 { OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel52 },
60
61 { OMX_VIDEO_AVCProfileConstrainedHigh, OMX_VIDEO_AVCLevel52 },
62
63 { OMX_VIDEO_AVCProfileHigh, OMX_VIDEO_AVCLevel52 },
64 };
65
GoldfishAVCDec(const char * name,const OMX_CALLBACKTYPE * callbacks,OMX_PTR appData,OMX_COMPONENTTYPE ** component,RenderMode renderMode)66 GoldfishAVCDec::GoldfishAVCDec(
67 const char *name,
68 const OMX_CALLBACKTYPE *callbacks,
69 OMX_PTR appData,
70 OMX_COMPONENTTYPE **component, RenderMode renderMode)
71 : GoldfishVideoDecoderOMXComponent(
72 name, componentName, codingType,
73 kProfileLevels, ARRAY_SIZE(kProfileLevels),
74 320 /* width */, 240 /* height */, callbacks,
75 appData, component),
76 mOmxColorFormat(OMX_COLOR_FormatYUV420Planar),
77 mChangingResolution(false),
78 mSignalledError(false),
79 mInputOffset(0), mRenderMode(renderMode){
80 initPorts(
81 1 /* numMinInputBuffers */, kNumBuffers, INPUT_BUF_SIZE,
82 1 /* numMinOutputBuffers */, kNumBuffers, CODEC_MIME_TYPE);
83
84 mTimeStart = mTimeEnd = systemTime();
85
86 // If input dump is enabled, then open create an empty file
87 GENERATE_FILE_NAMES();
88 CREATE_DUMP_FILE(mInFile);
89 ALOGD("created %s %d object %p", __func__, __LINE__, this);
90 }
91
~GoldfishAVCDec()92 GoldfishAVCDec::~GoldfishAVCDec() {
93 CHECK_EQ(deInitDecoder(), (status_t)OK);
94 ALOGD("destroyed %s %d object %p", __func__, __LINE__, this);
95 }
96
logVersion()97 void GoldfishAVCDec::logVersion() {
98 // TODO: get emulation decoder implementation version from the host.
99 ALOGV("GoldfishAVC decoder version 1.0");
100 }
101
resetPlugin()102 status_t GoldfishAVCDec::resetPlugin() {
103 mIsInFlush = false;
104 mReceivedEOS = false;
105
106 /* Initialize both start and end times */
107 mTimeStart = mTimeEnd = systemTime();
108
109 return OK;
110 }
111
resetDecoder()112 status_t GoldfishAVCDec::resetDecoder() {
113 if (mContext) {
114 // The resolution may have changed, so our safest bet is to just destroy the
115 // current context and recreate another one, with the new width and height.
116 mContext->destroyH264Context();
117 mContext.reset(nullptr);
118
119 }
120 return OK;
121 }
122
setFlushMode()123 status_t GoldfishAVCDec::setFlushMode() {
124 /* Set the decoder in Flush mode, subsequent decode() calls will flush */
125 mIsInFlush = true;
126 mContext->flush();
127 return OK;
128 }
129
initDecoder()130 status_t GoldfishAVCDec::initDecoder() {
131 /* Initialize the decoder */
132 mContext.reset(new MediaH264Decoder(mRenderMode));
133 mContext->initH264Context(mWidth,
134 mHeight,
135 mWidth,
136 mHeight,
137 MediaH264Decoder::PixelFormat::YUV420P);
138
139 /* Reset the plugin state */
140 resetPlugin();
141
142 /* Get codec version */
143 logVersion();
144
145 return OK;
146 }
147
deInitDecoder()148 status_t GoldfishAVCDec::deInitDecoder() {
149 if (mContext) {
150 mContext->destroyH264Context();
151 mContext.reset();
152 }
153
154 mChangingResolution = false;
155
156 return OK;
157 }
158
onReset()159 void GoldfishAVCDec::onReset() {
160 GoldfishVideoDecoderOMXComponent::onReset();
161
162 mSignalledError = false;
163 mInputOffset = 0;
164 resetDecoder();
165 resetPlugin();
166 }
167
getVUIParams(h264_image_t & img)168 bool GoldfishAVCDec::getVUIParams(h264_image_t& img) {
169 int32_t primaries = img.color_primaries;
170 bool fullRange = img.color_range == 2 ? true : false;
171 int32_t transfer = img.color_trc;
172 int32_t coeffs = img.colorspace;
173
174 ColorAspects colorAspects;
175 ColorUtils::convertIsoColorAspectsToCodecAspects(
176 primaries, transfer, coeffs, fullRange, colorAspects);
177
178 ALOGD("img pts %lld, primaries %d, range %d transfer %d colorspace %d", (long long)img.pts,
179 (int)img.color_primaries, (int)img.color_range, (int)img.color_trc, (int)img.colorspace);
180
181 // Update color aspects if necessary.
182 if (colorAspectsDiffer(colorAspects, mBitstreamColorAspects)) {
183 mBitstreamColorAspects = colorAspects;
184 status_t err = handleColorAspectsChange();
185 CHECK(err == OK);
186 }
187 return true;
188 }
189
setDecodeArgs(OMX_BUFFERHEADERTYPE * inHeader,OMX_BUFFERHEADERTYPE * outHeader)190 bool GoldfishAVCDec::setDecodeArgs(
191 OMX_BUFFERHEADERTYPE *inHeader,
192 OMX_BUFFERHEADERTYPE *outHeader) {
193 size_t sizeY = outputBufferWidth() * outputBufferHeight();
194 size_t sizeUV = sizeY / 4;
195
196 /* When in flush and after EOS with zero byte input,
197 * inHeader is set to zero. Hence check for non-null */
198 if (inHeader) {
199 mConsumedBytes = inHeader->nFilledLen - mInputOffset;
200 mInPBuffer = inHeader->pBuffer + inHeader->nOffset + mInputOffset;
201 ALOGD("got input timestamp %lld in-addr-base %p real-data-offset %d inputoffset %d", (long long)(inHeader->nTimeStamp),
202 inHeader->pBuffer, (int)(inHeader->nOffset + mInputOffset), (int)mInputOffset);
203 } else {
204 mConsumedBytes = 0;
205 mInPBuffer = nullptr;
206 }
207
208 if (outHeader) {
209 if (outHeader->nAllocLen < sizeY + (sizeUV * 2)) {
210 ALOGE("outHeader->nAllocLen %d < needed size %d", outHeader->nAllocLen, (int)(sizeY + sizeUV * 2));
211 android_errorWriteLog(0x534e4554, "27833616");
212 return false;
213 }
214 mOutHeaderBuf = outHeader->pBuffer;
215 } else {
216 // We flush out on the host side
217 mOutHeaderBuf = nullptr;
218 }
219
220 return true;
221 }
222
readAndDiscardAllHostBuffers()223 void GoldfishAVCDec::readAndDiscardAllHostBuffers() {
224 while (mContext) {
225 h264_image_t img = mContext->getImage();
226 if (img.data != nullptr) {
227 ALOGD("img pts %lld is discarded", (long long)img.pts);
228 } else {
229 return;
230 }
231 }
232 }
233
onPortFlushCompleted(OMX_U32 portIndex)234 void GoldfishAVCDec::onPortFlushCompleted(OMX_U32 portIndex) {
235 /* Once the output buffers are flushed, ignore any buffers that are held in decoder */
236 if (kOutputPortIndex == portIndex) {
237 setFlushMode();
238 ALOGD("%s %d", __func__, __LINE__);
239 readAndDiscardAllHostBuffers();
240 mContext->resetH264Context(mWidth, mHeight, mWidth, mHeight, MediaH264Decoder::PixelFormat::YUV420P);
241 if (!mCsd0.empty() && !mCsd1.empty()) {
242 mContext->decodeFrame(&(mCsd0[0]), mCsd0.size(), 0);
243 mContext->getImage();
244 mContext->decodeFrame(&(mCsd1[0]), mCsd1.size(), 0);
245 mContext->getImage();
246 }
247 resetPlugin();
248 } else {
249 mInputOffset = 0;
250 }
251 }
252
copyImageData(OMX_BUFFERHEADERTYPE * outHeader,h264_image_t & img)253 void GoldfishAVCDec::copyImageData( OMX_BUFFERHEADERTYPE *outHeader, h264_image_t & img) {
254 int myStride = outputBufferWidth();
255 for (int i=0; i < mHeight; ++i) {
256 memcpy(outHeader->pBuffer + i * myStride, img.data + i * mWidth, mWidth);
257 }
258 int Y = myStride * outputBufferHeight();
259 for (int i=0; i < mHeight/2; ++i) {
260 memcpy(outHeader->pBuffer + Y + i * myStride / 2 , img.data + mWidth * mHeight + i * mWidth/2, mWidth/2);
261 }
262 int UV = Y/4;
263 for (int i=0; i < mHeight/2; ++i) {
264 memcpy(outHeader->pBuffer + Y + UV + i * myStride / 2 , img.data + mWidth * mHeight * 5/4 + i * mWidth/2, mWidth/2);
265 }
266 }
267
getHostColorBufferId(void * header)268 int GoldfishAVCDec::getHostColorBufferId(void* header) {
269 if (mNWBuffers.find(header) == mNWBuffers.end()) {
270 ALOGD("cannot find color buffer for header %p", header);
271 return -1;
272 }
273 sp<ANativeWindowBuffer> nBuf = mNWBuffers[header];
274 cb_handle_t *handle = (cb_handle_t*)nBuf->handle;
275 ALOGD("found color buffer for header %p --> %d", header, handle->hostHandle);
276 return handle->hostHandle;
277 }
278
onQueueFilled(OMX_U32 portIndex)279 void GoldfishAVCDec::onQueueFilled(OMX_U32 portIndex) {
280 static int count1=0;
281 ALOGD("calling %s count %d object %p", __func__, ++count1, this);
282 UNUSED(portIndex);
283 OMX_BUFFERHEADERTYPE *inHeader = NULL;
284 BufferInfo *inInfo = NULL;
285
286 if (mSignalledError) {
287 return;
288 }
289 if (mOutputPortSettingsChange != NONE) {
290 return;
291 }
292
293 if (mContext == nullptr) {
294 if (OK != initDecoder()) {
295 ALOGE("Failed to initialize decoder");
296 notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL);
297 mSignalledError = true;
298 return;
299 }
300 }
301
302 List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
303 List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
304
305 int count2=0;
306 while (!outQueue.empty()) {
307 ALOGD("calling %s in while loop count %d", __func__, ++count2);
308 BufferInfo *outInfo;
309 OMX_BUFFERHEADERTYPE *outHeader;
310
311 if (!mIsInFlush && (NULL == inHeader)) {
312 if (!inQueue.empty()) {
313 inInfo = *inQueue.begin();
314 inHeader = inInfo->mHeader;
315 if (inHeader == NULL) {
316 inQueue.erase(inQueue.begin());
317 inInfo->mOwnedByUs = false;
318 continue;
319 }
320 } else {
321 break;
322 }
323 }
324
325 outInfo = *outQueue.begin();
326 outHeader = outInfo->mHeader;
327 outHeader->nFlags = 0;
328 outHeader->nTimeStamp = 0;
329 outHeader->nOffset = 0;
330
331 if (inHeader != NULL) {
332 if (inHeader->nFilledLen == 0) {
333 // An empty buffer can be end of stream (EOS) buffer, so
334 // we'll set the decoder in flush mode if so. If it's not EOS,
335 // then just release the buffer.
336 inQueue.erase(inQueue.begin());
337 inInfo->mOwnedByUs = false;
338 notifyEmptyBufferDone(inHeader);
339
340 if (!(inHeader->nFlags & OMX_BUFFERFLAG_EOS)) {
341 return;
342 }
343
344 mReceivedEOS = true;
345 inHeader = NULL;
346 setFlushMode();
347 } else if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
348 mReceivedEOS = true;
349 }
350 }
351
352 {
353 nsecs_t timeDelay, timeTaken;
354
355 if (!setDecodeArgs(inHeader, outHeader)) {
356 ALOGE("Decoder arg setup failed");
357 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
358 mSignalledError = true;
359 return;
360 }
361
362 mTimeStart = systemTime();
363 /* Compute time elapsed between end of previous decode()
364 * to start of current decode() */
365 timeDelay = mTimeStart - mTimeEnd;
366
367 // TODO: We also need to send the timestamp
368 h264_result_t h264Res = {(int)MediaH264Decoder::Err::NoErr, 0};
369 if (inHeader != nullptr) {
370 if (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
371 unsigned long mysize = (inHeader->nFilledLen - mInputOffset);
372 uint8_t* mydata = mInPBuffer;
373 if (mCsd0.empty()) {
374 mCsd0.assign(mydata, mydata + mysize);
375 } else if (mCsd1.empty()) {
376 mCsd1.assign(mydata, mydata + mysize);
377 }
378 }
379 ALOGD("Decoding frame(sz=%lu)", (unsigned long)(inHeader->nFilledLen - mInputOffset));
380 h264Res = mContext->decodeFrame(mInPBuffer,
381 inHeader->nFilledLen - mInputOffset,
382 inHeader->nTimeStamp);
383 mConsumedBytes = h264Res.bytesProcessed;
384 if (h264Res.ret == (int)MediaH264Decoder::Err::DecoderRestarted) {
385 mChangingResolution = true;
386 }
387 } else {
388 ALOGD("No more input data. Attempting to get a decoded frame, if any.");
389 }
390 h264_image_t img = {};
391
392 bool readBackPixels = true;
393 if (mRenderMode == RenderMode::RENDER_BY_GUEST_CPU) {
394 img = mContext->getImage();
395 } else {
396 int hostColorBufferId = getHostColorBufferId(outHeader);
397 if (hostColorBufferId >= 0) {
398 img = mContext->renderOnHostAndReturnImageMetadata(getHostColorBufferId(outHeader));
399 readBackPixels = false;
400 } else {
401 img = mContext->getImage();
402 }
403 }
404
405
406 if (img.data != nullptr) {
407 getVUIParams(img);
408 }
409
410 mTimeEnd = systemTime();
411 /* Compute time taken for decode() */
412 timeTaken = mTimeEnd - mTimeStart;
413
414
415 if (inHeader) {
416 ALOGD("input time stamp %lld flag %d", inHeader->nTimeStamp, (int)(inHeader->nFlags));
417 }
418
419 // If the decoder is in the changing resolution mode and there is no output present,
420 // that means the switching is done and it's ready to reset the decoder and the plugin.
421 if (mChangingResolution && img.data == nullptr) {
422 mChangingResolution = false;
423 ALOGD("re-create decoder because resolution changed");
424 bool portWillReset = false;
425 handlePortSettingsChange(&portWillReset, img.width, img.height);
426 {
427 ALOGD("handling port reset");
428 ALOGD("port resetting (img.width=%u, img.height=%u, mWidth=%u, mHeight=%u)",
429 img.width, img.height, mWidth, mHeight);
430 //resetDecoder();
431 resetPlugin();
432
433 //mContext->destroyH264Context();
434 //mContext.reset(new MediaH264Decoder());
435 mContext->resetH264Context(mWidth,
436 mHeight,
437 mWidth,
438 mHeight,
439 MediaH264Decoder::PixelFormat::YUV420P);
440 //mInputOffset += mConsumedBytes;
441 return;
442 }
443 }
444
445 if (img.data != nullptr) {
446 int myWidth = img.width;
447 int myHeight = img.height;
448 if (myWidth != mWidth || myHeight != mHeight) {
449 bool portWillReset = false;
450 handlePortSettingsChange(&portWillReset, myWidth, myHeight);
451 resetPlugin();
452 mWidth = myWidth;
453 mHeight = myHeight;
454 if (portWillReset) {
455 ALOGD("port will reset return now");
456 return;
457 } else {
458 ALOGD("port will NOT reset keep going now");
459 }
460 }
461 outHeader->nFilledLen = (outputBufferWidth() * outputBufferHeight() * 3) / 2;
462 if (readBackPixels) {
463 if (outputBufferWidth() == mWidth && outputBufferHeight() == mHeight) {
464 memcpy(outHeader->pBuffer, img.data, outHeader->nFilledLen);
465 } else {
466 copyImageData(outHeader, img);
467 }
468 }
469
470 outHeader->nTimeStamp = img.pts;
471 ALOGD("got output timestamp %lld", (long long)(img.pts));
472
473 outInfo->mOwnedByUs = false;
474 outQueue.erase(outQueue.begin());
475 outInfo = NULL;
476 notifyFillBufferDone(outHeader);
477 outHeader = NULL;
478 } else if (mIsInFlush) {
479 ALOGD("not img.data and it is in flush mode");
480 /* If in flush mode and no output is returned by the codec,
481 * then come out of flush mode */
482 mIsInFlush = false;
483
484 /* If EOS was recieved on input port and there is no output
485 * from the codec, then signal EOS on output port */
486 if (mReceivedEOS) {
487 ALOGD("recived EOS, re-create host context");
488 outHeader->nFilledLen = 0;
489 outHeader->nFlags |= OMX_BUFFERFLAG_EOS;
490
491 outInfo->mOwnedByUs = false;
492 outQueue.erase(outQueue.begin());
493 outInfo = NULL;
494 notifyFillBufferDone(outHeader);
495 outHeader = NULL;
496 resetPlugin();
497
498 //mContext->destroyH264Context();
499 //mContext.reset(new MediaH264Decoder());
500 mContext->resetH264Context(mWidth,
501 mHeight,
502 mWidth,
503 mHeight,
504 MediaH264Decoder::PixelFormat::YUV420P);
505
506 }
507 }
508 mInputOffset += mConsumedBytes;
509 }
510
511 // If more than 4 bytes are remaining in input, then do not release it
512 if (inHeader != NULL && ((inHeader->nFilledLen - mInputOffset) <= 4)) {
513 inInfo->mOwnedByUs = false;
514 inQueue.erase(inQueue.begin());
515 inInfo = NULL;
516 notifyEmptyBufferDone(inHeader);
517 inHeader = NULL;
518 mInputOffset = 0;
519
520 /* If input EOS is seen and decoder is not in flush mode,
521 * set the decoder in flush mode.
522 * There can be a case where EOS is sent along with last picture data
523 * In that case, only after decoding that input data, decoder has to be
524 * put in flush. This case is handled here */
525
526 if (mReceivedEOS && !mIsInFlush) {
527 setFlushMode();
528 }
529 }
530 }
531 }
532
internalGetParameter(OMX_INDEXTYPE index,OMX_PTR params)533 OMX_ERRORTYPE GoldfishAVCDec::internalGetParameter(
534 OMX_INDEXTYPE index, OMX_PTR params) {
535 const int32_t indexFull = index;
536 switch (indexFull) {
537 case kGetAndroidNativeBufferUsageIndex:
538 {
539 ALOGD("calling kGetAndroidNativeBufferUsageIndex");
540 GetAndroidNativeBufferUsageParams* nativeBuffersUsage = (GetAndroidNativeBufferUsageParams *) params;
541 nativeBuffersUsage->nUsage = (unsigned int)(BufferUsage::GPU_DATA_BUFFER);
542 return OMX_ErrorNone;
543 }
544
545 default:
546 return GoldfishVideoDecoderOMXComponent::internalGetParameter(index, params);
547 }
548 }
549
internalSetParameter(OMX_INDEXTYPE index,const OMX_PTR params)550 OMX_ERRORTYPE GoldfishAVCDec::internalSetParameter(
551 OMX_INDEXTYPE index, const OMX_PTR params) {
552 // Include extension index OMX_INDEXEXTTYPE.
553 const int32_t indexFull = index;
554
555 switch (indexFull) {
556 case kEnableAndroidNativeBuffersIndex:
557 {
558 ALOGD("calling kEnableAndroidNativeBuffersIndex");
559 EnableAndroidNativeBuffersParams* enableNativeBuffers = (EnableAndroidNativeBuffersParams *) params;
560 if (enableNativeBuffers) {
561 mEnableAndroidNativeBuffers = enableNativeBuffers->enable;
562 if (mEnableAndroidNativeBuffers == false) {
563 mNWBuffers.clear();
564 ALOGD("disabled kEnableAndroidNativeBuffersIndex");
565 } else {
566 ALOGD("enabled kEnableAndroidNativeBuffersIndex");
567 }
568 }
569 return OMX_ErrorNone;
570 }
571
572 case kUseAndroidNativeBufferIndex:
573 {
574 if (mEnableAndroidNativeBuffers == false) {
575 ALOGE("Error: not enabled Android Native Buffers");
576 return OMX_ErrorBadParameter;
577 }
578 UseAndroidNativeBufferParams *use_buffer_params = (UseAndroidNativeBufferParams *)params;
579 if (use_buffer_params) {
580 sp<ANativeWindowBuffer> nBuf = use_buffer_params->nativeBuffer;
581 cb_handle_t *handle = (cb_handle_t*)nBuf->handle;
582 void* dst = NULL;
583 ALOGD("kUseAndroidNativeBufferIndex with handle %p host color handle %d calling usebuffer", handle,
584 handle->hostHandle);
585 useBufferCallerLockedAlready(use_buffer_params->bufferHeader,use_buffer_params->nPortIndex,
586 use_buffer_params->pAppPrivate,handle->allocatedSize(), (OMX_U8*)dst);
587 mNWBuffers[*(use_buffer_params->bufferHeader)] = use_buffer_params->nativeBuffer;;
588 }
589 return OMX_ErrorNone;
590 }
591
592 default:
593 return GoldfishVideoDecoderOMXComponent::internalSetParameter(index, params);
594 }
595 }
596
getExtensionIndex(const char * name,OMX_INDEXTYPE * index)597 OMX_ERRORTYPE GoldfishAVCDec::getExtensionIndex(
598 const char *name, OMX_INDEXTYPE *index) {
599
600 if (mRenderMode == RenderMode::RENDER_BY_HOST_GPU) {
601 if (!strcmp(name, "OMX.google.android.index.enableAndroidNativeBuffers")) {
602 ALOGD("calling getExtensionIndex for enable ANB");
603 *(int32_t*)index = kEnableAndroidNativeBuffersIndex;
604 return OMX_ErrorNone;
605 } else if (!strcmp(name, "OMX.google.android.index.useAndroidNativeBuffer")) {
606 *(int32_t*)index = kUseAndroidNativeBufferIndex;
607 return OMX_ErrorNone;
608 } else if (!strcmp(name, "OMX.google.android.index.getAndroidNativeBufferUsage")) {
609 *(int32_t*)index = kGetAndroidNativeBufferUsageIndex;
610 return OMX_ErrorNone;
611 }
612 }
613 return GoldfishVideoDecoderOMXComponent::getExtensionIndex(name, index);
614 }
615
getColorAspectPreference()616 int GoldfishAVCDec::getColorAspectPreference() {
617 return kPreferBitstream;
618 }
619
620 } // namespace android
621
createGoldfishOMXComponent(const char * name,const OMX_CALLBACKTYPE * callbacks,OMX_PTR appData,OMX_COMPONENTTYPE ** component)622 android::GoldfishOMXComponent *createGoldfishOMXComponent(
623 const char *name, const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData,
624 OMX_COMPONENTTYPE **component) {
625 if (!strncmp("OMX.android.goldfish", name, 20)) {
626 return new android::GoldfishAVCDec(name, callbacks, appData, component, RenderMode::RENDER_BY_HOST_GPU);
627 } else {
628 return new android::GoldfishAVCDec(name, callbacks, appData, component, RenderMode::RENDER_BY_GUEST_CPU);
629 }
630 }
631
632