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