blob: d9d8a76dde824faf95c3aaf8027831016af2c7b7 [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 "TunnelRenderer"
#include <utils/Log.h>
#include "TunnelRenderer.h"
#include "ATSParser.h"
#include <binder/IMemory.h>
#include <binder/IServiceManager.h>
#include <gui/SurfaceComposerClient.h>
#include <media/IMediaPlayerService.h>
#include <media/IStreamSource.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <ui/DisplayInfo.h>
namespace android {
struct TunnelRenderer::PlayerClient : public BnMediaPlayerClient {
PlayerClient() {}
virtual void notify(int msg, int ext1, int ext2, const Parcel *obj) {
ALOGI("notify %d, %d, %d", msg, ext1, ext2);
}
protected:
virtual ~PlayerClient() {}
private:
DISALLOW_EVIL_CONSTRUCTORS(PlayerClient);
};
struct TunnelRenderer::StreamSource : public BnStreamSource {
StreamSource(TunnelRenderer *owner);
virtual void setListener(const sp<IStreamListener> &listener);
virtual void setBuffers(const Vector<sp<IMemory> > &buffers);
virtual void onBufferAvailable(size_t index);
virtual uint32_t flags() const;
void doSomeWork();
protected:
virtual ~StreamSource();
private:
mutable Mutex mLock;
TunnelRenderer *mOwner;
sp<IStreamListener> mListener;
Vector<sp<IMemory> > mBuffers;
List<size_t> mIndicesAvailable;
size_t mNumDeqeued;
DISALLOW_EVIL_CONSTRUCTORS(StreamSource);
};
////////////////////////////////////////////////////////////////////////////////
TunnelRenderer::StreamSource::StreamSource(TunnelRenderer *owner)
: mOwner(owner),
mNumDeqeued(0) {
}
TunnelRenderer::StreamSource::~StreamSource() {
}
void TunnelRenderer::StreamSource::setListener(
const sp<IStreamListener> &listener) {
mListener = listener;
}
void TunnelRenderer::StreamSource::setBuffers(
const Vector<sp<IMemory> > &buffers) {
mBuffers = buffers;
}
void TunnelRenderer::StreamSource::onBufferAvailable(size_t index) {
CHECK_LT(index, mBuffers.size());
{
Mutex::Autolock autoLock(mLock);
mIndicesAvailable.push_back(index);
}
doSomeWork();
}
uint32_t TunnelRenderer::StreamSource::flags() const {
return kFlagAlignedVideoData;
}
void TunnelRenderer::StreamSource::doSomeWork() {
Mutex::Autolock autoLock(mLock);
while (!mIndicesAvailable.empty()) {
sp<ABuffer> srcBuffer = mOwner->dequeueBuffer();
if (srcBuffer == NULL) {
break;
}
++mNumDeqeued;
if (mNumDeqeued == 1) {
ALOGI("fixing real time now.");
sp<AMessage> extra = new AMessage;
extra->setInt32(
IStreamListener::kKeyDiscontinuityMask,
ATSParser::DISCONTINUITY_ABSOLUTE_TIME);
extra->setInt64("timeUs", ALooper::GetNowUs());
mListener->issueCommand(
IStreamListener::DISCONTINUITY,
false /* synchronous */,
extra);
}
ALOGV("dequeue TS packet of size %d", srcBuffer->size());
size_t index = *mIndicesAvailable.begin();
mIndicesAvailable.erase(mIndicesAvailable.begin());
sp<IMemory> mem = mBuffers.itemAt(index);
CHECK_LE(srcBuffer->size(), mem->size());
CHECK_EQ((srcBuffer->size() % 188), 0u);
memcpy(mem->pointer(), srcBuffer->data(), srcBuffer->size());
mListener->queueBuffer(index, srcBuffer->size());
}
}
////////////////////////////////////////////////////////////////////////////////
TunnelRenderer::TunnelRenderer(
const sp<IGraphicBufferProducer> &bufferProducer)
: mSurfaceTex(bufferProducer),
mStartup(true) {
}
TunnelRenderer::~TunnelRenderer() {
destroyPlayer();
}
void TunnelRenderer::onMessageReceived(const sp<AMessage> &msg) {
switch (msg->what()) {
default:
TRESPASS();
}
}
void TunnelRenderer::initPlayer() {
if (mSurfaceTex == NULL) {
mComposerClient = new SurfaceComposerClient;
CHECK_EQ(mComposerClient->initCheck(), (status_t)OK);
DisplayInfo info;
SurfaceComposerClient::getDisplayInfo(0, &info);
ssize_t displayWidth = info.w;
ssize_t displayHeight = info.h;
mSurfaceControl =
mComposerClient->createSurface(
String8("A Surface"),
displayWidth,
displayHeight,
PIXEL_FORMAT_RGB_565,
0);
CHECK(mSurfaceControl != NULL);
CHECK(mSurfaceControl->isValid());
SurfaceComposerClient::openGlobalTransaction();
CHECK_EQ(mSurfaceControl->setLayer(INT_MAX), (status_t)OK);
CHECK_EQ(mSurfaceControl->show(), (status_t)OK);
SurfaceComposerClient::closeGlobalTransaction();
mSurface = mSurfaceControl->getSurface();
CHECK(mSurface != NULL);
}
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder = sm->getService(String16("media.player"));
sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
CHECK(service.get() != NULL);
mStreamSource = new StreamSource(this);
mPlayerClient = new PlayerClient;
mPlayer = service->create(mPlayerClient, 0);
CHECK(mPlayer != NULL);
CHECK_EQ(mPlayer->setDataSource(mStreamSource), (status_t)OK);
mPlayer->setVideoSurfaceTexture(
mSurfaceTex != NULL ? mSurfaceTex : mSurface->getIGraphicBufferProducer());
mPlayer->start();
}
void TunnelRenderer::destroyPlayer() {
mStreamSource.clear();
mPlayer->stop();
mPlayer.clear();
if (mSurfaceTex == NULL) {
mSurface.clear();
mSurfaceControl.clear();
mComposerClient->dispose();
mComposerClient.clear();
}
}
void TunnelRenderer::queueBuffer(const sp<ABuffer> &buffer) {
{
Mutex::Autolock autoLock(mLock);
mBuffers.push_back(buffer);
}
if (mStartup) {
initPlayer();
mStartup = false;
}
mStreamSource->doSomeWork();
}
sp<ABuffer> TunnelRenderer::dequeueBuffer() {
Mutex::Autolock autoLock(mLock);
if (mBuffers.empty()) {
return NULL;
}
sp<ABuffer> buf = *mBuffers.begin();
mBuffers.erase(mBuffers.begin());
return buf;
}
} // namespace android