OSDN Git Service

stagefright-plugins: Fix port reset problem
[android-x86/external-stagefright-plugins.git] / omx / SoftFFmpegVideo.cpp
1 /*
2  * Copyright 2012 Michael Chen <omxcodec@gmail.com>
3  * Copyright 2015 The CyanogenMod Project
4  *
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
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
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.
16  */
17
18 //#define LOG_NDEBUG 0
19 #define LOG_TAG "SoftFFmpegVideo"
20 #include <utils/Log.h>
21
22 #include "SoftFFmpegVideo.h"
23 #include "FFmpegComponents.h"
24
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>
29
30 #define DEBUG_PKT 0
31 #define DEBUG_FRM 0
32
33 static int decoder_reorder_pts = -1;
34
35 namespace android {
36
37 static const CodecProfileLevel kM4VProfileLevels[] = {
38     { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level5 },
39     { OMX_VIDEO_MPEG4ProfileAdvancedSimple, OMX_VIDEO_MPEG4Level5 },
40 };
41
42 SoftFFmpegVideo::SoftFFmpegVideo(
43         const char *name,
44         const char *componentRole,
45         OMX_VIDEO_CODINGTYPE codingType,
46         const CodecProfileLevel *profileLevels,
47         size_t numProfileLevels,
48         const OMX_CALLBACKTYPE *callbacks,
49         OMX_PTR appData,
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),
57       mCtx(NULL),
58       mImgConvertCtx(NULL),
59       mFrame(NULL),
60       mEOSStatus(INPUT_DATA_AVAILABLE),
61       mExtradataReady(false),
62       mIgnoreExtradata(false),
63       mStride(320),
64       mSignalledError(false) {
65
66     ALOGD("SoftFFmpegVideo component: %s codingType=%d appData: %p", name, codingType, appData);
67
68     initPorts(
69             kNumInputBuffers,
70             1024 * 1024 /* inputBufferSize */,
71             kNumOutputBuffers,
72             name);
73
74     CHECK_EQ(initDecoder(codecID), (status_t)OK);
75 }
76
77 SoftFFmpegVideo::~SoftFFmpegVideo() {
78     ALOGV("~SoftFFmpegVideo");
79     deInitDecoder();
80     if (mFFmpegAlreadyInited) {
81         deInitFFmpeg();
82     }
83 }
84
85 void SoftFFmpegVideo::setDefaultCtx(AVCodecContext *avctx, const AVCodec *codec) {
86     int fast = 1;
87
88     avctx->workaround_bugs   = 1;
89     avctx->lowres            = 0;
90     if(avctx->lowres > codec->max_lowres){
91         ALOGW("The maximum value for lowres supported by the decoder is %d",
92                 codec->max_lowres);
93         avctx->lowres= codec->max_lowres;
94     }
95     avctx->idct_algo         = 0;
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;
101
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;
106 }
107
108 status_t SoftFFmpegVideo::initDecoder(enum AVCodecID codecID) {
109     status_t status;
110
111     status = initFFmpeg();
112     if (status != OK) {
113         return NO_INIT;
114     }
115     mFFmpegAlreadyInited = true;
116
117     mCtx = avcodec_alloc_context3(NULL);
118     if (!mCtx)
119     {
120         ALOGE("avcodec_alloc_context failed.");
121         return NO_MEMORY;
122     }
123
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;
130     return OK;
131 }
132
133 void SoftFFmpegVideo::deInitDecoder() {
134     if (mCtx) {
135         if (avcodec_is_open(mCtx)) {
136             avcodec_flush_buffers(mCtx);
137         }
138         if (mCtx->extradata) {
139             av_free(mCtx->extradata);
140             mCtx->extradata = NULL;
141             mCtx->extradata_size = 0;
142         }
143         if (mCodecAlreadyOpened) {
144             avcodec_close(mCtx);
145             mCodecAlreadyOpened = false;
146         }
147         av_free(mCtx);
148         mCtx = NULL;
149     }
150     if (mFrame) {
151         av_frame_free(&mFrame);
152         mFrame = NULL;
153     }
154     if (mImgConvertCtx) {
155         sws_freeContext(mImgConvertCtx);
156         mImgConvertCtx = NULL;
157     }
158 }
159
160 OMX_ERRORTYPE SoftFFmpegVideo::internalGetParameter(
161         OMX_INDEXTYPE index, OMX_PTR params) {
162     //ALOGV("internalGetParameter index:0x%x", index);
163     switch (index) {
164         case OMX_IndexParamVideoWmv:
165         {
166             OMX_VIDEO_PARAM_WMVTYPE *profile =
167                 (OMX_VIDEO_PARAM_WMVTYPE *)params;
168
169             if (profile->nPortIndex != kInputPortIndex) {
170                 return OMX_ErrorUndefined;
171             }
172
173             profile->eFormat = OMX_VIDEO_WMVFormatUnused;
174
175             return OMX_ErrorNone;
176         }
177
178         case OMX_IndexParamVideoRv:
179         {
180             OMX_VIDEO_PARAM_RVTYPE *profile =
181                 (OMX_VIDEO_PARAM_RVTYPE *)params;
182
183             if (profile->nPortIndex != kInputPortIndex) {
184                 return OMX_ErrorUndefined;
185             }
186
187             profile->eFormat = OMX_VIDEO_RVFormatUnused;
188
189             return OMX_ErrorNone;
190         }
191
192         default:
193         {
194             if (index != (OMX_INDEXTYPE)OMX_IndexParamVideoFFmpeg) {
195                 return SoftVideoDecoderOMXComponent::internalGetParameter(index, params);
196             }
197
198             OMX_VIDEO_PARAM_FFMPEGTYPE *profile =
199                 (OMX_VIDEO_PARAM_FFMPEGTYPE *)params;
200
201             if (profile->nPortIndex != kInputPortIndex) {
202                 return OMX_ErrorUndefined;
203             }
204
205             profile->eCodecId = AV_CODEC_ID_NONE;
206             profile->nWidth   = 0;
207             profile->nHeight  = 0;
208
209             return OMX_ErrorNone;
210         }
211     }
212 }
213
214 OMX_ERRORTYPE SoftFFmpegVideo::isRoleSupported(
215                 const OMX_PARAM_COMPONENTROLETYPE *roleParams) {
216     for (size_t i = 0;
217          i < sizeof(kVideoComponents) / sizeof(kVideoComponents[0]);
218          ++i) {
219         if (strncmp((const char *)roleParams->cRole,
220                 kVideoComponents[i].mRole, OMX_MAX_STRINGNAME_SIZE - 1) == 0) {
221             return OMX_ErrorNone;
222         }
223     }
224     ALOGE("unsupported role: %s", (const char *)roleParams->cRole);
225     return OMX_ErrorUndefined;
226 }
227
228 OMX_ERRORTYPE SoftFFmpegVideo::internalSetParameter(
229         OMX_INDEXTYPE index, const OMX_PTR params) {
230     //ALOGV("internalSetParameter index:0x%x", index);
231     switch (index) {
232         case OMX_IndexParamStandardComponentRole:
233         {
234             const OMX_PARAM_COMPONENTROLETYPE *roleParams =
235                 (const OMX_PARAM_COMPONENTROLETYPE *)params;
236             return isRoleSupported(roleParams);
237         }
238
239         case OMX_IndexParamPortDefinition:
240         {
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;
245
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);
252                 if (outputPort) {
253                     ALOGV("OMX_IndexParamPortDefinition (output) width=%d height=%d", newWidth, newHeight);
254
255                     // only update (essentially crop) if size changes
256                     mWidth = newWidth;
257                     mHeight = newHeight;
258
259                     updatePortDefinitions(true, true);
260                     // reset buffer size based on frame size
261                     newParams->nBufferSize = def->nBufferSize;
262                 } else {
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;
271                 }
272             }
273             return SoftVideoDecoderOMXComponent::internalSetParameter(index, params);
274         }
275
276         case OMX_IndexParamVideoWmv:
277         {
278             OMX_VIDEO_PARAM_WMVTYPE *profile =
279                 (OMX_VIDEO_PARAM_WMVTYPE *)params;
280
281             if (profile->nPortIndex != kInputPortIndex) {
282                 return OMX_ErrorUndefined;
283             }
284
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;
291             } else {
292                 mCtx->codec_id = AV_CODEC_ID_VC1;
293             }
294
295             return OMX_ErrorNone;
296         }
297
298         case OMX_IndexParamVideoRv:
299         {
300             OMX_VIDEO_PARAM_RVTYPE *profile =
301                 (OMX_VIDEO_PARAM_RVTYPE *)params;
302
303             if (profile->nPortIndex != kInputPortIndex) {
304                 return OMX_ErrorUndefined;
305             }
306
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;
313             } else {
314                 ALOGE("unsupported rv codec: 0x%x", profile->eFormat);
315                 return OMX_ErrorUndefined;
316             }
317
318             return OMX_ErrorNone;
319         }
320
321         default:
322         {
323             if (index != (OMX_INDEXTYPE)OMX_IndexParamVideoFFmpeg) {
324                 return SoftVideoDecoderOMXComponent::internalSetParameter(index, params);
325             }
326
327             OMX_VIDEO_PARAM_FFMPEGTYPE *profile =
328                 (OMX_VIDEO_PARAM_FFMPEGTYPE *)params;
329
330             if (profile->nPortIndex != kInputPortIndex) {
331                 return OMX_ErrorUndefined;
332             }
333
334             mCtx->codec_id = (enum AVCodecID)profile->eCodecId;
335             mCtx->width    = profile->nWidth;
336             mCtx->height   = profile->nHeight;
337
338             ALOGD("got OMX_IndexParamVideoFFmpeg, "
339                 "eCodecId:%d(%s), width:%u, height:%u",
340                 profile->eCodecId,
341                 avcodec_get_name(mCtx->codec_id),
342                 profile->nWidth,
343                 profile->nHeight);
344
345             return OMX_ErrorNone;
346         }
347     }
348 }
349
350 int32_t SoftFFmpegVideo::handleExtradata() {
351     List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
352     BufferInfo *inInfo = *inQueue.begin();
353     OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
354
355     ALOGI("got extradata, ignore: %d, size: %u",
356             mIgnoreExtradata, inHeader->nFilledLen);
357     hexdump(inHeader->pBuffer + inHeader->nOffset, inHeader->nFilledLen);
358
359     if (mIgnoreExtradata) {
360         ALOGI("got extradata, size: %u, but ignore it", inHeader->nFilledLen);
361     } else {
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.");
372                 return ERR_OOM;
373             }
374
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);
380         }
381     }
382
383     inQueue.erase(inQueue.begin());
384     inInfo->mOwnedByUs = false;
385     notifyEmptyBufferDone(inHeader);
386
387     return ERR_OK;
388 }
389
390 int32_t SoftFFmpegVideo::openDecoder() {
391     if (mCodecAlreadyOpened) {
392         return ERR_OK;
393     }
394
395     if (!mExtradataReady) {
396         ALOGI("extradata is ready, size: %d", mCtx->extradata_size);
397         hexdump(mCtx->extradata, mCtx->extradata_size);
398         mExtradataReady = true;
399     }
400
401     //find decoder again as codec_id may have changed
402     mCtx->codec = avcodec_find_decoder(mCtx->codec_id);
403     if (!mCtx->codec) {
404         ALOGE("ffmpeg video decoder failed to find codec");
405         return ERR_CODEC_NOT_FOUND;
406     }
407
408     setDefaultCtx(mCtx, mCtx->codec);
409
410     ALOGD("begin to open ffmpeg decoder(%s) now",
411             avcodec_get_name(mCtx->codec_id));
412
413     int err = avcodec_open2(mCtx, mCtx->codec, NULL);
414     if (err < 0) {
415         ALOGE("ffmpeg video decoder failed to initialize. (%s)", av_err2str(err));
416         return ERR_DECODER_OPEN_FAILED;
417     }
418     mCodecAlreadyOpened = true;
419
420     ALOGD("open ffmpeg video decoder(%s) success",
421             avcodec_get_name(mCtx->codec_id));
422
423     mFrame = av_frame_alloc();
424     if (!mFrame) {
425         ALOGE("oom for video frame");
426         return ERR_OOM;
427     }
428
429     return ERR_OK;
430 }
431
432 void SoftFFmpegVideo::initPacket(AVPacket *pkt,
433         OMX_BUFFERHEADERTYPE *inHeader) {
434     memset(pkt, 0, sizeof(AVPacket));
435     av_init_packet(pkt);
436
437     if (inHeader) {
438         pkt->data = (uint8_t *)inHeader->pBuffer + inHeader->nOffset;
439         pkt->size = inHeader->nFilledLen;
440         pkt->pts = inHeader->nTimeStamp;
441         pkt->dts = inHeader->nTimeStamp;
442     } else {
443         pkt->data = NULL;
444         pkt->size = 0;
445         pkt->pts = AV_NOPTS_VALUE;
446     }
447
448 #if DEBUG_PKT
449     if (pkt->pts != AV_NOPTS_VALUE)
450     {
451         ALOGV("pkt size:%d, pts:%lld", pkt->size, pkt->pts);
452     } else {
453         ALOGV("pkt size:%d, pts:N/A", pkt->size);
454     }
455 #endif
456 }
457
458 int32_t SoftFFmpegVideo::decodeVideo() {
459     int len = 0, err = 0;
460     int gotPic = false;
461     int32_t ret = ERR_OK;
462     List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
463     BufferInfo *inInfo = NULL;
464     OMX_BUFFERHEADERTYPE *inHeader = NULL;
465
466     if (!inQueue.empty()) {
467         inInfo = *inQueue.begin();
468         if (inInfo != NULL)  {
469             inHeader = inInfo->mHeader;
470         }
471     }
472
473     if (mEOSStatus == INPUT_EOS_SEEN && (!inHeader || inHeader->nFilledLen == 0)
474         && !(mCtx->codec->capabilities & CODEC_CAP_DELAY)) {
475         return ERR_FLUSHED;
476     }
477
478     AVPacket pkt;
479     initPacket(&pkt, inHeader);
480
481     av_frame_unref(mFrame);
482
483     err = avcodec_decode_video2(mCtx, mFrame, &gotPic, &pkt);
484     av_packet_unref(&pkt);
485
486     if (err < 0) {
487         ALOGE("ffmpeg video decoder failed to decode frame. (%d)", err);
488         //don't send error to OMXCodec, skip!
489         ret = ERR_NO_FRM;
490     } else {
491         if (!gotPic) {
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) {
496                 ret = ERR_FLUSHED;
497             } else {
498                 ret = ERR_NO_FRM;
499             }
500         } else {
501             ret = ERR_OK;
502         }
503     }
504
505     if (!inQueue.empty()) {
506         inQueue.erase(inQueue.begin());
507         if (inInfo) {
508             inInfo->mOwnedByUs = false;
509             notifyEmptyBufferDone(inHeader);
510         }
511     }
512
513     return ret;
514 }
515
516 int32_t SoftFFmpegVideo::drainOneOutputBuffer() {
517     List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
518     BufferInfo *outInfo = *outQueue.begin();
519     OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
520
521     AVPicture pict;
522     int64_t pts = AV_NOPTS_VALUE;
523     uint8_t *dst = outHeader->pBuffer;
524
525     uint32_t width = outputBufferWidth();
526     uint32_t height = outputBufferHeight();
527
528     memset(&pict, 0, sizeof(AVPicture));
529     pict.data[0] = dst;
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;
535
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);
537
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;
545     }
546     sws_scale(mImgConvertCtx, mFrame->data, mFrame->linesize,
547             0, height, pict.data, pict.linesize);
548
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;
554     }
555
556     //process timestamps
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;
561     } else {
562         pts = mFrame->pkt_dts;
563     }
564
565     if (pts == AV_NOPTS_VALUE) {
566         pts = 0;
567     }
568     outHeader->nTimeStamp = pts; //FIXME pts is right???
569
570 #if DEBUG_FRM
571     ALOGV("mFrame pkt_pts: %lld pkt_dts: %lld used %lld", mFrame->pkt_pts, mFrame->pkt_dts, pts);
572 #endif
573
574     outQueue.erase(outQueue.begin());
575     outInfo->mOwnedByUs = false;
576     notifyFillBufferDone(outHeader);
577
578     return ERR_OK;
579 }
580
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;
587
588     ALOGD("ffmpeg video decoder fill eos outbuf");
589
590     outHeader->nTimeStamp = 0;
591     outHeader->nFilledLen = 0;
592     outHeader->nFlags = OMX_BUFFERFLAG_EOS;
593
594     outInfo->mOwnedByUs = false;
595     notifyFillBufferDone(outHeader);
596
597     mEOSStatus = OUTPUT_FRAMES_FLUSHED;
598 }
599
600 void SoftFFmpegVideo::drainAllOutputBuffers() {
601     List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
602    if (!mCodecAlreadyOpened) {
603         drainEOSOutputBuffer();
604         mEOSStatus = OUTPUT_FRAMES_FLUSHED;
605        return;
606    }
607
608     while (!outQueue.empty()) {
609         int32_t err = decodeVideo();
610         if (err < ERR_OK) {
611             notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
612             mSignalledError = true;
613             return;
614         } else if (err == ERR_FLUSHED) {
615             drainEOSOutputBuffer();
616             return;
617         } else if (err == ERR_NO_FRM) {
618             continue;
619         } else {
620             CHECK_EQ(err, ERR_OK);
621         }
622         if (drainOneOutputBuffer() != ERR_OK) {
623             notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
624             mSignalledError = true;
625             return;
626         }
627     }
628 }
629
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) {
635         crop = kCropSet;
636         if (mCropWidth != width || mCropHeight != height) {
637             mCropLeft = 0;
638             mCropTop = 0;
639             mCropWidth = width;
640             mCropHeight = height;
641             crop = kCropChanged;
642         }
643     }
644
645     bool portWillReset = false;
646     SoftVideoDecoderOMXComponent::handlePortSettingsChange(
647             &portWillReset, mCtx->width, mCtx->height, crop);
648     return portWillReset;
649 }
650
651 void SoftFFmpegVideo::onQueueFilled(OMX_U32 portIndex __unused) {
652     if (mSignalledError || mOutputPortSettingsChange != NONE) {
653         return;
654     }
655
656     if (mEOSStatus == OUTPUT_FRAMES_FLUSHED) {
657         return;
658     }
659
660     List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
661     List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
662
663     while (((mEOSStatus != INPUT_DATA_AVAILABLE) || !inQueue.empty())
664             && !outQueue.empty()) {
665
666         if (mEOSStatus == INPUT_EOS_SEEN) {
667             drainAllOutputBuffers();
668             return;
669         }
670
671         BufferInfo *inInfo = *inQueue.begin();
672         if (inInfo == NULL) {
673             continue;
674         }
675         OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
676         if (inHeader == NULL) {
677             continue;
678         }
679
680         if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
681             mEOSStatus = INPUT_EOS_SEEN;
682             continue;
683         }
684
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;
690             }
691             continue;
692         }
693
694         if (!mCodecAlreadyOpened) {
695             if (openDecoder() != ERR_OK) {
696                 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
697                 mSignalledError = true;
698                 return;
699             }
700         }
701
702         int32_t err = decodeVideo();
703         if (err < ERR_OK) {
704             notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
705             mSignalledError = true;
706             return;
707         } else if (err == ERR_FLUSHED) {
708             drainEOSOutputBuffer();
709             return;
710         } else if (err == ERR_NO_FRM) {
711             continue;
712         } else {
713             CHECK_EQ(err, ERR_OK);
714         }
715
716         if (handlePortSettingsChange()) {
717             ALOGV("PORT RESET w=%d h=%d", mCtx->width, mCtx->height);
718             return;
719         }
720
721         if (drainOneOutputBuffer() != ERR_OK) {
722             notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
723             mSignalledError = true;
724             return;
725         }
726     }
727 }
728
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);
736         }
737         mEOSStatus = INPUT_DATA_AVAILABLE;
738     }
739 }
740
741 void SoftFFmpegVideo::onReset() {
742     ALOGV("onReset()");
743     enum AVCodecID codecID = mCtx->codec_id;
744     deInitDecoder();
745     initDecoder(codecID);
746     SoftVideoDecoderOMXComponent::onReset();
747     mSignalledError = false;
748     mExtradataReady = false;
749     mEOSStatus = INPUT_DATA_AVAILABLE;
750 }
751
752 SoftOMXComponent* SoftFFmpegVideo::createSoftOMXComponent(
753         const char *name, const OMX_CALLBACKTYPE *callbacks,
754         OMX_PTR appData, OMX_COMPONENTTYPE **component) {
755
756     OMX_VIDEO_CODINGTYPE codingType = OMX_VIDEO_CodingAutoDetect;
757     char *componentRole = NULL;
758     enum AVCodecID codecID = AV_CODEC_ID_NONE;
759
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;
765             break;
766         }
767     }
768
769     if (componentRole == NULL) {
770         TRESPASS();
771     }
772
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);
777     }
778
779     return new SoftFFmpegVideo(name, componentRole, codingType,
780                 NULL, 0,
781                 callbacks, appData, component, codecID);
782 }
783
784 }  // namespace android