summaryrefslogtreecommitdiffstats
path: root/media/libmediaplayerservice
diff options
context:
space:
mode:
Diffstat (limited to 'media/libmediaplayerservice')
-rw-r--r--media/libmediaplayerservice/Android.mk1
-rw-r--r--media/libmediaplayerservice/Crypto.cpp3
-rw-r--r--media/libmediaplayerservice/Drm.cpp17
-rw-r--r--media/libmediaplayerservice/Drm.h2
-rw-r--r--media/libmediaplayerservice/HDCP.cpp32
-rw-r--r--media/libmediaplayerservice/HDCP.h6
-rw-r--r--media/libmediaplayerservice/MediaPlayerService.cpp374
-rw-r--r--media/libmediaplayerservice/MediaPlayerService.h35
-rw-r--r--media/libmediaplayerservice/MidiFile.cpp8
-rw-r--r--media/libmediaplayerservice/RemoteDisplay.cpp13
-rw-r--r--media/libmediaplayerservice/RemoteDisplay.h5
-rw-r--r--media/libmediaplayerservice/SharedLibrary.cpp6
-rw-r--r--media/libmediaplayerservice/SharedLibrary.h1
-rw-r--r--media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp194
-rw-r--r--media/libmediaplayerservice/nuplayer/HTTPLiveSource.h12
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayer.cpp183
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayer.h13
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp27
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerDriver.h2
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp36
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h6
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerSource.h10
-rw-r--r--media/libmediaplayerservice/nuplayer/RTSPSource.cpp9
23 files changed, 720 insertions, 275 deletions
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index d87bc7f..8f21632 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -34,6 +34,7 @@ LOCAL_SHARED_LIBRARIES := \
libsonivox \
libstagefright \
libstagefright_foundation \
+ libstagefright_httplive \
libstagefright_omx \
libstagefright_wfd \
libutils \
diff --git a/media/libmediaplayerservice/Crypto.cpp b/media/libmediaplayerservice/Crypto.cpp
index ae4d845..62593b2 100644
--- a/media/libmediaplayerservice/Crypto.cpp
+++ b/media/libmediaplayerservice/Crypto.cpp
@@ -134,7 +134,6 @@ void Crypto::findFactoryForScheme(const uint8_t uuid[16]) {
return;
}
- ALOGE("Failed to find crypto plugin");
mInitCheck = ERROR_UNSUPPORTED;
}
@@ -151,6 +150,7 @@ bool Crypto::loadLibraryForScheme(const String8 &path, const uint8_t uuid[16]) {
if (!mLibrary.get()) {
mLibrary = new SharedLibrary(path);
if (!*mLibrary) {
+ ALOGE("loadLibraryForScheme failed:%s", mLibrary->lastError());
return false;
}
@@ -165,6 +165,7 @@ bool Crypto::loadLibraryForScheme(const String8 &path, const uint8_t uuid[16]) {
if (createCryptoFactory == NULL ||
(mFactory = createCryptoFactory()) == NULL ||
!mFactory->isCryptoSchemeSupported(uuid)) {
+ ALOGE("createCryptoFactory failed:%s", mLibrary->lastError());
closeFactory();
return false;
}
diff --git a/media/libmediaplayerservice/Drm.cpp b/media/libmediaplayerservice/Drm.cpp
index f00f488..eebcb79 100644
--- a/media/libmediaplayerservice/Drm.cpp
+++ b/media/libmediaplayerservice/Drm.cpp
@@ -211,15 +211,22 @@ bool Drm::loadLibraryForScheme(const String8 &path, const uint8_t uuid[16]) {
return true;
}
-bool Drm::isCryptoSchemeSupported(const uint8_t uuid[16]) {
+bool Drm::isCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType) {
+
Mutex::Autolock autoLock(mLock);
- if (mFactory && mFactory->isCryptoSchemeSupported(uuid)) {
- return true;
+ if (!mFactory || !mFactory->isCryptoSchemeSupported(uuid)) {
+ findFactoryForScheme(uuid);
+ if (mInitCheck != OK) {
+ return false;
+ }
+ }
+
+ if (mimeType != "") {
+ return mFactory->isContentTypeSupported(mimeType);
}
- findFactoryForScheme(uuid);
- return (mInitCheck == OK);
+ return true;
}
status_t Drm::createPlugin(const uint8_t uuid[16]) {
diff --git a/media/libmediaplayerservice/Drm.h b/media/libmediaplayerservice/Drm.h
index 3f460f1..119fd50 100644
--- a/media/libmediaplayerservice/Drm.h
+++ b/media/libmediaplayerservice/Drm.h
@@ -37,7 +37,7 @@ struct Drm : public BnDrm,
virtual status_t initCheck() const;
- virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]);
+ virtual bool isCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType);
virtual status_t createPlugin(const uint8_t uuid[16]);
diff --git a/media/libmediaplayerservice/HDCP.cpp b/media/libmediaplayerservice/HDCP.cpp
index 469a02e..c2ac1a3 100644
--- a/media/libmediaplayerservice/HDCP.cpp
+++ b/media/libmediaplayerservice/HDCP.cpp
@@ -100,6 +100,20 @@ status_t HDCP::shutdownAsync() {
return mHDCPModule->shutdownAsync();
}
+uint32_t HDCP::getCaps() {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mHDCPModule == NULL) {
+ return NO_INIT;
+ }
+
+ // TO-DO:
+ // Only support HDCP_CAPS_ENCRYPT (byte-array to byte-array) for now.
+ // use mHDCPModule->getCaps() when the HDCP libraries get updated.
+ //return mHDCPModule->getCaps();
+ return HDCPModule::HDCP_CAPS_ENCRYPT;
+}
+
status_t HDCP::encrypt(
const void *inData, size_t size, uint32_t streamCTR,
uint64_t *outInputCTR, void *outData) {
@@ -116,6 +130,24 @@ status_t HDCP::encrypt(
return mHDCPModule->encrypt(inData, size, streamCTR, outInputCTR, outData);
}
+status_t HDCP::encryptNative(
+ const sp<GraphicBuffer> &graphicBuffer,
+ size_t offset, size_t size, uint32_t streamCTR,
+ uint64_t *outInputCTR, void *outData) {
+ Mutex::Autolock autoLock(mLock);
+
+ CHECK(mIsEncryptionModule);
+
+ if (mHDCPModule == NULL) {
+ *outInputCTR = 0;
+
+ return NO_INIT;
+ }
+
+ return mHDCPModule->encryptNative(graphicBuffer->handle,
+ offset, size, streamCTR, outInputCTR, outData);
+}
+
status_t HDCP::decrypt(
const void *inData, size_t size,
uint32_t streamCTR, uint64_t outInputCTR, void *outData) {
diff --git a/media/libmediaplayerservice/HDCP.h b/media/libmediaplayerservice/HDCP.h
index 42e6467..26ddc86 100644
--- a/media/libmediaplayerservice/HDCP.h
+++ b/media/libmediaplayerservice/HDCP.h
@@ -30,11 +30,17 @@ struct HDCP : public BnHDCP {
virtual status_t setObserver(const sp<IHDCPObserver> &observer);
virtual status_t initAsync(const char *host, unsigned port);
virtual status_t shutdownAsync();
+ virtual uint32_t getCaps();
virtual status_t encrypt(
const void *inData, size_t size, uint32_t streamCTR,
uint64_t *outInputCTR, void *outData);
+ virtual status_t encryptNative(
+ const sp<GraphicBuffer> &graphicBuffer,
+ size_t offset, size_t size, uint32_t streamCTR,
+ uint64_t *outInputCTR, void *outData);
+
virtual status_t decrypt(
const void *inData, size_t size,
uint32_t streamCTR, uint64_t outInputCTR, void *outData);
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 57ec7ea..9553458 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -53,6 +53,8 @@
#include <media/AudioTrack.h>
#include <media/MemoryLeakTrackUtil.h>
#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/AudioPlayer.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <system/audio.h>
@@ -317,8 +319,8 @@ status_t MediaPlayerService::AudioCache::dump(int fd, const Vector<String16>& ar
result.append(" AudioCache\n");
if (mHeap != 0) {
- snprintf(buffer, 255, " heap base(%p), size(%d), flags(%d), device(%s)\n",
- mHeap->getBase(), mHeap->getSize(), mHeap->getFlags(), mHeap->getDevice());
+ snprintf(buffer, 255, " heap base(%p), size(%d), flags(%d)\n",
+ mHeap->getBase(), mHeap->getSize(), mHeap->getFlags());
result.append(buffer);
}
snprintf(buffer, 255, " msec per frame(%f), channel count(%d), format(%d), frame count(%zd)\n",
@@ -742,7 +744,7 @@ status_t MediaPlayerService::Client::setVideoSurfaceTexture(
sp<ANativeWindow> anw;
if (bufferProducer != NULL) {
- anw = new Surface(bufferProducer);
+ anw = new Surface(bufferProducer, true /* controlledByApp */);
status_t err = native_window_api_connect(anw.get(),
NATIVE_WINDOW_API_MEDIA);
@@ -1174,13 +1176,13 @@ int Antagonizer::callbackThread(void* user)
}
#endif
-static size_t kDefaultHeapSize = 1024 * 1024; // 1MB
-
-sp<IMemory> MediaPlayerService::decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, audio_format_t* pFormat)
+status_t MediaPlayerService::decode(const char* url, uint32_t *pSampleRate, int* pNumChannels,
+ audio_format_t* pFormat,
+ const sp<IMemoryHeap>& heap, size_t *pSize)
{
ALOGV("decode(%s)", url);
- sp<MemoryBase> mem;
sp<MediaPlayerBase> player;
+ status_t status = BAD_VALUE;
// Protect our precious, precious DRMd ringtones by only allowing
// decoding of http, but not filesystem paths or content Uris.
@@ -1188,7 +1190,7 @@ sp<IMemory> MediaPlayerService::decode(const char* url, uint32_t *pSampleRate, i
// filedescriptor for them and use that.
if (url != NULL && strncmp(url, "http://", 7) != 0) {
ALOGD("Can't decode %s by path, use filedescriptor instead", url);
- return mem;
+ return BAD_VALUE;
}
player_type playerType =
@@ -1196,7 +1198,7 @@ sp<IMemory> MediaPlayerService::decode(const char* url, uint32_t *pSampleRate, i
ALOGV("player type = %d", playerType);
// create the right type of player
- sp<AudioCache> cache = new AudioCache(url);
+ sp<AudioCache> cache = new AudioCache(heap);
player = MediaPlayerFactory::createPlayer(playerType, cache.get(), cache->notify);
if (player == NULL) goto Exit;
if (player->hardwareOutput()) goto Exit;
@@ -1222,22 +1224,27 @@ sp<IMemory> MediaPlayerService::decode(const char* url, uint32_t *pSampleRate, i
goto Exit;
}
- mem = new MemoryBase(cache->getHeap(), 0, cache->size());
+ *pSize = cache->size();
*pSampleRate = cache->sampleRate();
*pNumChannels = cache->channelCount();
*pFormat = cache->format();
- ALOGV("return memory @ %p, sampleRate=%u, channelCount = %d, format = %d", mem->pointer(), *pSampleRate, *pNumChannels, *pFormat);
+ ALOGV("return size %d sampleRate=%u, channelCount = %d, format = %d",
+ *pSize, *pSampleRate, *pNumChannels, *pFormat);
+ status = NO_ERROR;
Exit:
if (player != 0) player->reset();
- return mem;
+ return status;
}
-sp<IMemory> MediaPlayerService::decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, audio_format_t* pFormat)
+status_t MediaPlayerService::decode(int fd, int64_t offset, int64_t length,
+ uint32_t *pSampleRate, int* pNumChannels,
+ audio_format_t* pFormat,
+ const sp<IMemoryHeap>& heap, size_t *pSize)
{
ALOGV("decode(%d, %lld, %lld)", fd, offset, length);
- sp<MemoryBase> mem;
sp<MediaPlayerBase> player;
+ status_t status = BAD_VALUE;
player_type playerType = MediaPlayerFactory::getPlayerType(NULL /* client */,
fd,
@@ -1246,7 +1253,7 @@ sp<IMemory> MediaPlayerService::decode(int fd, int64_t offset, int64_t length, u
ALOGV("player type = %d", playerType);
// create the right type of player
- sp<AudioCache> cache = new AudioCache("decode_fd");
+ sp<AudioCache> cache = new AudioCache(heap);
player = MediaPlayerFactory::createPlayer(playerType, cache.get(), cache->notify);
if (player == NULL) goto Exit;
if (player->hardwareOutput()) goto Exit;
@@ -1272,16 +1279,18 @@ sp<IMemory> MediaPlayerService::decode(int fd, int64_t offset, int64_t length, u
goto Exit;
}
- mem = new MemoryBase(cache->getHeap(), 0, cache->size());
+ *pSize = cache->size();
*pSampleRate = cache->sampleRate();
*pNumChannels = cache->channelCount();
*pFormat = cache->format();
- ALOGV("return memory @ %p, sampleRate=%u, channelCount = %d, format = %d", mem->pointer(), *pSampleRate, *pNumChannels, *pFormat);
+ ALOGV("return size %d, sampleRate=%u, channelCount = %d, format = %d",
+ *pSize, *pSampleRate, *pNumChannels, *pFormat);
+ status = NO_ERROR;
Exit:
if (player != 0) player->reset();
::close(fd);
- return mem;
+ return status;
}
@@ -1295,8 +1304,6 @@ MediaPlayerService::AudioOutput::AudioOutput(int sessionId)
mSessionId(sessionId),
mFlags(AUDIO_OUTPUT_FLAG_NONE) {
ALOGV("AudioOutput(%d)", sessionId);
- mTrack = 0;
- mRecycledTrack = 0;
mStreamType = AUDIO_STREAM_MUSIC;
mLeftVolume = 1.0;
mRightVolume = 1.0;
@@ -1311,7 +1318,6 @@ MediaPlayerService::AudioOutput::AudioOutput(int sessionId)
MediaPlayerService::AudioOutput::~AudioOutput()
{
close();
- delete mRecycledTrack;
delete mCallbackData;
}
@@ -1384,11 +1390,51 @@ status_t MediaPlayerService::AudioOutput::getFramesWritten(uint32_t *frameswritt
return OK;
}
+status_t MediaPlayerService::AudioOutput::setParameters(const String8& keyValuePairs)
+{
+ if (mTrack == 0) return NO_INIT;
+ return mTrack->setParameters(keyValuePairs);
+}
+
+String8 MediaPlayerService::AudioOutput::getParameters(const String8& keys)
+{
+ if (mTrack == 0) return String8::empty();
+ return mTrack->getParameters(keys);
+}
+
+void MediaPlayerService::AudioOutput::deleteRecycledTrack()
+{
+ ALOGV("deleteRecycledTrack");
+
+ if (mRecycledTrack != 0) {
+
+ if (mCallbackData != NULL) {
+ mCallbackData->setOutput(NULL);
+ mCallbackData->endTrackSwitch();
+ }
+
+ if ((mRecycledTrack->getFlags() & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0) {
+ mRecycledTrack->flush();
+ }
+ // An offloaded track isn't flushed because the STREAM_END is reported
+ // slightly prematurely to allow time for the gapless track switch
+ // but this means that if we decide not to recycle the track there
+ // could be a small amount of residual data still playing. We leave
+ // AudioFlinger to drain the track.
+
+ mRecycledTrack.clear();
+ delete mCallbackData;
+ mCallbackData = NULL;
+ close();
+ }
+}
+
status_t MediaPlayerService::AudioOutput::open(
uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
audio_format_t format, int bufferCount,
AudioCallback cb, void *cookie,
- audio_output_flags_t flags)
+ audio_output_flags_t flags,
+ const audio_offload_info_t *offloadInfo)
{
mCallback = cb;
mCallbackCookie = cookie;
@@ -1399,20 +1445,34 @@ status_t MediaPlayerService::AudioOutput::open(
bufferCount = mMinBufferCount;
}
- ALOGV("open(%u, %d, 0x%x, %d, %d, %d)", sampleRate, channelCount, channelMask,
- format, bufferCount, mSessionId);
+ ALOGV("open(%u, %d, 0x%x, 0x%x, %d, %d 0x%x)", sampleRate, channelCount, channelMask,
+ format, bufferCount, mSessionId, flags);
uint32_t afSampleRate;
size_t afFrameCount;
uint32_t frameCount;
- if (AudioSystem::getOutputFrameCount(&afFrameCount, mStreamType) != NO_ERROR) {
- return NO_INIT;
- }
- if (AudioSystem::getOutputSamplingRate(&afSampleRate, mStreamType) != NO_ERROR) {
- return NO_INIT;
+ // offloading is only supported in callback mode for now.
+ // offloadInfo must be present if offload flag is set
+ if (((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) &&
+ ((cb == NULL) || (offloadInfo == NULL))) {
+ return BAD_VALUE;
}
- frameCount = (sampleRate*afFrameCount*bufferCount)/afSampleRate;
+ if ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
+ frameCount = 0; // AudioTrack will get frame count from AudioFlinger
+ } else {
+ uint32_t afSampleRate;
+ size_t afFrameCount;
+
+ if (AudioSystem::getOutputFrameCount(&afFrameCount, mStreamType) != NO_ERROR) {
+ return NO_INIT;
+ }
+ if (AudioSystem::getOutputSamplingRate(&afSampleRate, mStreamType) != NO_ERROR) {
+ return NO_INIT;
+ }
+
+ frameCount = (sampleRate*afFrameCount*bufferCount)/afSampleRate;
+ }
if (channelMask == CHANNEL_MASK_USE_CHANNEL_ORDER) {
channelMask = audio_channel_out_mask_from_count(channelCount);
@@ -1422,90 +1482,127 @@ status_t MediaPlayerService::AudioOutput::open(
}
}
- AudioTrack *t;
- CallbackData *newcbd = NULL;
- if (mCallback != NULL) {
- newcbd = new CallbackData(this);
- t = new AudioTrack(
- mStreamType,
- sampleRate,
- format,
- channelMask,
- frameCount,
- flags,
- CallbackWrapper,
- newcbd,
- 0, // notification frames
- mSessionId);
- } else {
- t = new AudioTrack(
- mStreamType,
- sampleRate,
- format,
- channelMask,
- frameCount,
- flags,
- NULL,
- NULL,
- 0,
- mSessionId);
- }
-
- if ((t == 0) || (t->initCheck() != NO_ERROR)) {
- ALOGE("Unable to create audio track");
- delete t;
- delete newcbd;
- return NO_INIT;
- }
+ // Check whether we can recycle the track
+ bool reuse = false;
+ bool bothOffloaded = false;
+ if (mRecycledTrack != 0) {
+ // check whether we are switching between two offloaded tracks
+ bothOffloaded = (flags & mRecycledTrack->getFlags()
+ & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0;
- if (mRecycledTrack) {
// check if the existing track can be reused as-is, or if a new track needs to be created.
+ reuse = true;
- bool reuse = true;
if ((mCallbackData == NULL && mCallback != NULL) ||
(mCallbackData != NULL && mCallback == NULL)) {
// recycled track uses callbacks but the caller wants to use writes, or vice versa
ALOGV("can't chain callback and write");
reuse = false;
} else if ((mRecycledTrack->getSampleRate() != sampleRate) ||
- (mRecycledTrack->channelCount() != channelCount) ||
- (mRecycledTrack->frameCount() != t->frameCount())) {
- ALOGV("samplerate, channelcount or framecount differ: %d/%d Hz, %d/%d ch, %d/%d frames",
+ (mRecycledTrack->channelCount() != (uint32_t)channelCount) ) {
+ ALOGV("samplerate, channelcount differ: %u/%u Hz, %u/%d ch",
mRecycledTrack->getSampleRate(), sampleRate,
- mRecycledTrack->channelCount(), channelCount,
- mRecycledTrack->frameCount(), t->frameCount());
+ mRecycledTrack->channelCount(), channelCount);
reuse = false;
} else if (flags != mFlags) {
ALOGV("output flags differ %08x/%08x", flags, mFlags);
reuse = false;
+ } else if (mRecycledTrack->format() != format) {
+ reuse = false;
}
+ } else {
+ ALOGV("no track available to recycle");
+ }
+
+ ALOGV_IF(bothOffloaded, "both tracks offloaded");
+
+ // If we can't recycle and both tracks are offloaded
+ // we must close the previous output before opening a new one
+ if (bothOffloaded && !reuse) {
+ ALOGV("both offloaded and not recycling");
+ deleteRecycledTrack();
+ }
+
+ sp<AudioTrack> t;
+ CallbackData *newcbd = NULL;
+
+ // We don't attempt to create a new track if we are recycling an
+ // offloaded track. But, if we are recycling a non-offloaded or we
+ // are switching where one is offloaded and one isn't then we create
+ // the new track in advance so that we can read additional stream info
+
+ if (!(reuse && bothOffloaded)) {
+ ALOGV("creating new AudioTrack");
+
+ if (mCallback != NULL) {
+ newcbd = new CallbackData(this);
+ t = new AudioTrack(
+ mStreamType,
+ sampleRate,
+ format,
+ channelMask,
+ frameCount,
+ flags,
+ CallbackWrapper,
+ newcbd,
+ 0, // notification frames
+ mSessionId,
+ AudioTrack::TRANSFER_CALLBACK,
+ offloadInfo);
+ } else {
+ t = new AudioTrack(
+ mStreamType,
+ sampleRate,
+ format,
+ channelMask,
+ frameCount,
+ flags,
+ NULL,
+ NULL,
+ 0,
+ mSessionId);
+ }
+
+ if ((t == 0) || (t->initCheck() != NO_ERROR)) {
+ ALOGE("Unable to create audio track");
+ delete newcbd;
+ return NO_INIT;
+ }
+ }
+
+ if (reuse) {
+ CHECK(mRecycledTrack != NULL);
+
+ if (!bothOffloaded) {
+ if (mRecycledTrack->frameCount() != t->frameCount()) {
+ ALOGV("framecount differs: %u/%u frames",
+ mRecycledTrack->frameCount(), t->frameCount());
+ reuse = false;
+ }
+ }
+
if (reuse) {
- ALOGV("chaining to next output");
+ ALOGV("chaining to next output and recycling track");
close();
mTrack = mRecycledTrack;
- mRecycledTrack = NULL;
+ mRecycledTrack.clear();
if (mCallbackData != NULL) {
mCallbackData->setOutput(this);
}
- delete t;
delete newcbd;
return OK;
}
+ }
- // if we're not going to reuse the track, unblock and flush it
- if (mCallbackData != NULL) {
- mCallbackData->setOutput(NULL);
- mCallbackData->endTrackSwitch();
- }
- mRecycledTrack->flush();
- delete mRecycledTrack;
- mRecycledTrack = NULL;
- delete mCallbackData;
- mCallbackData = NULL;
- close();
+ // we're not going to reuse the track, unblock and flush it
+ // this was done earlier if both tracks are offloaded
+ if (!bothOffloaded) {
+ deleteRecycledTrack();
}
+ CHECK((t != NULL) && ((mCallback == NULL) || (newcbd != NULL)));
+
mCallbackData = newcbd;
ALOGV("setVolume");
t->setVolume(mLeftVolume, mRightVolume);
@@ -1519,25 +1616,30 @@ status_t MediaPlayerService::AudioOutput::open(
}
mTrack = t;
- status_t res = t->setSampleRate(mPlaybackRatePermille * mSampleRateHz / 1000);
- if (res != NO_ERROR) {
- return res;
+ status_t res = NO_ERROR;
+ if ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0) {
+ res = t->setSampleRate(mPlaybackRatePermille * mSampleRateHz / 1000);
+ if (res == NO_ERROR) {
+ t->setAuxEffectSendLevel(mSendLevel);
+ res = t->attachAuxEffect(mAuxEffectId);
+ }
}
- t->setAuxEffectSendLevel(mSendLevel);
- return t->attachAuxEffect(mAuxEffectId);;
+ ALOGV("open() DONE status %d", res);
+ return res;
}
-void MediaPlayerService::AudioOutput::start()
+status_t MediaPlayerService::AudioOutput::start()
{
ALOGV("start");
if (mCallbackData != NULL) {
mCallbackData->endTrackSwitch();
}
- if (mTrack) {
+ if (mTrack != 0) {
mTrack->setVolume(mLeftVolume, mRightVolume);
mTrack->setAuxEffectSendLevel(mSendLevel);
- mTrack->start();
+ return mTrack->start();
}
+ return NO_INIT;
}
void MediaPlayerService::AudioOutput::setNextOutput(const sp<AudioOutput>& nextOutput) {
@@ -1555,7 +1657,7 @@ void MediaPlayerService::AudioOutput::switchToNextOutput() {
mNextOutput->mCallbackData = mCallbackData;
mCallbackData = NULL;
mNextOutput->mRecycledTrack = mTrack;
- mTrack = NULL;
+ mTrack.clear();
mNextOutput->mSampleRateHz = mSampleRateHz;
mNextOutput->mMsecsPerFrame = mMsecsPerFrame;
mNextOutput->mBytesWritten = mBytesWritten;
@@ -1568,7 +1670,7 @@ ssize_t MediaPlayerService::AudioOutput::write(const void* buffer, size_t size)
LOG_FATAL_IF(mCallback != NULL, "Don't call write if supplying a callback.");
//ALOGV("write(%p, %u)", buffer, size);
- if (mTrack) {
+ if (mTrack != 0) {
ssize_t ret = mTrack->write(buffer, size);
mBytesWritten += ret;
return ret;
@@ -1579,26 +1681,25 @@ ssize_t MediaPlayerService::AudioOutput::write(const void* buffer, size_t size)
void MediaPlayerService::AudioOutput::stop()
{
ALOGV("stop");
- if (mTrack) mTrack->stop();
+ if (mTrack != 0) mTrack->stop();
}
void MediaPlayerService::AudioOutput::flush()
{
ALOGV("flush");
- if (mTrack) mTrack->flush();
+ if (mTrack != 0) mTrack->flush();
}
void MediaPlayerService::AudioOutput::pause()
{
ALOGV("pause");
- if (mTrack) mTrack->pause();
+ if (mTrack != 0) mTrack->pause();
}
void MediaPlayerService::AudioOutput::close()
{
ALOGV("close");
- delete mTrack;
- mTrack = 0;
+ mTrack.clear();
}
void MediaPlayerService::AudioOutput::setVolume(float left, float right)
@@ -1606,7 +1707,7 @@ void MediaPlayerService::AudioOutput::setVolume(float left, float right)
ALOGV("setVolume(%f, %f)", left, right);
mLeftVolume = left;
mRightVolume = right;
- if (mTrack) {
+ if (mTrack != 0) {
mTrack->setVolume(left, right);
}
}
@@ -1615,7 +1716,7 @@ status_t MediaPlayerService::AudioOutput::setPlaybackRatePermille(int32_t ratePe
{
ALOGV("setPlaybackRatePermille(%d)", ratePermille);
status_t res = NO_ERROR;
- if (mTrack) {
+ if (mTrack != 0) {
res = mTrack->setSampleRate(ratePermille * mSampleRateHz / 1000);
} else {
res = NO_INIT;
@@ -1631,7 +1732,7 @@ status_t MediaPlayerService::AudioOutput::setAuxEffectSendLevel(float level)
{
ALOGV("setAuxEffectSendLevel(%f)", level);
mSendLevel = level;
- if (mTrack) {
+ if (mTrack != 0) {
return mTrack->setAuxEffectSendLevel(level);
}
return NO_ERROR;
@@ -1641,7 +1742,7 @@ status_t MediaPlayerService::AudioOutput::attachAuxEffect(int effectId)
{
ALOGV("attachAuxEffect(%d)", effectId);
mAuxEffectId = effectId;
- if (mTrack) {
+ if (mTrack != 0) {
return mTrack->attachAuxEffect(effectId);
}
return NO_ERROR;
@@ -1651,10 +1752,6 @@ status_t MediaPlayerService::AudioOutput::attachAuxEffect(int effectId)
void MediaPlayerService::AudioOutput::CallbackWrapper(
int event, void *cookie, void *info) {
//ALOGV("callbackwrapper");
- if (event != AudioTrack::EVENT_MORE_DATA) {
- return;
- }
-
CallbackData *data = (CallbackData*)cookie;
data->lock();
AudioOutput *me = data->getOutput();
@@ -1663,22 +1760,46 @@ void MediaPlayerService::AudioOutput::CallbackWrapper(
// no output set, likely because the track was scheduled to be reused
// by another player, but the format turned out to be incompatible.
data->unlock();
- buffer->size = 0;
+ if (buffer != NULL) {
+ buffer->size = 0;
+ }
return;
}
- size_t actualSize = (*me->mCallback)(
- me, buffer->raw, buffer->size, me->mCallbackCookie);
+ switch(event) {
+ case AudioTrack::EVENT_MORE_DATA: {
+ size_t actualSize = (*me->mCallback)(
+ me, buffer->raw, buffer->size, me->mCallbackCookie,
+ CB_EVENT_FILL_BUFFER);
+
+ if (actualSize == 0 && buffer->size > 0 && me->mNextOutput == NULL) {
+ // We've reached EOS but the audio track is not stopped yet,
+ // keep playing silence.
+
+ memset(buffer->raw, 0, buffer->size);
+ actualSize = buffer->size;
+ }
+
+ buffer->size = actualSize;
+ } break;
- if (actualSize == 0 && buffer->size > 0 && me->mNextOutput == NULL) {
- // We've reached EOS but the audio track is not stopped yet,
- // keep playing silence.
- memset(buffer->raw, 0, buffer->size);
- actualSize = buffer->size;
+ case AudioTrack::EVENT_STREAM_END:
+ ALOGV("callbackwrapper: deliver EVENT_STREAM_END");
+ (*me->mCallback)(me, NULL /* buffer */, 0 /* size */,
+ me->mCallbackCookie, CB_EVENT_STREAM_END);
+ break;
+
+ case AudioTrack::EVENT_NEW_IAUDIOTRACK :
+ ALOGV("callbackwrapper: deliver EVENT_TEAR_DOWN");
+ (*me->mCallback)(me, NULL /* buffer */, 0 /* size */,
+ me->mCallbackCookie, CB_EVENT_TEAR_DOWN);
+ break;
+
+ default:
+ ALOGE("received unknown event type: %d inside CallbackWrapper !", event);
}
- buffer->size = actualSize;
data->unlock();
}
@@ -1689,12 +1810,10 @@ int MediaPlayerService::AudioOutput::getSessionId() const
#undef LOG_TAG
#define LOG_TAG "AudioCache"
-MediaPlayerService::AudioCache::AudioCache(const char* name) :
- mChannelCount(0), mFrameCount(1024), mSampleRate(0), mSize(0),
- mError(NO_ERROR), mCommandComplete(false)
+MediaPlayerService::AudioCache::AudioCache(const sp<IMemoryHeap>& heap) :
+ mHeap(heap), mChannelCount(0), mFrameCount(1024), mSampleRate(0), mSize(0),
+ mError(NO_ERROR), mCommandComplete(false)
{
- // create ashmem heap
- mHeap = new MemoryHeapBase(kDefaultHeapSize, 0, name);
}
uint32_t MediaPlayerService::AudioCache::latency () const
@@ -1774,7 +1893,8 @@ bool CallbackThread::threadLoop() {
}
size_t actualSize =
- (*mCallback)(sink.get(), mBuffer, mBufferSize, mCookie);
+ (*mCallback)(sink.get(), mBuffer, mBufferSize, mCookie,
+ MediaPlayerBase::AudioSink::CB_EVENT_FILL_BUFFER);
if (actualSize > 0) {
sink->write(mBuffer, actualSize);
@@ -1788,7 +1908,8 @@ bool CallbackThread::threadLoop() {
status_t MediaPlayerService::AudioCache::open(
uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
audio_format_t format, int bufferCount,
- AudioCallback cb, void *cookie, audio_output_flags_t flags)
+ AudioCallback cb, void *cookie, audio_output_flags_t flags,
+ const audio_offload_info_t *offloadInfo)
{
ALOGV("open(%u, %d, 0x%x, %d, %d)", sampleRate, channelCount, channelMask, format, bufferCount);
if (mHeap->getHeapID() < 0) {
@@ -1806,10 +1927,11 @@ status_t MediaPlayerService::AudioCache::open(
return NO_ERROR;
}
-void MediaPlayerService::AudioCache::start() {
+status_t MediaPlayerService::AudioCache::start() {
if (mCallbackThread != NULL) {
mCallbackThread->run("AudioCache callback");
}
+ return NO_ERROR;
}
void MediaPlayerService::AudioCache::stop() {
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index b33805d..21f4117 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -20,15 +20,12 @@
#include <arpa/inet.h>
-#include <utils/Log.h>
#include <utils/threads.h>
-#include <utils/List.h>
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
#include <utils/String8.h>
#include <utils/Vector.h>
-#include <media/IMediaPlayerService.h>
#include <media/MediaPlayerInterface.h>
#include <media/Metadata.h>
#include <media/stagefright/foundation/ABase.h>
@@ -78,7 +75,7 @@ class MediaPlayerService : public BnMediaPlayerService
AudioOutput(int sessionId);
virtual ~AudioOutput();
- virtual bool ready() const { return mTrack != NULL; }
+ virtual bool ready() const { return mTrack != 0; }
virtual bool realtime() const { return true; }
virtual ssize_t bufferSize() const;
virtual ssize_t frameCount() const;
@@ -94,9 +91,10 @@ class MediaPlayerService : public BnMediaPlayerService
uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
audio_format_t format, int bufferCount,
AudioCallback cb, void *cookie,
- audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE);
+ audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
+ const audio_offload_info_t *offloadInfo = NULL);
- virtual void start();
+ virtual status_t start();
virtual ssize_t write(const void* buffer, size_t size);
virtual void stop();
virtual void flush();
@@ -114,14 +112,17 @@ class MediaPlayerService : public BnMediaPlayerService
void setNextOutput(const sp<AudioOutput>& nextOutput);
void switchToNextOutput();
virtual bool needsTrailingPadding() { return mNextOutput == NULL; }
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
private:
static void setMinBufferCount();
static void CallbackWrapper(
int event, void *me, void *info);
+ void deleteRecycledTrack();
- AudioTrack* mTrack;
- AudioTrack* mRecycledTrack;
+ sp<AudioTrack> mTrack;
+ sp<AudioTrack> mRecycledTrack;
sp<AudioOutput> mNextOutput;
AudioCallback mCallback;
void * mCallbackCookie;
@@ -176,7 +177,7 @@ class MediaPlayerService : public BnMediaPlayerService
class AudioCache : public MediaPlayerBase::AudioSink
{
public:
- AudioCache(const char* name);
+ AudioCache(const sp<IMemoryHeap>& heap);
virtual ~AudioCache() {}
virtual bool ready() const { return (mChannelCount > 0) && (mHeap->getHeapID() > 0); }
@@ -195,9 +196,10 @@ class MediaPlayerService : public BnMediaPlayerService
uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
audio_format_t format, int bufferCount = 1,
AudioCallback cb = NULL, void *cookie = NULL,
- audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE);
+ audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
+ const audio_offload_info_t *offloadInfo = NULL);
- virtual void start();
+ virtual status_t start();
virtual ssize_t write(const void* buffer, size_t size);
virtual void stop();
virtual void flush() {}
@@ -222,7 +224,7 @@ class MediaPlayerService : public BnMediaPlayerService
Mutex mLock;
Condition mSignal;
- sp<MemoryHeapBase> mHeap;
+ sp<IMemoryHeap> mHeap;
float mMsecsPerFrame;
uint16_t mChannelCount;
audio_format_t mFormat;
@@ -245,8 +247,13 @@ public:
virtual sp<IMediaPlayer> create(const sp<IMediaPlayerClient>& client, int audioSessionId);
- virtual sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, audio_format_t* pFormat);
- virtual sp<IMemory> decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, audio_format_t* pFormat);
+ virtual status_t decode(const char* url, uint32_t *pSampleRate, int* pNumChannels,
+ audio_format_t* pFormat,
+ const sp<IMemoryHeap>& heap, size_t *pSize);
+ virtual status_t decode(int fd, int64_t offset, int64_t length,
+ uint32_t *pSampleRate, int* pNumChannels,
+ audio_format_t* pFormat,
+ const sp<IMemoryHeap>& heap, size_t *pSize);
virtual sp<IOMX> getOMX();
virtual sp<ICrypto> makeCrypto();
virtual sp<IDrm> makeDrm();
diff --git a/media/libmediaplayerservice/MidiFile.cpp b/media/libmediaplayerservice/MidiFile.cpp
index 8db5b9b..0a6aa90 100644
--- a/media/libmediaplayerservice/MidiFile.cpp
+++ b/media/libmediaplayerservice/MidiFile.cpp
@@ -220,6 +220,9 @@ status_t MidiFile::start()
}
mRender = true;
+ if (mState == EAS_STATE_PLAY) {
+ sendEvent(MEDIA_STARTED);
+ }
// wake up render thread
ALOGV(" wakeup render thread");
@@ -242,6 +245,7 @@ status_t MidiFile::stop()
}
}
mPaused = false;
+ sendEvent(MEDIA_STOPPED);
return NO_ERROR;
}
@@ -279,6 +283,7 @@ status_t MidiFile::pause()
return ERROR_EAS_FAILURE;
}
mPaused = true;
+ sendEvent(MEDIA_PAUSED);
return NO_ERROR;
}
@@ -382,6 +387,7 @@ status_t MidiFile::reset()
status_t MidiFile::reset_nosync()
{
ALOGV("MidiFile::reset_nosync");
+ sendEvent(MEDIA_STOPPED);
// close file
if (mEasHandle) {
EAS_CloseFile(mEasData, mEasHandle);
@@ -422,7 +428,7 @@ status_t MidiFile::setLooping(int loop)
status_t MidiFile::createOutputTrack() {
if (mAudioSink->open(pLibConfig->sampleRate, pLibConfig->numChannels,
- CHANNEL_MASK_USE_CHANNEL_ORDER, AUDIO_FORMAT_PCM_16_BIT, 2) != NO_ERROR) {
+ CHANNEL_MASK_USE_CHANNEL_ORDER, AUDIO_FORMAT_PCM_16_BIT, 2 /*bufferCount*/) != NO_ERROR) {
ALOGE("mAudioSink open failed");
return ERROR_OPEN_FAILED;
}
diff --git a/media/libmediaplayerservice/RemoteDisplay.cpp b/media/libmediaplayerservice/RemoteDisplay.cpp
index 20e6513..eb959b4 100644
--- a/media/libmediaplayerservice/RemoteDisplay.cpp
+++ b/media/libmediaplayerservice/RemoteDisplay.cpp
@@ -16,19 +16,23 @@
#include "RemoteDisplay.h"
-#include "ANetworkSession.h"
#include "source/WifiDisplaySource.h"
#include <media/IRemoteDisplayClient.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/ANetworkSession.h>
namespace android {
RemoteDisplay::RemoteDisplay(
- const sp<IRemoteDisplayClient> &client, const char *iface)
+ const sp<IRemoteDisplayClient> &client,
+ const char *iface)
: mLooper(new ALooper),
- mNetSession(new ANetworkSession),
- mSource(new WifiDisplaySource(mNetSession, client)) {
+ mNetSession(new ANetworkSession) {
mLooper->setName("wfd_looper");
+
+ mSource = new WifiDisplaySource(mNetSession, client);
mLooper->registerHandler(mSource);
mNetSession->start();
@@ -50,6 +54,7 @@ status_t RemoteDisplay::resume() {
status_t RemoteDisplay::dispose() {
mSource->stop();
+ mSource.clear();
mLooper->stop();
mNetSession->stop();
diff --git a/media/libmediaplayerservice/RemoteDisplay.h b/media/libmediaplayerservice/RemoteDisplay.h
index bd8b684..82a0116 100644
--- a/media/libmediaplayerservice/RemoteDisplay.h
+++ b/media/libmediaplayerservice/RemoteDisplay.h
@@ -18,6 +18,7 @@
#define REMOTE_DISPLAY_H_
+#include <media/IMediaPlayerService.h>
#include <media/IRemoteDisplay.h>
#include <media/stagefright/foundation/ABase.h>
#include <utils/Errors.h>
@@ -31,7 +32,9 @@ struct IRemoteDisplayClient;
struct WifiDisplaySource;
struct RemoteDisplay : public BnRemoteDisplay {
- RemoteDisplay(const sp<IRemoteDisplayClient> &client, const char *iface);
+ RemoteDisplay(
+ const sp<IRemoteDisplayClient> &client,
+ const char *iface);
virtual status_t pause();
virtual status_t resume();
diff --git a/media/libmediaplayerservice/SharedLibrary.cpp b/media/libmediaplayerservice/SharedLibrary.cpp
index 178e15d..34db761 100644
--- a/media/libmediaplayerservice/SharedLibrary.cpp
+++ b/media/libmediaplayerservice/SharedLibrary.cpp
@@ -46,4 +46,10 @@ namespace android {
}
return dlsym(mLibHandle, symbol);
}
+
+ const char *SharedLibrary::lastError() const {
+ const char *error = dlerror();
+ return error ? error : "No errors or unknown error";
+ }
+
};
diff --git a/media/libmediaplayerservice/SharedLibrary.h b/media/libmediaplayerservice/SharedLibrary.h
index 5353642..88451a0 100644
--- a/media/libmediaplayerservice/SharedLibrary.h
+++ b/media/libmediaplayerservice/SharedLibrary.h
@@ -29,6 +29,7 @@ namespace android {
bool operator!() const;
void *lookup(const char *symbol) const;
+ const char *lastError() const;
private:
void *mLibHandle;
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
index 655ee55..d8b35d7 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
@@ -20,7 +20,6 @@
#include "HTTPLiveSource.h"
-#include "ATSParser.h"
#include "AnotherPacketSource.h"
#include "LiveDataSource.h"
#include "LiveSession.h"
@@ -44,7 +43,8 @@ NuPlayer::HTTPLiveSource::HTTPLiveSource(
mUID(uid),
mFlags(0),
mFinalResult(OK),
- mOffset(0) {
+ mOffset(0),
+ mFetchSubtitleDataGeneration(0) {
if (headers) {
mExtraHeaders = *headers;
@@ -62,7 +62,10 @@ NuPlayer::HTTPLiveSource::HTTPLiveSource(
NuPlayer::HTTPLiveSource::~HTTPLiveSource() {
if (mLiveSession != NULL) {
mLiveSession->disconnect();
+ mLiveSession.clear();
+
mLiveLooper->stop();
+ mLiveLooper.clear();
}
}
@@ -76,128 +79,72 @@ void NuPlayer::HTTPLiveSource::prepareAsync() {
mLiveSession = new LiveSession(
notify,
(mFlags & kFlagIncognito) ? LiveSession::kFlagIncognito : 0,
- mUIDValid, mUID);
+ mUIDValid,
+ mUID);
mLiveLooper->registerHandler(mLiveSession);
- mLiveSession->connect(
+ mLiveSession->connectAsync(
mURL.c_str(), mExtraHeaders.isEmpty() ? NULL : &mExtraHeaders);
-
- mTSParser = new ATSParser;
}
void NuPlayer::HTTPLiveSource::start() {
}
-sp<MetaData> NuPlayer::HTTPLiveSource::getFormatMeta(bool audio) {
- ATSParser::SourceType type =
- audio ? ATSParser::AUDIO : ATSParser::VIDEO;
+sp<AMessage> NuPlayer::HTTPLiveSource::getFormat(bool audio) {
+ sp<AMessage> format;
+ status_t err = mLiveSession->getStreamFormat(
+ audio ? LiveSession::STREAMTYPE_AUDIO
+ : LiveSession::STREAMTYPE_VIDEO,
+ &format);
- sp<AnotherPacketSource> source =
- static_cast<AnotherPacketSource *>(mTSParser->getSource(type).get());
-
- if (source == NULL) {
+ if (err != OK) {
return NULL;
}
- return source->getFormat();
+ return format;
}
status_t NuPlayer::HTTPLiveSource::feedMoreTSData() {
- if (mFinalResult != OK) {
- return mFinalResult;
- }
-
- sp<LiveDataSource> source =
- static_cast<LiveDataSource *>(mLiveSession->getDataSource().get());
-
- for (int32_t i = 0; i < 50; ++i) {
- char buffer[188];
- ssize_t n = source->readAtNonBlocking(mOffset, buffer, sizeof(buffer));
-
- if (n == -EWOULDBLOCK) {
- break;
- } else if (n < 0) {
- if (n != ERROR_END_OF_STREAM) {
- ALOGI("input data EOS reached, error %ld", n);
- } else {
- ALOGI("input data EOS reached.");
- }
- mTSParser->signalEOS(n);
- mFinalResult = n;
- break;
- } else {
- if (buffer[0] == 0x00) {
- // XXX legacy
-
- uint8_t type = buffer[1];
-
- sp<AMessage> extra = new AMessage;
-
- if (type & 2) {
- int64_t mediaTimeUs;
- memcpy(&mediaTimeUs, &buffer[2], sizeof(mediaTimeUs));
-
- extra->setInt64(IStreamListener::kKeyMediaTimeUs, mediaTimeUs);
- }
-
- mTSParser->signalDiscontinuity(
- ((type & 1) == 0)
- ? ATSParser::DISCONTINUITY_SEEK
- : ATSParser::DISCONTINUITY_FORMATCHANGE,
- extra);
- } else {
- status_t err = mTSParser->feedTSPacket(buffer, sizeof(buffer));
-
- if (err != OK) {
- ALOGE("TS Parser returned error %d", err);
- mTSParser->signalEOS(err);
- mFinalResult = err;
- break;
- }
- }
-
- mOffset += n;
- }
- }
-
return OK;
}
status_t NuPlayer::HTTPLiveSource::dequeueAccessUnit(
bool audio, sp<ABuffer> *accessUnit) {
- ATSParser::SourceType type =
- audio ? ATSParser::AUDIO : ATSParser::VIDEO;
-
- sp<AnotherPacketSource> source =
- static_cast<AnotherPacketSource *>(mTSParser->getSource(type).get());
-
- if (source == NULL) {
- return -EWOULDBLOCK;
- }
-
- status_t finalResult;
- if (!source->hasBufferAvailable(&finalResult)) {
- return finalResult == OK ? -EWOULDBLOCK : finalResult;
- }
-
- return source->dequeueAccessUnit(accessUnit);
+ return mLiveSession->dequeueAccessUnit(
+ audio ? LiveSession::STREAMTYPE_AUDIO
+ : LiveSession::STREAMTYPE_VIDEO,
+ accessUnit);
}
status_t NuPlayer::HTTPLiveSource::getDuration(int64_t *durationUs) {
return mLiveSession->getDuration(durationUs);
}
-status_t NuPlayer::HTTPLiveSource::seekTo(int64_t seekTimeUs) {
- // We need to make sure we're not seeking until we have seen the very first
- // PTS timestamp in the whole stream (from the beginning of the stream).
- while (!mTSParser->PTSTimeDeltaEstablished() && feedMoreTSData() == OK) {
- usleep(100000);
+status_t NuPlayer::HTTPLiveSource::getTrackInfo(Parcel *reply) const {
+ return mLiveSession->getTrackInfo(reply);
+}
+
+status_t NuPlayer::HTTPLiveSource::selectTrack(size_t trackIndex, bool select) {
+ status_t err = mLiveSession->selectTrack(trackIndex, select);
+
+ if (err == OK) {
+ mFetchSubtitleDataGeneration++;
+ if (select) {
+ sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, id());
+ msg->setInt32("generation", mFetchSubtitleDataGeneration);
+ msg->post();
+ }
}
- mLiveSession->seekTo(seekTimeUs);
+ // LiveSession::selectTrack returns BAD_VALUE when selecting the currently
+ // selected track, or unselecting a non-selected track. In this case it's an
+ // no-op so we return OK.
+ return (err == OK || err == BAD_VALUE) ? OK : err;
+}
- return OK;
+status_t NuPlayer::HTTPLiveSource::seekTo(int64_t seekTimeUs) {
+ return mLiveSession->seekTo(seekTimeUs);
}
void NuPlayer::HTTPLiveSource::onMessageReceived(const sp<AMessage> &msg) {
@@ -208,6 +155,39 @@ void NuPlayer::HTTPLiveSource::onMessageReceived(const sp<AMessage> &msg) {
break;
}
+ case kWhatFetchSubtitleData:
+ {
+ int32_t generation;
+ CHECK(msg->findInt32("generation", &generation));
+
+ if (generation != mFetchSubtitleDataGeneration) {
+ // stale
+ break;
+ }
+
+ sp<ABuffer> buffer;
+ if (mLiveSession->dequeueAccessUnit(
+ LiveSession::STREAMTYPE_SUBTITLES, &buffer) == OK) {
+ sp<AMessage> notify = dupNotify();
+ notify->setInt32("what", kWhatSubtitleData);
+ notify->setBuffer("buffer", buffer);
+ notify->post();
+
+ int64_t timeUs, baseUs, durationUs, delayUs;
+ CHECK(buffer->meta()->findInt64("baseUs", &baseUs));
+ CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
+ CHECK(buffer->meta()->findInt64("durationUs", &durationUs));
+ delayUs = baseUs + timeUs - ALooper::GetNowUs();
+
+ msg->post(delayUs > 0ll ? delayUs : 0ll);
+ } else {
+ // try again in 1 second
+ msg->post(1000000ll);
+ }
+
+ break;
+ }
+
default:
Source::onMessageReceived(msg);
break;
@@ -249,6 +229,32 @@ void NuPlayer::HTTPLiveSource::onSessionNotify(const sp<AMessage> &msg) {
break;
}
+ case LiveSession::kWhatStreamsChanged:
+ {
+ uint32_t changedMask;
+ CHECK(msg->findInt32(
+ "changedMask", (int32_t *)&changedMask));
+
+ bool audio = changedMask & LiveSession::STREAMTYPE_AUDIO;
+ bool video = changedMask & LiveSession::STREAMTYPE_VIDEO;
+
+ sp<AMessage> reply;
+ CHECK(msg->findMessage("reply", &reply));
+
+ sp<AMessage> notify = dupNotify();
+ notify->setInt32("what", kWhatQueueDecoderShutdown);
+ notify->setInt32("audio", audio);
+ notify->setInt32("video", video);
+ notify->setMessage("reply", reply);
+ notify->post();
+ break;
+ }
+
+ case LiveSession::kWhatError:
+ {
+ break;
+ }
+
default:
TRESPASS();
}
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
index 067d1da..bcc3f8b 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
@@ -23,7 +23,6 @@
namespace android {
-struct ATSParser;
struct LiveSession;
struct NuPlayer::HTTPLiveSource : public NuPlayer::Source {
@@ -37,18 +36,18 @@ struct NuPlayer::HTTPLiveSource : public NuPlayer::Source {
virtual void prepareAsync();
virtual void start();
- virtual status_t feedMoreTSData();
-
virtual status_t dequeueAccessUnit(bool audio, sp<ABuffer> *accessUnit);
+ virtual sp<AMessage> getFormat(bool audio);
+ virtual status_t feedMoreTSData();
virtual status_t getDuration(int64_t *durationUs);
+ virtual status_t getTrackInfo(Parcel *reply) const;
+ virtual status_t selectTrack(size_t trackIndex, bool select);
virtual status_t seekTo(int64_t seekTimeUs);
protected:
virtual ~HTTPLiveSource();
- virtual sp<MetaData> getFormatMeta(bool audio);
-
virtual void onMessageReceived(const sp<AMessage> &msg);
private:
@@ -59,6 +58,7 @@ private:
enum {
kWhatSessionNotify,
+ kWhatFetchSubtitleData,
};
AString mURL;
@@ -70,7 +70,7 @@ private:
off64_t mOffset;
sp<ALooper> mLiveLooper;
sp<LiveSession> mLiveSession;
- sp<ATSParser> mTSParser;
+ int32_t mFetchSubtitleDataGeneration;
void onSessionNotify(const sp<AMessage> &msg);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 6d95a41..3669a5b 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -91,6 +91,38 @@ private:
DISALLOW_EVIL_CONSTRUCTORS(SetSurfaceAction);
};
+struct NuPlayer::ShutdownDecoderAction : public Action {
+ ShutdownDecoderAction(bool audio, bool video)
+ : mAudio(audio),
+ mVideo(video) {
+ }
+
+ virtual void execute(NuPlayer *player) {
+ player->performDecoderShutdown(mAudio, mVideo);
+ }
+
+private:
+ bool mAudio;
+ bool mVideo;
+
+ DISALLOW_EVIL_CONSTRUCTORS(ShutdownDecoderAction);
+};
+
+struct NuPlayer::PostMessageAction : public Action {
+ PostMessageAction(const sp<AMessage> &msg)
+ : mMessage(msg) {
+ }
+
+ virtual void execute(NuPlayer *) {
+ mMessage->post();
+ }
+
+private:
+ sp<AMessage> mMessage;
+
+ DISALLOW_EVIL_CONSTRUCTORS(PostMessageAction);
+};
+
// Use this if there's no state necessary to save in order to execute
// the action.
struct NuPlayer::SimpleAction : public Action {
@@ -311,6 +343,46 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
break;
}
+ case kWhatGetTrackInfo:
+ {
+ uint32_t replyID;
+ CHECK(msg->senderAwaitsResponse(&replyID));
+
+ status_t err = INVALID_OPERATION;
+ if (mSource != NULL) {
+ Parcel* reply;
+ CHECK(msg->findPointer("reply", (void**)&reply));
+ err = mSource->getTrackInfo(reply);
+ }
+
+ sp<AMessage> response = new AMessage;
+ response->setInt32("err", err);
+
+ response->postReply(replyID);
+ break;
+ }
+
+ case kWhatSelectTrack:
+ {
+ uint32_t replyID;
+ CHECK(msg->senderAwaitsResponse(&replyID));
+
+ status_t err = INVALID_OPERATION;
+ if (mSource != NULL) {
+ size_t trackIndex;
+ int32_t select;
+ CHECK(msg->findSize("trackIndex", &trackIndex));
+ CHECK(msg->findInt32("select", &select));
+ err = mSource->selectTrack(trackIndex, select);
+ }
+
+ sp<AMessage> response = new AMessage;
+ response->setInt32("err", err);
+
+ response->postReply(replyID);
+ break;
+ }
+
case kWhatPollDuration:
{
int32_t generation;
@@ -338,7 +410,8 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
ALOGV("kWhatSetVideoNativeWindow");
mDeferredActions.push_back(
- new SimpleAction(&NuPlayer::performDecoderShutdown));
+ new ShutdownDecoderAction(
+ false /* audio */, true /* video */));
sp<RefBase> obj;
CHECK(msg->findObject("native-window", &obj));
@@ -721,6 +794,9 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
ALOGV("renderer %s flush completed.", audio ? "audio" : "video");
} else if (what == Renderer::kWhatVideoRenderingStart) {
notifyListener(MEDIA_INFO, MEDIA_INFO_RENDERING_START, 0);
+ } else if (what == Renderer::kWhatMediaRenderingStart) {
+ ALOGV("media rendering started");
+ notifyListener(MEDIA_STARTED, 0, 0);
}
break;
}
@@ -735,7 +811,8 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
ALOGV("kWhatReset");
mDeferredActions.push_back(
- new SimpleAction(&NuPlayer::performDecoderShutdown));
+ new ShutdownDecoderAction(
+ true /* audio */, true /* video */));
mDeferredActions.push_back(
new SimpleAction(&NuPlayer::performReset));
@@ -1031,7 +1108,7 @@ void NuPlayer::renderBuffer(bool audio, const sp<AMessage> &msg) {
mRenderer->queueBuffer(audio, buffer, reply);
}
-void NuPlayer::notifyListener(int msg, int ext1, int ext2) {
+void NuPlayer::notifyListener(int msg, int ext1, int ext2, const Parcel *in) {
if (mDriver == NULL) {
return;
}
@@ -1042,10 +1119,13 @@ void NuPlayer::notifyListener(int msg, int ext1, int ext2) {
return;
}
- driver->notifyListener(msg, ext1, ext2);
+ driver->notifyListener(msg, ext1, ext2, in);
}
void NuPlayer::flushDecoder(bool audio, bool needShutdown) {
+ ALOGV("[%s] flushDecoder needShutdown=%d",
+ audio ? "audio" : "video", needShutdown);
+
if ((audio && mAudioDecoder == NULL) || (!audio && mVideoDecoder == NULL)) {
ALOGI("flushDecoder %s without decoder present",
audio ? "audio" : "video");
@@ -1115,6 +1195,26 @@ status_t NuPlayer::setVideoScalingMode(int32_t mode) {
return OK;
}
+status_t NuPlayer::getTrackInfo(Parcel* reply) const {
+ sp<AMessage> msg = new AMessage(kWhatGetTrackInfo, id());
+ msg->setPointer("reply", reply);
+
+ sp<AMessage> response;
+ status_t err = msg->postAndAwaitResponse(&response);
+ return err;
+}
+
+status_t NuPlayer::selectTrack(size_t trackIndex, bool select) {
+ sp<AMessage> msg = new AMessage(kWhatSelectTrack, id());
+ msg->setSize("trackIndex", trackIndex);
+ msg->setInt32("select", select);
+
+ sp<AMessage> response;
+ status_t err = msg->postAndAwaitResponse(&response);
+
+ return err;
+}
+
void NuPlayer::schedulePollDuration() {
sp<AMessage> msg = new AMessage(kWhatPollDuration, id());
msg->setInt32("generation", mPollDurationGeneration);
@@ -1196,20 +1296,29 @@ void NuPlayer::performDecoderFlush() {
}
}
-void NuPlayer::performDecoderShutdown() {
- ALOGV("performDecoderShutdown");
+void NuPlayer::performDecoderShutdown(bool audio, bool video) {
+ ALOGV("performDecoderShutdown audio=%d, video=%d", audio, video);
- if (mAudioDecoder == NULL && mVideoDecoder == NULL) {
+ if ((!audio || mAudioDecoder == NULL)
+ && (!video || mVideoDecoder == NULL)) {
return;
}
mTimeDiscontinuityPending = true;
- if (mAudioDecoder != NULL) {
+ if (mFlushingAudio == NONE && (!audio || mAudioDecoder == NULL)) {
+ mFlushingAudio = FLUSHED;
+ }
+
+ if (mFlushingVideo == NONE && (!video || mVideoDecoder == NULL)) {
+ mFlushingVideo = FLUSHED;
+ }
+
+ if (audio && mAudioDecoder != NULL) {
flushDecoder(true /* audio */, true /* needShutdown */);
}
- if (mVideoDecoder != NULL) {
+ if (video && mVideoDecoder != NULL) {
flushDecoder(false /* audio */, true /* needShutdown */);
}
}
@@ -1310,6 +1419,11 @@ void NuPlayer::onSourceNotify(const sp<AMessage> &msg) {
uint32_t flags;
CHECK(msg->findInt32("flags", (int32_t *)&flags));
+ sp<NuPlayerDriver> driver = mDriver.promote();
+ if (driver != NULL) {
+ driver->notifyFlagsChanged(flags);
+ }
+
if ((mSourceFlags & Source::FLAG_DYNAMIC_DURATION)
&& (!(flags & Source::FLAG_DYNAMIC_DURATION))) {
cancelPollDuration();
@@ -1345,6 +1459,42 @@ void NuPlayer::onSourceNotify(const sp<AMessage> &msg) {
break;
}
+ case Source::kWhatSubtitleData:
+ {
+ sp<ABuffer> buffer;
+ CHECK(msg->findBuffer("buffer", &buffer));
+
+ int32_t trackIndex;
+ int64_t timeUs, durationUs;
+ CHECK(buffer->meta()->findInt32("trackIndex", &trackIndex));
+ CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
+ CHECK(buffer->meta()->findInt64("durationUs", &durationUs));
+
+ Parcel in;
+ in.writeInt32(trackIndex);
+ in.writeInt64(timeUs);
+ in.writeInt64(durationUs);
+ in.writeInt32(buffer->size());
+ in.writeInt32(buffer->size());
+ in.write(buffer->data(), buffer->size());
+
+ notifyListener(MEDIA_SUBTITLE_DATA, 0, 0, &in);
+ break;
+ }
+
+ case Source::kWhatQueueDecoderShutdown:
+ {
+ int32_t audio, video;
+ CHECK(msg->findInt32("audio", &audio));
+ CHECK(msg->findInt32("video", &video));
+
+ sp<AMessage> reply;
+ CHECK(msg->findMessage("reply", &reply));
+
+ queueDecoderShutdown(audio, video, reply);
+ break;
+ }
+
default:
TRESPASS();
}
@@ -1378,4 +1528,19 @@ void NuPlayer::Source::onMessageReceived(const sp<AMessage> &msg) {
TRESPASS();
}
+void NuPlayer::queueDecoderShutdown(
+ bool audio, bool video, const sp<AMessage> &reply) {
+ ALOGI("queueDecoderShutdown audio=%d, video=%d", audio, video);
+
+ mDeferredActions.push_back(
+ new ShutdownDecoderAction(audio, video));
+
+ mDeferredActions.push_back(
+ new SimpleAction(&NuPlayer::performScanSources));
+
+ mDeferredActions.push_back(new PostMessageAction(reply));
+
+ processDeferredActions();
+}
+
} // namespace android
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index 59b4a38..590e1f2 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -60,6 +60,8 @@ struct NuPlayer : public AHandler {
void seekToAsync(int64_t seekTimeUs);
status_t setVideoScalingMode(int32_t mode);
+ status_t getTrackInfo(Parcel* reply) const;
+ status_t selectTrack(size_t trackIndex, bool select);
protected:
virtual ~NuPlayer();
@@ -80,6 +82,8 @@ private:
struct Action;
struct SeekAction;
struct SetSurfaceAction;
+ struct ShutdownDecoderAction;
+ struct PostMessageAction;
struct SimpleAction;
enum {
@@ -99,6 +103,8 @@ private:
kWhatResume = 'rsme',
kWhatPollDuration = 'polD',
kWhatSourceNotify = 'srcN',
+ kWhatGetTrackInfo = 'gTrI',
+ kWhatSelectTrack = 'selT',
};
wp<NuPlayerDriver> mDriver;
@@ -156,7 +162,7 @@ private:
status_t feedDecoderInputData(bool audio, const sp<AMessage> &msg);
void renderBuffer(bool audio, const sp<AMessage> &msg);
- void notifyListener(int msg, int ext1, int ext2);
+ void notifyListener(int msg, int ext1, int ext2, const Parcel *in = NULL);
void finishFlushIfPossible();
@@ -173,13 +179,16 @@ private:
void performSeek(int64_t seekTimeUs);
void performDecoderFlush();
- void performDecoderShutdown();
+ void performDecoderShutdown(bool audio, bool video);
void performReset();
void performScanSources();
void performSetSurface(const sp<NativeWindowWrapper> &wrapper);
void onSourceNotify(const sp<AMessage> &msg);
+ void queueDecoderShutdown(
+ bool audio, bool video, const sp<AMessage> &reply);
+
DISALLOW_EVIL_CONSTRUCTORS(NuPlayer);
};
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index 68b9623..47834fd 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -255,6 +255,7 @@ status_t NuPlayerDriver::pause() {
return OK;
case STATE_RUNNING:
+ notifyListener(MEDIA_PAUSED);
mPlayer->pause();
break;
@@ -287,6 +288,8 @@ status_t NuPlayerDriver::seekTo(int msec) {
case STATE_PAUSED:
{
mAtEOS = false;
+ // seeks can take a while, so we essentially paused
+ notifyListener(MEDIA_PAUSED);
mPlayer->seekToAsync(seekTimeUs);
break;
}
@@ -345,6 +348,8 @@ status_t NuPlayerDriver::reset() {
break;
}
+ notifyListener(MEDIA_STOPPED);
+
mState = STATE_RESET_IN_PROGRESS;
mPlayer->resetAsync();
@@ -387,6 +392,23 @@ status_t NuPlayerDriver::invoke(const Parcel &request, Parcel *reply) {
return mPlayer->setVideoScalingMode(mode);
}
+ case INVOKE_ID_GET_TRACK_INFO:
+ {
+ return mPlayer->getTrackInfo(reply);
+ }
+
+ case INVOKE_ID_SELECT_TRACK:
+ {
+ int trackIndex = request.readInt32();
+ return mPlayer->selectTrack(trackIndex, true /* select */);
+ }
+
+ case INVOKE_ID_UNSELECT_TRACK:
+ {
+ int trackIndex = request.readInt32();
+ return mPlayer->selectTrack(trackIndex, false /* select */);
+ }
+
default:
{
return INVALID_OPERATION;
@@ -490,12 +512,13 @@ status_t NuPlayerDriver::dump(int fd, const Vector<String16> &args) const {
return OK;
}
-void NuPlayerDriver::notifyListener(int msg, int ext1, int ext2) {
+void NuPlayerDriver::notifyListener(
+ int msg, int ext1, int ext2, const Parcel *in) {
if (msg == MEDIA_PLAYBACK_COMPLETE || msg == MEDIA_ERROR) {
mAtEOS = true;
}
- sendEvent(msg, ext1, ext2);
+ sendEvent(msg, ext1, ext2, in);
}
void NuPlayerDriver::notifySetDataSourceCompleted(status_t err) {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
index 5df0cfb..99f72a6 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
@@ -69,7 +69,7 @@ struct NuPlayerDriver : public MediaPlayerInterface {
void notifyPosition(int64_t positionUs);
void notifySeekComplete();
void notifyFrameStats(int64_t numFramesTotal, int64_t numFramesDropped);
- void notifyListener(int msg, int ext1 = 0, int ext2 = 0);
+ void notifyListener(int msg, int ext1 = 0, int ext2 = 0, const Parcel *in = NULL);
void notifyFlagsChanged(uint32_t flags);
protected:
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 7114be5..92b9a92 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -53,6 +53,8 @@ NuPlayer::Renderer::Renderer(
mSyncQueues(false),
mPaused(false),
mVideoRenderingStarted(false),
+ mVideoRenderingStartGeneration(0),
+ mAudioRenderingStartGeneration(0),
mLastPositionUpdateUs(-1ll),
mVideoLateByUs(0ll) {
}
@@ -104,11 +106,11 @@ void NuPlayer::Renderer::flush(bool audio) {
}
void NuPlayer::Renderer::signalTimeDiscontinuity() {
- CHECK(mAudioQueue.empty());
- CHECK(mVideoQueue.empty());
+ // CHECK(mAudioQueue.empty());
+ // CHECK(mVideoQueue.empty());
mAnchorTimeMediaUs = -1;
mAnchorTimeRealUs = -1;
- mSyncQueues = mHasAudio && mHasVideo;
+ mSyncQueues = false;
}
void NuPlayer::Renderer::pause() {
@@ -229,6 +231,23 @@ void NuPlayer::Renderer::signalAudioSinkChanged() {
(new AMessage(kWhatAudioSinkChanged, id()))->post();
}
+void NuPlayer::Renderer::prepareForMediaRenderingStart() {
+ mAudioRenderingStartGeneration = mAudioQueueGeneration;
+ mVideoRenderingStartGeneration = mVideoQueueGeneration;
+}
+
+void NuPlayer::Renderer::notifyIfMediaRenderingStarted() {
+ if (mVideoRenderingStartGeneration == mVideoQueueGeneration &&
+ mAudioRenderingStartGeneration == mAudioQueueGeneration) {
+ mVideoRenderingStartGeneration = -1;
+ mAudioRenderingStartGeneration = -1;
+
+ sp<AMessage> notify = mNotify->dup();
+ notify->setInt32("what", kWhatMediaRenderingStart);
+ notify->post();
+ }
+}
+
bool NuPlayer::Renderer::onDrainAudioQueue() {
uint32_t numFramesPlayed;
if (mAudioSink->getPosition(&numFramesPlayed) != OK) {
@@ -308,6 +327,8 @@ bool NuPlayer::Renderer::onDrainAudioQueue() {
numBytesAvailableToWrite -= copy;
size_t copiedFrames = copy / mAudioSink->frameSize();
mNumFramesWritten += copiedFrames;
+
+ notifyIfMediaRenderingStarted();
}
notifyPosition();
@@ -417,6 +438,8 @@ void NuPlayer::Renderer::onDrainVideoQueue() {
notifyVideoRenderingStart();
}
+ notifyIfMediaRenderingStarted();
+
notifyPosition();
}
@@ -564,6 +587,7 @@ void NuPlayer::Renderer::onFlush(const sp<AMessage> &msg) {
// is flushed.
syncQueuesDone();
+ ALOGV("flushing %s", audio ? "audio" : "video");
if (audio) {
flushQueue(&mAudioQueue);
@@ -572,6 +596,8 @@ void NuPlayer::Renderer::onFlush(const sp<AMessage> &msg) {
mDrainAudioQueuePending = false;
++mAudioQueueGeneration;
+
+ prepareForMediaRenderingStart();
} else {
flushQueue(&mVideoQueue);
@@ -580,6 +606,8 @@ void NuPlayer::Renderer::onFlush(const sp<AMessage> &msg) {
mDrainVideoQueuePending = false;
++mVideoQueueGeneration;
+
+ prepareForMediaRenderingStart();
}
notifyFlushComplete(audio);
@@ -670,6 +698,8 @@ void NuPlayer::Renderer::onPause() {
mDrainVideoQueuePending = false;
++mVideoQueueGeneration;
+ prepareForMediaRenderingStart();
+
if (mHasAudio) {
mAudioSink->pause();
}
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
index bd51af3..9124e03 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
@@ -54,6 +54,7 @@ struct NuPlayer::Renderer : public AHandler {
kWhatFlushComplete = 'fluC',
kWhatPosition = 'posi',
kWhatVideoRenderingStart = 'vdrd',
+ kWhatMediaRenderingStart = 'mdrd',
};
void setSoftRenderer(SoftwareRenderer *softRenderer);
@@ -110,6 +111,8 @@ private:
bool mPaused;
bool mVideoRenderingStarted;
+ int32_t mVideoRenderingStartGeneration;
+ int32_t mAudioRenderingStartGeneration;
int64_t mLastPositionUpdateUs;
int64_t mVideoLateByUs;
@@ -120,6 +123,9 @@ private:
void onDrainVideoQueue();
void postDrainVideoQueue();
+ void prepareForMediaRenderingStart();
+ void notifyIfMediaRenderingStarted();
+
void onQueueBuffer(const sp<AMessage> &msg);
void onQueueEOS(const sp<AMessage> &msg);
void onFlush(const sp<AMessage> &msg);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
index 1cbf575..e50533a 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
@@ -42,6 +42,8 @@ struct NuPlayer::Source : public AHandler {
kWhatVideoSizeChanged,
kWhatBufferingStart,
kWhatBufferingEnd,
+ kWhatSubtitleData,
+ kWhatQueueDecoderShutdown,
};
// The provides message is used to notify the player about various
@@ -70,6 +72,14 @@ struct NuPlayer::Source : public AHandler {
return INVALID_OPERATION;
}
+ virtual status_t getTrackInfo(Parcel* reply) const {
+ return INVALID_OPERATION;
+ }
+
+ virtual status_t selectTrack(size_t trackIndex, bool select) {
+ return INVALID_OPERATION;
+ }
+
virtual status_t seekTo(int64_t seekTimeUs) {
return INVALID_OPERATION;
}
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
index 3385a19..18cf6d1 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
@@ -358,11 +358,10 @@ void NuPlayer::RTSPSource::onMessageReceived(const sp<AMessage> &msg) {
uint32_t flags = 0;
if (mHandler->isSeekable()) {
- flags = FLAG_CAN_PAUSE | FLAG_CAN_SEEK;
-
- // Seeking 10secs forward or backward is a very expensive
- // operation for rtsp, so let's not enable that.
- // The user can always use the seek bar.
+ flags = FLAG_CAN_PAUSE
+ | FLAG_CAN_SEEK
+ | FLAG_CAN_SEEK_BACKWARD
+ | FLAG_CAN_SEEK_FORWARD;
}
notifyFlagsChanged(flags);