SoftAVC.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 "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 H264SwDecRet ret = H264SWDEC_PIC_RDY; 113 bool portSettingsChanged = false; 114 while ((mEOSStatus != INPUT_DATA_AVAILABLE || !inQueue.empty()) 115 && outQueue.size() == kNumOutputBuffers) { 116 117 if (mEOSStatus == INPUT_EOS_SEEN) { 118 drainAllOutputBuffers(); 119 return; 120 } 121 122 BufferInfo *inInfo = *inQueue.begin(); 123 OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; 124 ++mPicId; 125 126 OMX_BUFFERHEADERTYPE *header = new OMX_BUFFERHEADERTYPE; 127 memset(header, 0, sizeof(OMX_BUFFERHEADERTYPE)); 128 header->nTimeStamp = inHeader->nTimeStamp; 129 header->nFlags = inHeader->nFlags; 130 if (header->nFlags & OMX_BUFFERFLAG_EOS) { 131 mEOSStatus = INPUT_EOS_SEEN; 132 } 133 mPicToHeaderMap.add(mPicId, header); 134 inQueue.erase(inQueue.begin()); 135 136 H264SwDecInput inPicture; 137 H264SwDecOutput outPicture; 138 memset(&inPicture, 0, sizeof(inPicture)); 139 inPicture.dataLen = inHeader->nFilledLen; 140 inPicture.pStream = inHeader->pBuffer + inHeader->nOffset; 141 inPicture.picId = mPicId; 142 inPicture.intraConcealmentMethod = 1; 143 H264SwDecPicture decodedPicture; 144 145 while (inPicture.dataLen > 0) { 146 ret = H264SwDecDecode(mHandle, &inPicture, &outPicture); 147 if (ret == H264SWDEC_HDRS_RDY_BUFF_NOT_EMPTY || 148 ret == H264SWDEC_PIC_RDY_BUFF_NOT_EMPTY) { 149 inPicture.dataLen -= (u32)(outPicture.pStrmCurrPos - inPicture.pStream); 150 inPicture.pStream = outPicture.pStrmCurrPos; 151 if (ret == H264SWDEC_HDRS_RDY_BUFF_NOT_EMPTY) { 152 mHeadersDecoded = true; 153 H264SwDecInfo decoderInfo; 154 CHECK(H264SwDecGetInfo(mHandle, &decoderInfo) == H264SWDEC_OK); 155 156 if (handlePortSettingChangeEvent(&decoderInfo)) { 157 portSettingsChanged = true; 158 } 159 160 if (decoderInfo.croppingFlag && 161 handleCropRectEvent(&decoderInfo.cropParams)) { 162 portSettingsChanged = true; 163 } 164 } 165 } else { 166 if (portSettingsChanged) { 167 if (H264SwDecNextPicture(mHandle, &decodedPicture, 0) 168 == H264SWDEC_PIC_RDY) { 169 170 // Save this output buffer; otherwise, it will be 171 // lost during dynamic port reconfiguration because 172 // OpenMAX client will delete _all_ output buffers 173 // in the process. 174 saveFirstOutputBuffer( 175 decodedPicture.picId, 176 (uint8_t *)decodedPicture.pOutputPicture); 177 } 178 } 179 inPicture.dataLen = 0; 180 if (ret < 0) { 181 ALOGE("Decoder failed: %d", ret); 182 183 notify(OMX_EventError, OMX_ErrorUndefined, 184 ERROR_MALFORMED, NULL); 185 186 mSignalledError = true; 187 return; 188 } 189 } 190 } 191 inInfo->mOwnedByUs = false; 192 notifyEmptyBufferDone(inHeader); 193 194 if (portSettingsChanged) { 195 portSettingsChanged = false; 196 return; 197 } 198 199 if (mFirstPicture && !outQueue.empty()) { 200 drainOneOutputBuffer(mFirstPictureId, mFirstPicture); 201 delete[] mFirstPicture; 202 mFirstPicture = NULL; 203 mFirstPictureId = -1; 204 } 205 206 while (!outQueue.empty() && 207 mHeadersDecoded && 208 H264SwDecNextPicture(mHandle, &decodedPicture, 0) 209 == H264SWDEC_PIC_RDY) { 210 211 int32_t picId = decodedPicture.picId; 212 uint8_t *data = (uint8_t *) decodedPicture.pOutputPicture; 213 drainOneOutputBuffer(picId, data); 214 } 215 } 216} 217 218bool SoftAVC::handlePortSettingChangeEvent(const H264SwDecInfo *info) { 219 if (mWidth != info->picWidth || mHeight != info->picHeight) { 220 mWidth = info->picWidth; 221 mHeight = info->picHeight; 222 mPictureSize = mWidth * mHeight * 3 / 2; 223 updatePortDefinitions(); 224 notify(OMX_EventPortSettingsChanged, 1, 0, NULL); 225 mOutputPortSettingsChange = AWAITING_DISABLED; 226 return true; 227 } 228 229 return false; 230} 231 232bool SoftAVC::handleCropRectEvent(const CropParams *crop) { 233 if (mCropLeft != crop->cropLeftOffset || 234 mCropTop != crop->cropTopOffset || 235 mCropWidth != crop->cropOutWidth || 236 mCropHeight != crop->cropOutHeight) { 237 mCropLeft = crop->cropLeftOffset; 238 mCropTop = crop->cropTopOffset; 239 mCropWidth = crop->cropOutWidth; 240 mCropHeight = crop->cropOutHeight; 241 242 notify(OMX_EventPortSettingsChanged, 1, 243 OMX_IndexConfigCommonOutputCrop, NULL); 244 245 return true; 246 } 247 return false; 248} 249 250void SoftAVC::saveFirstOutputBuffer(int32_t picId, uint8_t *data) { 251 CHECK(mFirstPicture == NULL); 252 mFirstPictureId = picId; 253 254 mFirstPicture = new uint8_t[mPictureSize]; 255 memcpy(mFirstPicture, data, mPictureSize); 256} 257 258void SoftAVC::drainOneOutputBuffer(int32_t picId, uint8_t* data) { 259 List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex); 260 BufferInfo *outInfo = *outQueue.begin(); 261 outQueue.erase(outQueue.begin()); 262 OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; 263 OMX_BUFFERHEADERTYPE *header = mPicToHeaderMap.valueFor(picId); 264 outHeader->nTimeStamp = header->nTimeStamp; 265 outHeader->nFlags = header->nFlags; 266 outHeader->nFilledLen = mPictureSize; 267 memcpy(outHeader->pBuffer + outHeader->nOffset, 268 data, mPictureSize); 269 mPicToHeaderMap.removeItem(picId); 270 delete header; 271 outInfo->mOwnedByUs = false; 272 notifyFillBufferDone(outHeader); 273} 274 275bool SoftAVC::drainAllOutputBuffers() { 276 List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex); 277 H264SwDecPicture decodedPicture; 278 279 while (!outQueue.empty()) { 280 BufferInfo *outInfo = *outQueue.begin(); 281 outQueue.erase(outQueue.begin()); 282 OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; 283 if (mHeadersDecoded && 284 H264SWDEC_PIC_RDY == 285 H264SwDecNextPicture(mHandle, &decodedPicture, 1 /* flush */)) { 286 287 int32_t picId = decodedPicture.picId; 288 CHECK(mPicToHeaderMap.indexOfKey(picId) >= 0); 289 290 memcpy(outHeader->pBuffer + outHeader->nOffset, 291 decodedPicture.pOutputPicture, 292 mPictureSize); 293 294 OMX_BUFFERHEADERTYPE *header = mPicToHeaderMap.valueFor(picId); 295 outHeader->nTimeStamp = header->nTimeStamp; 296 outHeader->nFlags = header->nFlags; 297 outHeader->nFilledLen = mPictureSize; 298 mPicToHeaderMap.removeItem(picId); 299 delete header; 300 } else { 301 outHeader->nTimeStamp = 0; 302 outHeader->nFilledLen = 0; 303 outHeader->nFlags = OMX_BUFFERFLAG_EOS; 304 mEOSStatus = OUTPUT_FRAMES_FLUSHED; 305 } 306 307 outInfo->mOwnedByUs = false; 308 notifyFillBufferDone(outHeader); 309 } 310 311 return true; 312} 313 314void SoftAVC::onPortFlushCompleted(OMX_U32 portIndex) { 315 if (portIndex == kInputPortIndex) { 316 mEOSStatus = INPUT_DATA_AVAILABLE; 317 } 318} 319 320void SoftAVC::onReset() { 321 SoftVideoDecoderOMXComponent::onReset(); 322 mSignalledError = false; 323} 324 325} // namespace android 326 327android::SoftOMXComponent *createSoftOMXComponent( 328 const char *name, const OMX_CALLBACKTYPE *callbacks, 329 OMX_PTR appData, OMX_COMPONENTTYPE **component) { 330 return new android::SoftAVC(name, callbacks, appData, component); 331} 332