blob: 786029a589461ded52bd8f522075ef9eaf03edfc [file] [log] [blame]
/*
* Copyright 2012, 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 "MediaPuller"
#include <utils/Log.h>
#include "MediaPuller.h"
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
namespace android {
MediaPuller::MediaPuller(
const sp<MediaSource> &source, const sp<AMessage> &notify)
: mSource(source),
mNotify(notify),
mPullGeneration(0) {
}
MediaPuller::~MediaPuller() {
}
status_t MediaPuller::postSynchronouslyAndReturnError(
const sp<AMessage> &msg) {
sp<AMessage> response;
status_t err = msg->postAndAwaitResponse(&response);
if (err != OK) {
return err;
}
if (!response->findInt32("err", &err)) {
err = OK;
}
return err;
}
status_t MediaPuller::start() {
return postSynchronouslyAndReturnError(new AMessage(kWhatStart, id()));
}
status_t MediaPuller::stop() {
return postSynchronouslyAndReturnError(new AMessage(kWhatStop, id()));
}
void MediaPuller::onMessageReceived(const sp<AMessage> &msg) {
switch (msg->what()) {
case kWhatStart:
case kWhatStop:
{
status_t err;
if (msg->what() == kWhatStart) {
err = mSource->start();
if (err == OK) {
schedulePull();
}
} else {
err = mSource->stop();
++mPullGeneration;
}
sp<AMessage> response = new AMessage;
response->setInt32("err", err);
uint32_t replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
response->postReply(replyID);
break;
}
case kWhatPull:
{
int32_t generation;
CHECK(msg->findInt32("generation", &generation));
if (generation != mPullGeneration) {
break;
}
MediaBuffer *mbuf;
status_t err = mSource->read(&mbuf);
if (err != OK) {
if (err == ERROR_END_OF_STREAM) {
ALOGI("stream ended.");
} else {
ALOGE("error %d reading stream.", err);
}
sp<AMessage> notify = mNotify->dup();
notify->setInt32("what", kWhatEOS);
notify->post();
} else {
int64_t timeUs;
CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs));
sp<ABuffer> accessUnit = new ABuffer(mbuf->range_length());
memcpy(accessUnit->data(),
(const uint8_t *)mbuf->data() + mbuf->range_offset(),
mbuf->range_length());
accessUnit->meta()->setInt64("timeUs", timeUs);
accessUnit->meta()->setPointer("mediaBuffer", mbuf);
sp<AMessage> notify = mNotify->dup();
notify->setInt32("what", kWhatAccessUnit);
notify->setBuffer("accessUnit", accessUnit);
notify->post();
schedulePull();
}
break;
}
default:
TRESPASS();
}
}
void MediaPuller::schedulePull() {
sp<AMessage> msg = new AMessage(kWhatPull, id());
msg->setInt32("generation", mPullGeneration);
msg->post();
}
} // namespace android