summaryrefslogtreecommitdiffstats
path: root/media/libmediaplayerservice
diff options
context:
space:
mode:
authorMarco Nelissen <marcone@google.com>2009-09-20 10:42:13 -0700
committerMarco Nelissen <marcone@google.com>2009-10-06 08:51:16 -0700
commit10dbb8e97e7a81ca4867663b5517f048820b3094 (patch)
tree8a85a3f2c3547afc82a7ab1f92bed562ab980102 /media/libmediaplayerservice
parentdefd1bd08aaf7edc1918108419cf3f9d185c22f9 (diff)
downloadframeworks_av-10dbb8e97e7a81ca4867663b5517f048820b3094.zip
frameworks_av-10dbb8e97e7a81ca4867663b5517f048820b3094.tar.gz
frameworks_av-10dbb8e97e7a81ca4867663b5517f048820b3094.tar.bz2
Music visualizer support hack.
This currently assumes 44k stereo (won't crash on other formats, but won't give the correct results either), and links statically with libspeex to get FFT data, increasing the size of libmedia by about 45kb.
Diffstat (limited to 'media/libmediaplayerservice')
-rw-r--r--media/libmediaplayerservice/MediaPlayerService.cpp139
-rw-r--r--media/libmediaplayerservice/MediaPlayerService.h3
2 files changed, 141 insertions, 1 deletions
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index a11477a..84be874 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -41,6 +41,7 @@
#include <binder/MemoryBase.h>
#include <utils/Errors.h> // for status_t
#include <utils/String8.h>
+#include <utils/SystemClock.h>
#include <utils/Vector.h>
#include <cutils/properties.h>
@@ -1185,6 +1186,117 @@ Exit:
return mem;
}
+/*
+ * Avert your eyes, ugly hack ahead.
+ * The following is to support music visualizations.
+ */
+
+static const int NUMVIZBUF = 32;
+static const int VIZBUFFRAMES = 1024;
+static const int TOTALBUFTIMEMSEC = NUMVIZBUF * VIZBUFFRAMES * 1000 / 44100;
+
+static bool gotMem = false;
+static sp<MemoryBase> mem[NUMVIZBUF];
+static uint64_t timeStamp[NUMVIZBUF];
+static uint64_t lastReadTime;
+static uint64_t lastWriteTime;
+static int writeIdx = 0;
+
+static void allocVizBufs() {
+ if (!gotMem) {
+ 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;
+ }
+ gotMem = true;
+ }
+}
+
+
+/*
+ * Get a buffer of audio data that is about to be played.
+ * We don't synchronize this because in practice the writer
+ * is ahead of the reader, and even if we did happen to catch
+ * a buffer while it's being written, it's just a visualization,
+ * so no harm done.
+ */
+static sp<MemoryBase> getVizBuffer() {
+
+ allocVizBufs();
+
+ lastReadTime = uptimeMillis() + 100; // account for renderer delay (we shouldn't be doing this here)
+
+ // if there is no recent buffer (yet), just return empty handed
+ if (lastWriteTime + TOTALBUFTIMEMSEC < lastReadTime) {
+ //LOGI("@@@@ no audio data to look at yet");
+ 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;
+ }
+}
+
+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;
+ }
+ //LOGI("@@@ stored buffers from %d to %d", uint32_t(startTime), uint32_t(time));
+}
+
+sp<IMemory> MediaPlayerService::snoop()
+{
+ sp<MemoryBase> mem = getVizBuffer();
+ return mem;
+}
+
+
#undef LOG_TAG
#define LOG_TAG "AudioSink"
MediaPlayerService::AudioOutput::AudioOutput()
@@ -1196,6 +1308,7 @@ MediaPlayerService::AudioOutput::AudioOutput()
mRightVolume = 1.0;
mLatency = 0;
mMsecsPerFrame = 0;
+ mNumFramesWritten = 0;
setMinBufferCount();
}
@@ -1327,6 +1440,7 @@ void MediaPlayerService::AudioOutput::start()
if (mTrack) {
mTrack->setVolume(mLeftVolume, mRightVolume);
mTrack->start();
+ mTrack->getPosition(&mNumFramesWritten);
}
}
@@ -1335,7 +1449,29 @@ 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) return mTrack->write(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;
+ }
+ ssize_t ret = mTrack->write(buffer, size);
+ mNumFramesWritten += ret / 4; // assume 16 bit stereo
+ return ret;
+ }
return NO_INIT;
}
@@ -1343,6 +1479,7 @@ void MediaPlayerService::AudioOutput::stop()
{
LOGV("stop");
if (mTrack) mTrack->stop();
+ lastWriteTime = 0;
}
void MediaPlayerService::AudioOutput::flush()
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index a4be414..7d2e611 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -112,6 +112,8 @@ class MediaPlayerService : public BnMediaPlayerService
static bool mIsOnEmulator;
static int mMinBufferCount; // 12 for emulator; otherwise 4
+ public: // visualization hack support
+ uint32_t mNumFramesWritten;
};
class AudioCache : public MediaPlayerBase::AudioSink
@@ -180,6 +182,7 @@ public:
virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, int fd, int64_t offset, int64_t length);
virtual sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
virtual sp<IMemory> decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
+ virtual sp<IMemory> snoop();
virtual sp<IOMX> createOMX();
virtual status_t dump(int fd, const Vector<String16>& args);