OSDN Git Service

stagefright-plugins: Fix memory leak
[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         }
146         av_free(mCtx);
147         mCtx = NULL;
148     }
149     if (mFrame) {
150         av_freep(&mFrame);
151         mFrame = NULL;
152     }
153     if (mImgConvertCtx) {
154         sws_freeContext(mImgConvertCtx);
155         mImgConvertCtx = NULL;
156     }
157 }
158
159 OMX_ERRORTYPE SoftFFmpegVideo::internalGetParameter(
160         OMX_INDEXTYPE index, OMX_PTR params) {
161     //ALOGV("internalGetParameter index:0x%x", index);
162     switch (index) {
163         case OMX_IndexParamVideoWmv:
164         {
165             OMX_VIDEO_PARAM_WMVTYPE *profile =
166                 (OMX_VIDEO_PARAM_WMVTYPE *)params;
167
168             if (profile->nPortIndex != kInputPortIndex) {
169                 return OMX_ErrorUndefined;
170             }
171
172             profile->eFormat = OMX_VIDEO_WMVFormatUnused;
173
174             return OMX_ErrorNone;
175         }
176
177         case OMX_IndexParamVideoRv:
178         {
179             OMX_VIDEO_PARAM_RVTYPE *profile =
180                 (OMX_VIDEO_PARAM_RVTYPE *)params;
181
182             if (profile->nPortIndex != kInputPortIndex) {
183                 return OMX_ErrorUndefined;
184             }
185
186             profile->eFormat = OMX_VIDEO_RVFormatUnused;
187
188             return OMX_ErrorNone;
189         }
190
191         default:
192         {
193             if (index != (OMX_INDEXTYPE)OMX_IndexParamVideoFFmpeg) {
194                 return SoftVideoDecoderOMXComponent::internalGetParameter(index, params);
195             }
196
197             OMX_VIDEO_PARAM_FFMPEGTYPE *profile =
198                 (OMX_VIDEO_PARAM_FFMPEGTYPE *)params;
199
200             if (profile->nPortIndex != kInputPortIndex) {
201                 return OMX_ErrorUndefined;
202             }
203
204             profile->eCodecId = AV_CODEC_ID_NONE;
205             profile->nWidth   = 0;
206             profile->nHeight  = 0;
207
208             return OMX_ErrorNone;
209         }
210     }
211 }
212
213 OMX_ERRORTYPE SoftFFmpegVideo::isRoleSupported(
214                 const OMX_PARAM_COMPONENTROLETYPE *roleParams) {
215     for (size_t i = 0;
216          i < sizeof(kVideoComponents) / sizeof(kVideoComponents[0]);
217          ++i) {
218         if (strncmp((const char *)roleParams->cRole,
219                 kVideoComponents[i].mRole, OMX_MAX_STRINGNAME_SIZE - 1) == 0) {
220             return OMX_ErrorNone;
221         }
222     }
223     ALOGE("unsupported role: %s", (const char *)roleParams->cRole);
224     return OMX_ErrorUndefined;
225 }
226
227 OMX_ERRORTYPE SoftFFmpegVideo::internalSetParameter(
228         OMX_INDEXTYPE index, const OMX_PTR params) {
229     //ALOGV("internalSetParameter index:0x%x", index);
230     switch (index) {
231         case OMX_IndexParamStandardComponentRole:
232         {
233             const OMX_PARAM_COMPONENTROLETYPE *roleParams =
234                 (const OMX_PARAM_COMPONENTROLETYPE *)params;
235             return isRoleSupported(roleParams);
236         }
237
238         case OMX_IndexParamPortDefinition:
239         {
240             OMX_PARAM_PORTDEFINITIONTYPE *newParams =
241                 (OMX_PARAM_PORTDEFINITIONTYPE *)params;
242             OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &newParams->format.video;
243             OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(newParams->nPortIndex)->mDef;
244
245             uint32_t oldWidth = def->format.video.nFrameWidth;
246             uint32_t oldHeight = def->format.video.nFrameHeight;
247             uint32_t newWidth = video_def->nFrameWidth;
248             uint32_t newHeight = video_def->nFrameHeight;
249             if (newWidth != oldWidth || newHeight != oldHeight) {
250                 bool outputPort = (newParams->nPortIndex == kOutputPortIndex);
251                 if (outputPort) {
252                     ALOGV("OMX_IndexParamPortDefinition (output) width=%d height=%d", newWidth, newHeight);
253
254                     // only update (essentially crop) if size changes
255                     mWidth = newWidth;
256                     mHeight = newHeight;
257
258                     updatePortDefinitions(true, true);
259                     // reset buffer size based on frame size
260                     newParams->nBufferSize = def->nBufferSize;
261                 } else {
262                     // For input port, we only set nFrameWidth and nFrameHeight. Buffer size
263                     // is updated when configuring the output port using the max-frame-size,
264                     // though client can still request a larger size.
265                     ALOGV("OMX_IndexParamPortDefinition (input) width=%d height=%d", newWidth, newHeight);
266                     def->format.video.nFrameWidth = newWidth;
267                     def->format.video.nFrameHeight = newHeight;
268                     mCtx->width = newWidth;
269                     mCtx->height = newHeight;
270                 }
271             }
272             return SoftVideoDecoderOMXComponent::internalSetParameter(index, params);
273         }
274
275         case OMX_IndexParamVideoWmv:
276         {
277             OMX_VIDEO_PARAM_WMVTYPE *profile =
278                 (OMX_VIDEO_PARAM_WMVTYPE *)params;
279
280             if (profile->nPortIndex != kInputPortIndex) {
281                 return OMX_ErrorUndefined;
282             }
283
284             if (profile->eFormat == OMX_VIDEO_WMVFormat7) {
285                 mCtx->codec_id = AV_CODEC_ID_WMV1;
286             } else if (profile->eFormat == OMX_VIDEO_WMVFormat8) {
287                 mCtx->codec_id = AV_CODEC_ID_WMV2;
288             } else if (profile->eFormat == OMX_VIDEO_WMVFormat9) {
289                 mCtx->codec_id = AV_CODEC_ID_WMV3;
290             } else {
291                 mCtx->codec_id = AV_CODEC_ID_VC1;
292             }
293
294             return OMX_ErrorNone;
295         }
296
297         case OMX_IndexParamVideoRv:
298         {
299             OMX_VIDEO_PARAM_RVTYPE *profile =
300                 (OMX_VIDEO_PARAM_RVTYPE *)params;
301
302             if (profile->nPortIndex != kInputPortIndex) {
303                 return OMX_ErrorUndefined;
304             }
305
306             if (profile->eFormat == OMX_VIDEO_RVFormatG2) {
307                 mCtx->codec_id = AV_CODEC_ID_RV20;
308             } else if (profile->eFormat == OMX_VIDEO_RVFormat8) {
309                 mCtx->codec_id = AV_CODEC_ID_RV30;
310             } else if (profile->eFormat == OMX_VIDEO_RVFormat9) {
311                 mCtx->codec_id = AV_CODEC_ID_RV40;
312             } else {
313                 ALOGE("unsupported rv codec: 0x%x", profile->eFormat);
314                 return OMX_ErrorUndefined;
315             }
316
317             return OMX_ErrorNone;
318         }
319
320         default:
321         {
322             if (index != (OMX_INDEXTYPE)OMX_IndexParamVideoFFmpeg) {
323                 return SoftVideoDecoderOMXComponent::internalSetParameter(index, params);
324             }
325
326             OMX_VIDEO_PARAM_FFMPEGTYPE *profile =
327                 (OMX_VIDEO_PARAM_FFMPEGTYPE *)params;
328
329             if (profile->nPortIndex != kInputPortIndex) {
330                 return OMX_ErrorUndefined;
331             }
332
333             mCtx->codec_id = (enum AVCodecID)profile->eCodecId;
334             mCtx->width    = profile->nWidth;
335             mCtx->height   = profile->nHeight;
336
337             ALOGD("got OMX_IndexParamVideoFFmpeg, "
338                 "eCodecId:%d(%s), width:%u, height:%u",
339                 profile->eCodecId,
340                 avcodec_get_name(mCtx->codec_id),
341                 profile->nWidth,
342                 profile->nHeight);
343
344             return OMX_ErrorNone;
345         }
346     }
347 }
348
349 int32_t SoftFFmpegVideo::handleExtradata() {
350     List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
351     BufferInfo *inInfo = *inQueue.begin();
352     OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
353
354     ALOGI("got extradata, ignore: %d, size: %u",
355             mIgnoreExtradata, inHeader->nFilledLen);
356     hexdump(inHeader->pBuffer + inHeader->nOffset, inHeader->nFilledLen);
357
358     if (mIgnoreExtradata) {
359         ALOGI("got extradata, size: %u, but ignore it", inHeader->nFilledLen);
360     } else {
361         if (!mExtradataReady) {
362             //if (mMode == MODE_H264)
363             //it is possible to receive multiple input buffer with OMX_BUFFERFLAG_CODECCONFIG flag.
364             //for example, H264, the first input buffer is SPS, and another is PPS!
365             int orig_extradata_size = mCtx->extradata_size;
366             mCtx->extradata_size += inHeader->nFilledLen;
367             mCtx->extradata = (uint8_t *)realloc(mCtx->extradata,
368                     mCtx->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
369             if (!mCtx->extradata) {
370                 ALOGE("ffmpeg video decoder failed to alloc extradata memory.");
371                 return ERR_OOM;
372             }
373
374             memcpy(mCtx->extradata + orig_extradata_size,
375                     inHeader->pBuffer + inHeader->nOffset,
376                     inHeader->nFilledLen);
377             memset(mCtx->extradata + mCtx->extradata_size, 0,
378                     FF_INPUT_BUFFER_PADDING_SIZE);
379         }
380     }
381
382     inQueue.erase(inQueue.begin());
383     inInfo->mOwnedByUs = false;
384     notifyEmptyBufferDone(inHeader);
385
386     return ERR_OK;
387 }
388
389 int32_t SoftFFmpegVideo::openDecoder() {
390     if (mCodecAlreadyOpened) {
391         return ERR_OK;
392     }
393
394     if (!mExtradataReady) {
395         ALOGI("extradata is ready, size: %d", mCtx->extradata_size);
396         hexdump(mCtx->extradata, mCtx->extradata_size);
397         mExtradataReady = true;
398     }
399
400     //find decoder again as codec_id may have changed
401     mCtx->codec = avcodec_find_decoder(mCtx->codec_id);
402     if (!mCtx->codec) {
403         ALOGE("ffmpeg video decoder failed to find codec");
404         return ERR_CODEC_NOT_FOUND;
405     }
406
407     setDefaultCtx(mCtx, mCtx->codec);
408
409     ALOGD("begin to open ffmpeg decoder(%s) now",
410             avcodec_get_name(mCtx->codec_id));
411
412     int err = avcodec_open2(mCtx, mCtx->codec, NULL);
413     if (err < 0) {
414         ALOGE("ffmpeg video decoder failed to initialize. (%s)", av_err2str(err));
415         return ERR_DECODER_OPEN_FAILED;
416     }
417     mCodecAlreadyOpened = true;
418
419     ALOGD("open ffmpeg video decoder(%s) success",
420             avcodec_get_name(mCtx->codec_id));
421
422     mFrame = av_frame_alloc();
423     if (!mFrame) {
424         ALOGE("oom for video frame");
425         return ERR_OOM;
426     }
427
428     return ERR_OK;
429 }
430
431 void SoftFFmpegVideo::initPacket(AVPacket *pkt,
432         OMX_BUFFERHEADERTYPE *inHeader) {
433     memset(pkt, 0, sizeof(AVPacket));
434     av_init_packet(pkt);
435
436     if (inHeader) {
437         pkt->data = (uint8_t *)inHeader->pBuffer + inHeader->nOffset;
438         pkt->size = inHeader->nFilledLen;
439         pkt->pts = inHeader->nTimeStamp;
440         pkt->dts = inHeader->nTimeStamp;
441     } else {
442         pkt->data = NULL;
443         pkt->size = 0;
444         pkt->pts = AV_NOPTS_VALUE;
445     }
446
447 #if DEBUG_PKT
448     if (pkt->pts != AV_NOPTS_VALUE)
449     {
450         ALOGV("pkt size:%d, pts:%lld", pkt->size, pkt->pts);
451     } else {
452         ALOGV("pkt size:%d, pts:N/A", pkt->size);
453     }
454 #endif
455 }
456
457 int32_t SoftFFmpegVideo::decodeVideo() {
458     int len = 0, err = 0;
459     int gotPic = false;
460     int32_t ret = ERR_OK;
461     bool is_flush = (mEOSStatus != INPUT_DATA_AVAILABLE);
462     List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
463     BufferInfo *inInfo = NULL;
464     OMX_BUFFERHEADERTYPE *inHeader = NULL;
465
466     if (!is_flush) {
467         inInfo = *inQueue.begin();
468         CHECK(inInfo != NULL);
469         inHeader = inInfo->mHeader;
470     }
471
472     AVPacket pkt;
473     initPacket(&pkt, inHeader);
474
475     av_frame_unref(mFrame);
476
477     err = avcodec_decode_video2(mCtx, mFrame, &gotPic, &pkt);
478     av_packet_unref(&pkt);
479
480     if (err < 0) {
481         ALOGE("ffmpeg video decoder failed to decode frame. (%d)", err);
482         //don't send error to OMXCodec, skip!
483         ret = ERR_NO_FRM;
484     } else {
485         if (!gotPic) {
486             ALOGI("ffmpeg video decoder failed to get frame.");
487             //stop sending empty packets if the decoder is finished
488             if (is_flush && mCtx->codec->capabilities & CODEC_CAP_DELAY) {
489                 ret = ERR_FLUSHED;
490             } else {
491                 ret = ERR_NO_FRM;
492             }
493         } else {
494             ret = ERR_OK;
495         }
496     }
497
498     if (!is_flush) {
499         inQueue.erase(inQueue.begin());
500         inInfo->mOwnedByUs = false;
501         notifyEmptyBufferDone(inHeader);
502     }
503
504     return ret;
505 }
506
507 int32_t SoftFFmpegVideo::drainOneOutputBuffer() {
508     List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
509     BufferInfo *outInfo = *outQueue.begin();
510     OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
511
512     AVPicture pict;
513     int64_t pts = AV_NOPTS_VALUE;
514     uint8_t *dst = outHeader->pBuffer;
515
516     uint32_t width = outputBufferWidth();
517     uint32_t height = outputBufferHeight();
518
519     memset(&pict, 0, sizeof(AVPicture));
520     pict.data[0] = dst;
521     pict.data[1] = dst + width * height;
522     pict.data[2] = pict.data[1] + (width / 2  * height / 2);
523     pict.linesize[0] = width;
524     pict.linesize[1] = width / 2;
525     pict.linesize[2] = width / 2;
526
527     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);
528
529     int sws_flags = SWS_BICUBIC;
530     mImgConvertCtx = sws_getCachedContext(mImgConvertCtx,
531            mFrame->width, mFrame->height, (AVPixelFormat)mFrame->format, width, height,
532            AV_PIX_FMT_YUV420P, sws_flags, NULL, NULL, NULL);
533     if (mImgConvertCtx == NULL) {
534         ALOGE("Cannot initialize the conversion context");
535         return ERR_SWS_FAILED;
536     }
537     sws_scale(mImgConvertCtx, mFrame->data, mFrame->linesize,
538             0, height, pict.data, pict.linesize);
539
540     outHeader->nOffset = 0;
541     outHeader->nFilledLen = (outputBufferWidth() * outputBufferHeight() * 3) / 2;
542     outHeader->nFlags = 0;
543     if (mFrame->key_frame) {
544         outHeader->nFlags |= OMX_BUFFERFLAG_SYNCFRAME;
545     }
546
547     //process timestamps
548     if (decoder_reorder_pts == -1) {
549         pts = av_frame_get_best_effort_timestamp(mFrame);
550     } else if (decoder_reorder_pts) {
551         pts = mFrame->pkt_pts;
552     } else {
553         pts = mFrame->pkt_dts;
554     }
555
556     if (pts == AV_NOPTS_VALUE) {
557         pts = 0;
558     }
559     outHeader->nTimeStamp = pts; //FIXME pts is right???
560
561 #if DEBUG_FRM
562     ALOGV("mFrame pkt_pts: %lld pkt_dts: %lld used %lld", mFrame->pkt_pts, mFrame->pkt_dts, pts);
563 #endif
564
565     outQueue.erase(outQueue.begin());
566     outInfo->mOwnedByUs = false;
567     notifyFillBufferDone(outHeader);
568
569     return ERR_OK;
570 }
571
572 void SoftFFmpegVideo::drainEOSOutputBuffer() {
573     List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
574     BufferInfo *outInfo = *outQueue.begin();
575     CHECK(outInfo != NULL);
576     outQueue.erase(outQueue.begin());
577     OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
578
579     ALOGD("ffmpeg video decoder fill eos outbuf");
580
581     outHeader->nTimeStamp = 0;
582     outHeader->nFilledLen = 0;
583     outHeader->nFlags = OMX_BUFFERFLAG_EOS;
584
585     outInfo->mOwnedByUs = false;
586     notifyFillBufferDone(outHeader);
587
588     mEOSStatus = OUTPUT_FRAMES_FLUSHED;
589 }
590
591 void SoftFFmpegVideo::drainAllOutputBuffers() {
592     List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
593    if (!mCodecAlreadyOpened) {
594         drainEOSOutputBuffer();
595         mEOSStatus = OUTPUT_FRAMES_FLUSHED;
596        return;
597    }
598
599     if(!(mCtx->codec->capabilities & CODEC_CAP_DELAY)) {
600         drainEOSOutputBuffer();
601         mEOSStatus = OUTPUT_FRAMES_FLUSHED;
602         return;
603     }
604
605     while (!outQueue.empty()) {
606         int32_t err = decodeVideo();
607         if (err < ERR_OK) {
608             notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
609             mSignalledError = true;
610             return;
611         } else if (err == ERR_FLUSHED) {
612             drainEOSOutputBuffer();
613             return;
614         } else {
615             CHECK_EQ(err, ERR_OK);
616         }
617         if (drainOneOutputBuffer() != ERR_OK) {
618             notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
619             mSignalledError = true;
620             return;
621         }
622     }
623 }
624
625 bool SoftFFmpegVideo::handlePortSettingsChange() {
626     CropSettingsMode crop = kCropUnSet;
627     uint32_t width  = outputBufferWidth();
628     uint32_t height = outputBufferHeight();
629     if (width != (uint32_t)mCtx->width || height != (uint32_t)mCtx->height) {
630         crop = kCropSet;
631         if (mCropWidth != width || mCropHeight != height) {
632             mCropLeft = 0;
633             mCropTop = 0;
634             mCropWidth = width;
635             mCropHeight = height;
636             crop = kCropChanged;
637         }
638     }
639
640     bool portWillReset = false;
641     SoftVideoDecoderOMXComponent::handlePortSettingsChange(
642             &portWillReset, mCtx->width, mCtx->height, crop);
643     return portWillReset;
644 }
645
646 void SoftFFmpegVideo::onQueueFilled(OMX_U32 portIndex __unused) {
647     if (mSignalledError || mOutputPortSettingsChange != NONE) {
648         return;
649     }
650
651     if (mEOSStatus == OUTPUT_FRAMES_FLUSHED) {
652         return;
653     }
654
655     List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
656     List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
657
658     while (((mEOSStatus != INPUT_DATA_AVAILABLE) || !inQueue.empty())
659             && !outQueue.empty()) {
660
661         if (mEOSStatus == INPUT_EOS_SEEN) {
662             drainAllOutputBuffers();
663             return;
664         }
665
666         BufferInfo *inInfo = *inQueue.begin();
667         if (inInfo == NULL) {
668             continue;
669         }
670         OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
671         if (inHeader == NULL) {
672             continue;
673         }
674
675         if (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
676             ALOGD("ffmpeg got codecconfig buffer");
677             if (handleExtradata() != ERR_OK) {
678                 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
679                 mSignalledError = true;
680             }
681             continue;
682         }
683
684         if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
685             mEOSStatus = INPUT_EOS_SEEN;
686         }
687
688         if (!mCodecAlreadyOpened) {
689             if (openDecoder() != ERR_OK) {
690                 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
691                 mSignalledError = true;
692                 return;
693             }
694         }
695
696         int32_t err = decodeVideo();
697         if (err < ERR_OK) {
698             notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
699             mSignalledError = true;
700             return;
701         } else if (err == ERR_FLUSHED) {
702             drainEOSOutputBuffer();
703             return;
704         } else if (err == ERR_NO_FRM) {
705             continue;
706         } else {
707             CHECK_EQ(err, ERR_OK);
708         }
709
710         if (handlePortSettingsChange()) {
711             ALOGV("PORT RESET w=%d h=%d", mCtx->width, mCtx->height);
712             return;
713         }
714
715         if (drainOneOutputBuffer() != ERR_OK) {
716             notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
717             mSignalledError = true;
718             return;
719         }
720     }
721 }
722
723 void SoftFFmpegVideo::onPortFlushCompleted(OMX_U32 portIndex) {
724     ALOGV("ffmpeg video decoder flush port(%u)", portIndex);
725     if (portIndex == kInputPortIndex) {
726         if (mCtx && avcodec_is_open(mCtx)) {
727             //Make sure that the next buffer output does not still
728             //depend on fragments from the last one decoded.
729             avcodec_flush_buffers(mCtx);
730         }
731         mEOSStatus = INPUT_DATA_AVAILABLE;
732     }
733 }
734
735 void SoftFFmpegVideo::onReset() {
736     ALOGV("onReset()");
737     SoftVideoDecoderOMXComponent::onReset();
738     mSignalledError = false;
739     mExtradataReady = false;
740 }
741
742 SoftOMXComponent* SoftFFmpegVideo::createSoftOMXComponent(
743         const char *name, const OMX_CALLBACKTYPE *callbacks,
744         OMX_PTR appData, OMX_COMPONENTTYPE **component) {
745
746     OMX_VIDEO_CODINGTYPE codingType = OMX_VIDEO_CodingAutoDetect;
747     char *componentRole = NULL;
748     enum AVCodecID codecID = AV_CODEC_ID_NONE;
749
750     for (size_t i = 0; i < kNumVideoComponents; ++i) {
751         if (!strcasecmp(name, kVideoComponents[i].mName)) {
752             componentRole = strdup(kVideoComponents[i].mRole);
753             codingType = kVideoComponents[i].mVideoCodingType;
754             codecID = kVideoComponents[i].mCodecID;
755             break;
756         }
757     }
758
759     if (componentRole == NULL) {
760         TRESPASS();
761     }
762
763     if (!strcmp(name, "OMX.ffmpeg.mpeg4.decoder")) {
764         return new SoftFFmpegVideo(name, componentRole, codingType,
765                 kM4VProfileLevels, ARRAY_SIZE(kM4VProfileLevels),
766                 callbacks, appData, component, codecID);
767     }
768
769     return new SoftFFmpegVideo(name, componentRole, codingType,
770                 NULL, 0,
771                 callbacks, appData, component, codecID);
772 }
773
774 }  // namespace android