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.
17 //#define LOG_NDEBUG 0
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 "utils/common_utils.h"
28 #include "utils/ffmpeg_utils.h"
36 static int decoder_reorder_pts = -1;
41 static void InitOMXParams(T *params) {
42 params->nSize = sizeof(T);
43 params->nVersion.s.nVersionMajor = 1;
44 params->nVersion.s.nVersionMinor = 0;
45 params->nVersion.s.nRevision = 0;
46 params->nVersion.s.nStep = 0;
49 SoftFFmpegVideo::SoftFFmpegVideo(
51 const OMX_CALLBACKTYPE *callbacks,
53 OMX_COMPONENTTYPE **component)
54 : SimpleSoftOMXComponent(name, callbacks, appData, component),
58 mExtradataReady(false),
59 mIgnoreExtradata(false),
60 mSignalledError(false),
65 mOutputPortSettingsChange(NONE) {
66 if (!strcmp(name, "OMX.ffmpeg.mpeg4.decoder")) {
68 } else if (!strcmp(name, "OMX.ffmpeg.mpeg2v.decoder")) {
70 } else if (!strcmp(name, "OMX.ffmpeg.h263.decoder")) {
72 } else if (!strcmp(name, "OMX.ffmpeg.vpx.decoder")) {
74 } else if (!strcmp(name, "OMX.ffmpeg.vc1.decoder")) {
76 } else if (!strcmp(name, "OMX.ffmpeg.divx.decoder")) {
78 } else if (!strcmp(name, "OMX.ffmpeg.wmv.decoder")) {
80 } else if (!strcmp(name, "OMX.ffmpeg.flv.decoder")) {
82 } else if (!strcmp(name, "OMX.ffmpeg.rv.decoder")) {
85 CHECK(!strcmp(name, "OMX.ffmpeg.h264.decoder"));
88 LOGV("SoftFFmpegVideo component: %s", name);
91 CHECK_EQ(initDecoder(), (status_t)OK);
94 SoftFFmpegVideo::~SoftFFmpegVideo() {
95 LOGV("~SoftFFmpegVideo");
100 void SoftFFmpegVideo::initPorts() {
101 OMX_PARAM_PORTDEFINITIONTYPE def;
105 def.eDir = OMX_DirInput;
106 def.nBufferCountMin = kNumInputBuffers;
107 def.nBufferCountActual = def.nBufferCountMin;
108 def.nBufferSize = 1280 * 720; // 256 * 1024?
109 def.bEnabled = OMX_TRUE;
110 def.bPopulated = OMX_FALSE;
111 def.eDomain = OMX_PortDomainVideo;
112 def.bBuffersContiguous = OMX_FALSE;
113 def.nBufferAlignment = 1;
117 def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_AVC);
118 def.format.video.eCompressionFormat = OMX_VIDEO_CodingAVC;
121 def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_MPEG4);
122 def.format.video.eCompressionFormat = OMX_VIDEO_CodingMPEG4;
125 def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_MPEG2);
126 def.format.video.eCompressionFormat = OMX_VIDEO_CodingMPEG2;
129 def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_H263);
130 def.format.video.eCompressionFormat = OMX_VIDEO_CodingH263;
133 def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_VC1);
134 def.format.video.eCompressionFormat = OMX_VIDEO_CodingWMV;
137 def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_WMV);
138 def.format.video.eCompressionFormat = OMX_VIDEO_CodingWMV;
141 CHECK(!"Should not be here. Unsupported mime type and compression format");
145 def.format.video.pNativeRender = NULL;
146 def.format.video.nFrameWidth = mWidth;
147 def.format.video.nFrameHeight = mHeight;
148 def.format.video.nStride = def.format.video.nFrameWidth;
149 def.format.video.nSliceHeight = def.format.video.nFrameHeight;
150 def.format.video.nBitrate = 0;
151 def.format.video.xFramerate = 0;
152 def.format.video.bFlagErrorConcealment = OMX_FALSE;
153 def.format.video.eColorFormat = OMX_COLOR_FormatUnused;
154 def.format.video.pNativeWindow = NULL;
159 def.eDir = OMX_DirOutput;
160 def.nBufferCountMin = kNumOutputBuffers;
161 def.nBufferCountActual = def.nBufferCountMin;
162 def.bEnabled = OMX_TRUE;
163 def.bPopulated = OMX_FALSE;
164 def.eDomain = OMX_PortDomainVideo;
165 def.bBuffersContiguous = OMX_FALSE;
166 def.nBufferAlignment = 2;
168 def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_RAW);
169 def.format.video.pNativeRender = NULL;
170 def.format.video.nFrameWidth = mWidth;
171 def.format.video.nFrameHeight = mHeight;
172 def.format.video.nStride = def.format.video.nFrameWidth;
173 def.format.video.nSliceHeight = def.format.video.nFrameHeight;
174 def.format.video.nBitrate = 0;
175 def.format.video.xFramerate = 0;
176 def.format.video.bFlagErrorConcealment = OMX_FALSE;
177 def.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused;
178 def.format.video.eColorFormat = OMX_COLOR_FormatYUV420Planar;
179 def.format.video.pNativeWindow = NULL;
182 (def.format.video.nFrameWidth * def.format.video.nFrameHeight * 3) / 2;
187 void SoftFFmpegVideo::setAVCtxToDefault(AVCodecContext *avctx, const AVCodec *codec) {
190 avctx->workaround_bugs = 1;
192 if(avctx->lowres > codec->max_lowres){
193 LOGW("The maximum value for lowres supported by the decoder is %d",
195 avctx->lowres= codec->max_lowres;
197 avctx->idct_algo = 0;
198 avctx->skip_frame = AVDISCARD_DEFAULT;
199 avctx->skip_idct = AVDISCARD_DEFAULT;
200 avctx->skip_loop_filter = AVDISCARD_DEFAULT;
201 avctx->error_concealment = 3;
203 if(avctx->lowres) avctx->flags |= CODEC_FLAG_EMU_EDGE;
204 if (fast) avctx->flags2 |= CODEC_FLAG2_FAST;
205 if(codec->capabilities & CODEC_CAP_DR1)
206 avctx->flags |= CODEC_FLAG_EMU_EDGE;
209 status_t SoftFFmpegVideo::initDecoder() {
212 status = initFFmpeg();
216 mCtx = avcodec_alloc_context3(NULL);
219 LOGE("avcodec_alloc_context failed.");
223 mCtx->codec_type = AVMEDIA_TYPE_VIDEO;
226 mCtx->codec_id = CODEC_ID_H264;
229 mCtx->codec_id = CODEC_ID_MPEG4;
232 mCtx->codec_id = CODEC_ID_MPEG2VIDEO;
235 mCtx->codec_id = CODEC_ID_H263;
237 //mCtx->codec_id = CODEC_ID_H263P;
238 //mCtx->codec_id = CODEC_ID_H263I;
241 mCtx->codec_id = CODEC_ID_VC1;
244 mCtx->codec_id = CODEC_ID_WMV2; // default, adjust in "internalSetParameter" fxn
247 CHECK(!"Should not be here. Unsupported codec");
251 mCtx->codec = avcodec_find_decoder(mCtx->codec_id);
254 LOGE("find codec failed");
258 setAVCtxToDefault(mCtx, mCtx->codec);
260 mCtx->extradata_size = 0;
261 mCtx->extradata = NULL;
262 mCtx->width = mWidth;
263 mCtx->height = mHeight;
268 void SoftFFmpegVideo::deInitDecoder() {
270 avcodec_flush_buffers(mCtx);
271 if (!mCtx->extradata) {
272 av_free(mCtx->extradata);
273 mCtx->extradata = NULL;
274 mCtx->extradata_size = 0;
281 if (mImgConvertCtx) {
282 sws_freeContext(mImgConvertCtx);
283 mImgConvertCtx = NULL;
287 void SoftFFmpegVideo::preProcessVideoFrame(AVPicture *picture, void **bufp)
290 AVPicture picture_tmp;
293 /* deinterlace : must be done before any resize */
294 if (mDoDeinterlace) {
297 /* create temporary picture */
298 size = avpicture_get_size(mCtx->pix_fmt, mCtx->width, mCtx->height);
299 buf = (uint8_t *)av_malloc(size);
303 picture2 = &picture_tmp;
304 avpicture_fill(picture2, buf, mCtx->pix_fmt, mCtx->width, mCtx->height);
306 if (avpicture_deinterlace(picture2, picture,
307 mCtx->pix_fmt, mCtx->width, mCtx->height) < 0) {
308 /* if error, do not deinterlace */
309 LOGE("Deinterlacing failed");
318 if (picture != picture2)
319 *picture = *picture2;
323 OMX_ERRORTYPE SoftFFmpegVideo::internalGetParameter(
324 OMX_INDEXTYPE index, OMX_PTR params) {
326 case OMX_IndexParamVideoPortFormat:
328 OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams =
329 (OMX_VIDEO_PARAM_PORTFORMATTYPE *)params;
331 if (formatParams->nPortIndex > 1) {
332 return OMX_ErrorUndefined;
335 if (formatParams->nIndex != 0) {
336 return OMX_ErrorNoMore;
339 if (formatParams->nPortIndex == 0) {
342 formatParams->eCompressionFormat = OMX_VIDEO_CodingAVC;
345 formatParams->eCompressionFormat = OMX_VIDEO_CodingMPEG4;
348 formatParams->eCompressionFormat = OMX_VIDEO_CodingMPEG2;
351 formatParams->eCompressionFormat = OMX_VIDEO_CodingH263;
354 formatParams->eCompressionFormat = OMX_VIDEO_CodingWMV;
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;
376 case OMX_IndexParamVideoWmv:
378 OMX_VIDEO_PARAM_WMVTYPE *wmvParams =
379 (OMX_VIDEO_PARAM_WMVTYPE *)params;
381 if (wmvParams->nPortIndex != 0) {
382 return OMX_ErrorUndefined;
385 wmvParams->eFormat = OMX_VIDEO_WMVFormatUnused;
387 return OMX_ErrorNone;
391 return SimpleSoftOMXComponent::internalGetParameter(index, params);
395 OMX_ERRORTYPE SoftFFmpegVideo::internalSetParameter(
396 OMX_INDEXTYPE index, const OMX_PTR params) {
398 case OMX_IndexParamStandardComponentRole:
400 const OMX_PARAM_COMPONENTROLETYPE *roleParams =
401 (const OMX_PARAM_COMPONENTROLETYPE *)params;
403 bool supported = true;
406 if (strncmp((const char *)roleParams->cRole,
407 "video_decoder.avc", OMX_MAX_STRINGNAME_SIZE - 1))
411 if (strncmp((const char *)roleParams->cRole,
412 "video_decoder.mpeg4", OMX_MAX_STRINGNAME_SIZE - 1))
416 if (strncmp((const char *)roleParams->cRole,
417 "video_decoder.mpeg2v", OMX_MAX_STRINGNAME_SIZE - 1))
421 if (strncmp((const char *)roleParams->cRole,
422 "video_decoder.h263", OMX_MAX_STRINGNAME_SIZE - 1))
426 if (strncmp((const char *)roleParams->cRole,
427 "video_decoder.vc1", OMX_MAX_STRINGNAME_SIZE - 1))
431 if (strncmp((const char *)roleParams->cRole,
432 "video_decoder.wmv", OMX_MAX_STRINGNAME_SIZE - 1))
436 CHECK(!"Should not be here. Unsupported role.");
440 LOGE("unsupported role: %s", (const char *)roleParams->cRole);
441 return OMX_ErrorUndefined;
444 return OMX_ErrorNone;
447 case OMX_IndexParamVideoPortFormat:
449 OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams =
450 (OMX_VIDEO_PARAM_PORTFORMATTYPE *)params;
452 if (formatParams->nPortIndex > 1) {
453 return OMX_ErrorUndefined;
456 if (formatParams->nIndex != 0) {
457 return OMX_ErrorNoMore;
460 return OMX_ErrorNone;
463 case OMX_IndexParamPortDefinition:
465 OMX_PARAM_PORTDEFINITIONTYPE *defParams =
466 (OMX_PARAM_PORTDEFINITIONTYPE *)params;
468 if (defParams->nPortIndex > 1 ||
469 defParams->nSize != sizeof(OMX_PARAM_PORTDEFINITIONTYPE)) {
470 return OMX_ErrorUndefined;
473 CHECK_EQ((int)defParams->eDomain, (int)OMX_PortDomainVideo);
475 // only care about input port
476 if (defParams->nPortIndex == kPortIndexOutput) {
477 OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &defParams->format.video;
478 mWidth = video_def->nFrameWidth;
479 mHeight = video_def->nFrameHeight;
480 LOGV("got OMX_IndexParamPortDefinition, mWidth: %d, mHeight: %d",
482 return OMX_ErrorNone;
485 return OMX_ErrorNone;
488 case OMX_IndexParamVideoWmv:
490 OMX_VIDEO_PARAM_WMVTYPE *wmvParams =
491 (OMX_VIDEO_PARAM_WMVTYPE *)params;
493 if (wmvParams->nPortIndex != 0) {
494 return OMX_ErrorUndefined;
497 if (wmvParams->eFormat == OMX_VIDEO_WMVFormat7) {
498 mCtx->codec_id = CODEC_ID_WMV1;
499 } else if (wmvParams->eFormat == OMX_VIDEO_WMVFormat8) {
500 mCtx->codec_id = CODEC_ID_WMV2;
501 } else if (wmvParams->eFormat == OMX_VIDEO_WMVFormat9) {
502 mCtx->codec_id = CODEC_ID_WMV3;
504 LOGE("unsupported wmv codec: 0x%x", wmvParams->eFormat);
505 return OMX_ErrorUndefined;
508 return OMX_ErrorNone;
512 return SimpleSoftOMXComponent::internalSetParameter(index, params);
516 void SoftFFmpegVideo::onQueueFilled(OMX_U32 portIndex) {
519 if (mSignalledError || mOutputPortSettingsChange != NONE) {
523 List<BufferInfo *> &inQueue = getPortQueue(0);
524 List<BufferInfo *> &outQueue = getPortQueue(1);
526 while (!inQueue.empty() && !outQueue.empty()) {
527 BufferInfo *inInfo = *inQueue.begin();
528 OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
530 BufferInfo *outInfo = *outQueue.begin();
531 OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
533 if (mCtx->width != mWidth || mCtx->height != mHeight) {
534 mCtx->width = mWidth;
535 mCtx->height = mHeight;
538 updatePortDefinitions();
540 notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
541 mOutputPortSettingsChange = AWAITING_DISABLED;
545 if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
546 inQueue.erase(inQueue.begin());
547 inInfo->mOwnedByUs = false;
548 notifyEmptyBufferDone(inHeader);
550 outHeader->nFilledLen = 0;
551 outHeader->nFlags = OMX_BUFFERFLAG_EOS;
553 outQueue.erase(outQueue.begin());
554 outInfo->mOwnedByUs = false;
555 notifyFillBufferDone(outHeader);
559 if (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
560 LOGI("got extradata, ignore: %d, size: %lu", mIgnoreExtradata, inHeader->nFilledLen);
561 hexdump(inHeader->pBuffer + inHeader->nOffset, inHeader->nFilledLen);
562 if (!mExtradataReady && !mIgnoreExtradata) {
563 //if (mMode == MODE_H264)
564 // it is possible to receive multiple input buffer with OMX_BUFFERFLAG_CODECCONFIG flag.
565 // for example, H264, the first input buffer is SPS, and another is PPS!
566 int orig_extradata_size = mCtx->extradata_size;
567 mCtx->extradata_size += inHeader->nFilledLen;
568 mCtx->extradata = (uint8_t *)realloc(mCtx->extradata,
569 mCtx->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
570 if (!mCtx->extradata) {
571 LOGE("ffmpeg video decoder failed to alloc extradata memory.");
572 notify(OMX_EventError, OMX_ErrorInsufficientResources, 0, NULL);
573 mSignalledError = true;
577 memcpy(mCtx->extradata + orig_extradata_size,
578 inHeader->pBuffer + inHeader->nOffset, inHeader->nFilledLen);
579 memset(mCtx->extradata + mCtx->extradata_size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
581 inInfo->mOwnedByUs = false;
582 inQueue.erase(inQueue.begin());
584 notifyEmptyBufferDone(inHeader);
590 if (mIgnoreExtradata) {
591 LOGI("got extradata, size: %lu, but ignore it", inHeader->nFilledLen);
592 inInfo->mOwnedByUs = false;
593 inQueue.erase(inQueue.begin());
595 notifyEmptyBufferDone(inHeader);
603 av_init_packet(&pkt);
604 pkt.data = (uint8_t *)inHeader->pBuffer + inHeader->nOffset;
605 pkt.size = inHeader->nFilledLen;
606 pkt.pts = inHeader->nTimeStamp;
608 LOGV("pkt size: %d, pts: %lld", pkt.size, pkt.pts);
610 if (!mExtradataReady) {
611 LOGI("extradata is ready");
612 hexdump(mCtx->extradata, mCtx->extradata_size);
613 mExtradataReady = true;
615 // find decoder again as codec_id may have changed
616 mCtx->codec = avcodec_find_decoder(mCtx->codec_id);
618 LOGE("ffmpeg video decoder failed to find codec");
619 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
620 mSignalledError = true;
624 setAVCtxToDefault(mCtx, mCtx->codec);
626 LOGI("open ffmpeg decoder now");
627 err = avcodec_open2(mCtx, mCtx->codec, NULL);
629 LOGE("ffmpeg video decoder failed to initialize. (%d)", err);
630 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
631 mSignalledError = true;
637 AVFrame *frame = avcodec_alloc_frame();
638 err = avcodec_decode_video2(mCtx, frame, &gotPic, &pkt);
640 LOGE("ffmpeg video decoder failed to decode frame. (%d)", err);
641 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
642 mSignalledError = true;
649 void *buffer_to_free = NULL;
650 int64_t pts = AV_NOPTS_VALUE;
651 uint8_t *dst = outHeader->pBuffer;
653 // do deinterlace if necessary. for example, your TV is progressive
654 preProcessVideoFrame((AVPicture *)frame, &buffer_to_free);
656 memset(&pict, 0, sizeof(AVPicture));
658 pict.data[1] = dst + mStride * mHeight;
659 pict.data[2] = pict.data[1] + (mStride / 2 * mHeight / 2);
660 pict.linesize[0] = mStride;
661 pict.linesize[1] = mStride / 2;
662 pict.linesize[2] = mStride / 2;
664 int sws_flags = SWS_BICUBIC;
665 mImgConvertCtx = sws_getCachedContext(mImgConvertCtx,
666 mWidth, mHeight, mCtx->pix_fmt, mWidth, mHeight,
667 PIX_FMT_YUV420P, sws_flags, NULL, NULL, NULL);
668 if (mImgConvertCtx == NULL) {
669 LOGE("Cannot initialize the conversion context");
670 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
671 mSignalledError = true;
675 sws_scale(mImgConvertCtx, frame->data, frame->linesize,
676 0, mHeight, pict.data, pict.linesize);
678 outHeader->nOffset = 0;
679 outHeader->nFilledLen = (mStride * mHeight * 3) / 2;
680 outHeader->nFlags = 0;
681 if (frame->key_frame)
682 outHeader->nFlags |= OMX_BUFFERFLAG_SYNCFRAME;
684 // process timestamps
685 if (decoder_reorder_pts == -1) {
686 pts = *(int64_t*)av_opt_ptr(avcodec_get_frame_class(),
687 frame, "best_effort_timestamp");
688 } else if (decoder_reorder_pts) {
689 pts = frame->pkt_pts;
691 pts = frame->pkt_dts;
694 if (pts == AV_NOPTS_VALUE) {
697 outHeader->nTimeStamp = pts;
700 LOGV("frame pts: %lld", pts);
703 outInfo->mOwnedByUs = false;
704 outQueue.erase(outQueue.begin());
706 notifyFillBufferDone(outHeader);
709 av_free(buffer_to_free);
712 inInfo->mOwnedByUs = false;
713 inQueue.erase(inQueue.begin());
715 notifyEmptyBufferDone(inHeader);
721 void SoftFFmpegVideo::onPortFlushCompleted(OMX_U32 portIndex) {
722 if (portIndex == 0 && mCtx) {
723 // Make sure that the next buffer output does not still
724 // depend on fragments from the last one decoded.
725 avcodec_flush_buffers(mCtx);
729 void SoftFFmpegVideo::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
730 if (portIndex != 1) {
734 switch (mOutputPortSettingsChange) {
738 case AWAITING_DISABLED:
741 mOutputPortSettingsChange = AWAITING_ENABLED;
747 CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED);
749 mOutputPortSettingsChange = NONE;
755 void SoftFFmpegVideo::updatePortDefinitions() {
756 OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(0)->mDef;
757 def->format.video.nFrameWidth = mWidth;
758 def->format.video.nFrameHeight = mHeight;
759 def->format.video.nStride = def->format.video.nFrameWidth;
760 def->format.video.nSliceHeight = def->format.video.nFrameHeight;
762 def->format.video.nFrameWidth * def->format.video.nFrameHeight;
764 def = &editPortInfo(1)->mDef;
765 def->format.video.nFrameWidth = mWidth;
766 def->format.video.nFrameHeight = mHeight;
767 def->format.video.nStride = def->format.video.nFrameWidth;
768 def->format.video.nSliceHeight = def->format.video.nFrameHeight;
771 (def->format.video.nFrameWidth
772 * def->format.video.nFrameHeight * 3) / 2;
775 (((def->format.video.nFrameWidth + 15) & -16)
776 * ((def->format.video.nFrameHeight + 15) & -16) * 3) / 2;
780 } // namespace android
782 android::SoftOMXComponent *createSoftOMXComponent(
783 const char *name, const OMX_CALLBACKTYPE *callbacks,
784 OMX_PTR appData, OMX_COMPONENTTYPE **component) {
785 return new android::SoftFFmpegVideo(name, callbacks, appData, component);