OSDN Git Service

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