[go: nahoru, domu]

1/*
2 * Copyright (C) 2013 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#include <inttypes.h>
18
19//#define LOG_NDEBUG 0
20#define LOG_TAG "SoftVideoDecoderOMXComponent"
21#include <utils/Log.h>
22
23#include "include/SoftVideoDecoderOMXComponent.h"
24
25#include <media/hardware/HardwareAPI.h>
26#include <media/stagefright/foundation/ADebug.h>
27#include <media/stagefright/foundation/ALooper.h>
28#include <media/stagefright/foundation/AMessage.h>
29#include <media/stagefright/foundation/AUtils.h>
30#include <media/stagefright/MediaDefs.h>
31
32namespace android {
33
34template<class T>
35static void InitOMXParams(T *params) {
36    params->nSize = sizeof(T);
37    params->nVersion.s.nVersionMajor = 1;
38    params->nVersion.s.nVersionMinor = 0;
39    params->nVersion.s.nRevision = 0;
40    params->nVersion.s.nStep = 0;
41}
42
43SoftVideoDecoderOMXComponent::SoftVideoDecoderOMXComponent(
44        const char *name,
45        const char *componentRole,
46        OMX_VIDEO_CODINGTYPE codingType,
47        const CodecProfileLevel *profileLevels,
48        size_t numProfileLevels,
49        int32_t width,
50        int32_t height,
51        const OMX_CALLBACKTYPE *callbacks,
52        OMX_PTR appData,
53        OMX_COMPONENTTYPE **component)
54        : SimpleSoftOMXComponent(name, callbacks, appData, component),
55        mIsAdaptive(false),
56        mAdaptiveMaxWidth(0),
57        mAdaptiveMaxHeight(0),
58        mWidth(width),
59        mHeight(height),
60        mCropLeft(0),
61        mCropTop(0),
62        mCropWidth(width),
63        mCropHeight(height),
64        mOutputPortSettingsChange(NONE),
65        mMinInputBufferSize(384), // arbitrary, using one uncompressed macroblock
66        mMinCompressionRatio(1),  // max input size is normally the output size
67        mComponentRole(componentRole),
68        mCodingType(codingType),
69        mProfileLevels(profileLevels),
70        mNumProfileLevels(numProfileLevels) {
71}
72
73void SoftVideoDecoderOMXComponent::initPorts(
74        OMX_U32 numInputBuffers,
75        OMX_U32 inputBufferSize,
76        OMX_U32 numOutputBuffers,
77        const char *mimeType,
78        OMX_U32 minCompressionRatio) {
79    mMinInputBufferSize = inputBufferSize;
80    mMinCompressionRatio = minCompressionRatio;
81
82    OMX_PARAM_PORTDEFINITIONTYPE def;
83    InitOMXParams(&def);
84
85    def.nPortIndex = kInputPortIndex;
86    def.eDir = OMX_DirInput;
87    def.nBufferCountMin = numInputBuffers;
88    def.nBufferCountActual = def.nBufferCountMin;
89    def.nBufferSize = inputBufferSize;
90    def.bEnabled = OMX_TRUE;
91    def.bPopulated = OMX_FALSE;
92    def.eDomain = OMX_PortDomainVideo;
93    def.bBuffersContiguous = OMX_FALSE;
94    def.nBufferAlignment = 1;
95
96    def.format.video.cMIMEType = const_cast<char *>(mimeType);
97    def.format.video.pNativeRender = NULL;
98    /* size is initialized in updatePortDefinitions() */
99    def.format.video.nBitrate = 0;
100    def.format.video.xFramerate = 0;
101    def.format.video.bFlagErrorConcealment = OMX_FALSE;
102    def.format.video.eCompressionFormat = mCodingType;
103    def.format.video.eColorFormat = OMX_COLOR_FormatUnused;
104    def.format.video.pNativeWindow = NULL;
105
106    addPort(def);
107
108    def.nPortIndex = kOutputPortIndex;
109    def.eDir = OMX_DirOutput;
110    def.nBufferCountMin = numOutputBuffers;
111    def.nBufferCountActual = def.nBufferCountMin;
112    def.bEnabled = OMX_TRUE;
113    def.bPopulated = OMX_FALSE;
114    def.eDomain = OMX_PortDomainVideo;
115    def.bBuffersContiguous = OMX_FALSE;
116    def.nBufferAlignment = 2;
117
118    def.format.video.cMIMEType = const_cast<char *>("video/raw");
119    def.format.video.pNativeRender = NULL;
120    /* size is initialized in updatePortDefinitions() */
121    def.format.video.nBitrate = 0;
122    def.format.video.xFramerate = 0;
123    def.format.video.bFlagErrorConcealment = OMX_FALSE;
124    def.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused;
125    def.format.video.eColorFormat = OMX_COLOR_FormatYUV420Planar;
126    def.format.video.pNativeWindow = NULL;
127
128    addPort(def);
129
130    updatePortDefinitions(true /* updateCrop */, true /* updateInputSize */);
131}
132
133void SoftVideoDecoderOMXComponent::updatePortDefinitions(bool updateCrop, bool updateInputSize) {
134    OMX_PARAM_PORTDEFINITIONTYPE *outDef = &editPortInfo(kOutputPortIndex)->mDef;
135    outDef->format.video.nFrameWidth = outputBufferWidth();
136    outDef->format.video.nFrameHeight = outputBufferHeight();
137    outDef->format.video.nStride = outDef->format.video.nFrameWidth;
138    outDef->format.video.nSliceHeight = outDef->format.video.nFrameHeight;
139
140    outDef->nBufferSize =
141        (outDef->format.video.nStride * outDef->format.video.nSliceHeight * 3) / 2;
142
143    OMX_PARAM_PORTDEFINITIONTYPE *inDef = &editPortInfo(kInputPortIndex)->mDef;
144    inDef->format.video.nFrameWidth = mWidth;
145    inDef->format.video.nFrameHeight = mHeight;
146    // input port is compressed, hence it has no stride
147    inDef->format.video.nStride = 0;
148    inDef->format.video.nSliceHeight = 0;
149
150    // when output format changes, input buffer size does not actually change
151    if (updateInputSize) {
152        inDef->nBufferSize = max(
153                outDef->nBufferSize / mMinCompressionRatio,
154                max(mMinInputBufferSize, inDef->nBufferSize));
155    }
156
157    if (updateCrop) {
158        mCropLeft = 0;
159        mCropTop = 0;
160        mCropWidth = mWidth;
161        mCropHeight = mHeight;
162    }
163}
164
165
166uint32_t SoftVideoDecoderOMXComponent::outputBufferWidth() {
167    return mIsAdaptive ? mAdaptiveMaxWidth : mWidth;
168}
169
170uint32_t SoftVideoDecoderOMXComponent::outputBufferHeight() {
171    return mIsAdaptive ? mAdaptiveMaxHeight : mHeight;
172}
173
174void SoftVideoDecoderOMXComponent::handlePortSettingsChange(
175        bool *portWillReset, uint32_t width, uint32_t height,
176        CropSettingsMode cropSettingsMode, bool fakeStride) {
177    *portWillReset = false;
178    bool sizeChanged = (width != mWidth || height != mHeight);
179    bool updateCrop = (cropSettingsMode == kCropUnSet);
180    bool cropChanged = (cropSettingsMode == kCropChanged);
181    bool strideChanged = false;
182    if (fakeStride) {
183        OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kOutputPortIndex)->mDef;
184        if (def->format.video.nStride != (OMX_S32)width
185                || def->format.video.nSliceHeight != (OMX_U32)height) {
186            strideChanged = true;
187        }
188    }
189
190    if (sizeChanged || cropChanged || strideChanged) {
191        mWidth = width;
192        mHeight = height;
193
194        if ((sizeChanged && !mIsAdaptive)
195            || width > mAdaptiveMaxWidth
196            || height > mAdaptiveMaxHeight) {
197            if (mIsAdaptive) {
198                if (width > mAdaptiveMaxWidth) {
199                    mAdaptiveMaxWidth = width;
200                }
201                if (height > mAdaptiveMaxHeight) {
202                    mAdaptiveMaxHeight = height;
203                }
204            }
205            updatePortDefinitions(updateCrop);
206            notify(OMX_EventPortSettingsChanged, kOutputPortIndex, 0, NULL);
207            mOutputPortSettingsChange = AWAITING_DISABLED;
208            *portWillReset = true;
209        } else {
210            updatePortDefinitions(updateCrop);
211
212            if (fakeStride) {
213                // MAJOR HACK that is not pretty, it's just to fool the renderer to read the correct
214                // data.
215                // Some software decoders (e.g. SoftMPEG4) fill decoded frame directly to output
216                // buffer without considering the output buffer stride and slice height. So this is
217                // used to signal how the buffer is arranged.  The alternative is to re-arrange the
218                // output buffer in SoftMPEG4, but that results in memcopies.
219                OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kOutputPortIndex)->mDef;
220                def->format.video.nStride = mWidth;
221                def->format.video.nSliceHeight = mHeight;
222            }
223
224            notify(OMX_EventPortSettingsChanged, kOutputPortIndex,
225                   OMX_IndexConfigCommonOutputCrop, NULL);
226        }
227    }
228}
229
230void SoftVideoDecoderOMXComponent::copyYV12FrameToOutputBuffer(
231        uint8_t *dst, const uint8_t *srcY, const uint8_t *srcU, const uint8_t *srcV,
232        size_t srcYStride, size_t srcUStride, size_t srcVStride) {
233    size_t dstYStride = outputBufferWidth();
234    size_t dstUVStride = dstYStride / 2;
235    size_t dstHeight = outputBufferHeight();
236    uint8_t *dstStart = dst;
237
238    for (size_t i = 0; i < mHeight; ++i) {
239         memcpy(dst, srcY, mWidth);
240         srcY += srcYStride;
241         dst += dstYStride;
242    }
243
244    dst = dstStart + dstYStride * dstHeight;
245    for (size_t i = 0; i < mHeight / 2; ++i) {
246         memcpy(dst, srcU, mWidth / 2);
247         srcU += srcUStride;
248         dst += dstUVStride;
249    }
250
251    dst = dstStart + (5 * dstYStride * dstHeight) / 4;
252    for (size_t i = 0; i < mHeight / 2; ++i) {
253         memcpy(dst, srcV, mWidth / 2);
254         srcV += srcVStride;
255         dst += dstUVStride;
256    }
257}
258
259OMX_ERRORTYPE SoftVideoDecoderOMXComponent::internalGetParameter(
260        OMX_INDEXTYPE index, OMX_PTR params) {
261    switch (index) {
262        case OMX_IndexParamVideoPortFormat:
263        {
264            OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams =
265                (OMX_VIDEO_PARAM_PORTFORMATTYPE *)params;
266
267            if (!isValidOMXParam(formatParams)) {
268                return OMX_ErrorBadParameter;
269            }
270
271            if (formatParams->nPortIndex > kMaxPortIndex) {
272                return OMX_ErrorBadPortIndex;
273            }
274
275            if (formatParams->nIndex != 0) {
276                return OMX_ErrorNoMore;
277            }
278
279            if (formatParams->nPortIndex == kInputPortIndex) {
280                formatParams->eCompressionFormat = mCodingType;
281                formatParams->eColorFormat = OMX_COLOR_FormatUnused;
282                formatParams->xFramerate = 0;
283            } else {
284                CHECK_EQ(formatParams->nPortIndex, 1u);
285
286                formatParams->eCompressionFormat = OMX_VIDEO_CodingUnused;
287                formatParams->eColorFormat = OMX_COLOR_FormatYUV420Planar;
288                formatParams->xFramerate = 0;
289            }
290
291            return OMX_ErrorNone;
292        }
293
294        case OMX_IndexParamVideoProfileLevelQuerySupported:
295        {
296            OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileLevel =
297                  (OMX_VIDEO_PARAM_PROFILELEVELTYPE *) params;
298
299            if (!isValidOMXParam(profileLevel)) {
300                return OMX_ErrorBadParameter;
301            }
302
303            if (profileLevel->nPortIndex != kInputPortIndex) {
304                ALOGE("Invalid port index: %" PRIu32, profileLevel->nPortIndex);
305                return OMX_ErrorUnsupportedIndex;
306            }
307
308            if (profileLevel->nProfileIndex >= mNumProfileLevels) {
309                return OMX_ErrorNoMore;
310            }
311
312            profileLevel->eProfile = mProfileLevels[profileLevel->nProfileIndex].mProfile;
313            profileLevel->eLevel   = mProfileLevels[profileLevel->nProfileIndex].mLevel;
314            return OMX_ErrorNone;
315        }
316
317        default:
318            return SimpleSoftOMXComponent::internalGetParameter(index, params);
319    }
320}
321
322OMX_ERRORTYPE SoftVideoDecoderOMXComponent::internalSetParameter(
323        OMX_INDEXTYPE index, const OMX_PTR params) {
324    // Include extension index OMX_INDEXEXTTYPE.
325    const int32_t indexFull = index;
326
327    switch (indexFull) {
328        case OMX_IndexParamStandardComponentRole:
329        {
330            const OMX_PARAM_COMPONENTROLETYPE *roleParams =
331                (const OMX_PARAM_COMPONENTROLETYPE *)params;
332
333            if (!isValidOMXParam(roleParams)) {
334                return OMX_ErrorBadParameter;
335            }
336
337            if (strncmp((const char *)roleParams->cRole,
338                        mComponentRole,
339                        OMX_MAX_STRINGNAME_SIZE - 1)) {
340                return OMX_ErrorUndefined;
341            }
342
343            return OMX_ErrorNone;
344        }
345
346        case OMX_IndexParamVideoPortFormat:
347        {
348            OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams =
349                (OMX_VIDEO_PARAM_PORTFORMATTYPE *)params;
350
351            if (!isValidOMXParam(formatParams)) {
352                return OMX_ErrorBadParameter;
353            }
354
355            if (formatParams->nPortIndex > kMaxPortIndex) {
356                return OMX_ErrorBadPortIndex;
357            }
358
359            if (formatParams->nIndex != 0) {
360                return OMX_ErrorNoMore;
361            }
362
363            if (formatParams->nPortIndex == kInputPortIndex) {
364                if (formatParams->eCompressionFormat != mCodingType
365                        || formatParams->eColorFormat != OMX_COLOR_FormatUnused) {
366                    return OMX_ErrorUnsupportedSetting;
367                }
368            } else {
369                if (formatParams->eCompressionFormat != OMX_VIDEO_CodingUnused
370                        || formatParams->eColorFormat != OMX_COLOR_FormatYUV420Planar) {
371                    return OMX_ErrorUnsupportedSetting;
372                }
373            }
374
375            return OMX_ErrorNone;
376        }
377
378        case kPrepareForAdaptivePlaybackIndex:
379        {
380            const PrepareForAdaptivePlaybackParams* adaptivePlaybackParams =
381                    (const PrepareForAdaptivePlaybackParams *)params;
382
383            if (!isValidOMXParam(adaptivePlaybackParams)) {
384                return OMX_ErrorBadParameter;
385            }
386
387            mIsAdaptive = adaptivePlaybackParams->bEnable;
388            if (mIsAdaptive) {
389                mAdaptiveMaxWidth = adaptivePlaybackParams->nMaxFrameWidth;
390                mAdaptiveMaxHeight = adaptivePlaybackParams->nMaxFrameHeight;
391                mWidth = mAdaptiveMaxWidth;
392                mHeight = mAdaptiveMaxHeight;
393            } else {
394                mAdaptiveMaxWidth = 0;
395                mAdaptiveMaxHeight = 0;
396            }
397            updatePortDefinitions(true /* updateCrop */, true /* updateInputSize */);
398            return OMX_ErrorNone;
399        }
400
401        case OMX_IndexParamPortDefinition:
402        {
403            OMX_PARAM_PORTDEFINITIONTYPE *newParams =
404                (OMX_PARAM_PORTDEFINITIONTYPE *)params;
405
406            if (!isValidOMXParam(newParams)) {
407                return OMX_ErrorBadParameter;
408            }
409
410            OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &newParams->format.video;
411            OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(newParams->nPortIndex)->mDef;
412
413            uint32_t oldWidth = def->format.video.nFrameWidth;
414            uint32_t oldHeight = def->format.video.nFrameHeight;
415            uint32_t newWidth = video_def->nFrameWidth;
416            uint32_t newHeight = video_def->nFrameHeight;
417            // We need width, height, stride and slice-height to be non-zero and sensible.
418            // These values were chosen to prevent integer overflows further down the line, and do
419            // not indicate support for 32kx32k video.
420            if (newWidth > 32768 || newHeight > 32768
421                    || video_def->nStride > 32768 || video_def->nSliceHeight > 32768) {
422                ALOGE("b/22885421");
423                return OMX_ErrorBadParameter;
424            }
425            if (newWidth != oldWidth || newHeight != oldHeight) {
426                bool outputPort = (newParams->nPortIndex == kOutputPortIndex);
427                if (outputPort) {
428                    // only update (essentially crop) if size changes
429                    mWidth = newWidth;
430                    mHeight = newHeight;
431
432                    updatePortDefinitions(true /* updateCrop */, true /* updateInputSize */);
433                    // reset buffer size based on frame size
434                    newParams->nBufferSize = def->nBufferSize;
435                } else {
436                    // For input port, we only set nFrameWidth and nFrameHeight. Buffer size
437                    // is updated when configuring the output port using the max-frame-size,
438                    // though client can still request a larger size.
439                    def->format.video.nFrameWidth = newWidth;
440                    def->format.video.nFrameHeight = newHeight;
441                }
442            }
443            return SimpleSoftOMXComponent::internalSetParameter(index, params);
444        }
445
446        default:
447            return SimpleSoftOMXComponent::internalSetParameter(index, params);
448    }
449}
450
451OMX_ERRORTYPE SoftVideoDecoderOMXComponent::getConfig(
452        OMX_INDEXTYPE index, OMX_PTR params) {
453    switch (index) {
454        case OMX_IndexConfigCommonOutputCrop:
455        {
456            OMX_CONFIG_RECTTYPE *rectParams = (OMX_CONFIG_RECTTYPE *)params;
457
458            if (!isValidOMXParam(rectParams)) {
459                return OMX_ErrorBadParameter;
460            }
461
462            if (rectParams->nPortIndex != kOutputPortIndex) {
463                return OMX_ErrorUndefined;
464            }
465
466            rectParams->nLeft = mCropLeft;
467            rectParams->nTop = mCropTop;
468            rectParams->nWidth = mCropWidth;
469            rectParams->nHeight = mCropHeight;
470
471            return OMX_ErrorNone;
472        }
473
474        default:
475            return OMX_ErrorUnsupportedIndex;
476    }
477}
478
479OMX_ERRORTYPE SoftVideoDecoderOMXComponent::getExtensionIndex(
480        const char *name, OMX_INDEXTYPE *index) {
481    if (!strcmp(name, "OMX.google.android.index.prepareForAdaptivePlayback")) {
482        *(int32_t*)index = kPrepareForAdaptivePlaybackIndex;
483        return OMX_ErrorNone;
484    }
485
486    return SimpleSoftOMXComponent::getExtensionIndex(name, index);
487}
488
489void SoftVideoDecoderOMXComponent::onReset() {
490    mOutputPortSettingsChange = NONE;
491}
492
493void SoftVideoDecoderOMXComponent::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
494    if (portIndex != kOutputPortIndex) {
495        return;
496    }
497
498    switch (mOutputPortSettingsChange) {
499        case NONE:
500            break;
501
502        case AWAITING_DISABLED:
503        {
504            CHECK(!enabled);
505            mOutputPortSettingsChange = AWAITING_ENABLED;
506            break;
507        }
508
509        default:
510        {
511            CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED);
512            CHECK(enabled);
513            mOutputPortSettingsChange = NONE;
514            break;
515        }
516    }
517}
518
519}  // namespace android
520