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