2 * Copyright 2012 Michael Chen <omxcodec@gmail.com>
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 #define LOG_TAG "FFmpegExtractor"
19 #include <utils/Log.h>
21 #include <limits.h> /* INT_MAX */
23 #include <media/stagefright/foundation/ABitReader.h>
24 #include <media/stagefright/foundation/ABuffer.h>
25 #include <media/stagefright/foundation/ADebug.h>
26 #include <media/stagefright/foundation/AMessage.h>
27 #include <media/stagefright/foundation/hexdump.h>
28 #include <media/stagefright/DataSource.h>
29 #include <media/stagefright/MediaBuffer.h>
30 #include <media/stagefright/MediaDebug.h>
31 #include <media/stagefright/MediaDefs.h>
32 #include <media/stagefright/MediaErrors.h>
33 #include <media/stagefright/MediaSource.h>
34 #include <media/stagefright/MetaData.h>
35 #include <media/stagefright/Utils.h>
36 #include <utils/String8.h>
37 #include <utils/misc.h>
39 #include "include/avc_utils.h"
40 #include "utils/common_utils.h"
41 #include "utils/ffmpeg_utils.h"
42 #include "FFmpegExtractor.h"
44 #define DEBUG_READ_ENTRY 0
45 #define DIABLE_VIDEO 0
46 #define DIABLE_AUDIO 0
47 #define WAIT_KEY_PACKET_AFTER_SEEK 1
48 #define DISABLE_NAL_TO_ANNEXB 0
50 #define MAX_QUEUE_SIZE (15 * 1024 * 1024)
51 #define MIN_AUDIOQ_SIZE (20 * 16 * 1024)
53 #define EXTRACTOR_MAX_PROBE_PACKETS 200
55 #define FF_MAX_EXTRADATA_SIZE ((1 << 28) - FF_INPUT_BUFFER_PADDING_SIZE)
62 static AVPacket flush_pkt;
66 struct FFmpegExtractor::Track : public MediaSource {
67 Track(const sp<FFmpegExtractor> &extractor, sp<MetaData> meta, bool isAVC,
68 AVStream *stream, PacketQueue *queue);
70 virtual status_t start(MetaData *params);
71 virtual status_t stop();
72 virtual sp<MetaData> getFormat();
74 virtual status_t read(
75 MediaBuffer **buffer, const ReadOptions *options);
81 friend struct FFmpegExtractor;
83 sp<FFmpegExtractor> mExtractor;
86 enum AVMediaType mMediaType;
91 size_t mNALLengthSize;
97 DISALLOW_EVIL_CONSTRUCTORS(Track);
100 ////////////////////////////////////////////////////////////////////////////////
102 FFmpegExtractor::FFmpegExtractor(const sp<DataSource> &source)
103 : mDataSource(source),
104 mReaderThreadStarted(false),
105 mInitCheck(NO_INIT) {
106 LOGV("FFmpegExtractor::FFmpegExtractor");
109 const char *url = mDataSource->getNamURI();
111 LOGI("url is error!");
115 if (!strcmp(url, "-")) {
116 av_strlcpy(mFilename, "pipe:", strlen("pipe:") + 1);
118 av_strlcpy(mFilename, url, strlen(url) + 1);
120 LOGI("url: %s, mFilename: %s", url, mFilename);
124 LOGE("failed to init ffmpeg");
128 // start reader here, as we want to extract extradata from bitstream if no extradata
131 while(mProbePkts <= EXTRACTOR_MAX_PROBE_PACKETS && !mEOF &&
132 (mFormatCtx->pb ? !mFormatCtx->pb->error : 1) &&
133 (mDefersToCreateVideoTrack || mDefersToCreateAudioTrack)) {
134 // FIXME, i am so lazy! Should use pthread_cond_wait to wait conditions
138 LOGV("mProbePkts: %d, mEOF: %d, pb->error(if has): %d, mDefersToCreateVideoTrack: %d, mDefersToCreateAudioTrack: %d",
139 mProbePkts, mEOF, mFormatCtx->pb ? mFormatCtx->pb->error : 0, mDefersToCreateVideoTrack, mDefersToCreateAudioTrack);
144 FFmpegExtractor::~FFmpegExtractor() {
145 LOGV("FFmpegExtractor::~FFmpegExtractor");
147 // stop reader here if no track!
153 size_t FFmpegExtractor::countTracks() {
154 return mInitCheck == OK ? mTracks.size() : 0;
157 sp<MediaSource> FFmpegExtractor::getTrack(size_t index) {
158 LOGV("FFmpegExtractor::getTrack[%d]", index);
160 if (mInitCheck != OK) {
164 if (index >= mTracks.size()) {
168 return mTracks.valueAt(index);
171 sp<MetaData> FFmpegExtractor::getTrackMetaData(size_t index, uint32_t flags) {
172 LOGV("FFmpegExtractor::getTrackMetaData[%d]", index);
174 if (mInitCheck != OK) {
178 if (index >= mTracks.size()) {
182 return mTracks.valueAt(index)->getFormat();
185 sp<MetaData> FFmpegExtractor::getMetaData() {
186 LOGV("FFmpegExtractor::getMetaData");
188 if (mInitCheck != OK) {
192 sp<MetaData> meta = new MetaData;
194 meta->setCString(kKeyMIMEType, "video/ffmpeg");
199 uint32_t FFmpegExtractor::flags() const {
200 LOGV("FFmpegExtractor::flags");
202 if (mInitCheck != OK) {
206 uint32_t flags = CAN_PAUSE;
208 if (mFormatCtx->duration != AV_NOPTS_VALUE) {
209 flags |= CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK;
215 void FFmpegExtractor::packet_queue_init(PacketQueue *q)
217 memset(q, 0, sizeof(PacketQueue));
218 pthread_mutex_init(&q->mutex, NULL);
219 pthread_cond_init(&q->cond, NULL);
220 packet_queue_put(q, &flush_pkt);
223 void FFmpegExtractor::packet_queue_flush(PacketQueue *q)
225 AVPacketList *pkt, *pkt1;
227 pthread_mutex_lock(&q->mutex);
228 for (pkt = q->first_pkt; pkt != NULL; pkt = pkt1) {
230 av_free_packet(&pkt->pkt);
237 pthread_mutex_unlock(&q->mutex);
240 void FFmpegExtractor::packet_queue_end(PacketQueue *q)
242 packet_queue_flush(q);
245 void FFmpegExtractor::packet_queue_abort(PacketQueue *q)
247 pthread_mutex_lock(&q->mutex);
249 q->abort_request = 1;
251 pthread_cond_signal(&q->cond);
253 pthread_mutex_unlock(&q->mutex);
256 int FFmpegExtractor::packet_queue_put(PacketQueue *q, AVPacket *pkt)
260 /* duplicate the packet */
261 if (pkt != &flush_pkt && av_dup_packet(pkt) < 0)
264 pkt1 = (AVPacketList *)av_malloc(sizeof(AVPacketList));
270 pthread_mutex_lock(&q->mutex);
276 q->last_pkt->next = pkt1;
279 //q->size += pkt1->pkt.size + sizeof(*pkt1);
280 q->size += pkt1->pkt.size;
281 pthread_cond_signal(&q->cond);
283 pthread_mutex_unlock(&q->mutex);
287 /* packet queue handling */
288 /* return < 0 if aborted, 0 if no packet and > 0 if packet. */
289 int FFmpegExtractor::packet_queue_get(PacketQueue *q, AVPacket *pkt, int block)
294 pthread_mutex_lock(&q->mutex);
297 if (q->abort_request) {
304 q->first_pkt = pkt1->next;
308 //q->size -= pkt1->pkt.size + sizeof(*pkt1);
309 q->size -= pkt1->pkt.size;
318 pthread_cond_wait(&q->cond, &q->mutex);
321 pthread_mutex_unlock(&q->mutex);
325 static void EncodeSize14(uint8_t **_ptr, size_t size) {
326 CHECK_LE(size, 0x3fff);
328 uint8_t *ptr = *_ptr;
330 *ptr++ = 0x80 | (size >> 7);
331 *ptr++ = size & 0x7f;
336 static sp<ABuffer> MakeMPEGVideoESDS(const sp<ABuffer> &csd) {
337 sp<ABuffer> esds = new ABuffer(csd->size() + 25);
339 uint8_t *ptr = esds->data();
341 EncodeSize14(&ptr, 22 + csd->size());
343 *ptr++ = 0x00; // ES_ID
346 *ptr++ = 0x00; // streamDependenceFlag, URL_Flag, OCRstreamFlag
349 EncodeSize14(&ptr, 16 + csd->size());
351 *ptr++ = 0x40; // Audio ISO/IEC 14496-3
353 for (size_t i = 0; i < 12; ++i) {
358 EncodeSize14(&ptr, csd->size());
360 memcpy(ptr, csd->data(), csd->size());
365 // the same as MakeMPEGVideoESDS
366 static sp<ABuffer> MakeRawCodecSpecificData(const sp<ABuffer> &csd) {
367 sp<ABuffer> esds = new ABuffer(csd->size() + 25);
369 uint8_t *ptr = esds->data();
371 EncodeSize14(&ptr, 22 + csd->size());
373 *ptr++ = 0x00; // ES_ID
376 *ptr++ = 0x00; // streamDependenceFlag, URL_Flag, OCRstreamFlag
379 EncodeSize14(&ptr, 16 + csd->size());
381 *ptr++ = 0x40; // Audio ISO/IEC 14496-3
383 for (size_t i = 0; i < 12; ++i) {
388 EncodeSize14(&ptr, csd->size());
390 memcpy(ptr, csd->data(), csd->size());
395 // Returns the sample rate based on the sampling frequency index
396 static uint32_t get_sample_rate(const uint8_t sf_index)
398 static const uint32_t sample_rates[] =
400 96000, 88200, 64000, 48000, 44100, 32000,
401 24000, 22050, 16000, 12000, 11025, 8000
404 if (sf_index < sizeof(sample_rates) / sizeof(sample_rates[0])) {
405 return sample_rates[sf_index];
411 int FFmpegExtractor::check_extradata(AVCodecContext *avctx)
414 bool *defersToCreateTrack;
415 AVBitStreamFilterContext **bsfc;
418 if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) {
420 defersToCreateTrack = &mDefersToCreateVideoTrack;
421 } else if (avctx->codec_type == AVMEDIA_TYPE_AUDIO){
423 defersToCreateTrack = &mDefersToCreateAudioTrack;
427 if (avctx->codec_id == CODEC_ID_MP3 ||
428 avctx->codec_id == CODEC_ID_MP1 ||
429 avctx->codec_id == CODEC_ID_MP2 ||
430 avctx->codec_id == CODEC_ID_AC3 ||
431 avctx->codec_id == CODEC_ID_H263 ||
432 avctx->codec_id == CODEC_ID_H263P ||
433 avctx->codec_id == CODEC_ID_H263I ||
434 avctx->codec_id == CODEC_ID_WMV1)
437 // is extradata compatible with android?
438 if (avctx->codec_id != CODEC_ID_AAC) {
439 int is_compatible = is_extradata_compatible_with_android(avctx);
440 if (!is_compatible) {
441 LOGI("%s extradata is not compatible with android, should to extract it from bitstream",
442 av_get_media_type_string(avctx->codec_type));
443 *defersToCreateTrack = true;
444 *bsfc = NULL; // H264 don't need bsfc, only AAC?
450 if (avctx->codec_id == CODEC_ID_AAC) {
451 name = "aac_adtstoasc";
454 if (avctx->extradata_size <= 0) {
455 LOGI("No %s extradata found, should to extract it from bitstream",
456 av_get_media_type_string(avctx->codec_type));
457 *defersToCreateTrack = true;
458 //CHECK(name != NULL);
459 if (!*bsfc && name) {
460 *bsfc = av_bitstream_filter_init(name);
462 LOGE("Cannot open the %s BSF!", name);
463 *defersToCreateTrack = false;
466 LOGV("open the %s bsf", name);
477 int FFmpegExtractor::stream_component_open(int stream_index)
479 AVCodecContext *avctx;
482 bool supported = false;
488 LOGI("stream_index: %d", stream_index);
489 if (stream_index < 0 || stream_index >= mFormatCtx->nb_streams)
491 avctx = mFormatCtx->streams[stream_index]->codec;
493 switch(avctx->codec_id) {
504 case CODEC_ID_MPEG2VIDEO:
519 LOGE("unsupport the codec, id: 0x%0x", avctx->codec_id);
522 LOGV("support the codec");
525 ssize_t index = mTracks.indexOfKey(stream_index);
528 LOGE("this track already exists");
532 mFormatCtx->streams[stream_index]->discard = AVDISCARD_DEFAULT;
535 av_get_codec_tag_string(tagbuf, sizeof(tagbuf), avctx->codec_tag);
536 LOGV("Tag %s/0x%08x with codec id '%d'\n", tagbuf, avctx->codec_tag, avctx->codec_id);
538 switch (avctx->codec_type) {
539 case AVMEDIA_TYPE_VIDEO:
540 if (mVideoStreamIdx == -1)
541 mVideoStreamIdx = stream_index;
542 if (mVideoStream == NULL)
543 mVideoStream = mFormatCtx->streams[stream_index];
544 if (!mVideoQInited) {
545 packet_queue_init(&mVideoQ);
546 mVideoQInited = true;
549 ret = check_extradata(avctx);
552 // disable the stream
553 mVideoStreamIdx = -1;
555 packet_queue_end(&mVideoQ);
556 mVideoQInited = false;
557 mFormatCtx->streams[stream_index]->discard = AVDISCARD_ALL;
562 if (avctx->extradata) {
563 LOGV("video stream extradata:");
564 hexdump(avctx->extradata, avctx->extradata_size);
566 LOGV("video stream no extradata, but we can ignore it.");
571 switch(avctx->codec_id) {
575 * http://msdn.microsoft.com/en-us/library/dd757808(v=vs.85).aspx
577 //if (avctx->codec_tag && avctx->codec_tag == AV_RL32("avc1")) {
578 if (avctx->extradata[0] == 1 /* configurationVersion */) {
579 // H.264 bitstream without start codes.
583 if (avctx->width == 0 || avctx->height == 0) {
584 int32_t width, height;
585 sp<ABuffer> seqParamSet = new ABuffer(avctx->extradata_size - 8);
586 memcpy(seqParamSet->data(), avctx->extradata + 8, avctx->extradata_size - 8);
587 FindAVCDimensions(seqParamSet, &width, &height);
588 avctx->width = width;
589 avctx->height = height;
592 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
593 meta->setData(kKeyAVCC, kTypeAVCC, avctx->extradata, avctx->extradata_size);
595 // H.264 bitstream with start codes.
599 /* set NULL to release meta as we will new a meta in MakeAVCCodecSpecificData() fxn */
603 sp<ABuffer> buffer = new ABuffer(avctx->extradata_size);
604 memcpy(buffer->data(), avctx->extradata, avctx->extradata_size);
605 meta = MakeAVCCodecSpecificData(buffer);
610 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
612 sp<ABuffer> csd = new ABuffer(avctx->extradata_size);
613 memcpy(csd->data(), avctx->extradata, avctx->extradata_size);
614 sp<ABuffer> esds = MakeMPEGVideoESDS(csd);
615 meta->setData(kKeyESDS, kTypeESDS, esds->data(), esds->size());
622 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263);
624 case CODEC_ID_MPEG2VIDEO:
626 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG2);
628 sp<ABuffer> csd = new ABuffer(avctx->extradata_size);
629 memcpy(csd->data(), avctx->extradata, avctx->extradata_size);
630 sp<ABuffer> esds = MakeMPEGVideoESDS(csd);
631 meta->setData(kKeyESDS, kTypeESDS, esds->data(), esds->size());
636 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_WMV12);
637 meta->setData(kKeyESDS, kTypeESDS, avctx->extradata, avctx->extradata_size);
641 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_WMV12);
645 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_WMV12);
647 sp<ABuffer> csd = new ABuffer(avctx->extradata_size);
648 memcpy(csd->data(), avctx->extradata, avctx->extradata_size);
649 sp<ABuffer> esds = MakeRawCodecSpecificData(csd);
650 meta->setData(kKeyESDS, kTypeESDS, esds->data(), esds->size());
654 CHECK(!"Should not be here. Unsupported codec.");
658 LOGI("width: %d, height: %d, bit_rate: %d", avctx->width, avctx->height, avctx->bit_rate);
660 meta->setInt32(kKeyWidth, avctx->width);
661 meta->setInt32(kKeyHeight, avctx->height);
662 if (avctx->bit_rate > 0)
663 meta->setInt32(kKeyBitRate, avctx->bit_rate);
664 if (mFormatCtx->duration != AV_NOPTS_VALUE)
665 meta->setInt64(kKeyDuration, mFormatCtx->duration);
667 LOGV("create a video track");
669 stream_index, new Track(this, meta, isAVC, mVideoStream, &mVideoQ));
671 mDefersToCreateVideoTrack = false;
674 case AVMEDIA_TYPE_AUDIO:
675 if (mAudioStreamIdx == -1)
676 mAudioStreamIdx = stream_index;
677 if (mAudioStream == NULL)
678 mAudioStream = mFormatCtx->streams[stream_index];
679 if (!mAudioQInited) {
680 packet_queue_init(&mAudioQ);
681 mAudioQInited = true;
684 ret = check_extradata(avctx);
687 // disable the stream
688 mAudioStreamIdx = -1;
690 packet_queue_end(&mAudioQ);
691 mAudioQInited = false;
692 mFormatCtx->streams[stream_index]->discard = AVDISCARD_ALL;
697 if (avctx->extradata) {
698 LOGV("audio stream extradata:");
699 hexdump(avctx->extradata, avctx->extradata_size);
701 LOGV("audio stream no extradata, but we can ignore it.");
704 switch(avctx->codec_id) {
708 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I);
713 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II);
718 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
723 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AC3);
728 const uint8_t *header;
729 uint8_t profile, sf_index, channel;
731 header = avctx->extradata;
732 CHECK(header != NULL);
734 // AudioSpecificInfo follows
735 // oooo offf fccc c000
736 // o - audioObjectType
737 // f - samplingFreqIndex
739 profile = ((header[0] & 0xf8) >> 3) - 1;
740 sf_index = (header[0] & 0x07) << 1 | (header[1] & 0x80) >> 7;
741 sr = get_sample_rate(sf_index);
743 LOGE("unsupport the sample rate");
746 channel = (header[1] >> 3) & 0xf;
747 LOGV("profile: %d, sf_index: %d, channel: %d", profile, sf_index, channel);
749 meta = MakeAACCodecSpecificData(profile, sf_index, channel);
750 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
755 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_WMA);
757 sp<ABuffer> csd = new ABuffer(avctx->extradata_size);
758 memcpy(csd->data(), avctx->extradata, avctx->extradata_size);
759 sp<ABuffer> esds = MakeRawCodecSpecificData(csd);
760 meta->setData(kKeyESDS, kTypeESDS, esds->data(), esds->size());
764 CHECK(!"Should not be here. Unsupported codec.");
768 LOGI("bit_rate: %d, sample_rate: %d, channels: %d", avctx->bit_rate, avctx->sample_rate, avctx->channels);
770 meta->setInt32(kKeySampleRate, avctx->sample_rate);
771 meta->setInt32(kKeyChannelCount, avctx->channels);
772 meta->setInt32(kKeyBitRate, avctx->bit_rate);
773 if (mFormatCtx->duration != AV_NOPTS_VALUE)
774 meta->setInt64(kKeyDuration, mFormatCtx->duration);
776 if (avctx->codec_id != CODEC_ID_MP3 &&
777 avctx->codec_id != CODEC_ID_MP1 &&
778 avctx->codec_id != CODEC_ID_MP2 &&
779 avctx->codec_id != CODEC_ID_AC3) {
780 LOGV("audio meta esds:");
781 CHECK(meta->findData(kKeyESDS, &type, &data, &size));
785 LOGV("create a audio track");
787 stream_index, new Track(this, meta, false, mAudioStream, &mAudioQ));
789 mDefersToCreateAudioTrack = false;
792 case AVMEDIA_TYPE_SUBTITLE:
794 CHECK(!"Should not be here. Unsupported media type.");
797 CHECK(!"Should not be here. Unsupported media type.");
803 void FFmpegExtractor::stream_component_close(int stream_index)
805 AVCodecContext *avctx;
807 if (stream_index < 0 || stream_index >= mFormatCtx->nb_streams)
809 avctx = mFormatCtx->streams[stream_index]->codec;
811 switch (avctx->codec_type) {
812 case AVMEDIA_TYPE_VIDEO:
813 LOGV("packet_queue_abort videoq");
814 packet_queue_abort(&mVideoQ);
815 /* wait until the end */
816 while (!mAbortRequest && !mVideoEOSReceived) {
817 LOGV("wait for video received");
820 LOGV("packet_queue_end videoq");
821 packet_queue_end(&mVideoQ);
823 case AVMEDIA_TYPE_AUDIO:
824 LOGV("packet_queue_abort audioq");
825 packet_queue_abort(&mAudioQ);
826 while (!mAbortRequest && !mAudioEOSReceived) {
827 LOGV("wait for audio received");
830 LOGV("packet_queue_end audioq");
831 packet_queue_end(&mAudioQ);
833 case AVMEDIA_TYPE_SUBTITLE:
839 mFormatCtx->streams[stream_index]->discard = AVDISCARD_ALL;
840 switch (avctx->codec_type) {
841 case AVMEDIA_TYPE_VIDEO:
843 mVideoStreamIdx = -1;
845 av_bitstream_filter_close(mVideoBsfc);
849 case AVMEDIA_TYPE_AUDIO:
851 mAudioStreamIdx = -1;
853 av_bitstream_filter_close(mAudioBsfc);
857 case AVMEDIA_TYPE_SUBTITLE:
864 void FFmpegExtractor::reachedEOS(enum AVMediaType media_type)
866 Mutex::Autolock autoLock(mLock);
868 if (media_type == AVMEDIA_TYPE_VIDEO) {
869 mVideoEOSReceived = true;
870 } else if (media_type == AVMEDIA_TYPE_AUDIO) {
871 mAudioEOSReceived = true;
875 /* seek in the stream */
876 int FFmpegExtractor::stream_seek(int64_t pos, enum AVMediaType media_type)
878 Mutex::Autolock autoLock(mLock);
880 if (mVideoStreamIdx >= 0 &&
881 mAudioStreamIdx >= 0 &&
882 media_type == AVMEDIA_TYPE_AUDIO &&
883 !mVideoEOSReceived) {
888 if (mAudioStreamIdx >= 0)
889 packet_queue_flush(&mAudioQ);
890 if (mVideoStreamIdx >= 0)
891 packet_queue_flush(&mVideoQ);
894 mSeekFlags &= ~AVSEEK_FLAG_BYTE;
901 int FFmpegExtractor::decode_interrupt_cb(void *ctx)
903 FFmpegExtractor *extrator = static_cast<FFmpegExtractor *>(ctx);
904 return extrator->mAbortRequest;
907 void FFmpegExtractor::print_error_ex(const char *filename, int err)
910 const char *errbuf_ptr = errbuf;
912 if (av_strerror(err, errbuf, sizeof(errbuf)) < 0)
913 errbuf_ptr = strerror(AVUNERROR(err));
914 LOGI("%s: %s\n", filename, errbuf_ptr);
917 void FFmpegExtractor::setFFmpegDefaultOpts()
931 mSeekByBytes = 0; /* seek by bytes 0=off 1=on -1=auto" */
932 mStartTime = AV_NOPTS_VALUE;
933 mDuration = AV_NOPTS_VALUE;
934 mSeekPos = AV_NOPTS_VALUE;
938 mVideoStreamIdx = -1;
939 mAudioStreamIdx = -1;
942 mVideoQInited = false;
943 mAudioQInited = false;
944 mDefersToCreateVideoTrack = false;
945 mDefersToCreateAudioTrack = false;
958 int FFmpegExtractor::initStreams()
963 int ret = 0, audio_ret = 0, video_ret = 0;
964 int pkt_in_play_range = 0;
965 AVDictionaryEntry *t;
968 int st_index[AVMEDIA_TYPE_NB] = {0};
969 int wanted_stream[AVMEDIA_TYPE_NB] = {0};
970 st_index[AVMEDIA_TYPE_AUDIO] = -1;
971 st_index[AVMEDIA_TYPE_VIDEO] = -1;
972 wanted_stream[AVMEDIA_TYPE_AUDIO] = -1;
973 wanted_stream[AVMEDIA_TYPE_VIDEO] = -1;
975 setFFmpegDefaultOpts();
977 status = initFFmpeg();
983 av_init_packet(&flush_pkt);
984 flush_pkt.data = (uint8_t *)"FLUSH";
987 mFormatCtx = avformat_alloc_context();
988 mFormatCtx->interrupt_callback.callback = decode_interrupt_cb;
989 mFormatCtx->interrupt_callback.opaque = this;
990 LOGV("mFilename: %s", mFilename);
991 err = avformat_open_input(&mFormatCtx, mFilename, NULL, &format_opts);
993 print_error_ex(mFilename, err);
997 if ((t = av_dict_get(format_opts, "", NULL, AV_DICT_IGNORE_SUFFIX))) {
998 LOGE("Option %s not found.\n", t->key);
999 //ret = AVERROR_OPTION_NOT_FOUND;
1005 mFormatCtx->flags |= AVFMT_FLAG_GENPTS;
1007 opts = setup_find_stream_info_opts(mFormatCtx, codec_opts);
1008 orig_nb_streams = mFormatCtx->nb_streams;
1010 err = avformat_find_stream_info(mFormatCtx, opts);
1012 LOGE("%s: could not find codec parameters\n", mFilename);
1016 for (i = 0; i < orig_nb_streams; i++)
1017 av_dict_free(&opts[i]);
1021 mFormatCtx->pb->eof_reached = 0; // FIXME hack, ffplay maybe should not use url_feof() to test for the end
1023 if (mSeekByBytes < 0)
1024 mSeekByBytes = !!(mFormatCtx->iformat->flags & AVFMT_TS_DISCONT);
1026 /* if seeking requested, we execute it */
1027 if (mStartTime != AV_NOPTS_VALUE) {
1030 timestamp = mStartTime;
1031 /* add the stream start time */
1032 if (mFormatCtx->start_time != AV_NOPTS_VALUE)
1033 timestamp += mFormatCtx->start_time;
1034 ret = avformat_seek_file(mFormatCtx, -1, INT64_MIN, timestamp, INT64_MAX, 0);
1036 LOGE("%s: could not seek to position %0.3f",
1037 mFilename, (double)timestamp / AV_TIME_BASE);
1042 for (i = 0; i < mFormatCtx->nb_streams; i++)
1043 mFormatCtx->streams[i]->discard = AVDISCARD_ALL;
1045 st_index[AVMEDIA_TYPE_VIDEO] =
1046 av_find_best_stream(mFormatCtx, AVMEDIA_TYPE_VIDEO,
1047 wanted_stream[AVMEDIA_TYPE_VIDEO], -1, NULL, 0);
1049 st_index[AVMEDIA_TYPE_AUDIO] =
1050 av_find_best_stream(mFormatCtx, AVMEDIA_TYPE_AUDIO,
1051 wanted_stream[AVMEDIA_TYPE_AUDIO],
1052 st_index[AVMEDIA_TYPE_VIDEO],
1055 av_dump_format(mFormatCtx, 0, mFilename, 0);
1058 if (mFormatCtx->duration != AV_NOPTS_VALUE) {
1059 int hours, mins, secs, us;
1060 secs = mFormatCtx->duration / AV_TIME_BASE;
1061 us = mFormatCtx->duration % AV_TIME_BASE;
1066 LOGI("the duration is %02d:%02d:%02d.%02d", hours, mins, secs, (100 * us) / AV_TIME_BASE);
1069 if (st_index[AVMEDIA_TYPE_AUDIO] >= 0) {
1070 audio_ret = stream_component_open(st_index[AVMEDIA_TYPE_AUDIO]);
1073 if (st_index[AVMEDIA_TYPE_VIDEO] >= 0) {
1074 video_ret = stream_component_open(st_index[AVMEDIA_TYPE_VIDEO]);
1077 if ( audio_ret < 0 && video_ret < 0) {
1078 LOGE("%s: could not open codecs\n", mFilename);
1089 void FFmpegExtractor::deInitStreams()
1092 avformat_close_input(&mFormatCtx);
1098 status_t FFmpegExtractor::startReaderThread() {
1099 LOGV("Starting reader thread");
1100 Mutex::Autolock autoLock(mLock);
1102 if (mReaderThreadStarted)
1105 pthread_attr_t attr;
1106 pthread_attr_init(&attr);
1107 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
1108 pthread_create(&mReaderThread, &attr, ReaderWrapper, this);
1109 pthread_attr_destroy(&attr);
1110 mReaderThreadStarted = true;
1111 LOGD("Reader thread started");
1116 void FFmpegExtractor::stopReaderThread() {
1117 LOGV("Stopping reader thread");
1118 Mutex::Autolock autoLock(mLock);
1120 if (!mReaderThreadStarted) {
1121 LOGD("Reader thread have been stopped");
1128 pthread_join(mReaderThread, &dummy);
1129 mReaderThreadStarted = false;
1130 LOGD("Reader thread stopped");
1134 void *FFmpegExtractor::ReaderWrapper(void *me) {
1135 ((FFmpegExtractor *)me)->readerEntry();
1140 void FFmpegExtractor::readerEntry() {
1142 AVPacket pkt1, *pkt = &pkt1;
1144 int pkt_in_play_range = 0;
1146 LOGV("FFmpegExtractor::readerEntry");
1148 mVideoEOSReceived = false;
1149 mAudioEOSReceived = false;
1155 if (mPaused != mLastPaused) {
1156 mLastPaused = mPaused;
1158 mReadPauseReturn = av_read_pause(mFormatCtx);
1160 av_read_play(mFormatCtx);
1162 #if CONFIG_RTSP_DEMUXER || CONFIG_MMSH_PROTOCOL
1164 (!strcmp(mFormatCtx->iformat->name, "rtsp") ||
1165 (mFormatCtx->pb && !strncmp(mFilename, "mmsh:", 5)))) {
1166 /* wait 10 ms to avoid trying to get another packet */
1174 LOGV("readerEntry, mSeekReq: %d", mSeekReq);
1175 ret = avformat_seek_file(mFormatCtx, -1, INT64_MIN, mSeekPos, INT64_MAX, mSeekFlags);
1177 LOGE("%s: error while seeking", mFormatCtx->filename);
1179 if (mAudioStreamIdx >= 0) {
1180 packet_queue_flush(&mAudioQ);
1181 packet_queue_put(&mAudioQ, &flush_pkt);
1183 if (mVideoStreamIdx >= 0) {
1184 packet_queue_flush(&mVideoQ);
1185 packet_queue_put(&mVideoQ, &flush_pkt);
1192 /* if the queue are full, no need to read more */
1193 if ( mAudioQ.size + mVideoQ.size > MAX_QUEUE_SIZE
1194 || ( (mAudioQ .size > MIN_AUDIOQ_SIZE || mAudioStreamIdx < 0)
1195 && (mVideoQ .nb_packets > MIN_FRAMES || mVideoStreamIdx < 0))) {
1196 #if DEBUG_READ_ENTRY
1197 LOGV("readerEntry, is full, fuck");
1205 if (mVideoStreamIdx >= 0) {
1206 av_init_packet(pkt);
1209 pkt->stream_index = mVideoStreamIdx;
1210 packet_queue_put(&mVideoQ, pkt);
1212 if (mAudioStreamIdx >= 0) {
1213 av_init_packet(pkt);
1216 pkt->stream_index = mAudioStreamIdx;
1217 packet_queue_put(&mAudioQ, pkt);
1220 #if DEBUG_READ_ENTRY
1221 LOGV("readerEntry, eof = 1, mVideoQ.size: %d, mVideoQ.nb_packets: %d, mAudioQ.size: %d, mAudioQ.nb_packets: %d",
1222 mVideoQ.size, mVideoQ.nb_packets, mAudioQ.size, mAudioQ.nb_packets);
1224 if (mAudioQ.size + mVideoQ.size == 0) {
1225 if (mLoop != 1 && (!mLoop || --mLoop)) {
1226 if (mVideoStreamIdx >= 0) {
1227 stream_seek(mStartTime != AV_NOPTS_VALUE ? mStartTime : 0, AVMEDIA_TYPE_VIDEO);
1228 } else if (mAudioStreamIdx >= 0) {
1229 stream_seek(mStartTime != AV_NOPTS_VALUE ? mStartTime : 0, AVMEDIA_TYPE_AUDIO);
1231 } else if (mAutoExit) {
1240 ret = av_read_frame(mFormatCtx, pkt);
1243 if (ret == AVERROR_EOF || url_feof(mFormatCtx->pb))
1244 if (ret == AVERROR_EOF) {
1245 //LOGV("ret == AVERROR_EOF");
1247 if (url_feof(mFormatCtx->pb)) {
1248 //LOGV("url_feof(mFormatCtx->pb)");
1253 if (mFormatCtx->pb && mFormatCtx->pb->error) {
1254 LOGE("mFormatCtx->pb->error: %d", mFormatCtx->pb->error);
1261 if (pkt->stream_index == mVideoStreamIdx) {
1262 if (mDefersToCreateVideoTrack) {
1263 AVCodecContext *avctx = mFormatCtx->streams[mVideoStreamIdx]->codec;
1265 int i = parser_split(avctx, pkt->data, pkt->size);
1266 if (i > 0 && i < FF_MAX_EXTRADATA_SIZE) {
1267 if (avctx->extradata)
1268 av_freep(&avctx->extradata);
1269 avctx->extradata_size= i;
1270 avctx->extradata = (uint8_t *)av_malloc(avctx->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
1271 if (!avctx->extradata) {
1272 //return AVERROR(ENOMEM);
1273 ret = AVERROR(ENOMEM);
1276 // sps + pps(there may be sei in it)
1277 memcpy(avctx->extradata, pkt->data, avctx->extradata_size);
1278 memset(avctx->extradata + i, 0, FF_INPUT_BUFFER_PADDING_SIZE);
1280 av_free_packet(pkt);
1284 stream_component_open(mVideoStreamIdx);
1285 if (!mDefersToCreateVideoTrack)
1286 LOGI("probe packet counter: %d when create video track ok", mProbePkts);
1287 if (mProbePkts == EXTRACTOR_MAX_PROBE_PACKETS)
1288 LOGI("probe packet counter to max: %d, create video track: %d",
1289 mProbePkts, !mDefersToCreateVideoTrack);
1291 } else if (pkt->stream_index == mAudioStreamIdx) {
1295 AVCodecContext *avctx = mFormatCtx->streams[mAudioStreamIdx]->codec;
1296 if (mAudioBsfc && pkt && pkt->data) {
1297 ret = av_bitstream_filter_filter(mAudioBsfc, avctx, NULL, &outbuf, &outbuf_size,
1298 pkt->data, pkt->size, pkt->flags & AV_PKT_FLAG_KEY);
1300 if (ret < 0 ||!outbuf_size) {
1301 av_free_packet(pkt);
1304 if (outbuf && outbuf != pkt->data) {
1305 memmove(pkt->data, outbuf, outbuf_size);
1306 pkt->size = outbuf_size;
1309 if (mDefersToCreateAudioTrack) {
1310 if (avctx->extradata_size <= 0) {
1311 av_free_packet(pkt);
1314 stream_component_open(mAudioStreamIdx);
1315 if (!mDefersToCreateAudioTrack)
1316 LOGI("probe packet counter: %d when create audio track ok", mProbePkts);
1317 if (mProbePkts == EXTRACTOR_MAX_PROBE_PACKETS)
1318 LOGI("probe packet counter to max: %d, create audio track: %d",
1319 mProbePkts, !mDefersToCreateAudioTrack);
1323 /* check if packet is in play range specified by user, then queue, otherwise discard */
1324 pkt_in_play_range = mDuration == AV_NOPTS_VALUE ||
1325 (pkt->pts - mFormatCtx->streams[pkt->stream_index]->start_time) *
1326 av_q2d(mFormatCtx->streams[pkt->stream_index]->time_base) -
1327 (double)(mStartTime != AV_NOPTS_VALUE ? mStartTime : 0) / 1000000
1328 <= ((double)mDuration / 1000000);
1329 if (pkt->stream_index == mAudioStreamIdx && pkt_in_play_range) {
1330 packet_queue_put(&mAudioQ, pkt);
1331 } else if (pkt->stream_index == mVideoStreamIdx && pkt_in_play_range) {
1332 packet_queue_put(&mVideoQ, pkt);
1334 av_free_packet(pkt);
1337 /* wait until the end */
1338 while (!mAbortRequest) {
1344 LOGI("reader thread goto end...");
1346 /* close each stream */
1347 if (mAudioStreamIdx >= 0)
1348 stream_component_close(mAudioStreamIdx);
1349 if (mVideoStreamIdx >= 0)
1350 stream_component_close(mVideoStreamIdx);
1352 avformat_close_input(&mFormatCtx);
1356 ////////////////////////////////////////////////////////////////////////////////
1358 FFmpegExtractor::Track::Track(
1359 const sp<FFmpegExtractor> &extractor, sp<MetaData> meta, bool isAVC,
1360 AVStream *stream, PacketQueue *queue)
1361 : mExtractor(extractor),
1368 /* H.264 Video Types */
1370 mNal2AnnexB = false;
1376 CHECK(meta->findData(kKeyAVCC, &type, &data, &size));
1378 const uint8_t *ptr = (const uint8_t *)data;
1381 CHECK_EQ((unsigned)ptr[0], 1u); // configurationVersion == 1
1383 // The number of bytes used to encode the length of a NAL unit.
1384 mNALLengthSize = 1 + (ptr[4] & 3);
1386 LOGV("the stream is AVC, the length of a NAL unit: %d", mNALLengthSize);
1392 mMediaType = mStream->codec->codec_type;
1395 FFmpegExtractor::Track::~Track() {
1398 status_t FFmpegExtractor::Track::start(MetaData *params) {
1399 Mutex::Autolock autoLock(mLock);
1400 //mExtractor->startReaderThread();
1404 status_t FFmpegExtractor::Track::stop() {
1405 Mutex::Autolock autoLock(mLock);
1406 mExtractor->stopReaderThread();
1410 sp<MetaData> FFmpegExtractor::Track::getFormat() {
1411 Mutex::Autolock autoLock(mLock);
1416 status_t FFmpegExtractor::Track::read(
1417 MediaBuffer **buffer, const ReadOptions *options) {
1420 Mutex::Autolock autoLock(mLock);
1423 bool seeking = false;
1424 bool waitKeyPkt = false;
1425 ReadOptions::SeekMode mode;
1426 int64_t pktTS = AV_NOPTS_VALUE;
1427 int64_t seekTimeUs = AV_NOPTS_VALUE;
1430 status_t status = OK;
1432 if (options && options->getSeekTo(&seekTimeUs, &mode)) {
1433 LOGV("~~~%s seekTimeUs: %lld, mode: %d", av_get_media_type_string(mMediaType), seekTimeUs, mode);
1434 if (mExtractor->stream_seek(seekTimeUs, mMediaType) == SEEK)
1439 if (mExtractor->packet_queue_get(mQueue, &pkt, 1) < 0) {
1440 mExtractor->reachedEOS(mMediaType);
1441 return ERROR_END_OF_STREAM;
1445 if (pkt.data != flush_pkt.data) {
1446 av_free_packet(&pkt);
1450 #if WAIT_KEY_PACKET_AFTER_SEEK
1456 if (pkt.data == flush_pkt.data) {
1457 LOGV("read %s flush pkt", av_get_media_type_string(mMediaType));
1458 av_free_packet(&pkt);
1460 } else if (pkt.data == NULL && pkt.size == 0) {
1461 LOGV("read %s eos pkt", av_get_media_type_string(mMediaType));
1462 av_free_packet(&pkt);
1463 mExtractor->reachedEOS(mMediaType);
1464 return ERROR_END_OF_STREAM;
1467 key = pkt.flags & AV_PKT_FLAG_KEY ? 1 : 0;
1471 LOGV("drop the no key packet");
1472 av_free_packet(&pkt);
1475 LOGV("~~~~~~ got the key packet");
1480 MediaBuffer *mediaBuffer = new MediaBuffer(pkt.size + FF_INPUT_BUFFER_PADDING_SIZE);
1481 mediaBuffer->meta_data()->clear();
1482 mediaBuffer->set_range(0, pkt.size);
1483 #if DISABLE_NAL_TO_ANNEXB
1484 mNal2AnnexB = false;
1486 if (mIsAVC && mNal2AnnexB) {
1487 /* Convert H.264 NAL format to annex b */
1488 if (mNALLengthSize >= 3 && mNALLengthSize <= 4 )
1490 uint8_t *dst = (uint8_t *)mediaBuffer->data();
1492 /* This only works for NAL sizes 3-4 */
1493 size_t len = pkt.size, i;
1494 uint8_t *ptr = pkt.data;
1495 while (len >= mNALLengthSize) {
1496 uint32_t nal_len = 0;
1497 for( i = 0; i < mNALLengthSize; i++ ) {
1498 nal_len = (nal_len << 8) | ptr[i];
1501 dst[mNALLengthSize - 1] = 1;
1502 if (nal_len > INT_MAX || nal_len > (unsigned int)len) {
1503 status = ERROR_MALFORMED;
1506 dst += mNALLengthSize;
1507 ptr += mNALLengthSize;
1508 len -= mNALLengthSize;
1510 memcpy(dst, ptr, nal_len);
1517 status = ERROR_MALFORMED;
1521 LOGV("status != OK");
1522 mediaBuffer->release();
1524 av_free_packet(&pkt);
1525 return ERROR_MALFORMED;
1528 memcpy(mediaBuffer->data(), pkt.data, pkt.size);
1533 if (pkt.pts == AV_NOPTS_VALUE)
1537 // TODO, Stagefright can't handle negative timestamps
1538 // if needed, work around this by offsetting them manually?
1543 timeUs = (int64_t)(pktTS * av_q2d(mStream->time_base) * 1000000);
1546 LOGV("read %s pkt, size: %d, key: %d, pts: %lld, dts: %lld, timeUs: %llu us (%.2f secs)",
1547 av_get_media_type_string(mMediaType), pkt.size, key, pkt.pts, pkt.dts, timeUs, timeUs/1E6);
1551 // TODO, Stagefright can't handle negative timestamps
1552 // if needed, work around this by offsetting them manually?
1557 mediaBuffer->meta_data()->setInt64(kKeyTime, timeUs);
1558 mediaBuffer->meta_data()->setInt32(kKeyIsSyncFrame, key);
1560 *buffer = mediaBuffer;
1562 av_free_packet(&pkt);
1567 ////////////////////////////////////////////////////////////////////////////////
1569 // LegacySniffFFMPEG
1571 const char *extension;
1572 const char *container;
1575 static extmap FILE_EXTS[] = {
1576 {".mp4", MEDIA_MIMETYPE_CONTAINER_MPEG4},
1577 {".3gp", MEDIA_MIMETYPE_CONTAINER_MPEG4},
1578 {".mp3", MEDIA_MIMETYPE_AUDIO_MPEG},
1579 {".mov", MEDIA_MIMETYPE_CONTAINER_MOV},
1580 {".mkv", MEDIA_MIMETYPE_CONTAINER_MATROSKA},
1581 {".ts", MEDIA_MIMETYPE_CONTAINER_TS},
1582 {".avi", MEDIA_MIMETYPE_CONTAINER_AVI},
1583 {".asf", MEDIA_MIMETYPE_CONTAINER_ASF},
1585 {".wmv", MEDIA_MIMETYPE_CONTAINER_WMV},
1586 {".wma", MEDIA_MIMETYPE_CONTAINER_WMA},
1587 {".mpg", MEDIA_MIMETYPE_CONTAINER_MPG},
1588 {".flv", MEDIA_MIMETYPE_CONTAINER_FLV},
1589 {".divx", MEDIA_MIMETYPE_CONTAINER_DIVX},
1590 {".mp2", MEDIA_MIMETYPE_CONTAINER_MP2},
1591 {".ape", MEDIA_MIMETYPE_CONTAINER_APE},
1592 {".rm ", MEDIA_MIMETYPE_CONTAINER_RM},
1593 {".ra", MEDIA_MIMETYPE_CONTAINER_RA},
1597 const char *LegacySniffFFMPEG(const char * uri)
1600 const char *container = NULL;
1602 LOGI("list the file extensions suppoted by ffmpeg: ");
1603 LOGI("========================================");
1604 for (i = 0; i < NELEM(FILE_EXTS); ++i) {
1605 LOGV("file_exts[%02d]: %s", i, FILE_EXTS[i].extension);
1607 LOGI("========================================");
1609 int lenURI = strlen(uri);
1610 for (i = 0; i < NELEM(FILE_EXTS); ++i) {
1611 int len = strlen(FILE_EXTS[i].extension);
1612 int start = lenURI - len;
1614 if (!av_strncasecmp(uri + start, FILE_EXTS[i].extension, len)) {
1615 container = FILE_EXTS[i].container;
1624 // BetterSniffFFMPEG
1627 const char *container;
1630 static formatmap FILE_FORMATS[] = {
1631 {"mpegts", MEDIA_MIMETYPE_CONTAINER_TS},
1632 {"mov,mp4,m4a,3gp,3g2,mj2", MEDIA_MIMETYPE_CONTAINER_MOV},
1633 {"asf", MEDIA_MIMETYPE_CONTAINER_ASF},
1636 const char *BetterSniffFFMPEG(const char * uri)
1639 const char *container = NULL;
1640 AVFormatContext *ic = NULL;
1642 status_t status = initFFmpeg();
1644 LOGE("could not init ffmpeg");
1648 ic = avformat_alloc_context();
1649 avformat_open_input(&ic, uri, NULL, NULL);
1651 av_dump_format(ic, 0, uri, 0);
1653 LOGI("FFmpegExtrator, uri: %s, format_name: %s, format_long_name: %s", uri, ic->iformat->name, ic->iformat->long_name);
1655 LOGI("list the format suppoted by ffmpeg: ");
1656 LOGI("========================================");
1657 for (i = 0; i < NELEM(FILE_FORMATS); ++i) {
1658 LOGV("format_names[%02d]: %s", i, FILE_FORMATS[i].format);
1660 LOGI("========================================");
1662 for (i = 0; i < NELEM(FILE_FORMATS); ++i) {
1663 int len = strlen(FILE_FORMATS[i].format);
1664 if (!av_strncasecmp(ic->iformat->name, FILE_FORMATS[i].format, len)) {
1665 container = FILE_FORMATS[i].container;
1670 avformat_close_input(&ic);
1677 const sp<DataSource> &source, String8 *mimeType, float *confidence,
1678 sp<AMessage> *meta) {
1679 LOGV("SniffFFMPEG");
1680 const char *uri, *container = NULL;
1682 uri = source->getNamURI();
1687 LOGI("ffmpeg uri: %s", uri);
1689 container = BetterSniffFFMPEG(uri);
1691 LOGW("sniff through LegacySniffFFMPEG, only check the file extension");
1692 container = LegacySniffFFMPEG(uri);
1695 if (container == NULL)
1698 LOGV("found container: %s", container);
1700 *confidence = 0.88f; // Slightly larger than other extractor's confidence
1701 mimeType->setTo(container);
1703 /* use MPEG4Extractor(not extended extractor) for HTTP source only */
1704 if (!av_strcasecmp(container, MEDIA_MIMETYPE_CONTAINER_MPEG4)
1705 && (source->flags() & DataSource::kIsCachingDataSource)) {
1709 *meta = new AMessage;
1710 (*meta)->setString("extended-extractor", "extended-extractor");
1711 (*meta)->setString("extended-extractor-subtype", "ffmpegextractor");
1716 } // namespace android