From bfa6b2d7a1be1832ac40ed90aece1834f720b5c6 Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Fri, 20 Nov 2009 09:32:46 -0800 Subject: Squashed commit of the following: commit 1efc38dc3c33fef57b759002db3965ed07a28cb0 Author: Andreas Huber Date: Thu Nov 19 14:36:14 2009 -0800 Sending the SEEK-COMPLETE notification temporarily broke seeking backwards in time behaviour. This is now fixed. Also, get rid of the semi-random delay after posting buffers to surface flinger in favour of delaying the buffer release until the next frame is displayed. commit 51973062eb5ee63fd64b845d72bac517cc3369cf Author: Andreas Huber Date: Wed Nov 18 14:01:43 2009 -0800 Fix one more unit test, properly send seek-complete notification only after seek actually completed. commit cb22250b34b1fcfe1bf459723a761fd003950229 Author: Andreas Huber Date: Wed Nov 18 12:31:36 2009 -0800 Fix seek-while-paused in AwesomePlayer, revert to using FileSource if MmapSource fails. commit 25eb9241138ddf7bb27ce90657116c5f8a94d880 Author: Andreas Huber Date: Wed Nov 18 12:30:40 2009 -0800 Support seeking and duration in AMRExtractor, assuming all frames are the same size. commit 44192f2ebb7ea3bbd3ba5910025692dbc6a08faa Author: Andreas Huber Date: Wed Nov 18 10:21:44 2009 -0800 MediaPlayerImpl is dead, long live AwesomePlayer. commit c5b52d3c0674f5dc94db506afbce52401cceddac Author: Andreas Huber Date: Wed Nov 18 09:42:23 2009 -0800 New implementation of the stagefright mediaplayer. --- .../StagefrightMetadataRetriever.cpp | 4 +- media/libmediaplayerservice/StagefrightPlayer.cpp | 115 ++-- media/libmediaplayerservice/StagefrightPlayer.h | 4 +- media/libstagefright/AMRExtractor.cpp | 106 +++- media/libstagefright/Android.mk | 3 +- media/libstagefright/AudioPlayer.cpp | 19 +- media/libstagefright/AwesomePlayer.cpp | 626 ++++++++++++++++++++ media/libstagefright/MediaExtractor.cpp | 6 +- media/libstagefright/MediaPlayerImpl.cpp | 658 --------------------- media/libstagefright/MmapSource.cpp | 113 ---- media/libstagefright/OMXCodec.cpp | 1 - media/libstagefright/TimedEventQueue.cpp | 10 +- media/libstagefright/include/AMRExtractor.h | 4 +- media/libstagefright/include/AwesomePlayer.h | 133 +++++ 14 files changed, 906 insertions(+), 896 deletions(-) create mode 100644 media/libstagefright/AwesomePlayer.cpp delete mode 100644 media/libstagefright/MediaPlayerImpl.cpp delete mode 100644 media/libstagefright/MmapSource.cpp create mode 100644 media/libstagefright/include/AwesomePlayer.h (limited to 'media') diff --git a/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp b/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp index 7a3aee8..42c1877 100644 --- a/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp +++ b/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp @@ -24,11 +24,11 @@ #include #include #include +#include #include #include #include #include -#include #include namespace android { @@ -58,7 +58,7 @@ status_t StagefrightMetadataRetriever::setDataSource( LOGV("setDataSource(%d, %lld, %lld)", fd, offset, length); mExtractor = MediaExtractor::Create( - new MmapSource(fd, offset, length)); + new FileSource(fd, offset, length)); return OK; } diff --git a/media/libmediaplayerservice/StagefrightPlayer.cpp b/media/libmediaplayerservice/StagefrightPlayer.cpp index dbee451..5915105 100644 --- a/media/libmediaplayerservice/StagefrightPlayer.cpp +++ b/media/libmediaplayerservice/StagefrightPlayer.cpp @@ -3,19 +3,24 @@ #include #include "StagefrightPlayer.h" -#include + +#include "AwesomePlayer.h" namespace android { StagefrightPlayer::StagefrightPlayer() - : mPlayer(NULL) { + : mPlayer(new AwesomePlayer) { LOGV("StagefrightPlayer"); + + mPlayer->setListener(this); } StagefrightPlayer::~StagefrightPlayer() { LOGV("~StagefrightPlayer"); reset(); - LOGV("~StagefrightPlayer done."); + + delete mPlayer; + mPlayer = NULL; } status_t StagefrightPlayer::initCheck() { @@ -25,62 +30,32 @@ status_t StagefrightPlayer::initCheck() { status_t StagefrightPlayer::setDataSource(const char *url) { LOGV("setDataSource('%s')", url); - - reset(); - mPlayer = new MediaPlayerImpl(url); - - status_t err = mPlayer->initCheck(); - if (err != OK) { - delete mPlayer; - mPlayer = NULL; - } else { - mPlayer->setAudioSink(mAudioSink); - } - - return err; + return mPlayer->setDataSource(url); } // Warning: The filedescriptor passed into this method will only be valid until // the method returns, if you want to keep it, dup it! status_t StagefrightPlayer::setDataSource(int fd, int64_t offset, int64_t length) { LOGV("setDataSource(%d, %lld, %lld)", fd, offset, length); - - reset(); - mPlayer = new MediaPlayerImpl(dup(fd), offset, length); - - status_t err = mPlayer->initCheck(); - if (err != OK) { - delete mPlayer; - mPlayer = NULL; - } else { - mPlayer->setAudioSink(mAudioSink); - } - - return err; + return mPlayer->setDataSource(dup(fd), offset, length); } status_t StagefrightPlayer::setVideoSurface(const sp &surface) { LOGV("setVideoSurface"); - if (mPlayer == NULL) { - return NO_INIT; - } - mPlayer->setISurface(surface); - return OK; } status_t StagefrightPlayer::prepare() { LOGV("prepare"); - if (mPlayer == NULL) { - return NO_INIT; + int32_t width, height; + if (mPlayer->getVideoDimensions(&width, &height) != OK) { + width = height = 0; } - sendEvent( - MEDIA_SET_VIDEO_SIZE, - mPlayer->getWidth(), mPlayer->getHeight()); + sendEvent(MEDIA_SET_VIDEO_SIZE, width, height); return OK; } @@ -102,92 +77,76 @@ status_t StagefrightPlayer::prepareAsync() { status_t StagefrightPlayer::start() { LOGV("start"); - if (mPlayer == NULL) { - return NO_INIT; - } - - mPlayer->play(); - - return OK; + return mPlayer->play(); } status_t StagefrightPlayer::stop() { LOGV("stop"); - if (mPlayer == NULL) { - return NO_INIT; - } - - reset(); - - return OK; + return pause(); // what's the difference? } status_t StagefrightPlayer::pause() { LOGV("pause"); - if (mPlayer == NULL) { - return NO_INIT; - } - - mPlayer->pause(); - - return OK; + return mPlayer->pause(); } bool StagefrightPlayer::isPlaying() { LOGV("isPlaying"); - return mPlayer != NULL && mPlayer->isPlaying(); + return mPlayer->isPlaying(); } status_t StagefrightPlayer::seekTo(int msec) { LOGV("seekTo"); - if (mPlayer == NULL) { - return NO_INIT; - } - status_t err = mPlayer->seekTo((int64_t)msec * 1000); - sendEvent(MEDIA_SEEK_COMPLETE); - return err; } status_t StagefrightPlayer::getCurrentPosition(int *msec) { LOGV("getCurrentPosition"); - if (mPlayer == NULL) { - return NO_INIT; + int64_t positionUs; + status_t err = mPlayer->getPosition(&positionUs); + + if (err != OK) { + return err; } - *msec = mPlayer->getPosition() / 1000; + *msec = (positionUs + 500) / 1000; + return OK; } status_t StagefrightPlayer::getDuration(int *msec) { LOGV("getDuration"); - if (mPlayer == NULL) { - return NO_INIT; + int64_t durationUs; + status_t err = mPlayer->getDuration(&durationUs); + + if (err != OK) { + return err; } - *msec = mPlayer->getDuration() / 1000; + *msec = (durationUs + 500) / 1000; + return OK; } status_t StagefrightPlayer::reset() { LOGV("reset"); - delete mPlayer; - mPlayer = NULL; + mPlayer->reset(); return OK; } status_t StagefrightPlayer::setLooping(int loop) { LOGV("setLooping"); - return UNKNOWN_ERROR; + + return mPlayer->setLooping(loop); } player_type StagefrightPlayer::playerType() { @@ -202,9 +161,7 @@ status_t StagefrightPlayer::invoke(const Parcel &request, Parcel *reply) { void StagefrightPlayer::setAudioSink(const sp &audioSink) { MediaPlayerInterface::setAudioSink(audioSink); - if (mPlayer != NULL) { - mPlayer->setAudioSink(audioSink); - } + mPlayer->setAudioSink(audioSink); } } // namespace android diff --git a/media/libmediaplayerservice/StagefrightPlayer.h b/media/libmediaplayerservice/StagefrightPlayer.h index f214872..9d005cb 100644 --- a/media/libmediaplayerservice/StagefrightPlayer.h +++ b/media/libmediaplayerservice/StagefrightPlayer.h @@ -22,7 +22,7 @@ namespace android { -class MediaPlayerImpl; +struct AwesomePlayer; class StagefrightPlayer : public MediaPlayerInterface { public: @@ -49,7 +49,7 @@ public: virtual void setAudioSink(const sp &audioSink); private: - MediaPlayerImpl *mPlayer; + AwesomePlayer *mPlayer; StagefrightPlayer(const StagefrightPlayer &); StagefrightPlayer &operator=(const StagefrightPlayer &); diff --git a/media/libstagefright/AMRExtractor.cpp b/media/libstagefright/AMRExtractor.cpp index 1e3c5a4..bdd7550 100644 --- a/media/libstagefright/AMRExtractor.cpp +++ b/media/libstagefright/AMRExtractor.cpp @@ -33,7 +33,10 @@ namespace android { class AMRSource : public MediaSource { public: - AMRSource(const sp &source, bool isWide); + AMRSource(const sp &source, + const sp &meta, + size_t frameSize, + bool isWide); virtual status_t start(MetaData *params = NULL); virtual status_t stop(); @@ -48,6 +51,8 @@ protected: private: sp mDataSource; + sp mMeta; + size_t mFrameSize; bool mIsWide; off_t mOffset; @@ -61,15 +66,63 @@ private: //////////////////////////////////////////////////////////////////////////////// +static size_t getFrameSize(bool isWide, unsigned FT) { + static const size_t kFrameSizeNB[8] = { + 95, 103, 118, 134, 148, 159, 204, 244 + }; + static const size_t kFrameSizeWB[9] = { + 132, 177, 253, 285, 317, 365, 397, 461, 477 + }; + + size_t frameSize = isWide ? kFrameSizeWB[FT] : kFrameSizeNB[FT]; + + // Round up bits to bytes and add 1 for the header byte. + frameSize = (frameSize + 7) / 8 + 1; + + return frameSize; +} + AMRExtractor::AMRExtractor(const sp &source) : mDataSource(source), mInitCheck(NO_INIT) { String8 mimeType; float confidence; - if (SniffAMR(mDataSource, &mimeType, &confidence)) { - mInitCheck = OK; - mIsWide = (mimeType == MEDIA_MIMETYPE_AUDIO_AMR_WB); + if (!SniffAMR(mDataSource, &mimeType, &confidence)) { + return; } + + mIsWide = (mimeType == MEDIA_MIMETYPE_AUDIO_AMR_WB); + + mMeta = new MetaData; + mMeta->setCString( + kKeyMIMEType, mIsWide ? MEDIA_MIMETYPE_AUDIO_AMR_WB + : MEDIA_MIMETYPE_AUDIO_AMR_NB); + + mMeta->setInt32(kKeyChannelCount, 1); + mMeta->setInt32(kKeySampleRate, mIsWide ? 16000 : 8000); + + size_t offset = mIsWide ? 9 : 6; + uint8_t header; + if (mDataSource->readAt(offset, &header, 1) != 1) { + return; + } + + unsigned FT = (header >> 3) & 0x0f; + + if (FT > 8 || (!mIsWide && FT > 7)) { + return; + } + + mFrameSize = getFrameSize(mIsWide, FT); + + off_t streamSize; + if (mDataSource->getSize(&streamSize) == OK) { + off_t numFrames = streamSize / mFrameSize; + + mMeta->setInt64(kKeyDuration, 20000ll * numFrames); + } + + mInitCheck = OK; } AMRExtractor::~AMRExtractor() { @@ -84,7 +137,7 @@ sp AMRExtractor::getTrack(size_t index) { return NULL; } - return new AMRSource(mDataSource, mIsWide); + return new AMRSource(mDataSource, mMeta, mFrameSize, mIsWide); } sp AMRExtractor::getTrackMetaData(size_t index, uint32_t flags) { @@ -92,26 +145,17 @@ sp AMRExtractor::getTrackMetaData(size_t index, uint32_t flags) { return NULL; } - return makeAMRFormat(mIsWide); -} - -// static -sp AMRExtractor::makeAMRFormat(bool isWide) { - sp meta = new MetaData; - meta->setCString( - kKeyMIMEType, isWide ? MEDIA_MIMETYPE_AUDIO_AMR_WB - : MEDIA_MIMETYPE_AUDIO_AMR_NB); - - meta->setInt32(kKeyChannelCount, 1); - meta->setInt32(kKeySampleRate, isWide ? 16000 : 8000); - - return meta; + return mMeta; } //////////////////////////////////////////////////////////////////////////////// -AMRSource::AMRSource(const sp &source, bool isWide) +AMRSource::AMRSource( + const sp &source, const sp &meta, + size_t frameSize, bool isWide) : mDataSource(source), + mMeta(meta), + mFrameSize(frameSize), mIsWide(isWide), mOffset(mIsWide ? 9 : 6), mCurrentTimeUs(0), @@ -148,13 +192,20 @@ status_t AMRSource::stop() { } sp AMRSource::getFormat() { - return AMRExtractor::makeAMRFormat(mIsWide); + return mMeta; } status_t AMRSource::read( MediaBuffer **out, const ReadOptions *options) { *out = NULL; + int64_t seekTimeUs; + if (options && options->getSeekTo(&seekTimeUs)) { + int64_t seekFrame = seekTimeUs / 20000ll; // 20ms per frame. + mCurrentTimeUs = seekFrame * 20000ll; + mOffset = seekFrame * mFrameSize + (mIsWide ? 9 : 6); + } + uint8_t header; ssize_t n = mDataSource->readAt(mOffset, &header, 1); @@ -180,17 +231,8 @@ status_t AMRSource::read( return ERROR_MALFORMED; } - static const size_t kFrameSizeNB[8] = { - 95, 103, 118, 134, 148, 159, 204, 244 - }; - static const size_t kFrameSizeWB[9] = { - 132, 177, 253, 285, 317, 365, 397, 461, 477 - }; - - size_t frameSize = mIsWide ? kFrameSizeWB[FT] : kFrameSizeNB[FT]; - - // Round up bits to bytes and add 1 for the header byte. - frameSize = (frameSize + 7) / 8 + 1; + size_t frameSize = getFrameSize(mIsWide, FT); + CHECK_EQ(frameSize, mFrameSize); n = mDataSource->readAt(mOffset, buffer->data(), frameSize); diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk index c36e769..460c496 100644 --- a/media/libstagefright/Android.mk +++ b/media/libstagefright/Android.mk @@ -17,6 +17,7 @@ ifeq ($(BUILD_WITH_FULL_STAGEFRIGHT),true) LOCAL_SRC_FILES += \ AMRExtractor.cpp \ AudioPlayer.cpp \ + AwesomePlayer.cpp \ CachingDataSource.cpp \ CameraSource.cpp \ DataSource.cpp \ @@ -28,8 +29,6 @@ LOCAL_SRC_FILES += \ MPEG4Extractor.cpp \ MPEG4Writer.cpp \ MediaExtractor.cpp \ - MediaPlayerImpl.cpp \ - MmapSource.cpp \ SampleTable.cpp \ ShoutcastSource.cpp \ TimeSource.cpp \ diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp index d7e3f66..4280683 100644 --- a/media/libstagefright/AudioPlayer.cpp +++ b/media/libstagefright/AudioPlayer.cpp @@ -47,6 +47,12 @@ AudioPlayer::~AudioPlayer() { } } +void AudioPlayer::setListenerCallback( + void (*notify)(void *cookie, int what), void *cookie) { + mListenerCallback = notify; + mListenerCookie = cookie; +} + void AudioPlayer::setSource(const sp &source) { CHECK_EQ(mSource, NULL); mSource = source; @@ -195,7 +201,6 @@ void AudioPlayer::fillBuffer(void *data, size_t size) { mInputBuffer->release(); mInputBuffer = NULL; } - mSeeking = false; } } @@ -205,7 +210,19 @@ void AudioPlayer::fillBuffer(void *data, size_t size) { CHECK((err == OK && mInputBuffer != NULL) || (err != OK && mInputBuffer == NULL)); + if (mSeeking) { + mSeeking = false; + + if (mListenerCallback) { + (*mListenerCallback)(mListenerCookie, SEEK_COMPLETE); + } + } + if (err != OK) { + if (mListenerCallback) { + (*mListenerCallback)(mListenerCookie, REACHED_EOS); + } + memset((char *)data + size_done, 0, size_remaining); break; } diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp new file mode 100644 index 0000000..ed46cea --- /dev/null +++ b/media/libstagefright/AwesomePlayer.cpp @@ -0,0 +1,626 @@ +/* + * Copyright (C) 2009 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 "AwesomePlayer" +#include + +#include "include/AwesomePlayer.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace android { + +struct AwesomeEvent : public TimedEventQueue::Event { + AwesomeEvent(AwesomePlayer *player, int32_t code) + : mPlayer(player), + mCode(code) { + } + +protected: + virtual ~AwesomeEvent() {} + + virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) { + mPlayer->onEvent(mCode); + } + +private: + AwesomePlayer *mPlayer; + int32_t mCode; + + AwesomeEvent(const AwesomeEvent &); + AwesomeEvent &operator=(const AwesomeEvent &); +}; + +AwesomePlayer::AwesomePlayer() + : mTimeSource(NULL), + mAudioPlayer(NULL), + mLastVideoBuffer(NULL), + mVideoBuffer(NULL) { + CHECK_EQ(mClient.connect(), OK); + + DataSource::RegisterDefaultSniffers(); + + mVideoEvent = new AwesomeEvent(this, 0); + mVideoEventPending = false; + mStreamDoneEvent = new AwesomeEvent(this, 1); + mStreamDoneEventPending = false; + + mQueue.start(); + + reset(); +} + +AwesomePlayer::~AwesomePlayer() { + mQueue.stop(); + + reset(); + + mClient.disconnect(); +} + +void AwesomePlayer::cancelPlayerEvents() { + mQueue.cancelEvent(mVideoEvent->eventID()); + mVideoEventPending = false; + mQueue.cancelEvent(mStreamDoneEvent->eventID()); + mStreamDoneEventPending = false; +} + +void AwesomePlayer::setListener(const sp &listener) { + Mutex::Autolock autoLock(mLock); + mListener = listener; +} + +status_t AwesomePlayer::setDataSource(const char *uri) { + Mutex::Autolock autoLock(mLock); + + reset_l(); + + sp extractor = MediaExtractor::CreateFromURI(uri); + + if (extractor == NULL) { + return UNKNOWN_ERROR; + } + + return setDataSource_l(extractor); +} + +status_t AwesomePlayer::setDataSource( + int fd, int64_t offset, int64_t length) { + Mutex::Autolock autoLock(mLock); + + reset_l(); + + sp source = new FileSource(fd, offset, length); + + status_t err = source->initCheck(); + + if (err != OK) { + return err; + } + + sp extractor = MediaExtractor::Create(source); + + if (extractor == NULL) { + return UNKNOWN_ERROR; + } + + return setDataSource_l(extractor); +} + +status_t AwesomePlayer::setDataSource_l(const sp &extractor) { + reset_l(); + + bool haveAudio = false; + bool haveVideo = false; + for (size_t i = 0; i < extractor->countTracks(); ++i) { + sp meta = extractor->getTrackMetaData(i); + + const char *mime; + CHECK(meta->findCString(kKeyMIMEType, &mime)); + + if (!haveVideo && !strncasecmp(mime, "video/", 6)) { + if (setVideoSource(extractor->getTrack(i)) == OK) { + haveVideo = true; + } + } else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) { + if (setAudioSource(extractor->getTrack(i)) == OK) { + haveAudio = true; + } + } + + if (haveAudio && haveVideo) { + break; + } + } + + return !haveAudio && !haveVideo ? UNKNOWN_ERROR : OK; +} + +void AwesomePlayer::reset() { + Mutex::Autolock autoLock(mLock); + reset_l(); +} + +void AwesomePlayer::reset_l() { + cancelPlayerEvents(); + + if (mLastVideoBuffer) { + mLastVideoBuffer->release(); + mLastVideoBuffer = NULL; + } + + if (mVideoBuffer) { + mVideoBuffer->release(); + mVideoBuffer = NULL; + } + + if (mVideoSource != NULL) { + mVideoSource->stop(); + mVideoSource.clear(); + } + + mAudioSource.clear(); + + if (mTimeSource != mAudioPlayer) { + delete mTimeSource; + } + mTimeSource = NULL; + + delete mAudioPlayer; + mAudioPlayer = NULL; + + mVideoRenderer.clear(); + + mDurationUs = -1; + mFlags = 0; + mVideoWidth = mVideoHeight = -1; + mTimeSourceDeltaUs = 0; + mVideoTimeUs = 0; + + mSeeking = false; + mSeekTimeUs = 0; +} + +// static +void AwesomePlayer::AudioNotify(void *_me, int what) { + AwesomePlayer *me = (AwesomePlayer *)_me; + + Mutex::Autolock autoLock(me->mLock); + + switch (what) { + case AudioPlayer::REACHED_EOS: + me->postStreamDoneEvent_l(); + break; + + case AudioPlayer::SEEK_COMPLETE: + { + if (me->mListener != NULL) { + me->mListener->sendEvent(MEDIA_SEEK_COMPLETE); + } + + break; + } + + default: + CHECK(!"should not be here."); + break; + } +} + +void AwesomePlayer::onStreamDone() { + // Posted whenever any stream finishes playing. + + Mutex::Autolock autoLock(mLock); + mStreamDoneEventPending = false; + + if (mFlags & LOOPING) { + seekTo_l(0); + + if (mVideoRenderer != NULL) { + postVideoEvent_l(); + } + } else { + if (mListener != NULL) { + mListener->sendEvent(MEDIA_PLAYBACK_COMPLETE); + } + + pause_l(); + } +} + +status_t AwesomePlayer::play() { + Mutex::Autolock autoLock(mLock); + + if (mFlags & PLAYING) { + return OK; + } + + mFlags |= PLAYING; + mFlags |= FIRST_FRAME; + + if (mAudioSource != NULL) { + if (mAudioPlayer == NULL) { + if (mAudioSink != NULL) { + mAudioPlayer = new AudioPlayer(mAudioSink); + + mAudioPlayer->setListenerCallback( + &AwesomePlayer::AudioNotify, this); + + mAudioPlayer->setSource(mAudioSource); + mAudioPlayer->start(); + + delete mTimeSource; + mTimeSource = mAudioPlayer; + + // If there was a seek request while we were paused + // and we're just starting up again, honor the request now. + seekAudioIfNecessary_l(); + } + } else { + mAudioPlayer->resume(); + } + } + + if (mTimeSource == NULL && mAudioPlayer == NULL) { + mTimeSource = new SystemTimeSource; + } + + if (mVideoSource != NULL) { + if (mVideoRenderer == NULL) { + initRenderer_l(); + } + + if (mVideoRenderer != NULL) { + // Kick off video playback + postVideoEvent_l(); + } + } + + return OK; +} + +void AwesomePlayer::initRenderer_l() { + if (mISurface != NULL) { + sp meta = mVideoSource->getFormat(); + + int32_t format; + const char *component; + int32_t decodedWidth, decodedHeight; + CHECK(meta->findInt32(kKeyColorFormat, &format)); + CHECK(meta->findCString(kKeyDecoderComponent, &component)); + CHECK(meta->findInt32(kKeyWidth, &decodedWidth)); + CHECK(meta->findInt32(kKeyHeight, &decodedHeight)); + + mVideoRenderer = + mClient.interface()->createRenderer( + mISurface, component, + (OMX_COLOR_FORMATTYPE)format, + decodedWidth, decodedHeight, + mVideoWidth, mVideoHeight); + } +} + +status_t AwesomePlayer::pause() { + Mutex::Autolock autoLock(mLock); + return pause_l(); +} + +status_t AwesomePlayer::pause_l() { + if (!(mFlags & PLAYING)) { + return OK; + } + + cancelPlayerEvents(); + + if (mAudioPlayer != NULL) { + mAudioPlayer->pause(); + } + + mFlags &= ~PLAYING; + + return OK; +} + +bool AwesomePlayer::isPlaying() const { + Mutex::Autolock autoLock(mLock); + + return mFlags & PLAYING; +} + +void AwesomePlayer::setISurface(const sp &isurface) { + Mutex::Autolock autoLock(mLock); + + mISurface = isurface; +} + +void AwesomePlayer::setAudioSink( + const sp &audioSink) { + Mutex::Autolock autoLock(mLock); + + mAudioSink = audioSink; +} + +status_t AwesomePlayer::setLooping(bool shouldLoop) { + Mutex::Autolock autoLock(mLock); + + mFlags = mFlags & ~LOOPING; + + if (shouldLoop) { + mFlags |= LOOPING; + } + + return OK; +} + +status_t AwesomePlayer::getDuration(int64_t *durationUs) { + Mutex::Autolock autoLock(mLock); + + if (mDurationUs < 0) { + return UNKNOWN_ERROR; + } + + *durationUs = mDurationUs; + + return OK; +} + +status_t AwesomePlayer::getPosition(int64_t *positionUs) { + Mutex::Autolock autoLock(mLock); + + if (mVideoRenderer != NULL) { + *positionUs = mVideoTimeUs; + } else if (mAudioPlayer != NULL) { + *positionUs = mAudioPlayer->getMediaTimeUs(); + } else { + *positionUs = 0; + } + + return OK; +} + +status_t AwesomePlayer::seekTo(int64_t timeUs) { + Mutex::Autolock autoLock(mLock); + return seekTo_l(timeUs); +} + +status_t AwesomePlayer::seekTo_l(int64_t timeUs) { + mSeeking = true; + mSeekTimeUs = timeUs; + + seekAudioIfNecessary_l(); + + return OK; +} + +void AwesomePlayer::seekAudioIfNecessary_l() { + if (mSeeking && mVideoRenderer == NULL && mAudioPlayer != NULL) { + mAudioPlayer->seekTo(mSeekTimeUs); + + mSeeking = false; + } +} + +status_t AwesomePlayer::getVideoDimensions( + int32_t *width, int32_t *height) const { + Mutex::Autolock autoLock(mLock); + + if (mVideoWidth < 0 || mVideoHeight < 0) { + return UNKNOWN_ERROR; + } + + *width = mVideoWidth; + *height = mVideoHeight; + + return OK; +} + +status_t AwesomePlayer::setAudioSource(const sp &source) { + if (source == NULL) { + return UNKNOWN_ERROR; + } + + mAudioSource = OMXCodec::Create( + mClient.interface(), source->getFormat(), + false, // createEncoder + source); + + if (mAudioSource != NULL) { + int64_t durationUs; + if (source->getFormat()->findInt64(kKeyDuration, &durationUs)) { + if (mDurationUs < 0 || durationUs > mDurationUs) { + mDurationUs = durationUs; + } + } + } + + return mAudioSource != NULL ? OK : UNKNOWN_ERROR; +} + +status_t AwesomePlayer::setVideoSource(const sp &source) { + if (source == NULL) { + return UNKNOWN_ERROR; + } + + mVideoSource = OMXCodec::Create( + mClient.interface(), source->getFormat(), + false, // createEncoder + source); + + if (mVideoSource != NULL) { + int64_t durationUs; + if (source->getFormat()->findInt64(kKeyDuration, &durationUs)) { + if (mDurationUs < 0 || durationUs > mDurationUs) { + mDurationUs = durationUs; + } + } + + CHECK(source->getFormat()->findInt32(kKeyWidth, &mVideoWidth)); + CHECK(source->getFormat()->findInt32(kKeyHeight, &mVideoHeight)); + + mVideoSource->start(); + } + + return mVideoSource != NULL ? OK : UNKNOWN_ERROR; +} + +void AwesomePlayer::onEvent(int32_t code) { + if (code == 1) { + onStreamDone(); + return; + } + + Mutex::Autolock autoLock(mLock); + mVideoEventPending = false; + + if (mSeeking) { + if (mLastVideoBuffer) { + mLastVideoBuffer->release(); + mLastVideoBuffer = NULL; + } + + if (mVideoBuffer) { + mVideoBuffer->release(); + mVideoBuffer = NULL; + } + } + + if (!mVideoBuffer) { + MediaSource::ReadOptions options; + if (mSeeking) { + LOGV("seeking to %lld us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6); + + options.setSeekTo(mSeekTimeUs); + } + for (;;) { + status_t err = mVideoSource->read(&mVideoBuffer, &options); + + if (err != OK) { + CHECK_EQ(mVideoBuffer, NULL); + + if (err == INFO_FORMAT_CHANGED) { + LOGV("VideoSource signalled format change."); + + initRenderer_l(); + continue; + } + + postStreamDoneEvent_l(); + return; + } + + break; + } + } + + int64_t timeUs; + CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs)); + + mVideoTimeUs = timeUs; + + if (mSeeking) { + if (mAudioPlayer != NULL) { + LOGV("seeking audio to %lld us (%.2f secs).", timeUs, timeUs / 1E6); + + mAudioPlayer->seekTo(timeUs); + } else { + // If we're playing video only, report seek complete now, + // otherwise audio player will notify us later. + if (mListener != NULL) { + mListener->sendEvent(MEDIA_SEEK_COMPLETE); + } + } + + mFlags |= FIRST_FRAME; + mSeeking = false; + } + + if (mFlags & FIRST_FRAME) { + mFlags &= ~FIRST_FRAME; + + mTimeSourceDeltaUs = mTimeSource->getRealTimeUs() - timeUs; + } + + int64_t realTimeUs, mediaTimeUs; + if (mAudioPlayer != NULL + && mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) { + mTimeSourceDeltaUs = realTimeUs - mediaTimeUs; + } + + int64_t nowUs = mTimeSource->getRealTimeUs() - mTimeSourceDeltaUs; + + int64_t latenessUs = nowUs - timeUs; + + if (latenessUs > 20000) { + // We're more than 20ms late. + LOGV("we're late by %lld us (%.2f secs)", latenessUs, latenessUs / 1E6); + + mVideoBuffer->release(); + mVideoBuffer = NULL; + + postVideoEvent_l(); + return; + } + + if (latenessUs < -10000) { + // We're more than 10ms early. + + postVideoEvent_l(10000); + return; + } + + void *id; + if (mVideoBuffer->meta_data()->findPointer(kKeyBufferID, &id)) { + mVideoRenderer->render((IOMX::buffer_id)id); + } + + if (mLastVideoBuffer) { + mLastVideoBuffer->release(); + mLastVideoBuffer = NULL; + } + mLastVideoBuffer = mVideoBuffer; + mVideoBuffer = NULL; + + postVideoEvent_l(); +} + +void AwesomePlayer::postVideoEvent_l(int64_t delayUs) { + if (mVideoEventPending) { + return; + } + + mVideoEventPending = true; + mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs); +} + +void AwesomePlayer::postStreamDoneEvent_l() { + if (mStreamDoneEventPending) { + return; + } + mStreamDoneEventPending = true; + mQueue.postEvent(mStreamDoneEvent); +} + +} // namespace android + diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp index 19a1f85..9d3deb7 100644 --- a/media/libstagefright/MediaExtractor.cpp +++ b/media/libstagefright/MediaExtractor.cpp @@ -25,10 +25,10 @@ #include #include +#include #include #include #include -#include #include namespace android { @@ -70,13 +70,13 @@ sp MediaExtractor::CreateFromURI( const char *uri, const char *mime) { sp source; if (!strncasecmp("file://", uri, 7)) { - source = new MmapSource(uri + 7); + source = new FileSource(uri + 7); } else if (!strncasecmp("http://", uri, 7)) { source = new HTTPDataSource(uri); source = new CachingDataSource(source, 64 * 1024, 10); } else { // Assume it's a filename. - source = new MmapSource(uri); + source = new FileSource(uri); } if (source == NULL || source->initCheck() != OK) { diff --git a/media/libstagefright/MediaPlayerImpl.cpp b/media/libstagefright/MediaPlayerImpl.cpp deleted file mode 100644 index c1044a3..0000000 --- a/media/libstagefright/MediaPlayerImpl.cpp +++ /dev/null @@ -1,658 +0,0 @@ -/* - * Copyright (C) 2009 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 "MediaPlayerImpl" -#include "utils/Log.h" - -#include "include/stagefright_string.h" -#include "include/HTTPStream.h" - -#include - -#include - -#include -// #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace android { - -MediaPlayerImpl::MediaPlayerImpl(const char *uri) - : mInitCheck(NO_INIT), - mTimeSource(NULL), - mAudioPlayer(NULL), - mVideoWidth(0), - mVideoHeight(0), - mVideoPosition(0), - mDuration(0), - mPlaying(false), - mPaused(false), - mSeeking(false) { - LOGV("MediaPlayerImpl(%s)", uri); - DataSource::RegisterDefaultSniffers(); - - status_t err = mClient.connect(); - if (err != OK) { - LOGE("Failed to connect to OMXClient."); - return; - } - - if (!strncasecmp("shoutcast://", uri, 12)) { - setAudioSource(makeShoutcastSource(uri)); -#if 0 - } else if (!strncasecmp("camera:", uri, 7)) { - mVideoWidth = 480; - mVideoHeight = 320; - mVideoDecoder = CameraSource::Create(); -#endif - } else { - mExtractor = MediaExtractor::CreateFromURI(uri); - - if (mExtractor == NULL) { - return; - } - } - - init(); - - mInitCheck = OK; -} - -MediaPlayerImpl::MediaPlayerImpl(int fd, int64_t offset, int64_t length) - : mInitCheck(NO_INIT), - mTimeSource(NULL), - mAudioPlayer(NULL), - mVideoWidth(0), - mVideoHeight(0), - mVideoPosition(0), - mDuration(0), - mPlaying(false), - mPaused(false), - mSeeking(false) { - LOGV("MediaPlayerImpl(%d, %lld, %lld)", fd, offset, length); - DataSource::RegisterDefaultSniffers(); - - status_t err = mClient.connect(); - if (err != OK) { - LOGE("Failed to connect to OMXClient."); - return; - } - - mExtractor = MediaExtractor::Create( - new MmapSource(fd, offset, length)); - - if (mExtractor == NULL) { - return; - } - - init(); - - mInitCheck = OK; -} - -status_t MediaPlayerImpl::initCheck() const { - return mInitCheck; -} - -MediaPlayerImpl::~MediaPlayerImpl() { - stop(); - setSurface(NULL); - - if (mInitCheck == OK) { - mClient.disconnect(); - } - - LOGV("~MediaPlayerImpl done."); -} - -void MediaPlayerImpl::play() { - LOGV("play"); - - if (mPlaying) { - if (mPaused) { - if (mAudioSource != NULL) { - mAudioPlayer->resume(); - } - mPaused = false; - } - return; - } - - mPlaying = true; - - if (mAudioSource != NULL) { - mAudioPlayer = new AudioPlayer(mAudioSink); - mAudioPlayer->setSource(mAudioDecoder); - - if (mVideoDecoder == NULL) { - // If there is no video, start playing right away, - // otherwise we'll start the audio player after we decode - // the first video frame, this way we won't be behind right - // away. - mAudioPlayer->start(); - } - - mTimeSource = mAudioPlayer; - } else { - mTimeSource = new SystemTimeSource; - } - - if (mVideoDecoder != NULL) { - pthread_attr_t attr; - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); - - pthread_create(&mVideoThread, &attr, VideoWrapper, this); - - pthread_attr_destroy(&attr); - } -} - -void MediaPlayerImpl::pause() { - if (!mPlaying || mPaused) { - return; - } - - if (mAudioSource != NULL) { - mAudioPlayer->pause(); - } - - mPaused = true; -} - -void MediaPlayerImpl::stop() { - if (!mPlaying) { - return; - } - - mPlaying = false; - - if (mVideoDecoder != NULL) { - void *dummy; - pthread_join(mVideoThread, &dummy); - } - - if (mAudioSource != NULL) { - mAudioPlayer->stop(); - - delete mAudioPlayer; - mAudioPlayer = NULL; - } else { - delete mTimeSource; - } - - mTimeSource = NULL; -} - -// static -void *MediaPlayerImpl::VideoWrapper(void *me) { - ((MediaPlayerImpl *)me)->videoEntry(); - - return NULL; -} - -void MediaPlayerImpl::videoEntry() { - bool firstFrame = true; - bool eof = false; - - status_t err = mVideoDecoder->start(); - CHECK_EQ(err, OK); - - while (mPlaying) { - MediaBuffer *buffer; - - MediaSource::ReadOptions options; - bool seeking = false; - - { - Mutex::Autolock autoLock(mLock); - if (mSeeking) { - LOGV("seek-options to %lld", mSeekTimeUs); - options.setSeekTo(mSeekTimeUs); - - mSeeking = false; - seeking = true; - eof = false; - } - } - - if (eof || mPaused) { - usleep(100000); - continue; - } - - status_t err = mVideoDecoder->read(&buffer, &options); - CHECK((err == OK && buffer != NULL) || (err != OK && buffer == NULL)); - - if (err == INFO_FORMAT_CHANGED) { - LOGV("format changed."); - depopulateISurface(); - populateISurface(); - continue; - } - - if (err == ERROR_END_OF_STREAM || err != OK) { - eof = true; - continue; - } - - if (buffer->range_length() == 0) { - // The final buffer is empty. - buffer->release(); - continue; - } - - int64_t pts_us; - CHECK(buffer->meta_data()->findInt64(kKeyTime, &pts_us)); - - { - Mutex::Autolock autoLock(mLock); - mVideoPosition = pts_us; - - LOGV("now_video = %.2f secs (%lld ms)", - pts_us / 1E6, (pts_us + 500) / 1000); - } - - if (seeking && mAudioPlayer != NULL) { - // Now that we know where exactly video seeked (taking sync-samples - // into account), we will seek the audio track to the same time. - mAudioPlayer->seekTo(pts_us); - } - - if (firstFrame || seeking) { - if (firstFrame && mAudioPlayer != NULL) { - // We've deferred starting the audio player until now. - mAudioPlayer->start(); - } - mTimeSourceDeltaUs = mTimeSource->getRealTimeUs() - pts_us; - firstFrame = false; - } - - displayOrDiscardFrame(buffer, pts_us); - } - - mVideoDecoder->stop(); -} - -void MediaPlayerImpl::displayOrDiscardFrame( - MediaBuffer *buffer, int64_t pts_us) { - for (;;) { - if (!mPlaying || mPaused) { - buffer->release(); - buffer = NULL; - - return; - } - - int64_t realtime_us, mediatime_us; - if (mAudioPlayer != NULL - && mAudioPlayer->getMediaTimeMapping(&realtime_us, &mediatime_us)) { - mTimeSourceDeltaUs = realtime_us - mediatime_us; - LOGV("mTimeSourceDeltaUs = %.2f secs", mTimeSourceDeltaUs / 1E6); - } - - int64_t now_us = mTimeSource->getRealTimeUs(); - now_us -= mTimeSourceDeltaUs; - - int64_t delay_us = pts_us - now_us; - - if (delay_us < -15000) { - // We're late. - - LOGV("we're late by %lld ms, dropping a frame\n", - -delay_us / 1000); - - buffer->release(); - buffer = NULL; - return; - } else if (delay_us > 100000) { - LOGV("we're much too early (by %lld ms)\n", - delay_us / 1000); - usleep(100000); - continue; - } else if (delay_us > 0) { - usleep(delay_us); - } - - break; - } - - { - Mutex::Autolock autoLock(mLock); - if (mVideoRenderer.get() != NULL) { - sendFrameToISurface(buffer); - } - } - - buffer->release(); - buffer = NULL; -} - -void MediaPlayerImpl::init() { - if (mExtractor != NULL) { - size_t num_tracks = mExtractor->countTracks(); - - mDuration = 0; - - for (size_t i = 0; i < num_tracks; ++i) { - const sp meta = mExtractor->getTrackMetaData(i); - CHECK(meta != NULL); - - const char *mime; - if (!meta->findCString(kKeyMIMEType, &mime)) { - continue; - } - - bool is_audio = false; - bool is_acceptable = false; - if (!strncasecmp(mime, "audio/", 6)) { - is_audio = true; - is_acceptable = (mAudioSource == NULL); - } else if (!strncasecmp(mime, "video/", 6)) { - is_acceptable = (mVideoSource == NULL); - } - - if (!is_acceptable) { - continue; - } - - sp source = mExtractor->getTrack(i); - - int64_t durationUs; - if (meta->findInt64(kKeyDuration, &durationUs)) { - if (durationUs > mDuration) { - mDuration = durationUs; - } - } - - if (is_audio) { - setAudioSource(source); - } else { - setVideoSource(source); - } - } - } -} - -void MediaPlayerImpl::setAudioSource(const sp &source) { - LOGV("setAudioSource"); - mAudioSource = source; - - sp meta = source->getFormat(); - - const char *mime; - CHECK(meta->findCString(kKeyMIMEType, &mime)); - - if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) { - mAudioDecoder = source; - } else { - mAudioDecoder = OMXCodec::Create( - mClient.interface(), meta, false /* createEncoder */, source); - } -} - -void MediaPlayerImpl::setVideoSource(const sp &source) { - LOGV("setVideoSource"); - mVideoSource = source; - - sp meta = source->getFormat(); - - bool success = meta->findInt32(kKeyWidth, &mVideoWidth); - CHECK(success); - - success = meta->findInt32(kKeyHeight, &mVideoHeight); - CHECK(success); - - mVideoDecoder = OMXCodec::Create( - mClient.interface(), meta, false /* createEncoder */, source); - - if (mISurface.get() != NULL || mSurface.get() != NULL) { - depopulateISurface(); - populateISurface(); - } -} - -void MediaPlayerImpl::setSurface(const sp &surface) { - LOGV("setSurface %p", surface.get()); - Mutex::Autolock autoLock(mLock); - - depopulateISurface(); - - mSurface = surface; - mISurface = NULL; - - if (mSurface.get() != NULL) { - populateISurface(); - } -} - -void MediaPlayerImpl::setISurface(const sp &isurface) { - LOGV("setISurface %p", isurface.get()); - Mutex::Autolock autoLock(mLock); - - depopulateISurface(); - - mSurface = NULL; - mISurface = isurface; - - if (mISurface.get() != NULL) { - populateISurface(); - } -} - -MediaSource *MediaPlayerImpl::makeShoutcastSource(const char *uri) { - if (strncasecmp(uri, "shoutcast://", 12)) { - return NULL; - } - - string host; - string path; - int port; - - char *slash = strchr(uri + 12, '/'); - if (slash == NULL) { - host = uri + 12; - path = "/"; - } else { - host = string(uri + 12, slash - (uri + 12)); - path = slash; - } - - char *colon = strchr(host.c_str(), ':'); - if (colon == NULL) { - port = 80; - } else { - char *end; - long tmp = strtol(colon + 1, &end, 10); - CHECK(end > colon + 1); - CHECK(tmp > 0 && tmp < 65536); - port = tmp; - - host = string(host, 0, colon - host.c_str()); - } - - LOGV("Connecting to host '%s', port %d, path '%s'", - host.c_str(), port, path.c_str()); - - HTTPStream *http = new HTTPStream; - int http_status; - - for (;;) { - status_t err = http->connect(host.c_str(), port); - CHECK_EQ(err, OK); - - err = http->send("GET "); - err = http->send(path.c_str()); - err = http->send(" HTTP/1.1\r\n"); - err = http->send("Host: "); - err = http->send(host.c_str()); - err = http->send("\r\n"); - err = http->send("Icy-MetaData: 1\r\n\r\n"); - - CHECK_EQ(OK, http->receive_header(&http_status)); - - if (http_status == 301 || http_status == 302) { - string location; - CHECK(http->find_header_value("Location", &location)); - - CHECK(string(location, 0, 7) == "http://"); - location.erase(0, 7); - string::size_type slashPos = location.find('/'); - if (slashPos == string::npos) { - slashPos = location.size(); - location += '/'; - } - - http->disconnect(); - - LOGV("Redirecting to %s\n", location.c_str()); - - host = string(location, 0, slashPos); - - string::size_type colonPos = host.find(':'); - if (colonPos != string::npos) { - const char *start = host.c_str() + colonPos + 1; - char *end; - long tmp = strtol(start, &end, 10); - CHECK(end > start && (*end == '\0')); - - port = (tmp >= 0 && tmp < 65536) ? (int)tmp : 80; - } else { - port = 80; - } - - path = string(location, slashPos); - - continue; - } - - break; - } - - if (http_status != 200) { - LOGE("Connection failed: http_status = %d", http_status); - return NULL; - } - - MediaSource *source = new ShoutcastSource(http); - - return source; -} - -bool MediaPlayerImpl::isPlaying() const { - return mPlaying && !mPaused; -} - -int64_t MediaPlayerImpl::getDuration() { - return mDuration; -} - -int64_t MediaPlayerImpl::getPosition() { - int64_t position = 0; - if (mVideoSource != NULL) { - Mutex::Autolock autoLock(mLock); - position = mVideoPosition; - } else if (mAudioPlayer != NULL) { - position = mAudioPlayer->getMediaTimeUs(); - } - - return position; -} - -status_t MediaPlayerImpl::seekTo(int64_t time) { - LOGV("seekTo %lld", time); - - if (mPaused) { - return UNKNOWN_ERROR; - } - - if (mVideoSource == NULL && mAudioPlayer != NULL) { - mAudioPlayer->seekTo(time); - } else { - Mutex::Autolock autoLock(mLock); - mSeekTimeUs = time; - mSeeking = true; - } - - return OK; -} - -void MediaPlayerImpl::populateISurface() { - if (mVideoSource == NULL) { - return; - } - - sp meta = mVideoDecoder->getFormat(); - - int32_t format; - const char *component; - int32_t decodedWidth, decodedHeight; - bool success = meta->findInt32(kKeyColorFormat, &format); - success = success && meta->findCString(kKeyDecoderComponent, &component); - success = success && meta->findInt32(kKeyWidth, &decodedWidth); - success = success && meta->findInt32(kKeyHeight, &decodedHeight); - CHECK(success); - - LOGV("mVideoWidth=%d, mVideoHeight=%d, decodedWidth=%d, decodedHeight=%d", - mVideoWidth, mVideoHeight, decodedWidth, decodedHeight); - - if (mSurface.get() != NULL) { - mVideoRenderer = - mClient.interface()->createRenderer( - mSurface, component, - (OMX_COLOR_FORMATTYPE)format, - decodedWidth, decodedHeight, - mVideoWidth, mVideoHeight); - } else { - mVideoRenderer = - mClient.interface()->createRenderer( - mISurface, component, - (OMX_COLOR_FORMATTYPE)format, - decodedWidth, decodedHeight, - mVideoWidth, mVideoHeight); - } -} - -void MediaPlayerImpl::depopulateISurface() { - mVideoRenderer.clear(); -} - -void MediaPlayerImpl::sendFrameToISurface(MediaBuffer *buffer) { - void *id; - if (buffer->meta_data()->findPointer(kKeyBufferID, &id)) { - mVideoRenderer->render((IOMX::buffer_id)id); - } -} - -void MediaPlayerImpl::setAudioSink( - const sp &audioSink) { - LOGV("setAudioSink %p", audioSink.get()); - mAudioSink = audioSink; -} - -} // namespace android - diff --git a/media/libstagefright/MmapSource.cpp b/media/libstagefright/MmapSource.cpp deleted file mode 100644 index 42749cf..0000000 --- a/media/libstagefright/MmapSource.cpp +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (C) 2009 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 "MmapSource" -#include - -#include - -#include -#include -#include - -#include -#include - -namespace android { - -MmapSource::MmapSource(const char *filename) - : mFd(open(filename, O_RDONLY)), - mBase(NULL), - mSize(0) { - LOGV("MmapSource '%s'", filename); - - if (mFd < 0) { - return; - } - - off_t size = lseek(mFd, 0, SEEK_END); - mSize = (size_t)size; - - mBase = mmap(0, mSize, PROT_READ, MAP_FILE | MAP_SHARED, mFd, 0); - - if (mBase == (void *)-1) { - mBase = NULL; - - close(mFd); - mFd = -1; - } -} - -MmapSource::MmapSource(int fd, int64_t offset, int64_t length) - : mFd(fd), - mBase(NULL), - mSize(length) { - LOGV("MmapSource fd:%d offset:%lld length:%lld", fd, offset, length); - CHECK(fd >= 0); - - mBase = mmap(0, mSize, PROT_READ, MAP_FILE | MAP_SHARED, mFd, offset); - - if (mBase == (void *)-1) { - mBase = NULL; - - close(mFd); - mFd = -1; - } - -} - -MmapSource::~MmapSource() { - if (mFd != -1) { - munmap(mBase, mSize); - mBase = NULL; - mSize = 0; - - close(mFd); - mFd = -1; - } -} - -status_t MmapSource::initCheck() const { - return mFd == -1 ? NO_INIT : OK; -} - -ssize_t MmapSource::readAt(off_t offset, void *data, size_t size) { - LOGV("readAt offset:%ld data:%p size:%d", offset, data, size); - CHECK(offset >= 0); - - size_t avail = 0; - if (offset >= 0 && offset < (off_t)mSize) { - avail = mSize - offset; - } - - if (size > avail) { - size = avail; - } - - memcpy(data, (const uint8_t *)mBase + offset, size); - - return (ssize_t)size; -} - -status_t MmapSource::getSize(off_t *size) { - *size = mSize; - - return OK; -} - -} // namespace android - diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index d36653e..9297aff 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include diff --git a/media/libstagefright/TimedEventQueue.cpp b/media/libstagefright/TimedEventQueue.cpp index fa68771..d079e70 100644 --- a/media/libstagefright/TimedEventQueue.cpp +++ b/media/libstagefright/TimedEventQueue.cpp @@ -135,7 +135,9 @@ static bool MatchesEventID( } bool TimedEventQueue::cancelEvent(event_id id) { - CHECK(id != 0); + if (id == 0) { + return false; + } cancelEvents(&MatchesEventID, &id, true /* stopAfterFirstMatch */); @@ -162,6 +164,7 @@ void TimedEventQueue::cancelEvents( mQueueHeadChangedCondition.signal(); } + (*it).event->setEventID(0); it = mQueue.erase(it); if (stopAfterFirstMatch) { @@ -228,7 +231,12 @@ void TimedEventQueue::threadEntry() { } } + if (mQueue.empty()) { + continue; + } + event = (*it).event; + event->setEventID(0); mQueue.erase(it); } diff --git a/media/libstagefright/include/AMRExtractor.h b/media/libstagefright/include/AMRExtractor.h index debf006..1972a1c 100644 --- a/media/libstagefright/include/AMRExtractor.h +++ b/media/libstagefright/include/AMRExtractor.h @@ -32,14 +32,14 @@ public: virtual sp getTrack(size_t index); virtual sp getTrackMetaData(size_t index, uint32_t flags); - static sp makeAMRFormat(bool isWide); - protected: virtual ~AMRExtractor(); private: sp mDataSource; + sp mMeta; status_t mInitCheck; + size_t mFrameSize; bool mIsWide; AMRExtractor(const AMRExtractor &); diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h new file mode 100644 index 0000000..2727c3c --- /dev/null +++ b/media/libstagefright/include/AwesomePlayer.h @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2009 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 AWESOME_PLAYER_H_ + +#define AWESOME_PLAYER_H_ + +#include "TimedEventQueue.h" + +#include +#include +#include + +namespace android { + +struct MediaBuffer; +struct MediaExtractor; +struct MediaSource; +struct AudioPlayer; +struct TimeSource; + +struct AwesomePlayer { + AwesomePlayer(); + ~AwesomePlayer(); + + void setListener(const sp &listener); + + status_t setDataSource(const char *uri); + status_t setDataSource(int fd, int64_t offset, int64_t length); + + void reset(); + + status_t play(); + status_t pause(); + + bool isPlaying() const; + + void setISurface(const sp &isurface); + void setAudioSink(const sp &audioSink); + status_t setLooping(bool shouldLoop); + + status_t getDuration(int64_t *durationUs); + status_t getPosition(int64_t *positionUs); + + status_t seekTo(int64_t timeUs); + + status_t getVideoDimensions(int32_t *width, int32_t *height) const; + +private: + friend struct AwesomeEvent; + + enum Flags { + PLAYING = 1, + LOOPING = 2, + FIRST_FRAME = 4, + }; + + mutable Mutex mLock; + + OMXClient mClient; + TimedEventQueue mQueue; + sp mListener; + + sp mISurface; + sp mAudioSink; + + TimeSource *mTimeSource; + + sp mVideoSource; + sp mVideoRenderer; + + sp mAudioSource; + AudioPlayer *mAudioPlayer; + int64_t mDurationUs; + + uint32_t mFlags; + + int32_t mVideoWidth, mVideoHeight; + int64_t mTimeSourceDeltaUs; + int64_t mVideoTimeUs; + + bool mSeeking; + int64_t mSeekTimeUs; + + sp mVideoEvent; + bool mVideoEventPending; + sp mStreamDoneEvent; + bool mStreamDoneEventPending; + + void postVideoEvent_l(int64_t delayUs = -1); + void postStreamDoneEvent_l(); + + MediaBuffer *mLastVideoBuffer; + MediaBuffer *mVideoBuffer; + + status_t setDataSource_l(const sp &extractor); + void reset_l(); + status_t seekTo_l(int64_t timeUs); + status_t pause_l(); + void initRenderer_l(); + void seekAudioIfNecessary_l(); + + void cancelPlayerEvents(); + + status_t setAudioSource(const sp &source); + status_t setVideoSource(const sp &source); + + void onEvent(int32_t code); + + static void AudioNotify(void *me, int what); + void onStreamDone(); + + AwesomePlayer(const AwesomePlayer &); + AwesomePlayer &operator=(const AwesomePlayer &); +}; + +} // namespace android + +#endif // AWESOME_PLAYER_H_ + -- cgit v1.1