Make extractors separate libraries

instead of being integrated into libstagefright

Test: thoroughly
Change-Id: I11cdfde6d2daf248c8e0f99237db1c74be260eb0
diff --git a/media/extractors/Android.bp b/media/extractors/Android.bp
new file mode 100644
index 0000000..e8176cf
--- /dev/null
+++ b/media/extractors/Android.bp
@@ -0,0 +1,3 @@
+subdirs = [
+    "*",
+]
diff --git a/media/libstagefright/AACExtractor.cpp b/media/extractors/aac/AACExtractor.cpp
similarity index 92%
rename from media/libstagefright/AACExtractor.cpp
rename to media/extractors/aac/AACExtractor.cpp
index 30fb5fe..ce5f976 100644
--- a/media/libstagefright/AACExtractor.cpp
+++ b/media/extractors/aac/AACExtractor.cpp
@@ -18,7 +18,7 @@
 #define LOG_TAG "AACExtractor"
 #include <utils/Log.h>
 
-#include "include/AACExtractor.h"
+#include "AACExtractor.h"
 #include "include/avc_utils.h"
 
 #include <media/stagefright/foundation/ABuffer.h>
@@ -140,13 +140,8 @@
     sp<AMessage> meta = _meta;
 
     if (meta == NULL) {
-        String8 mimeType;
-        float confidence;
-        sp<AMessage> _meta;
-
-        if (!SniffAAC(mDataSource, &mimeType, &confidence, &meta)) {
-            return;
-        }
+        ALOGE("no metadata specified");
+        return;
     }
 
     int64_t offset;
@@ -333,7 +328,13 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-bool SniffAAC(
+static MediaExtractor* CreateExtractor(
+        const sp<DataSource> &source,
+        const sp<AMessage>& meta) {
+    return new AACExtractor(source, meta);
+}
+
+static MediaExtractor::CreatorFunc Sniff(
         const sp<DataSource> &source, String8 *mimeType, float *confidence,
         sp<AMessage> *meta) {
     off64_t pos = 0;
@@ -342,7 +343,7 @@
         uint8_t id3header[10];
         if (source->readAt(pos, id3header, sizeof(id3header))
                 < (ssize_t)sizeof(id3header)) {
-            return false;
+            return NULL;
         }
 
         if (memcmp("ID3", id3header, 3)) {
@@ -368,7 +369,7 @@
     uint8_t header[2];
 
     if (source->readAt(pos, &header, 2) != 2) {
-        return false;
+        return NULL;
     }
 
     // ADTS syncword
@@ -379,10 +380,26 @@
         *meta = new AMessage;
         (*meta)->setInt64("offset", pos);
 
-        return true;
+        return CreateExtractor;
     }
 
-    return false;
+    return NULL;
 }
 
-}  // namespace android
+
+extern "C" {
+// This is the only symbol that needs to be exported
+__attribute__ ((visibility ("default")))
+MediaExtractor::ExtractorDef GETEXTRACTORDEF() {
+    return {
+        MediaExtractor::EXTRACTORDEF_VERSION,
+        UUID("4fd80eae-03d2-4d72-9eb9-48fa6bb54613"),
+        1, // version
+        "AAC Extractor",
+        Sniff
+    };
+}
+
+} // extern "C"
+
+} // namespace android
diff --git a/media/libstagefright/include/AACExtractor.h b/media/extractors/aac/AACExtractor.h
similarity index 100%
rename from media/libstagefright/include/AACExtractor.h
rename to media/extractors/aac/AACExtractor.h
diff --git a/media/extractors/aac/Android.bp b/media/extractors/aac/Android.bp
new file mode 100644
index 0000000..b4ef53e
--- /dev/null
+++ b/media/extractors/aac/Android.bp
@@ -0,0 +1,39 @@
+cc_library_shared {
+
+    srcs: ["AACExtractor.cpp"],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright/",
+    ],
+
+    shared_libs: [
+        "libstagefright",
+        "libmedia",
+        "libstagefright_foundation",
+        "libutils",
+        "liblog",
+    ],
+
+    name: "libaacextractor",
+    relative_install_path: "extractors",
+
+    compile_multilib: "first",
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+        "-fvisibility=hidden",
+    ],
+
+    sanitize: {
+        cfi: true,
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+        diag: {
+            cfi: true,
+        },
+    },
+
+}
diff --git a/media/libstagefright/matroska/MODULE_LICENSE_APACHE2 b/media/extractors/aac/MODULE_LICENSE_APACHE2
similarity index 100%
rename from media/libstagefright/matroska/MODULE_LICENSE_APACHE2
rename to media/extractors/aac/MODULE_LICENSE_APACHE2
diff --git a/media/libstagefright/matroska/NOTICE b/media/extractors/aac/NOTICE
similarity index 100%
rename from media/libstagefright/matroska/NOTICE
rename to media/extractors/aac/NOTICE
diff --git a/media/libstagefright/AMRExtractor.cpp b/media/extractors/amr/AMRExtractor.cpp
similarity index 91%
rename from media/libstagefright/AMRExtractor.cpp
rename to media/extractors/amr/AMRExtractor.cpp
index 8b4d14d..d8b92bd 100644
--- a/media/libstagefright/AMRExtractor.cpp
+++ b/media/extractors/amr/AMRExtractor.cpp
@@ -18,7 +18,7 @@
 #define LOG_TAG "AMRExtractor"
 #include <utils/Log.h>
 
-#include "include/AMRExtractor.h"
+#include "AMRExtractor.h"
 
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/DataSource.h>
@@ -362,4 +362,31 @@
     return false;
 }
 
+extern "C" {
+// This is the only symbol that needs to be exported
+__attribute__ ((visibility ("default")))
+MediaExtractor::ExtractorDef GETEXTRACTORDEF() {
+    return {
+        MediaExtractor::EXTRACTORDEF_VERSION,
+        UUID("c86639c9-2f31-40ac-a715-fa01b4493aaf"),
+        1,
+        "AMR Extractor",
+        [](
+                const sp<DataSource> &source,
+                String8 *mimeType,
+                float *confidence,
+                sp<AMessage> *meta __unused) -> MediaExtractor::CreatorFunc {
+            if (SniffAMR(source, mimeType, confidence, meta)) {
+                return [](
+                        const sp<DataSource> &source,
+                        const sp<AMessage>& meta __unused) -> MediaExtractor* {
+                    return new AMRExtractor(source);};
+            }
+            return NULL;
+        }
+    };
+}
+
+} // extern "C"
+
 }  // namespace android
diff --git a/media/libstagefright/include/AMRExtractor.h b/media/extractors/amr/AMRExtractor.h
similarity index 100%
rename from media/libstagefright/include/AMRExtractor.h
rename to media/extractors/amr/AMRExtractor.h
diff --git a/media/extractors/amr/Android.bp b/media/extractors/amr/Android.bp
new file mode 100644
index 0000000..85e4777
--- /dev/null
+++ b/media/extractors/amr/Android.bp
@@ -0,0 +1,39 @@
+cc_library_shared {
+
+    srcs: ["AMRExtractor.cpp"],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright/include",
+    ],
+
+    shared_libs: [
+        "libstagefright",
+        "libmedia",
+        "libstagefright_foundation",
+        "libutils",
+        "liblog",
+    ],
+
+    name: "libamrextractor",
+    relative_install_path: "extractors",
+
+    compile_multilib: "first",
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+        "-fvisibility=hidden",
+    ],
+
+    sanitize: {
+        cfi: true,
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+        diag: {
+            cfi: true,
+        },
+    },
+
+}
diff --git a/media/libstagefright/matroska/MODULE_LICENSE_APACHE2 b/media/extractors/amr/MODULE_LICENSE_APACHE2
similarity index 100%
copy from media/libstagefright/matroska/MODULE_LICENSE_APACHE2
copy to media/extractors/amr/MODULE_LICENSE_APACHE2
diff --git a/media/libstagefright/matroska/NOTICE b/media/extractors/amr/NOTICE
similarity index 100%
copy from media/libstagefright/matroska/NOTICE
copy to media/extractors/amr/NOTICE
diff --git a/media/extractors/flac/Android.bp b/media/extractors/flac/Android.bp
new file mode 100644
index 0000000..5edc182
--- /dev/null
+++ b/media/extractors/flac/Android.bp
@@ -0,0 +1,44 @@
+cc_library_shared {
+
+    srcs: ["FLACExtractor.cpp"],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright/include",
+        "external/flac/include",
+    ],
+
+    shared_libs: [
+        "libstagefright",
+        "libmedia",
+        "libstagefright_foundation",
+        "libutils",
+        "liblog",
+    ],
+
+    static_libs: [
+        "libFLAC",
+    ],
+
+    name: "libflacextractor",
+    relative_install_path: "extractors",
+
+    compile_multilib: "first",
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+        "-fvisibility=hidden",
+    ],
+
+    sanitize: {
+        cfi: true,
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+        diag: {
+            cfi: true,
+        },
+    },
+
+}
diff --git a/media/libstagefright/FLACExtractor.cpp b/media/extractors/flac/FLACExtractor.cpp
similarity index 84%
rename from media/libstagefright/FLACExtractor.cpp
rename to media/extractors/flac/FLACExtractor.cpp
index 99315d6..dda8100 100644
--- a/media/libstagefright/FLACExtractor.cpp
+++ b/media/extractors/flac/FLACExtractor.cpp
@@ -18,22 +18,147 @@
 #define LOG_TAG "FLACExtractor"
 #include <utils/Log.h>
 
-#include "include/FLACExtractor.h"
-// Vorbis comments
-#include "include/OggExtractor.h"
+#include "FLACExtractor.h"
 // libFLAC parser
 #include "FLAC/stream_decoder.h"
 
+#include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/base64.h>
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/Utils.h>
 
 namespace android {
 
+// also exists in OggExtractor, candidate for moving to utility/support library?
+static void extractAlbumArt(
+        const sp<MetaData> &fileMeta, const void *data, size_t size) {
+    ALOGV("extractAlbumArt from '%s'", (const char *)data);
+
+    sp<ABuffer> flacBuffer = decodeBase64(AString((const char *)data, size));
+    if (flacBuffer == NULL) {
+        ALOGE("malformed base64 encoded data.");
+        return;
+    }
+
+    size_t flacSize = flacBuffer->size();
+    uint8_t *flac = flacBuffer->data();
+    ALOGV("got flac of size %zu", flacSize);
+
+    uint32_t picType;
+    uint32_t typeLen;
+    uint32_t descLen;
+    uint32_t dataLen;
+    char type[128];
+
+    if (flacSize < 8) {
+        return;
+    }
+
+    picType = U32_AT(flac);
+
+    if (picType != 3) {
+        // This is not a front cover.
+        return;
+    }
+
+    typeLen = U32_AT(&flac[4]);
+    if (typeLen > sizeof(type) - 1) {
+        return;
+    }
+
+    // we've already checked above that flacSize >= 8
+    if (flacSize - 8 < typeLen) {
+        return;
+    }
+
+    memcpy(type, &flac[8], typeLen);
+    type[typeLen] = '\0';
+
+    ALOGV("picType = %d, type = '%s'", picType, type);
+
+    if (!strcmp(type, "-->")) {
+        // This is not inline cover art, but an external url instead.
+        return;
+    }
+
+    if (flacSize < 32 || flacSize - 32 < typeLen) {
+        return;
+    }
+
+    descLen = U32_AT(&flac[8 + typeLen]);
+    if (flacSize - 32 - typeLen < descLen) {
+        return;
+    }
+
+    dataLen = U32_AT(&flac[8 + typeLen + 4 + descLen + 16]);
+
+    // we've already checked above that (flacSize - 32 - typeLen - descLen) >= 0
+    if (flacSize - 32 - typeLen - descLen < dataLen) {
+        return;
+    }
+
+    ALOGV("got image data, %zu trailing bytes",
+         flacSize - 32 - typeLen - descLen - dataLen);
+
+    fileMeta->setData(
+            kKeyAlbumArt, 0, &flac[8 + typeLen + 4 + descLen + 20], dataLen);
+
+    fileMeta->setCString(kKeyAlbumArtMIME, type);
+}
+
+// also exists in OggExtractor, candidate for moving to utility/support library?
+static void parseVorbisComment(
+        const sp<MetaData> &fileMeta, const char *comment, size_t commentLength)
+{
+    struct {
+        const char *const mTag;
+        uint32_t mKey;
+    } kMap[] = {
+        { "TITLE", kKeyTitle },
+        { "ARTIST", kKeyArtist },
+        { "ALBUMARTIST", kKeyAlbumArtist },
+        { "ALBUM ARTIST", kKeyAlbumArtist },
+        { "COMPILATION", kKeyCompilation },
+        { "ALBUM", kKeyAlbum },
+        { "COMPOSER", kKeyComposer },
+        { "GENRE", kKeyGenre },
+        { "AUTHOR", kKeyAuthor },
+        { "TRACKNUMBER", kKeyCDTrackNumber },
+        { "DISCNUMBER", kKeyDiscNumber },
+        { "DATE", kKeyDate },
+        { "YEAR", kKeyYear },
+        { "LYRICIST", kKeyWriter },
+        { "METADATA_BLOCK_PICTURE", kKeyAlbumArt },
+        { "ANDROID_LOOP", kKeyAutoLoop },
+    };
+
+        for (size_t j = 0; j < sizeof(kMap) / sizeof(kMap[0]); ++j) {
+            size_t tagLen = strlen(kMap[j].mTag);
+            if (!strncasecmp(kMap[j].mTag, comment, tagLen)
+                    && comment[tagLen] == '=') {
+                if (kMap[j].mKey == kKeyAlbumArt) {
+                    extractAlbumArt(
+                            fileMeta,
+                            &comment[tagLen + 1],
+                            commentLength - tagLen - 1);
+                } else if (kMap[j].mKey == kKeyAutoLoop) {
+                    if (!strcasecmp(&comment[tagLen + 1], "true")) {
+                        fileMeta->setInt32(kKeyAutoLoop, true);
+                    }
+                } else {
+                    fileMeta->setCString(kMap[j].mKey, &comment[tagLen + 1]);
+                }
+            }
+        }
+
+}
+
 class FLACParser;
 
 class FLACSource : public MediaSource {
@@ -864,4 +989,32 @@
     return true;
 }
 
+
+extern "C" {
+// This is the only symbol that needs to be exported
+__attribute__ ((visibility ("default")))
+MediaExtractor::ExtractorDef GETEXTRACTORDEF() {
+    return {
+        MediaExtractor::EXTRACTORDEF_VERSION,
+            UUID("1364b048-cc45-4fda-9934-327d0ebf9829"),
+            1,
+            "FLAC Extractor",
+            [](
+                    const sp<DataSource> &source,
+                    String8 *mimeType,
+                    float *confidence,
+                    sp<AMessage> *meta __unused) -> MediaExtractor::CreatorFunc {
+                if (SniffFLAC(source, mimeType, confidence, meta)) {
+                    return [](
+                            const sp<DataSource> &source,
+                            const sp<AMessage>& meta __unused) -> MediaExtractor* {
+                        return new FLACExtractor(source);};
+                }
+                return NULL;
+            }
+     };
+}
+
+} // extern "C"
+
 }  // namespace android
diff --git a/media/libstagefright/include/FLACExtractor.h b/media/extractors/flac/FLACExtractor.h
similarity index 100%
rename from media/libstagefright/include/FLACExtractor.h
rename to media/extractors/flac/FLACExtractor.h
diff --git a/media/libstagefright/matroska/MODULE_LICENSE_APACHE2 b/media/extractors/flac/MODULE_LICENSE_APACHE2
similarity index 100%
copy from media/libstagefright/matroska/MODULE_LICENSE_APACHE2
copy to media/extractors/flac/MODULE_LICENSE_APACHE2
diff --git a/media/libstagefright/matroska/NOTICE b/media/extractors/flac/NOTICE
similarity index 100%
copy from media/libstagefright/matroska/NOTICE
copy to media/extractors/flac/NOTICE
diff --git a/media/extractors/midi/Android.bp b/media/extractors/midi/Android.bp
new file mode 100644
index 0000000..1b84b94
--- /dev/null
+++ b/media/extractors/midi/Android.bp
@@ -0,0 +1,40 @@
+cc_library_shared {
+
+    srcs: ["MidiExtractor.cpp"],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright/include",
+    ],
+
+    shared_libs: [
+        "libsonivox",
+        "libstagefright",
+        "libmedia",
+        "libstagefright_foundation",
+        "libutils",
+        "liblog",
+    ],
+
+    name: "libmidiextractor",
+    relative_install_path: "extractors",
+
+    compile_multilib: "first",
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+        "-fvisibility=hidden",
+    ],
+
+    sanitize: {
+        cfi: true,
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+        diag: {
+            cfi: true,
+        },
+    },
+
+}
diff --git a/media/libstagefright/matroska/MODULE_LICENSE_APACHE2 b/media/extractors/midi/MODULE_LICENSE_APACHE2
similarity index 100%
copy from media/libstagefright/matroska/MODULE_LICENSE_APACHE2
copy to media/extractors/midi/MODULE_LICENSE_APACHE2
diff --git a/media/libstagefright/MidiExtractor.cpp b/media/extractors/midi/MidiExtractor.cpp
similarity index 90%
rename from media/libstagefright/MidiExtractor.cpp
rename to media/extractors/midi/MidiExtractor.cpp
index 89cfa3c..1f32cb3 100644
--- a/media/libstagefright/MidiExtractor.cpp
+++ b/media/extractors/midi/MidiExtractor.cpp
@@ -18,7 +18,7 @@
 #define LOG_TAG "MidiExtractor"
 #include <utils/Log.h>
 
-#include "include/MidiExtractor.h"
+#include "MidiExtractor.h"
 
 #include <media/MidiIoWrapper.h>
 #include <media/stagefright/foundation/ADebug.h>
@@ -323,4 +323,31 @@
 
 }
 
+extern "C" {
+// This is the only symbol that needs to be exported
+__attribute__ ((visibility ("default")))
+MediaExtractor::ExtractorDef GETEXTRACTORDEF() {
+    return {
+        MediaExtractor::EXTRACTORDEF_VERSION,
+        UUID("ef6cca0a-f8a2-43e6-ba5f-dfcd7c9a7ef2"),
+        1,
+        "MIDI Extractor",
+        [](
+                const sp<DataSource> &source,
+                String8 *mimeType,
+                float *confidence,
+                sp<AMessage> *meta __unused) -> MediaExtractor::CreatorFunc {
+            if (SniffMidi(source, mimeType, confidence, meta)) {
+                return [](
+                        const sp<DataSource> &source,
+                        const sp<AMessage>& meta __unused) -> MediaExtractor* {
+                    return new MidiExtractor(source);};
+            }
+            return NULL;
+        }
+    };
+}
+
+} // extern "C"
+
 }  // namespace android
diff --git a/media/libstagefright/include/MidiExtractor.h b/media/extractors/midi/MidiExtractor.h
similarity index 100%
rename from media/libstagefright/include/MidiExtractor.h
rename to media/extractors/midi/MidiExtractor.h
diff --git a/media/libstagefright/matroska/NOTICE b/media/extractors/midi/NOTICE
similarity index 100%
copy from media/libstagefright/matroska/NOTICE
copy to media/extractors/midi/NOTICE
diff --git a/media/libstagefright/matroska/Android.bp b/media/extractors/mkv/Android.bp
similarity index 62%
rename from media/libstagefright/matroska/Android.bp
rename to media/extractors/mkv/Android.bp
index ec2fb4b..f855bbb 100644
--- a/media/libstagefright/matroska/Android.bp
+++ b/media/extractors/mkv/Android.bp
@@ -1,35 +1,47 @@
-cc_library_static {
-    name: "libstagefright_matroska",
+cc_library_shared {
 
     srcs: ["MatroskaExtractor.cpp"],
 
     include_dirs: [
         "external/flac/include",
         "external/libvpx/libwebm",
-        "frameworks/native/include/media/openmax",
-        "frameworks/av/media/libstagefright/flac/dec",
         "frameworks/av/media/libstagefright/include",
+        "frameworks/av/media/libstagefright/flac/dec",
     ],
 
+    shared_libs: [
+        "libstagefright",
+        "libmedia",
+        "libstagefright_foundation",
+        "libstagefright_flacdec",
+        "libutils",
+        "liblog",
+    ],
+
+    static_libs: [
+        "libwebm",
+    ],
+
+    name: "libmkvextractor",
+    relative_install_path: "extractors",
+
+    compile_multilib: "first",
+
     cflags: [
-        "-Wno-multichar",
         "-Werror",
         "-Wall",
+        "-fvisibility=hidden",
     ],
 
     sanitize: {
-        misc_undefined: [
-            "signed-integer-overflow",
-            "unsigned-integer-overflow",
-        ],
         cfi: true,
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
         diag: {
             cfi: true,
         },
     },
 
-    shared_libs: [
-        "libmedia",
-        "libstagefright_flacdec"
-    ],
 }
diff --git a/media/libstagefright/matroska/MODULE_LICENSE_APACHE2 b/media/extractors/mkv/MODULE_LICENSE_APACHE2
similarity index 100%
copy from media/libstagefright/matroska/MODULE_LICENSE_APACHE2
copy to media/extractors/mkv/MODULE_LICENSE_APACHE2
diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/extractors/mkv/MatroskaExtractor.cpp
similarity index 97%
rename from media/libstagefright/matroska/MatroskaExtractor.cpp
rename to media/extractors/mkv/MatroskaExtractor.cpp
index 487603c..1de6f90 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.cpp
+++ b/media/extractors/mkv/MatroskaExtractor.cpp
@@ -1527,4 +1527,32 @@
     return true;
 }
 
+
+extern "C" {
+// This is the only symbol that needs to be exported
+__attribute__ ((visibility ("default")))
+MediaExtractor::ExtractorDef GETEXTRACTORDEF() {
+    return {
+        MediaExtractor::EXTRACTORDEF_VERSION,
+        UUID("abbedd92-38c4-4904-a4c1-b3f45f899980"),
+        1,
+        "Matroska Extractor",
+        [](
+                const sp<DataSource> &source,
+                String8 *mimeType,
+                float *confidence,
+                sp<AMessage> *meta __unused) -> MediaExtractor::CreatorFunc {
+            if (SniffMatroska(source, mimeType, confidence, meta)) {
+                return [](
+                        const sp<DataSource> &source,
+                        const sp<AMessage>& meta __unused) -> MediaExtractor* {
+                    return new MatroskaExtractor(source);};
+            }
+            return NULL;
+        }
+    };
+}
+
+} // extern "C"
+
 }  // namespace android
diff --git a/media/libstagefright/matroska/MatroskaExtractor.h b/media/extractors/mkv/MatroskaExtractor.h
similarity index 100%
rename from media/libstagefright/matroska/MatroskaExtractor.h
rename to media/extractors/mkv/MatroskaExtractor.h
diff --git a/media/libstagefright/matroska/NOTICE b/media/extractors/mkv/NOTICE
similarity index 100%
copy from media/libstagefright/matroska/NOTICE
copy to media/extractors/mkv/NOTICE
diff --git a/media/extractors/mp3/Android.bp b/media/extractors/mp3/Android.bp
new file mode 100644
index 0000000..b189ddf
--- /dev/null
+++ b/media/extractors/mp3/Android.bp
@@ -0,0 +1,47 @@
+cc_library_shared {
+
+    srcs: [
+            "MP3Extractor.cpp",
+            "VBRISeeker.cpp",
+            "XINGSeeker.cpp",
+    ],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright/include",
+    ],
+
+    shared_libs: [
+        "libstagefright",
+        "libmedia",
+        "libstagefright_foundation",
+        "libutils",
+        "liblog",
+    ],
+
+    static_libs: [
+        "libstagefright_id3",
+    ],
+
+    name: "libmp3extractor",
+    relative_install_path: "extractors",
+
+    compile_multilib: "first",
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+        "-fvisibility=hidden",
+    ],
+
+    sanitize: {
+        cfi: true,
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+        diag: {
+            cfi: true,
+        },
+    },
+
+}
diff --git a/media/libstagefright/MP3Extractor.cpp b/media/extractors/mp3/MP3Extractor.cpp
similarity index 96%
rename from media/libstagefright/MP3Extractor.cpp
rename to media/extractors/mp3/MP3Extractor.cpp
index 2c696e5..63ef8cf 100644
--- a/media/libstagefright/MP3Extractor.cpp
+++ b/media/extractors/mp3/MP3Extractor.cpp
@@ -18,12 +18,12 @@
 #define LOG_TAG "MP3Extractor"
 #include <utils/Log.h>
 
-#include "include/MP3Extractor.h"
+#include "MP3Extractor.h"
 
-#include "include/avc_utils.h"
-#include "include/ID3.h"
-#include "include/VBRISeeker.h"
-#include "include/XINGSeeker.h"
+#include "avc_utils.h"
+#include "ID3.h"
+#include "VBRISeeker.h"
+#include "XINGSeeker.h"
 
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
@@ -666,14 +666,20 @@
     return meta;
 }
 
-bool SniffMP3(
+static MediaExtractor* CreateExtractor(
+        const sp<DataSource> &source,
+        const sp<AMessage>& meta) {
+    return new MP3Extractor(source, meta);
+}
+
+static MediaExtractor::CreatorFunc Sniff(
         const sp<DataSource> &source, String8 *mimeType,
         float *confidence, sp<AMessage> *meta) {
     off64_t pos = 0;
     off64_t post_id3_pos;
     uint32_t header;
     if (!Resync(source, 0, &pos, &post_id3_pos, &header)) {
-        return false;
+        return NULL;
     }
 
     *meta = new AMessage;
@@ -684,7 +690,22 @@
     *mimeType = MEDIA_MIMETYPE_AUDIO_MPEG;
     *confidence = 0.2f;
 
-    return true;
+    return CreateExtractor;
 }
 
+extern "C" {
+// This is the only symbol that needs to be exported
+__attribute__ ((visibility ("default")))
+MediaExtractor::ExtractorDef GETEXTRACTORDEF() {
+    return {
+        MediaExtractor::EXTRACTORDEF_VERSION,
+        UUID("812a3f6c-c8cf-46de-b529-3774b14103d4"),
+        1, // version
+        "MP3 Extractor",
+        Sniff
+    };
+}
+
+} // extern "C"
+
 }  // namespace android
diff --git a/media/libstagefright/include/MP3Extractor.h b/media/extractors/mp3/MP3Extractor.h
similarity index 100%
rename from media/libstagefright/include/MP3Extractor.h
rename to media/extractors/mp3/MP3Extractor.h
diff --git a/media/libstagefright/include/MP3Seeker.h b/media/extractors/mp3/MP3Seeker.h
similarity index 100%
rename from media/libstagefright/include/MP3Seeker.h
rename to media/extractors/mp3/MP3Seeker.h
diff --git a/media/libstagefright/VBRISeeker.cpp b/media/extractors/mp3/VBRISeeker.cpp
similarity index 97%
rename from media/libstagefright/VBRISeeker.cpp
rename to media/extractors/mp3/VBRISeeker.cpp
index 5b8f23a..24002db 100644
--- a/media/libstagefright/VBRISeeker.cpp
+++ b/media/extractors/mp3/VBRISeeker.cpp
@@ -21,10 +21,9 @@
 
 #include <utils/Log.h>
 
-#include "include/VBRISeeker.h"
+#include "VBRISeeker.h"
 
-#include "include/avc_utils.h"
-#include "include/MP3Extractor.h"
+#include "avc_utils.h"
 
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/DataSource.h>
diff --git a/media/libstagefright/include/VBRISeeker.h b/media/extractors/mp3/VBRISeeker.h
similarity index 97%
rename from media/libstagefright/include/VBRISeeker.h
rename to media/extractors/mp3/VBRISeeker.h
index c57d571..87258b0 100644
--- a/media/libstagefright/include/VBRISeeker.h
+++ b/media/extractors/mp3/VBRISeeker.h
@@ -18,7 +18,7 @@
 
 #define VBRI_SEEKER_H_
 
-#include "include/MP3Seeker.h"
+#include "MP3Seeker.h"
 
 #include <utils/Vector.h>
 
diff --git a/media/libstagefright/XINGSeeker.cpp b/media/extractors/mp3/XINGSeeker.cpp
similarity index 98%
rename from media/libstagefright/XINGSeeker.cpp
rename to media/extractors/mp3/XINGSeeker.cpp
index 81ed9c6..954e61b 100644
--- a/media/libstagefright/XINGSeeker.cpp
+++ b/media/extractors/mp3/XINGSeeker.cpp
@@ -17,8 +17,8 @@
 #define LOG_TAG "XINGSEEKER"
 #include <utils/Log.h>
 
-#include "include/XINGSeeker.h"
-#include "include/avc_utils.h"
+#include "XINGSeeker.h"
+#include "avc_utils.h"
 
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/Utils.h>
diff --git a/media/libstagefright/include/XINGSeeker.h b/media/extractors/mp3/XINGSeeker.h
similarity index 97%
rename from media/libstagefright/include/XINGSeeker.h
rename to media/extractors/mp3/XINGSeeker.h
index cce04f0..37077c4 100644
--- a/media/libstagefright/include/XINGSeeker.h
+++ b/media/extractors/mp3/XINGSeeker.h
@@ -18,7 +18,7 @@
 
 #define XING_SEEKER_H_
 
-#include "include/MP3Seeker.h"
+#include "MP3Seeker.h"
 
 namespace android {
 
diff --git a/media/extractors/mp4/Android.bp b/media/extractors/mp4/Android.bp
new file mode 100644
index 0000000..a957e98
--- /dev/null
+++ b/media/extractors/mp4/Android.bp
@@ -0,0 +1,48 @@
+cc_library_shared {
+
+    srcs: [
+        "ItemTable.cpp",
+        "MPEG4Extractor.cpp",
+        "SampleIterator.cpp",
+        "SampleTable.cpp",
+    ],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright/",
+    ],
+
+    shared_libs: [
+        "libstagefright",
+        "libmedia",
+        "libstagefright_foundation",
+        "libutils",
+        "liblog",
+    ],
+
+    static_libs: [
+        "libstagefright_id3",
+    ],
+
+    name: "libmp4extractor",
+    relative_install_path: "extractors",
+
+    compile_multilib: "first",
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+        "-fvisibility=hidden",
+    ],
+
+    sanitize: {
+        cfi: true,
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+        diag: {
+            cfi: true,
+        },
+    },
+
+}
diff --git a/media/libstagefright/ItemTable.cpp b/media/extractors/mp4/ItemTable.cpp
similarity index 99%
rename from media/libstagefright/ItemTable.cpp
rename to media/extractors/mp4/ItemTable.cpp
index 3ec416b..558a2bc 100644
--- a/media/libstagefright/ItemTable.cpp
+++ b/media/extractors/mp4/ItemTable.cpp
@@ -17,7 +17,7 @@
 //#define LOG_NDEBUG 0
 #define LOG_TAG "ItemTable"
 
-#include <include/ItemTable.h>
+#include <ItemTable.h>
 #include <media/MediaDefs.h>
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/MetaData.h>
diff --git a/media/libstagefright/include/ItemTable.h b/media/extractors/mp4/ItemTable.h
similarity index 100%
rename from media/libstagefright/include/ItemTable.h
rename to media/extractors/mp4/ItemTable.h
diff --git a/media/libstagefright/matroska/MODULE_LICENSE_APACHE2 b/media/extractors/mp4/MODULE_LICENSE_APACHE2
similarity index 100%
copy from media/libstagefright/matroska/MODULE_LICENSE_APACHE2
copy to media/extractors/mp4/MODULE_LICENSE_APACHE2
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
similarity index 99%
rename from media/libstagefright/MPEG4Extractor.cpp
rename to media/extractors/mp4/MPEG4Extractor.cpp
index cef4945..a625e24 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -26,9 +26,9 @@
 
 #include <utils/Log.h>
 
-#include "include/MPEG4Extractor.h"
-#include "include/SampleTable.h"
-#include "include/ItemTable.h"
+#include "MPEG4Extractor.h"
+#include "SampleTable.h"
+#include "ItemTable.h"
 #include "include/ESDS.h"
 
 #include <media/stagefright/foundation/ABitReader.h>
@@ -5474,19 +5474,42 @@
     return true;
 }
 
-bool SniffMPEG4(
-        const sp<DataSource> &source, String8 *mimeType, float *confidence,
+static MediaExtractor* CreateExtractor(
+        const sp<DataSource> &source,
+        const sp<AMessage>& meta __unused) {
+    return new MPEG4Extractor(source);
+}
+
+static MediaExtractor::CreatorFunc Sniff(
+        const sp<DataSource> &source,
+        String8 *mimeType,
+        float *confidence,
         sp<AMessage> *meta) {
     if (BetterSniffMPEG4(source, mimeType, confidence, meta)) {
-        return true;
+        return CreateExtractor;
     }
 
     if (LegacySniffMPEG4(source, mimeType, confidence)) {
         ALOGW("Identified supported mpeg4 through LegacySniffMPEG4.");
-        return true;
+        return CreateExtractor;
     }
 
-    return false;
+    return NULL;
 }
 
+extern "C" {
+// This is the only symbol that needs to be exported
+__attribute__ ((visibility ("default")))
+MediaExtractor::ExtractorDef GETEXTRACTORDEF() {
+    return {
+        MediaExtractor::EXTRACTORDEF_VERSION,
+        UUID("27575c67-4417-4c54-8d3d-8e626985a164"),
+        1, // version
+        "MP4 Extractor",
+        Sniff
+    };
+}
+
+} // extern "C"
+
 }  // namespace android
diff --git a/media/libstagefright/include/MPEG4Extractor.h b/media/extractors/mp4/MPEG4Extractor.h
similarity index 100%
rename from media/libstagefright/include/MPEG4Extractor.h
rename to media/extractors/mp4/MPEG4Extractor.h
diff --git a/media/libstagefright/matroska/NOTICE b/media/extractors/mp4/NOTICE
similarity index 100%
copy from media/libstagefright/matroska/NOTICE
copy to media/extractors/mp4/NOTICE
diff --git a/media/libstagefright/SampleIterator.cpp b/media/extractors/mp4/SampleIterator.cpp
similarity index 98%
rename from media/libstagefright/SampleIterator.cpp
rename to media/extractors/mp4/SampleIterator.cpp
index 75f744d..c4c6faf 100644
--- a/media/libstagefright/SampleIterator.cpp
+++ b/media/extractors/mp4/SampleIterator.cpp
@@ -18,7 +18,7 @@
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
-#include "include/SampleIterator.h"
+#include "SampleIterator.h"
 
 #include <arpa/inet.h>
 
@@ -26,7 +26,7 @@
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/Utils.h>
 
-#include "include/SampleTable.h"
+#include "SampleTable.h"
 
 namespace android {
 
diff --git a/media/libstagefright/include/SampleIterator.h b/media/extractors/mp4/SampleIterator.h
similarity index 100%
rename from media/libstagefright/include/SampleIterator.h
rename to media/extractors/mp4/SampleIterator.h
diff --git a/media/libstagefright/SampleTable.cpp b/media/extractors/mp4/SampleTable.cpp
similarity index 99%
rename from media/libstagefright/SampleTable.cpp
rename to media/extractors/mp4/SampleTable.cpp
index 1d2a931..d87d1b6 100644
--- a/media/libstagefright/SampleTable.cpp
+++ b/media/extractors/mp4/SampleTable.cpp
@@ -20,8 +20,8 @@
 
 #include <limits>
 
-#include "include/SampleTable.h"
-#include "include/SampleIterator.h"
+#include "SampleTable.h"
+#include "SampleIterator.h"
 
 #include <arpa/inet.h>
 
diff --git a/media/libstagefright/include/SampleTable.h b/media/extractors/mp4/SampleTable.h
similarity index 100%
rename from media/libstagefright/include/SampleTable.h
rename to media/extractors/mp4/SampleTable.h
diff --git a/media/extractors/mpeg2/Android.bp b/media/extractors/mpeg2/Android.bp
new file mode 100644
index 0000000..e69afd8
--- /dev/null
+++ b/media/extractors/mpeg2/Android.bp
@@ -0,0 +1,56 @@
+cc_library_shared {
+
+    srcs: [
+        "ExtractorBundle.cpp",
+        "MPEG2PSExtractor.cpp",
+        "MPEG2TSExtractor.cpp",
+    ],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright",
+        "frameworks/av/media/libstagefright/include",
+    ],
+
+    shared_libs: [
+        "libbinder",
+        "libstagefright",
+        "libmedia",
+        "libstagefright_foundation",
+        "libcutils",
+        "libutils",
+        "liblog",
+        "libcrypto",
+        "libmedia",
+        "libhidlbase",
+        "android.hidl.token@1.0-utils",
+        "android.hardware.cas@1.0",
+        "android.hardware.cas.native@1.0",
+    ],
+
+    static_libs: [
+        "libstagefright_mpeg2support",
+    ],
+
+    name: "libmpeg2extractor",
+    relative_install_path: "extractors",
+
+    compile_multilib: "first",
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+        "-fvisibility=hidden",
+    ],
+
+    sanitize: {
+        cfi: true,
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+        diag: {
+            cfi: true,
+        },
+    },
+
+}
diff --git a/media/extractors/mpeg2/ExtractorBundle.cpp b/media/extractors/mpeg2/ExtractorBundle.cpp
new file mode 100644
index 0000000..076515e
--- /dev/null
+++ b/media/extractors/mpeg2/ExtractorBundle.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MPEG2ExtractorBundle"
+#include <utils/Log.h>
+
+#include <media/stagefright/MediaExtractor.h>
+#include "MPEG2PSExtractor.h"
+#include "MPEG2TSExtractor.h"
+
+namespace android {
+
+extern "C" {
+// This is the only symbol that needs to be exported
+__attribute__ ((visibility ("default")))
+MediaExtractor::ExtractorDef GETEXTRACTORDEF() {
+    return {
+        MediaExtractor::EXTRACTORDEF_VERSION,
+        UUID("3d1dcfeb-e40a-436d-a574-c2438a555e5f"),
+        1,
+        "MPEG2-PS/TS Extractor",
+        [](
+                const sp<DataSource> &source,
+                String8 *mimeType,
+                float *confidence,
+                sp<AMessage> *meta __unused) -> MediaExtractor::CreatorFunc {
+            if (SniffMPEG2TS(source, mimeType, confidence, meta)) {
+                return [](
+                        const sp<DataSource> &source,
+                        const sp<AMessage>& meta __unused) -> MediaExtractor* {
+                    return new MPEG2TSExtractor(source);};
+            } else if (SniffMPEG2PS(source, mimeType, confidence, meta)) {
+                        return [](
+                                const sp<DataSource> &source,
+                                const sp<AMessage>& meta __unused) -> MediaExtractor* {
+                            return new MPEG2PSExtractor(source);};
+            }
+            return NULL;
+        }
+    };
+}
+
+} // extern "C"
+
+} // namespace android
diff --git a/media/libstagefright/matroska/MODULE_LICENSE_APACHE2 b/media/extractors/mpeg2/MODULE_LICENSE_APACHE2
similarity index 100%
copy from media/libstagefright/matroska/MODULE_LICENSE_APACHE2
copy to media/extractors/mpeg2/MODULE_LICENSE_APACHE2
diff --git a/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp b/media/extractors/mpeg2/MPEG2PSExtractor.cpp
similarity index 99%
rename from media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp
rename to media/extractors/mpeg2/MPEG2PSExtractor.cpp
index 0f18fac..a8a35bd 100644
--- a/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp
+++ b/media/extractors/mpeg2/MPEG2PSExtractor.cpp
@@ -18,10 +18,10 @@
 #define LOG_TAG "MPEG2PSExtractor"
 #include <utils/Log.h>
 
-#include "include/MPEG2PSExtractor.h"
+#include "MPEG2PSExtractor.h"
 
-#include "AnotherPacketSource.h"
-#include "ESQueue.h"
+#include "mpeg2ts/AnotherPacketSource.h"
+#include "mpeg2ts/ESQueue.h"
 
 #include <media/stagefright/foundation/ABitReader.h>
 #include <media/stagefright/foundation/ABuffer.h>
diff --git a/media/libstagefright/include/MPEG2PSExtractor.h b/media/extractors/mpeg2/MPEG2PSExtractor.h
similarity index 100%
rename from media/libstagefright/include/MPEG2PSExtractor.h
rename to media/extractors/mpeg2/MPEG2PSExtractor.h
diff --git a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp b/media/extractors/mpeg2/MPEG2TSExtractor.cpp
similarity index 98%
rename from media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
rename to media/extractors/mpeg2/MPEG2TSExtractor.cpp
index b66af7b..d42e901 100644
--- a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
+++ b/media/extractors/mpeg2/MPEG2TSExtractor.cpp
@@ -20,8 +20,7 @@
 #include <inttypes.h>
 #include <utils/Log.h>
 
-#include "include/MPEG2TSExtractor.h"
-#include "include/NuCachedSource2.h"
+#include "MPEG2TSExtractor.h"
 
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
@@ -35,8 +34,8 @@
 #include <media/IStreamSource.h>
 #include <utils/String8.h>
 
-#include "AnotherPacketSource.h"
-#include "ATSParser.h"
+#include "mpeg2ts/AnotherPacketSource.h"
+#include "mpeg2ts/ATSParser.h"
 
 #include <hidl/HybridInterface.h>
 #include <android/hardware/cas/1.0/ICas.h>
diff --git a/media/libstagefright/include/MPEG2TSExtractor.h b/media/extractors/mpeg2/MPEG2TSExtractor.h
similarity index 100%
rename from media/libstagefright/include/MPEG2TSExtractor.h
rename to media/extractors/mpeg2/MPEG2TSExtractor.h
diff --git a/media/libstagefright/matroska/NOTICE b/media/extractors/mpeg2/NOTICE
similarity index 100%
copy from media/libstagefright/matroska/NOTICE
copy to media/extractors/mpeg2/NOTICE
diff --git a/media/extractors/ogg/Android.bp b/media/extractors/ogg/Android.bp
new file mode 100644
index 0000000..17b939a
--- /dev/null
+++ b/media/extractors/ogg/Android.bp
@@ -0,0 +1,41 @@
+cc_library_shared {
+
+    srcs: ["OggExtractor.cpp"],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright/include",
+        "external/tremolo",
+    ],
+
+    shared_libs: [
+        "libstagefright",
+        "libmedia",
+        "libstagefright_foundation",
+        "libutils",
+        "liblog",
+        "libvorbisidec",
+    ],
+
+    name: "liboggextractor",
+    relative_install_path: "extractors",
+
+    compile_multilib: "first",
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+        "-fvisibility=hidden",
+    ],
+
+    sanitize: {
+        cfi: true,
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+        diag: {
+            cfi: true,
+        },
+    },
+
+}
diff --git a/media/libstagefright/matroska/MODULE_LICENSE_APACHE2 b/media/extractors/ogg/MODULE_LICENSE_APACHE2
similarity index 100%
copy from media/libstagefright/matroska/MODULE_LICENSE_APACHE2
copy to media/extractors/ogg/MODULE_LICENSE_APACHE2
diff --git a/media/libstagefright/matroska/NOTICE b/media/extractors/ogg/NOTICE
similarity index 100%
copy from media/libstagefright/matroska/NOTICE
copy to media/extractors/ogg/NOTICE
diff --git a/media/libstagefright/OggExtractor.cpp b/media/extractors/ogg/OggExtractor.cpp
similarity index 97%
rename from media/libstagefright/OggExtractor.cpp
rename to media/extractors/ogg/OggExtractor.cpp
index 58467db..db4fc4d 100644
--- a/media/libstagefright/OggExtractor.cpp
+++ b/media/extractors/ogg/OggExtractor.cpp
@@ -18,7 +18,7 @@
 #define LOG_TAG "OggExtractor"
 #include <utils/Log.h>
 
-#include "include/OggExtractor.h"
+#include "OggExtractor.h"
 
 #include <cutils/properties.h>
 #include <media/stagefright/foundation/ABuffer.h>
@@ -1176,19 +1176,8 @@
     return (mVi.bitrate_lower + mVi.bitrate_upper) / 2;
 }
 
-void MyOggExtractor::parseFileMetaData() {
-    mFileMeta = new MetaData;
-    mFileMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_OGG);
-
-    for (int i = 0; i < mVc.comments; ++i) {
-        const char *comment = mVc.user_comments[i];
-        size_t commentLength = mVc.comment_lengths[i];
-        parseVorbisComment(mFileMeta, comment, commentLength);
-        //ALOGI("comment #%d: '%s'", i + 1, mVc.user_comments[i]);
-    }
-}
-
-void parseVorbisComment(
+// also exists in FLACExtractor, candidate for moving to utility/support library?
+static void parseVorbisComment(
         const sp<MetaData> &fileMeta, const char *comment, size_t commentLength)
 {
     struct {
@@ -1234,6 +1223,7 @@
 
 }
 
+// also exists in FLACExtractor, candidate for moving to utility/support library?
 static void extractAlbumArt(
         const sp<MetaData> &fileMeta, const void *data, size_t size) {
     ALOGV("extractAlbumArt from '%s'", (const char *)data);
@@ -1310,6 +1300,19 @@
     fileMeta->setCString(kKeyAlbumArtMIME, type);
 }
 
+void MyOggExtractor::parseFileMetaData() {
+    mFileMeta = new MetaData;
+    mFileMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_OGG);
+
+    for (int i = 0; i < mVc.comments; ++i) {
+        const char *comment = mVc.user_comments[i];
+        size_t commentLength = mVc.comment_lengths[i];
+        parseVorbisComment(mFileMeta, comment, commentLength);
+        //ALOGI("comment #%d: '%s'", i + 1, mVc.user_comments[i]);
+    }
+}
+
+
 ////////////////////////////////////////////////////////////////////////////////
 
 OggExtractor::OggExtractor(const sp<DataSource> &source)
@@ -1366,18 +1369,41 @@
     return mImpl->getFileMetaData();
 }
 
-bool SniffOgg(
-        const sp<DataSource> &source, String8 *mimeType, float *confidence,
+static MediaExtractor* CreateExtractor(
+        const sp<DataSource> &source,
+        const sp<AMessage>& meta __unused) {
+    return new OggExtractor(source);
+}
+
+static MediaExtractor::CreatorFunc Sniff(
+        const sp<DataSource> &source,
+        String8 *mimeType,
+        float *confidence,
         sp<AMessage> *) {
     char tmp[4];
     if (source->readAt(0, tmp, 4) < 4 || memcmp(tmp, "OggS", 4)) {
-        return false;
+        return NULL;
     }
 
     mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_OGG);
     *confidence = 0.2f;
 
-    return true;
+    return CreateExtractor;
 }
 
+extern "C" {
+// This is the only symbol that needs to be exported
+__attribute__ ((visibility ("default")))
+MediaExtractor::ExtractorDef GETEXTRACTORDEF() {
+    return {
+        MediaExtractor::EXTRACTORDEF_VERSION,
+        UUID("8cc5cd06-f772-495e-8a62-cba9649374e9"),
+        1, // version
+        "Ogg Extractor",
+        Sniff
+    };
+}
+
+} // extern "C"
+
 }  // namespace android
diff --git a/media/libstagefright/include/OggExtractor.h b/media/extractors/ogg/OggExtractor.h
similarity index 93%
rename from media/libstagefright/include/OggExtractor.h
rename to media/extractors/ogg/OggExtractor.h
index c01850f..f42c105 100644
--- a/media/libstagefright/include/OggExtractor.h
+++ b/media/extractors/ogg/OggExtractor.h
@@ -59,9 +59,6 @@
         const sp<DataSource> &source, String8 *mimeType, float *confidence,
         sp<AMessage> *);
 
-void parseVorbisComment(
-        const sp<MetaData> &fileMeta, const char *comment, size_t commentLength);
-
 }  // namespace android
 
 #endif  // OGG_EXTRACTOR_H_
diff --git a/media/extractors/wav/Android.bp b/media/extractors/wav/Android.bp
new file mode 100644
index 0000000..ead02a9
--- /dev/null
+++ b/media/extractors/wav/Android.bp
@@ -0,0 +1,43 @@
+cc_library_shared {
+
+    srcs: ["WAVExtractor.cpp"],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright/include",
+    ],
+
+    shared_libs: [
+        "libstagefright",
+        "libmedia",
+        "libstagefright_foundation",
+        "libutils",
+        "liblog",
+    ],
+
+    static_libs: [
+        "libfifo",
+    ],
+
+    name: "libwavextractor",
+    relative_install_path: "extractors",
+
+    compile_multilib: "first",
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+        "-fvisibility=hidden",
+    ],
+
+    sanitize: {
+        cfi: true,
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+        diag: {
+            cfi: true,
+        },
+    },
+
+}
diff --git a/media/libstagefright/matroska/MODULE_LICENSE_APACHE2 b/media/extractors/wav/MODULE_LICENSE_APACHE2
similarity index 100%
copy from media/libstagefright/matroska/MODULE_LICENSE_APACHE2
copy to media/extractors/wav/MODULE_LICENSE_APACHE2
diff --git a/media/libstagefright/matroska/NOTICE b/media/extractors/wav/NOTICE
similarity index 100%
copy from media/libstagefright/matroska/NOTICE
copy to media/extractors/wav/NOTICE
diff --git a/media/libstagefright/WAVExtractor.cpp b/media/extractors/wav/WAVExtractor.cpp
similarity index 95%
rename from media/libstagefright/WAVExtractor.cpp
rename to media/extractors/wav/WAVExtractor.cpp
index 18bf4ae..cce488b 100644
--- a/media/libstagefright/WAVExtractor.cpp
+++ b/media/extractors/wav/WAVExtractor.cpp
@@ -18,7 +18,7 @@
 #define LOG_TAG "WAVExtractor"
 #include <utils/Log.h>
 
-#include "include/WAVExtractor.h"
+#include "WAVExtractor.h"
 
 #include <audio_utils/primitives.h>
 #include <media/stagefright/foundation/ADebug.h>
@@ -544,27 +544,50 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-bool SniffWAV(
-        const sp<DataSource> &source, String8 *mimeType, float *confidence,
+static MediaExtractor* CreateExtractor(
+        const sp<DataSource> &source,
+        const sp<AMessage>& meta __unused) {
+    return new WAVExtractor(source);
+}
+
+static MediaExtractor::CreatorFunc Sniff(
+        const sp<DataSource> &source,
+        String8 *mimeType,
+        float *confidence,
         sp<AMessage> *) {
     char header[12];
     if (source->readAt(0, header, sizeof(header)) < (ssize_t)sizeof(header)) {
-        return false;
+        return NULL;
     }
 
     if (memcmp(header, "RIFF", 4) || memcmp(&header[8], "WAVE", 4)) {
-        return false;
+        return NULL;
     }
 
     sp<MediaExtractor> extractor = new WAVExtractor(source);
     if (extractor->countTracks() == 0) {
-        return false;
+        return NULL;
     }
 
     *mimeType = MEDIA_MIMETYPE_CONTAINER_WAV;
     *confidence = 0.3f;
 
-    return true;
+    return CreateExtractor;
 }
 
-}  // namespace android
+extern "C" {
+// This is the only symbol that needs to be exported
+__attribute__ ((visibility ("default")))
+MediaExtractor::ExtractorDef GETEXTRACTORDEF() {
+    return {
+        MediaExtractor::EXTRACTORDEF_VERSION,
+        UUID("7d613858-5837-4a38-84c5-332d1cddee27"),
+        1, // version
+        "WAV Extractor",
+        Sniff
+    };
+}
+
+} // extern "C"
+
+} // namespace android
diff --git a/media/libstagefright/include/WAVExtractor.h b/media/extractors/wav/WAVExtractor.h
similarity index 93%
rename from media/libstagefright/include/WAVExtractor.h
rename to media/extractors/wav/WAVExtractor.h
index dbcbe86..9fe0335 100644
--- a/media/libstagefright/include/WAVExtractor.h
+++ b/media/extractors/wav/WAVExtractor.h
@@ -61,10 +61,6 @@
     WAVExtractor &operator=(const WAVExtractor &);
 };
 
-bool SniffWAV(
-        const sp<DataSource> &source, String8 *mimeType, float *confidence,
-        sp<AMessage> *);
-
 }  // namespace android
 
 #endif  // WAV_EXTRACTOR_H_
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index 93656a8..58ce17b 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -24,7 +24,7 @@
         "-Wno-error=deprecated-declarations",
         "-Wall",
     ],
-    shared_libs: ["libutils", "liblog", "libgui"],
+    shared_libs: ["libutils", "liblog"],
     header_libs: [
         "libmedia_headers",
         "libaudioclient_headers",
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index 614a942..11066b2 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -19,7 +19,6 @@
     libbinder                   \
     libcrypto                   \
     libcutils                   \
-    libdrmframework             \
     liblog                      \
     libdl                       \
     libgui                      \
@@ -34,8 +33,8 @@
     libstagefright_httplive     \
     libstagefright_omx          \
     libutils                    \
-    libnativewindow             \
     libhidlbase                 \
+    libhidlmemory               \
     android.hardware.media.omx@1.0 \
 
 LOCAL_STATIC_LIBRARIES :=       \
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index c07898c..fc2bff3 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -10,9 +10,7 @@
     srcs: [
         "ACodec.cpp",
         "ACodecBufferChannel.cpp",
-        "AACExtractor.cpp",
         "AACWriter.cpp",
-        "AMRExtractor.cpp",
         "AMRWriter.cpp",
         "AudioPlayer.cpp",
         "AudioSource.cpp",
@@ -27,15 +25,11 @@
         "DataURISource.cpp",
         "ESDS.cpp",
         "FileSource.cpp",
-        "FLACExtractor.cpp",
         "FrameRenderTracker.cpp",
         "HTTPBase.cpp",
         "HevcUtils.cpp",
-        "ItemTable.cpp",
         "JPEGSource.cpp",
-        "MP3Extractor.cpp",
         "MPEG2TSWriter.cpp",
-        "MPEG4Extractor.cpp",
         "MPEG4Writer.cpp",
         "MediaAdapter.cpp",
         "MediaClock.cpp",
@@ -45,7 +39,6 @@
         "MediaCodecSource.cpp",
         "MediaExtractor.cpp",
         "MediaSync.cpp",
-        "MidiExtractor.cpp",
         "http/MediaHTTP.cpp",
         "MediaMuxer.cpp",
         "MediaSource.cpp",
@@ -53,11 +46,8 @@
         "NuMediaExtractor.cpp",
         "OMXClient.cpp",
         "OmxInfoBuilder.cpp",
-        "OggExtractor.cpp",
         "RemoteMediaExtractor.cpp",
         "RemoteMediaSource.cpp",
-        "SampleIterator.cpp",
-        "SampleTable.cpp",
         "SimpleDecodingSource.cpp",
         "SkipCutBuffer.cpp",
         "StagefrightMediaScanner.cpp",
@@ -66,10 +56,7 @@
         "SurfaceUtils.cpp",
         "ThrottledSource.cpp",
         "Utils.cpp",
-        "VBRISeeker.cpp",
         "VideoFrameScheduler.cpp",
-        "WAVExtractor.cpp",
-        "XINGSeeker.cpp",
         "avc_utils.cpp",
     ],
 
@@ -77,7 +64,6 @@
         "libaudioutils",
         "libbinder",
         "libcamera_client",
-        "libcrypto",
         "libcutils",
         "libdl",
         "libdrmframework",
@@ -88,21 +74,16 @@
         "libmediametrics",
         "libmediautils",
         "libnetd_client",
-        "libsonivox",
         "libui",
         "libutils",
-        "libvorbisidec",
         "libmedia_helper",
         "libstagefright_omx_utils",
-        "libstagefright_flacdec",
         "libstagefright_foundation",
         "libdl",
         "libRScpp",
         "libhidlbase",
         "libhidlmemory",
         "android.hidl.allocator@1.0",
-        "android.hidl.token@1.0-utils",
-        "android.hardware.cas@1.0",
         "android.hardware.cas.native@1.0",
         "android.hardware.media.omx@1.0",
     ],
@@ -110,13 +91,12 @@
     static_libs: [
         "libstagefright_color_conversion",
         "libyuv_static",
-        "libstagefright_matroska",
         "libstagefright_mediafilter",
         "libstagefright_webm",
         "libstagefright_timedtext",
         "libvpx",
         "libwebm",
-        "libstagefright_mpeg2ts",
+        "libstagefright_mpeg2support",
         "libstagefright_id3",
         "libFLAC",
     ],
@@ -166,7 +146,6 @@
     "http",
     "httplive",
     "id3",
-    "matroska",
     "mpeg2ts",
     "omx",
     "rtsp",
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index 14e6251..e7e42b2 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -20,19 +20,6 @@
 #include <inttypes.h>
 #include <pwd.h>
 
-#include "include/AMRExtractor.h"
-#include "include/MP3Extractor.h"
-#include "include/MPEG4Extractor.h"
-#include "include/WAVExtractor.h"
-#include "include/OggExtractor.h"
-#include "include/MPEG2PSExtractor.h"
-#include "include/MPEG2TSExtractor.h"
-#include "include/FLACExtractor.h"
-#include "include/AACExtractor.h"
-#include "include/MidiExtractor.h"
-
-#include "matroska/MatroskaExtractor.h"
-
 #include <binder/IServiceManager.h>
 #include <binder/MemoryDealer.h>
 
@@ -54,6 +41,9 @@
 // still doing some on/off toggling here.
 #define MEDIA_LOG       1
 
+#include <sys/types.h>
+#include <dirent.h>
+#include <dlfcn.h>
 
 namespace android {
 
@@ -68,7 +58,7 @@
     if (!LOG_NDEBUG) {
         uid_t uid = getuid();
         struct passwd *pw = getpwuid(uid);
-        ALOGI("extractor created in uid: %d (%s)", getuid(), pw->pw_name);
+        ALOGV("extractor created in uid: %d (%s)", getuid(), pw->pw_name);
     }
 
     mAnalyticsItem = NULL;
@@ -162,12 +152,13 @@
 
     sp<AMessage> meta;
 
+    CreatorFunc creator = NULL;
     String8 tmp;
     if (mime == NULL) {
         float confidence;
-        if (!sniff(source, &tmp, &confidence, &meta)) {
-            ALOGW("FAILED to autodetect media content.");
-
+        creator = sniff(source, &tmp, &confidence, &meta);
+        if (!creator) {
+            ALOGV("FAILED to autodetect media content.");
             return NULL;
         }
 
@@ -176,32 +167,7 @@
              mime, confidence);
     }
 
-    MediaExtractor *ret = NULL;
-    if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG4)
-            || !strcasecmp(mime, "audio/mp4")) {
-        ret = new MPEG4Extractor(source);
-    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {
-        ret = new MP3Extractor(source, meta);
-    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)
-            || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB)) {
-        ret = new AMRExtractor(source);
-    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_FLAC)) {
-        ret = new FLACExtractor(source);
-    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WAV)) {
-        ret = new WAVExtractor(source);
-    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_OGG)) {
-        ret = new OggExtractor(source);
-    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MATROSKA)) {
-        ret = new MatroskaExtractor(source);
-    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) {
-        ret = new MPEG2TSExtractor(source);
-    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC_ADTS)) {
-        ret = new AACExtractor(source, meta);
-    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2PS)) {
-        ret = new MPEG2PSExtractor(source);
-    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MIDI)) {
-        ret = new MidiExtractor(source);
-    }
+    MediaExtractor *ret = creator(source, meta);
 
     if (ret != NULL) {
         // track the container format (mpeg, aac, wvm, etc)
@@ -231,11 +197,11 @@
 }
 
 Mutex MediaExtractor::gSnifferMutex;
-List<MediaExtractor::SnifferFunc> MediaExtractor::gSniffers;
+List<MediaExtractor::ExtractorDef> MediaExtractor::gSniffers;
 bool MediaExtractor::gSniffersRegistered = false;
 
 // static
-bool MediaExtractor::sniff(
+MediaExtractor::CreatorFunc MediaExtractor::sniff(
         const sp<DataSource> &source, String8 *mimeType, float *confidence, sp<AMessage> *meta) {
     *mimeType = "";
     *confidence = 0.0f;
@@ -244,37 +210,69 @@
     {
         Mutex::Autolock autoLock(gSnifferMutex);
         if (!gSniffersRegistered) {
-            return false;
+            return NULL;
         }
     }
 
-    for (List<SnifferFunc>::iterator it = gSniffers.begin();
+    CreatorFunc curCreator = NULL;
+    CreatorFunc bestCreator = NULL;
+    for (List<ExtractorDef>::iterator it = gSniffers.begin();
          it != gSniffers.end(); ++it) {
         String8 newMimeType;
         float newConfidence;
         sp<AMessage> newMeta;
-        if ((*it)(source, &newMimeType, &newConfidence, &newMeta)) {
+        if ((curCreator = (*it).sniff(source, &newMimeType, &newConfidence, &newMeta))) {
             if (newConfidence > *confidence) {
                 *mimeType = newMimeType;
                 *confidence = newConfidence;
                 *meta = newMeta;
+                bestCreator = curCreator;
             }
         }
     }
 
-    return *confidence > 0.0;
+    return bestCreator;
 }
 
 // static
-void MediaExtractor::RegisterSniffer_l(SnifferFunc func) {
-    for (List<SnifferFunc>::iterator it = gSniffers.begin();
-         it != gSniffers.end(); ++it) {
-        if (*it == func) {
-            return;
-        }
+void MediaExtractor::RegisterSniffer_l(const ExtractorDef &def) {
+    // sanity check check struct version, uuid, name
+    if (def.def_version == 0 || def.def_version > EXTRACTORDEF_VERSION) {
+        ALOGE("don't understand extractor format %u, ignoring.", def.def_version);
+        return;
+    }
+    if (memcmp(&def.extractor_uuid, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16) == 0) {
+        ALOGE("invalid UUID, ignoring");
+        return;
+    }
+    if (def.extractor_name == NULL || strlen(def.extractor_name) == 0) {
+        ALOGE("extractors should have a name, ignoring");
+        return;
     }
 
-    gSniffers.push_back(func);
+    for (List<ExtractorDef>::iterator it = gSniffers.begin();
+            it != gSniffers.end(); ++it) {
+        if (memcmp(&((*it).extractor_uuid), &def.extractor_uuid, 16) == 0) {
+            // there's already an extractor with the same uuid
+            if ((*it).extractor_version < def.extractor_version) {
+                // this one is newer, replace the old one
+                ALOGW("replacing extractor '%s' version %u with version %u",
+                        def.extractor_name,
+                        (*it).extractor_version,
+                        def.extractor_version);
+                gSniffers.erase(it);
+                break;
+            } else {
+                ALOGW("ignoring extractor '%s' version %u in favor of version %u",
+                        def.extractor_name,
+                        def.extractor_version,
+                        (*it).extractor_version);
+                return;
+            }
+        }
+    }
+    ALOGV("registering extractor for %s", def.extractor_name);
+    gSniffers.push_back(def);
 }
 
 // static
@@ -284,17 +282,44 @@
         return;
     }
 
-    RegisterSniffer_l(SniffMPEG4);
-    RegisterSniffer_l(SniffMatroska);
-    RegisterSniffer_l(SniffOgg);
-    RegisterSniffer_l(SniffWAV);
-    RegisterSniffer_l(SniffFLAC);
-    RegisterSniffer_l(SniffAMR);
-    RegisterSniffer_l(SniffMPEG2TS);
-    RegisterSniffer_l(SniffMP3);
-    RegisterSniffer_l(SniffAAC);
-    RegisterSniffer_l(SniffMPEG2PS);
-    RegisterSniffer_l(SniffMidi);
+    auto registerExtractors = [](const char *libDirPath) -> void {
+        DIR *libDir = opendir(libDirPath);
+        if (libDir) {
+            struct dirent* libEntry;
+            while ((libEntry = readdir(libDir))) {
+                String8 libPath = String8(libDirPath) + libEntry->d_name;
+                void *libHandle = dlopen(libPath.string(), RTLD_NOW | RTLD_LOCAL);
+                if (libHandle) {
+                    GetExtractorDef getsniffer = (GetExtractorDef) dlsym(libHandle, "GETEXTRACTORDEF");
+                    if (getsniffer) {
+                        ALOGV("registering sniffer for %s", libPath.string());
+                        RegisterSniffer_l(getsniffer());
+                    } else {
+                        ALOGW("%s does not contain sniffer", libPath.string());
+                        dlclose(libHandle);
+                    }
+                } else {
+                    ALOGW("couldn't dlopen(%s)", libPath.string());
+                }
+            }
+
+            closedir(libDir);
+        } else {
+            ALOGE("couldn't opendir(%s)", libDirPath);
+        }
+    };
+
+    registerExtractors("/system/lib"
+#ifdef __LP64__
+            "64"
+#endif
+            "/extractors/");
+
+    registerExtractors("/vendor/lib"
+#ifdef __LP64__
+            "64"
+#endif
+            "/extractors/");
 
     gSniffersRegistered = true;
 }
diff --git a/media/libstagefright/flac/dec/Android.bp b/media/libstagefright/flac/dec/Android.bp
index 1b9fe0f..bbbd8c0 100644
--- a/media/libstagefright/flac/dec/Android.bp
+++ b/media/libstagefright/flac/dec/Android.bp
@@ -30,7 +30,6 @@
     static_libs: ["libFLAC"],
 
     shared_libs: [
-        "libcutils",
         "liblog",
         "libstagefright_foundation",
         "libutils",
diff --git a/media/libstagefright/foundation/Android.bp b/media/libstagefright/foundation/Android.bp
index 221af1d..459ada1 100644
--- a/media/libstagefright/foundation/Android.bp
+++ b/media/libstagefright/foundation/Android.bp
@@ -13,6 +13,8 @@
     include_dirs: [
         "frameworks/av/include",
         "frameworks/native/include",
+        "frameworks/native/libs/arect/include",
+        "frameworks/native/libs/nativebase/include",
     ],
 
     local_include_dirs: [
@@ -30,7 +32,6 @@
 
     export_shared_lib_headers: [
         "libbinder",
-        "libui",
     ],
 
     cflags: [
@@ -42,7 +43,6 @@
     shared_libs: [
         "libbinder",
         "libutils",
-        "libui",
         "libcutils",
         "liblog",
         "libpowermanager",
diff --git a/media/libstagefright/http/Android.bp b/media/libstagefright/http/Android.bp
index 5d90b0a..2e49fc4 100644
--- a/media/libstagefright/http/Android.bp
+++ b/media/libstagefright/http/Android.bp
@@ -12,7 +12,6 @@
     shared_libs: [
         "liblog",
         "libutils",
-        "libbinder",
         "libandroid_runtime",
         "libmedia",
     ],
diff --git a/media/libstagefright/httplive/Android.bp b/media/libstagefright/httplive/Android.bp
index e415334..b10585e 100644
--- a/media/libstagefright/httplive/Android.bp
+++ b/media/libstagefright/httplive/Android.bp
@@ -39,5 +39,14 @@
         "libstagefright",
         "libstagefright_foundation",
         "libutils",
+        "libhidlbase",
+        "android.hardware.cas@1.0",
+        "android.hardware.cas.native@1.0",
     ],
+
+    static_libs: [
+        "libstagefright_id3",
+        "libstagefright_mpeg2support",
+    ],
+
 }
diff --git a/media/libstagefright/include/media/stagefright/MediaExtractor.h b/media/libstagefright/include/media/stagefright/MediaExtractor.h
index f8eb7fd..441c6d7 100644
--- a/media/libstagefright/include/media/stagefright/MediaExtractor.h
+++ b/media/libstagefright/include/media/stagefright/MediaExtractor.h
@@ -18,6 +18,8 @@
 
 #define MEDIA_EXTRACTOR_H_
 
+#include <stdio.h>
+
 #include <media/IMediaExtractor.h>
 #include <media/MediaAnalyticsItem.h>
 
@@ -76,6 +78,43 @@
     virtual const char * name() { return "<unspecified>"; }
 
     virtual void release() {}
+    typedef MediaExtractor* (*CreatorFunc)(
+            const sp<DataSource> &source, const sp<AMessage> &meta);
+
+    // The sniffer can optionally fill in "meta" with an AMessage containing
+    // a dictionary of values that helps the corresponding extractor initialize
+    // its state without duplicating effort already exerted by the sniffer.
+    typedef CreatorFunc (*SnifferFunc)(
+            const sp<DataSource> &source, String8 *mimeType,
+            float *confidence, sp<AMessage> *meta);
+
+    typedef struct {
+        const uint8_t b[16];
+    } uuid_t;
+
+    typedef struct {
+        // version number of this structure
+        const uint32_t def_version;
+
+        // A unique identifier for this extractor.
+        // See below for a convenience macro to create this from a string.
+        uuid_t extractor_uuid;
+
+        // Version number of this extractor. When two extractors with the same
+        // uuid are encountered, the one with the largest version number will
+        // be used.
+        const uint32_t extractor_version;
+
+        // a human readable name
+        const char *extractor_name;
+
+        // the sniffer function
+        const SnifferFunc sniff;
+    } ExtractorDef;
+
+    static const uint32_t EXTRACTORDEF_VERSION = 1;
+
+    typedef ExtractorDef (*GetExtractorDef)();
 
 protected:
     MediaExtractor();
@@ -87,20 +126,13 @@
 
 private:
 
-    typedef bool (*SnifferFunc)(
-            const sp<DataSource> &source, String8 *mimeType,
-            float *confidence, sp<AMessage> *meta);
-
     static Mutex gSnifferMutex;
-    static List<SnifferFunc> gSniffers;
+    static List<ExtractorDef> gSniffers;
     static bool gSniffersRegistered;
 
-    // The sniffer can optionally fill in "meta" with an AMessage containing
-    // a dictionary of values that helps the corresponding extractor initialize
-    // its state without duplicating effort already exerted by the sniffer.
-    static void RegisterSniffer_l(SnifferFunc func);
+    static void RegisterSniffer_l(const ExtractorDef &def);
 
-    static bool sniff(const sp<DataSource> &source,
+    static CreatorFunc sniff(const sp<DataSource> &source,
             String8 *mimeType, float *confidence, sp<AMessage> *meta);
 
     static void RegisterDefaultSniffers();
@@ -109,6 +141,68 @@
     MediaExtractor &operator=(const MediaExtractor &);
 };
 
+// purposely not defined anywhere so that this will fail to link if
+// expressions below are not evaluated at compile time
+int invalid_uuid_string(const char *);
+
+template <typename T, size_t N>
+constexpr uint8_t _digitAt_(const T (&s)[N], const size_t n) {
+    return s[n] >= '0' && s[n] <= '9' ? s[n] - '0'
+            : s[n] >= 'a' && s[n] <= 'f' ? s[n] - 'a' + 10
+                    : s[n] >= 'A' && s[n] <= 'F' ? s[n] - 'A' + 10
+                            : invalid_uuid_string("uuid: bad digits");
+}
+
+template <typename T, size_t N>
+constexpr uint8_t _hexByteAt_(const T (&s)[N], size_t n) {
+    return (_digitAt_(s, n) << 4) + _digitAt_(s, n + 1);
+}
+
+constexpr bool _assertIsDash_(char c) {
+    return c == '-' ? true : invalid_uuid_string("Wrong format");
+}
+
+template <size_t N>
+constexpr MediaExtractor::uuid_t constUUID(const char (&s) [N]) {
+    static_assert(N == 37, "uuid: wrong length");
+    return
+            _assertIsDash_(s[8]),
+            _assertIsDash_(s[13]),
+            _assertIsDash_(s[18]),
+            _assertIsDash_(s[23]),
+            MediaExtractor::uuid_t {{
+                _hexByteAt_(s, 0),
+                _hexByteAt_(s, 2),
+                _hexByteAt_(s, 4),
+                _hexByteAt_(s, 6),
+                _hexByteAt_(s, 9),
+                _hexByteAt_(s, 11),
+                _hexByteAt_(s, 14),
+                _hexByteAt_(s, 16),
+                _hexByteAt_(s, 19),
+                _hexByteAt_(s, 21),
+                _hexByteAt_(s, 24),
+                _hexByteAt_(s, 26),
+                _hexByteAt_(s, 28),
+                _hexByteAt_(s, 30),
+                _hexByteAt_(s, 32),
+                _hexByteAt_(s, 34),
+            }};
+}
+// Convenience macro to create a uuid_t from a string literal, which should
+// be formatted as "12345678-1234-1234-1234-123456789abc", as generated by
+// e.g. https://www.uuidgenerator.net/ or the 'uuidgen' linux command.
+// Hex digits may be upper or lower case.
+//
+// The macro call is otherwise equivalent to specifying the structure directly
+// (e.g. UUID("7d613858-5837-4a38-84c5-332d1cddee27") is the same as
+//       {{0x7d, 0x61, 0x38, 0x58, 0x58, 0x37, 0x4a, 0x38,
+//         0x84, 0xc5, 0x33, 0x2d, 0x1c, 0xdd, 0xee, 0x27}})
+
+#define UUID(str) []{ constexpr MediaExtractor::uuid_t uuid = constUUID(str); return uuid; }()
+
+
+
 }  // namespace android
 
 #endif  // MEDIA_EXTRACTOR_H_
diff --git a/media/libstagefright/mpeg2ts/Android.bp b/media/libstagefright/mpeg2ts/Android.bp
index 21259c4..7654eb3 100644
--- a/media/libstagefright/mpeg2ts/Android.bp
+++ b/media/libstagefright/mpeg2ts/Android.bp
@@ -1,5 +1,5 @@
 cc_library_static {
-    name: "libstagefright_mpeg2ts",
+    name: "libstagefright_mpeg2support",
 
     srcs: [
         "AnotherPacketSource.cpp",
@@ -7,8 +7,6 @@
         "CasManager.cpp",
         "ESQueue.cpp",
         "HlsSampleDecryptor.cpp",
-        "MPEG2PSExtractor.cpp",
-        "MPEG2TSExtractor.cpp",
     ],
 
     include_dirs: [
diff --git a/media/libstagefright/omx/Android.bp b/media/libstagefright/omx/Android.bp
index bec022a..0d6c696 100644
--- a/media/libstagefright/omx/Android.bp
+++ b/media/libstagefright/omx/Android.bp
@@ -58,16 +58,11 @@
         "libhidltransport",
         "libnativewindow", // TODO(b/62923479): use header library
         "libvndksupport",
-        "android.hidl.memory@1.0",
-        "android.hidl.token@1.0-utils",
-        "android.hardware.media@1.0",
         "android.hardware.media.omx@1.0",
-        "android.hardware.graphics.common@1.0",
         "android.hardware.graphics.bufferqueue@1.0",
     ],
 
     export_shared_lib_headers: [
-        "android.hidl.memory@1.0",
         "libmedia_omx",
         "libstagefright_foundation",
         "libstagefright_xmlparser",
diff --git a/media/libstagefright/xmlparser/Android.bp b/media/libstagefright/xmlparser/Android.bp
index 3507284..a4fa342 100644
--- a/media/libstagefright/xmlparser/Android.bp
+++ b/media/libstagefright/xmlparser/Android.bp
@@ -15,10 +15,7 @@
 
     shared_libs: [
         "libexpat",
-        "libutils",
         "liblog",
-        "libcutils",
-        "libstagefright_foundation",
         "libstagefright_omx_utils",
     ],
 
diff --git a/services/mediaextractor/Android.mk b/services/mediaextractor/Android.mk
index 1ebb7ff..2f7b7f7 100644
--- a/services/mediaextractor/Android.mk
+++ b/services/mediaextractor/Android.mk
@@ -14,6 +14,20 @@
 LOCAL_REQUIRED_MODULES_arm := mediaextractor.policy
 LOCAL_REQUIRED_MODULES_arm64 := mediaextractor.policy
 LOCAL_REQUIRED_MODULES_x86 := mediaextractor.policy
+
+# extractor libraries
+LOCAL_REQUIRED_MODULES := \
+    libaacextractor \
+    libamrextractor \
+    libflacextractor \
+    libmidiextractor \
+    libmkvextractor \
+    libmp3extractor \
+    libmp4extractor \
+    libmpeg2extractor \
+    liboggextractor \
+    libwavextractor \
+
 LOCAL_SRC_FILES := main_extractorservice.cpp
 LOCAL_SHARED_LIBRARIES := libmedia libmediaextractorservice libbinder libutils \
     liblog libbase libicuuc libavservices_minijail
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy b/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy
index d1278a9..438a332 100644
--- a/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy
@@ -33,6 +33,12 @@
 # for FileSource
 readlinkat: 1
 
+# for dynamically loading extractors
+getdents64: 1
+readlinkat: 1
+pread64: 1
+mremap: 1
+
 # for attaching to debuggerd on process crash
 tgkill: 1
 rt_sigprocmask: 1
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy b/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy
index 3b37f92..ede108e 100644
--- a/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy
@@ -39,6 +39,12 @@
 nanosleep: 1
 getrandom: 1
 
+# for dynamically loading extractors
+getdents64: 1
+readlinkat: 1
+pread64: 1
+mremap: 1
+
 # for FileSource
 readlinkat: 1
 _llseek: 1