+static const char *LegacySniffFFMPEG(const sp<DataSource> &source, float *confidence)
+{
+ String8 uri = source->getUri();
+ if (uri.empty()) {
+ return NULL;
+ }
+
+ ALOGI("source url:%s", uri.string());
+
+ return SniffFFMPEGCommon(uri.string(), confidence);
+}
+
+static const char *BetterSniffFFMPEG(const sp<DataSource> &source, float *confidence)
+{
+ char url[128] = {0};
+
+ ALOGI("android-source:%p", source.get());
+
+ // pass the addr of smart pointer("source")
+ snprintf(url, sizeof(url), "android-source:%p", source.get());
+
+ return SniffFFMPEGCommon(url, confidence);
+}
+
+bool SniffFFMPEG(
+ const sp<DataSource> &source, String8 *mimeType, float *confidence,
+ sp<AMessage> *meta) {
+ ALOGV("SniffFFMPEG");
+
+ *confidence = 0.08f; // be the last resort, by default
+
+ const char *container = BetterSniffFFMPEG(source, confidence);
+ if (!container) {
+ ALOGW("sniff through BetterSniffFFMPEG failed, try LegacySniffFFMPEG");
+ container = LegacySniffFFMPEG(source, confidence);
+ if (container) {
+ ALOGI("sniff through LegacySniffFFMPEG success");
+ }
+ } else {
+ ALOGI("sniff through BetterSniffFFMPEG success");
+ }
+
+ if (container == NULL) {
+ ALOGD("SniffFFMPEG failed to sniff this source");
+ return false;
+ }
+
+ ALOGD("ffmpeg detected media content as '%s' with confidence %.2f",
+ container, *confidence);
+
+ /* use MPEG4Extractor(not extended extractor) for HTTP source only */
+ if (!strcasecmp(container, MEDIA_MIMETYPE_CONTAINER_MPEG4)
+ && (source->flags() & DataSource::kIsCachingDataSource)) {
+ ALOGI("support container: %s, but it is caching data source, "
+ "Don't use ffmpegextractor", container);
+ return false;
+ }
+
+ mimeType->setTo(container);
+
+ *meta = new AMessage;
+ (*meta)->setString("extended-extractor", "extended-extractor");
+ (*meta)->setString("extended-extractor-subtype", "ffmpegextractor");
+
+ //debug only
+ char value[PROPERTY_VALUE_MAX];
+ property_get("sys.media.parser.ffmpeg", value, "0");
+ if (atoi(value)) {
+ ALOGI("[debug] parser use ffmpeg");
+ *confidence = 0.88f;
+ }
+
+ if (*confidence > 0.08f) {
+ (*meta)->setString("extended-extractor-use", "ffmpegextractor");
+ }
+
+ return true;
+}
+
+MediaExtractor *CreateFFmpegExtractor(const sp<DataSource> &source, const char *mime, const sp<AMessage> &meta) {
+ MediaExtractor *ret = NULL;
+ AString notuse;
+ if (meta.get() && meta->findString("extended-extractor", ¬use) && (
+ !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) ||
+ !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2PS) ||
+ !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_AVI) ||
+ !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_ASF) ||
+ !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WEBM) ||
+ !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WMV) ||
+ !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPG) ||
+ !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_FLV) ||
+ !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_DIVX) ||
+ !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_RM) ||
+ !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WAV) ||
+ !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_FLAC) ||
+ !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_APE) ||
+ !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);
+ }
+
+ ALOGD("%ssupported mime: %s", (ret ? "" : "un"), mime);
+ return ret;