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 static const CodecProfileLevel kM4VProfileLevels[] = {
38 { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level5 },
39 { OMX_VIDEO_MPEG4ProfileAdvancedSimple, OMX_VIDEO_MPEG4Level5 },
42 SoftFFmpegVideo::SoftFFmpegVideo(
44 const char *componentRole,
45 OMX_VIDEO_CODINGTYPE codingType,
46 const CodecProfileLevel *profileLevels,
47 size_t numProfileLevels,
48 const OMX_CALLBACKTYPE *callbacks,
50 OMX_COMPONENTTYPE **component,
51 enum AVCodecID codecID)
52 : SoftVideoDecoderOMXComponent(name, componentRole, codingType,
53 profileLevels, numProfileLevels, 352, 288, callbacks, appData, component),
54 mCodingType(codingType),
55 mFFmpegAlreadyInited(false),
56 mCodecAlreadyOpened(false),
60 mEOSStatus(INPUT_DATA_AVAILABLE),
61 mExtradataReady(false),
62 mIgnoreExtradata(false),
64 mSignalledError(false) {
66 ALOGD("SoftFFmpegVideo component: %s codingType=%d appData: %p", name, codingType, appData);
70 1024 * 1024 /* inputBufferSize */,
74 CHECK_EQ(initDecoder(codecID), (status_t)OK);
77 SoftFFmpegVideo::~SoftFFmpegVideo() {
78 ALOGV("~SoftFFmpegVideo");
80 if (mFFmpegAlreadyInited) {
85 void SoftFFmpegVideo::setDefaultCtx(AVCodecContext *avctx, const AVCodec *codec) {
88 avctx->workaround_bugs = 1;
90 if(avctx->lowres > codec->max_lowres){
91 ALOGW("The maximum value for lowres supported by the decoder is %d",
93 avctx->lowres= codec->max_lowres;
96 avctx->skip_frame = AVDISCARD_DEFAULT;
97 avctx->skip_idct = AVDISCARD_DEFAULT;
98 avctx->skip_loop_filter = AVDISCARD_ALL;
99 avctx->error_concealment = 3;
100 avctx->thread_count = 0;
102 if(avctx->lowres) avctx->flags |= CODEC_FLAG_EMU_EDGE;
103 if (fast) avctx->flags2 |= CODEC_FLAG2_FAST;
104 if(codec->capabilities & CODEC_CAP_DR1)
105 avctx->flags |= CODEC_FLAG_EMU_EDGE;
108 status_t SoftFFmpegVideo::initDecoder(enum AVCodecID codecID) {
111 status = initFFmpeg();
115 mFFmpegAlreadyInited = true;
117 mCtx = avcodec_alloc_context3(NULL);
120 ALOGE("avcodec_alloc_context failed.");
124 mCtx->codec_type = AVMEDIA_TYPE_VIDEO;
125 mCtx->codec_id = codecID;
126 mCtx->extradata_size = 0;
127 mCtx->extradata = NULL;
128 mCtx->width = mWidth;
129 mCtx->height = mHeight;
133 void SoftFFmpegVideo::deInitDecoder() {
135 if (avcodec_is_open(mCtx)) {
136 avcodec_flush_buffers(mCtx);
138 if (mCtx->extradata) {
139 av_free(mCtx->extradata);
140 mCtx->extradata = NULL;
141 mCtx->extradata_size = 0;
143 if (mCodecAlreadyOpened) {
145 mCodecAlreadyOpened = false;
151 av_frame_free(&mFrame);
154 if (mImgConvertCtx) {
155 sws_freeContext(mImgConvertCtx);
156 mImgConvertCtx = NULL;
160 OMX_ERRORTYPE SoftFFmpegVideo::internalGetParameter(
161 OMX_INDEXTYPE index, OMX_PTR params) {
162 //ALOGV("internalGetParameter index:0x%x", index);
164 case OMX_IndexParamVideoWmv:
166 OMX_VIDEO_PARAM_WMVTYPE *profile =
167 (OMX_VIDEO_PARAM_WMVTYPE *)params;
169 if (profile->nPortIndex != kInputPortIndex) {
170 return OMX_ErrorUndefined;
173 profile->eFormat = OMX_VIDEO_WMVFormatUnused;
175 return OMX_ErrorNone;
178 case OMX_IndexParamVideoRv:
180 OMX_VIDEO_PARAM_RVTYPE *profile =
181 (OMX_VIDEO_PARAM_RVTYPE *)params;
183 if (profile->nPortIndex != kInputPortIndex) {
184 return OMX_ErrorUndefined;
187 profile->eFormat = OMX_VIDEO_RVFormatUnused;
189 return OMX_ErrorNone;
194 if (index != (OMX_INDEXTYPE)OMX_IndexParamVideoFFmpeg) {
195 return SoftVideoDecoderOMXComponent::internalGetParameter(index, params);
198 OMX_VIDEO_PARAM_FFMPEGTYPE *profile =
199 (OMX_VIDEO_PARAM_FFMPEGTYPE *)params;
201 if (profile->nPortIndex != kInputPortIndex) {
202 return OMX_ErrorUndefined;
205 profile->eCodecId = AV_CODEC_ID_NONE;
207 profile->nHeight = 0;
209 return OMX_ErrorNone;
214 OMX_ERRORTYPE SoftFFmpegVideo::isRoleSupported(
215 const OMX_PARAM_COMPONENTROLETYPE *roleParams) {
217 i < sizeof(kVideoComponents) / sizeof(kVideoComponents[0]);
219 if (strncmp((const char *)roleParams->cRole,
220 kVideoComponents[i].mRole, OMX_MAX_STRINGNAME_SIZE - 1) == 0) {
221 return OMX_ErrorNone;
224 ALOGE("unsupported role: %s", (const char *)roleParams->cRole);
225 return OMX_ErrorUndefined;
228 OMX_ERRORTYPE SoftFFmpegVideo::internalSetParameter(
229 OMX_INDEXTYPE index, const OMX_PTR params) {
230 //ALOGV("internalSetParameter index:0x%x", index);
232 case OMX_IndexParamStandardComponentRole:
234 const OMX_PARAM_COMPONENTROLETYPE *roleParams =
235 (const OMX_PARAM_COMPONENTROLETYPE *)params;
236 return isRoleSupported(roleParams);
239 case OMX_IndexParamPortDefinition:
241 OMX_PARAM_PORTDEFINITIONTYPE *newParams =
242 (OMX_PARAM_PORTDEFINITIONTYPE *)params;
243 OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &newParams->format.video;
244 OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(newParams->nPortIndex)->mDef;
246 uint32_t oldWidth = def->format.video.nFrameWidth;
247 uint32_t oldHeight = def->format.video.nFrameHeight;
248 uint32_t newWidth = video_def->nFrameWidth;
249 uint32_t newHeight = video_def->nFrameHeight;
250 if (newWidth != oldWidth || newHeight != oldHeight) {
251 bool outputPort = (newParams->nPortIndex == kOutputPortIndex);
253 ALOGV("OMX_IndexParamPortDefinition (output) width=%d height=%d", newWidth, newHeight);
255 // only update (essentially crop) if size changes
259 updatePortDefinitions(true, true);
260 // reset buffer size based on frame size
261 newParams->nBufferSize = def->nBufferSize;
263 // For input port, we only set nFrameWidth and nFrameHeight. Buffer size
264 // is updated when configuring the output port using the max-frame-size,
265 // though client can still request a larger size.
266 ALOGV("OMX_IndexParamPortDefinition (input) width=%d height=%d", newWidth, newHeight);
267 def->format.video.nFrameWidth = newWidth;
268 def->format.video.nFrameHeight = newHeight;
269 mCtx->width = newWidth;
270 mCtx->height = newHeight;
273 return SoftVideoDecoderOMXComponent::internalSetParameter(index, params);
276 case OMX_IndexParamVideoWmv:
278 OMX_VIDEO_PARAM_WMVTYPE *profile =
279 (OMX_VIDEO_PARAM_WMVTYPE *)params;
281 if (profile->nPortIndex != kInputPortIndex) {
282 return OMX_ErrorUndefined;
285 if (profile->eFormat == OMX_VIDEO_WMVFormat7) {
286 mCtx->codec_id = AV_CODEC_ID_WMV1;
287 } else if (profile->eFormat == OMX_VIDEO_WMVFormat8) {
288 mCtx->codec_id = AV_CODEC_ID_WMV2;
289 } else if (profile->eFormat == OMX_VIDEO_WMVFormat9) {
290 mCtx->codec_id = AV_CODEC_ID_WMV3;
292 mCtx->codec_id = AV_CODEC_ID_VC1;
295 return OMX_ErrorNone;
298 case OMX_IndexParamVideoRv:
300 OMX_VIDEO_PARAM_RVTYPE *profile =
301 (OMX_VIDEO_PARAM_RVTYPE *)params;
303 if (profile->nPortIndex != kInputPortIndex) {
304 return OMX_ErrorUndefined;
307 if (profile->eFormat == OMX_VIDEO_RVFormatG2) {
308 mCtx->codec_id = AV_CODEC_ID_RV20;
309 } else if (profile->eFormat == OMX_VIDEO_RVFormat8) {
310 mCtx->codec_id = AV_CODEC_ID_RV30;
311 } else if (profile->eFormat == OMX_VIDEO_RVFormat9) {
312 mCtx->codec_id = AV_CODEC_ID_RV40;
314 ALOGE("unsupported rv codec: 0x%x", profile->eFormat);
315 return OMX_ErrorUndefined;
318 return OMX_ErrorNone;
323 if (index != (OMX_INDEXTYPE)OMX_IndexParamVideoFFmpeg) {
324 return SoftVideoDecoderOMXComponent::internalSetParameter(index, params);
327 OMX_VIDEO_PARAM_FFMPEGTYPE *profile =
328 (OMX_VIDEO_PARAM_FFMPEGTYPE *)params;
330 if (profile->nPortIndex != kInputPortIndex) {
331 return OMX_ErrorUndefined;
334 mCtx->codec_id = (enum AVCodecID)profile->eCodecId;
335 mCtx->width = profile->nWidth;
336 mCtx->height = profile->nHeight;
338 ALOGD("got OMX_IndexParamVideoFFmpeg, "
339 "eCodecId:%d(%s), width:%u, height:%u",
341 avcodec_get_name(mCtx->codec_id),
345 return OMX_ErrorNone;
350 int32_t SoftFFmpegVideo::handleExtradata() {
351 List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
352 BufferInfo *inInfo = *inQueue.begin();
353 OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
355 ALOGI("got extradata, ignore: %d, size: %u",
356 mIgnoreExtradata, inHeader->nFilledLen);
357 hexdump(inHeader->pBuffer + inHeader->nOffset, inHeader->nFilledLen);
359 if (mIgnoreExtradata) {
360 ALOGI("got extradata, size: %u, but ignore it", inHeader->nFilledLen);
362 if (!mExtradataReady) {
363 //if (mMode == MODE_H264)
364 //it is possible to receive multiple input buffer with OMX_BUFFERFLAG_CODECCONFIG flag.
365 //for example, H264, the first input buffer is SPS, and another is PPS!
366 int orig_extradata_size = mCtx->extradata_size;
367 mCtx->extradata_size += inHeader->nFilledLen;
368 mCtx->extradata = (uint8_t *)realloc(mCtx->extradata,
369 mCtx->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
370 if (!mCtx->extradata) {
371 ALOGE("ffmpeg video decoder failed to alloc extradata memory.");
375 memcpy(mCtx->extradata + orig_extradata_size,
376 inHeader->pBuffer + inHeader->nOffset,
377 inHeader->nFilledLen);
378 memset(mCtx->extradata + mCtx->extradata_size, 0,
379 FF_INPUT_BUFFER_PADDING_SIZE);
383 inQueue.erase(inQueue.begin());
384 inInfo->mOwnedByUs = false;
385 notifyEmptyBufferDone(inHeader);
390 int32_t SoftFFmpegVideo::openDecoder() {
391 if (mCodecAlreadyOpened) {
395 if (!mExtradataReady) {
396 ALOGI("extradata is ready, size: %d", mCtx->extradata_size);
397 hexdump(mCtx->extradata, mCtx->extradata_size);
398 mExtradataReady = true;
401 //find decoder again as codec_id may have changed
402 mCtx->codec = avcodec_find_decoder(mCtx->codec_id);
404 ALOGE("ffmpeg video decoder failed to find codec");
405 return ERR_CODEC_NOT_FOUND;
408 setDefaultCtx(mCtx, mCtx->codec);
410 ALOGD("begin to open ffmpeg decoder(%s) now",
411 avcodec_get_name(mCtx->codec_id));
413 int err = avcodec_open2(mCtx, mCtx->codec, NULL);
415 ALOGE("ffmpeg video decoder failed to initialize. (%s)", av_err2str(err));
416 return ERR_DECODER_OPEN_FAILED;
418 mCodecAlreadyOpened = true;
420 ALOGD("open ffmpeg video decoder(%s) success",
421 avcodec_get_name(mCtx->codec_id));
423 mFrame = av_frame_alloc();
425 ALOGE("oom for video frame");
432 void SoftFFmpegVideo::initPacket(AVPacket *pkt,
433 OMX_BUFFERHEADERTYPE *inHeader) {
434 memset(pkt, 0, sizeof(AVPacket));
438 pkt->data = (uint8_t *)inHeader->pBuffer + inHeader->nOffset;
439 pkt->size = inHeader->nFilledLen;
440 pkt->pts = inHeader->nTimeStamp;
441 pkt->dts = inHeader->nTimeStamp;
445 pkt->pts = AV_NOPTS_VALUE;
449 if (pkt->pts != AV_NOPTS_VALUE)
451 ALOGV("pkt size:%d, pts:%lld", pkt->size, pkt->pts);
453 ALOGV("pkt size:%d, pts:N/A", pkt->size);
458 int32_t SoftFFmpegVideo::decodeVideo() {
459 int len = 0, err = 0;
461 int32_t ret = ERR_OK;
462 List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
463 BufferInfo *inInfo = NULL;
464 OMX_BUFFERHEADERTYPE *inHeader = NULL;
466 if (!inQueue.empty()) {
467 inInfo = *inQueue.begin();
468 if (inInfo != NULL) {
469 inHeader = inInfo->mHeader;
473 if (mEOSStatus == INPUT_EOS_SEEN && (!inHeader || inHeader->nFilledLen == 0)
474 && !(mCtx->codec->capabilities & CODEC_CAP_DELAY)) {
479 initPacket(&pkt, inHeader);
481 av_frame_unref(mFrame);
483 err = avcodec_decode_video2(mCtx, mFrame, &gotPic, &pkt);
484 av_packet_unref(&pkt);
487 ALOGE("ffmpeg video decoder failed to decode frame. (%d)", err);
488 //don't send error to OMXCodec, skip!
492 ALOGI("ffmpeg video decoder failed to get frame.");
493 //stop sending empty packets if the decoder is finished
494 if (mEOSStatus != INPUT_DATA_AVAILABLE && mCtx->codec->capabilities & CODEC_CAP_DELAY &&
495 !inHeader || inHeader->nFilledLen == 0) {
505 if (!inQueue.empty()) {
506 inQueue.erase(inQueue.begin());
508 inInfo->mOwnedByUs = false;
509 notifyEmptyBufferDone(inHeader);
516 int32_t SoftFFmpegVideo::drainOneOutputBuffer() {
517 List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
518 BufferInfo *outInfo = *outQueue.begin();
519 OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
522 int64_t pts = AV_NOPTS_VALUE;
523 uint8_t *dst = outHeader->pBuffer;
525 uint32_t width = outputBufferWidth();
526 uint32_t height = outputBufferHeight();
528 memset(&pict, 0, sizeof(AVPicture));
530 pict.data[1] = dst + width * height;
531 pict.data[2] = pict.data[1] + (width / 2 * height / 2);
532 pict.linesize[0] = width;
533 pict.linesize[1] = width / 2;
534 pict.linesize[2] = width / 2;
536 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);
538 int sws_flags = SWS_BICUBIC;
539 mImgConvertCtx = sws_getCachedContext(mImgConvertCtx,
540 mFrame->width, mFrame->height, (AVPixelFormat)mFrame->format, width, height,
541 AV_PIX_FMT_YUV420P, sws_flags, NULL, NULL, NULL);
542 if (mImgConvertCtx == NULL) {
543 ALOGE("Cannot initialize the conversion context");
544 return ERR_SWS_FAILED;
546 sws_scale(mImgConvertCtx, mFrame->data, mFrame->linesize,
547 0, height, pict.data, pict.linesize);
549 outHeader->nOffset = 0;
550 outHeader->nFilledLen = (outputBufferWidth() * outputBufferHeight() * 3) / 2;
551 outHeader->nFlags = 0;
552 if (mFrame->key_frame) {
553 outHeader->nFlags |= OMX_BUFFERFLAG_SYNCFRAME;
557 if (decoder_reorder_pts == -1) {
558 pts = av_frame_get_best_effort_timestamp(mFrame);
559 } else if (decoder_reorder_pts) {
560 pts = mFrame->pkt_pts;
562 pts = mFrame->pkt_dts;
565 if (pts == AV_NOPTS_VALUE) {
568 outHeader->nTimeStamp = pts; //FIXME pts is right???
571 ALOGV("mFrame pkt_pts: %lld pkt_dts: %lld used %lld", mFrame->pkt_pts, mFrame->pkt_dts, pts);
574 outQueue.erase(outQueue.begin());
575 outInfo->mOwnedByUs = false;
576 notifyFillBufferDone(outHeader);
581 void SoftFFmpegVideo::drainEOSOutputBuffer() {
582 List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
583 BufferInfo *outInfo = *outQueue.begin();
584 CHECK(outInfo != NULL);
585 outQueue.erase(outQueue.begin());
586 OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
588 ALOGD("ffmpeg video decoder fill eos outbuf");
590 outHeader->nTimeStamp = 0;
591 outHeader->nFilledLen = 0;
592 outHeader->nFlags = OMX_BUFFERFLAG_EOS;
594 outInfo->mOwnedByUs = false;
595 notifyFillBufferDone(outHeader);
597 mEOSStatus = OUTPUT_FRAMES_FLUSHED;
600 void SoftFFmpegVideo::drainAllOutputBuffers() {
601 List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
602 if (!mCodecAlreadyOpened) {
603 drainEOSOutputBuffer();
604 mEOSStatus = OUTPUT_FRAMES_FLUSHED;
608 while (!outQueue.empty()) {
609 int32_t err = decodeVideo();
611 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
612 mSignalledError = true;
614 } else if (err == ERR_FLUSHED) {
615 drainEOSOutputBuffer();
617 } else if (err == ERR_NO_FRM) {
620 CHECK_EQ(err, ERR_OK);
622 if (drainOneOutputBuffer() != ERR_OK) {
623 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
624 mSignalledError = true;
630 bool SoftFFmpegVideo::handlePortSettingsChange() {
631 CropSettingsMode crop = kCropUnSet;
632 uint32_t width = outputBufferWidth();
633 uint32_t height = outputBufferHeight();
634 if (width != (uint32_t)mCtx->width || height != (uint32_t)mCtx->height) {
636 if (mCropWidth != width || mCropHeight != height) {
640 mCropHeight = height;
645 bool portWillReset = false;
646 SoftVideoDecoderOMXComponent::handlePortSettingsChange(
647 &portWillReset, mCtx->width, mCtx->height, crop);
648 return portWillReset;
651 void SoftFFmpegVideo::onQueueFilled(OMX_U32 portIndex __unused) {
652 if (mSignalledError || mOutputPortSettingsChange != NONE) {
656 if (mEOSStatus == OUTPUT_FRAMES_FLUSHED) {
660 List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
661 List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
663 while (((mEOSStatus != INPUT_DATA_AVAILABLE) || !inQueue.empty())
664 && !outQueue.empty()) {
666 if (mEOSStatus == INPUT_EOS_SEEN) {
667 drainAllOutputBuffers();
671 BufferInfo *inInfo = *inQueue.begin();
672 if (inInfo == NULL) {
675 OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
676 if (inHeader == NULL) {
680 if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
681 mEOSStatus = INPUT_EOS_SEEN;
685 if (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
686 ALOGD("ffmpeg got codecconfig buffer");
687 if (handleExtradata() != ERR_OK) {
688 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
689 mSignalledError = true;
694 if (!mCodecAlreadyOpened) {
695 if (openDecoder() != ERR_OK) {
696 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
697 mSignalledError = true;
702 int32_t err = decodeVideo();
704 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
705 mSignalledError = true;
707 } else if (err == ERR_FLUSHED) {
708 drainEOSOutputBuffer();
710 } else if (err == ERR_NO_FRM) {
713 CHECK_EQ(err, ERR_OK);
716 if (handlePortSettingsChange()) {
717 ALOGV("PORT RESET w=%d h=%d", mCtx->width, mCtx->height);
721 if (drainOneOutputBuffer() != ERR_OK) {
722 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
723 mSignalledError = true;
729 void SoftFFmpegVideo::onPortFlushCompleted(OMX_U32 portIndex) {
730 ALOGV("ffmpeg video decoder flush port(%u)", portIndex);
731 if (portIndex == kInputPortIndex) {
732 if (mCtx && avcodec_is_open(mCtx)) {
733 //Make sure that the next buffer output does not still
734 //depend on fragments from the last one decoded.
735 avcodec_flush_buffers(mCtx);
737 mEOSStatus = INPUT_DATA_AVAILABLE;
741 void SoftFFmpegVideo::onReset() {
743 enum AVCodecID codecID = mCtx->codec_id;
745 initDecoder(codecID);
746 SoftVideoDecoderOMXComponent::onReset();
747 mSignalledError = false;
748 mExtradataReady = false;
749 mEOSStatus = INPUT_DATA_AVAILABLE;
752 SoftOMXComponent* SoftFFmpegVideo::createSoftOMXComponent(
753 const char *name, const OMX_CALLBACKTYPE *callbacks,
754 OMX_PTR appData, OMX_COMPONENTTYPE **component) {
756 OMX_VIDEO_CODINGTYPE codingType = OMX_VIDEO_CodingAutoDetect;
757 char *componentRole = NULL;
758 enum AVCodecID codecID = AV_CODEC_ID_NONE;
760 for (size_t i = 0; i < kNumVideoComponents; ++i) {
761 if (!strcasecmp(name, kVideoComponents[i].mName)) {
762 componentRole = strdup(kVideoComponents[i].mRole);
763 codingType = kVideoComponents[i].mVideoCodingType;
764 codecID = kVideoComponents[i].mCodecID;
769 if (componentRole == NULL) {
773 if (!strcmp(name, "OMX.ffmpeg.mpeg4.decoder")) {
774 return new SoftFFmpegVideo(name, componentRole, codingType,
775 kM4VProfileLevels, ARRAY_SIZE(kM4VProfileLevels),
776 callbacks, appData, component, codecID);
779 return new SoftFFmpegVideo(name, componentRole, codingType,
781 callbacks, appData, component, codecID);
784 } // namespace android