diff options
Diffstat (limited to 'media/libmediaplayerservice/MediaPlayerService.cpp')
| -rw-r--r-- | media/libmediaplayerservice/MediaPlayerService.cpp | 360 |
1 files changed, 276 insertions, 84 deletions
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index 49032e7..6a6afa1 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -199,10 +199,14 @@ extmap FILE_EXTS [] = { {".ota", SONIVOX_PLAYER}, {".ogg", VORBIS_PLAYER}, {".oga", VORBIS_PLAYER}, +#ifndef NO_OPENCORE + {".wma", PV_PLAYER}, + {".wmv", PV_PLAYER}, + {".asf", PV_PLAYER}, +#endif }; // TODO: Find real cause of Audio/Video delay in PV framework and remove this workaround -/* static */ const uint32_t MediaPlayerService::AudioOutput::kAudioVideoDelayMs = 0; /* static */ int MediaPlayerService::AudioOutput::mMinBufferCount = 4; /* static */ bool MediaPlayerService::AudioOutput::mIsOnEmulator = false; @@ -250,12 +254,14 @@ sp<IMediaMetadataRetriever> MediaPlayerService::createMetadataRetriever(pid_t pi return retriever; } -sp<IMediaPlayer> MediaPlayerService::create(pid_t pid, const sp<IMediaPlayerClient>& client, const char* url) +sp<IMediaPlayer> MediaPlayerService::create( + pid_t pid, const sp<IMediaPlayerClient>& client, const char* url, + const KeyedVector<String8, String8> *headers) { int32_t connId = android_atomic_inc(&mNextConnId); sp<Client> c = new Client(this, pid, connId, client); LOGV("Create new client(%d) from pid %d, url=%s, connId=%d", connId, pid, url, connId); - if (NO_ERROR != c->setDataSource(url)) + if (NO_ERROR != c->setDataSource(url, headers)) { c.clear(); return c; @@ -366,11 +372,44 @@ extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize, size_t* infoSize, size_t* totalMemory, size_t* backtraceSize); extern "C" void free_malloc_leak_info(uint8_t* info); +// Use the String-class below instead of String8 to allocate all memory +// beforehand and not reenter the heap while we are examining it... +struct MyString8 { + static const size_t MAX_SIZE = 256 * 1024; + + MyString8() + : mPtr((char *)malloc(MAX_SIZE)) { + *mPtr = '\0'; + } + + ~MyString8() { + free(mPtr); + } + + void append(const char *s) { + strcat(mPtr, s); + } + + const char *string() const { + return mPtr; + } + + size_t size() const { + return strlen(mPtr); + } + +private: + char *mPtr; + + MyString8(const MyString8 &); + MyString8 &operator=(const MyString8 &); +}; + void memStatus(int fd, const Vector<String16>& args) { const size_t SIZE = 256; char buffer[SIZE]; - String8 result; + MyString8 result; typedef struct { size_t size; @@ -391,6 +430,8 @@ void memStatus(int fd, const Vector<String16>& args) snprintf(buffer, SIZE, " Allocation count %i\n", count); result.append(buffer); + snprintf(buffer, SIZE, " Total memory %i\n", totalMemory); + result.append(buffer); AllocEntry * entries = new AllocEntry[count]; @@ -439,7 +480,7 @@ void memStatus(int fd, const Vector<String16>& args) for (size_t i = 0; i < count; i++) { AllocEntry *e = &entries[i]; - snprintf(buffer, SIZE, "size %8i, dup %4i", e->size, e->dups); + snprintf(buffer, SIZE, "size %8i, dup %4i, ", e->size, e->dups); result.append(buffer); for (size_t ct = 0; (ct < backtraceSize) && e->backtrace[ct]; ct++) { if (ct) { @@ -637,6 +678,26 @@ static player_type getDefaultPlayerType() { return PV_PLAYER; } +// By default we use the VORBIS_PLAYER for vorbis playback (duh!), +// but if the magic property is set we will use our new experimental +// stagefright code instead. +static player_type OverrideStagefrightForVorbis(player_type player) { + if (player != VORBIS_PLAYER) { + return player; + } + +#if BUILD_WITH_FULL_STAGEFRIGHT + char value[PROPERTY_VALUE_MAX]; + if (property_get("media.stagefright.enable-vorbis", value, NULL) + && (!strcmp(value, "1") || !strcmp(value, "true"))) { + return STAGEFRIGHT_PLAYER; + } +#endif + + return VORBIS_PLAYER; +} + + player_type getPlayerType(int fd, int64_t offset, int64_t length) { char buf[20]; @@ -648,7 +709,15 @@ player_type getPlayerType(int fd, int64_t offset, int64_t length) // Ogg vorbis? if (ident == 0x5367674f) // 'OggS' - return VORBIS_PLAYER; + return OverrideStagefrightForVorbis(VORBIS_PLAYER); + +#ifndef NO_OPENCORE + if (ident == 0x75b22630) { + // The magic number for .asf files, i.e. wmv and wma content. + // These are not currently supported through stagefright. + return PV_PLAYER; + } +#endif // Some kind of MIDI? EAS_DATA_HANDLE easdata; @@ -676,6 +745,13 @@ player_type getPlayerType(const char* url) return TEST_PLAYER; } + bool useStagefrightForHTTP = false; + char value[PROPERTY_VALUE_MAX]; + if (property_get("media.stagefright.enable-http", value, NULL) + && (!strcmp(value, "1") || !strcasecmp(value, "true"))) { + useStagefrightForHTTP = true; + } + // use MidiFile for MIDI extensions int lenURL = strlen(url); for (int i = 0; i < NELEM(FILE_EXTS); ++i) { @@ -683,11 +759,27 @@ player_type getPlayerType(const char* url) int start = lenURL - len; if (start > 0) { if (!strncasecmp(url + start, FILE_EXTS[i].extension, len)) { - return FILE_EXTS[i].playertype; + if (FILE_EXTS[i].playertype == VORBIS_PLAYER + && !strncasecmp(url, "http://", 7) + && useStagefrightForHTTP) { + return STAGEFRIGHT_PLAYER; + } + return OverrideStagefrightForVorbis(FILE_EXTS[i].playertype); } } } + if (!strncasecmp(url, "http://", 7)) { + if (!useStagefrightForHTTP) { + return PV_PLAYER; + } + } + + // Use PV_PLAYER for rtsp for now + if (!strncasecmp(url, "rtsp://", 7)) { + return PV_PLAYER; + } + return getDefaultPlayerType(); } @@ -748,7 +840,8 @@ sp<MediaPlayerBase> MediaPlayerService::Client::createPlayer(player_type playerT return p; } -status_t MediaPlayerService::Client::setDataSource(const char *url) +status_t MediaPlayerService::Client::setDataSource( + const char *url, const KeyedVector<String8, String8> *headers) { LOGV("setDataSource(%s)", url); if (url == NULL) @@ -783,7 +876,7 @@ status_t MediaPlayerService::Client::setDataSource(const char *url) // now set data source LOGV(" setDataSource"); - mStatus = p->setDataSource(url); + mStatus = p->setDataSource(url, headers); if (mStatus == NO_ERROR) { mPlayer = p; } else { @@ -912,6 +1005,20 @@ status_t MediaPlayerService::Client::getMetadata( return OK; } +status_t MediaPlayerService::Client::suspend() { + sp<MediaPlayerBase> p = getPlayer(); + if (p == 0) return UNKNOWN_ERROR; + + return p->suspend(); +} + +status_t MediaPlayerService::Client::resume() { + sp<MediaPlayerBase> p = getPlayer(); + if (p == 0) return UNKNOWN_ERROR; + + return p->resume(); +} + status_t MediaPlayerService::Client::prepareAsync() { LOGV("[%d] prepareAsync", mConnId); @@ -1216,22 +1323,24 @@ Exit: static const int NUMVIZBUF = 32; static const int VIZBUFFRAMES = 1024; -static const int TOTALBUFTIMEMSEC = NUMVIZBUF * VIZBUFFRAMES * 1000 / 44100; +static const int BUFTIMEMSEC = NUMVIZBUF * VIZBUFFRAMES * 1000 / 44100; +static const int TOTALBUFTIMEMSEC = NUMVIZBUF * BUFTIMEMSEC; static bool gotMem = false; +static sp<MemoryHeapBase> heap; static sp<MemoryBase> mem[NUMVIZBUF]; -static uint64_t timeStamp[NUMVIZBUF]; +static uint64_t endTime; static uint64_t lastReadTime; static uint64_t lastWriteTime; static int writeIdx = 0; static void allocVizBufs() { if (!gotMem) { + heap = new MemoryHeapBase(NUMVIZBUF * VIZBUFFRAMES * 2, 0, "snooper"); for (int i=0;i<NUMVIZBUF;i++) { - sp<MemoryHeapBase> heap = new MemoryHeapBase(VIZBUFFRAMES*2, 0, "snooper"); - mem[i] = new MemoryBase(heap, 0, heap->getSize()); - timeStamp[i] = 0; + mem[i] = new MemoryBase(heap, VIZBUFFRAMES * 2 * i, VIZBUFFRAMES * 2); } + endTime = 0; gotMem = true; } } @@ -1248,68 +1357,48 @@ static sp<MemoryBase> getVizBuffer() { allocVizBufs(); - lastReadTime = uptimeMillis() + 100; // account for renderer delay (we shouldn't be doing this here) + lastReadTime = uptimeMillis(); // if there is no recent buffer (yet), just return empty handed if (lastWriteTime + TOTALBUFTIMEMSEC < lastReadTime) { - //LOGI("@@@@ no audio data to look at yet"); + //LOGI("@@@@ no audio data to look at yet: %d + %d < %d", (int)lastWriteTime, TOTALBUFTIMEMSEC, (int)lastReadTime); return NULL; } - char buf[200]; - - int closestIdx = -1; - uint32_t closestTime = 0x7ffffff; - - for (int i = 0; i < NUMVIZBUF; i++) { - uint64_t tsi = timeStamp[i]; - uint64_t diff = tsi > lastReadTime ? tsi - lastReadTime : lastReadTime - tsi; - if (diff < closestTime) { - closestIdx = i; - closestTime = diff; - } - } - - - if (closestIdx >= 0) { - //LOGI("@@@ return buffer %d, %d/%d", closestIdx, uint32_t(lastReadTime), uint32_t(timeStamp[closestIdx])); - return mem[closestIdx]; - } - - // we won't get here, since we either bailed out early, or got a buffer - LOGD("Didn't expect to be here"); - return NULL; -} - -static void storeVizBuf(const void *data, int len, uint64_t time) { - // Copy the data in to the visualizer buffer - // Assume a 16 bit stereo source for now. - short *viz = (short*)mem[writeIdx]->pointer(); - short *src = (short*)data; - for (int i = 0; i < VIZBUFFRAMES; i++) { - // Degrade quality by mixing to mono and clearing the lowest 3 bits. - // This should still be good enough for a visualization - *viz++ = ((int(src[0]) + int(src[1])) >> 1) & ~0x7; - src += 2; - } - timeStamp[writeIdx++] = time; - if (writeIdx >= NUMVIZBUF) { - writeIdx = 0; + int timedelta = endTime - lastReadTime; + if (timedelta < 0) timedelta = 0; + int framedelta = timedelta * 44100 / 1000; + int headIdx = (writeIdx - framedelta) / VIZBUFFRAMES - 1; + while (headIdx < 0) { + headIdx += NUMVIZBUF; } + return mem[headIdx]; } +// Append the data to the vizualization buffer static void makeVizBuffers(const char *data, int len, uint64_t time) { allocVizBufs(); uint64_t startTime = time; const int frameSize = 4; // 16 bit stereo sample is 4 bytes - while (len >= VIZBUFFRAMES * frameSize) { - storeVizBuf(data, len, time); - data += VIZBUFFRAMES * frameSize; - len -= VIZBUFFRAMES * frameSize; - time += 1000 * VIZBUFFRAMES / 44100; + int offset = writeIdx; + int maxoff = heap->getSize() / 2; // in shorts + short *base = (short*)heap->getBase(); + short *src = (short*)data; + while (len > 0) { + + // Degrade quality by mixing to mono and clearing the lowest 3 bits. + // This should still be good enough for a visualization + base[offset++] = ((int(src[0]) + int(src[1])) >> 1) & ~0x7; + src += 2; + len -= frameSize; + if (offset >= maxoff) { + offset = 0; + } } + writeIdx = offset; + endTime = time + (len / frameSize) / 44; //LOGI("@@@ stored buffers from %d to %d", uint32_t(startTime), uint32_t(time)); } @@ -1395,6 +1484,12 @@ float MediaPlayerService::AudioOutput::msecsPerFrame() const return mMsecsPerFrame; } +status_t MediaPlayerService::AudioOutput::getPosition(uint32_t *position) +{ + if (mTrack == 0) return NO_INIT; + return mTrack->getPosition(position); +} + status_t MediaPlayerService::AudioOutput::open( uint32_t sampleRate, int channelCount, int format, int bufferCount, AudioCallback cb, void *cookie) @@ -1452,7 +1547,7 @@ status_t MediaPlayerService::AudioOutput::open( LOGV("setVolume"); t->setVolume(mLeftVolume, mRightVolume); mMsecsPerFrame = 1.e3 / (float) sampleRate; - mLatency = t->latency() + kAudioVideoDelayMs; + mLatency = t->latency(); mTrack = t; return NO_ERROR; } @@ -1467,30 +1562,35 @@ void MediaPlayerService::AudioOutput::start() } } +void MediaPlayerService::AudioOutput::snoopWrite(const void* buffer, size_t size) { + // Only make visualization buffers if anyone recently requested visualization data + uint64_t now = uptimeMillis(); + if (lastReadTime + TOTALBUFTIMEMSEC >= now) { + // Based on the current play counter, the number of frames written and + // the current real time we can calculate the approximate real start + // time of the buffer we're about to write. + uint32_t pos; + mTrack->getPosition(&pos); + + // we're writing ahead by this many frames: + int ahead = mNumFramesWritten - pos; + //LOGI("@@@ written: %d, playpos: %d, latency: %d", mNumFramesWritten, pos, mTrack->latency()); + // which is this many milliseconds, assuming 44100 Hz: + ahead /= 44; + + makeVizBuffers((const char*)buffer, size, now + ahead + mTrack->latency()); + lastWriteTime = now; + } +} + + ssize_t MediaPlayerService::AudioOutput::write(const void* buffer, size_t size) { LOG_FATAL_IF(mCallback != NULL, "Don't call write if supplying a callback."); //LOGV("write(%p, %u)", buffer, size); if (mTrack) { - // Only make visualization buffers if anyone recently requested visualization data - uint64_t now = uptimeMillis(); - if (lastReadTime + TOTALBUFTIMEMSEC >= now) { - // Based on the current play counter, the number of frames written and - // the current real time we can calculate the approximate real start - // time of the buffer we're about to write. - uint32_t pos; - mTrack->getPosition(&pos); - - // we're writing ahead by this many frames: - int ahead = mNumFramesWritten - pos; - //LOGI("@@@ written: %d, playpos: %d, latency: %d", mNumFramesWritten, pos, mTrack->latency()); - // which is this many milliseconds, assuming 44100 Hz: - ahead /= 44; - - makeVizBuffers((const char*)buffer, size, now + ahead + mTrack->latency()); - lastWriteTime = now; - } + snoopWrite(buffer, size); ssize_t ret = mTrack->write(buffer, size); mNumFramesWritten += ret / 4; // assume 16 bit stereo return ret; @@ -1538,6 +1638,7 @@ void MediaPlayerService::AudioOutput::setVolume(float left, float right) // static void MediaPlayerService::AudioOutput::CallbackWrapper( int event, void *cookie, void *info) { + //LOGV("callbackwrapper"); if (event != AudioTrack::EVENT_MORE_DATA) { return; } @@ -1545,8 +1646,14 @@ void MediaPlayerService::AudioOutput::CallbackWrapper( AudioOutput *me = (AudioOutput *)cookie; AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info; - (*me->mCallback)( + size_t actualSize = (*me->mCallback)( me, buffer->raw, buffer->size, me->mCallbackCookie); + + buffer->size = actualSize; + + if (actualSize > 0) { + me->snoopWrite(buffer->raw, actualSize); + } } #undef LOG_TAG @@ -1569,14 +1676,82 @@ float MediaPlayerService::AudioCache::msecsPerFrame() const return mMsecsPerFrame; } +status_t MediaPlayerService::AudioCache::getPosition(uint32_t *position) +{ + if (position == 0) return BAD_VALUE; + *position = mSize; + return NO_ERROR; +} + +//////////////////////////////////////////////////////////////////////////////// + +struct CallbackThread : public Thread { + CallbackThread(const wp<MediaPlayerBase::AudioSink> &sink, + MediaPlayerBase::AudioSink::AudioCallback cb, + void *cookie); + +protected: + virtual ~CallbackThread(); + + virtual bool threadLoop(); + +private: + wp<MediaPlayerBase::AudioSink> mSink; + MediaPlayerBase::AudioSink::AudioCallback mCallback; + void *mCookie; + void *mBuffer; + size_t mBufferSize; + + CallbackThread(const CallbackThread &); + CallbackThread &operator=(const CallbackThread &); +}; + +CallbackThread::CallbackThread( + const wp<MediaPlayerBase::AudioSink> &sink, + MediaPlayerBase::AudioSink::AudioCallback cb, + void *cookie) + : mSink(sink), + mCallback(cb), + mCookie(cookie), + mBuffer(NULL), + mBufferSize(0) { +} + +CallbackThread::~CallbackThread() { + if (mBuffer) { + free(mBuffer); + mBuffer = NULL; + } +} + +bool CallbackThread::threadLoop() { + sp<MediaPlayerBase::AudioSink> sink = mSink.promote(); + if (sink == NULL) { + return false; + } + + if (mBuffer == NULL) { + mBufferSize = sink->bufferSize(); + mBuffer = malloc(mBufferSize); + } + + size_t actualSize = + (*mCallback)(sink.get(), mBuffer, mBufferSize, mCookie); + + if (actualSize > 0) { + sink->write(mBuffer, actualSize); + } + + return true; +} + +//////////////////////////////////////////////////////////////////////////////// + status_t MediaPlayerService::AudioCache::open( uint32_t sampleRate, int channelCount, int format, int bufferCount, AudioCallback cb, void *cookie) { LOGV("open(%u, %d, %d, %d)", sampleRate, channelCount, format, bufferCount); - if (cb != NULL) { - return UNKNOWN_ERROR; // TODO: implement this. - } if (mHeap->getHeapID() < 0) { return NO_INIT; } @@ -1585,9 +1760,25 @@ status_t MediaPlayerService::AudioCache::open( mChannelCount = (uint16_t)channelCount; mFormat = (uint16_t)format; mMsecsPerFrame = 1.e3 / (float) sampleRate; + + if (cb != NULL) { + mCallbackThread = new CallbackThread(this, cb, cookie); + } return NO_ERROR; } +void MediaPlayerService::AudioCache::start() { + if (mCallbackThread != NULL) { + mCallbackThread->run("AudioCache callback"); + } +} + +void MediaPlayerService::AudioCache::stop() { + if (mCallbackThread != NULL) { + mCallbackThread->requestExitAndWait(); + } +} + ssize_t MediaPlayerService::AudioCache::write(const void* buffer, size_t size) { LOGV("write(%p, %u)", buffer, size); @@ -1610,7 +1801,7 @@ ssize_t MediaPlayerService::AudioCache::write(const void* buffer, size_t size) status_t MediaPlayerService::AudioCache::wait() { Mutex::Autolock lock(mLock); - if (!mCommandComplete) { + while (!mCommandComplete) { mSignal.wait(mLock); } mCommandComplete = false; @@ -1647,6 +1838,7 @@ void MediaPlayerService::AudioCache::notify(void* cookie, int msg, int ext1, int } // wake up thread + Mutex::Autolock lock(p->mLock); p->mCommandComplete = true; p->mSignal.signal(); } |
