From afed0e1fa37473a4cd30018577b560acc79d9a3f Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Tue, 20 Sep 2011 15:39:58 -0700 Subject: [PATCH] Use NuPlayer for media playback everywhere if media.stagefright.use-nuplayer is set to true. Change-Id: Ibb217e7d7d5195b7feeea557554fe78e1585744c --- cmds/stagefright/sf2.cpp | 8 +- media/libmediaplayerservice/MediaPlayerService.cpp | 6 + .../MetadataRetrieverClient.cpp | 1 + media/libmediaplayerservice/nuplayer/Android.mk | 1 + .../nuplayer/GenericSource.cpp | 265 +++++++++++++++++++++ .../libmediaplayerservice/nuplayer/GenericSource.h | 79 ++++++ media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 37 ++- media/libmediaplayerservice/nuplayer/NuPlayer.h | 5 +- .../nuplayer/NuPlayerDecoder.cpp | 14 ++ .../nuplayer/NuPlayerDriver.cpp | 13 +- .../nuplayer/NuPlayerRenderer.cpp | 3 +- 11 files changed, 420 insertions(+), 12 deletions(-) create mode 100644 media/libmediaplayerservice/nuplayer/GenericSource.cpp create mode 100644 media/libmediaplayerservice/nuplayer/GenericSource.h diff --git a/cmds/stagefright/sf2.cpp b/cmds/stagefright/sf2.cpp index e47cdc05ac..64df5d10ec 100644 --- a/cmds/stagefright/sf2.cpp +++ b/cmds/stagefright/sf2.cpp @@ -176,8 +176,9 @@ protected: } onDrainThisBuffer(msg); - } else if (what == ACodec::kWhatEOS) { - printf("$\n"); + } else if (what == ACodec::kWhatEOS + || what == ACodec::kWhatError) { + printf((what == ACodec::kWhatEOS) ? "$\n" : "E\n"); int64_t delayUs = ALooper::GetNowUs() - mStartTimeUs; @@ -412,7 +413,8 @@ private: sp reply; CHECK(msg->findMessage("reply", &reply)); - if (mSeekState == SEEK_FLUSHING) { + if (mSource == NULL || mSeekState == SEEK_FLUSHING) { + reply->setInt32("err", ERROR_END_OF_STREAM); reply->post(); return; } diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index 148018d967..840e4757f0 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -541,6 +541,12 @@ void MediaPlayerService::Client::disconnect() } static player_type getDefaultPlayerType() { + char value[PROPERTY_VALUE_MAX]; + if (property_get("media.stagefright.use-nuplayer", value, NULL) + && (!strcmp("1", value) || !strcasecmp("true", value))) { + return NU_PLAYER; + } + return STAGEFRIGHT_PLAYER; } diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp index 7dbb57f47c..776d28832c 100644 --- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp +++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp @@ -87,6 +87,7 @@ static sp createRetriever(player_type playerType) sp p; switch (playerType) { case STAGEFRIGHT_PLAYER: + case NU_PLAYER: { p = new StagefrightMetadataRetriever; break; diff --git a/media/libmediaplayerservice/nuplayer/Android.mk b/media/libmediaplayerservice/nuplayer/Android.mk index 9b485d7c5b..73336efc4a 100644 --- a/media/libmediaplayerservice/nuplayer/Android.mk +++ b/media/libmediaplayerservice/nuplayer/Android.mk @@ -2,6 +2,7 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ + GenericSource.cpp \ HTTPLiveSource.cpp \ NuPlayer.cpp \ NuPlayerDecoder.cpp \ diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp new file mode 100644 index 0000000000..99569c9fd2 --- /dev/null +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -0,0 +1,265 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "GenericSource.h" + +#include "AnotherPacketSource.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace android { + +NuPlayer::GenericSource::GenericSource( + const char *url, + const KeyedVector *headers, + bool uidValid, + uid_t uid) + : mDurationUs(0ll), + mAudioIsVorbis(false) { + DataSource::RegisterDefaultSniffers(); + + sp dataSource = + DataSource::CreateFromURI(url, headers); + CHECK(dataSource != NULL); + + initFromDataSource(dataSource); +} + +NuPlayer::GenericSource::GenericSource( + int fd, int64_t offset, int64_t length) + : mDurationUs(0ll), + mAudioIsVorbis(false) { + DataSource::RegisterDefaultSniffers(); + + sp dataSource = new FileSource(dup(fd), offset, length); + + initFromDataSource(dataSource); +} + +void NuPlayer::GenericSource::initFromDataSource( + const sp &dataSource) { + sp extractor = MediaExtractor::Create(dataSource); + + CHECK(extractor != NULL); + + for (size_t i = 0; i < extractor->countTracks(); ++i) { + sp meta = extractor->getTrackMetaData(i); + + const char *mime; + CHECK(meta->findCString(kKeyMIMEType, &mime)); + + sp track; + + if (!strncasecmp(mime, "audio/", 6)) { + if (mAudioTrack.mSource == NULL) { + mAudioTrack.mSource = track = extractor->getTrack(i); + + if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) { + mAudioIsVorbis = true; + } else { + mAudioIsVorbis = false; + } + } + } else if (!strncasecmp(mime, "video/", 6)) { + if (mVideoTrack.mSource == NULL) { + mVideoTrack.mSource = track = extractor->getTrack(i); + } + } + + if (track != NULL) { + int64_t durationUs; + if (meta->findInt64(kKeyDuration, &durationUs)) { + if (durationUs > mDurationUs) { + mDurationUs = durationUs; + } + } + } + } +} + +NuPlayer::GenericSource::~GenericSource() { +} + +void NuPlayer::GenericSource::start() { + ALOGI("start"); + + if (mAudioTrack.mSource != NULL) { + CHECK_EQ(mAudioTrack.mSource->start(), (status_t)OK); + + mAudioTrack.mPackets = + new AnotherPacketSource(mAudioTrack.mSource->getFormat()); + + readBuffer(true /* audio */); + } + + if (mVideoTrack.mSource != NULL) { + CHECK_EQ(mVideoTrack.mSource->start(), (status_t)OK); + + mVideoTrack.mPackets = + new AnotherPacketSource(mVideoTrack.mSource->getFormat()); + + readBuffer(false /* audio */); + } +} + +status_t NuPlayer::GenericSource::feedMoreTSData() { + return OK; +} + +sp NuPlayer::GenericSource::getFormat(bool audio) { + sp source = audio ? mAudioTrack.mSource : mVideoTrack.mSource; + + if (source == NULL) { + return NULL; + } + + return source->getFormat(); +} + +status_t NuPlayer::GenericSource::dequeueAccessUnit( + bool audio, sp *accessUnit) { + Track *track = audio ? &mAudioTrack : &mVideoTrack; + + if (track->mSource == NULL) { + return -EWOULDBLOCK; + } + + status_t finalResult; + if (!track->mPackets->hasBufferAvailable(&finalResult)) { + return finalResult == OK ? -EWOULDBLOCK : finalResult; + } + + status_t result = track->mPackets->dequeueAccessUnit(accessUnit); + + readBuffer(audio, -1ll); + + return result; +} + +status_t NuPlayer::GenericSource::getDuration(int64_t *durationUs) { + *durationUs = mDurationUs; + return OK; +} + +status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs) { + if (mVideoTrack.mSource != NULL) { + int64_t actualTimeUs; + readBuffer(false /* audio */, seekTimeUs, &actualTimeUs); + + seekTimeUs = actualTimeUs; + } + + if (mAudioTrack.mSource != NULL) { + readBuffer(true /* audio */, seekTimeUs); + } + + return OK; +} + +void NuPlayer::GenericSource::readBuffer( + bool audio, int64_t seekTimeUs, int64_t *actualTimeUs) { + Track *track = audio ? &mAudioTrack : &mVideoTrack; + CHECK(track->mSource != NULL); + + if (actualTimeUs) { + *actualTimeUs = seekTimeUs; + } + + MediaSource::ReadOptions options; + + bool seeking = false; + + if (seekTimeUs >= 0) { + options.setSeekTo(seekTimeUs); + seeking = true; + } + + for (;;) { + MediaBuffer *mbuf; + status_t err = track->mSource->read(&mbuf, &options); + + options.clearSeekTo(); + + if (err == OK) { + size_t outLength = mbuf->range_length(); + + if (audio && mAudioIsVorbis) { + outLength += sizeof(int32_t); + } + + sp buffer = new ABuffer(outLength); + + memcpy(buffer->data(), + (const uint8_t *)mbuf->data() + mbuf->range_offset(), + mbuf->range_length()); + + if (audio && mAudioIsVorbis) { + int32_t numPageSamples; + if (!mbuf->meta_data()->findInt32( + kKeyValidSamples, &numPageSamples)) { + numPageSamples = -1; + } + + memcpy(buffer->data() + mbuf->range_length(), + &numPageSamples, + sizeof(numPageSamples)); + } + + int64_t timeUs; + CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs)); + + buffer->meta()->setInt64("timeUs", timeUs); + + if (actualTimeUs) { + *actualTimeUs = timeUs; + } + + mbuf->release(); + mbuf = NULL; + + if (seeking) { + track->mPackets->queueDiscontinuity( + ATSParser::DISCONTINUITY_SEEK, NULL); + } + + track->mPackets->queueAccessUnit(buffer); + break; + } else if (err == INFO_FORMAT_CHANGED) { +#if 0 + track->mPackets->queueDiscontinuity( + ATSParser::DISCONTINUITY_FORMATCHANGE, NULL); +#endif + } else { + track->mPackets->signalEOS(err); + break; + } + } +} + +bool NuPlayer::GenericSource::isSeekable() { + return true; +} + +} // namespace android diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h new file mode 100644 index 0000000000..aaa5876c35 --- /dev/null +++ b/media/libmediaplayerservice/nuplayer/GenericSource.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef GENERIC_SOURCE_H_ + +#define GENERIC_SOURCE_H_ + +#include "NuPlayer.h" +#include "NuPlayerSource.h" + +#include "ATSParser.h" + +namespace android { + +struct AnotherPacketSource; +struct ARTSPController; +struct DataSource; +struct MediaSource; + +struct NuPlayer::GenericSource : public NuPlayer::Source { + GenericSource( + const char *url, + const KeyedVector *headers, + bool uidValid = false, + uid_t uid = 0); + + GenericSource(int fd, int64_t offset, int64_t length); + + virtual void start(); + + virtual status_t feedMoreTSData(); + + virtual sp getFormat(bool audio); + virtual status_t dequeueAccessUnit(bool audio, sp *accessUnit); + + virtual status_t getDuration(int64_t *durationUs); + virtual status_t seekTo(int64_t seekTimeUs); + virtual bool isSeekable(); + +protected: + virtual ~GenericSource(); + +private: + struct Track { + sp mSource; + sp mPackets; + }; + + Track mAudioTrack; + Track mVideoTrack; + + int64_t mDurationUs; + bool mAudioIsVorbis; + + void initFromDataSource(const sp &dataSource); + + void readBuffer( + bool audio, + int64_t seekTimeUs = -1ll, int64_t *actualTimeUs = NULL); + + DISALLOW_EVIL_CONSTRUCTORS(GenericSource); +}; + +} // namespace android + +#endif // GENERIC_SOURCE_H_ diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 526120ab94..544d501fb3 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -27,6 +27,7 @@ #include "NuPlayerSource.h" #include "RTSPSource.h" #include "StreamingSource.h" +#include "GenericSource.h" #include "ATSParser.h" @@ -84,18 +85,44 @@ void NuPlayer::setDataSource(const sp &source) { msg->post(); } +static bool IsHTTPLiveURL(const char *url) { + if (!strncasecmp("http://", url, 7) + || !strncasecmp("https://", url, 8)) { + size_t len = strlen(url); + if (len >= 5 && !strcasecmp(".m3u8", &url[len - 5])) { + return true; + } + + if (strstr(url,"m3u8")) { + return true; + } + } + + return false; +} + void NuPlayer::setDataSource( const char *url, const KeyedVector *headers) { sp msg = new AMessage(kWhatSetDataSource, id()); - if (!strncasecmp(url, "rtsp://", 7)) { - msg->setObject( - "source", new RTSPSource(url, headers, mUIDValid, mUID)); + sp source; + if (IsHTTPLiveURL(url)) { + source = new HTTPLiveSource(url, headers, mUIDValid, mUID); + } else if (!strncasecmp(url, "rtsp://", 7)) { + source = new RTSPSource(url, headers, mUIDValid, mUID); } else { - msg->setObject( - "source", new HTTPLiveSource(url, headers, mUIDValid, mUID)); + source = new GenericSource(url, headers, mUIDValid, mUID); } + msg->setObject("source", source); + msg->post(); +} + +void NuPlayer::setDataSource(int fd, int64_t offset, int64_t length) { + sp msg = new AMessage(kWhatSetDataSource, id()); + + sp source = new GenericSource(fd, offset, length); + msg->setObject("source", source); msg->post(); } diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h index 6be14be6c8..25766e0038 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h @@ -40,6 +40,8 @@ struct NuPlayer : public AHandler { void setDataSource( const char *url, const KeyedVector *headers); + void setDataSource(int fd, int64_t offset, int64_t length); + void setVideoSurfaceTexture(const sp &surfaceTexture); void setAudioSink(const sp &sink); void start(); @@ -60,12 +62,13 @@ protected: private: struct Decoder; + struct GenericSource; struct HTTPLiveSource; struct NuPlayerStreamListener; struct Renderer; + struct RTSPSource; struct Source; struct StreamingSource; - struct RTSPSource; enum { kWhatSetDataSource = '=DaS', diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp index 460fc98393..160014178a 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp @@ -228,6 +228,20 @@ sp NuPlayer::Decoder::makeFormat(const sp &meta) { buffer->meta()->setInt32("csd", true); mCSD.push(buffer); + } else if (meta->findData(kKeyVorbisInfo, &type, &data, &size)) { + sp buffer = new ABuffer(size); + memcpy(buffer->data(), data, size); + + buffer->meta()->setInt32("csd", true); + mCSD.push(buffer); + + CHECK(meta->findData(kKeyVorbisBooks, &type, &data, &size)); + + buffer = new ABuffer(size); + memcpy(buffer->data(), data, size); + + buffer->meta()->setInt32("csd", true); + mCSD.push(buffer); } return msg; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp index 5aa99bfa1e..253bc2fad5 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp @@ -76,7 +76,13 @@ status_t NuPlayerDriver::setDataSource( } status_t NuPlayerDriver::setDataSource(int fd, int64_t offset, int64_t length) { - return INVALID_OPERATION; + CHECK_EQ((int)mState, (int)UNINITIALIZED); + + mPlayer->setDataSource(fd, offset, length); + + mState = STOPPED; + + return OK; } status_t NuPlayerDriver::setDataSource(const sp &source) { @@ -97,13 +103,16 @@ status_t NuPlayerDriver::setVideoSurfaceTexture( } status_t NuPlayerDriver::prepare() { + sendEvent(MEDIA_SET_VIDEO_SIZE, 320, 240); return OK; } status_t NuPlayerDriver::prepareAsync() { + status_t err = prepare(); + notifyListener(MEDIA_PREPARED); - return OK; + return err; } status_t NuPlayerDriver::start() { diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp index 5738ecb60b..ecbc4287dd 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp @@ -376,7 +376,8 @@ void NuPlayer::Renderer::onDrainVideoQueue() { bool tooLate = (mVideoLateByUs > 40000); if (tooLate) { - ALOGV("video late by %lld us (%.2f secs)", mVideoLateByUs, mVideoLateByUs / 1E6); + ALOGV("video late by %lld us (%.2f secs)", + mVideoLateByUs, mVideoLateByUs / 1E6); } else { ALOGV("rendering video at media time %.2f secs", mediaTimeUs / 1E6); } -- 2.11.0