1/*
2* Copyright (c) 2012 Intel Corporation.  All rights reserved.
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
18#define LOG_NDEBUG 0
19#define LOG_TAG "OMXVideoDecoderVP9HWR"
20#include <wrs_omxil_core/log.h>
21#include "OMXVideoDecoderVP9HWR.h"
22
23#include <system/window.h>
24#include <HardwareAPI.h>
25#include <hardware/hardware.h>
26#include <hardware/gralloc.h>
27#include <system/graphics.h>
28
29static const char* VP9_MIME_TYPE = "video/x-vnd.on2.vp9";
30
31static int GetCPUCoreCount()
32{
33    int cpuCoreCount = 1;
34#if defined(_SC_NPROCESSORS_ONLN)
35    cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
36#else
37    // _SC_NPROC_ONLN must be defined...
38    cpuCoreCount = sysconf(_SC_NPROC_ONLN);
39#endif
40    if (cpuCoreCount < 1) {
41        LOGW("Get CPU Core Count error.");
42        cpuCoreCount = 1;
43    }
44    LOGV("Number of CPU cores: %d", cpuCoreCount);
45    return cpuCoreCount;
46}
47
48
49OMXVideoDecoderVP9HWR::OMXVideoDecoderVP9HWR()
50{
51    LOGV("OMXVideoDecoderVP9HWR is constructed.");
52
53    mNumFrameBuffer = 0;
54    mCtx = NULL;
55
56    mNativeBufferCount = OUTPORT_NATIVE_BUFFER_COUNT;
57    extUtilBufferCount = 0;
58    extMappedNativeBufferCount = 0;
59    BuildHandlerList();
60
61    mDecodedImageWidth = 0;
62    mDecodedImageHeight = 0;
63    mDecodedImageNewWidth = 0;
64    mDecodedImageNewHeight = 0;
65
66#ifdef DECODE_WITH_GRALLOC_BUFFER
67    // setup va
68    VAStatus vaStatus = VA_STATUS_SUCCESS;
69    mDisplay = new Display;
70    *mDisplay = ANDROID_DISPLAY_HANDLE;
71
72    mVADisplay = vaGetDisplay(mDisplay);
73    if (mVADisplay == NULL) {
74        LOGE("vaGetDisplay failed.");
75    }
76
77    int majorVersion, minorVersion;
78    vaStatus = vaInitialize(mVADisplay, &majorVersion, &minorVersion);
79    if (vaStatus != VA_STATUS_SUCCESS) {
80        LOGE("vaInitialize failed.");
81    } else {
82        LOGV("va majorVersion=%d, minorVersion=%d", majorVersion, minorVersion);
83    }
84#endif
85}
86
87OMXVideoDecoderVP9HWR::~OMXVideoDecoderVP9HWR()
88{
89    LOGV("OMXVideoDecoderVP9HWR is destructed.");
90
91    unsigned int i = 0;
92
93    if (mVADisplay) {
94        vaTerminate(mVADisplay);
95        mVADisplay = NULL;
96    }
97}
98
99
100// Callback func for vpx decoder to get decode buffer
101// Now we map from the vaSurface to deploy gralloc buffer
102// as decode buffer
103int getVP9FrameBuffer(void *user_priv,
104                          unsigned int new_size,
105                          vpx_codec_frame_buffer_t *fb)
106{
107    OMXVideoDecoderVP9HWR * p = (OMXVideoDecoderVP9HWR *)user_priv;
108    if (fb == NULL) {
109        return -1;
110    }
111
112    // TODO: Adaptive playback case needs to reconsider
113    if (p->extNativeBufferSize < new_size) {
114        LOGE("Provided frame buffer size < requesting min size.");
115        return -1;
116    }
117
118    int i;
119    for (i = 0; i < p->extMappedNativeBufferCount; i++ ) {
120        if ((p->extMIDs[i]->m_render_done == true) &&
121            (p->extMIDs[i]->m_released == true)) {
122            fb->data = p->extMIDs[i]->m_usrAddr;
123            fb->size = p->extNativeBufferSize;
124            fb->fb_stride = p->extActualBufferStride;
125            fb->fb_height_stride = p->extActualBufferHeightStride;
126            fb->fb_index = i;
127            p->extMIDs[i]->m_released = false;
128            break;
129        }
130    }
131
132    if (i == p->extMappedNativeBufferCount) {
133        LOGE("No available frame buffer in pool.");
134        return -1;
135    }
136    return 0;
137}
138
139// call back function from libvpx to inform frame buffer
140// not used anymore.
141int releaseVP9FrameBuffer(void *user_priv, vpx_codec_frame_buffer_t *fb)
142{
143    int i;
144    OMXVideoDecoderVP9HWR * p = (OMXVideoDecoderVP9HWR *)user_priv;
145    if (fb == NULL) {
146        return -1;
147    }
148    for (i = 0; i < p->extMappedNativeBufferCount; i++ ) {
149        if (fb->data == p->extMIDs[i]->m_usrAddr) {
150            p->extMIDs[i]->m_released = true;
151            break;
152        }
153    }
154
155    if (i == p->extMappedNativeBufferCount) {
156        LOGE("Not found matching frame buffer in pool, libvpx's wrong?");
157        return -1;
158    }
159    return 0;
160}
161
162
163OMX_ERRORTYPE OMXVideoDecoderVP9HWR::initDecoder()
164{
165    mCtx = new vpx_codec_ctx_t;
166    vpx_codec_err_t vpx_err;
167    vpx_codec_dec_cfg_t cfg;
168    memset(&cfg, 0, sizeof(vpx_codec_dec_cfg_t));
169    cfg.threads = GetCPUCoreCount();
170    if ((vpx_err = vpx_codec_dec_init(
171                (vpx_codec_ctx_t *)mCtx,
172                 &vpx_codec_vp9_dx_algo,
173                 &cfg, 0))) {
174        LOGE("on2 decoder failed to initialize. (%d)", vpx_err);
175        return OMX_ErrorNotReady;
176    }
177
178    mNumFrameBuffer = OUTPORT_NATIVE_BUFFER_COUNT;
179
180    if (vpx_codec_set_frame_buffer_functions((vpx_codec_ctx_t *)mCtx,
181                                    getVP9FrameBuffer,
182                                    releaseVP9FrameBuffer,
183                                    this)) {
184      LOGE("Failed to configure external frame buffers");
185      return OMX_ErrorNotReady;
186    }
187
188    return OMX_ErrorNone;
189}
190
191OMX_ERRORTYPE OMXVideoDecoderVP9HWR::destroyDecoder()
192{
193    vpx_codec_destroy((vpx_codec_ctx_t *)mCtx);
194    delete (vpx_codec_ctx_t *)mCtx;
195    mCtx = NULL;
196    return OMX_ErrorNone;
197}
198
199
200OMX_ERRORTYPE OMXVideoDecoderVP9HWR::InitInputPortFormatSpecific(
201    OMX_PARAM_PORTDEFINITIONTYPE *paramPortDefinitionInput)
202{
203    paramPortDefinitionInput->nBufferCountActual = INPORT_ACTUAL_BUFFER_COUNT;
204    paramPortDefinitionInput->nBufferCountMin = INPORT_MIN_BUFFER_COUNT;
205    paramPortDefinitionInput->nBufferSize = INPORT_BUFFER_SIZE;
206    paramPortDefinitionInput->format.video.cMIMEType = (OMX_STRING)VP9_MIME_TYPE;
207    paramPortDefinitionInput->format.video.eCompressionFormat = OMX_VIDEO_CodingVP9;
208
209    return OMX_ErrorNone;
210}
211
212OMX_ERRORTYPE OMXVideoDecoderVP9HWR::ProcessorInit(void)
213{
214    unsigned int i = 0;
215
216    for (i = 0; i < MAX_NATIVE_BUFFER_COUNT; i++) {
217        extMIDs[i] = (vaapiMemId*)malloc(sizeof(vaapiMemId));
218        extMIDs[i]->m_usrAddr = NULL;
219        extMIDs[i]->m_surface = new VASurfaceID;
220    }
221
222    initDecoder();
223
224    if (RAWDATA_MODE == mWorkingMode) {
225        OMX_PARAM_PORTDEFINITIONTYPE paramPortDefinitionInput;
226
227        memcpy(&paramPortDefinitionInput,
228               this->ports[INPORT_INDEX]->GetPortDefinition(),
229               sizeof(paramPortDefinitionInput));
230
231        extNativeBufferSize = INTERNAL_MAX_FRAME_WIDTH *
232                              INTERNAL_MAX_FRAME_HEIGHT * 1.5;
233        extActualBufferStride = INTERNAL_MAX_FRAME_WIDTH;
234        extActualBufferHeightStride = INTERNAL_MAX_FRAME_HEIGHT;
235
236        for (i = 0; i < OUTPORT_ACTUAL_BUFFER_COUNT; i++ ) {
237            extMIDs[i]->m_usrAddr = (unsigned char*)malloc(sizeof(unsigned char) *
238                                    extNativeBufferSize);
239            extMIDs[i]->m_render_done = true;
240            extMIDs[i]->m_released = true;
241        }
242        extMappedNativeBufferCount = OUTPORT_ACTUAL_BUFFER_COUNT;
243        return OMX_ErrorNone;
244    }
245
246#ifdef DECODE_WITH_GRALLOC_BUFFER
247    if (mOMXBufferHeaderTypePtrNum > MAX_NATIVE_BUFFER_COUNT) {
248        LOGE("Actual OMX outport buffer header type num (%d) > MAX_NATIVE_BUFFER_COUNT (%d)",
249              mOMXBufferHeaderTypePtrNum, MAX_NATIVE_BUFFER_COUNT);
250        return OMX_ErrorOverflow;
251    }
252
253    OMX_PARAM_PORTDEFINITIONTYPE paramPortDefinitionInput;
254
255    memcpy(&paramPortDefinitionInput,
256        this->ports[INPORT_INDEX]->GetPortDefinition(),
257        sizeof(paramPortDefinitionInput));
258
259    int surfaceWidth = mGraphicBufferParam.graphicBufferWidth;
260    int surfaceHeight = mGraphicBufferParam.graphicBufferHeight;
261    int surfaceStride = mGraphicBufferParam.graphicBufferStride;
262    extNativeBufferSize = mGraphicBufferParam.graphicBufferStride *
263                          mGraphicBufferParam.graphicBufferHeight * 1.5;
264    extActualBufferStride = surfaceStride;
265    extActualBufferHeightStride = surfaceHeight;
266
267    for (i = 0; i < mOMXBufferHeaderTypePtrNum; i++) {
268        OMX_BUFFERHEADERTYPE *buf_hdr = mOMXBufferHeaderTypePtrArray[i];
269
270        extMIDs[i]->m_key = (unsigned int)(buf_hdr->pBuffer);
271        extMIDs[i]->m_render_done = false;
272        extMIDs[i]->m_released = true;
273
274        VAStatus va_res;
275        unsigned int buffer;
276        VASurfaceAttrib attribs[2];
277        VASurfaceAttribExternalBuffers* surfExtBuf = new VASurfaceAttribExternalBuffers;
278        int32_t format = VA_RT_FORMAT_YUV420;
279
280        surfExtBuf->buffers= (unsigned long *)&buffer;
281        surfExtBuf->num_buffers = 1;
282        surfExtBuf->pixel_format = VA_FOURCC_NV12;
283        surfExtBuf->width = surfaceWidth;
284        surfExtBuf->height = surfaceHeight;
285        surfExtBuf->data_size = surfaceStride * surfaceHeight * 1.5;
286        surfExtBuf->num_planes = 2;
287        surfExtBuf->pitches[0] = surfaceStride;
288        surfExtBuf->pitches[1] = surfaceStride;
289        surfExtBuf->pitches[2] = 0;
290        surfExtBuf->pitches[3] = 0;
291        surfExtBuf->offsets[0] = 0;
292        surfExtBuf->offsets[1] = surfaceStride * surfaceHeight;
293        surfExtBuf->offsets[2] = 0;
294        surfExtBuf->offsets[3] = 0;
295        surfExtBuf->flags = VA_SURFACE_ATTRIB_MEM_TYPE_ANDROID_GRALLOC;
296
297        surfExtBuf->buffers[0] = (unsigned int)buf_hdr->pBuffer;
298
299        attribs[0].type = (VASurfaceAttribType)VASurfaceAttribMemoryType;
300        attribs[0].flags = VA_SURFACE_ATTRIB_SETTABLE;
301        attribs[0].value.type = VAGenericValueTypeInteger;
302        attribs[0].value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_ANDROID_GRALLOC;
303
304        attribs[1].type = (VASurfaceAttribType)VASurfaceAttribExternalBufferDescriptor;
305        attribs[1].flags = VA_SURFACE_ATTRIB_SETTABLE;
306        attribs[1].value.type = VAGenericValueTypePointer;
307        attribs[1].value.value.p = (void *)surfExtBuf;
308
309        va_res = vaCreateSurfaces(mVADisplay,
310                                  format,
311                                  surfaceWidth,
312                                  surfaceHeight,
313                                  extMIDs[i]->m_surface,
314                                  1,
315                                  attribs,
316                                  2);
317
318        if (va_res != VA_STATUS_SUCCESS) {
319            LOGE("Failed to create vaSurface!");
320            return OMX_ErrorUndefined;
321        }
322
323        delete surfExtBuf;
324
325        VAImage image;
326        unsigned char* usrptr;
327
328        va_res = vaDeriveImage(mVADisplay, *(extMIDs[i]->m_surface), &image);
329        if (VA_STATUS_SUCCESS == va_res) {
330            va_res = vaMapBuffer(mVADisplay, image.buf, (void **) &usrptr);
331            if (VA_STATUS_SUCCESS == va_res) {
332                extMIDs[i]->m_usrAddr = usrptr;
333                vaUnmapBuffer(mVADisplay, image.buf);
334            }
335            vaDestroyImage(mVADisplay, image.image_id);
336        }
337        extMappedNativeBufferCount++;
338    }
339    return OMX_ErrorNone;
340#endif
341}
342
343OMX_ERRORTYPE OMXVideoDecoderVP9HWR::ProcessorDeinit(void)
344{
345    destroyDecoder();
346    unsigned int i = 0;
347    if (mWorkingMode == GRAPHICBUFFER_MODE) {
348        for (i = 0; i < mOMXBufferHeaderTypePtrNum; i++) {
349            if (extMIDs[i]->m_surface != NULL) {
350                vaDestroySurfaces(mVADisplay, extMIDs[i]->m_surface, 1);
351            }
352        }
353
354    } else if (mWorkingMode == RAWDATA_MODE) {
355        for (i = 0; i < OUTPORT_ACTUAL_BUFFER_COUNT; i++ ) {
356            if (extMIDs[i]->m_usrAddr != NULL) {
357                free(extMIDs[i]->m_usrAddr);
358                extMIDs[i]->m_usrAddr = NULL;
359            }
360        }
361    }
362    mOMXBufferHeaderTypePtrNum = 0;
363    memset(&mGraphicBufferParam, 0, sizeof(mGraphicBufferParam));
364    for (i = 0; i < MAX_NATIVE_BUFFER_COUNT; i++) {
365        delete extMIDs[i]->m_surface;
366        free(extMIDs[i]);
367    }
368    return OMXComponentCodecBase::ProcessorDeinit();
369}
370
371OMX_ERRORTYPE OMXVideoDecoderVP9HWR::ProcessorStop(void)
372{
373    return OMXComponentCodecBase::ProcessorStop();
374}
375
376OMX_ERRORTYPE OMXVideoDecoderVP9HWR::ProcessorFlush(OMX_U32)
377{
378    return OMX_ErrorNone;
379}
380
381OMX_ERRORTYPE OMXVideoDecoderVP9HWR::ProcessorPreFillBuffer(OMX_BUFFERHEADERTYPE* buffer)
382{
383    unsigned int handle = (unsigned int)buffer->pBuffer;
384    unsigned int i = 0;
385
386    if (buffer->nOutputPortIndex == OUTPORT_INDEX){
387        for (i = 0; i < mOMXBufferHeaderTypePtrNum; i++) {
388            if (handle == extMIDs[i]->m_key) {
389                extMIDs[i]->m_render_done = true;
390                break;
391            }
392        }
393    }
394    return OMX_ErrorNone;
395}
396
397OMX_ERRORTYPE OMXVideoDecoderVP9HWR::ProcessorProcess(
398        OMX_BUFFERHEADERTYPE ***pBuffers,
399        buffer_retain_t *retains,
400        OMX_U32)
401{
402    OMX_ERRORTYPE ret;
403    OMX_BUFFERHEADERTYPE *inBuffer = *pBuffers[INPORT_INDEX];
404    OMX_BUFFERHEADERTYPE *outBuffer = *pBuffers[OUTPORT_INDEX];
405    OMX_BOOL isResolutionChange = OMX_FALSE;
406
407    if (inBuffer->pBuffer == NULL) {
408        LOGE("Buffer to decode is empty.");
409        return OMX_ErrorBadParameter;
410    }
411
412    if (inBuffer->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
413        LOGI("Buffer has OMX_BUFFERFLAG_CODECCONFIG flag.");
414    }
415
416    if (inBuffer->nFlags & OMX_BUFFERFLAG_DECODEONLY) {
417        LOGW("Buffer has OMX_BUFFERFLAG_DECODEONLY flag.");
418    }
419
420    if (inBuffer->nFlags & OMX_BUFFERFLAG_EOS) {
421        if (inBuffer->nFilledLen == 0) {
422            (*pBuffers[OUTPORT_INDEX])->nFilledLen = 0;
423            (*pBuffers[OUTPORT_INDEX])->nFlags = OMX_BUFFERFLAG_EOS;
424            return OMX_ErrorNone;
425        }
426    }
427
428    if (vpx_codec_decode((vpx_codec_ctx_t *)mCtx,
429                         inBuffer->pBuffer + inBuffer->nOffset,
430                         inBuffer->nFilledLen,
431                         NULL,
432                         0)) {
433        LOGE("on2 decoder failed to decode frame.");
434        return OMX_ErrorBadParameter;
435    }
436
437    ret = FillRenderBuffer(pBuffers[OUTPORT_INDEX],
438                           &retains[OUTPORT_INDEX],
439                           ((*pBuffers[INPORT_INDEX]))->nFlags,
440                           &isResolutionChange);
441
442    if (ret == OMX_ErrorNone) {
443        (*pBuffers[OUTPORT_INDEX])->nTimeStamp = inBuffer->nTimeStamp;
444    }
445
446    if (isResolutionChange) {
447        HandleFormatChange();
448    }
449
450    bool inputEoS = ((*pBuffers[INPORT_INDEX])->nFlags & OMX_BUFFERFLAG_EOS);
451    bool outputEoS = ((*pBuffers[OUTPORT_INDEX])->nFlags & OMX_BUFFERFLAG_EOS);
452    // if output port is not eos, retain the input buffer
453    // until all the output buffers are drained.
454    if (inputEoS && !outputEoS) {
455        retains[INPORT_INDEX] = BUFFER_RETAIN_GETAGAIN;
456        // the input buffer is retained for draining purpose.
457        // Set nFilledLen to 0 so buffer will not be decoded again.
458        (*pBuffers[INPORT_INDEX])->nFilledLen = 0;
459    }
460
461    if (ret == OMX_ErrorNotReady) {
462        retains[OUTPORT_INDEX] = BUFFER_RETAIN_GETAGAIN;
463        ret = OMX_ErrorNone;
464    }
465
466    return ret;
467}
468
469OMX_ERRORTYPE OMXVideoDecoderVP9HWR::ProcessorReset(void)
470{
471    return OMX_ErrorNone;
472}
473
474static int ALIGN(int x, int y)
475{
476    // y must be a power of 2.
477    return (x + y - 1) & ~(y - 1);
478}
479
480OMX_ERRORTYPE OMXVideoDecoderVP9HWR::HandleFormatChange(void)
481{
482    mDecodedImageWidth = mDecodedImageNewWidth;
483    mDecodedImageHeight = mDecodedImageNewHeight;
484
485    // Sync port definition as it may change.
486    OMX_PARAM_PORTDEFINITIONTYPE paramPortDefinitionInput, paramPortDefinitionOutput;
487
488    memcpy(&paramPortDefinitionInput,
489        this->ports[INPORT_INDEX]->GetPortDefinition(),
490        sizeof(paramPortDefinitionInput));
491
492    memcpy(&paramPortDefinitionOutput,
493        this->ports[OUTPORT_INDEX]->GetPortDefinition(),
494        sizeof(paramPortDefinitionOutput));
495
496    uint32_t width = mDecodedImageWidth;
497    uint32_t height = mDecodedImageHeight;
498    uint32_t stride = mDecodedImageWidth;
499    uint32_t sliceHeight = mDecodedImageHeight;
500
501    uint32_t widthCropped = mDecodedImageWidth;
502    uint32_t heightCropped = mDecodedImageHeight;
503    uint32_t strideCropped = widthCropped;
504    uint32_t sliceHeightCropped = heightCropped;
505
506    if (widthCropped == paramPortDefinitionOutput.format.video.nFrameWidth &&
507        heightCropped == paramPortDefinitionOutput.format.video.nFrameHeight) {
508        if (mWorkingMode == RAWDATA_MODE) {
509            LOGW("Change of portsetting is not reported as size is not changed.");
510            return OMX_ErrorNone;
511        }
512    }
513
514    paramPortDefinitionInput.format.video.nFrameWidth = width;
515    paramPortDefinitionInput.format.video.nFrameHeight = height;
516    paramPortDefinitionInput.format.video.nStride = stride;
517    paramPortDefinitionInput.format.video.nSliceHeight = sliceHeight;
518
519    if (mWorkingMode == RAWDATA_MODE) {
520        paramPortDefinitionOutput.format.video.nFrameWidth = widthCropped;
521        paramPortDefinitionOutput.format.video.nFrameHeight = heightCropped;
522        paramPortDefinitionOutput.format.video.nStride = strideCropped;
523        paramPortDefinitionOutput.format.video.nSliceHeight = sliceHeightCropped;
524    } else if (mWorkingMode == GRAPHICBUFFER_MODE) {
525        // when the width and height ES parse are not larger than allocated graphic buffer in outport,
526        // there is no need to reallocate graphic buffer,just report the crop info to omx client
527        if (width <= mGraphicBufferParam.graphicBufferWidth &&
528            height <= mGraphicBufferParam.graphicBufferHeight) {
529            this->ports[INPORT_INDEX]->SetPortDefinition(&paramPortDefinitionInput, true);
530            this->ports[OUTPORT_INDEX]->ReportOutputCrop();
531            return OMX_ErrorNone;
532        }
533
534        if (width > mGraphicBufferParam.graphicBufferWidth ||
535            height > mGraphicBufferParam.graphicBufferHeight) {
536            // update the real decoded resolution to outport instead of display resolution
537            // for graphic buffer reallocation
538            // when the width and height parsed from ES are larger than allocated graphic buffer in outport,
539            paramPortDefinitionOutput.format.video.nFrameWidth = width;
540            paramPortDefinitionOutput.format.video.nFrameHeight = (height + 0x1f) & ~0x1f;
541            paramPortDefinitionOutput.format.video.eColorFormat = GetOutputColorFormat(
542                    paramPortDefinitionOutput.format.video.nFrameWidth);
543            paramPortDefinitionOutput.format.video.nStride = stride;
544            paramPortDefinitionOutput.format.video.nSliceHeight = sliceHeight;
545       }
546    }
547
548    paramPortDefinitionOutput.bEnabled = (OMX_BOOL)false;
549    mOMXBufferHeaderTypePtrNum = 0;
550    memset(&mGraphicBufferParam, 0, sizeof(mGraphicBufferParam));
551
552    this->ports[INPORT_INDEX]->SetPortDefinition(&paramPortDefinitionInput, true);
553    this->ports[OUTPORT_INDEX]->SetPortDefinition(&paramPortDefinitionOutput, true);
554
555    this->ports[OUTPORT_INDEX]->ReportPortSettingsChanged();
556    return OMX_ErrorNone;
557}
558
559OMX_ERRORTYPE OMXVideoDecoderVP9HWR::FillRenderBuffer(OMX_BUFFERHEADERTYPE **pBuffer,
560                                                      buffer_retain_t *retain,
561                                                      OMX_U32 inportBufferFlags,
562                                                      OMX_BOOL *isResolutionChange)
563{
564    OMX_BUFFERHEADERTYPE *buffer = *pBuffer;
565    OMX_BUFFERHEADERTYPE *buffer_orign = buffer;
566
567    OMX_ERRORTYPE ret = OMX_ErrorNone;
568
569    vpx_codec_iter_t iter = NULL;
570    vpx_image_t *img = NULL;
571    img = vpx_codec_get_frame((vpx_codec_ctx_t *)mCtx, &iter);
572
573    if (img != NULL) {
574        if ((mDecodedImageWidth == 0) && (mDecodedImageHeight == 0)) { // init value
575            mDecodedImageWidth = img->d_w;
576            mDecodedImageHeight = img->d_h;
577        }
578        if ((mDecodedImageWidth != img->d_w) && (mDecodedImageHeight != img->d_h)) {
579            mDecodedImageNewWidth = img->d_w;
580            mDecodedImageNewHeight = img->d_h;
581            *isResolutionChange = OMX_TRUE;
582        }
583    }
584
585    if (mWorkingMode == RAWDATA_MODE) {
586        if (img == NULL) {
587            LOGE("vpx_codec_get_frame return NULL.");
588            return OMX_ErrorNotReady;
589        }
590
591        // in Raw data mode, this flag should be always true
592        extMIDs[img->fb_index]->m_render_done = true;
593
594        void *dst = buffer->pBuffer;
595        uint8_t *dst_y = (uint8_t *)dst;
596        const OMX_PARAM_PORTDEFINITIONTYPE *paramPortDefinitionInput
597                                      = this->ports[INPORT_INDEX]->GetPortDefinition();
598
599        size_t inBufferWidth = paramPortDefinitionInput->format.video.nFrameWidth;
600        size_t inBufferHeight = paramPortDefinitionInput->format.video.nFrameHeight;
601
602        const OMX_PARAM_PORTDEFINITIONTYPE *paramPortDefinitionOutput
603                                      = this->ports[OUTPORT_INDEX]->GetPortDefinition();
604
605        size_t dst_y_size = paramPortDefinitionOutput->format.video.nStride *
606                            paramPortDefinitionOutput->format.video.nFrameHeight;
607        size_t dst_c_stride = ALIGN(paramPortDefinitionOutput->format.video.nStride / 2, 16);
608        size_t dst_c_size = dst_c_stride * paramPortDefinitionOutput->format.video.nFrameHeight / 2;
609        uint8_t *dst_v = dst_y + dst_y_size;
610        uint8_t *dst_u = dst_v + dst_c_size;
611
612        //test border
613        dst_y += VPX_DECODE_BORDER * paramPortDefinitionOutput->format.video.nStride + VPX_DECODE_BORDER;
614        dst_v += (VPX_DECODE_BORDER/2) * dst_c_stride + (VPX_DECODE_BORDER/2);
615        dst_u += (VPX_DECODE_BORDER/2) * dst_c_stride + (VPX_DECODE_BORDER/2);
616
617        const uint8_t *srcLine = (const uint8_t *)img->planes[PLANE_Y];
618
619        for (size_t i = 0; i < img->d_h; ++i) {
620            memcpy(dst_y, srcLine, img->d_w);
621
622            srcLine += img->stride[PLANE_Y];
623            dst_y += paramPortDefinitionOutput->format.video.nStride;
624        }
625
626        srcLine = (const uint8_t *)img->planes[PLANE_U];
627        for (size_t i = 0; i < img->d_h / 2; ++i) {
628            memcpy(dst_u, srcLine, img->d_w / 2);
629
630            srcLine += img->stride[PLANE_U];
631            dst_u += dst_c_stride;
632        }
633
634        srcLine = (const uint8_t *)img->planes[PLANE_V];
635        for (size_t i = 0; i < img->d_h / 2; ++i) {
636            memcpy(dst_v, srcLine, img->d_w / 2);
637
638            srcLine += img->stride[PLANE_V];
639            dst_v += dst_c_stride;
640        }
641
642        buffer->nOffset = 0;
643        buffer->nFilledLen = dst_y_size + dst_c_size * 2;
644        if (inportBufferFlags & OMX_BUFFERFLAG_EOS) {
645            buffer->nFlags = OMX_BUFFERFLAG_EOS;
646        }
647
648        if (buffer_orign != buffer) {
649            *retain = BUFFER_RETAIN_OVERRIDDEN;
650        }
651        ret = OMX_ErrorNone;
652
653        return ret;
654
655    }
656
657#ifdef DECODE_WITH_GRALLOC_BUFFER
658    if (NULL != img) {
659        buffer = *pBuffer = mOMXBufferHeaderTypePtrArray[img->fb_index];
660
661        if ((unsigned int)(buffer->pBuffer) != extMIDs[img->fb_index]->m_key) {
662            LOGE("There is gralloc handle mismatching between pool\
663                  and mOMXBufferHeaderTypePtrArray.");
664            return OMX_ErrorNotReady;
665        }
666
667        extMIDs[img->fb_index]->m_render_done = false;
668
669        buffer->nOffset = 0;
670
671        size_t dst_y_size = img->d_w * img->d_h;
672
673        buffer->nFilledLen = dst_y_size * 1.5; // suport only 4:2:0 for now
674
675        if (inportBufferFlags & OMX_BUFFERFLAG_EOS) {
676            buffer->nFlags = OMX_BUFFERFLAG_EOS;
677        }
678
679        if (buffer_orign != buffer) {
680            *retain = BUFFER_RETAIN_OVERRIDDEN;
681        }
682
683        return OMX_ErrorNone;
684    } else {
685        LOGE("vpx_codec_get_frame return NULL.");
686        return OMX_ErrorNotReady;
687    }
688#endif
689}
690
691OMX_ERRORTYPE OMXVideoDecoderVP9HWR::PrepareConfigBuffer(VideoConfigBuffer *)
692{
693    return OMX_ErrorNone;
694}
695
696OMX_ERRORTYPE OMXVideoDecoderVP9HWR::PrepareDecodeBuffer(OMX_BUFFERHEADERTYPE *,
697                                                         buffer_retain_t *,
698                                                         VideoDecodeBuffer *)
699{
700    return OMX_ErrorNone;
701}
702
703OMX_ERRORTYPE OMXVideoDecoderVP9HWR::BuildHandlerList(void)
704{
705    OMXVideoDecoderBase::BuildHandlerList();
706    return OMX_ErrorNone;
707}
708
709OMX_ERRORTYPE OMXVideoDecoderVP9HWR::GetParamVideoVp9(OMX_PTR)
710{
711    return OMX_ErrorNone;
712}
713
714OMX_ERRORTYPE OMXVideoDecoderVP9HWR::SetParamVideoVp9(OMX_PTR)
715{
716    return OMX_ErrorNone;
717}
718
719OMX_COLOR_FORMATTYPE OMXVideoDecoderVP9HWR::GetOutputColorFormat(int)
720{
721    LOGV("Output color format is OMX_INTEL_COLOR_FormatHalYV12.");
722    return (OMX_COLOR_FORMATTYPE)HAL_PIXEL_FORMAT_YV12;
723}
724
725OMX_ERRORTYPE OMXVideoDecoderVP9HWR::GetDecoderOutputCropSpecific(OMX_PTR pStructure)
726{
727    OMX_ERRORTYPE ret = OMX_ErrorNone;
728    OMX_CONFIG_RECTTYPE *rectParams = (OMX_CONFIG_RECTTYPE *)pStructure;
729
730    CHECK_TYPE_HEADER(rectParams);
731
732    if (rectParams->nPortIndex != OUTPORT_INDEX) {
733        return OMX_ErrorUndefined;
734    }
735
736    const OMX_PARAM_PORTDEFINITIONTYPE *paramPortDefinitionInput
737                                      = this->ports[INPORT_INDEX]->GetPortDefinition();
738
739    rectParams->nLeft = VPX_DECODE_BORDER;
740    rectParams->nTop = VPX_DECODE_BORDER;
741    rectParams->nWidth = paramPortDefinitionInput->format.video.nFrameWidth;
742    rectParams->nHeight = paramPortDefinitionInput->format.video.nFrameHeight;
743
744    return ret;
745}
746
747OMX_ERRORTYPE OMXVideoDecoderVP9HWR::GetNativeBufferUsageSpecific(OMX_PTR pStructure)
748{
749    OMX_ERRORTYPE ret;
750    android::GetAndroidNativeBufferUsageParams *param =
751        (android::GetAndroidNativeBufferUsageParams*)pStructure;
752    CHECK_TYPE_HEADER(param);
753
754    param->nUsage |= (GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_SW_READ_NEVER \
755                     | GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_EXTERNAL_DISP);
756    return OMX_ErrorNone;
757
758}
759
760OMX_ERRORTYPE OMXVideoDecoderVP9HWR::SetNativeBufferModeSpecific(OMX_PTR pStructure)
761{
762    OMX_ERRORTYPE ret;
763    EnableAndroidNativeBuffersParams *param =
764        (EnableAndroidNativeBuffersParams*)pStructure;
765
766    CHECK_TYPE_HEADER(param);
767    CHECK_PORT_INDEX_RANGE(param);
768    CHECK_SET_PARAM_STATE();
769
770    if (!param->enable) {
771        mWorkingMode = RAWDATA_MODE;
772        return OMX_ErrorNone;
773    }
774    mWorkingMode = GRAPHICBUFFER_MODE;
775    PortVideo *port = NULL;
776    port = static_cast<PortVideo *>(this->ports[OUTPORT_INDEX]);
777
778
779    OMX_PARAM_PORTDEFINITIONTYPE port_def;
780    memcpy(&port_def,port->GetPortDefinition(),sizeof(port_def));
781    port_def.nBufferCountMin = mNativeBufferCount;
782    port_def.nBufferCountActual = mNativeBufferCount;
783    port_def.format.video.cMIMEType = (OMX_STRING)VA_VED_RAW_MIME_TYPE;
784    port_def.format.video.eColorFormat = OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar;
785
786    // add borders for libvpx decode need.
787    port_def.format.video.nFrameHeight += VPX_DECODE_BORDER * 2;
788    port_def.format.video.nFrameWidth += VPX_DECODE_BORDER * 2;
789    // make heigth 32bit align
790    port_def.format.video.nFrameHeight = (port_def.format.video.nFrameHeight + 0x1f) & ~0x1f;
791    port_def.format.video.eColorFormat = GetOutputColorFormat(
792                        port_def.format.video.nFrameWidth);
793    port->SetPortDefinition(&port_def,true);
794
795     return OMX_ErrorNone;
796}
797
798
799bool OMXVideoDecoderVP9HWR::IsAllBufferAvailable(void)
800{
801    bool b = ComponentBase::IsAllBufferAvailable();
802    if (b == false) {
803        return false;
804    }
805
806    PortVideo *port = NULL;
807    port = static_cast<PortVideo *>(this->ports[OUTPORT_INDEX]);
808    const OMX_PARAM_PORTDEFINITIONTYPE* port_def = port->GetPortDefinition();
809     // if output port is disabled, retain the input buffer
810    if (!port_def->bEnabled) {
811        return false;
812    }
813
814    unsigned int i = 0;
815    int found = 0;
816
817    if (RAWDATA_MODE == mWorkingMode) {
818        for (i = 0; i < OUTPORT_ACTUAL_BUFFER_COUNT; i++) {
819            if (extMIDs[i]->m_released == true) {
820               found ++;
821               if (found > 1) { //libvpx sometimes needs 2 buffer when calling decode once.
822                   return true;
823               }
824            }
825        }
826    } else { // graphic buffer mode
827        for (i = 0; i < mOMXBufferHeaderTypePtrNum; i++) {
828            if ((extMIDs[i]->m_render_done == true) && (extMIDs[i]->m_released == true)) {
829               found ++;
830               if (found > 1) { //libvpx sometimes needs 2 buffer when calling decode once.
831                   return true;
832               }
833            }
834        }
835    }
836
837    b = false;
838
839    return b;
840}
841
842DECLARE_OMX_COMPONENT("OMX.Intel.VideoDecoder.VP9.hwr", "video_decoder.vp9", OMXVideoDecoderVP9HWR);
843
844