OSDN Git Service

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