SoftMPEG4.cpp revision a0940a569f2bc24b00dc10ce0fa7658b1dc3a3a5
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
107        PortInfo *port = editPortInfo(1);
108
109        OMX_BUFFERHEADERTYPE *outHeader =
110            port->mBuffers.editItemAt(mNumSamplesOutput & 1).mHeader;
111
112        if ((inHeader->nFlags & OMX_BUFFERFLAG_EOS) && inHeader->nFilledLen == 0) {
113            inQueue.erase(inQueue.begin());
114            inInfo->mOwnedByUs = false;
115            notifyEmptyBufferDone(inHeader);
116
117            ++mInputBufferCount;
118
119            outHeader->nFilledLen = 0;
120            outHeader->nFlags = OMX_BUFFERFLAG_EOS;
121
122            List<BufferInfo *>::iterator it = outQueue.begin();
123            while ((*it)->mHeader != outHeader) {
124                ++it;
125            }
126
127            BufferInfo *outInfo = *it;
128            outInfo->mOwnedByUs = false;
129            outQueue.erase(it);
130            outInfo = NULL;
131
132            notifyFillBufferDone(outHeader);
133            outHeader = NULL;
134            return;
135        }
136
137        uint8_t *bitstream = inHeader->pBuffer + inHeader->nOffset;
138        uint32_t *start_code = (uint32_t *)bitstream;
139        bool volHeader = *start_code == 0xB0010000;
140        if (volHeader) {
141            PVCleanUpVideoDecoder(mHandle);
142            mInitialized = false;
143        }
144
145        if (!mInitialized) {
146            uint8_t *vol_data[1];
147            int32_t vol_size = 0;
148
149            vol_data[0] = NULL;
150
151            if ((inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) || volHeader) {
152                vol_data[0] = bitstream;
153                vol_size = inHeader->nFilledLen;
154            }
155
156            MP4DecodingMode mode =
157                (mMode == MODE_MPEG4) ? MPEG4_MODE : H263_MODE;
158
159            Bool success = PVInitVideoDecoder(
160                    mHandle, vol_data, &vol_size, 1,
161                    outputBufferWidth(), outputBufferHeight(), mode);
162
163            if (!success) {
164                ALOGW("PVInitVideoDecoder failed. Unsupported content?");
165
166                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
167                mSignalledError = true;
168                return;
169            }
170
171            MP4DecodingMode actualMode = PVGetDecBitstreamMode(mHandle);
172            if (mode != actualMode) {
173                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
174                mSignalledError = true;
175                return;
176            }
177
178            PVSetPostProcType((VideoDecControls *) mHandle, 0);
179
180            bool hasFrameData = false;
181            if (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
182                inInfo->mOwnedByUs = false;
183                inQueue.erase(inQueue.begin());
184                inInfo = NULL;
185                notifyEmptyBufferDone(inHeader);
186                inHeader = NULL;
187            } else if (volHeader) {
188                hasFrameData = true;
189            }
190
191            mInitialized = true;
192
193            if (mode == MPEG4_MODE && handlePortSettingsChange()) {
194                return;
195            }
196
197            if (!hasFrameData) {
198                continue;
199            }
200        }
201
202        if (!mFramesConfigured) {
203            PortInfo *port = editPortInfo(1);
204            OMX_BUFFERHEADERTYPE *outHeader = port->mBuffers.editItemAt(1).mHeader;
205
206            PVSetReferenceYUV(mHandle, outHeader->pBuffer);
207
208            mFramesConfigured = true;
209        }
210
211        uint32_t useExtTimestamp = (inHeader->nOffset == 0);
212
213        // decoder deals in ms (int32_t), OMX in us (int64_t)
214        // so use fake timestamp instead
215        uint32_t timestamp = 0xFFFFFFFF;
216        if (useExtTimestamp) {
217            mPvToOmxTimeMap.add(mPvTime, inHeader->nTimeStamp);
218            timestamp = mPvTime;
219            mPvTime++;
220        }
221
222        int32_t bufferSize = inHeader->nFilledLen;
223        int32_t tmp = bufferSize;
224
225        // The PV decoder is lying to us, sometimes it'll claim to only have
226        // consumed a subset of the buffer when it clearly consumed all of it.
227        // ignore whatever it says...
228        if (PVDecodeVideoFrame(
229                    mHandle, &bitstream, &timestamp, &tmp,
230                    &useExtTimestamp,
231                    outHeader->pBuffer) != PV_TRUE) {
232            ALOGE("failed to decode video frame.");
233
234            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
235            mSignalledError = true;
236            return;
237        }
238
239        // H263 doesn't have VOL header, the frame size information is in short header, i.e. the
240        // decoder may detect size change after PVDecodeVideoFrame.
241        if (handlePortSettingsChange()) {
242            return;
243        }
244
245        // decoder deals in ms, OMX in us.
246        outHeader->nTimeStamp = mPvToOmxTimeMap.valueFor(timestamp);
247        mPvToOmxTimeMap.removeItem(timestamp);
248
249        inHeader->nOffset += bufferSize;
250        inHeader->nFilledLen = 0;
251        if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
252            outHeader->nFlags = OMX_BUFFERFLAG_EOS;
253        } else {
254            outHeader->nFlags = 0;
255        }
256
257        if (inHeader->nFilledLen == 0) {
258            inInfo->mOwnedByUs = false;
259            inQueue.erase(inQueue.begin());
260            inInfo = NULL;
261            notifyEmptyBufferDone(inHeader);
262            inHeader = NULL;
263        }
264
265        ++mInputBufferCount;
266
267        outHeader->nOffset = 0;
268        outHeader->nFilledLen = (mWidth * mHeight * 3) / 2;
269
270        List<BufferInfo *>::iterator it = outQueue.begin();
271        while ((*it)->mHeader != outHeader) {
272            ++it;
273        }
274
275        BufferInfo *outInfo = *it;
276        outInfo->mOwnedByUs = false;
277        outQueue.erase(it);
278        outInfo = NULL;
279
280        notifyFillBufferDone(outHeader);
281        outHeader = NULL;
282
283        ++mNumSamplesOutput;
284    }
285}
286
287bool SoftMPEG4::handlePortSettingsChange() {
288    uint32_t disp_width, disp_height;
289    PVGetVideoDimensions(mHandle, (int32 *)&disp_width, (int32 *)&disp_height);
290
291    uint32_t buf_width, buf_height;
292    PVGetBufferDimensions(mHandle, (int32 *)&buf_width, (int32 *)&buf_height);
293
294    CHECK_LE(disp_width, buf_width);
295    CHECK_LE(disp_height, buf_height);
296
297    ALOGV("disp_width = %d, disp_height = %d, buf_width = %d, buf_height = %d",
298            disp_width, disp_height, buf_width, buf_height);
299
300    CropSettingsMode cropSettingsMode = kCropUnSet;
301    if (disp_width != buf_width || disp_height != buf_height) {
302        cropSettingsMode = kCropSet;
303
304        if (mCropWidth != disp_width || mCropHeight != disp_height) {
305            mCropLeft = 0;
306            mCropTop = 0;
307            mCropWidth = disp_width;
308            mCropHeight = disp_height;
309            cropSettingsMode = kCropChanged;
310        }
311    }
312
313    bool portWillReset = false;
314    const bool fakeStride = true;
315    SoftVideoDecoderOMXComponent::handlePortSettingsChange(
316            &portWillReset, buf_width, buf_height, cropSettingsMode, fakeStride);
317    if (portWillReset) {
318        if (mMode == MODE_H263) {
319            PVCleanUpVideoDecoder(mHandle);
320
321            uint8_t *vol_data[1];
322            int32_t vol_size = 0;
323
324            vol_data[0] = NULL;
325            if (!PVInitVideoDecoder(
326                    mHandle, vol_data, &vol_size, 1, outputBufferWidth(), outputBufferHeight(),
327                    H263_MODE)) {
328                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
329                mSignalledError = true;
330                return true;
331            }
332        }
333
334        mFramesConfigured = false;
335    }
336
337    return portWillReset;
338}
339
340void SoftMPEG4::onPortFlushCompleted(OMX_U32 portIndex) {
341    if (portIndex == 0 && mInitialized) {
342        CHECK_EQ((int)PVResetVideoDecoder(mHandle), (int)PV_TRUE);
343    }
344}
345
346void SoftMPEG4::onReset() {
347    SoftVideoDecoderOMXComponent::onReset();
348    mPvToOmxTimeMap.clear();
349    mSignalledError = false;
350    mFramesConfigured = false;
351    if (mInitialized) {
352        PVCleanUpVideoDecoder(mHandle);
353        mInitialized = false;
354    }
355}
356
357void SoftMPEG4::updatePortDefinitions(bool updateCrop, bool updateInputSize) {
358    SoftVideoDecoderOMXComponent::updatePortDefinitions(updateCrop, updateInputSize);
359
360    /* We have to align our width and height - this should affect stride! */
361    OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kOutputPortIndex)->mDef;
362    def->format.video.nStride = align(def->format.video.nStride, 16);
363    def->format.video.nSliceHeight = align(def->format.video.nSliceHeight, 16);
364    def->nBufferSize = (def->format.video.nStride * def->format.video.nSliceHeight * 3) / 2;
365}
366
367}  // namespace android
368
369android::SoftOMXComponent *createSoftOMXComponent(
370        const char *name, const OMX_CALLBACKTYPE *callbacks,
371        OMX_PTR appData, OMX_COMPONENTTYPE **component) {
372    using namespace android;
373    if (!strcmp(name, "OMX.google.h263.decoder")) {
374        return new android::SoftMPEG4(
375                name, "video_decoder.h263", OMX_VIDEO_CodingH263,
376                kH263ProfileLevels, ARRAY_SIZE(kH263ProfileLevels),
377                callbacks, appData, component);
378    } else if (!strcmp(name, "OMX.google.mpeg4.decoder")) {
379        return new android::SoftMPEG4(
380                name, "video_decoder.mpeg4", OMX_VIDEO_CodingMPEG4,
381                kM4VProfileLevels, ARRAY_SIZE(kM4VProfileLevels),
382                callbacks, appData, component);
383    } else {
384        CHECK(!"Unknown component");
385    }
386    return NULL;
387}
388
389