/* * 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 #include "TunnelRenderer.h" #include "ATSParser.h" #include #include #include #include #include #include #include #include #include #include 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 &listener); virtual void setBuffers(const Vector > &buffers); virtual void onBufferAvailable(size_t index); virtual uint32_t flags() const; void doSomeWork(); void setTimeOffset(int64_t offset); protected: virtual ~StreamSource(); private: mutable Mutex mLock; TunnelRenderer *mOwner; sp mListener; Vector > mBuffers; List mIndicesAvailable; size_t mNumDeqeued; int64_t mTimeOffsetUs; bool mTimeOffsetChanged; DISALLOW_EVIL_CONSTRUCTORS(StreamSource); }; //////////////////////////////////////////////////////////////////////////////// TunnelRenderer::StreamSource::StreamSource(TunnelRenderer *owner) : mOwner(owner), mNumDeqeued(0), mTimeOffsetUs(0ll), mTimeOffsetChanged(false) { } TunnelRenderer::StreamSource::~StreamSource() { } void TunnelRenderer::StreamSource::setListener( const sp &listener) { mListener = listener; } void TunnelRenderer::StreamSource::setBuffers( const Vector > &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 | kFlagIsRealTimeData; } void TunnelRenderer::StreamSource::doSomeWork() { Mutex::Autolock autoLock(mLock); while (!mIndicesAvailable.empty()) { sp srcBuffer = mOwner->dequeueBuffer(); if (srcBuffer == NULL) { break; } ++mNumDeqeued; if (mTimeOffsetChanged) { sp extra = new AMessage; extra->setInt32( IStreamListener::kKeyDiscontinuityMask, ATSParser::DISCONTINUITY_TIME_OFFSET); extra->setInt64("offset", mTimeOffsetUs); mListener->issueCommand( IStreamListener::DISCONTINUITY, false /* synchronous */, extra); mTimeOffsetChanged = false; } ALOGV("dequeue TS packet of size %d", srcBuffer->size()); size_t index = *mIndicesAvailable.begin(); mIndicesAvailable.erase(mIndicesAvailable.begin()); sp 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()); } } void TunnelRenderer::StreamSource::setTimeOffset(int64_t offset) { Mutex::Autolock autoLock(mLock); if (offset != mTimeOffsetUs) { mTimeOffsetUs = offset; mTimeOffsetChanged = true; } } //////////////////////////////////////////////////////////////////////////////// TunnelRenderer::TunnelRenderer( const sp &bufferProducer) : mSurfaceTex(bufferProducer), mStartup(true) { mStreamSource = new StreamSource(this); } TunnelRenderer::~TunnelRenderer() { destroyPlayer(); } void TunnelRenderer::setTimeOffset(int64_t offset) { mStreamSource->setTimeOffset(offset); } void TunnelRenderer::onMessageReceived(const sp &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 sm = defaultServiceManager(); sp binder = sm->getService(String16("media.player")); sp service = interface_cast(binder); CHECK(service.get() != NULL); 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->setVideoSurfaceTexture(NULL); mPlayer->stop(); mPlayer.clear(); if (mSurfaceTex == NULL) { mSurface.clear(); mSurfaceControl.clear(); mComposerClient->dispose(); mComposerClient.clear(); } } void TunnelRenderer::queueBuffer(const sp &buffer) { { Mutex::Autolock autoLock(mLock); mBuffers.push_back(buffer); } if (mStartup) { initPlayer(); mStartup = false; } mStreamSource->doSomeWork(); } sp TunnelRenderer::dequeueBuffer() { Mutex::Autolock autoLock(mLock); if (mBuffers.empty()) { return NULL; } sp buf = *mBuffers.begin(); mBuffers.erase(mBuffers.begin()); return buf; } } // namespace android