OSDN Git Service

add HEVC(H.265) decoder. plz sync:
[android-x86/external-stagefright-plugins.git] / libstagefright / FFmpegExtractor / FFmpegExtractor.cpp
index d7d9fde..08fa7a2 100644 (file)
@@ -67,6 +67,8 @@ static AVPacket flush_pkt;
 
 namespace android {
 
+static const char *findMatchingContainer(const char *name);
+
 struct FFmpegExtractor::Track : public MediaSource {
     Track(FFmpegExtractor *extractor, sp<MetaData> meta, bool isAVC,
           AVStream *stream, PacketQueue *queue);
@@ -107,6 +109,7 @@ private:
 
 FFmpegExtractor::FFmpegExtractor(const sp<DataSource> &source)
     : mDataSource(source),
+      mMeta(new MetaData),
       mInitCheck(NO_INIT),
       mFFmpegInited(false),
       mFormatCtx(NULL),
@@ -185,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 {
@@ -376,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;
@@ -389,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",
@@ -414,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";
     }
 
@@ -457,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;
@@ -473,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);
@@ -523,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:
@@ -532,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;
         }
 
@@ -559,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
@@ -595,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);
             {
@@ -605,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);
@@ -621,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;
         }
 
@@ -664,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
@@ -701,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;
@@ -755,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
@@ -951,16 +1021,6 @@ 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
@@ -1041,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();
 
@@ -1067,7 +1128,7 @@ int FFmpegExtractor::initStreams()
     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;
     }
@@ -1086,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;
     }
@@ -1094,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
 
@@ -1494,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)) {
@@ -1540,14 +1605,22 @@ retry:
     }
 
     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 {
@@ -1556,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;
@@ -1619,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 DEBUG_PKT
-    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 (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);
@@ -1651,14 +1731,15 @@ static formatmap FILE_FORMATS[] = {
         {"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     },
         {"ac3",                     MEDIA_MIMETYPE_AUDIO_AC3          },
-#if 0
         {"wav",                     MEDIA_MIMETYPE_CONTAINER_WAV      },
-#endif
+        {"ogg",                     MEDIA_MIMETYPE_CONTAINER_OGG      },
+        {"hevc",                     MEDIA_MIMETYPE_CONTAINER_HEVC    },
 };
 
 static void adjustMPEG4Confidence(AVFormatContext *ic, float *confidence)
@@ -1698,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;
        }
@@ -1717,19 +1805,29 @@ 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,
@@ -1746,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) {
@@ -1768,29 +1891,28 @@ static const char *SniffFFMPEGCommon(const char *url, float *confidence)
 
        err = avformat_open_input(&ic, url, NULL, NULL);
        if (err < 0) {
-               ALOGE("avformat_open_input faild, url: %s err: %d", url, err);
+        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);
@@ -1912,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);
     }