am 8946ab26: A ThreadedSource wraps around an existing MediaSource and reads output buffers on a separate thread. It\'s now used for the vpx decoder to decode frames ahead of time to improve playback performance.

Merge commit '8946ab2618a4eebfdf7b00c6b68e6a5d8432cafa' into gingerbread-plus-aosp

* commit '8946ab2618a4eebfdf7b00c6b68e6a5d8432cafa':
  A ThreadedSource wraps around an existing MediaSource and reads output buffers on a separate thread. It's now used for the vpx decoder to decode frames ahead of time to improve playback performance.
This commit is contained in:
Andreas Huber
2010-09-16 10:02:52 -07:00
committed by Android Git Automerger
4 changed files with 289 additions and 0 deletions

View File

@@ -34,6 +34,7 @@ LOCAL_SRC_FILES:= \
ShoutcastSource.cpp \
StagefrightMediaScanner.cpp \
StagefrightMetadataRetriever.cpp \
ThreadedSource.cpp \
ThrottledSource.cpp \
TimeSource.cpp \
TimedEventQueue.cpp \

View File

@@ -52,6 +52,8 @@
#include <OMX_Audio.h>
#include <OMX_Component.h>
#include "include/ThreadedSource.h"
namespace android {
static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
@@ -134,6 +136,10 @@ static sp<MediaSource> InstantiateSoftwareCodec(
for (size_t i = 0;
i < sizeof(kFactoryInfo) / sizeof(kFactoryInfo[0]); ++i) {
if (!strcmp(name, kFactoryInfo[i].name)) {
if (!strcmp(name, "VPXDecoder")) {
return new ThreadedSource(
(*kFactoryInfo[i].CreateFunc)(source));
}
return (*kFactoryInfo[i].CreateFunc)(source);
}
}

View File

@@ -0,0 +1,209 @@
/*
* 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.
*/
#include "include/ThreadedSource.h"
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MetaData.h>
namespace android {
static const size_t kMaxQueueSize = 2;
ThreadedSource::ThreadedSource(const sp<MediaSource> &source)
: mSource(source),
mReflector(new AHandlerReflector<ThreadedSource>(this)),
mLooper(new ALooper),
mStarted(false) {
mLooper->registerHandler(mReflector);
}
ThreadedSource::~ThreadedSource() {
if (mStarted) {
stop();
}
}
status_t ThreadedSource::start(MetaData *params) {
CHECK(!mStarted);
status_t err = mSource->start(params);
if (err != OK) {
return err;
}
mFinalResult = OK;
mSeekTimeUs = -1;
mDecodePending = false;
Mutex::Autolock autoLock(mLock);
postDecodeMore_l();
CHECK_EQ(mLooper->start(), (status_t)OK);
mStarted = true;
return OK;
}
status_t ThreadedSource::stop() {
CHECK(mStarted);
CHECK_EQ(mLooper->stop(), (status_t)OK);
Mutex::Autolock autoLock(mLock);
clearQueue_l();
status_t err = mSource->stop();
mStarted = false;
return err;
}
sp<MetaData> ThreadedSource::getFormat() {
return mSource->getFormat();
}
status_t ThreadedSource::read(
MediaBuffer **buffer, const ReadOptions *options) {
*buffer = NULL;
Mutex::Autolock autoLock(mLock);
int64_t seekTimeUs;
ReadOptions::SeekMode seekMode;
if (options && options->getSeekTo(&seekTimeUs, &seekMode)) {
int32_t seekComplete = 0;
sp<AMessage> msg = new AMessage(kWhatSeek, mReflector->id());
msg->setInt64("timeUs", seekTimeUs);
msg->setInt32("mode", seekMode);
msg->setPointer("complete", &seekComplete);
msg->post();
while (!seekComplete) {
mCondition.wait(mLock);
}
}
while (mQueue.empty() && mFinalResult == OK) {
mCondition.wait(mLock);
}
if (!mQueue.empty()) {
*buffer = *mQueue.begin();
mQueue.erase(mQueue.begin());
if (mFinalResult == OK) {
postDecodeMore_l();
}
return OK;
}
return mFinalResult;
}
void ThreadedSource::onMessageReceived(const sp<AMessage> &msg) {
switch (msg->what()) {
case kWhatSeek:
{
CHECK(msg->findInt64("timeUs", &mSeekTimeUs));
CHECK_GE(mSeekTimeUs, 0ll);
int32_t x;
CHECK(msg->findInt32("mode", &x));
mSeekMode = (ReadOptions::SeekMode)x;
int32_t *seekComplete;
CHECK(msg->findPointer("complete", (void **)&seekComplete));
Mutex::Autolock autoLock(mLock);
clearQueue_l();
mFinalResult = OK;
*seekComplete = 1;
mCondition.signal();
postDecodeMore_l();
break;
}
case kWhatDecodeMore:
{
{
Mutex::Autolock autoLock(mLock);
mDecodePending = false;
if (mQueue.size() == kMaxQueueSize) {
break;
}
}
MediaBuffer *buffer;
ReadOptions options;
if (mSeekTimeUs >= 0) {
options.setSeekTo(mSeekTimeUs, mSeekMode);
mSeekTimeUs = -1ll;
}
status_t err = mSource->read(&buffer, &options);
Mutex::Autolock autoLock(mLock);
if (err != OK) {
mFinalResult = err;
} else {
mQueue.push_back(buffer);
if (mQueue.size() < kMaxQueueSize) {
postDecodeMore_l();
}
}
mCondition.signal();
break;
}
default:
TRESPASS();
break;
}
}
void ThreadedSource::postDecodeMore_l() {
if (mDecodePending) {
return;
}
mDecodePending = true;
(new AMessage(kWhatDecodeMore, mReflector->id()))->post();
}
void ThreadedSource::clearQueue_l() {
while (!mQueue.empty()) {
MediaBuffer *buffer = *mQueue.begin();
mQueue.erase(mQueue.begin());
buffer->release();
buffer = NULL;
}
}
} // namespace android

View File

@@ -0,0 +1,73 @@
/*
* 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.
*/
#ifndef THREADED_SOURCE_H_
#define THREADED_SOURCE_H_
#include <media/stagefright/foundation/ABase.h>
#include <media/stagefright/foundation/AHandlerReflector.h>
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/MediaSource.h>
#include <utils/threads.h>
namespace android {
struct ThreadedSource : public MediaSource {
ThreadedSource(const sp<MediaSource> &source);
virtual status_t start(MetaData *params);
virtual status_t stop();
virtual sp<MetaData> getFormat();
virtual status_t read(
MediaBuffer **buffer, const ReadOptions *options);
virtual void onMessageReceived(const sp<AMessage> &msg);
protected:
virtual ~ThreadedSource();
private:
enum {
kWhatDecodeMore = 'deco',
kWhatSeek = 'seek',
};
sp<MediaSource> mSource;
sp<AHandlerReflector<ThreadedSource> > mReflector;
sp<ALooper> mLooper;
Mutex mLock;
Condition mCondition;
List<MediaBuffer *> mQueue;
status_t mFinalResult;
bool mDecodePending;
bool mStarted;
int64_t mSeekTimeUs;
ReadOptions::SeekMode mSeekMode;
void postDecodeMore_l();
void clearQueue_l();
DISALLOW_EVIL_CONSTRUCTORS(ThreadedSource);
};
} // namespace android
#endif // THREADED_SOURCE_H_