1/*
2* Copyright (c) 2009-2011 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 "OMXVideoDecoder"
20#include <wrs_omxil_core/log.h>
21#include "OMXVideoDecoderAVC.h"
22
23
24// Be sure to have an equal string in VideoDecoderHost.cpp (libmix)
25static const char* AVC_MIME_TYPE = "video/h264";
26#define INVALID_PTS (OMX_S64)-1
27
28
29OMXVideoDecoderAVC::OMXVideoDecoderAVC()
30    : mAccumulateBuffer(NULL),
31      mBufferSize(0),
32      mFilledLen(0),
33      mTimeStamp(INVALID_PTS) {
34    LOGV("OMXVideoDecoderAVC is constructed.");
35    mVideoDecoder = createVideoDecoder(AVC_MIME_TYPE);
36    if (!mVideoDecoder) {
37        LOGE("createVideoDecoder failed for \"%s\"", AVC_MIME_TYPE);
38    }
39    // Override default native buffer count defined in the base class
40    mNativeBufferCount = OUTPORT_NATIVE_BUFFER_COUNT;
41    BuildHandlerList();
42}
43
44OMXVideoDecoderAVC::~OMXVideoDecoderAVC() {
45    LOGV("OMXVideoDecoderAVC is destructed.");
46}
47
48OMX_ERRORTYPE OMXVideoDecoderAVC::InitInputPortFormatSpecific(OMX_PARAM_PORTDEFINITIONTYPE *paramPortDefinitionInput) {
49    //OMX_VIDEO_PARAM_INTEL_AVC_DECODE_SETTINGS
50    memset(&mDecodeSettings, 0, sizeof(mDecodeSettings));
51    SetTypeHeader(&mDecodeSettings, sizeof(mDecodeSettings));
52    mDecodeSettings.nMaxNumberOfReferenceFrame = NUM_REFERENCE_FRAME;
53
54    // OMX_PARAM_PORTDEFINITIONTYPE
55    paramPortDefinitionInput->nBufferCountActual = INPORT_ACTUAL_BUFFER_COUNT;
56    paramPortDefinitionInput->nBufferCountMin = INPORT_MIN_BUFFER_COUNT;
57    paramPortDefinitionInput->nBufferSize = INPORT_BUFFER_SIZE;
58    paramPortDefinitionInput->format.video.cMIMEType = (OMX_STRING)AVC_MIME_TYPE;
59    paramPortDefinitionInput->format.video.eCompressionFormat = OMX_VIDEO_CodingAVC;
60
61    // OMX_VIDEO_PARAM_AVCTYPE
62    memset(&mParamAvc, 0, sizeof(mParamAvc));
63    SetTypeHeader(&mParamAvc, sizeof(mParamAvc));
64    mParamAvc.nPortIndex = INPORT_INDEX;
65    // TODO: check eProfile/eLevel
66    mParamAvc.eProfile = OMX_VIDEO_AVCProfileHigh; //OMX_VIDEO_AVCProfileBaseline;
67    mParamAvc.eLevel = OMX_VIDEO_AVCLevel41; //OMX_VIDEO_AVCLevel1;
68
69    return OMX_ErrorNone;
70}
71
72OMX_ERRORTYPE OMXVideoDecoderAVC::ProcessorInit(void) {
73    return OMXVideoDecoderBase::ProcessorInit();
74}
75
76OMX_ERRORTYPE OMXVideoDecoderAVC::ProcessorDeinit(void) {
77    if (mAccumulateBuffer) {
78        delete mAccumulateBuffer;
79    }
80    mAccumulateBuffer = NULL;
81    mBufferSize = 0;
82    mFilledLen = 0;
83    mTimeStamp = INVALID_PTS;
84
85    return OMXVideoDecoderBase::ProcessorDeinit();
86}
87
88OMX_ERRORTYPE OMXVideoDecoderAVC::ProcessorFlush(OMX_U32 portIndex) {
89    mFilledLen = 0;
90    mTimeStamp = INVALID_PTS;
91    return OMXVideoDecoderBase::ProcessorFlush(portIndex);
92}
93
94OMX_ERRORTYPE OMXVideoDecoderAVC::ProcessorProcess(
95        OMX_BUFFERHEADERTYPE ***pBuffers,
96        buffer_retain_t *retains,
97        OMX_U32 numberBuffers) {
98
99    return OMXVideoDecoderBase::ProcessorProcess(pBuffers, retains, numberBuffers);
100}
101
102OMX_ERRORTYPE OMXVideoDecoderAVC::PrepareConfigBuffer(VideoConfigBuffer *p) {
103    OMX_ERRORTYPE ret;
104
105    ret = OMXVideoDecoderBase::PrepareConfigBuffer(p);
106    CHECK_RETURN_VALUE("OMXVideoDecoderBase::PrepareConfigBuffer");
107
108    if (mParamAvc.eProfile == OMX_VIDEO_AVCProfileBaseline) {
109        p->flag |= WANT_LOW_DELAY;
110    }
111
112    if (mDecodeSettings.nMaxWidth == 0 ||
113        mDecodeSettings.nMaxHeight == 0) {
114        return OMX_ErrorNone;
115    }
116
117    LOGW("AVC Video decoder used in Video Conferencing Mode.");
118
119    // For video conferencing application
120    p->width = mDecodeSettings.nMaxWidth;
121    p->height = mDecodeSettings.nMaxHeight;
122    p->profile = VAProfileH264ConstrainedBaseline;
123    if(!(p->flag & USE_NATIVE_GRAPHIC_BUFFER)) {
124        p->surfaceNumber = mDecodeSettings.nMaxNumberOfReferenceFrame + EXTRA_REFERENCE_FRAME;
125        p->flag = WANT_ERROR_CONCEALMENT | WANT_LOW_DELAY | HAS_SURFACE_NUMBER | HAS_VA_PROFILE;
126    } else {
127        p->flag |= WANT_ERROR_CONCEALMENT | WANT_LOW_DELAY | HAS_SURFACE_NUMBER | HAS_VA_PROFILE;
128    }
129
130    return OMX_ErrorNone;
131}
132
133OMX_ERRORTYPE OMXVideoDecoderAVC::PrepareDecodeBuffer(OMX_BUFFERHEADERTYPE *buffer, buffer_retain_t *retain, VideoDecodeBuffer *p) {
134    OMX_ERRORTYPE ret;
135    ret = OMXVideoDecoderBase::PrepareDecodeBuffer(buffer, retain, p);
136    CHECK_RETURN_VALUE("OMXVideoDecoderBase::PrepareDecodeBuffer");
137
138    // OMX_BUFFERFLAG_CODECCONFIG is an optional flag
139    // if flag is set, buffer will only contain codec data.
140    if (buffer->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
141        LOGV("Received AVC codec data.");
142        return ret;
143    }
144
145    // OMX_BUFFERFLAG_ENDOFFRAME is an optional flag
146    if (buffer->nFlags & (OMX_BUFFERFLAG_ENDOFFRAME | OMX_BUFFERFLAG_EOS)) {
147        // TODO: if OMX_BUFFERFLAG_ENDOFFRAME indicates end of a NAL unit and in OMXVideoDecodeBase
148        // we set buffer flag to HAS_COMPLETE_FRAME,  corruption will happen
149        mTimeStamp = buffer->nTimeStamp;
150        if (mFilledLen == 0) {
151            // buffer is not accumulated and it contains a complete frame
152            return ret;
153        }
154        // buffer contains  the last part of fragmented frame
155        ret = AccumulateBuffer(buffer);
156        CHECK_RETURN_VALUE("AccumulateBuffer");
157        ret = FillDecodeBuffer(p);
158        CHECK_RETURN_VALUE("FillDecodeBuffer");
159        return ret;
160    }
161
162    LOGW("Received fragmented buffer.");
163    // use time stamp to determine frame boundary
164    if (mTimeStamp == INVALID_PTS) {
165        // first ever buffer
166        mTimeStamp = buffer->nTimeStamp;
167    }
168
169    if (mTimeStamp != buffer->nTimeStamp && mFilledLen != 0) {
170        // buffer accumulated contains a complete frame
171        ret = FillDecodeBuffer(p);
172        CHECK_RETURN_VALUE("FillDecodeBuffer");
173        // retain the current buffer
174        *retain = BUFFER_RETAIN_GETAGAIN;
175    } else {
176        // buffer accumulation for beginning of fragmented buffer (mFilledLen == 0) or
177        // middle/end of fragmented buffer (mFilledLen != 0)
178        ret = AccumulateBuffer(buffer);
179        CHECK_RETURN_VALUE("AccumulateBuffer");
180        ret = OMX_ErrorNotReady;
181    }
182
183    if (buffer->nFilledLen != 0) {
184        mTimeStamp = buffer->nTimeStamp;
185    }
186    return ret;
187}
188
189OMX_ERRORTYPE OMXVideoDecoderAVC::AccumulateBuffer(OMX_BUFFERHEADERTYPE *buffer) {
190    // check if allocated buffer is big enough
191    if (mFilledLen + buffer->nFilledLen > mBufferSize) {
192        mBufferSize = mFilledLen + buffer->nFilledLen;
193        if (mBufferSize < INPORT_BUFFER_SIZE) {
194            mBufferSize = INPORT_BUFFER_SIZE;
195        }
196        if (mBufferSize == 0) {
197            return OMX_ErrorBadParameter;
198        }
199        OMX_U8 *temp = new OMX_U8 [mBufferSize];
200        if (temp == NULL) {
201            mBufferSize = 0;
202            return OMX_ErrorInsufficientResources;
203        }
204        if (mFilledLen != 0) {
205            memcpy(temp, mAccumulateBuffer, mFilledLen);
206        }
207        if (mAccumulateBuffer) {
208            delete [] mAccumulateBuffer;
209        }
210        mAccumulateBuffer = temp;
211    }
212    if (buffer->nFilledLen != 0) {
213        memcpy(mAccumulateBuffer + mFilledLen, buffer->pBuffer + buffer->nOffset, buffer->nFilledLen);
214    }
215    mFilledLen += buffer->nFilledLen;
216    return OMX_ErrorNone;
217}
218
219OMX_ERRORTYPE OMXVideoDecoderAVC::FillDecodeBuffer(VideoDecodeBuffer *p) {
220    p->data = mAccumulateBuffer;
221    p->size = mFilledLen;
222    p->timeStamp = mTimeStamp;
223    p->flag = HAS_COMPLETE_FRAME;
224
225    mFilledLen = 0;
226    return OMX_ErrorNone;
227}
228
229OMX_ERRORTYPE OMXVideoDecoderAVC::BuildHandlerList(void) {
230    OMXVideoDecoderBase::BuildHandlerList();
231    AddHandler(OMX_IndexParamVideoAvc, GetParamVideoAvc, SetParamVideoAvc);
232    AddHandler((OMX_INDEXTYPE)OMX_IndexParamIntelAVCDecodeSettings, GetParamIntelAVCDecodeSettings, SetParamIntelAVCDecodeSettings);
233    AddHandler(OMX_IndexParamVideoProfileLevelQuerySupported, GetParamVideoAVCProfileLevel, SetParamVideoAVCProfileLevel);
234    return OMX_ErrorNone;
235}
236
237OMX_ERRORTYPE OMXVideoDecoderAVC::GetParamVideoAvc(OMX_PTR pStructure) {
238    OMX_ERRORTYPE ret;
239    OMX_VIDEO_PARAM_AVCTYPE *p = (OMX_VIDEO_PARAM_AVCTYPE *)pStructure;
240    CHECK_TYPE_HEADER(p);
241    CHECK_PORT_INDEX(p, INPORT_INDEX);
242
243    memcpy(p, &mParamAvc, sizeof(*p));
244    return OMX_ErrorNone;
245}
246
247OMX_ERRORTYPE OMXVideoDecoderAVC::SetParamVideoAvc(OMX_PTR pStructure) {
248    OMX_ERRORTYPE ret;
249    OMX_VIDEO_PARAM_AVCTYPE *p = (OMX_VIDEO_PARAM_AVCTYPE *)pStructure;
250    CHECK_TYPE_HEADER(p);
251    CHECK_PORT_INDEX(p, INPORT_INDEX);
252    CHECK_SET_PARAM_STATE();
253
254    // TODO: do we need to check if port is enabled?
255    // TODO: see SetPortAvcParam implementation - Can we make simple copy????
256    memcpy(&mParamAvc, p, sizeof(mParamAvc));
257
258    return OMX_ErrorNone;
259}
260
261OMX_ERRORTYPE OMXVideoDecoderAVC::GetParamIntelAVCDecodeSettings(OMX_PTR) {
262    return OMX_ErrorNotImplemented;
263}
264
265OMX_ERRORTYPE OMXVideoDecoderAVC::SetParamIntelAVCDecodeSettings(OMX_PTR pStructure) {
266    LOGW("SetParamIntelAVCDecodeSettings");
267
268    OMX_ERRORTYPE ret;
269    OMX_VIDEO_PARAM_INTEL_AVC_DECODE_SETTINGS *p = (OMX_VIDEO_PARAM_INTEL_AVC_DECODE_SETTINGS *)pStructure;
270
271    CHECK_TYPE_HEADER(p);
272    CHECK_PORT_INDEX(p, INPORT_INDEX);
273    CHECK_SET_PARAM_STATE();
274
275    if(p->nMaxNumberOfReferenceFrame == 0) {
276        // TODO: check if we just return in this case.
277        p->nMaxNumberOfReferenceFrame = NUM_REFERENCE_FRAME;
278    }
279    LOGI("Maximum width = %u, height = %u, dpb = %u", p->nMaxWidth, p->nMaxHeight, p->nMaxNumberOfReferenceFrame);
280    mDecodeSettings = *p;
281
282    return OMX_ErrorNone;
283}
284
285OMX_ERRORTYPE OMXVideoDecoderAVC::GetParamVideoAVCProfileLevel(OMX_PTR pStructure) {
286    OMX_ERRORTYPE ret;
287    OMX_VIDEO_PARAM_PROFILELEVELTYPE *p = (OMX_VIDEO_PARAM_PROFILELEVELTYPE *)pStructure;
288    CHECK_TYPE_HEADER(p);
289    CHECK_PORT_INDEX(p, INPORT_INDEX);
290
291    struct ProfileLevelTable {
292        OMX_U32 profile;
293        OMX_U32 level;
294    } plTable[] = {
295        {OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel42},
296        {OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel42},
297        {OMX_VIDEO_AVCProfileHigh, OMX_VIDEO_AVCLevel42}
298    };
299
300    OMX_U32 count = sizeof(plTable)/sizeof(ProfileLevelTable);
301    CHECK_ENUMERATION_RANGE(p->nProfileIndex,count);
302
303    p->eProfile = plTable[p->nProfileIndex].profile;
304    p->eLevel = plTable[p->nProfileIndex].level;
305
306    return OMX_ErrorNone;
307}
308
309OMX_ERRORTYPE OMXVideoDecoderAVC::SetParamVideoAVCProfileLevel(OMX_PTR) {
310    LOGW("SetParamVideoAVCProfileLevel is not supported.");
311    return OMX_ErrorUnsupportedSetting;
312}
313
314OMX_COLOR_FORMATTYPE OMXVideoDecoderAVC::GetOutputColorFormat(int width)
315{
316#ifdef USE_GEN_HW
317    return OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled;
318#else
319    return OMXVideoDecoderBase::GetOutputColorFormat(width);
320#endif
321}
322
323OMX_ERRORTYPE OMXVideoDecoderAVC::SetMaxOutputBufferCount(OMX_PARAM_PORTDEFINITIONTYPE *p) {
324    OMX_ERRORTYPE ret;
325    CHECK_TYPE_HEADER(p);
326    CHECK_PORT_INDEX(p, OUTPORT_INDEX);
327
328    p->nBufferCountActual = MAX_OUTPORT_BUFFER_COUNT;
329    return OMXVideoDecoderBase::SetMaxOutputBufferCount(p);
330}
331
332DECLARE_OMX_COMPONENT("OMX.Intel.VideoDecoder.AVC", "video_decoder.avc", OMXVideoDecoderAVC);
333