diff options
-rw-r--r-- | include/media/stagefright/MediaSourceSplitter.h | 193 | ||||
-rw-r--r-- | media/libstagefright/Android.mk | 1 | ||||
-rw-r--r-- | media/libstagefright/MediaSourceSplitter.cpp | 234 |
3 files changed, 0 insertions, 428 deletions
diff --git a/include/media/stagefright/MediaSourceSplitter.h b/include/media/stagefright/MediaSourceSplitter.h deleted file mode 100644 index 568f4c2..0000000 --- a/include/media/stagefright/MediaSourceSplitter.h +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ - -// This class provides a way to split a single media source into multiple sources. -// The constructor takes in the real mediaSource and createClient() can then be -// used to create multiple sources served from this real mediaSource. -// -// Usage: -// - Create MediaSourceSplitter by passing in a real mediaSource from which -// multiple duplicate channels are needed. -// - Create a client using createClient() and use it as any other mediaSource. -// -// Note that multiple clients can be created using createClient() and -// started/stopped in any order. MediaSourceSplitter stops the real source only -// when all clients have been stopped. -// -// If a new client is created/started after some existing clients have already -// started, the new client will start getting its read frames from the current -// time. - -#ifndef MEDIA_SOURCE_SPLITTER_H_ - -#define MEDIA_SOURCE_SPLITTER_H_ - -#include <media/stagefright/MediaSource.h> -#include <utils/threads.h> -#include <utils/Vector.h> -#include <utils/RefBase.h> - -namespace android { - -class MediaBuffer; -class MetaData; - -class MediaSourceSplitter : public RefBase { -public: - // Constructor - // mediaSource: The real mediaSource. The class keeps a reference to it to - // implement the various clients. - MediaSourceSplitter(sp<MediaSource> mediaSource); - - ~MediaSourceSplitter(); - - // Creates a new client of base type MediaSource. Multiple clients can be - // created which get their data through the same real mediaSource. These - // clients can then be used like any other MediaSource, all of which provide - // data from the same real source. - sp<MediaSource> createClient(); - -private: - // Total number of clients created through createClient(). - int32_t mNumberOfClients; - - // reference to the real MediaSource passed to the constructor. - sp<MediaSource> mSource; - - // Stores pointer to the MediaBuffer read from the real MediaSource. - // All clients use this to implement the read() call. - MediaBuffer *mLastReadMediaBuffer; - - // Status code for read from the real MediaSource. All clients return - // this for their read(). - status_t mLastReadStatus; - - // Boolean telling whether the real MediaSource has started. - bool mSourceStarted; - - // List of booleans, one for each client, storing whether the corresponding - // client's start() has been called. - Vector<bool> mClientsStarted; - - // Stores the number of clients which are currently started. - int32_t mNumberOfClientsStarted; - - // Since different clients call read() asynchronously, we need to keep track - // of what data is currently read into the mLastReadMediaBuffer. - // mCurrentReadBit stores the bit for the current read buffer. This bit - // flips each time a new buffer is read from the source. - // mClientsDesiredReadBit stores the bit for the next desired read buffer - // for each client. This bit flips each time read() is completed for this - // client. - bool mCurrentReadBit; - Vector<bool> mClientsDesiredReadBit; - - // Number of clients whose current read has been completed. - int32_t mNumberOfCurrentReads; - - // Boolean telling whether the last read has been completed for all clients. - // The variable is reset to false each time buffer is read from the real - // source. - bool mLastReadCompleted; - - // A global mutex for access to critical sections. - Mutex mLock; - - // Condition variable for waiting on read from source to complete. - Condition mReadFromSourceCondition; - - // Condition variable for waiting on all client's last read to complete. - Condition mAllReadsCompleteCondition; - - // Functions used by Client to implement the MediaSource interface. - - // If the real source has not been started yet by any client, starts it. - status_t start(int clientId, MetaData *params); - - // Stops the real source after all clients have called stop(). - status_t stop(int clientId); - - // returns the real source's getFormat(). - sp<MetaData> getFormat(int clientId); - - // If the client's desired buffer has already been read into - // mLastReadMediaBuffer, points the buffer to that. Otherwise if it is the - // master client, reads the buffer from source or else waits for the master - // client to read the buffer and uses that. - status_t read(int clientId, - MediaBuffer **buffer, const MediaSource::ReadOptions *options = NULL); - - // Not implemented right now. - status_t pause(int clientId); - - // Function which reads a buffer from the real source into - // mLastReadMediaBuffer - void readFromSource_lock(const MediaSource::ReadOptions *options); - - // Waits until read from the real source has been completed. - // _lock means that the function should be called when the thread has already - // obtained the lock for the mutex mLock. - void waitForReadFromSource_lock(int32_t clientId); - - // Waits until all clients have read the current buffer in - // mLastReadCompleted. - void waitForAllClientsLastRead_lock(int32_t clientId); - - // Each client calls this after it completes its read(). Once all clients - // have called this for the current buffer, the function calls - // mAllReadsCompleteCondition.broadcast() to signal the waiting clients. - void signalReadComplete_lock(bool readAborted); - - // Make these constructors private. - MediaSourceSplitter(); - MediaSourceSplitter(const MediaSourceSplitter &); - MediaSourceSplitter &operator=(const MediaSourceSplitter &); - - // This class implements the MediaSource interface. Each client stores a - // reference to the parent MediaSourceSplitter and uses it to complete the - // various calls. - class Client : public MediaSource { - public: - // Constructor stores reference to the parent MediaSourceSplitter and it - // client id. - Client(sp<MediaSourceSplitter> splitter, int32_t clientId); - - // MediaSource interface - virtual status_t start(MetaData *params = NULL); - - virtual status_t stop(); - - virtual sp<MetaData> getFormat(); - - virtual status_t read( - MediaBuffer **buffer, const ReadOptions *options = NULL); - - virtual status_t pause(); - - private: - // Refernce to the parent MediaSourceSplitter - sp<MediaSourceSplitter> mSplitter; - - // Id of this client. - int32_t mClientId; - }; - - friend class Client; -}; - -} // namespace android - -#endif // MEDIA_SOURCE_SPLITTER_H_ diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk index 21d6866..5aea8d0 100644 --- a/media/libstagefright/Android.mk +++ b/media/libstagefright/Android.mk @@ -34,7 +34,6 @@ LOCAL_SRC_FILES:= \ MediaDefs.cpp \ MediaExtractor.cpp \ MediaSource.cpp \ - MediaSourceSplitter.cpp \ MetaData.cpp \ NuCachedSource2.cpp \ NuMediaExtractor.cpp \ diff --git a/media/libstagefright/MediaSourceSplitter.cpp b/media/libstagefright/MediaSourceSplitter.cpp deleted file mode 100644 index 3b64ded..0000000 --- a/media/libstagefright/MediaSourceSplitter.cpp +++ /dev/null @@ -1,234 +0,0 @@ -/* - * Copyright (C) 2010 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 "MediaSourceSplitter" -#include <utils/Log.h> - -#include <media/stagefright/foundation/ADebug.h> -#include <media/stagefright/MediaSourceSplitter.h> -#include <media/stagefright/MediaBuffer.h> -#include <media/stagefright/MetaData.h> - -namespace android { - -MediaSourceSplitter::MediaSourceSplitter(sp<MediaSource> mediaSource) { - mNumberOfClients = 0; - mSource = mediaSource; - mSourceStarted = false; - - mNumberOfClientsStarted = 0; - mNumberOfCurrentReads = 0; - mCurrentReadBit = 0; - mLastReadCompleted = true; -} - -MediaSourceSplitter::~MediaSourceSplitter() { -} - -sp<MediaSource> MediaSourceSplitter::createClient() { - Mutex::Autolock autoLock(mLock); - - sp<MediaSource> client = new Client(this, mNumberOfClients++); - mClientsStarted.push(false); - mClientsDesiredReadBit.push(0); - return client; -} - -status_t MediaSourceSplitter::start(int clientId, MetaData *params) { - Mutex::Autolock autoLock(mLock); - - ALOGV("start client (%d)", clientId); - if (mClientsStarted[clientId]) { - return OK; - } - - mNumberOfClientsStarted++; - - if (!mSourceStarted) { - ALOGV("Starting real source from client (%d)", clientId); - status_t err = mSource->start(params); - - if (err == OK) { - mSourceStarted = true; - mClientsStarted.editItemAt(clientId) = true; - mClientsDesiredReadBit.editItemAt(clientId) = !mCurrentReadBit; - } - - return err; - } else { - mClientsStarted.editItemAt(clientId) = true; - if (mLastReadCompleted) { - // Last read was completed. So join in the threads for the next read. - mClientsDesiredReadBit.editItemAt(clientId) = !mCurrentReadBit; - } else { - // Last read is ongoing. So join in the threads for the current read. - mClientsDesiredReadBit.editItemAt(clientId) = mCurrentReadBit; - } - return OK; - } -} - -status_t MediaSourceSplitter::stop(int clientId) { - Mutex::Autolock autoLock(mLock); - - ALOGV("stop client (%d)", clientId); - CHECK(clientId >= 0 && clientId < mNumberOfClients); - CHECK(mClientsStarted[clientId]); - - if (--mNumberOfClientsStarted == 0) { - ALOGV("Stopping real source from client (%d)", clientId); - status_t err = mSource->stop(); - mSourceStarted = false; - mClientsStarted.editItemAt(clientId) = false; - return err; - } else { - mClientsStarted.editItemAt(clientId) = false; - if (!mLastReadCompleted && (mClientsDesiredReadBit[clientId] == mCurrentReadBit)) { - // !mLastReadCompleted implies that buffer has been read from source, but all - // clients haven't read it. - // mClientsDesiredReadBit[clientId] == mCurrentReadBit implies that this - // client would have wanted to read from this buffer. (i.e. it has not yet - // called read() for the current read buffer.) - // Since other threads may be waiting for all the clients' reads to complete, - // signal that this read has been aborted. - signalReadComplete_lock(true); - } - return OK; - } -} - -sp<MetaData> MediaSourceSplitter::getFormat(int clientId) { - Mutex::Autolock autoLock(mLock); - - ALOGV("getFormat client (%d)", clientId); - return mSource->getFormat(); -} - -status_t MediaSourceSplitter::read(int clientId, - MediaBuffer **buffer, const MediaSource::ReadOptions *options) { - Mutex::Autolock autoLock(mLock); - - CHECK(clientId >= 0 && clientId < mNumberOfClients); - - ALOGV("read client (%d)", clientId); - *buffer = NULL; - - if (!mClientsStarted[clientId]) { - return OK; - } - - if (mCurrentReadBit != mClientsDesiredReadBit[clientId]) { - // Desired buffer has not been read from source yet. - - // If the current client is the special client with clientId = 0 - // then read from source, else wait until the client 0 has finished - // reading from source. - if (clientId == 0) { - // Wait for all client's last read to complete first so as to not - // corrupt the buffer at mLastReadMediaBuffer. - waitForAllClientsLastRead_lock(clientId); - - readFromSource_lock(options); - *buffer = mLastReadMediaBuffer; - } else { - waitForReadFromSource_lock(clientId); - - *buffer = mLastReadMediaBuffer; - (*buffer)->add_ref(); - } - CHECK(mCurrentReadBit == mClientsDesiredReadBit[clientId]); - } else { - // Desired buffer has already been read from source. Use the cached data. - CHECK(clientId != 0); - - *buffer = mLastReadMediaBuffer; - (*buffer)->add_ref(); - } - - mClientsDesiredReadBit.editItemAt(clientId) = !mClientsDesiredReadBit[clientId]; - signalReadComplete_lock(false); - - return mLastReadStatus; -} - -void MediaSourceSplitter::readFromSource_lock(const MediaSource::ReadOptions *options) { - mLastReadStatus = mSource->read(&mLastReadMediaBuffer , options); - - mCurrentReadBit = !mCurrentReadBit; - mLastReadCompleted = false; - mReadFromSourceCondition.broadcast(); -} - -void MediaSourceSplitter::waitForReadFromSource_lock(int32_t clientId) { - mReadFromSourceCondition.wait(mLock); -} - -void MediaSourceSplitter::waitForAllClientsLastRead_lock(int32_t clientId) { - if (mLastReadCompleted) { - return; - } - mAllReadsCompleteCondition.wait(mLock); - CHECK(mLastReadCompleted); -} - -void MediaSourceSplitter::signalReadComplete_lock(bool readAborted) { - if (!readAborted) { - mNumberOfCurrentReads++; - } - - if (mNumberOfCurrentReads == mNumberOfClientsStarted) { - mLastReadCompleted = true; - mNumberOfCurrentReads = 0; - mAllReadsCompleteCondition.broadcast(); - } -} - -status_t MediaSourceSplitter::pause(int clientId) { - return ERROR_UNSUPPORTED; -} - -// Client - -MediaSourceSplitter::Client::Client( - sp<MediaSourceSplitter> splitter, - int32_t clientId) { - mSplitter = splitter; - mClientId = clientId; -} - -status_t MediaSourceSplitter::Client::start(MetaData *params) { - return mSplitter->start(mClientId, params); -} - -status_t MediaSourceSplitter::Client::stop() { - return mSplitter->stop(mClientId); -} - -sp<MetaData> MediaSourceSplitter::Client::getFormat() { - return mSplitter->getFormat(mClientId); -} - -status_t MediaSourceSplitter::Client::read( - MediaBuffer **buffer, const ReadOptions *options) { - return mSplitter->read(mClientId, buffer, options); -} - -status_t MediaSourceSplitter::Client::pause() { - return mSplitter->pause(mClientId); -} - -} // namespace android |