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