Remove libmedia and libstagefright dependency from extractors
- MediaSource, DataSource and MediaExtractor are moved to
libmediaextractor so that they can be used by extractor
implementations without depending on libmedia and libstagefright.
- XXXFactory classes has been added in order not to expose CreateXXX
methods in libmediaextractor.
- avc_utils is moved to libstagefright_foundation since most of
extractor implementations are relying on that.
Test: build + post submit media CTS tests
Bug: 65851881
Change-Id: I7d5cf18dd25abc10478ac3f6e7d1828ad023e3fb
diff --git a/media/libmediaextractor/Android.bp b/media/libmediaextractor/Android.bp
new file mode 100644
index 0000000..c57cd41
--- /dev/null
+++ b/media/libmediaextractor/Android.bp
@@ -0,0 +1,42 @@
+cc_library_shared {
+ name: "libmediaextractor",
+ include_dirs: [
+ "frameworks/av/include",
+ "frameworks/av/media/libmediaextractor/include",
+ ],
+
+ export_include_dirs: ["include"],
+
+ cflags: [
+ "-Wno-multichar",
+ "-Werror",
+ "-Wall",
+ ],
+
+ shared_libs: [
+ "libmediametrics",
+ "libstagefright_foundation",
+ "libutils",
+ "libcutils",
+ "liblog",
+ ],
+
+ srcs: [
+ "DataSource.cpp",
+ "MediaSource.cpp",
+ "MediaExtractor.cpp",
+ ],
+
+ clang: true,
+
+ sanitize: {
+ misc_undefined: [
+ "unsigned-integer-overflow",
+ "signed-integer-overflow",
+ ],
+ cfi: true,
+ diag: {
+ cfi: true,
+ },
+ },
+}
diff --git a/media/libmediaextractor/DataSource.cpp b/media/libmediaextractor/DataSource.cpp
index e9aaa84..c22e4cb 100644
--- a/media/libmediaextractor/DataSource.cpp
+++ b/media/libmediaextractor/DataSource.cpp
@@ -16,28 +16,12 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "DataSource"
-#include "include/CallbackDataSource.h"
-#include "include/HTTPBase.h"
-#include "include/NuCachedSource2.h"
-
+#include <media/DataSource.h>
#include <media/IDataSource.h>
-#include <media/IMediaHTTPConnection.h>
-#include <media/IMediaHTTPService.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/ByteUtils.h>
-#include <media/stagefright/DataSource.h>
-#include <media/stagefright/DataURISource.h>
-#include <media/stagefright/FileSource.h>
#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaHTTP.h>
-#include <media/stagefright/RemoteDataSource.h>
#include <utils/String8.h>
-#include <cutils/properties.h>
-
-#include <private/android_filesystem_config.h>
-
namespace android {
bool DataSource::getUInt16(off64_t offset, uint16_t *x) {
@@ -144,103 +128,8 @@
return nullptr;
}
-////////////////////////////////////////////////////////////////////////////////
-
-// static
-sp<DataSource> DataSource::CreateFromURI(
- const sp<IMediaHTTPService> &httpService,
- const char *uri,
- const KeyedVector<String8, String8> *headers,
- String8 *contentType,
- HTTPBase *httpSource) {
- if (contentType != NULL) {
- *contentType = "";
- }
-
- sp<DataSource> source;
- if (!strncasecmp("file://", uri, 7)) {
- source = new FileSource(uri + 7);
- } else if (!strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8)) {
- if (httpService == NULL) {
- ALOGE("Invalid http service!");
- return NULL;
- }
-
- if (httpSource == NULL) {
- sp<IMediaHTTPConnection> conn = httpService->makeHTTPConnection();
- if (conn == NULL) {
- ALOGE("Failed to make http connection from http service!");
- return NULL;
- }
- httpSource = new MediaHTTP(conn);
- }
-
- String8 cacheConfig;
- bool disconnectAtHighwatermark = false;
- KeyedVector<String8, String8> nonCacheSpecificHeaders;
- if (headers != NULL) {
- nonCacheSpecificHeaders = *headers;
- NuCachedSource2::RemoveCacheSpecificHeaders(
- &nonCacheSpecificHeaders,
- &cacheConfig,
- &disconnectAtHighwatermark);
- }
-
- if (httpSource->connect(uri, &nonCacheSpecificHeaders) != OK) {
- ALOGE("Failed to connect http source!");
- return NULL;
- }
-
- if (contentType != NULL) {
- *contentType = httpSource->getMIMEType();
- }
-
- source = NuCachedSource2::Create(
- httpSource,
- cacheConfig.isEmpty() ? NULL : cacheConfig.string(),
- disconnectAtHighwatermark);
- } else if (!strncasecmp("data:", uri, 5)) {
- source = DataURISource::Create(uri);
- } else {
- // Assume it's a filename.
- source = new FileSource(uri);
- }
-
- if (source == NULL || source->initCheck() != OK) {
- return NULL;
- }
-
- return source;
-}
-
-sp<DataSource> DataSource::CreateFromFd(int fd, int64_t offset, int64_t length) {
- sp<FileSource> source = new FileSource(fd, offset, length);
- return source->initCheck() != OK ? nullptr : source;
-}
-
-sp<DataSource> DataSource::CreateMediaHTTP(const sp<IMediaHTTPService> &httpService) {
- if (httpService == NULL) {
- return NULL;
- }
-
- sp<IMediaHTTPConnection> conn = httpService->makeHTTPConnection();
- if (conn == NULL) {
- return NULL;
- } else {
- return new MediaHTTP(conn);
- }
-}
-
-sp<DataSource> DataSource::CreateFromIDataSource(const sp<IDataSource> &source) {
- return new TinyCacheSource(new CallbackDataSource(source));
-}
-
String8 DataSource::getMIMEType() const {
return String8("application/octet-stream");
}
-sp<IDataSource> DataSource::asIDataSource() {
- return RemoteDataSource::wrap(sp<DataSource>(this));
-}
-
} // namespace android
diff --git a/media/libmediaextractor/MediaExtractor.cpp b/media/libmediaextractor/MediaExtractor.cpp
index cc2fa63..6ba7c0e 100644
--- a/media/libmediaextractor/MediaExtractor.cpp
+++ b/media/libmediaextractor/MediaExtractor.cpp
@@ -17,42 +17,17 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "MediaExtractor"
#include <utils/Log.h>
-#include <inttypes.h>
#include <pwd.h>
-#include <binder/IServiceManager.h>
-#include <binder/MemoryDealer.h>
-
#include <media/MediaAnalyticsItem.h>
+#include <media/MediaExtractor.h>
#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/DataSource.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaExtractor.h>
#include <media/stagefright/MetaData.h>
-#include <media/stagefright/RemoteMediaExtractor.h>
-#include <media/IMediaExtractor.h>
-#include <media/IMediaExtractorService.h>
-#include <media/IMediaSource.h>
-#include <cutils/properties.h>
-#include <utils/String8.h>
-#include <private/android_filesystem_config.h>
-
-// still doing some on/off toggling here.
-#define MEDIA_LOG 1
-
-#include <sys/types.h>
-#include <dirent.h>
-#include <dlfcn.h>
namespace android {
// key for media statistics
static const char *kKeyExtractor = "extractor";
-// attrs for media statistics
-static const char *kExtractorMime = "android.media.mediaextractor.mime";
-static const char *kExtractorTracks = "android.media.mediaextractor.ntrk";
-static const char *kExtractorFormat = "android.media.mediaextractor.fmt";
MediaExtractor::MediaExtractor() {
if (!LOG_NDEBUG) {
@@ -85,10 +60,6 @@
}
}
-sp<IMediaExtractor> MediaExtractor::asIMediaExtractor() {
- return RemoteMediaExtractor::wrap(sp<MediaExtractor>(this));
-}
-
sp<MetaData> MediaExtractor::getMetaData() {
return new MetaData;
}
@@ -114,213 +85,4 @@
return CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_PAUSE | CAN_SEEK;
}
-// static
-sp<IMediaExtractor> MediaExtractor::Create(
- const sp<DataSource> &source, const char *mime) {
- ALOGV("MediaExtractor::Create %s", mime);
-
- if (!property_get_bool("media.stagefright.extractremote", true)) {
- // local extractor
- ALOGW("creating media extractor in calling process");
- sp<MediaExtractor> extractor = CreateFromService(source, mime);
- return (extractor.get() == nullptr) ? nullptr : extractor->asIMediaExtractor();
- } else {
- // remote extractor
- ALOGV("get service manager");
- sp<IBinder> binder = defaultServiceManager()->getService(String16("media.extractor"));
-
- if (binder != 0) {
- sp<IMediaExtractorService> mediaExService(interface_cast<IMediaExtractorService>(binder));
- sp<IMediaExtractor> ex = mediaExService->makeExtractor(source->asIDataSource(), mime);
- return ex;
- } else {
- ALOGE("extractor service not running");
- return NULL;
- }
- }
- return NULL;
-}
-
-sp<MediaExtractor> MediaExtractor::CreateFromService(
- const sp<DataSource> &source, const char *mime) {
-
- ALOGV("MediaExtractor::CreateFromService %s", mime);
- RegisterDefaultSniffers();
-
- // initialize source decryption if needed
- source->DrmInitialization(nullptr /* mime */);
-
- sp<AMessage> meta;
-
- CreatorFunc creator = NULL;
- String8 tmp;
- float confidence;
- creator = sniff(source, &tmp, &confidence, &meta);
- if (!creator) {
- ALOGV("FAILED to autodetect media content.");
- return NULL;
- }
-
- mime = tmp.string();
- ALOGV("Autodetected media content as '%s' with confidence %.2f",
- mime, confidence);
-
- MediaExtractor *ret = creator(source, meta);
-
- if (ret != NULL) {
- // track the container format (mpeg, aac, wvm, etc)
- if (MEDIA_LOG) {
- if (ret->mAnalyticsItem != NULL) {
- size_t ntracks = ret->countTracks();
- ret->mAnalyticsItem->setCString(kExtractorFormat, ret->name());
- // tracks (size_t)
- ret->mAnalyticsItem->setInt32(kExtractorTracks, ntracks);
- // metadata
- sp<MetaData> pMetaData = ret->getMetaData();
- if (pMetaData != NULL) {
- String8 xx = pMetaData->toString();
- // 'titl' -- but this verges into PII
- // 'mime'
- const char *mime = NULL;
- if (pMetaData->findCString(kKeyMIMEType, &mime)) {
- ret->mAnalyticsItem->setCString(kExtractorMime, mime);
- }
- // what else is interesting and not already available?
- }
- }
- }
- }
-
- return ret;
-}
-
-Mutex MediaExtractor::gSnifferMutex;
-List<MediaExtractor::ExtractorDef> MediaExtractor::gSniffers;
-bool MediaExtractor::gSniffersRegistered = false;
-
-// static
-MediaExtractor::CreatorFunc MediaExtractor::sniff(
- const sp<DataSource> &source, String8 *mimeType, float *confidence, sp<AMessage> *meta) {
- *mimeType = "";
- *confidence = 0.0f;
- meta->clear();
-
- {
- Mutex::Autolock autoLock(gSnifferMutex);
- if (!gSniffersRegistered) {
- return NULL;
- }
- }
-
- 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 ((curCreator = (*it).sniff(source, &newMimeType, &newConfidence, &newMeta))) {
- if (newConfidence > *confidence) {
- *mimeType = newMimeType;
- *confidence = newConfidence;
- *meta = newMeta;
- bestCreator = curCreator;
- }
- }
- }
-
- return bestCreator;
-}
-
-// static
-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;
- }
-
- 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
-void MediaExtractor::RegisterDefaultSniffers() {
- Mutex::Autolock autoLock(gSnifferMutex);
- if (gSniffersRegistered) {
- return;
- }
-
- 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;
-}
-
-
} // namespace android
diff --git a/media/libmediaextractor/MediaSource.cpp b/media/libmediaextractor/MediaSource.cpp
index 8b92a6b..8038a59 100644
--- a/media/libmediaextractor/MediaSource.cpp
+++ b/media/libmediaextractor/MediaSource.cpp
@@ -14,9 +14,8 @@
* limitations under the License.
*/
-#include <media/stagefright/CallbackMediaSource.h>
-#include <media/stagefright/MediaSource.h>
-#include <media/stagefright/RemoteMediaSource.h>
+#include <media/MediaSource.h>
+#include <media/IMediaSource.h>
namespace android {
@@ -24,16 +23,56 @@
MediaSource::~MediaSource() {}
-// static
-sp<MediaSource> MediaSource::CreateFromIMediaSource(const sp<IMediaSource> &source) {
- if (source == nullptr) {
- return nullptr;
- }
- return new CallbackMediaSource(source);
+////////////////////////////////////////////////////////////////////////////////
+
+MediaSource::ReadOptions::ReadOptions() {
+ reset();
}
-sp<IMediaSource> MediaSource::asIMediaSource() {
- return RemoteMediaSource::wrap(sp<MediaSource>(this));
+void MediaSource::ReadOptions::reset() {
+ mOptions = 0;
+ mSeekTimeUs = 0;
+ mLatenessUs = 0;
+ mNonBlocking = false;
+}
+
+void MediaSource::ReadOptions::setNonBlocking() {
+ mNonBlocking = true;
+}
+
+void MediaSource::ReadOptions::clearNonBlocking() {
+ mNonBlocking = false;
+}
+
+bool MediaSource::ReadOptions::getNonBlocking() const {
+ return mNonBlocking;
+}
+
+void MediaSource::ReadOptions::setSeekTo(int64_t time_us, SeekMode mode) {
+ mOptions |= kSeekTo_Option;
+ mSeekTimeUs = time_us;
+ mSeekMode = mode;
+}
+
+void MediaSource::ReadOptions::clearSeekTo() {
+ mOptions &= ~kSeekTo_Option;
+ mSeekTimeUs = 0;
+ mSeekMode = SEEK_CLOSEST_SYNC;
+}
+
+bool MediaSource::ReadOptions::getSeekTo(
+ int64_t *time_us, SeekMode *mode) const {
+ *time_us = mSeekTimeUs;
+ *mode = mSeekMode;
+ return (mOptions & kSeekTo_Option) != 0;
+}
+
+void MediaSource::ReadOptions::setLateBy(int64_t lateness_us) {
+ mLatenessUs = lateness_us;
+}
+
+int64_t MediaSource::ReadOptions::getLateBy() const {
+ return mLatenessUs;
}
} // namespace android
diff --git a/media/libmediaextractor/include/media/DataSource.h b/media/libmediaextractor/include/media/DataSource.h
index bd863ba..e917f4e 100644
--- a/media/libmediaextractor/include/media/DataSource.h
+++ b/media/libmediaextractor/include/media/DataSource.h
@@ -47,17 +47,6 @@
kIsLocalFileSource = 16,
};
- static sp<DataSource> CreateFromURI(
- const sp<IMediaHTTPService> &httpService,
- const char *uri,
- const KeyedVector<String8, String8> *headers = NULL,
- String8 *contentType = NULL,
- HTTPBase *httpSource = NULL);
-
- static sp<DataSource> CreateMediaHTTP(const sp<IMediaHTTPService> &httpService);
- static sp<DataSource> CreateFromIDataSource(const sp<IDataSource> &source);
- static sp<DataSource> CreateFromFd(int fd, int64_t offset, int64_t length);
-
DataSource() {}
virtual status_t initCheck() const = 0;
@@ -123,9 +112,6 @@
virtual void close() {};
- // creates an IDataSource wrapper to the DataSource.
- virtual sp<IDataSource> asIDataSource();
-
// returns a pointer to IDataSource if it is wrapped.
virtual sp<IDataSource> getIDataSource() const;
diff --git a/media/libmediaextractor/include/media/MediaExtractor.h b/media/libmediaextractor/include/media/MediaExtractor.h
index 441c6d7..2dcced3 100644
--- a/media/libmediaextractor/include/media/MediaExtractor.h
+++ b/media/libmediaextractor/include/media/MediaExtractor.h
@@ -19,23 +19,29 @@
#define MEDIA_EXTRACTOR_H_
#include <stdio.h>
+#include <vector>
-#include <media/IMediaExtractor.h>
-#include <media/MediaAnalyticsItem.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+
+// still doing some on/off toggling here.
+#define MEDIA_LOG 1
namespace android {
class DataSource;
-struct MediaSource;
+class IMediaSource;
+class MediaAnalyticsItem;
+class MediaExtractorFactory;
class MetaData;
+class Parcel;
+class String8;
+struct AMessage;
+struct MediaSource;
+typedef std::vector<uint8_t> HInterfaceToken;
class MediaExtractor : public RefBase {
public:
- static sp<IMediaExtractor> Create(
- const sp<DataSource> &source, const char *mime = NULL);
- static sp<MediaExtractor> CreateFromService(
- const sp<DataSource> &source, const char *mime = NULL);
-
virtual size_t countTracks() = 0;
virtual sp<MediaSource> getTrack(size_t index) = 0;
@@ -62,9 +68,6 @@
// CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK | CAN_PAUSE
virtual uint32_t flags() const;
- // Creates an IMediaExtractor wrapper to this MediaExtractor.
- virtual sp<IMediaExtractor> asIMediaExtractor();
-
// for DRM
virtual char* getDrmTrackInfo(size_t /*trackID*/, int * /*len*/) {
return NULL;
@@ -125,20 +128,9 @@
virtual void populateMetrics();
private:
-
- static Mutex gSnifferMutex;
- static List<ExtractorDef> gSniffers;
- static bool gSniffersRegistered;
-
- static void RegisterSniffer_l(const ExtractorDef &def);
-
- static CreatorFunc sniff(const sp<DataSource> &source,
- String8 *mimeType, float *confidence, sp<AMessage> *meta);
-
- static void RegisterDefaultSniffers();
-
MediaExtractor(const MediaExtractor &);
MediaExtractor &operator=(const MediaExtractor &);
+ friend class MediaExtractorFactory;
};
// purposely not defined anywhere so that this will fail to link if
diff --git a/media/libmediaextractor/include/media/MediaSource.h b/media/libmediaextractor/include/media/MediaSource.h
index 7e30e30..749a4df 100644
--- a/media/libmediaextractor/include/media/MediaSource.h
+++ b/media/libmediaextractor/include/media/MediaSource.h
@@ -20,7 +20,8 @@
#include <sys/types.h>
-#include <media/IMediaSource.h>
+#include <binder/IMemory.h>
+#include <binder/MemoryDealer.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
#include <utils/RefBase.h>
@@ -33,15 +34,6 @@
class IMediaSource;
struct MediaSource : public virtual RefBase {
- // TODO: Move ReadOptions implementation from IMediaSource to MediaSource
- // once this class moves to a separate extractor lib on which both libmedia
- // and libstagefright rely. For now, alias is added to avoid circular
- // dependency.
- using ReadOptions = IMediaSource::ReadOptions;
-
- // Creates a MediaSource which wraps the given IMediaSource object.
- static sp<MediaSource> CreateFromIMediaSource(const sp<IMediaSource> &source);
-
MediaSource();
// To be called before any other methods on this object, except
@@ -59,6 +51,51 @@
// Returns the format of the data output by this media source.
virtual sp<MetaData> getFormat() = 0;
+ // Options that modify read() behaviour. The default is to
+ // a) not request a seek
+ // b) not be late, i.e. lateness_us = 0
+ struct ReadOptions {
+ enum SeekMode : int32_t {
+ SEEK_PREVIOUS_SYNC,
+ SEEK_NEXT_SYNC,
+ SEEK_CLOSEST_SYNC,
+ SEEK_CLOSEST,
+ };
+
+ ReadOptions();
+
+ // Reset everything back to defaults.
+ void reset();
+
+ void setSeekTo(int64_t time_us, SeekMode mode = SEEK_CLOSEST_SYNC);
+ void clearSeekTo();
+ bool getSeekTo(int64_t *time_us, SeekMode *mode) const;
+
+ // TODO: remove this if unused.
+ void setLateBy(int64_t lateness_us);
+ int64_t getLateBy() const;
+
+ void setNonBlocking();
+ void clearNonBlocking();
+ bool getNonBlocking() const;
+
+ // Used to clear all non-persistent options for multiple buffer reads.
+ void clearNonPersistent() {
+ clearSeekTo();
+ }
+
+ private:
+ enum Options {
+ kSeekTo_Option = 1,
+ };
+
+ uint32_t mOptions;
+ int64_t mSeekTimeUs;
+ SeekMode mSeekMode;
+ int64_t mLatenessUs;
+ bool mNonBlocking;
+ } __attribute__((packed)); // sent through Binder
+
// Returns a new buffer of data. Call blocks until a
// buffer is available, an error is encountered of the end of the stream
// is reached.
@@ -103,9 +140,6 @@
return ERROR_UNSUPPORTED;
}
- // Creates an IMediaSource wrapper to this MediaSource.
- virtual sp<IMediaSource> asIMediaSource();
-
protected:
virtual ~MediaSource();