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#define LOG_TAG "SoftMPEG4"
19#include <utils/Log.h>
20
21#include "SoftMPEG4.h"
22
23#include <media/stagefright/foundation/ADebug.h>
24#include <media/stagefright/foundation/AUtils.h>
25#include <media/stagefright/MediaDefs.h>
26#include <media/stagefright/MediaErrors.h>
27#include <media/IOMX.h>
28
29#include "mp4dec_api.h"
30
31namespace android {
32
33static const CodecProfileLevel kM4VProfileLevels[] = {
34    { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level0 },
35    { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level0b },
36    { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level1 },
37    { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level2 },
38    { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level3 },
39};
40
41static const CodecProfileLevel kH263ProfileLevels[] = {
42    { OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level10 },
43    { OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level20 },
44    { OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level30 },
45    { OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level45 },
46    { OMX_VIDEO_H263ProfileISWV2,    OMX_VIDEO_H263Level10 },
47    { OMX_VIDEO_H263ProfileISWV2,    OMX_VIDEO_H263Level20 },
48    { OMX_VIDEO_H263ProfileISWV2,    OMX_VIDEO_H263Level30 },
49    { OMX_VIDEO_H263ProfileISWV2,    OMX_VIDEO_H263Level45 },
50};
51
52SoftMPEG4::SoftMPEG4(
53        const char *name,
54        const char *componentRole,
55        OMX_VIDEO_CODINGTYPE codingType,
56        const CodecProfileLevel *profileLevels,
57        size_t numProfileLevels,
58        const OMX_CALLBACKTYPE *callbacks,
59        OMX_PTR appData,
60        OMX_COMPONENTTYPE **component)
61    : SoftVideoDecoderOMXComponent(
62            name, componentRole, codingType, profileLevels, numProfileLevels,
63            352 /* width */, 288 /* height */, callbacks, appData, component),
64      mMode(codingType == OMX_VIDEO_CodingH263 ? MODE_H263 : MODE_MPEG4),
65      mHandle(new tagvideoDecControls),
66      mInputBufferCount(0),
67      mSignalledError(false),
68      mInitialized(false),
69      mFramesConfigured(false),
70      mNumSamplesOutput(0),
71      mPvTime(0) {
72    initPorts(
73            kNumInputBuffers,
74            352 * 288 * 3 / 2 /* minInputBufferSize */,
75            kNumOutputBuffers,
76            (mMode == MODE_MPEG4)
77            ? MEDIA_MIMETYPE_VIDEO_MPEG4 : MEDIA_MIMETYPE_VIDEO_H263);
78    CHECK_EQ(initDecoder(), (status_t)OK);
79}
80
81SoftMPEG4::~SoftMPEG4() {
82    if (mInitialized) {
83        PVCleanUpVideoDecoder(mHandle);
84    }
85
86    delete mHandle;
87    mHandle = NULL;
88}
89
90status_t SoftMPEG4::initDecoder() {
91    memset(mHandle, 0, sizeof(tagvideoDecControls));
92    return OK;
93}
94
95void SoftMPEG4::onQueueFilled(OMX_U32 /* portIndex */) {
96    if (mSignalledError || mOutputPortSettingsChange != NONE) {
97        return;
98    }
99
100    List<BufferInfo *> &inQueue = getPortQueue(0);
101    List<BufferInfo *> &outQueue = getPortQueue(1);
102
103    while (!inQueue.empty() && outQueue.size() == kNumOutputBuffers) {
104        BufferInfo *inInfo = *inQueue.begin();
105        OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
106        if (inHeader == NULL) {
107            inQueue.erase(inQueue.begin());
108            inInfo->mOwnedByUs = false;
109            continue;
110        }
111
112        PortInfo *port = editPortInfo(1);
113
114        OMX_BUFFERHEADERTYPE *outHeader =
115            port->mBuffers.editItemAt(mNumSamplesOutput & 1).mHeader;
116
117        if (inHeader->nFilledLen == 0) {
118            inQueue.erase(inQueue.begin());
119            inInfo->mOwnedByUs = false;
120            notifyEmptyBufferDone(inHeader);
121
122            ++mInputBufferCount;
123
124            if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
125                outHeader->nFilledLen = 0;
126                outHeader->nFlags = OMX_BUFFERFLAG_EOS;
127
128                List<BufferInfo *>::iterator it = outQueue.begin();
129                while ((*it)->mHeader != outHeader) {
130                    ++it;
131                }
132
133                BufferInfo *outInfo = *it;
134                outInfo->mOwnedByUs = false;
135                outQueue.erase(it);
136                outInfo = NULL;
137
138                notifyFillBufferDone(outHeader);
139                outHeader = NULL;
140            }
141            return;
142        }
143
144        uint8_t *bitstream = inHeader->pBuffer + inHeader->nOffset;
145        uint32_t *start_code = (uint32_t *)bitstream;
146        bool volHeader = *start_code == 0xB0010000;
147        if (volHeader) {
148            PVCleanUpVideoDecoder(mHandle);
149            mInitialized = false;
150        }
151
152        if (!mInitialized) {
153            uint8_t *vol_data[1];
154            int32_t vol_size = 0;
155
156            vol_data[0] = NULL;
157
158            if ((inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) || volHeader) {
159                vol_data[0] = bitstream;
160                vol_size = inHeader->nFilledLen;
161            }
162
163            MP4DecodingMode mode =
164                (mMode == MODE_MPEG4) ? MPEG4_MODE : H263_MODE;
165
166            Bool success = PVInitVideoDecoder(
167                    mHandle, vol_data, &vol_size, 1,
168                    outputBufferWidth(), outputBufferHeight(), mode);
169
170            if (!success) {
171                ALOGW("PVInitVideoDecoder failed. Unsupported content?");
172
173                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
174                mSignalledError = true;
175                return;
176            }
177
178            MP4DecodingMode actualMode = PVGetDecBitstreamMode(mHandle);
179            if (mode != actualMode) {
180                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
181                mSignalledError = true;
182                return;
183            }
184
185            PVSetPostProcType((VideoDecControls *) mHandle, 0);
186
187            bool hasFrameData = false;
188            if (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
189                inInfo->mOwnedByUs = false;
190                inQueue.erase(inQueue.begin());
191                inInfo = NULL;
192                notifyEmptyBufferDone(inHeader);
193                inHeader = NULL;
194            } else if (volHeader) {
195                hasFrameData = true;
196            }
197
198            mInitialized = true;
199
200            if (mode == MPEG4_MODE && handlePortSettingsChange()) {
201                return;
202            }
203
204            if (!hasFrameData) {
205                continue;
206            }
207        }
208
209        if (!mFramesConfigured) {
210            PortInfo *port = editPortInfo(1);
211            OMX_BUFFERHEADERTYPE *outHeader = port->mBuffers.editItemAt(1).mHeader;
212
213            PVSetReferenceYUV(mHandle, outHeader->pBuffer);
214
215            mFramesConfigured = true;
216        }
217
218        uint32_t useExtTimestamp = (inHeader->nOffset == 0);
219
220        // decoder deals in ms (int32_t), OMX in us (int64_t)
221        // so use fake timestamp instead
222        uint32_t timestamp = 0xFFFFFFFF;
223        if (useExtTimestamp) {
224            mPvToOmxTimeMap.add(mPvTime, inHeader->nTimeStamp);
225            timestamp = mPvTime;
226            mPvTime++;
227        }
228
229        int32_t bufferSize = inHeader->nFilledLen;
230        int32_t tmp = bufferSize;
231
232        OMX_U32 frameSize = (mWidth * mHeight * 3) / 2;
233        if (outHeader->nAllocLen < frameSize) {
234            android_errorWriteLog(0x534e4554, "27833616");
235            ALOGE("Insufficient output buffer size");
236            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
237            mSignalledError = true;
238            return;
239        }
240        // The PV decoder is lying to us, sometimes it'll claim to only have
241        // consumed a subset of the buffer when it clearly consumed all of it.
242        // ignore whatever it says...
243        if (PVDecodeVideoFrame(
244                    mHandle, &bitstream, &timestamp, &tmp,
245                    &useExtTimestamp,
246                    outHeader->pBuffer) != PV_TRUE) {
247            ALOGE("failed to decode video frame.");
248
249            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
250            mSignalledError = true;
251            return;
252        }
253
254        // H263 doesn't have VOL header, the frame size information is in short header, i.e. the
255        // decoder may detect size change after PVDecodeVideoFrame.
256        if (handlePortSettingsChange()) {
257            return;
258        }
259
260        // decoder deals in ms, OMX in us.
261        outHeader->nTimeStamp = mPvToOmxTimeMap.valueFor(timestamp);
262        mPvToOmxTimeMap.removeItem(timestamp);
263
264        inHeader->nOffset += bufferSize;
265        inHeader->nFilledLen = 0;
266        if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
267            outHeader->nFlags = OMX_BUFFERFLAG_EOS;
268        } else {
269            outHeader->nFlags = 0;
270        }
271
272        if (inHeader->nFilledLen == 0) {
273            inInfo->mOwnedByUs = false;
274            inQueue.erase(inQueue.begin());
275            inInfo = NULL;
276            notifyEmptyBufferDone(inHeader);
277            inHeader = NULL;
278        }
279
280        ++mInputBufferCount;
281
282        outHeader->nOffset = 0;
283        outHeader->nFilledLen = frameSize;
284
285        List<BufferInfo *>::iterator it = outQueue.begin();
286        while ((*it)->mHeader != outHeader) {
287            ++it;
288        }
289
290        BufferInfo *outInfo = *it;
291        outInfo->mOwnedByUs = false;
292        outQueue.erase(it);
293        outInfo = NULL;
294
295        notifyFillBufferDone(outHeader);
296        outHeader = NULL;
297
298        ++mNumSamplesOutput;
299    }
300}
301
302bool SoftMPEG4::handlePortSettingsChange() {
303    uint32_t disp_width, disp_height;
304    PVGetVideoDimensions(mHandle, (int32 *)&disp_width, (int32 *)&disp_height);
305
306    uint32_t buf_width, buf_height;
307    PVGetBufferDimensions(mHandle, (int32 *)&buf_width, (int32 *)&buf_height);
308
309    CHECK_LE(disp_width, buf_width);
310    CHECK_LE(disp_height, buf_height);
311
312    ALOGV("disp_width = %d, disp_height = %d, buf_width = %d, buf_height = %d",
313            disp_width, disp_height, buf_width, buf_height);
314
315    CropSettingsMode cropSettingsMode = kCropUnSet;
316    if (disp_width != buf_width || disp_height != buf_height) {
317        cropSettingsMode = kCropSet;
318
319        if (mCropWidth != disp_width || mCropHeight != disp_height) {
320            mCropLeft = 0;
321            mCropTop = 0;
322            mCropWidth = disp_width;
323            mCropHeight = disp_height;
324            cropSettingsMode = kCropChanged;
325        }
326    }
327
328    bool portWillReset = false;
329    const bool fakeStride = true;
330    SoftVideoDecoderOMXComponent::handlePortSettingsChange(
331            &portWillReset, buf_width, buf_height, cropSettingsMode, fakeStride);
332    if (portWillReset) {
333        if (mMode == MODE_H263) {
334            PVCleanUpVideoDecoder(mHandle);
335
336            uint8_t *vol_data[1];
337            int32_t vol_size = 0;
338
339            vol_data[0] = NULL;
340            if (!PVInitVideoDecoder(
341                    mHandle, vol_data, &vol_size, 1, outputBufferWidth(), outputBufferHeight(),
342                    H263_MODE)) {
343                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
344                mSignalledError = true;
345                return true;
346            }
347        }
348
349        mFramesConfigured = false;
350    }
351
352    return portWillReset;
353}
354
355void SoftMPEG4::onPortFlushCompleted(OMX_U32 portIndex) {
356    if (portIndex == 0 && mInitialized) {
357        CHECK_EQ((int)PVResetVideoDecoder(mHandle), (int)PV_TRUE);
358    }
359}
360
361void SoftMPEG4::onReset() {
362    SoftVideoDecoderOMXComponent::onReset();
363    mPvToOmxTimeMap.clear();
364    mSignalledError = false;
365    mFramesConfigured = false;
366    if (mInitialized) {
367        PVCleanUpVideoDecoder(mHandle);
368        mInitialized = false;
369    }
370}
371
372void SoftMPEG4::updatePortDefinitions(bool updateCrop, bool updateInputSize) {
373    SoftVideoDecoderOMXComponent::updatePortDefinitions(updateCrop, updateInputSize);
374
375    /* We have to align our width and height - this should affect stride! */
376    OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kOutputPortIndex)->mDef;
377    def->format.video.nStride = align(def->format.video.nStride, 16);
378    def->format.video.nSliceHeight = align(def->format.video.nSliceHeight, 16);
379    def->nBufferSize = (def->format.video.nStride * def->format.video.nSliceHeight * 3) / 2;
380}
381
382}  // namespace android
383
384android::SoftOMXComponent *createSoftOMXComponent(
385        const char *name, const OMX_CALLBACKTYPE *callbacks,
386        OMX_PTR appData, OMX_COMPONENTTYPE **component) {
387    using namespace android;
388    if (!strcmp(name, "OMX.google.h263.decoder")) {
389        return new android::SoftMPEG4(
390                name, "video_decoder.h263", OMX_VIDEO_CodingH263,
391                kH263ProfileLevels, ARRAY_SIZE(kH263ProfileLevels),
392                callbacks, appData, component);
393    } else if (!strcmp(name, "OMX.google.mpeg4.decoder")) {
394        return new android::SoftMPEG4(
395                name, "video_decoder.mpeg4", OMX_VIDEO_CodingMPEG4,
396                kM4VProfileLevels, ARRAY_SIZE(kM4VProfileLevels),
397                callbacks, appData, component);
398    } else {
399        CHECK(!"Unknown component");
400    }
401    return NULL;
402}
403
404