SoftAVC.cpp revision e75d53abb2f986cf07476d1430eb9981a79b2d2f
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 "SoftAVC" 19#include <utils/Log.h> 20 21#include "SoftAVC.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 29namespace android { 30 31static const CodecProfileLevel kProfileLevels[] = { 32 { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel1 }, 33 { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel1b }, 34 { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel11 }, 35 { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel12 }, 36 { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel13 }, 37 { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel2 }, 38 { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel21 }, 39 { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel22 }, 40 { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel3 }, 41 { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel31 }, 42 { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel32 }, 43 { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel4 }, 44 { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel41 }, 45 { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel42 }, 46 { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel5 }, 47 { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel51 }, 48}; 49 50SoftAVC::SoftAVC( 51 const char *name, 52 const OMX_CALLBACKTYPE *callbacks, 53 OMX_PTR appData, 54 OMX_COMPONENTTYPE **component) 55 : SoftVideoDecoderOMXComponent( 56 name, "video_decoder.avc", OMX_VIDEO_CodingAVC, 57 kProfileLevels, ARRAY_SIZE(kProfileLevels), 58 320 /* width */, 240 /* height */, callbacks, appData, component), 59 mHandle(NULL), 60 mInputBufferCount(0), 61 mPictureSize(mWidth * mHeight * 3 / 2), 62 mFirstPicture(NULL), 63 mFirstPictureId(-1), 64 mPicId(0), 65 mHeadersDecoded(false), 66 mEOSStatus(INPUT_DATA_AVAILABLE), 67 mSignalledError(false) { 68 initPorts( 69 kNumInputBuffers, 8192 /* inputBufferSize */, 70 kNumOutputBuffers, MEDIA_MIMETYPE_VIDEO_AVC); 71 72 CHECK_EQ(initDecoder(), (status_t)OK); 73} 74 75SoftAVC::~SoftAVC() { 76 H264SwDecRelease(mHandle); 77 mHandle = NULL; 78 79 while (mPicToHeaderMap.size() != 0) { 80 OMX_BUFFERHEADERTYPE *header = mPicToHeaderMap.editValueAt(0); 81 mPicToHeaderMap.removeItemsAt(0); 82 delete header; 83 header = NULL; 84 } 85 List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex); 86 List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex); 87 CHECK(outQueue.empty()); 88 CHECK(inQueue.empty()); 89 90 delete[] mFirstPicture; 91} 92 93status_t SoftAVC::initDecoder() { 94 // Force decoder to output buffers in display order. 95 if (H264SwDecInit(&mHandle, 0) == H264SWDEC_OK) { 96 return OK; 97 } 98 return UNKNOWN_ERROR; 99} 100 101void SoftAVC::onQueueFilled(OMX_U32 portIndex) { 102 if (mSignalledError || mOutputPortSettingsChange != NONE) { 103 return; 104 } 105 106 if (mEOSStatus == OUTPUT_FRAMES_FLUSHED) { 107 return; 108 } 109 110 List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex); 111 List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex); 112 113 if (mHeadersDecoded) { 114 // Dequeue any already decoded output frames to free up space 115 // in the output queue. 116 117 drainAllOutputBuffers(false /* eos */); 118 } 119 120 H264SwDecRet ret = H264SWDEC_PIC_RDY; 121 bool portSettingsChanged = false; 122 while ((mEOSStatus != INPUT_DATA_AVAILABLE || !inQueue.empty()) 123 && outQueue.size() == kNumOutputBuffers) { 124 125 if (mEOSStatus == INPUT_EOS_SEEN) { 126 drainAllOutputBuffers(true /* eos */); 127 return; 128 } 129 130 BufferInfo *inInfo = *inQueue.begin(); 131 OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; 132 ++mPicId; 133 134 OMX_BUFFERHEADERTYPE *header = new OMX_BUFFERHEADERTYPE; 135 memset(header, 0, sizeof(OMX_BUFFERHEADERTYPE)); 136 header->nTimeStamp = inHeader->nTimeStamp; 137 header->nFlags = inHeader->nFlags; 138 if (header->nFlags & OMX_BUFFERFLAG_EOS) { 139 mEOSStatus = INPUT_EOS_SEEN; 140 } 141 mPicToHeaderMap.add(mPicId, header); 142 inQueue.erase(inQueue.begin()); 143 144 H264SwDecInput inPicture; 145 H264SwDecOutput outPicture; 146 memset(&inPicture, 0, sizeof(inPicture)); 147 inPicture.dataLen = inHeader->nFilledLen; 148 inPicture.pStream = inHeader->pBuffer + inHeader->nOffset; 149 inPicture.picId = mPicId; 150 inPicture.intraConcealmentMethod = 1; 151 H264SwDecPicture decodedPicture; 152 153 while (inPicture.dataLen > 0) { 154 ret = H264SwDecDecode(mHandle, &inPicture, &outPicture); 155 if (ret == H264SWDEC_HDRS_RDY_BUFF_NOT_EMPTY || 156 ret == H264SWDEC_PIC_RDY_BUFF_NOT_EMPTY) { 157 inPicture.dataLen -= (u32)(outPicture.pStrmCurrPos - inPicture.pStream); 158 inPicture.pStream = outPicture.pStrmCurrPos; 159 if (ret == H264SWDEC_HDRS_RDY_BUFF_NOT_EMPTY) { 160 mHeadersDecoded = true; 161 H264SwDecInfo decoderInfo; 162 CHECK(H264SwDecGetInfo(mHandle, &decoderInfo) == H264SWDEC_OK); 163 164 if (handlePortSettingChangeEvent(&decoderInfo)) { 165 portSettingsChanged = true; 166 } 167 168 if (decoderInfo.croppingFlag && 169 handleCropRectEvent(&decoderInfo.cropParams)) { 170 portSettingsChanged = true; 171 } 172 } 173 } else { 174 if (portSettingsChanged) { 175 if (H264SwDecNextPicture(mHandle, &decodedPicture, 0) 176 == H264SWDEC_PIC_RDY) { 177 178 // Save this output buffer; otherwise, it will be 179 // lost during dynamic port reconfiguration because 180 // OpenMAX client will delete _all_ output buffers 181 // in the process. 182 saveFirstOutputBuffer( 183 decodedPicture.picId, 184 (uint8_t *)decodedPicture.pOutputPicture); 185 } 186 } 187 inPicture.dataLen = 0; 188 if (ret < 0) { 189 ALOGE("Decoder failed: %d", ret); 190 191 notify(OMX_EventError, OMX_ErrorUndefined, 192 ERROR_MALFORMED, NULL); 193 194 mSignalledError = true; 195 return; 196 } 197 } 198 } 199 inInfo->mOwnedByUs = false; 200 notifyEmptyBufferDone(inHeader); 201 202 if (portSettingsChanged) { 203 portSettingsChanged = false; 204 return; 205 } 206 207 if (mFirstPicture && !outQueue.empty()) { 208 if (!drainOneOutputBuffer(mFirstPictureId, mFirstPicture)) { 209 ALOGE("Drain failed"); 210 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); 211 mSignalledError = true; 212 return; 213 } 214 delete[] mFirstPicture; 215 mFirstPicture = NULL; 216 mFirstPictureId = -1; 217 } 218 219 drainAllOutputBuffers(false /* eos */); 220 } 221} 222 223bool SoftAVC::handlePortSettingChangeEvent(const H264SwDecInfo *info) { 224 if (mWidth != info->picWidth || mHeight != info->picHeight) { 225 mWidth = info->picWidth; 226 mHeight = info->picHeight; 227 mPictureSize = mWidth * mHeight * 3 / 2; 228 updatePortDefinitions(); 229 notify(OMX_EventPortSettingsChanged, 1, 0, NULL); 230 mOutputPortSettingsChange = AWAITING_DISABLED; 231 return true; 232 } 233 234 return false; 235} 236 237bool SoftAVC::handleCropRectEvent(const CropParams *crop) { 238 if (mCropLeft != crop->cropLeftOffset || 239 mCropTop != crop->cropTopOffset || 240 mCropWidth != crop->cropOutWidth || 241 mCropHeight != crop->cropOutHeight) { 242 mCropLeft = crop->cropLeftOffset; 243 mCropTop = crop->cropTopOffset; 244 mCropWidth = crop->cropOutWidth; 245 mCropHeight = crop->cropOutHeight; 246 247 notify(OMX_EventPortSettingsChanged, 1, 248 OMX_IndexConfigCommonOutputCrop, NULL); 249 250 return true; 251 } 252 return false; 253} 254 255void SoftAVC::saveFirstOutputBuffer(int32_t picId, uint8_t *data) { 256 CHECK(mFirstPicture == NULL); 257 mFirstPictureId = picId; 258 259 mFirstPicture = new uint8_t[mPictureSize]; 260 memcpy(mFirstPicture, data, mPictureSize); 261} 262 263bool SoftAVC::drainOneOutputBuffer(int32_t picId, uint8_t* data) { 264 List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex); 265 BufferInfo *outInfo = *outQueue.begin(); 266 OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; 267 if (outHeader->nAllocLen - outHeader->nOffset < mPictureSize) { 268 android_errorWriteLog(0x534e4554, "27833616"); 269 return false; 270 } 271 outQueue.erase(outQueue.begin()); 272 OMX_BUFFERHEADERTYPE *header = mPicToHeaderMap.valueFor(picId); 273 outHeader->nTimeStamp = header->nTimeStamp; 274 outHeader->nFlags = header->nFlags; 275 outHeader->nFilledLen = mPictureSize; 276 memcpy(outHeader->pBuffer + outHeader->nOffset, 277 data, mPictureSize); 278 mPicToHeaderMap.removeItem(picId); 279 delete header; 280 outInfo->mOwnedByUs = false; 281 notifyFillBufferDone(outHeader); 282 return true; 283} 284 285void SoftAVC::drainAllOutputBuffers(bool eos) { 286 List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex); 287 H264SwDecPicture decodedPicture; 288 289 if (mHeadersDecoded) { 290 while (!outQueue.empty() 291 && H264SWDEC_PIC_RDY == H264SwDecNextPicture( 292 mHandle, &decodedPicture, eos /* flush */)) { 293 int32_t picId = decodedPicture.picId; 294 uint8_t *data = (uint8_t *) decodedPicture.pOutputPicture; 295 if (!drainOneOutputBuffer(picId, data)) { 296 ALOGE("Drain failed"); 297 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); 298 mSignalledError = true; 299 return; 300 } 301 } 302 } 303 304 if (!eos) { 305 return; 306 } 307 308 while (!outQueue.empty()) { 309 BufferInfo *outInfo = *outQueue.begin(); 310 outQueue.erase(outQueue.begin()); 311 OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; 312 313 outHeader->nTimeStamp = 0; 314 outHeader->nFilledLen = 0; 315 outHeader->nFlags = OMX_BUFFERFLAG_EOS; 316 317 outInfo->mOwnedByUs = false; 318 notifyFillBufferDone(outHeader); 319 320 mEOSStatus = OUTPUT_FRAMES_FLUSHED; 321 } 322} 323 324void SoftAVC::onPortFlushCompleted(OMX_U32 portIndex) { 325 if (portIndex == kInputPortIndex) { 326 mEOSStatus = INPUT_DATA_AVAILABLE; 327 } 328} 329 330void SoftAVC::onReset() { 331 SoftVideoDecoderOMXComponent::onReset(); 332 mSignalledError = false; 333} 334 335} // namespace android 336 337android::SoftOMXComponent *createSoftOMXComponent( 338 const char *name, const OMX_CALLBACKTYPE *callbacks, 339 OMX_PTR appData, OMX_COMPONENTTYPE **component) { 340 return new android::SoftAVC(name, callbacks, appData, component); 341} 342