2 * Copyright 2012 Michael Chen <omxcodec@gmail.com>
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #define LOG_TAG "SoftFFmpegVideo"
19 #include <utils/Log.h>
21 #include "SoftFFmpegVideo.h"
23 #include <media/stagefright/foundation/ADebug.h>
24 #include <media/stagefright/foundation/hexdump.h>
25 #include <media/stagefright/MediaDefs.h>
27 #include "ffmpeg_utils/ffmpeg_utils.h"
35 static int decoder_reorder_pts = -1;
40 static void InitOMXParams(T *params) {
41 params->nSize = sizeof(T);
42 params->nVersion.s.nVersionMajor = 1;
43 params->nVersion.s.nVersionMinor = 0;
44 params->nVersion.s.nRevision = 0;
45 params->nVersion.s.nStep = 0;
48 SoftFFmpegVideo::SoftFFmpegVideo(
50 const OMX_CALLBACKTYPE *callbacks,
52 OMX_COMPONENTTYPE **component)
53 : SimpleSoftOMXComponent(name, callbacks, appData, component),
57 mExtradataReady(false),
58 mIgnoreExtradata(false),
59 mSignalledError(false),
63 mOutputPortSettingsChange(NONE) {
64 if (!strcmp(name, "OMX.ffmpeg.mpeg4.decoder")) {
66 } else if (!strcmp(name, "OMX.ffmpeg.mpeg2v.decoder")) {
68 } else if (!strcmp(name, "OMX.ffmpeg.h263.decoder")) {
70 } else if (!strcmp(name, "OMX.ffmpeg.vc1.decoder")) {
73 CHECK(!strcmp(name, "OMX.ffmpeg.h264.decoder"));
74 //mIgnoreExtradata = true;
77 LOGV("SoftFFmpegVideo component: %s", name);
80 CHECK_EQ(initDecoder(), (status_t)OK);
83 SoftFFmpegVideo::~SoftFFmpegVideo() {
84 LOGV("~SoftFFmpegVideo");
89 void SoftFFmpegVideo::initPorts() {
90 OMX_PARAM_PORTDEFINITIONTYPE def;
94 def.eDir = OMX_DirInput;
95 def.nBufferCountMin = kNumInputBuffers;
96 def.nBufferCountActual = def.nBufferCountMin;
97 def.nBufferSize = 1280 * 720; // 256 * 1024?
98 def.bEnabled = OMX_TRUE;
99 def.bPopulated = OMX_FALSE;
100 def.eDomain = OMX_PortDomainVideo;
101 def.bBuffersContiguous = OMX_FALSE;
102 def.nBufferAlignment = 1;
106 def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_AVC);
107 def.format.video.eCompressionFormat = OMX_VIDEO_CodingAVC;
110 def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_MPEG4);
111 def.format.video.eCompressionFormat = OMX_VIDEO_CodingMPEG4;
114 def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_MPEG2);
115 def.format.video.eCompressionFormat = OMX_VIDEO_CodingMPEG2;
118 def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_H263);
119 def.format.video.eCompressionFormat = OMX_VIDEO_CodingH263;
122 def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_VC1);
123 def.format.video.eCompressionFormat = OMX_VIDEO_CodingWMV;
126 CHECK(!"Should not be here. Unsupported mime type and compression format");
130 def.format.video.pNativeRender = NULL;
131 def.format.video.nFrameWidth = mWidth;
132 def.format.video.nFrameHeight = mHeight;
133 def.format.video.nStride = def.format.video.nFrameWidth;
134 def.format.video.nSliceHeight = def.format.video.nFrameHeight;
135 def.format.video.nBitrate = 0;
136 def.format.video.xFramerate = 0;
137 def.format.video.bFlagErrorConcealment = OMX_FALSE;
138 def.format.video.eColorFormat = OMX_COLOR_FormatUnused;
139 def.format.video.pNativeWindow = NULL;
144 def.eDir = OMX_DirOutput;
145 def.nBufferCountMin = kNumOutputBuffers;
146 def.nBufferCountActual = def.nBufferCountMin;
147 def.bEnabled = OMX_TRUE;
148 def.bPopulated = OMX_FALSE;
149 def.eDomain = OMX_PortDomainVideo;
150 def.bBuffersContiguous = OMX_FALSE;
151 def.nBufferAlignment = 2;
153 def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_RAW);
154 def.format.video.pNativeRender = NULL;
155 def.format.video.nFrameWidth = mWidth;
156 def.format.video.nFrameHeight = mHeight;
157 def.format.video.nStride = def.format.video.nFrameWidth;
158 def.format.video.nSliceHeight = def.format.video.nFrameHeight;
159 def.format.video.nBitrate = 0;
160 def.format.video.xFramerate = 0;
161 def.format.video.bFlagErrorConcealment = OMX_FALSE;
162 def.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused;
163 def.format.video.eColorFormat = OMX_COLOR_FormatYUV420Planar;
164 def.format.video.pNativeWindow = NULL;
167 (def.format.video.nFrameWidth * def.format.video.nFrameHeight * 3) / 2;
172 static int lockmgr(void **mtx, enum AVLockOp op) {
175 *mtx = (void *)SDL_CreateMutex();
180 return !!SDL_LockMutex((SDL_mutex *)*mtx);
181 case AV_LOCK_RELEASE:
182 return !!SDL_UnlockMutex((SDL_mutex *)*mtx);
183 case AV_LOCK_DESTROY:
184 SDL_DestroyMutex((SDL_mutex *)*mtx);
190 status_t SoftFFmpegVideo::initFFmpeg() {
191 //nam_av_log_set_flags(AV_LOG_SKIP_REPEATED);
192 av_log_set_level(AV_LOG_DEBUG);
193 av_log_set_callback(nam_av_log_callback);
195 /* register all codecs, demux and protocols */
196 avcodec_register_all();
198 avdevice_register_all();
201 avformat_network_init();
205 if (av_lockmgr_register(lockmgr)) {
206 LOGE("could not initialize lock manager!");
213 void SoftFFmpegVideo::deInitFFmpeg() {
214 av_lockmgr_register(NULL);
216 avformat_network_deinit();
220 void SoftFFmpegVideo::setAVCtxToDefault(AVCodecContext *avctx, const AVCodec *codec) {
223 avctx->workaround_bugs = 1;
225 if(avctx->lowres > codec->max_lowres){
226 LOGW("The maximum value for lowres supported by the decoder is %d",
228 avctx->lowres= codec->max_lowres;
230 avctx->idct_algo = 0;
231 avctx->skip_frame = AVDISCARD_DEFAULT;
232 avctx->skip_idct = AVDISCARD_DEFAULT;
233 avctx->skip_loop_filter = AVDISCARD_DEFAULT;
234 avctx->error_concealment = 3;
236 if(avctx->lowres) avctx->flags |= CODEC_FLAG_EMU_EDGE;
237 if (fast) avctx->flags2 |= CODEC_FLAG2_FAST;
238 if(codec->capabilities & CODEC_CAP_DR1)
239 avctx->flags |= CODEC_FLAG_EMU_EDGE;
242 status_t SoftFFmpegVideo::initDecoder() {
245 status = initFFmpeg();
249 mCtx = avcodec_alloc_context3(NULL);
252 LOGE("avcodec_alloc_context failed.");
253 return OMX_ErrorInsufficientResources;
256 mCtx->codec_type = AVMEDIA_TYPE_VIDEO;
259 mCtx->codec_id = CODEC_ID_H264;
262 mCtx->codec_id = CODEC_ID_MPEG4;
265 mCtx->codec_id = CODEC_ID_MPEG2VIDEO;
268 mCtx->codec_id = CODEC_ID_H263;
270 //mCtx->codec_id = CODEC_ID_H263P;
271 //mCtx->codec_id = CODEC_ID_H263I;
274 mCtx->codec_id = CODEC_ID_VC1;
277 CHECK(!"Should not be here. Unsupported codec");
281 mCtx->codec = avcodec_find_decoder(mCtx->codec_id);
284 LOGE("find codec failed");
285 return OMX_ErrorNotImplemented;
288 setAVCtxToDefault(mCtx, mCtx->codec);
290 mCtx->extradata_size = 0;
291 mCtx->extradata = NULL;
292 mCtx->width = mWidth;
293 mCtx->height = mHeight;
296 // FIXME, defer to open? ref: OMXCodec.cpp:setVideoOutputFormat
297 err = avcodec_open2(mCtx, mCtx->codec, NULL);
299 LOGE("ffmpeg video decoder failed to initialize. (%d)", err);
300 return OMX_ErrorUndefined;
304 return OMX_ErrorNone;
307 void SoftFFmpegVideo::deInitDecoder() {
309 avcodec_flush_buffers(mCtx);
310 if (!mCtx->extradata) {
311 av_free(mCtx->extradata);
312 mCtx->extradata = NULL;
313 mCtx->extradata_size = 0;
320 if (mImgConvertCtx) {
321 sws_freeContext(mImgConvertCtx);
322 mImgConvertCtx = NULL;
326 OMX_ERRORTYPE SoftFFmpegVideo::internalGetParameter(
327 OMX_INDEXTYPE index, OMX_PTR params) {
329 case OMX_IndexParamVideoPortFormat:
331 OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams =
332 (OMX_VIDEO_PARAM_PORTFORMATTYPE *)params;
334 if (formatParams->nPortIndex > 1) {
335 return OMX_ErrorUndefined;
338 if (formatParams->nIndex != 0) {
339 return OMX_ErrorNoMore;
342 if (formatParams->nPortIndex == 0) {
345 formatParams->eCompressionFormat = OMX_VIDEO_CodingAVC;
348 formatParams->eCompressionFormat = OMX_VIDEO_CodingMPEG4;
351 formatParams->eCompressionFormat = OMX_VIDEO_CodingMPEG2;
354 formatParams->eCompressionFormat = OMX_VIDEO_CodingH263;
357 formatParams->eCompressionFormat = OMX_VIDEO_CodingWMV;
360 CHECK(!"Should not be here. Unsupported compression format.");
363 formatParams->eColorFormat = OMX_COLOR_FormatUnused;
364 formatParams->xFramerate = 0;
366 CHECK_EQ(formatParams->nPortIndex, 1u);
368 formatParams->eCompressionFormat = OMX_VIDEO_CodingUnused;
369 formatParams->eColorFormat = OMX_COLOR_FormatYUV420Planar;
370 formatParams->xFramerate = 0;
373 return OMX_ErrorNone;
377 return SimpleSoftOMXComponent::internalGetParameter(index, params);
381 OMX_ERRORTYPE SoftFFmpegVideo::internalSetParameter(
382 OMX_INDEXTYPE index, const OMX_PTR params) {
384 case OMX_IndexParamStandardComponentRole:
386 const OMX_PARAM_COMPONENTROLETYPE *roleParams =
387 (const OMX_PARAM_COMPONENTROLETYPE *)params;
389 bool supported = true;
392 if (strncmp((const char *)roleParams->cRole,
393 "video_decoder.avc", OMX_MAX_STRINGNAME_SIZE - 1))
397 if (strncmp((const char *)roleParams->cRole,
398 "video_decoder.mpeg4", OMX_MAX_STRINGNAME_SIZE - 1))
402 if (strncmp((const char *)roleParams->cRole,
403 "video_decoder.mpeg2v", OMX_MAX_STRINGNAME_SIZE - 1))
407 if (strncmp((const char *)roleParams->cRole,
408 "video_decoder.h263", OMX_MAX_STRINGNAME_SIZE - 1))
412 if (strncmp((const char *)roleParams->cRole,
413 "video_decoder.vc1", OMX_MAX_STRINGNAME_SIZE - 1))
417 CHECK(!"Should not be here. Unsupported role.");
421 LOGE("unsupported role: %s", (const char *)roleParams->cRole);
422 return OMX_ErrorUndefined;
425 return OMX_ErrorNone;
428 case OMX_IndexParamVideoPortFormat:
430 OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams =
431 (OMX_VIDEO_PARAM_PORTFORMATTYPE *)params;
433 if (formatParams->nPortIndex > 1) {
434 return OMX_ErrorUndefined;
437 if (formatParams->nIndex != 0) {
438 return OMX_ErrorNoMore;
441 return OMX_ErrorNone;
444 case OMX_IndexParamPortDefinition:
446 OMX_PARAM_PORTDEFINITIONTYPE *defParams =
447 (OMX_PARAM_PORTDEFINITIONTYPE *)params;
449 if (defParams->nPortIndex > 1 ||
450 defParams->nSize != sizeof(OMX_PARAM_PORTDEFINITIONTYPE)) {
451 return OMX_ErrorUndefined;
454 CHECK_EQ((int)defParams->eDomain, (int)OMX_PortDomainVideo);
456 // only care about input port
457 if (defParams->nPortIndex == kPortIndexOutput) {
458 OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &defParams->format.video;
459 mWidth = video_def->nFrameWidth;
460 mHeight = video_def->nFrameHeight;
461 LOGV("got OMX_IndexParamPortDefinition, mWidth: %d, mHeight: %d",
463 return OMX_ErrorNone;
468 return SimpleSoftOMXComponent::internalSetParameter(index, params);
472 void SoftFFmpegVideo::onQueueFilled(OMX_U32 portIndex) {
475 if (mSignalledError || mOutputPortSettingsChange != NONE) {
479 List<BufferInfo *> &inQueue = getPortQueue(0);
480 List<BufferInfo *> &outQueue = getPortQueue(1);
482 while (!inQueue.empty() && !outQueue.empty()) {
483 BufferInfo *inInfo = *inQueue.begin();
484 OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
486 BufferInfo *outInfo = *outQueue.begin();
487 OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
489 if (mCtx->width != mWidth || mCtx->height != mHeight) {
490 mCtx->width = mWidth;
491 mCtx->height = mHeight;
494 updatePortDefinitions();
496 notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
497 mOutputPortSettingsChange = AWAITING_DISABLED;
501 if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
502 inQueue.erase(inQueue.begin());
503 inInfo->mOwnedByUs = false;
504 notifyEmptyBufferDone(inHeader);
506 outHeader->nFilledLen = 0;
507 outHeader->nFlags = OMX_BUFFERFLAG_EOS;
509 outQueue.erase(outQueue.begin());
510 outInfo->mOwnedByUs = false;
511 notifyFillBufferDone(outHeader);
515 if (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
516 LOGI("got extradata, ignore: %d, size: %lu", mIgnoreExtradata, inHeader->nFilledLen);
517 hexdump(inHeader->pBuffer + inHeader->nOffset, inHeader->nFilledLen);
518 if (!mExtradataReady && !mIgnoreExtradata) {
519 //if (mMode == MODE_H264)
520 // it is possible to receive multiple input buffer with OMX_BUFFERFLAG_CODECCONFIG flag.
521 // for example, H264, the first input buffer is SPS, and another is PPS!
522 int orig_extradata_size = mCtx->extradata_size;
523 mCtx->extradata_size += inHeader->nFilledLen;
524 mCtx->extradata = (uint8_t *)realloc(mCtx->extradata,
525 mCtx->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
526 if (!mCtx->extradata) {
527 LOGE("ffmpeg video decoder failed to alloc extradata memory.");
528 notify(OMX_EventError, OMX_ErrorInsufficientResources, 0, NULL);
529 mSignalledError = true;
533 memcpy(mCtx->extradata + orig_extradata_size,
534 inHeader->pBuffer + inHeader->nOffset, inHeader->nFilledLen);
535 memset(mCtx->extradata + mCtx->extradata_size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
537 inInfo->mOwnedByUs = false;
538 inQueue.erase(inQueue.begin());
540 notifyEmptyBufferDone(inHeader);
546 if (mIgnoreExtradata) {
547 LOGI("got extradata, size: %lu, but ignore it", inHeader->nFilledLen);
548 inInfo->mOwnedByUs = false;
549 inQueue.erase(inQueue.begin());
551 notifyEmptyBufferDone(inHeader);
559 av_init_packet(&pkt);
560 pkt.data = (uint8_t *)inHeader->pBuffer + inHeader->nOffset;
561 pkt.size = inHeader->nFilledLen;
562 pkt.pts = inHeader->nTimeStamp;
564 LOGV("pkt size: %d, pts: %lld", pkt.size, pkt.pts);
566 if (!mExtradataReady) {
567 LOGI("extradata is ready");
568 hexdump(mCtx->extradata, mCtx->extradata_size);
569 LOGI("open ffmpeg decoder now");
570 mExtradataReady = true;
572 err = avcodec_open2(mCtx, mCtx->codec, NULL);
574 LOGE("ffmpeg video decoder failed to initialize. (%d)", err);
575 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
576 mSignalledError = true;
582 AVFrame *frame = avcodec_alloc_frame();
583 err = avcodec_decode_video2(mCtx, frame, &gotPic, &pkt);
585 LOGE("ffmpeg video decoder failed to decode frame. (%d)", err);
586 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
587 mSignalledError = true;
594 int64_t pts = AV_NOPTS_VALUE;
595 uint8_t *dst = outHeader->pBuffer;
597 memset(&pict, 0, sizeof(AVPicture));
599 pict.data[1] = dst + mStride * mHeight;
600 pict.data[2] = pict.data[1] + (mStride / 2 * mHeight / 2);
601 pict.linesize[0] = mStride;
602 pict.linesize[1] = mStride / 2;
603 pict.linesize[2] = mStride / 2;
605 int sws_flags = SWS_BICUBIC;
606 mImgConvertCtx = sws_getCachedContext(mImgConvertCtx,
607 mWidth, mHeight, mCtx->pix_fmt, mWidth, mHeight,
608 PIX_FMT_YUV420P, sws_flags, NULL, NULL, NULL);
609 if (mImgConvertCtx == NULL) {
610 LOGE("Cannot initialize the conversion context");
611 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
612 mSignalledError = true;
616 sws_scale(mImgConvertCtx, frame->data, frame->linesize,
617 0, mHeight, pict.data, pict.linesize);
619 outHeader->nOffset = 0;
620 outHeader->nFilledLen = (mStride * mHeight * 3) / 2;
621 outHeader->nFlags = 0;
622 if (frame->key_frame)
623 outHeader->nFlags |= OMX_BUFFERFLAG_SYNCFRAME;
625 // process timestamps
626 if (decoder_reorder_pts == -1) {
627 pts = *(int64_t*)av_opt_ptr(avcodec_get_frame_class(),
628 frame, "best_effort_timestamp");
629 } else if (decoder_reorder_pts) {
630 pts = frame->pkt_pts;
632 pts = frame->pkt_dts;
635 if (pts == AV_NOPTS_VALUE) {
638 outHeader->nTimeStamp = pts;
641 LOGV("frame pts: %lld", pts);
644 outInfo->mOwnedByUs = false;
645 outQueue.erase(outQueue.begin());
647 notifyFillBufferDone(outHeader);
651 inInfo->mOwnedByUs = false;
652 inQueue.erase(inQueue.begin());
654 notifyEmptyBufferDone(inHeader);
660 void SoftFFmpegVideo::onPortFlushCompleted(OMX_U32 portIndex) {
661 if (portIndex == 0 && mCtx) {
662 // Make sure that the next buffer output does not still
663 // depend on fragments from the last one decoded.
664 avcodec_flush_buffers(mCtx);
668 void SoftFFmpegVideo::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
669 if (portIndex != 1) {
673 switch (mOutputPortSettingsChange) {
677 case AWAITING_DISABLED:
680 mOutputPortSettingsChange = AWAITING_ENABLED;
686 CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED);
688 mOutputPortSettingsChange = NONE;
694 void SoftFFmpegVideo::updatePortDefinitions() {
695 OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(0)->mDef;
696 def->format.video.nFrameWidth = mWidth;
697 def->format.video.nFrameHeight = mHeight;
698 def->format.video.nStride = def->format.video.nFrameWidth;
699 def->format.video.nSliceHeight = def->format.video.nFrameHeight;
701 def->format.video.nFrameWidth * def->format.video.nFrameHeight;
703 def = &editPortInfo(1)->mDef;
704 def->format.video.nFrameWidth = mWidth;
705 def->format.video.nFrameHeight = mHeight;
706 def->format.video.nStride = def->format.video.nFrameWidth;
707 def->format.video.nSliceHeight = def->format.video.nFrameHeight;
710 (def->format.video.nFrameWidth
711 * def->format.video.nFrameHeight * 3) / 2;
714 (((def->format.video.nFrameWidth + 15) & -16)
715 * ((def->format.video.nFrameHeight + 15) & -16) * 3) / 2;
719 } // namespace android
721 android::SoftOMXComponent *createSoftOMXComponent(
722 const char *name, const OMX_CALLBACKTYPE *callbacks,
723 OMX_PTR appData, OMX_COMPONENTTYPE **component) {
724 return new android::SoftFFmpegVideo(name, callbacks, appData, component);