2 * Copyright 2012 Michael Chen <omxcodec@gmail.com>
3 * Copyright 2015 The CyanogenMod Project
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 //#define LOG_NDEBUG 0
19 #define LOG_TAG "SoftFFmpegVideo"
20 #include <utils/Log.h>
22 #include "SoftFFmpegVideo.h"
23 #include "FFmpegComponents.h"
25 #include <media/stagefright/foundation/ADebug.h>
26 #include <media/stagefright/foundation/AUtils.h>
27 #include <media/stagefright/foundation/hexdump.h>
28 #include <media/stagefright/MediaDefs.h>
33 static int decoder_reorder_pts = -1;
37 SoftFFmpegVideo::SoftFFmpegVideo(
39 const char *componentRole,
40 OMX_VIDEO_CODINGTYPE codingType,
41 const OMX_CALLBACKTYPE *callbacks,
43 OMX_COMPONENTTYPE **component,
44 enum AVCodecID codecID)
45 : SoftVideoDecoderOMXComponent(name, componentRole, codingType,
46 NULL, 0, 320, 240, callbacks, appData, component),
47 mCodingType(codingType),
48 mFFmpegAlreadyInited(false),
49 mCodecAlreadyOpened(false),
53 mEOSStatus(INPUT_DATA_AVAILABLE),
54 mExtradataReady(false),
55 mIgnoreExtradata(false),
57 mSignalledError(false) {
59 ALOGD("SoftFFmpegVideo component: %s codingType=%d appData: %p", name, codingType, appData);
63 8192 /* inputBufferSize */,
67 CHECK_EQ(initDecoder(codecID), (status_t)OK);
70 SoftFFmpegVideo::~SoftFFmpegVideo() {
71 ALOGV("~SoftFFmpegVideo");
73 if (mFFmpegAlreadyInited) {
78 void SoftFFmpegVideo::setDefaultCtx(AVCodecContext *avctx, const AVCodec *codec) {
81 avctx->workaround_bugs = 1;
83 if(avctx->lowres > codec->max_lowres){
84 ALOGW("The maximum value for lowres supported by the decoder is %d",
86 avctx->lowres= codec->max_lowres;
89 avctx->skip_frame = AVDISCARD_DEFAULT;
90 avctx->skip_idct = AVDISCARD_DEFAULT;
91 avctx->skip_loop_filter = AVDISCARD_ALL;
92 avctx->error_concealment = 3;
93 avctx->thread_count = 0;
95 if(avctx->lowres) avctx->flags |= CODEC_FLAG_EMU_EDGE;
96 if (fast) avctx->flags2 |= CODEC_FLAG2_FAST;
97 if(codec->capabilities & CODEC_CAP_DR1)
98 avctx->flags |= CODEC_FLAG_EMU_EDGE;
101 status_t SoftFFmpegVideo::initDecoder(enum AVCodecID codecID) {
104 status = initFFmpeg();
108 mFFmpegAlreadyInited = true;
110 mCtx = avcodec_alloc_context3(NULL);
113 ALOGE("avcodec_alloc_context failed.");
117 mCtx->codec_type = AVMEDIA_TYPE_VIDEO;
118 mCtx->codec_id = codecID;
119 mCtx->extradata_size = 0;
120 mCtx->extradata = NULL;
124 void SoftFFmpegVideo::deInitDecoder() {
126 if (avcodec_is_open(mCtx)) {
127 avcodec_flush_buffers(mCtx);
129 if (mCtx->extradata) {
130 av_free(mCtx->extradata);
131 mCtx->extradata = NULL;
132 mCtx->extradata_size = 0;
134 if (mCodecAlreadyOpened) {
144 if (mImgConvertCtx) {
145 sws_freeContext(mImgConvertCtx);
146 mImgConvertCtx = NULL;
150 OMX_ERRORTYPE SoftFFmpegVideo::internalGetParameter(
151 OMX_INDEXTYPE index, OMX_PTR params) {
152 //ALOGV("internalGetParameter index:0x%x", index);
154 case OMX_IndexParamVideoWmv:
156 OMX_VIDEO_PARAM_WMVTYPE *profile =
157 (OMX_VIDEO_PARAM_WMVTYPE *)params;
159 if (profile->nPortIndex != kInputPortIndex) {
160 return OMX_ErrorUndefined;
163 profile->eFormat = OMX_VIDEO_WMVFormatUnused;
165 return OMX_ErrorNone;
168 case OMX_IndexParamVideoRv:
170 OMX_VIDEO_PARAM_RVTYPE *profile =
171 (OMX_VIDEO_PARAM_RVTYPE *)params;
173 if (profile->nPortIndex != kInputPortIndex) {
174 return OMX_ErrorUndefined;
177 profile->eFormat = OMX_VIDEO_RVFormatUnused;
179 return OMX_ErrorNone;
184 if (index != (OMX_INDEXTYPE)OMX_IndexParamVideoFFmpeg) {
185 return SoftVideoDecoderOMXComponent::internalGetParameter(index, params);
188 OMX_VIDEO_PARAM_FFMPEGTYPE *profile =
189 (OMX_VIDEO_PARAM_FFMPEGTYPE *)params;
191 if (profile->nPortIndex != kInputPortIndex) {
192 return OMX_ErrorUndefined;
195 profile->eCodecId = AV_CODEC_ID_NONE;
197 profile->nHeight = 0;
199 return OMX_ErrorNone;
204 OMX_ERRORTYPE SoftFFmpegVideo::isRoleSupported(
205 const OMX_PARAM_COMPONENTROLETYPE *roleParams) {
207 i < sizeof(kVideoComponents) / sizeof(kVideoComponents[0]);
209 if (mCodingType == kVideoComponents[i].mVideoCodingType &&
210 strncmp((const char *)roleParams->cRole,
211 kVideoComponents[i].mRole, OMX_MAX_STRINGNAME_SIZE - 1) == 0) {
212 return OMX_ErrorNone;
215 ALOGE("unsupported role: %s", (const char *)roleParams->cRole);
216 return OMX_ErrorUndefined;
219 OMX_ERRORTYPE SoftFFmpegVideo::internalSetParameter(
220 OMX_INDEXTYPE index, const OMX_PTR params) {
221 //ALOGV("internalSetParameter index:0x%x", index);
223 case OMX_IndexParamStandardComponentRole:
225 const OMX_PARAM_COMPONENTROLETYPE *roleParams =
226 (const OMX_PARAM_COMPONENTROLETYPE *)params;
227 return isRoleSupported(roleParams);
230 case OMX_IndexParamPortDefinition:
232 OMX_PARAM_PORTDEFINITIONTYPE *newParams =
233 (OMX_PARAM_PORTDEFINITIONTYPE *)params;
234 OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &newParams->format.video;
235 OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(newParams->nPortIndex)->mDef;
237 uint32_t oldWidth = def->format.video.nFrameWidth;
238 uint32_t oldHeight = def->format.video.nFrameHeight;
239 uint32_t newWidth = video_def->nFrameWidth;
240 uint32_t newHeight = video_def->nFrameHeight;
241 if (newWidth != oldWidth || newHeight != oldHeight) {
242 bool outputPort = (newParams->nPortIndex == kOutputPortIndex);
244 ALOGV("OMX_IndexParamPortDefinition (output) width=%d height=%d", newWidth, newHeight);
246 // only update (essentially crop) if size changes
250 updatePortDefinitions(true, true);
251 // reset buffer size based on frame size
252 newParams->nBufferSize = def->nBufferSize;
254 // For input port, we only set nFrameWidth and nFrameHeight. Buffer size
255 // is updated when configuring the output port using the max-frame-size,
256 // though client can still request a larger size.
257 ALOGV("OMX_IndexParamPortDefinition (input) width=%d height=%d", newWidth, newHeight);
258 def->format.video.nFrameWidth = newWidth;
259 def->format.video.nFrameHeight = newHeight;
260 mCtx->width = newWidth;
261 mCtx->height = newHeight;
264 return SoftVideoDecoderOMXComponent::internalSetParameter(index, params);
267 case OMX_IndexParamVideoWmv:
269 OMX_VIDEO_PARAM_WMVTYPE *profile =
270 (OMX_VIDEO_PARAM_WMVTYPE *)params;
272 if (profile->nPortIndex != kInputPortIndex) {
273 return OMX_ErrorUndefined;
276 if (profile->eFormat == OMX_VIDEO_WMVFormat7) {
277 mCtx->codec_id = AV_CODEC_ID_WMV1;
278 } else if (profile->eFormat == OMX_VIDEO_WMVFormat8) {
279 mCtx->codec_id = AV_CODEC_ID_WMV2;
280 } else if (profile->eFormat == OMX_VIDEO_WMVFormat9) {
281 mCtx->codec_id = AV_CODEC_ID_WMV3;
283 mCtx->codec_id = AV_CODEC_ID_VC1;
286 return OMX_ErrorNone;
289 case OMX_IndexParamVideoRv:
291 OMX_VIDEO_PARAM_RVTYPE *profile =
292 (OMX_VIDEO_PARAM_RVTYPE *)params;
294 if (profile->nPortIndex != kInputPortIndex) {
295 return OMX_ErrorUndefined;
298 if (profile->eFormat == OMX_VIDEO_RVFormatG2) {
299 mCtx->codec_id = AV_CODEC_ID_RV20;
300 } else if (profile->eFormat == OMX_VIDEO_RVFormat8) {
301 mCtx->codec_id = AV_CODEC_ID_RV30;
302 } else if (profile->eFormat == OMX_VIDEO_RVFormat9) {
303 mCtx->codec_id = AV_CODEC_ID_RV40;
305 ALOGE("unsupported rv codec: 0x%x", profile->eFormat);
306 return OMX_ErrorUndefined;
309 return OMX_ErrorNone;
314 if (index != (OMX_INDEXTYPE)OMX_IndexParamVideoFFmpeg) {
315 return SoftVideoDecoderOMXComponent::internalSetParameter(index, params);
318 OMX_VIDEO_PARAM_FFMPEGTYPE *profile =
319 (OMX_VIDEO_PARAM_FFMPEGTYPE *)params;
321 if (profile->nPortIndex != kInputPortIndex) {
322 return OMX_ErrorUndefined;
325 mCtx->codec_id = (enum AVCodecID)profile->eCodecId;
326 mCtx->width = profile->nWidth;
327 mCtx->height = profile->nHeight;
329 ALOGD("got OMX_IndexParamVideoFFmpeg, "
330 "eCodecId:%d(%s), width:%u, height:%u",
332 avcodec_get_name(mCtx->codec_id),
336 return OMX_ErrorNone;
341 int32_t SoftFFmpegVideo::handleExtradata() {
342 List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
343 BufferInfo *inInfo = *inQueue.begin();
344 OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
346 ALOGI("got extradata, ignore: %d, size: %u",
347 mIgnoreExtradata, inHeader->nFilledLen);
348 hexdump(inHeader->pBuffer + inHeader->nOffset, inHeader->nFilledLen);
350 if (mIgnoreExtradata) {
351 ALOGI("got extradata, size: %u, but ignore it", inHeader->nFilledLen);
353 if (!mExtradataReady) {
354 //if (mMode == MODE_H264)
355 //it is possible to receive multiple input buffer with OMX_BUFFERFLAG_CODECCONFIG flag.
356 //for example, H264, the first input buffer is SPS, and another is PPS!
357 int orig_extradata_size = mCtx->extradata_size;
358 mCtx->extradata_size += inHeader->nFilledLen;
359 mCtx->extradata = (uint8_t *)realloc(mCtx->extradata,
360 mCtx->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
361 if (!mCtx->extradata) {
362 ALOGE("ffmpeg video decoder failed to alloc extradata memory.");
366 memcpy(mCtx->extradata + orig_extradata_size,
367 inHeader->pBuffer + inHeader->nOffset,
368 inHeader->nFilledLen);
369 memset(mCtx->extradata + mCtx->extradata_size, 0,
370 FF_INPUT_BUFFER_PADDING_SIZE);
374 inQueue.erase(inQueue.begin());
375 inInfo->mOwnedByUs = false;
376 notifyEmptyBufferDone(inHeader);
381 int32_t SoftFFmpegVideo::openDecoder() {
382 if (mCodecAlreadyOpened) {
386 if (!mExtradataReady) {
387 ALOGI("extradata is ready, size: %d", mCtx->extradata_size);
388 hexdump(mCtx->extradata, mCtx->extradata_size);
389 mExtradataReady = true;
392 //find decoder again as codec_id may have changed
393 mCtx->codec = avcodec_find_decoder(mCtx->codec_id);
395 ALOGE("ffmpeg video decoder failed to find codec");
396 return ERR_CODEC_NOT_FOUND;
399 setDefaultCtx(mCtx, mCtx->codec);
401 ALOGD("begin to open ffmpeg decoder(%s) now",
402 avcodec_get_name(mCtx->codec_id));
404 int err = avcodec_open2(mCtx, mCtx->codec, NULL);
406 ALOGE("ffmpeg video decoder failed to initialize. (%s)", av_err2str(err));
407 return ERR_DECODER_OPEN_FAILED;
409 mCodecAlreadyOpened = true;
411 ALOGD("open ffmpeg video decoder(%s) success",
412 avcodec_get_name(mCtx->codec_id));
414 mFrame = av_frame_alloc();
416 ALOGE("oom for video frame");
423 void SoftFFmpegVideo::initPacket(AVPacket *pkt,
424 OMX_BUFFERHEADERTYPE *inHeader) {
425 memset(pkt, 0, sizeof(AVPacket));
429 pkt->data = (uint8_t *)inHeader->pBuffer + inHeader->nOffset;
430 pkt->size = inHeader->nFilledLen;
431 pkt->pts = inHeader->nTimeStamp;
432 pkt->dts = inHeader->nTimeStamp;
436 pkt->pts = AV_NOPTS_VALUE;
440 if (pkt->pts != AV_NOPTS_VALUE)
442 ALOGV("pkt size:%d, pts:%lld", pkt->size, pkt->pts);
444 ALOGV("pkt size:%d, pts:N/A", pkt->size);
449 int32_t SoftFFmpegVideo::decodeVideo() {
450 int len = 0, err = 0;
452 int32_t ret = ERR_OK;
453 bool is_flush = (mEOSStatus != INPUT_DATA_AVAILABLE);
454 List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
455 BufferInfo *inInfo = NULL;
456 OMX_BUFFERHEADERTYPE *inHeader = NULL;
459 inInfo = *inQueue.begin();
460 CHECK(inInfo != NULL);
461 inHeader = inInfo->mHeader;
465 initPacket(&pkt, inHeader);
467 av_frame_unref(mFrame);
469 err = avcodec_decode_video2(mCtx, mFrame, &gotPic, &pkt);
472 ALOGE("ffmpeg video decoder failed to decode frame. (%d)", err);
473 //don't send error to OMXCodec, skip!
477 ALOGI("ffmpeg video decoder failed to get frame.");
478 //stop sending empty packets if the decoder is finished
479 if (is_flush && mCtx->codec->capabilities & CODEC_CAP_DELAY) {
490 inQueue.erase(inQueue.begin());
491 inInfo->mOwnedByUs = false;
492 notifyEmptyBufferDone(inHeader);
498 int32_t SoftFFmpegVideo::drainOneOutputBuffer() {
499 List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
500 BufferInfo *outInfo = *outQueue.begin();
501 OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
504 int64_t pts = AV_NOPTS_VALUE;
505 uint8_t *dst = outHeader->pBuffer;
507 uint32_t width = outputBufferWidth();
508 uint32_t height = outputBufferHeight();
510 memset(&pict, 0, sizeof(AVPicture));
512 pict.data[1] = dst + width * height;
513 pict.data[2] = pict.data[1] + (width / 2 * height / 2);
514 pict.linesize[0] = width;
515 pict.linesize[1] = width / 2;
516 pict.linesize[2] = width / 2;
518 ALOGV("drainOneOutputBuffer: frame_width=%d frame_height=%d width=%d height=%d ctx_width=%d ctx_height=%d", mFrame->width, mFrame->height, width, height, mCtx->width, mCtx->height);
520 int sws_flags = SWS_BICUBIC;
521 mImgConvertCtx = sws_getCachedContext(mImgConvertCtx,
522 mFrame->width, mFrame->height, (AVPixelFormat)mFrame->format, width, height,
523 PIX_FMT_YUV420P, sws_flags, NULL, NULL, NULL);
524 if (mImgConvertCtx == NULL) {
525 ALOGE("Cannot initialize the conversion context");
526 return ERR_SWS_FAILED;
528 sws_scale(mImgConvertCtx, mFrame->data, mFrame->linesize,
529 0, height, pict.data, pict.linesize);
531 outHeader->nOffset = 0;
532 outHeader->nFilledLen = (outputBufferWidth() * outputBufferHeight() * 3) / 2;
533 outHeader->nFlags = 0;
534 if (mFrame->key_frame) {
535 outHeader->nFlags |= OMX_BUFFERFLAG_SYNCFRAME;
539 if (decoder_reorder_pts == -1) {
540 pts = av_frame_get_best_effort_timestamp(mFrame);
541 } else if (decoder_reorder_pts) {
542 pts = mFrame->pkt_pts;
544 pts = mFrame->pkt_dts;
547 if (pts == AV_NOPTS_VALUE) {
550 outHeader->nTimeStamp = pts; //FIXME pts is right???
553 ALOGV("mFrame pkt_pts: %lld pkt_dts: %lld used %lld", mFrame->pkt_pts, mFrame->pkt_dts, pts);
556 outQueue.erase(outQueue.begin());
557 outInfo->mOwnedByUs = false;
558 notifyFillBufferDone(outHeader);
563 void SoftFFmpegVideo::drainEOSOutputBuffer() {
564 List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
565 BufferInfo *outInfo = *outQueue.begin();
566 CHECK(outInfo != NULL);
567 outQueue.erase(outQueue.begin());
568 OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
570 ALOGD("ffmpeg video decoder fill eos outbuf");
572 outHeader->nTimeStamp = 0;
573 outHeader->nFilledLen = 0;
574 outHeader->nFlags = OMX_BUFFERFLAG_EOS;
576 outInfo->mOwnedByUs = false;
577 notifyFillBufferDone(outHeader);
579 mEOSStatus = OUTPUT_FRAMES_FLUSHED;
582 void SoftFFmpegVideo::drainAllOutputBuffers() {
583 List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
584 if (!mCodecAlreadyOpened) {
585 drainEOSOutputBuffer();
586 mEOSStatus = OUTPUT_FRAMES_FLUSHED;
590 if(!(mCtx->codec->capabilities & CODEC_CAP_DELAY)) {
591 drainEOSOutputBuffer();
592 mEOSStatus = OUTPUT_FRAMES_FLUSHED;
596 while (!outQueue.empty()) {
597 int32_t err = decodeVideo();
599 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
600 mSignalledError = true;
602 } else if (err == ERR_FLUSHED) {
603 drainEOSOutputBuffer();
606 CHECK_EQ(err, ERR_OK);
608 if (drainOneOutputBuffer() != ERR_OK) {
609 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
610 mSignalledError = true;
616 bool SoftFFmpegVideo::handlePortSettingsChange() {
617 CropSettingsMode crop = kCropUnSet;
618 uint32_t width = outputBufferWidth();
619 uint32_t height = outputBufferHeight();
620 if (width != (uint32_t)mCtx->width || height != (uint32_t)mCtx->height) {
622 if (mCropWidth != width || mCropHeight != height) {
626 mCropHeight = height;
631 bool portWillReset = false;
632 SoftVideoDecoderOMXComponent::handlePortSettingsChange(
633 &portWillReset, mCtx->width, mCtx->height, crop);
634 return portWillReset;
637 void SoftFFmpegVideo::onQueueFilled(OMX_U32 portIndex __unused) {
638 if (mSignalledError || mOutputPortSettingsChange != NONE) {
642 if (mEOSStatus == OUTPUT_FRAMES_FLUSHED) {
646 List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
647 List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
649 while (((mEOSStatus != INPUT_DATA_AVAILABLE) || !inQueue.empty())
650 && !outQueue.empty()) {
652 if (mEOSStatus == INPUT_EOS_SEEN) {
653 drainAllOutputBuffers();
657 BufferInfo *inInfo = *inQueue.begin();
658 if (inInfo == NULL) {
661 OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
662 if (inHeader == NULL) {
666 if (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
667 ALOGD("ffmpeg got codecconfig buffer");
668 if (handleExtradata() != ERR_OK) {
669 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
670 mSignalledError = true;
675 if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
676 mEOSStatus = INPUT_EOS_SEEN;
679 if (!mCodecAlreadyOpened) {
680 if (openDecoder() != ERR_OK) {
681 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
682 mSignalledError = true;
687 int32_t err = decodeVideo();
689 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
690 mSignalledError = true;
692 } else if (err == ERR_FLUSHED) {
693 drainEOSOutputBuffer();
695 } else if (err == ERR_NO_FRM) {
698 CHECK_EQ(err, ERR_OK);
701 if (handlePortSettingsChange()) {
702 ALOGV("PORT RESET w=%d h=%d", mCtx->width, mCtx->height);
706 if (drainOneOutputBuffer() != ERR_OK) {
707 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
708 mSignalledError = true;
714 void SoftFFmpegVideo::onPortFlushCompleted(OMX_U32 portIndex) {
715 ALOGV("ffmpeg video decoder flush port(%u)", portIndex);
716 if (portIndex == kInputPortIndex) {
718 //Make sure that the next buffer output does not still
719 //depend on fragments from the last one decoded.
720 avcodec_flush_buffers(mCtx);
722 mEOSStatus = INPUT_DATA_AVAILABLE;
726 void SoftFFmpegVideo::onReset() {
728 SoftVideoDecoderOMXComponent::onReset();
729 mSignalledError = false;
730 mExtradataReady = false;
733 SoftOMXComponent* SoftFFmpegVideo::createSoftOMXComponent(
734 const char *name, const OMX_CALLBACKTYPE *callbacks,
735 OMX_PTR appData, OMX_COMPONENTTYPE **component) {
737 OMX_VIDEO_CODINGTYPE codingType = OMX_VIDEO_CodingAutoDetect;
738 char *componentRole = NULL;
739 enum AVCodecID codecID = AV_CODEC_ID_NONE;
741 for (size_t i = 0; i < kNumVideoComponents; ++i) {
742 if (!strcasecmp(name, kVideoComponents[i].mName)) {
743 componentRole = strdup(kVideoComponents[i].mRole);
744 codingType = kVideoComponents[i].mVideoCodingType;
745 codecID = kVideoComponents[i].mCodecID;
750 if (componentRole == NULL) {
754 return new SoftFFmpegVideo(name, componentRole, codingType,
755 callbacks, appData, component, codecID);
758 } // namespace android