blob: ee70306a35af0816c7442dcc1556d1cf307eef30 [file] [log] [blame]
/*
* 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 "NuPlayerStreamListener"
#include <utils/Log.h>
#include "NuPlayerStreamListener.h"
#include <binder/MemoryDealer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/MediaErrors.h>
namespace android {
NuPlayer::NuPlayerStreamListener::NuPlayerStreamListener(
const sp<IStreamSource> &source,
const sp<AHandler> &targetHandler)
: mSource(source),
mTargetHandler(targetHandler),
mEOS(false),
mSendDataNotification(true) {
mSource->setListener(this);
mMemoryDealer = new MemoryDealer(kNumBuffers * kBufferSize);
for (size_t i = 0; i < kNumBuffers; ++i) {
sp<IMemory> mem = mMemoryDealer->allocate(kBufferSize);
CHECK(mem != NULL);
mBuffers.push(mem);
}
mSource->setBuffers(mBuffers);
}
void NuPlayer::NuPlayerStreamListener::start() {
for (size_t i = 0; i < kNumBuffers; ++i) {
mSource->onBufferAvailable(i);
}
}
void NuPlayer::NuPlayerStreamListener::queueBuffer(size_t index, size_t size) {
QueueEntry entry;
entry.mIsCommand = false;
entry.mIndex = index;
entry.mSize = size;
entry.mOffset = 0;
Mutex::Autolock autoLock(mLock);
mQueue.push_back(entry);
if (mSendDataNotification) {
mSendDataNotification = false;
if (mTargetHandler != NULL) {
(new AMessage(kWhatMoreDataQueued, mTargetHandler))->post();
}
}
}
void NuPlayer::NuPlayerStreamListener::issueCommand(
Command cmd, bool synchronous, const sp<AMessage> &extra) {
CHECK(!synchronous);
QueueEntry entry;
entry.mIsCommand = true;
entry.mCommand = cmd;
entry.mExtra = extra;
Mutex::Autolock autoLock(mLock);
mQueue.push_back(entry);
if (mSendDataNotification) {
mSendDataNotification = false;
if (mTargetHandler != NULL) {
(new AMessage(kWhatMoreDataQueued, mTargetHandler))->post();
}
}
}
ssize_t NuPlayer::NuPlayerStreamListener::read(
void *data, size_t size, sp<AMessage> *extra) {
CHECK_GT(size, 0u);
extra->clear();
Mutex::Autolock autoLock(mLock);
if (mEOS) {
return 0;
}
if (mQueue.empty()) {
mSendDataNotification = true;
return -EWOULDBLOCK;
}
QueueEntry *entry = &*mQueue.begin();
if (entry->mIsCommand) {
switch (entry->mCommand) {
case EOS:
{
mQueue.erase(mQueue.begin());
entry = NULL;
mEOS = true;
return 0;
}
case DISCONTINUITY:
{
*extra = entry->mExtra;
mQueue.erase(mQueue.begin());
entry = NULL;
return INFO_DISCONTINUITY;
}
default:
TRESPASS();
break;
}
}
size_t copy = entry->mSize;
if (copy > size) {
copy = size;
}
if (entry->mIndex >= mBuffers.size()) {
return ERROR_MALFORMED;
}
sp<IMemory> mem = mBuffers.editItemAt(entry->mIndex);
if (mem == NULL || mem->size() < copy || mem->size() - copy < entry->mOffset) {
return ERROR_MALFORMED;
}
memcpy(data,
(const uint8_t *)mem->pointer()
+ entry->mOffset,
copy);
entry->mOffset += copy;
entry->mSize -= copy;
if (entry->mSize == 0) {
mSource->onBufferAvailable(entry->mIndex);
mQueue.erase(mQueue.begin());
entry = NULL;
}
return copy;
}
} // namespace android