SoftMPEG4.cpp revision a585407bd04f2f4189dc393fc7e3f7f58d4f1a7a
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                LOGE("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) {
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                LOGW("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
424        // The PV decoder is lying to us, sometimes it'll claim to only have
425        // consumed a subset of the buffer when it clearly consumed all of it.
426        // ignore whatever it says...
427        int32_t tmp = bufferSize;
428
429        if (PVDecodeVideoFrame(
430                    mHandle, &bitstream, &timestamp, &tmp,
431                    &useExtTimestamp,
432                    outHeader->pBuffer) != PV_TRUE) {
433            LOGE("failed to decode video frame.");
434
435            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
436            mSignalledError = true;
437            return;
438        }
439
440        if (portSettingsChanged()) {
441            return;
442        }
443
444        // decoder deals in ms, OMX in us.
445        outHeader->nTimeStamp = timestamp * 1000;
446
447        CHECK_LE(bufferSize, inHeader->nFilledLen);
448        inHeader->nOffset += inHeader->nFilledLen - bufferSize;
449        inHeader->nFilledLen = bufferSize;
450
451        if (inHeader->nFilledLen == 0) {
452            inInfo->mOwnedByUs = false;
453            inQueue.erase(inQueue.begin());
454            inInfo = NULL;
455            notifyEmptyBufferDone(inHeader);
456            inHeader = NULL;
457        }
458
459        ++mInputBufferCount;
460
461        outHeader->nOffset = 0;
462        outHeader->nFilledLen = (mWidth * mHeight * 3) / 2;
463        outHeader->nFlags = 0;
464
465        List<BufferInfo *>::iterator it = outQueue.begin();
466        while ((*it)->mHeader != outHeader) {
467            ++it;
468        }
469
470        BufferInfo *outInfo = *it;
471        outInfo->mOwnedByUs = false;
472        outQueue.erase(it);
473        outInfo = NULL;
474
475        notifyFillBufferDone(outHeader);
476        outHeader = NULL;
477
478        ++mNumSamplesOutput;
479    }
480}
481
482bool SoftMPEG4::portSettingsChanged() {
483    int32_t disp_width, disp_height;
484    PVGetVideoDimensions(mHandle, &disp_width, &disp_height);
485
486    int32_t buf_width, buf_height;
487    PVGetBufferDimensions(mHandle, &buf_width, &buf_height);
488
489    CHECK_LE(disp_width, buf_width);
490    CHECK_LE(disp_height, buf_height);
491
492    ALOGV("disp_width = %d, disp_height = %d, buf_width = %d, buf_height = %d",
493            disp_width, disp_height, buf_width, buf_height);
494
495    if (mCropRight != disp_width - 1
496            || mCropBottom != disp_height - 1) {
497        mCropLeft = 0;
498        mCropTop = 0;
499        mCropRight = disp_width - 1;
500        mCropBottom = disp_height - 1;
501
502        notify(OMX_EventPortSettingsChanged,
503               1,
504               OMX_IndexConfigCommonOutputCrop,
505               NULL);
506    }
507
508    if (buf_width != mWidth || buf_height != mHeight) {
509        mWidth = buf_width;
510        mHeight = buf_height;
511
512        updatePortDefinitions();
513
514        if (mMode == MODE_H263) {
515            PVCleanUpVideoDecoder(mHandle);
516
517            uint8_t *vol_data[1];
518            int32_t vol_size = 0;
519
520            vol_data[0] = NULL;
521            if (!PVInitVideoDecoder(
522                    mHandle, vol_data, &vol_size, 1, mWidth, mHeight,
523                    H263_MODE)) {
524                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
525                mSignalledError = true;
526                return true;
527            }
528        }
529
530        mFramesConfigured = false;
531
532        notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
533        mOutputPortSettingsChange = AWAITING_DISABLED;
534        return true;
535    }
536
537    return false;
538}
539
540void SoftMPEG4::onPortFlushCompleted(OMX_U32 portIndex) {
541    if (portIndex == 0 && mInitialized) {
542        CHECK_EQ((int)PVResetVideoDecoder(mHandle), (int)PV_TRUE);
543    }
544}
545
546void SoftMPEG4::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
547    if (portIndex != 1) {
548        return;
549    }
550
551    switch (mOutputPortSettingsChange) {
552        case NONE:
553            break;
554
555        case AWAITING_DISABLED:
556        {
557            CHECK(!enabled);
558            mOutputPortSettingsChange = AWAITING_ENABLED;
559            break;
560        }
561
562        default:
563        {
564            CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED);
565            CHECK(enabled);
566            mOutputPortSettingsChange = NONE;
567            break;
568        }
569    }
570}
571
572void SoftMPEG4::updatePortDefinitions() {
573    OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(0)->mDef;
574    def->format.video.nFrameWidth = mWidth;
575    def->format.video.nFrameHeight = mHeight;
576    def->format.video.nStride = def->format.video.nFrameWidth;
577    def->format.video.nSliceHeight = def->format.video.nFrameHeight;
578
579    def = &editPortInfo(1)->mDef;
580    def->format.video.nFrameWidth = mWidth;
581    def->format.video.nFrameHeight = mHeight;
582    def->format.video.nStride = def->format.video.nFrameWidth;
583    def->format.video.nSliceHeight = def->format.video.nFrameHeight;
584
585    def->nBufferSize =
586        (((def->format.video.nFrameWidth + 15) & -16)
587            * ((def->format.video.nFrameHeight + 15) & -16) * 3) / 2;
588}
589
590}  // namespace android
591
592android::SoftOMXComponent *createSoftOMXComponent(
593        const char *name, const OMX_CALLBACKTYPE *callbacks,
594        OMX_PTR appData, OMX_COMPONENTTYPE **component) {
595    return new android::SoftMPEG4(name, callbacks, appData, component);
596}
597
598