OSDN Git Service

add HEVC(H.265) decoder. plz sync:
[android-x86/external-stagefright-plugins.git] / libstagefright / FFmpegExtractor / FFmpegExtractor.cpp
index 0192cd8..08fa7a2 100644 (file)
 #include "utils/ffmpeg_cmdutils.h"
 #include "FFmpegExtractor.h"
 
-#define DEBUG_READ_ENTRY           0
-#define DEBUG_DISABLE_VIDEO        0
-#define DEBUG_DISABLE_AUDIO        0
-#define WAIT_KEY_PACKET_AFTER_SEEK 1
-#define DISABLE_NAL_TO_ANNEXB      0
-
 #define MAX_QUEUE_SIZE (15 * 1024 * 1024)
 #define MIN_AUDIOQ_SIZE (20 * 16 * 1024)
 #define MIN_FRAMES 5
 #define EXTRACTOR_MAX_PROBE_PACKETS 200
-
 #define FF_MAX_EXTRADATA_SIZE ((1 << 28) - FF_INPUT_BUFFER_PADDING_SIZE)
 
+//debug
+#define DEBUG_READ_ENTRY           0
+#define DEBUG_DISABLE_VIDEO        0
+#define DEBUG_DISABLE_AUDIO        0
+#define WAIT_KEY_PACKET_AFTER_SEEK 1
+#define DISABLE_NAL_TO_ANNEXB      0
+#define DEBUG_PKT                  0
+
 enum {
     NO_SEEK = 0,
     SEEK,
@@ -66,8 +67,10 @@ static AVPacket flush_pkt;
 
 namespace android {
 
+static const char *findMatchingContainer(const char *name);
+
 struct FFmpegExtractor::Track : public MediaSource {
-    Track(const sp<FFmpegExtractor> &extractor, sp<MetaData> meta, bool isAVC,
+    Track(FFmpegExtractor *extractor, sp<MetaData> meta, bool isAVC,
           AVStream *stream, PacketQueue *queue);
 
     virtual status_t start(MetaData *params);
@@ -83,7 +86,7 @@ protected:
 private:
     friend struct FFmpegExtractor;
 
-    sp<FFmpegExtractor> mExtractor;
+    FFmpegExtractor *mExtractor;
     sp<MetaData> mMeta;
 
     enum AVMediaType mMediaType;
@@ -106,7 +109,10 @@ private:
 
 FFmpegExtractor::FFmpegExtractor(const sp<DataSource> &source)
     : mDataSource(source),
+      mMeta(new MetaData),
       mInitCheck(NO_INIT),
+      mFFmpegInited(false),
+      mFormatCtx(NULL),
       mReaderThreadStarted(false) {
     ALOGV("FFmpegExtractor::FFmpegExtractor");
 
@@ -182,11 +188,7 @@ sp<MetaData> FFmpegExtractor::getMetaData() {
         return NULL;
     }
 
-    sp<MetaData> meta = new MetaData;
-    // TODO
-    meta->setCString(kKeyMIMEType, "video/ffmpeg");
-
-    return meta;
+    return mMeta;
 }
 
 uint32_t FFmpegExtractor::flags() const {
@@ -373,6 +375,7 @@ static uint32_t get_sample_rate(const uint8_t sf_index)
 
 int FFmpegExtractor::check_extradata(AVCodecContext *avctx)
 {
+    enum AVCodecID codec_id = AV_CODEC_ID_NONE;
     const char *name = NULL;
     bool *defersToCreateTrack = NULL;
     AVBitStreamFilterContext **bsfc = NULL;
@@ -386,20 +389,19 @@ int FFmpegExtractor::check_extradata(AVCodecContext *avctx)
         defersToCreateTrack = &mDefersToCreateAudioTrack;
     }
 
+       codec_id = avctx->codec_id;
+
     // ignore extradata
-    if (avctx->codec_id == CODEC_ID_MP3 ||
-            avctx->codec_id == CODEC_ID_MP1  ||
-            avctx->codec_id == CODEC_ID_MP2  ||
-            avctx->codec_id == CODEC_ID_AC3  ||
-            avctx->codec_id == CODEC_ID_DTS  ||
-            avctx->codec_id == CODEC_ID_H263  ||
-            avctx->codec_id == CODEC_ID_H263P ||
-            avctx->codec_id == CODEC_ID_H263I ||
-            avctx->codec_id == CODEC_ID_WMV1)
+    if (codec_id != AV_CODEC_ID_H264
+            && codec_id != AV_CODEC_ID_MPEG4
+            && codec_id != AV_CODEC_ID_MPEG1VIDEO
+            && codec_id != AV_CODEC_ID_MPEG2VIDEO
+            && codec_id != AV_CODEC_ID_AAC) {
         return 1;
+    }
 
     // is extradata compatible with android?
-    if (avctx->codec_id != CODEC_ID_AAC) {
+    if (codec_id != AV_CODEC_ID_AAC) {
         int is_compatible = is_extradata_compatible_with_android(avctx);
         if (!is_compatible) {
             ALOGI("%s extradata is not compatible with android, should to extract it from bitstream",
@@ -411,7 +413,7 @@ int FFmpegExtractor::check_extradata(AVCodecContext *avctx)
         return 1;
     }
 
-    if (avctx->codec_id == CODEC_ID_AAC) {
+    if (codec_id == AV_CODEC_ID_AAC) {
         name = "aac_adtstoasc";
     }
 
@@ -454,6 +456,55 @@ void FFmpegExtractor::printTime(int64_t time)
         hours, mins, secs, (100 * us) / AV_TIME_BASE);
 }
 
+bool FFmpegExtractor::is_codec_supported(enum AVCodecID codec_id)
+{
+    bool supported = false;
+
+    switch(codec_id) {
+    case AV_CODEC_ID_H264:
+    case AV_CODEC_ID_MPEG4:
+    case AV_CODEC_ID_H263:
+    case AV_CODEC_ID_H263P:
+    case AV_CODEC_ID_H263I:
+    case AV_CODEC_ID_AAC:
+    case AV_CODEC_ID_AC3:
+    case AV_CODEC_ID_MP2:
+    case AV_CODEC_ID_MP3:
+    case AV_CODEC_ID_MPEG1VIDEO:
+    case AV_CODEC_ID_MPEG2VIDEO:
+    case AV_CODEC_ID_WMV1:
+    case AV_CODEC_ID_WMV2:
+    case AV_CODEC_ID_WMV3:
+    case AV_CODEC_ID_VC1:
+    case AV_CODEC_ID_WMAV1:
+    case AV_CODEC_ID_WMAV2:
+    case AV_CODEC_ID_WMAPRO:
+    case AV_CODEC_ID_WMALOSSLESS:
+    case AV_CODEC_ID_RV20:
+    case AV_CODEC_ID_RV30:
+    case AV_CODEC_ID_RV40:
+    case AV_CODEC_ID_COOK:
+    case AV_CODEC_ID_APE:
+    case AV_CODEC_ID_DTS:
+    case AV_CODEC_ID_FLAC:
+    case AV_CODEC_ID_FLV1:
+    case AV_CODEC_ID_VORBIS:
+    case AV_CODEC_ID_HEVC:
+
+        supported = true;
+        break;
+    default:
+        ALOGD("unsuppoted codec(%s), but give it a chance",
+                avcodec_get_name(codec_id));
+        //Won't promise that the following codec id can be supported.
+           //Just give these codecs a chance.
+        supported = true;
+        break;
+    }
+
+       return supported;
+}
+
 int FFmpegExtractor::stream_component_open(int stream_index)
 {
     AVCodecContext *avctx = NULL;
@@ -470,43 +521,13 @@ int FFmpegExtractor::stream_component_open(int stream_index)
         return -1;
     avctx = mFormatCtx->streams[stream_index]->codec;
 
-    switch(avctx->codec_id) {
-    case CODEC_ID_H264:
-    case CODEC_ID_MPEG4:
-    case CODEC_ID_H263:
-    case CODEC_ID_H263P:
-    case CODEC_ID_H263I:
-    case CODEC_ID_AAC:
-    case CODEC_ID_AC3:
-    case CODEC_ID_MP1:
-    case CODEC_ID_MP2:
-    case CODEC_ID_MP3:
-    case CODEC_ID_MPEG2VIDEO:
-    case CODEC_ID_WMV1:
-    case CODEC_ID_WMV2:
-    case CODEC_ID_WMV3:
-    case CODEC_ID_VC1:
-    case CODEC_ID_WMAV1:
-    case CODEC_ID_WMAV2:
-    case CODEC_ID_WMAPRO:
-    case CODEC_ID_WMALOSSLESS:
-    case CODEC_ID_RV40:
-    case CODEC_ID_COOK:
-    case CODEC_ID_APE:
-    case CODEC_ID_DTS:
-    case CODEC_ID_FLAC:
-        supported = true;
-        break;
-    default:
-        supported = false;
-        break;
-    }
+    supported = is_codec_supported(avctx->codec_id);
 
     if (!supported) {
-        ALOGE("unsupport the codec, id: 0x%0x", avctx->codec_id);
+        ALOGE("unsupport the codec(%s)", avcodec_get_name(avctx->codec_id));
         return -1;
     }
-    ALOGV("support the codec");
+    ALOGI("support the codec(%s)", avcodec_get_name(avctx->codec_id));
 
     unsigned streamType;
     ssize_t index = mTracks.indexOfKey(stream_index);
@@ -520,7 +541,7 @@ int FFmpegExtractor::stream_component_open(int stream_index)
 
     char tagbuf[32];
     av_get_codec_tag_string(tagbuf, sizeof(tagbuf), avctx->codec_tag);
-    ALOGV("Tag %s/0x%08x with codec id '%d'\n", tagbuf, avctx->codec_tag, avctx->codec_id);
+    ALOGV("Tag %s/0x%08x with codec(%s)\n", tagbuf, avctx->codec_tag, avcodec_get_name(avctx->codec_id));
 
     switch (avctx->codec_type) {
     case AVMEDIA_TYPE_VIDEO:
@@ -529,7 +550,7 @@ int FFmpegExtractor::stream_component_open(int stream_index)
         if (mVideoStream == NULL)
             mVideoStream = mFormatCtx->streams[stream_index];
         if (!mVideoQInited) {
-           packet_queue_init(&mVideoQ);
+               packet_queue_init(&mVideoQ);
             mVideoQInited = true;
         }
 
@@ -556,7 +577,7 @@ int FFmpegExtractor::stream_component_open(int stream_index)
         meta = new MetaData;
 
         switch(avctx->codec_id) {
-        case CODEC_ID_H264:
+        case AV_CODEC_ID_H264:
             /**
              * H.264 Video Types
              * http://msdn.microsoft.com/en-us/library/dd757808(v=vs.85).aspx
@@ -592,7 +613,7 @@ int FFmpegExtractor::stream_component_open(int stream_index)
                 meta = MakeAVCCodecSpecificData(buffer);
             }
             break;
-        case CODEC_ID_MPEG4:
+        case AV_CODEC_ID_MPEG4:
             ALOGV("MPEG4");
             meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
             {
@@ -602,14 +623,15 @@ int FFmpegExtractor::stream_component_open(int stream_index)
                 meta->setData(kKeyESDS, kTypeESDS, esds->data(), esds->size());
             }
             break;
-        case CODEC_ID_H263:
-        case CODEC_ID_H263P:
-        case CODEC_ID_H263I:
+        case AV_CODEC_ID_H263:
+        case AV_CODEC_ID_H263P:
+        case AV_CODEC_ID_H263I:
             ALOGV("H263");
             meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263);
             break;
-        case CODEC_ID_MPEG2VIDEO:
-            ALOGV("MPEG2VIDEO");
+        case AV_CODEC_ID_MPEG1VIDEO:
+        case AV_CODEC_ID_MPEG2VIDEO:
+            ALOGV("MPEG%dVIDEO", avctx->codec_id == AV_CODEC_ID_MPEG2VIDEO ? 2 : 1);
             meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG2);
             {
                 sp<ABuffer> csd = new ABuffer(avctx->extradata_size);
@@ -618,35 +640,65 @@ int FFmpegExtractor::stream_component_open(int stream_index)
                 meta->setData(kKeyESDS, kTypeESDS, esds->data(), esds->size());
             }
             break;
-        case CODEC_ID_VC1:
+        case AV_CODEC_ID_VC1:
             ALOGV("VC1");
             meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_VC1);
             meta->setData(kKeyRawCodecSpecificData, 0, avctx->extradata, avctx->extradata_size);
             break;
-        case CODEC_ID_WMV1:
+        case AV_CODEC_ID_WMV1:
             ALOGV("WMV1");
             meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_WMV);
             meta->setInt32(kKeyWMVVersion, kTypeWMVVer_7);
             break;
-        case CODEC_ID_WMV2:
+        case AV_CODEC_ID_WMV2:
             ALOGV("WMV2");
             meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_WMV);
             meta->setData(kKeyRawCodecSpecificData, 0, avctx->extradata, avctx->extradata_size);
             meta->setInt32(kKeyWMVVersion, kTypeWMVVer_8);
             break;
-        case CODEC_ID_WMV3:
+        case AV_CODEC_ID_WMV3:
             ALOGV("WMV3");
             meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_WMV);
             meta->setData(kKeyRawCodecSpecificData, 0, avctx->extradata, avctx->extradata_size);
             meta->setInt32(kKeyWMVVersion, kTypeWMVVer_9);
             break;
-        case CODEC_ID_RV40:
+        case AV_CODEC_ID_RV20:
+            ALOGV("RV30");
+            meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RV);
+            meta->setData(kKeyRawCodecSpecificData, 0, avctx->extradata, avctx->extradata_size);
+            meta->setInt32(kKeyRVVersion, kTypeRVVer_G2); //http://en.wikipedia.org/wiki/RealVideo
+        case AV_CODEC_ID_RV30:
+            ALOGV("RV30");
+            meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RV);
+            meta->setData(kKeyRawCodecSpecificData, 0, avctx->extradata, avctx->extradata_size);
+            meta->setInt32(kKeyRVVersion, kTypeRVVer_8); //http://en.wikipedia.org/wiki/RealVideo
+            break;
+        case AV_CODEC_ID_RV40:
             ALOGV("RV40");
             meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RV);
             meta->setData(kKeyRawCodecSpecificData, 0, avctx->extradata, avctx->extradata_size);
+            meta->setInt32(kKeyRVVersion, kTypeRVVer_9); //http://en.wikipedia.org/wiki/RealVideo
+            break;
+        case AV_CODEC_ID_FLV1:
+            ALOGV("FLV1");
+            meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_FLV1);
+            meta->setData(kKeyRawCodecSpecificData, 0, avctx->extradata, avctx->extradata_size);
+            break;
+        case AV_CODEC_ID_HEVC:
+            ALOGV("HEVC");
+            meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_HEVC);
+            meta->setData(kKeyRawCodecSpecificData, 0, avctx->extradata, avctx->extradata_size);
             break;
         default:
-            CHECK(!"Should not be here. Unsupported codec.");
+            ALOGD("unsuppoted video codec(id:%d, name:%s), but give it a chance",
+                    avctx->codec_id, avcodec_get_name(avctx->codec_id));
+            meta = new MetaData;
+            meta->setInt32(kKeyCodecId, avctx->codec_id);
+            meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_FFMPEG);
+            if (avctx->extradata_size > 0) {
+                meta->setData(kKeyRawCodecSpecificData, 0, avctx->extradata, avctx->extradata_size);
+            }
+            //CHECK(!"Should not be here. Unsupported codec.");
             break;
         }
 
@@ -661,6 +713,11 @@ int FFmpegExtractor::stream_component_open(int stream_index)
             int64_t duration = mVideoStream->duration * av_q2d(mVideoStream->time_base) * 1000000;
             printTime(duration);
             ALOGV("video startTime: %lld", mVideoStream->start_time);
+            if (mVideoStream->start_time != AV_NOPTS_VALUE) {
+                ALOGV("video startTime:%lld", mVideoStream->start_time);
+            } else {
+                ALOGV("video startTime:N/A");
+            }
             meta->setInt64(kKeyDuration, duration);
         } else {
             // default when no stream duration
@@ -698,34 +755,35 @@ int FFmpegExtractor::stream_component_open(int stream_index)
         }
 
         if (avctx->extradata) {
-            ALOGV("audio stream extradata:");
+            ALOGV("audio stream extradata(%d):", avctx->extradata_size);
             hexdump(avctx->extradata, avctx->extradata_size);
         } else {
             ALOGV("audio stream no extradata, but we can ignore it.");
         }
 
         switch(avctx->codec_id) {
-        case CODEC_ID_MP1:
-            ALOGV("MP1");
-            meta = new MetaData;
-            meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I);
-            break;
-        case CODEC_ID_MP2:
+        case AV_CODEC_ID_MP2:
             ALOGV("MP2");
             meta = new MetaData;
             meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II);
             break;
-        case CODEC_ID_MP3:
+        case AV_CODEC_ID_MP3:
             ALOGV("MP3");
             meta = new MetaData;
             meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
             break;
-        case CODEC_ID_AC3:
+        case AV_CODEC_ID_VORBIS:
+            ALOGV("VORBIS");
+            meta = new MetaData;
+            meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_VORBIS);
+            meta->setData(kKeyRawCodecSpecificData, 0, avctx->extradata, avctx->extradata_size);
+            break;
+        case AV_CODEC_ID_AC3:
             ALOGV("AC3");
             meta = new MetaData;
             meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AC3);
             break;
-        case CODEC_ID_AAC:
+        case AV_CODEC_ID_AAC:
             ALOGV("AAC");
             uint32_t sr;
             const uint8_t *header;
@@ -752,74 +810,89 @@ int FFmpegExtractor::stream_component_open(int stream_index)
             meta = MakeAACCodecSpecificData(profile, sf_index, channel);
             meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
             break;
-        case CODEC_ID_WMAV1:  // TODO, version?
+        case AV_CODEC_ID_WMAV1:  // TODO, version?
             ALOGV("WMAV1");
             meta = new MetaData;
             meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_WMA);
             meta->setData(kKeyRawCodecSpecificData, 0, avctx->extradata, avctx->extradata_size);
             break;
-        case CODEC_ID_WMAV2:
+        case AV_CODEC_ID_WMAV2:
             ALOGV("WMAV2");
             meta = new MetaData;
             meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_WMA);
             meta->setData(kKeyRawCodecSpecificData, 0, avctx->extradata, avctx->extradata_size);
             meta->setInt32(kKeyWMAVersion, kTypeWMA);
             break;
-        case CODEC_ID_WMAPRO:
+        case AV_CODEC_ID_WMAPRO:
             ALOGV("WMAPRO");
             meta = new MetaData;
             meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_WMA);
             meta->setData(kKeyRawCodecSpecificData, 0, avctx->extradata, avctx->extradata_size);
             meta->setInt32(kKeyWMAVersion, kTypeWMAPro);
             break;
-        case CODEC_ID_WMALOSSLESS:
+        case AV_CODEC_ID_WMALOSSLESS:
             ALOGV("WMALOSSLESS");
             meta = new MetaData;
             meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_WMA);
             meta->setData(kKeyRawCodecSpecificData, 0, avctx->extradata, avctx->extradata_size);
             meta->setInt32(kKeyWMAVersion, kTypeWMALossLess);
             break;
-        case CODEC_ID_COOK: // audio codec in RMVB
+        case AV_CODEC_ID_COOK: // audio codec in RMVB
             ALOGV("COOK");
             meta = new MetaData;
             meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RA);
             meta->setData(kKeyRawCodecSpecificData, 0, avctx->extradata, avctx->extradata_size);
             break;
-        case CODEC_ID_APE:
+        case AV_CODEC_ID_APE:
             ALOGV("APE");
             meta = new MetaData;
             meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_APE);
             meta->setData(kKeyRawCodecSpecificData, 0, avctx->extradata, avctx->extradata_size);
             break;
-        case CODEC_ID_DTS:
+        case AV_CODEC_ID_DTS:
             ALOGV("DTS");
             meta = new MetaData;
             meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_DTS);
             meta->setData(kKeyRawCodecSpecificData, 0, avctx->extradata, avctx->extradata_size);
             break;
-        case CODEC_ID_FLAC:
+        case AV_CODEC_ID_FLAC:
             ALOGV("FLAC");
             meta = new MetaData;
             meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_FLAC);
             meta->setData(kKeyRawCodecSpecificData, 0, avctx->extradata, avctx->extradata_size);
             break;
         default:
-            CHECK(!"Should not be here. Unsupported codec.");
+            ALOGD("unsuppoted audio codec(id:%d, name:%s), but give it a chance",
+                    avctx->codec_id, avcodec_get_name(avctx->codec_id));
+            meta = new MetaData;
+            meta->setInt32(kKeyCodecId, avctx->codec_id);
+            meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_FFMPEG);
+            if (avctx->extradata_size > 0) {
+                meta->setData(kKeyRawCodecSpecificData, 0, avctx->extradata, avctx->extradata_size);
+            }
+            //CHECK(!"Should not be here. Unsupported codec.");
             break;
         }
 
-        ALOGI("bit_rate: %d, sample_rate: %d, channels: %d, bits_per_coded_sample: %d",
-             avctx->bit_rate, avctx->sample_rate, avctx->channels, avctx->bits_per_coded_sample);
+        ALOGI("bit_rate: %d, sample_rate: %d, channels: %d, "
+                "bits_per_coded_sample: %d, block_align:%d",
+                avctx->bit_rate, avctx->sample_rate, avctx->channels,
+                avctx->bits_per_coded_sample, avctx->block_align);
 
-        meta->setInt32(kKeySampleRate, avctx->sample_rate);
         meta->setInt32(kKeyChannelCount, avctx->channels);
-        meta->setInt32(kKeyBitspersample, avctx->bits_per_coded_sample);
         meta->setInt32(kKeyBitRate, avctx->bit_rate);
+        meta->setInt32(kKeyBitspersample, avctx->bits_per_coded_sample);
+        meta->setInt32(kKeySampleRate, avctx->sample_rate);
         meta->setInt32(kKeyBlockAlign, avctx->block_align);
+        meta->setInt32(kKeySampleFormat, avctx->sample_fmt);
         if (mAudioStream->duration != AV_NOPTS_VALUE) {
             int64_t duration = mAudioStream->duration * av_q2d(mAudioStream->time_base) * 1000000;
             printTime(duration);
-            ALOGV("audio startTime: %lld", mAudioStream->start_time);
+            if (mAudioStream->start_time != AV_NOPTS_VALUE) {
+                ALOGV("audio startTime:%lld", mAudioStream->start_time);
+            } else {
+                ALOGV("audio startTime:N/A");
+            }
             meta->setInt64(kKeyDuration, duration);
         } else {
             // default when no stream duration
@@ -948,22 +1021,12 @@ int FFmpegExtractor::decode_interrupt_cb(void *ctx)
     return extrator->mAbortRequest;
 }
 
-void FFmpegExtractor::print_error_ex(const char *filename, int err)
-{
-    char errbuf[128];
-    const char *errbuf_ptr = errbuf;
-
-    if (av_strerror(err, errbuf, sizeof(errbuf)) < 0)
-        errbuf_ptr = strerror(AVUNERROR(err));
-    ALOGI("%s: %s\n", filename, errbuf_ptr);
-}
-
 void FFmpegExtractor::buildFileName(const sp<DataSource> &source)
 {
 #if 1
-    ALOGI("android-source:%p", &source);
+    ALOGI("android-source:%p", source.get());
     // pass the addr of smart pointer("source")
-    snprintf(mFilename, sizeof(mFilename), "android-source:%p", &source);
+    snprintf(mFilename, sizeof(mFilename), "android-source:%p", source.get());
     ALOGI("build mFilename: %s", mFilename);
 #else
     const char *url = mDataSource->getNamURI();
@@ -1027,7 +1090,7 @@ int FFmpegExtractor::initStreams()
        int i = 0;
     status_t status = UNKNOWN_ERROR;
     int eof = 0;
-    int ret = 0, audio_ret = 0, video_ret = 0;
+    int ret = 0, audio_ret = -1, video_ret = -1;
     int pkt_in_play_range = 0;
     AVDictionaryEntry *t = NULL;
     AVDictionary **opts = NULL;
@@ -1038,6 +1101,7 @@ int FFmpegExtractor::initStreams()
     st_index[AVMEDIA_TYPE_VIDEO]  = -1;
     wanted_stream[AVMEDIA_TYPE_AUDIO]  = -1;
     wanted_stream[AVMEDIA_TYPE_VIDEO]  = -1;
+    const char *mime = NULL;
 
     setFFmpegDefaultOpts();
 
@@ -1046,6 +1110,7 @@ int FFmpegExtractor::initStreams()
         ret = -1;
         goto fail;
     }
+    mFFmpegInited = true;
 
     av_init_packet(&flush_pkt);
     flush_pkt.data = (uint8_t *)"FLUSH";
@@ -1055,15 +1120,15 @@ int FFmpegExtractor::initStreams()
        if (!mFormatCtx)
        {
         ALOGE("oom for alloc avformat context");
-        ret -1;
-               goto fail;
+        ret -1;
+        goto fail;
        }
     mFormatCtx->interrupt_callback.callback = decode_interrupt_cb;
     mFormatCtx->interrupt_callback.opaque = this;
     ALOGV("mFilename: %s", mFilename);
     err = avformat_open_input(&mFormatCtx, mFilename, NULL, &format_opts);
     if (err < 0) {
-        print_error_ex(mFilename, err);
+        ALOGE("%s: avformat_open_input failed, err:%s", mFilename, av_err2str(err));
         ret = -1;
         goto fail;
     }
@@ -1082,7 +1147,7 @@ int FFmpegExtractor::initStreams()
 
     err = avformat_find_stream_info(mFormatCtx, opts);
     if (err < 0) {
-        ALOGE("%s: could not find codec parameters\n", mFilename);
+        ALOGE("%s: could not find stream info, err:%s", mFilename, av_err2str(err));
         ret = -1;
         goto fail;
     }
@@ -1090,6 +1155,10 @@ int FFmpegExtractor::initStreams()
         av_dict_free(&opts[i]);
     av_freep(&opts);
 
+    mime = findMatchingContainer(mFormatCtx->iformat->name);
+    CHECK(mime != NULL);
+    mMeta->setCString(kKeyMIMEType, mime);
+
     if (mFormatCtx->pb)
         mFormatCtx->pb->eof_reached = 0; // FIXME hack, ffplay maybe should not use url_feof() to test for the end
 
@@ -1156,7 +1225,9 @@ void FFmpegExtractor::deInitStreams()
         avformat_close_input(&mFormatCtx);
     }
 
-    deInitFFmpeg();
+    if (mFFmpegInited) {
+        deInitFFmpeg();
+    }
 }
 
 status_t FFmpegExtractor::startReaderThread() {
@@ -1207,7 +1278,7 @@ void FFmpegExtractor::readerEntry() {
     int eof = 0;
     int pkt_in_play_range = 0;
 
-    ALOGV("FFmpegExtractor::readerEntry");
+    ALOGV("FFmpegExtractor enter thread(readerEntry)");
 
     mVideoEOSReceived = false;
     mAudioEOSReceived = false;
@@ -1403,13 +1474,15 @@ fail:
     if (mFormatCtx) {
         avformat_close_input(&mFormatCtx);
     }
+
+    ALOGV("FFmpegExtractor exit thread(readerEntry)");
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 
 FFmpegExtractor::Track::Track(
-        const sp<FFmpegExtractor> &extractor, sp<MetaData> meta, bool isAVC,
-          AVStream *stream, PacketQueue *queue)
+        FFmpegExtractor *extractor, sp<MetaData> meta, bool isAVC,
+        AVStream *stream, PacketQueue *queue)
     : mExtractor(extractor),
       mMeta(meta),
       mIsAVC(isAVC),
@@ -1446,17 +1519,25 @@ FFmpegExtractor::Track::Track(
 }
 
 FFmpegExtractor::Track::~Track() {
+    ALOGV("FFmpegExtractor::Track::~Track %s",
+            av_get_media_type_string(mMediaType));
+       mExtractor = NULL;
+       mMeta = NULL;
 }
 
 status_t FFmpegExtractor::Track::start(MetaData *params) {
+    ALOGV("FFmpegExtractor::Track::start %s",
+            av_get_media_type_string(mMediaType));
     Mutex::Autolock autoLock(mLock);
     //mExtractor->startReaderThread();
     return OK;
 }
 
 status_t FFmpegExtractor::Track::stop() {
+    ALOGV("FFmpegExtractor::Track::stop %s",
+            av_get_media_type_string(mMediaType));
     Mutex::Autolock autoLock(mLock);
-    mExtractor->stopReaderThread();
+    //mExtractor->stopReaderThread();
     return OK;
 }
 
@@ -1478,8 +1559,8 @@ status_t FFmpegExtractor::Track::read(
     ReadOptions::SeekMode mode;
     int64_t pktTS = AV_NOPTS_VALUE;
     int64_t seekTimeUs = AV_NOPTS_VALUE;
-    int64_t timeUs;
-    int key;
+    int64_t timeUs = AV_NOPTS_VALUE;
+    int key = 0;
     status_t status = OK;
 
     if (options && options->getSeekTo(&seekTimeUs, &mode)) {
@@ -1517,21 +1598,29 @@ retry:
         mFirstKeyPktTimestamp = AV_NOPTS_VALUE;
         goto retry;
     } else if (pkt.data == NULL && pkt.size == 0) {
-        ALOGV("read %s eos pkt", av_get_media_type_string(mMediaType));
+        ALOGD("read %s eos pkt", av_get_media_type_string(mMediaType));
         av_free_packet(&pkt);
         mExtractor->reachedEOS(mMediaType);
-       return ERROR_END_OF_STREAM;
+           return ERROR_END_OF_STREAM;
     }
 
     key = pkt.flags & AV_PKT_FLAG_KEY ? 1 : 0;
-    pktTS = pkt.pts;
-    // use dts when AVI
+    pktTS = pkt.pts; //FIXME AV_NOPTS_VALUE??
+
+    //use dts when AVI
     if (pkt.pts == AV_NOPTS_VALUE)
         pktTS = pkt.dts;
 
+    //FIXME, drop, omxcodec requires a positive timestamp! e.g. vorbis
+    if (pktTS != AV_NOPTS_VALUE && pktTS < 0) {
+        ALOGW("drop the packet with negative timestamp(pts:%lld)", pktTS);
+        av_free_packet(&pkt);
+        goto retry;
+    }
+
     if (waitKeyPkt) {
         if (!key) {
-            ALOGV("drop the no key packet");
+            ALOGV("drop the non-key packet");
             av_free_packet(&pkt);
             goto retry;
         } else {
@@ -1540,12 +1629,12 @@ retry:
         }
     }
 
-    if (mFirstKeyPktTimestamp == AV_NOPTS_VALUE) {
+    if (pktTS != AV_NOPTS_VALUE && mFirstKeyPktTimestamp == AV_NOPTS_VALUE) {
         // update the first key timestamp
         mFirstKeyPktTimestamp = pktTS;
     }
      
-    if (pktTS < mFirstKeyPktTimestamp) {
+    if (pktTS != AV_NOPTS_VALUE && pktTS < mFirstKeyPktTimestamp) {
             ALOGV("drop the packet with the backward timestamp, maybe they are B-frames after I-frame ^_^");
             av_free_packet(&pkt);
             goto retry;
@@ -1603,11 +1692,18 @@ retry:
     }
 
     int64_t start_time = mStream->start_time != AV_NOPTS_VALUE ? mStream->start_time : 0;
-    timeUs = (int64_t)((pktTS - start_time) * av_q2d(mStream->time_base) * 1000000);
+    if (pktTS != AV_NOPTS_VALUE)
+        timeUs = (int64_t)((pktTS - start_time) * av_q2d(mStream->time_base) * 1000000);
+    else
+        timeUs = SF_NOPTS_VALUE; //FIXME AV_NOPTS_VALUE is negative, but stagefright need positive
 
-#if 0
-    ALOGV("read %s pkt, size: %d, key: %d, pts: %lld, dts: %lld, timeUs[-startTime]: %llu us (%.2f secs)",
-        av_get_media_type_string(mMediaType), pkt.size, key, pkt.pts, pkt.dts, timeUs, timeUs/1E6);
+#if DEBUG_PKT
+    if (pktTS != AV_NOPTS_VALUE)
+        ALOGV("read %s pkt, size:%d, key:%d, pts:%lld, dts:%lld, timeUs[-startTime]:%lld us (%.2f secs)",
+            av_get_media_type_string(mMediaType), pkt.size, key, pkt.pts, pkt.dts, timeUs, timeUs/1E6);
+    else
+        ALOGV("read %s pkt, size:%d, key:%d, pts:N/A, dts:N/A, timeUs[-startTime]:N/A",
+            av_get_media_type_string(mMediaType), pkt.size, key);
 #endif
 
     mediaBuffer->meta_data()->setInt64(kKeyTime, timeUs);
@@ -1622,7 +1718,6 @@ retry:
 
 ////////////////////////////////////////////////////////////////////////////////
 
-// LegacySniffFFMPEG
 typedef struct {
     const char *format;
     const char *container;
@@ -1631,21 +1726,23 @@ typedef struct {
 static formatmap FILE_FORMATS[] = {
         {"mpeg",                    MEDIA_MIMETYPE_CONTAINER_MPEG2PS  },
         {"mpegts",                  MEDIA_MIMETYPE_CONTAINER_TS       },
-        {"mov,mp4,m4a,3gp,3g2,mj2", MEDIA_MIMETYPE_CONTAINER_MOV      },
+        {"mov,mp4,m4a,3gp,3g2,mj2", MEDIA_MIMETYPE_CONTAINER_MPEG4    },
         {"matroska,webm",           MEDIA_MIMETYPE_CONTAINER_MATROSKA },
         {"asf",                     MEDIA_MIMETYPE_CONTAINER_ASF      },
         {"rm",                      MEDIA_MIMETYPE_CONTAINER_RM       },
         {"flv",                     MEDIA_MIMETYPE_CONTAINER_FLV      },
+        {"swf",                     MEDIA_MIMETYPE_CONTAINER_FLV      },
         {"avi",                     MEDIA_MIMETYPE_CONTAINER_AVI      },
         {"ape",                     MEDIA_MIMETYPE_CONTAINER_APE      },
         {"dts",                     MEDIA_MIMETYPE_CONTAINER_DTS      },
         {"flac",                    MEDIA_MIMETYPE_CONTAINER_FLAC     },
-#if 0
+        {"ac3",                     MEDIA_MIMETYPE_AUDIO_AC3          },
         {"wav",                     MEDIA_MIMETYPE_CONTAINER_WAV      },
-#endif
+        {"ogg",                     MEDIA_MIMETYPE_CONTAINER_OGG      },
+        {"hevc",                     MEDIA_MIMETYPE_CONTAINER_HEVC    },
 };
 
-static void adjustMOVConfidence(AVFormatContext *ic, float *confidence)
+static void adjustMPEG4Confidence(AVFormatContext *ic, float *confidence)
 {
        AVDictionary *tags = NULL;
        AVDictionaryEntry *tag = NULL;
@@ -1662,7 +1759,7 @@ static void adjustMOVConfidence(AVFormatContext *ic, float *confidence)
 
        ALOGV("major_brand tag is:%s", tag->value);
 
-       //when MEDIA_MIMETYPE_CONTAINER_MOV
+       //when MEDIA_MIMETYPE_CONTAINER_MPEG4
        //WTF, MPEG4Extractor.cpp can not extractor mov format
        //NOTE: isCompatibleBrand(MPEG4Extractor.cpp)
        //  Won't promise that the following file types can be played.
@@ -1682,14 +1779,21 @@ static void adjustVideoCodecConfidence(AVFormatContext *ic,
        //add to here
 }
 
+//TODO. if the other stream(e.g. mp3) is supported by stagefright
 static void adjustAudioCodecConfidence(AVFormatContext *ic,
                enum AVCodecID codec_id, float *confidence)
 {
        switch (codec_id) {
-       case CODEC_ID_AC3:
-               //TODO. if the other stream(e.g. mp3) is supported by stagefright
+       case AV_CODEC_ID_AC3:
                ALOGI("ffmpeg can demux ac3 only");
                *confidence = 0.88f;
+               break;
+       case AV_CODEC_ID_MP1:
+       case AV_CODEC_ID_MP2:
+               //TODO. if the other stream(e.g. mp3) is supported by stagefright
+               ALOGI("ffmpeg can demux mp1 and mp2 only");
+               *confidence = 0.88f;
+               break;
        default:
                break;
        }
@@ -1701,27 +1805,37 @@ static void adjustCodecConfidence(AVFormatContext *ic, float *confidence)
        AVCodecContext *avctx = NULL;
        AVMediaType     codec_type = AVMEDIA_TYPE_UNKNOWN;
        enum AVCodecID codec_id = AV_CODEC_ID_NONE;
+       bool haveVideo = false;
+       bool haveAudio = false;
+       bool haveMP3 = false;
 
-       for (idx = 0; idx < ic->nb_streams; idx++)
-       {
+       for (idx = 0; idx < ic->nb_streams; idx++) {
                avctx = ic->streams[idx]->codec;
                codec_type = avctx->codec_type;
                codec_id = avctx->codec_id;
 
                if (codec_type == AVMEDIA_TYPE_VIDEO) {
+                       haveVideo = true;
                        adjustVideoCodecConfidence(ic, codec_id, confidence);
                } else if (codec_type == AVMEDIA_TYPE_AUDIO) {
+                       haveAudio = true;
                        adjustAudioCodecConfidence(ic, codec_id, confidence);
+                       if (codec_id == AV_CODEC_ID_MP3)
+                               haveMP3 = true;
                }
        }
+
+       if (haveVideo && haveMP3) {
+               *confidence = 0.22f; // larger than MP3Extractor an MP3Extractor
+       }
 }
 
 static void adjustConfidenceIfNeeded(const char *mime,
                AVFormatContext *ic, float *confidence)
 {
        //check mime
-       if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MOV)) {
-               adjustMOVConfidence(ic, confidence);
+       if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG4)) {
+               adjustMPEG4Confidence(ic, confidence);
        } else {
                //add to here;
        }
@@ -1730,12 +1844,37 @@ static void adjustConfidenceIfNeeded(const char *mime,
        adjustCodecConfidence(ic, confidence);
 }
 
+static const char *findMatchingContainer(const char *name)
+{
+       size_t i = 0;
+       const char *container = NULL;
+
+       ALOGI("list the formats suppoted by ffmpeg: ");
+       ALOGI("========================================");
+       for (i = 0; i < NELEM(FILE_FORMATS); ++i) {
+               ALOGV("format_names[%02d]: %s", i, FILE_FORMATS[i].format);
+       }
+       ALOGI("========================================");
+
+       for (i = 0; i < NELEM(FILE_FORMATS); ++i) {
+               int len = strlen(FILE_FORMATS[i].format);
+               if (!av_strncasecmp(name, FILE_FORMATS[i].format, len)) {
+                       container = FILE_FORMATS[i].container;
+                       break;
+               }
+       }
+
+       return container;
+}
+
 static const char *SniffFFMPEGCommon(const char *url, float *confidence)
 {
        size_t i = 0;
        int err = 0;
        const char *container = NULL;
        AVFormatContext *ic = NULL;
+       AVDictionary **opts = NULL;
+       size_t orig_nb_streams = 0;
 
        status_t status = initFFmpeg();
        if (status != OK) {
@@ -1747,41 +1886,46 @@ static const char *SniffFFMPEGCommon(const char *url, float *confidence)
        if (!ic)
        {
                ALOGE("oom for alloc avformat context");
-               return NULL;
+               goto fail;
        }
 
        err = avformat_open_input(&ic, url, NULL, NULL);
        if (err < 0) {
-               ALOGE("avformat_open_input faild, url: %s err: %d", url, err);
-               return NULL;
+        ALOGE("%s: avformat_open_input failed, err:%s", url, av_err2str(err));
+               goto fail;
+       }
+
+       opts = setup_find_stream_info_opts(ic, codec_opts);
+       orig_nb_streams = ic->nb_streams;
+       err = avformat_find_stream_info(ic, opts);
+       if (err < 0) {
+        ALOGE("%s: could not find stream info, err:%s", url, av_err2str(err));
+               goto fail;
+       }
+       for (i = 0; i < orig_nb_streams; i++) {
+               av_dict_free(&opts[i]);
        }
+       av_freep(&opts);
 
        av_dump_format(ic, 0, url, 0);
 
        ALOGI("FFmpegExtrator, url: %s, format_name: %s, format_long_name: %s",
                        url, ic->iformat->name, ic->iformat->long_name);
 
-       ALOGI("list the formats suppoted by ffmpeg: ");
-       ALOGI("========================================");
-       for (i = 0; i < NELEM(FILE_FORMATS); ++i) {
-               ALOGV("format_names[%02d]: %s", i, FILE_FORMATS[i].format);
-       }
-       ALOGI("========================================");
-
-       for (i = 0; i < NELEM(FILE_FORMATS); ++i) {
-               int len = strlen(FILE_FORMATS[i].format);
-               if (!av_strncasecmp(ic->iformat->name, FILE_FORMATS[i].format, len)) {
-                       container = FILE_FORMATS[i].container;
-                       break;
-               }
-       }
+       container = findMatchingContainer(ic->iformat->name);
 
        if (container) {
                adjustConfidenceIfNeeded(container, ic, confidence);
        }
 
-       avformat_close_input(&ic);
-       av_free(ic);
+fail:
+       if (ic) {
+               avformat_close_input(&ic);
+               av_free(ic);
+       }
+       if (status == OK) {
+               deInitFFmpeg();
+       }
 
        return container;
 }
@@ -1802,10 +1946,10 @@ static const char *BetterSniffFFMPEG(const sp<DataSource> &source, float *confid
 {
        char url[128] = {0};
 
-       ALOGI("android-source:%p", &source);
+       ALOGI("android-source:%p", source.get());
 
        // pass the addr of smart pointer("source")
-       snprintf(url, sizeof(url), "android-source:%p", &source);
+       snprintf(url, sizeof(url), "android-source:%p", source.get());
 
        return SniffFFMPEGCommon(url, confidence);
 }
@@ -1833,18 +1977,18 @@ bool SniffFFMPEG(
                return false;
        }
 
-       ALOGV("found container: %s", container);
-
-       mimeType->setTo(container);
+       ALOGD("ffmpeg detected media content as '%s' with confidence %.2f",
+                       container, *confidence);
 
        /* use MPEG4Extractor(not extended extractor) for HTTP source only */
-       if (!av_strcasecmp(container, MEDIA_MIMETYPE_CONTAINER_MPEG4)
+       if (!strcasecmp(container, MEDIA_MIMETYPE_CONTAINER_MPEG4)
                        && (source->flags() & DataSource::kIsCachingDataSource)) {
-               return true;
+               ALOGI("support container: %s, but it is caching data source, "
+                               "Don't use ffmpegextractor", container);
+               return false;
        }
 
-       ALOGD("ffmpeg detected media content as '%s' with confidence %.2f",
-                       container, *confidence);
+       mimeType->setTo(container);
 
        *meta = new AMessage;
        (*meta)->setString("extended-extractor", "extended-extractor");
@@ -1871,6 +2015,7 @@ MediaExtractor *CreateFFmpegExtractor(const sp<DataSource> &source, const char *
     if (meta.get() && meta->findString("extended-extractor", &notuse) && (
             !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG4)     ||
             !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)          ||
+            !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AC3)           ||
             !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MOV)       ||
             !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MATROSKA)  ||
             !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_TS)        ||
@@ -1889,6 +2034,8 @@ MediaExtractor *CreateFFmpegExtractor(const sp<DataSource> &source, const char *
             !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_DTS)       ||
             !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MP2)       ||
             !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_RA)        ||
+            !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_OGG)       ||
+            !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_HEVC)      ||
             !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WMA))) {
         ret = new FFmpegExtractor(source);
     }