SoftMPEG4.cpp revision 4c44e9fed87ff6363393f2559b150291242da247
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/MediaDefs.h>
25#include <media/stagefright/MediaErrors.h>
26#include <media/IOMX.h>
27
28#include "mp4dec_api.h"
29
30namespace android {
31
32static const CodecProfileLevel kM4VProfileLevels[] = {
33    { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level0 },
34    { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level0b },
35    { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level1 },
36    { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level2 },
37    { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level3 },
38};
39
40static const CodecProfileLevel kH263ProfileLevels[] = {
41    { OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level10 },
42    { OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level20 },
43    { OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level30 },
44    { OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level45 },
45    { OMX_VIDEO_H263ProfileISWV2,    OMX_VIDEO_H263Level10 },
46    { OMX_VIDEO_H263ProfileISWV2,    OMX_VIDEO_H263Level20 },
47    { OMX_VIDEO_H263ProfileISWV2,    OMX_VIDEO_H263Level30 },
48    { OMX_VIDEO_H263ProfileISWV2,    OMX_VIDEO_H263Level45 },
49};
50
51template<class T>
52static void InitOMXParams(T *params) {
53    params->nSize = sizeof(T);
54    params->nVersion.s.nVersionMajor = 1;
55    params->nVersion.s.nVersionMinor = 0;
56    params->nVersion.s.nRevision = 0;
57    params->nVersion.s.nStep = 0;
58}
59
60SoftMPEG4::SoftMPEG4(
61        const char *name,
62        const OMX_CALLBACKTYPE *callbacks,
63        OMX_PTR appData,
64        OMX_COMPONENTTYPE **component)
65    : SimpleSoftOMXComponent(name, callbacks, appData, component),
66      mMode(MODE_MPEG4),
67      mHandle(new tagvideoDecControls),
68      mInputBufferCount(0),
69      mWidth(352),
70      mHeight(288),
71      mCropLeft(0),
72      mCropTop(0),
73      mCropRight(mWidth - 1),
74      mCropBottom(mHeight - 1),
75      mSignalledError(false),
76      mInitialized(false),
77      mFramesConfigured(false),
78      mNumSamplesOutput(0),
79      mOutputPortSettingsChange(NONE) {
80    if (!strcmp(name, "OMX.google.h263.decoder")) {
81        mMode = MODE_H263;
82    } else {
83        CHECK(!strcmp(name, "OMX.google.mpeg4.decoder"));
84    }
85
86    initPorts();
87    CHECK_EQ(initDecoder(), (status_t)OK);
88}
89
90SoftMPEG4::~SoftMPEG4() {
91    if (mInitialized) {
92        PVCleanUpVideoDecoder(mHandle);
93    }
94
95    delete mHandle;
96    mHandle = NULL;
97}
98
99void SoftMPEG4::initPorts() {
100    OMX_PARAM_PORTDEFINITIONTYPE def;
101    InitOMXParams(&def);
102
103    def.nPortIndex = 0;
104    def.eDir = OMX_DirInput;
105    def.nBufferCountMin = kNumInputBuffers;
106    def.nBufferCountActual = def.nBufferCountMin;
107    def.nBufferSize = 8192;
108    def.bEnabled = OMX_TRUE;
109    def.bPopulated = OMX_FALSE;
110    def.eDomain = OMX_PortDomainVideo;
111    def.bBuffersContiguous = OMX_FALSE;
112    def.nBufferAlignment = 1;
113
114    def.format.video.cMIMEType =
115        (mMode == MODE_MPEG4)
116            ? const_cast<char *>(MEDIA_MIMETYPE_VIDEO_MPEG4)
117            : const_cast<char *>(MEDIA_MIMETYPE_VIDEO_H263);
118
119    def.format.video.pNativeRender = NULL;
120    def.format.video.nFrameWidth = mWidth;
121    def.format.video.nFrameHeight = mHeight;
122    def.format.video.nStride = def.format.video.nFrameWidth;
123    def.format.video.nSliceHeight = def.format.video.nFrameHeight;
124    def.format.video.nBitrate = 0;
125    def.format.video.xFramerate = 0;
126    def.format.video.bFlagErrorConcealment = OMX_FALSE;
127
128    def.format.video.eCompressionFormat =
129        mMode == MODE_MPEG4 ? OMX_VIDEO_CodingMPEG4 : OMX_VIDEO_CodingH263;
130
131    def.format.video.eColorFormat = OMX_COLOR_FormatUnused;
132    def.format.video.pNativeWindow = NULL;
133
134    addPort(def);
135
136    def.nPortIndex = 1;
137    def.eDir = OMX_DirOutput;
138    def.nBufferCountMin = kNumOutputBuffers;
139    def.nBufferCountActual = def.nBufferCountMin;
140    def.bEnabled = OMX_TRUE;
141    def.bPopulated = OMX_FALSE;
142    def.eDomain = OMX_PortDomainVideo;
143    def.bBuffersContiguous = OMX_FALSE;
144    def.nBufferAlignment = 2;
145
146    def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_RAW);
147    def.format.video.pNativeRender = NULL;
148    def.format.video.nFrameWidth = mWidth;
149    def.format.video.nFrameHeight = mHeight;
150    def.format.video.nStride = def.format.video.nFrameWidth;
151    def.format.video.nSliceHeight = def.format.video.nFrameHeight;
152    def.format.video.nBitrate = 0;
153    def.format.video.xFramerate = 0;
154    def.format.video.bFlagErrorConcealment = OMX_FALSE;
155    def.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused;
156    def.format.video.eColorFormat = OMX_COLOR_FormatYUV420Planar;
157    def.format.video.pNativeWindow = NULL;
158
159    def.nBufferSize =
160        (def.format.video.nFrameWidth * def.format.video.nFrameHeight * 3) / 2;
161
162    addPort(def);
163}
164
165status_t SoftMPEG4::initDecoder() {
166    memset(mHandle, 0, sizeof(tagvideoDecControls));
167    return OK;
168}
169
170OMX_ERRORTYPE SoftMPEG4::internalGetParameter(
171        OMX_INDEXTYPE index, OMX_PTR params) {
172    switch (index) {
173        case OMX_IndexParamVideoPortFormat:
174        {
175            OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams =
176                (OMX_VIDEO_PARAM_PORTFORMATTYPE *)params;
177
178            if (formatParams->nPortIndex > 1) {
179                return OMX_ErrorUndefined;
180            }
181
182            if (formatParams->nIndex != 0) {
183                return OMX_ErrorNoMore;
184            }
185
186            if (formatParams->nPortIndex == 0) {
187                formatParams->eCompressionFormat =
188                    (mMode == MODE_MPEG4)
189                        ? OMX_VIDEO_CodingMPEG4 : OMX_VIDEO_CodingH263;
190
191                formatParams->eColorFormat = OMX_COLOR_FormatUnused;
192                formatParams->xFramerate = 0;
193            } else {
194                CHECK_EQ(formatParams->nPortIndex, 1u);
195
196                formatParams->eCompressionFormat = OMX_VIDEO_CodingUnused;
197                formatParams->eColorFormat = OMX_COLOR_FormatYUV420Planar;
198                formatParams->xFramerate = 0;
199            }
200
201            return OMX_ErrorNone;
202        }
203
204        case OMX_IndexParamVideoProfileLevelQuerySupported:
205        {
206            OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileLevel =
207                    (OMX_VIDEO_PARAM_PROFILELEVELTYPE *) params;
208
209            if (profileLevel->nPortIndex != 0) {  // Input port only
210                ALOGE("Invalid port index: %ld", profileLevel->nPortIndex);
211                return OMX_ErrorUnsupportedIndex;
212            }
213
214            size_t index = profileLevel->nProfileIndex;
215            if (mMode == MODE_H263) {
216                size_t nProfileLevels =
217                    sizeof(kH263ProfileLevels) / sizeof(kH263ProfileLevels[0]);
218                if (index >= nProfileLevels) {
219                    return OMX_ErrorNoMore;
220                }
221
222                profileLevel->eProfile = kH263ProfileLevels[index].mProfile;
223                profileLevel->eLevel = kH263ProfileLevels[index].mLevel;
224            } else {
225                size_t nProfileLevels =
226                    sizeof(kM4VProfileLevels) / sizeof(kM4VProfileLevels[0]);
227                if (index >= nProfileLevels) {
228                    return OMX_ErrorNoMore;
229                }
230
231                profileLevel->eProfile = kM4VProfileLevels[index].mProfile;
232                profileLevel->eLevel = kM4VProfileLevels[index].mLevel;
233            }
234            return OMX_ErrorNone;
235        }
236
237        default:
238            return SimpleSoftOMXComponent::internalGetParameter(index, params);
239    }
240}
241
242OMX_ERRORTYPE SoftMPEG4::internalSetParameter(
243        OMX_INDEXTYPE index, const OMX_PTR params) {
244    switch (index) {
245        case OMX_IndexParamStandardComponentRole:
246        {
247            const OMX_PARAM_COMPONENTROLETYPE *roleParams =
248                (const OMX_PARAM_COMPONENTROLETYPE *)params;
249
250            if (mMode == MODE_MPEG4) {
251                if (strncmp((const char *)roleParams->cRole,
252                            "video_decoder.mpeg4",
253                            OMX_MAX_STRINGNAME_SIZE - 1)) {
254                    return OMX_ErrorUndefined;
255                }
256            } else {
257                if (strncmp((const char *)roleParams->cRole,
258                            "video_decoder.h263",
259                            OMX_MAX_STRINGNAME_SIZE - 1)) {
260                    return OMX_ErrorUndefined;
261                }
262            }
263
264            return OMX_ErrorNone;
265        }
266
267        case OMX_IndexParamVideoPortFormat:
268        {
269            OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams =
270                (OMX_VIDEO_PARAM_PORTFORMATTYPE *)params;
271
272            if (formatParams->nPortIndex > 1) {
273                return OMX_ErrorUndefined;
274            }
275
276            if (formatParams->nIndex != 0) {
277                return OMX_ErrorNoMore;
278            }
279
280            return OMX_ErrorNone;
281        }
282
283        default:
284            return SimpleSoftOMXComponent::internalSetParameter(index, params);
285    }
286}
287
288OMX_ERRORTYPE SoftMPEG4::getConfig(
289        OMX_INDEXTYPE index, OMX_PTR params) {
290    switch (index) {
291        case OMX_IndexConfigCommonOutputCrop:
292        {
293            OMX_CONFIG_RECTTYPE *rectParams = (OMX_CONFIG_RECTTYPE *)params;
294
295            if (rectParams->nPortIndex != 1) {
296                return OMX_ErrorUndefined;
297            }
298
299            rectParams->nLeft = mCropLeft;
300            rectParams->nTop = mCropTop;
301            rectParams->nWidth = mCropRight - mCropLeft + 1;
302            rectParams->nHeight = mCropBottom - mCropTop + 1;
303
304            return OMX_ErrorNone;
305        }
306
307        default:
308            return OMX_ErrorUnsupportedIndex;
309    }
310}
311
312void SoftMPEG4::onQueueFilled(OMX_U32 portIndex) {
313    if (mSignalledError || mOutputPortSettingsChange != NONE) {
314        return;
315    }
316
317    List<BufferInfo *> &inQueue = getPortQueue(0);
318    List<BufferInfo *> &outQueue = getPortQueue(1);
319
320    while (!inQueue.empty() && outQueue.size() == kNumOutputBuffers) {
321        BufferInfo *inInfo = *inQueue.begin();
322        OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
323
324        PortInfo *port = editPortInfo(1);
325
326        OMX_BUFFERHEADERTYPE *outHeader =
327            port->mBuffers.editItemAt(mNumSamplesOutput & 1).mHeader;
328
329        if ((inHeader->nFlags & OMX_BUFFERFLAG_EOS) && inHeader->nFilledLen == 0) {
330            inQueue.erase(inQueue.begin());
331            inInfo->mOwnedByUs = false;
332            notifyEmptyBufferDone(inHeader);
333
334            ++mInputBufferCount;
335
336            outHeader->nFilledLen = 0;
337            outHeader->nFlags = OMX_BUFFERFLAG_EOS;
338
339            List<BufferInfo *>::iterator it = outQueue.begin();
340            while ((*it)->mHeader != outHeader) {
341                ++it;
342            }
343
344            BufferInfo *outInfo = *it;
345            outInfo->mOwnedByUs = false;
346            outQueue.erase(it);
347            outInfo = NULL;
348
349            notifyFillBufferDone(outHeader);
350            outHeader = NULL;
351            return;
352        }
353
354        uint8_t *bitstream = inHeader->pBuffer + inHeader->nOffset;
355
356        if (!mInitialized) {
357            uint8_t *vol_data[1];
358            int32_t vol_size = 0;
359
360            vol_data[0] = NULL;
361
362            if (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
363                vol_data[0] = bitstream;
364                vol_size = inHeader->nFilledLen;
365            }
366
367            MP4DecodingMode mode =
368                (mMode == MODE_MPEG4) ? MPEG4_MODE : H263_MODE;
369
370            Bool success = PVInitVideoDecoder(
371                    mHandle, vol_data, &vol_size, 1, mWidth, mHeight, mode);
372
373            if (!success) {
374                ALOGW("PVInitVideoDecoder failed. Unsupported content?");
375
376                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
377                mSignalledError = true;
378                return;
379            }
380
381            MP4DecodingMode actualMode = PVGetDecBitstreamMode(mHandle);
382            if (mode != actualMode) {
383                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
384                mSignalledError = true;
385                return;
386            }
387
388            PVSetPostProcType((VideoDecControls *) mHandle, 0);
389
390            if (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
391                inInfo->mOwnedByUs = false;
392                inQueue.erase(inQueue.begin());
393                inInfo = NULL;
394                notifyEmptyBufferDone(inHeader);
395                inHeader = NULL;
396            }
397
398            mInitialized = true;
399
400            if (mode == MPEG4_MODE && portSettingsChanged()) {
401                return;
402            }
403
404            continue;
405        }
406
407        if (!mFramesConfigured) {
408            PortInfo *port = editPortInfo(1);
409            OMX_BUFFERHEADERTYPE *outHeader = port->mBuffers.editItemAt(1).mHeader;
410
411            PVSetReferenceYUV(mHandle, outHeader->pBuffer);
412
413            mFramesConfigured = true;
414        }
415
416        uint32_t useExtTimestamp = (inHeader->nOffset == 0);
417
418        // decoder deals in ms, OMX in us.
419        uint32_t timestamp =
420            useExtTimestamp ? (inHeader->nTimeStamp + 500) / 1000 : 0xFFFFFFFF;
421
422        int32_t bufferSize = inHeader->nFilledLen;
423        int32_t tmp = bufferSize;
424
425        // The PV decoder is lying to us, sometimes it'll claim to only have
426        // consumed a subset of the buffer when it clearly consumed all of it.
427        // ignore whatever it says...
428        if (PVDecodeVideoFrame(
429                    mHandle, &bitstream, &timestamp, &tmp,
430                    &useExtTimestamp,
431                    outHeader->pBuffer) != PV_TRUE) {
432            ALOGE("failed to decode video frame.");
433
434            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
435            mSignalledError = true;
436            return;
437        }
438
439        if (portSettingsChanged()) {
440            return;
441        }
442
443        // decoder deals in ms, OMX in us.
444        outHeader->nTimeStamp = timestamp * 1000;
445
446        inHeader->nOffset += bufferSize;
447        inHeader->nFilledLen = 0;
448        if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
449            outHeader->nFlags = OMX_BUFFERFLAG_EOS;
450        } else {
451            outHeader->nFlags = 0;
452        }
453
454        if (inHeader->nFilledLen == 0) {
455            inInfo->mOwnedByUs = false;
456            inQueue.erase(inQueue.begin());
457            inInfo = NULL;
458            notifyEmptyBufferDone(inHeader);
459            inHeader = NULL;
460        }
461
462        ++mInputBufferCount;
463
464        outHeader->nOffset = 0;
465        outHeader->nFilledLen = (mWidth * mHeight * 3) / 2;
466
467        List<BufferInfo *>::iterator it = outQueue.begin();
468        while ((*it)->mHeader != outHeader) {
469            ++it;
470        }
471
472        BufferInfo *outInfo = *it;
473        outInfo->mOwnedByUs = false;
474        outQueue.erase(it);
475        outInfo = NULL;
476
477        notifyFillBufferDone(outHeader);
478        outHeader = NULL;
479
480        ++mNumSamplesOutput;
481    }
482}
483
484bool SoftMPEG4::portSettingsChanged() {
485    int32_t disp_width, disp_height;
486    PVGetVideoDimensions(mHandle, &disp_width, &disp_height);
487
488    int32_t buf_width, buf_height;
489    PVGetBufferDimensions(mHandle, &buf_width, &buf_height);
490
491    CHECK_LE(disp_width, buf_width);
492    CHECK_LE(disp_height, buf_height);
493
494    ALOGV("disp_width = %d, disp_height = %d, buf_width = %d, buf_height = %d",
495            disp_width, disp_height, buf_width, buf_height);
496
497    if (mCropRight != disp_width - 1
498            || mCropBottom != disp_height - 1) {
499        mCropLeft = 0;
500        mCropTop = 0;
501        mCropRight = disp_width - 1;
502        mCropBottom = disp_height - 1;
503
504        notify(OMX_EventPortSettingsChanged,
505               1,
506               OMX_IndexConfigCommonOutputCrop,
507               NULL);
508    }
509
510    if (buf_width != mWidth || buf_height != mHeight) {
511        mWidth = buf_width;
512        mHeight = buf_height;
513
514        updatePortDefinitions();
515
516        if (mMode == MODE_H263) {
517            PVCleanUpVideoDecoder(mHandle);
518
519            uint8_t *vol_data[1];
520            int32_t vol_size = 0;
521
522            vol_data[0] = NULL;
523            if (!PVInitVideoDecoder(
524                    mHandle, vol_data, &vol_size, 1, mWidth, mHeight,
525                    H263_MODE)) {
526                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
527                mSignalledError = true;
528                return true;
529            }
530        }
531
532        mFramesConfigured = false;
533
534        notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
535        mOutputPortSettingsChange = AWAITING_DISABLED;
536        return true;
537    }
538
539    return false;
540}
541
542void SoftMPEG4::onPortFlushCompleted(OMX_U32 portIndex) {
543    if (portIndex == 0 && mInitialized) {
544        CHECK_EQ((int)PVResetVideoDecoder(mHandle), (int)PV_TRUE);
545    }
546}
547
548void SoftMPEG4::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
549    if (portIndex != 1) {
550        return;
551    }
552
553    switch (mOutputPortSettingsChange) {
554        case NONE:
555            break;
556
557        case AWAITING_DISABLED:
558        {
559            CHECK(!enabled);
560            mOutputPortSettingsChange = AWAITING_ENABLED;
561            break;
562        }
563
564        default:
565        {
566            CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED);
567            CHECK(enabled);
568            mOutputPortSettingsChange = NONE;
569            break;
570        }
571    }
572}
573
574void SoftMPEG4::updatePortDefinitions() {
575    OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(0)->mDef;
576    def->format.video.nFrameWidth = mWidth;
577    def->format.video.nFrameHeight = mHeight;
578    def->format.video.nStride = def->format.video.nFrameWidth;
579    def->format.video.nSliceHeight = def->format.video.nFrameHeight;
580
581    def = &editPortInfo(1)->mDef;
582    def->format.video.nFrameWidth = mWidth;
583    def->format.video.nFrameHeight = mHeight;
584    def->format.video.nStride = def->format.video.nFrameWidth;
585    def->format.video.nSliceHeight = def->format.video.nFrameHeight;
586
587    def->nBufferSize =
588        (((def->format.video.nFrameWidth + 15) & -16)
589            * ((def->format.video.nFrameHeight + 15) & -16) * 3) / 2;
590}
591
592}  // namespace android
593
594android::SoftOMXComponent *createSoftOMXComponent(
595        const char *name, const OMX_CALLBACKTYPE *callbacks,
596        OMX_PTR appData, OMX_COMPONENTTYPE **component) {
597    return new android::SoftMPEG4(name, callbacks, appData, component);
598}
599
600