OSDN Git Service

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