SoftVPX.cpp revision 7f616d3cc5366a4b8af20d3d0c768e3de1df0666
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 "SoftVPX"
19#include <utils/Log.h>
20
21#include "SoftVPX.h"
22
23#include <media/stagefright/foundation/ADebug.h>
24#include <media/stagefright/MediaDefs.h>
25
26#include "vpx/vpx_decoder.h"
27#include "vpx/vpx_codec.h"
28#include "vpx/vp8dx.h"
29
30namespace android {
31
32SoftVPX::SoftVPX(
33        const char *name,
34        const OMX_CALLBACKTYPE *callbacks,
35        OMX_PTR appData,
36        OMX_COMPONENTTYPE **component)
37    : SoftVideoDecoderOMXComponent(
38            name, "video_decoder.vpx", OMX_VIDEO_CodingVPX,
39            NULL /* profileLevels */, 0 /* numProfileLevels */,
40            320 /* width */, 240 /* height */, callbacks, appData, component),
41      mCtx(NULL) {
42    initPorts(kNumBuffers, 768 * 1024 /* inputBufferSize */,
43            kNumBuffers, MEDIA_MIMETYPE_VIDEO_VPX);
44
45    CHECK_EQ(initDecoder(), (status_t)OK);
46}
47
48SoftVPX::~SoftVPX() {
49    vpx_codec_destroy((vpx_codec_ctx_t *)mCtx);
50    delete (vpx_codec_ctx_t *)mCtx;
51    mCtx = NULL;
52}
53
54static int GetCPUCoreCount() {
55    int cpuCoreCount = 1;
56#if defined(_SC_NPROCESSORS_ONLN)
57    cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
58#else
59    // _SC_NPROC_ONLN must be defined...
60    cpuCoreCount = sysconf(_SC_NPROC_ONLN);
61#endif
62    CHECK(cpuCoreCount >= 1);
63    ALOGV("Number of CPU cores: %d", cpuCoreCount);
64    return cpuCoreCount;
65}
66
67status_t SoftVPX::initDecoder() {
68    mCtx = new vpx_codec_ctx_t;
69    vpx_codec_err_t vpx_err;
70    vpx_codec_dec_cfg_t cfg;
71    memset(&cfg, 0, sizeof(vpx_codec_dec_cfg_t));
72    cfg.threads = GetCPUCoreCount();
73    if ((vpx_err = vpx_codec_dec_init(
74                (vpx_codec_ctx_t *)mCtx, &vpx_codec_vp8_dx_algo, &cfg, 0))) {
75        ALOGE("on2 decoder failed to initialize. (%d)", vpx_err);
76        return UNKNOWN_ERROR;
77    }
78
79    return OK;
80}
81
82void SoftVPX::onQueueFilled(OMX_U32 portIndex) {
83    if (mOutputPortSettingsChange != NONE) {
84        return;
85    }
86
87    List<BufferInfo *> &inQueue = getPortQueue(0);
88    List<BufferInfo *> &outQueue = getPortQueue(1);
89    bool EOSseen = false;
90
91    while (!inQueue.empty() && !outQueue.empty()) {
92        BufferInfo *inInfo = *inQueue.begin();
93        OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
94
95        BufferInfo *outInfo = *outQueue.begin();
96        OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
97
98        if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
99            EOSseen = true;
100            if (inHeader->nFilledLen == 0) {
101                inQueue.erase(inQueue.begin());
102                inInfo->mOwnedByUs = false;
103                notifyEmptyBufferDone(inHeader);
104
105                outHeader->nFilledLen = 0;
106                outHeader->nFlags = OMX_BUFFERFLAG_EOS;
107
108                outQueue.erase(outQueue.begin());
109                outInfo->mOwnedByUs = false;
110                notifyFillBufferDone(outHeader);
111                return;
112            }
113        }
114
115        if (vpx_codec_decode(
116                    (vpx_codec_ctx_t *)mCtx,
117                    inHeader->pBuffer + inHeader->nOffset,
118                    inHeader->nFilledLen,
119                    NULL,
120                    0)) {
121            ALOGE("on2 decoder failed to decode frame.");
122
123            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
124            return;
125        }
126
127        vpx_codec_iter_t iter = NULL;
128        vpx_image_t *img = vpx_codec_get_frame((vpx_codec_ctx_t *)mCtx, &iter);
129
130        if (img != NULL) {
131            CHECK_EQ(img->fmt, IMG_FMT_I420);
132
133            uint32_t width = img->d_w;
134            uint32_t height = img->d_h;
135
136            if (width != mWidth || height != mHeight) {
137                mWidth = width;
138                mHeight = height;
139
140                updatePortDefinitions();
141
142                notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
143                mOutputPortSettingsChange = AWAITING_DISABLED;
144                return;
145            }
146
147            outHeader->nOffset = 0;
148            outHeader->nFilledLen = (width * height * 3) / 2;
149            outHeader->nFlags = EOSseen ? OMX_BUFFERFLAG_EOS : 0;
150            outHeader->nTimeStamp = inHeader->nTimeStamp;
151
152            const uint8_t *srcLine = (const uint8_t *)img->planes[PLANE_Y];
153            uint8_t *dst = outHeader->pBuffer;
154            for (size_t i = 0; i < img->d_h; ++i) {
155                memcpy(dst, srcLine, img->d_w);
156
157                srcLine += img->stride[PLANE_Y];
158                dst += img->d_w;
159            }
160
161            srcLine = (const uint8_t *)img->planes[PLANE_U];
162            for (size_t i = 0; i < img->d_h / 2; ++i) {
163                memcpy(dst, srcLine, img->d_w / 2);
164
165                srcLine += img->stride[PLANE_U];
166                dst += img->d_w / 2;
167            }
168
169            srcLine = (const uint8_t *)img->planes[PLANE_V];
170            for (size_t i = 0; i < img->d_h / 2; ++i) {
171                memcpy(dst, srcLine, img->d_w / 2);
172
173                srcLine += img->stride[PLANE_V];
174                dst += img->d_w / 2;
175            }
176
177            outInfo->mOwnedByUs = false;
178            outQueue.erase(outQueue.begin());
179            outInfo = NULL;
180            notifyFillBufferDone(outHeader);
181            outHeader = NULL;
182        }
183
184        inInfo->mOwnedByUs = false;
185        inQueue.erase(inQueue.begin());
186        inInfo = NULL;
187        notifyEmptyBufferDone(inHeader);
188        inHeader = NULL;
189    }
190}
191
192}  // namespace android
193
194android::SoftOMXComponent *createSoftOMXComponent(
195        const char *name, const OMX_CALLBACKTYPE *callbacks,
196        OMX_PTR appData, OMX_COMPONENTTYPE **component) {
197    return new android::SoftVPX(name, callbacks, appData, component);
198}
199
200