Extractor service
Run extractors in a separate process. Currently all data is copied through a
binder transaction, and WVMExtractor is still run in the mediaserver process.
Change-Id: Ic5dbce87126dd321ad792f4dd540c2ff6b068d13
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index be88aa0..285c33e 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -33,11 +33,14 @@
IMediaHTTPConnection.cpp \
IMediaHTTPService.cpp \
IMediaLogService.cpp \
+ IMediaExtractor.cpp \
+ IMediaExtractorService.cpp \
IMediaPlayerService.cpp \
IMediaPlayerClient.cpp \
IMediaRecorderClient.cpp \
IMediaPlayer.cpp \
IMediaRecorder.cpp \
+ IMediaSource.cpp \
IRemoteDisplay.cpp \
IRemoteDisplayClient.cpp \
IResourceManagerClient.cpp \
diff --git a/media/libmedia/IMediaExtractor.cpp b/media/libmedia/IMediaExtractor.cpp
new file mode 100644
index 0000000..85362fd
--- /dev/null
+++ b/media/libmedia/IMediaExtractor.cpp
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2009 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 "BpMediaExtractor"
+#include <utils/Log.h>
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <binder/Parcel.h>
+#include <media/IMediaExtractor.h>
+#include <media/stagefright/MetaData.h>
+
+namespace android {
+
+enum {
+ COUNTTRACKS = IBinder::FIRST_CALL_TRANSACTION,
+ GETTRACK,
+ GETTRACKMETADATA,
+ GETMETADATA,
+ FLAGS,
+ SETDRMFLAG,
+ GETDRMFLAG,
+ GETDRMTRACKINFO,
+ SETUID,
+ NAME
+};
+
+class BpMediaExtractor : public BpInterface<IMediaExtractor> {
+public:
+ BpMediaExtractor(const sp<IBinder>& impl)
+ : BpInterface<IMediaExtractor>(impl)
+ {
+ }
+
+ virtual size_t countTracks() {
+ ALOGV("countTracks");
+ Parcel data, reply;
+ data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
+ status_t ret = remote()->transact(COUNTTRACKS, data, &reply);
+ size_t numTracks = 0;
+ if (ret == NO_ERROR) {
+ numTracks = reply.readUint32();
+ }
+ return numTracks;
+ }
+ virtual sp<IMediaSource> getTrack(size_t index) {
+ ALOGV("getTrack(%zu)", index);
+ Parcel data, reply;
+ data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
+ data.writeUint32(index);
+ status_t ret = remote()->transact(GETTRACK, data, &reply);
+ if (ret == NO_ERROR) {
+ return interface_cast<IMediaSource>(reply.readStrongBinder());
+ }
+ return NULL;
+ }
+
+ virtual sp<MetaData> getTrackMetaData(
+ size_t index, uint32_t flags) {
+ ALOGV("getTrackMetaData(%zu, %u)", index, flags);
+ Parcel data, reply;
+ data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
+ data.writeUint32(index);
+ data.writeUint32(flags);
+ status_t ret = remote()->transact(GETTRACKMETADATA, data, &reply);
+ if (ret == NO_ERROR) {
+ return MetaData::createFromParcel(reply);
+ }
+ return NULL;
+ }
+
+ virtual sp<MetaData> getMetaData() {
+ ALOGV("getMetaData");
+ Parcel data, reply;
+ data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
+ status_t ret = remote()->transact(GETMETADATA, data, &reply);
+ if (ret == NO_ERROR) {
+ return MetaData::createFromParcel(reply);
+ }
+ return NULL;
+ }
+
+ virtual uint32_t flags() const {
+ ALOGV("flags NOT IMPLEMENTED");
+ return 0;
+ }
+
+ virtual void setDrmFlag(bool flag __unused) {
+ ALOGV("setDrmFlag NOT IMPLEMENTED");
+ }
+ virtual bool getDrmFlag() {
+ ALOGV("getDrmFlag NOT IMPLEMENTED");
+ return false;
+ }
+ virtual char* getDrmTrackInfo(size_t trackID __unused, int *len __unused) {
+ ALOGV("getDrmTrackInfo NOT IMPLEMENTED");
+ return NULL;
+ }
+ virtual void setUID(uid_t uid __unused) {
+ ALOGV("setUID NOT IMPLEMENTED");
+ }
+
+ virtual const char * name() {
+ ALOGV("name NOT IMPLEMENTED");
+ return NULL;
+ }
+};
+
+IMPLEMENT_META_INTERFACE(MediaExtractor, "android.media.IMediaExtractor");
+
+#undef LOG_TAG
+#define LOG_TAG "BnMediaExtractor"
+
+status_t BnMediaExtractor::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch (code) {
+ case COUNTTRACKS: {
+ ALOGV("countTracks");
+ CHECK_INTERFACE(IMediaExtractor, data, reply);
+ size_t numTracks = countTracks();
+ if (numTracks > INT32_MAX) {
+ numTracks = 0;
+ }
+ reply->writeUint32(uint32_t(numTracks));
+ return NO_ERROR;
+ }
+ case GETTRACK: {
+ ALOGV("getTrack()");
+ CHECK_INTERFACE(IMediaExtractor, data, reply);
+ uint32_t idx;
+ if (data.readUint32(&idx) == NO_ERROR) {
+ return reply->writeStrongBinder(IInterface::asBinder(getTrack((size_t(idx)))));
+ }
+ return UNKNOWN_ERROR;
+ }
+ case GETTRACKMETADATA: {
+ ALOGV("getTrackMetaData");
+ CHECK_INTERFACE(IMediaExtractor, data, reply);
+ uint32_t idx;
+ uint32_t flags;
+ if (data.readUint32(&idx) == NO_ERROR &&
+ data.readUint32(&flags) == NO_ERROR) {
+ sp<MetaData> meta = getTrackMetaData(idx, flags);
+ meta->writeToParcel(*reply);
+ return NO_ERROR;
+ }
+ return UNKNOWN_ERROR;
+ }
+ case GETMETADATA: {
+ ALOGV("getMetaData");
+ CHECK_INTERFACE(IMediaExtractor, data, reply);
+ sp<MetaData> meta = getMetaData();
+ if (meta != NULL) {
+ meta->writeToParcel(*reply);
+ return NO_ERROR;
+ }
+ return UNKNOWN_ERROR;
+ }
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+
+} // namespace android
+
diff --git a/media/libmedia/IMediaExtractorService.cpp b/media/libmedia/IMediaExtractorService.cpp
new file mode 100644
index 0000000..51a3c1a
--- /dev/null
+++ b/media/libmedia/IMediaExtractorService.cpp
@@ -0,0 +1,81 @@
+/*
+**
+** Copyright 2007, 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_TAG "IMediaExtractorService"
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <binder/Parcel.h>
+#include <media/IMediaExtractorService.h>
+
+namespace android {
+
+enum {
+ MAKE_EXTRACTOR = IBinder::FIRST_CALL_TRANSACTION
+};
+
+class BpMediaExtractorService : public BpInterface<IMediaExtractorService>
+{
+public:
+ BpMediaExtractorService(const sp<IBinder>& impl)
+ : BpInterface<IMediaExtractorService>(impl)
+ {
+ }
+
+ virtual sp<IMediaExtractor> makeExtractor(const sp<IDataSource> &source, const char *mime) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaExtractorService::getInterfaceDescriptor());
+ data.writeStrongBinder(IInterface::asBinder(source));
+ if (mime != NULL) {
+ data.writeCString(mime);
+ }
+ status_t ret = remote()->transact(MAKE_EXTRACTOR, data, &reply);
+ if (ret == NO_ERROR) {
+ return interface_cast<IMediaExtractor>(reply.readStrongBinder());
+ }
+ return NULL;
+ }
+
+};
+
+IMPLEMENT_META_INTERFACE(MediaExtractorService, "android.media.IMediaExtractorService");
+
+// ----------------------------------------------------------------------
+
+status_t BnMediaExtractorService::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch (code) {
+
+ case MAKE_EXTRACTOR: {
+ CHECK_INTERFACE(IMediaExtractorService, data, reply);
+ sp<IDataSource> source = interface_cast<IDataSource>(data.readStrongBinder());
+ const char *mime = data.readCString();
+ sp<IMediaExtractor> ex = makeExtractor(source, mime);
+ reply->writeStrongBinder(IInterface::asBinder(ex));
+ return NO_ERROR;
+ }
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+} // namespace android
diff --git a/media/libmedia/IMediaSource.cpp b/media/libmedia/IMediaSource.cpp
new file mode 100644
index 0000000..aec6255
--- /dev/null
+++ b/media/libmedia/IMediaSource.cpp
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2009 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 "BpMediaSource"
+#include <utils/Log.h>
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <binder/Parcel.h>
+#include <media/IMediaSource.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+
+namespace android {
+
+enum {
+ START = IBinder::FIRST_CALL_TRANSACTION,
+ STOP,
+ PAUSE,
+ GETFORMAT,
+ READ
+};
+
+class BpMediaSource : public BpInterface<IMediaSource> {
+public:
+ BpMediaSource(const sp<IBinder>& impl)
+ : BpInterface<IMediaSource>(impl)
+ {
+ }
+
+ virtual status_t start(MetaData *params) {
+ ALOGV("start");
+ Parcel data, reply;
+ data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
+ if (params) {
+ params->writeToParcel(data);
+ }
+ status_t ret = remote()->transact(START, data, &reply);
+ if (ret == NO_ERROR && params) {
+ ALOGW("ignoring potentially modified MetaData from start");
+ ALOGW("input:");
+ params->dumpToLog();
+ sp<MetaData> meta = MetaData::createFromParcel(reply);
+ ALOGW("output:");
+ meta->dumpToLog();
+ }
+ return ret;
+ }
+
+ virtual status_t stop() {
+ ALOGV("stop");
+ Parcel data, reply;
+ data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
+ return remote()->transact(STOP, data, &reply);
+ }
+
+ virtual sp<MetaData> getFormat() {
+ ALOGV("getFormat");
+ Parcel data, reply;
+ data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
+ status_t ret = remote()->transact(GETFORMAT, data, &reply);
+ if (ret == NO_ERROR) {
+ mMetaData = MetaData::createFromParcel(reply);
+ return mMetaData;
+ }
+ return NULL;
+ }
+
+ virtual status_t read(MediaBuffer **buffer, const ReadOptions *options) {
+ ALOGV("read");
+ Parcel data, reply;
+ data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
+ if (options) {
+ data.writeByteArray(sizeof(*options), (uint8_t*) options);
+ }
+ status_t ret = remote()->transact(READ, data, &reply);
+ if (ret != NO_ERROR) {
+ return ret;
+ }
+ // wrap the returned data in a MediaBuffer
+ // XXX use a group, and use shared memory for transfer
+ ret = reply.readInt32();
+ int32_t len = reply.readInt32();
+ if (len < 0) {
+ ALOGV("got status %d and len %d, returning NULL buffer", ret, len);
+ *buffer = NULL;
+ } else {
+ ALOGV("got status %d and len %d", ret, len);
+ *buffer = new MediaBuffer(len);
+ reply.read((*buffer)->data(), len);
+ (*buffer)->meta_data()->updateFromParcel(reply);
+ }
+ return ret;
+ }
+
+ virtual status_t pause() {
+ ALOGV("pause");
+ Parcel data, reply;
+ data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
+ return remote()->transact(PAUSE, data, &reply);
+ }
+
+ virtual status_t setBuffers(const Vector<MediaBuffer *> & buffers __unused) {
+ ALOGV("setBuffers NOT IMPLEMENTED");
+ return ERROR_UNSUPPORTED; // default
+ }
+
+private:
+ // NuPlayer passes pointers-to-metadata around, so we use this to keep the metadata alive
+ // XXX: could we use this for caching, or does metadata change on the fly?
+ sp<MetaData> mMetaData;
+
+};
+
+IMPLEMENT_META_INTERFACE(MediaSource, "android.media.IMediaSource");
+
+#undef LOG_TAG
+#define LOG_TAG "BnMediaSource"
+
+status_t BnMediaSource::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch (code) {
+ case START: {
+ ALOGV("start");
+ CHECK_INTERFACE(IMediaSource, data, reply);
+ sp<MetaData> meta;
+ if (data.dataAvail()) {
+ meta = MetaData::createFromParcel(data);
+ }
+ status_t ret = start(meta.get());
+ if (ret == NO_ERROR && meta != NULL) {
+ meta->writeToParcel(*reply);
+ }
+ return ret;
+ }
+ case STOP: {
+ ALOGV("stop");
+ CHECK_INTERFACE(IMediaSource, data, reply);
+ return stop();
+ }
+ case PAUSE: {
+ ALOGV("pause");
+ CHECK_INTERFACE(IMediaSource, data, reply);
+ return pause();
+ }
+ case GETFORMAT: {
+ ALOGV("getFormat");
+ CHECK_INTERFACE(IMediaSource, data, reply);
+ sp<MetaData> meta = getFormat();
+ if (meta != NULL) {
+ meta->writeToParcel(*reply);
+ return NO_ERROR;
+ }
+ return UNKNOWN_ERROR;
+ }
+ case READ: {
+ ALOGV("read");
+ CHECK_INTERFACE(IMediaSource, data, reply);
+ status_t ret;
+ MediaBuffer *buf = NULL;
+ ReadOptions opts;
+ uint32_t len;
+ if (data.readUint32(&len) == NO_ERROR &&
+ len == sizeof(opts) && data.read((void*)&opts, len) == NO_ERROR) {
+ ret = read(&buf, &opts);
+ } else {
+ ret = read(&buf, NULL);
+ }
+ // return data inside binder for now
+ // XXX return data using shared memory
+ reply->writeInt32(ret);
+ if (buf != NULL) {
+ ALOGV("ret %d, buflen %zu", ret, buf->range_length());
+ reply->writeByteArray(buf->range_length(), (uint8_t*)buf->data() + buf->range_offset());
+ buf->meta_data()->writeToParcel(*reply);
+ buf->release();
+ } else {
+ ALOGV("ret %d, buf %p", ret, buf);
+ reply->writeInt32(-1);
+ }
+ return NO_ERROR;
+ }
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+IMediaSource::ReadOptions::ReadOptions() {
+ reset();
+}
+
+void IMediaSource::ReadOptions::reset() {
+ mOptions = 0;
+ mSeekTimeUs = 0;
+ mLatenessUs = 0;
+ mNonBlocking = false;
+}
+
+void IMediaSource::ReadOptions::setNonBlocking() {
+ mNonBlocking = true;
+}
+
+void IMediaSource::ReadOptions::clearNonBlocking() {
+ mNonBlocking = false;
+}
+
+bool IMediaSource::ReadOptions::getNonBlocking() const {
+ return mNonBlocking;
+}
+
+void IMediaSource::ReadOptions::setSeekTo(int64_t time_us, SeekMode mode) {
+ mOptions |= kSeekTo_Option;
+ mSeekTimeUs = time_us;
+ mSeekMode = mode;
+}
+
+void IMediaSource::ReadOptions::clearSeekTo() {
+ mOptions &= ~kSeekTo_Option;
+ mSeekTimeUs = 0;
+ mSeekMode = SEEK_CLOSEST_SYNC;
+}
+
+bool IMediaSource::ReadOptions::getSeekTo(
+ int64_t *time_us, SeekMode *mode) const {
+ *time_us = mSeekTimeUs;
+ *mode = mSeekMode;
+ return (mOptions & kSeekTo_Option) != 0;
+}
+
+void IMediaSource::ReadOptions::setLateBy(int64_t lateness_us) {
+ mLatenessUs = lateness_us;
+}
+
+int64_t IMediaSource::ReadOptions::getLateBy() const {
+ return mLatenessUs;
+}
+
+
+} // namespace android
+