summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authorAndreas Huber <andih@google.com>2009-11-20 09:32:46 -0800
committerAndreas Huber <andih@google.com>2009-11-23 10:44:30 -0800
commitbfa6b2d7a1be1832ac40ed90aece1834f720b5c6 (patch)
tree5b4948c52fde583d593d088ffc4a7f772c904a86 /media
parentbf89c099fc97717e3008a481aeddc76c1ac5e00d (diff)
downloadframeworks_av-bfa6b2d7a1be1832ac40ed90aece1834f720b5c6.zip
frameworks_av-bfa6b2d7a1be1832ac40ed90aece1834f720b5c6.tar.gz
frameworks_av-bfa6b2d7a1be1832ac40ed90aece1834f720b5c6.tar.bz2
Squashed commit of the following:
commit 1efc38dc3c33fef57b759002db3965ed07a28cb0 Author: Andreas Huber <andih@google.com> 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 <andih@google.com> 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 <andih@google.com> 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 <andih@google.com> 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 <andih@google.com> Date: Wed Nov 18 10:21:44 2009 -0800 MediaPlayerImpl is dead, long live AwesomePlayer. commit c5b52d3c0674f5dc94db506afbce52401cceddac Author: Andreas Huber <andih@google.com> Date: Wed Nov 18 09:42:23 2009 -0800 New implementation of the stagefright mediaplayer.
Diffstat (limited to 'media')
-rw-r--r--media/libmediaplayerservice/StagefrightMetadataRetriever.cpp4
-rw-r--r--media/libmediaplayerservice/StagefrightPlayer.cpp115
-rw-r--r--media/libmediaplayerservice/StagefrightPlayer.h4
-rw-r--r--media/libstagefright/AMRExtractor.cpp106
-rw-r--r--media/libstagefright/Android.mk3
-rw-r--r--media/libstagefright/AudioPlayer.cpp19
-rw-r--r--media/libstagefright/AwesomePlayer.cpp626
-rw-r--r--media/libstagefright/MediaExtractor.cpp6
-rw-r--r--media/libstagefright/MediaPlayerImpl.cpp658
-rw-r--r--media/libstagefright/MmapSource.cpp113
-rw-r--r--media/libstagefright/OMXCodec.cpp1
-rw-r--r--media/libstagefright/TimedEventQueue.cpp10
-rw-r--r--media/libstagefright/include/AMRExtractor.h4
-rw-r--r--media/libstagefright/include/AwesomePlayer.h133
14 files changed, 906 insertions, 896 deletions
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 <media/stagefright/CachingDataSource.h>
#include <media/stagefright/ColorConverter.h>
#include <media/stagefright/DataSource.h>
+#include <media/stagefright/FileSource.h>
#include <media/stagefright/HTTPDataSource.h>
#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaExtractor.h>
#include <media/stagefright/MetaData.h>
-#include <media/stagefright/MmapSource.h>
#include <media/stagefright/OMXCodec.h>
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 <utils/Log.h>
#include "StagefrightPlayer.h"
-#include <media/stagefright/MediaPlayerImpl.h>
+
+#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<ISurface> &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> &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> &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<DataSource> &source, bool isWide);
+ AMRSource(const sp<DataSource> &source,
+ const sp<MetaData> &meta,
+ size_t frameSize,
+ bool isWide);
virtual status_t start(MetaData *params = NULL);
virtual status_t stop();
@@ -48,6 +51,8 @@ protected:
private:
sp<DataSource> mDataSource;
+ sp<MetaData> 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<DataSource> &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<MediaSource> AMRExtractor::getTrack(size_t index) {
return NULL;
}
- return new AMRSource(mDataSource, mIsWide);
+ return new AMRSource(mDataSource, mMeta, mFrameSize, mIsWide);
}
sp<MetaData> AMRExtractor::getTrackMetaData(size_t index, uint32_t flags) {
@@ -92,26 +145,17 @@ sp<MetaData> AMRExtractor::getTrackMetaData(size_t index, uint32_t flags) {
return NULL;
}
- return makeAMRFormat(mIsWide);
-}
-
-// static
-sp<MetaData> AMRExtractor::makeAMRFormat(bool isWide) {
- sp<MetaData> 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<DataSource> &source, bool isWide)
+AMRSource::AMRSource(
+ const sp<DataSource> &source, const sp<MetaData> &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<MetaData> 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<MediaSource> &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 <utils/Log.h>
+
+#include "include/AwesomePlayer.h"
+
+#include <media/stagefright/AudioPlayer.h>
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/FileSource.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaExtractor.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/OMXCodec.h>
+
+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<MediaPlayerBase> &listener) {
+ Mutex::Autolock autoLock(mLock);
+ mListener = listener;
+}
+
+status_t AwesomePlayer::setDataSource(const char *uri) {
+ Mutex::Autolock autoLock(mLock);
+
+ reset_l();
+
+ sp<MediaExtractor> 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<DataSource> source = new FileSource(fd, offset, length);
+
+ status_t err = source->initCheck();
+
+ if (err != OK) {
+ return err;
+ }
+
+ sp<MediaExtractor> extractor = MediaExtractor::Create(source);
+
+ if (extractor == NULL) {
+ return UNKNOWN_ERROR;
+ }
+
+ return setDataSource_l(extractor);
+}
+
+status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) {
+ reset_l();
+
+ bool haveAudio = false;
+ bool haveVideo = false;
+ for (size_t i = 0; i < extractor->countTracks(); ++i) {
+ sp<MetaData> 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<MetaData> 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> &isurface) {
+ Mutex::Autolock autoLock(mLock);
+
+ mISurface = isurface;
+}
+
+void AwesomePlayer::setAudioSink(
+ const sp<MediaPlayerBase::AudioSink> &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<MediaSource> &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<MediaSource> &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 <media/stagefright/CachingDataSource.h>
#include <media/stagefright/DataSource.h>
+#include <media/stagefright/FileSource.h>
#include <media/stagefright/HTTPDataSource.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaExtractor.h>
-#include <media/stagefright/MmapSource.h>
#include <utils/String8.h>
namespace android {
@@ -70,13 +70,13 @@ sp<MediaExtractor> MediaExtractor::CreateFromURI(
const char *uri, const char *mime) {
sp<DataSource> 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 <OMX_Component.h>
-
-#include <unistd.h>
-
-#include <media/stagefright/AudioPlayer.h>
-// #include <media/stagefright/CameraSource.h>
-#include <media/stagefright/MediaDebug.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaExtractor.h>
-#include <media/stagefright/MediaPlayerImpl.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/MmapSource.h>
-#include <media/stagefright/OMXCodec.h>
-#include <media/stagefright/ShoutcastSource.h>
-#include <media/stagefright/TimeSource.h>
-#include <ui/PixelFormat.h>
-#include <ui/Surface.h>
-
-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<MetaData> 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<MediaSource> 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<MediaSource> &source) {
- LOGV("setAudioSource");
- mAudioSource = source;
-
- sp<MetaData> 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<MediaSource> &source) {
- LOGV("setVideoSource");
- mVideoSource = source;
-
- sp<MetaData> 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> &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> &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<MetaData> 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<MediaPlayerBase::AudioSink> &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 <utils/Log.h>
-
-#include <sys/mman.h>
-
-#include <fcntl.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <media/stagefright/MediaDebug.h>
-#include <media/stagefright/MmapSource.h>
-
-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 <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaExtractor.h>
#include <media/stagefright/MetaData.h>
-#include <media/stagefright/MmapSource.h>
#include <media/stagefright/OMXCodec.h>
#include <media/stagefright/Utils.h>
#include <utils/Vector.h>
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<MediaSource> getTrack(size_t index);
virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
- static sp<MetaData> makeAMRFormat(bool isWide);
-
protected:
virtual ~AMRExtractor();
private:
sp<DataSource> mDataSource;
+ sp<MetaData> 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 <media/MediaPlayerInterface.h>
+#include <media/stagefright/OMXClient.h>
+#include <utils/threads.h>
+
+namespace android {
+
+struct MediaBuffer;
+struct MediaExtractor;
+struct MediaSource;
+struct AudioPlayer;
+struct TimeSource;
+
+struct AwesomePlayer {
+ AwesomePlayer();
+ ~AwesomePlayer();
+
+ void setListener(const sp<MediaPlayerBase> &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> &isurface);
+ void setAudioSink(const sp<MediaPlayerBase::AudioSink> &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<MediaPlayerBase> mListener;
+
+ sp<ISurface> mISurface;
+ sp<MediaPlayerBase::AudioSink> mAudioSink;
+
+ TimeSource *mTimeSource;
+
+ sp<MediaSource> mVideoSource;
+ sp<IOMXRenderer> mVideoRenderer;
+
+ sp<MediaSource> 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<TimedEventQueue::Event> mVideoEvent;
+ bool mVideoEventPending;
+ sp<TimedEventQueue::Event> mStreamDoneEvent;
+ bool mStreamDoneEventPending;
+
+ void postVideoEvent_l(int64_t delayUs = -1);
+ void postStreamDoneEvent_l();
+
+ MediaBuffer *mLastVideoBuffer;
+ MediaBuffer *mVideoBuffer;
+
+ status_t setDataSource_l(const sp<MediaExtractor> &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<MediaSource> &source);
+ status_t setVideoSource(const sp<MediaSource> &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_
+