diff options
Diffstat (limited to 'media/libmediaplayerservice')
-rw-r--r-- | media/libmediaplayerservice/Android.mk | 17 | ||||
-rw-r--r-- | media/libmediaplayerservice/MediaPlayerService.cpp | 298 | ||||
-rw-r--r-- | media/libmediaplayerservice/MediaPlayerService.h | 24 | ||||
-rw-r--r-- | media/libmediaplayerservice/MediaRecorderClient.cpp | 11 | ||||
-rw-r--r-- | media/libmediaplayerservice/MediaRecorderClient.h | 21 | ||||
-rw-r--r-- | media/libmediaplayerservice/MetadataRetrieverClient.cpp | 18 | ||||
-rw-r--r-- | media/libmediaplayerservice/StagefrightRecorder.cpp | 999 | ||||
-rw-r--r-- | media/libmediaplayerservice/StagefrightRecorder.h | 70 | ||||
-rw-r--r-- | media/libmediaplayerservice/VorbisMetadataRetriever.cpp | 87 | ||||
-rw-r--r-- | media/libmediaplayerservice/VorbisMetadataRetriever.h | 49 | ||||
-rw-r--r-- | media/libmediaplayerservice/VorbisPlayer.cpp | 529 | ||||
-rw-r--r-- | media/libmediaplayerservice/VorbisPlayer.h | 94 |
12 files changed, 1107 insertions, 1110 deletions
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk index cf97b23..8f010c9 100644 --- a/media/libmediaplayerservice/Android.mk +++ b/media/libmediaplayerservice/Android.mk @@ -11,21 +11,11 @@ LOCAL_SRC_FILES:= \ MediaPlayerService.cpp \ MetadataRetrieverClient.cpp \ TestPlayerStub.cpp \ - VorbisPlayer.cpp \ - VorbisMetadataRetriever.cpp \ - MidiMetadataRetriever.cpp \ - MidiFile.cpp - -ifeq ($(BUILD_WITH_FULL_STAGEFRIGHT),true) - -LOCAL_SRC_FILES += \ - StagefrightPlayer.cpp \ + MidiMetadataRetriever.cpp \ + MidiFile.cpp \ + StagefrightPlayer.cpp \ StagefrightRecorder.cpp -LOCAL_CFLAGS += -DBUILD_WITH_FULL_STAGEFRIGHT=1 - -endif - ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true) LOCAL_LDLIBS += -ldl -lpthread endif @@ -37,6 +27,7 @@ LOCAL_SHARED_LIBRARIES := \ libvorbisidec \ libsonivox \ libmedia \ + libcamera_client \ libandroid_runtime \ libstagefright \ libstagefright_omx \ diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index 6a6afa1..b5972e7 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -56,7 +56,6 @@ #include "MetadataRetrieverClient.h" #include "MidiFile.h" -#include "VorbisPlayer.h" #include <media/PVPlayer.h> #include "TestPlayerStub.h" #include "StagefrightPlayer.h" @@ -197,8 +196,6 @@ extmap FILE_EXTS [] = { {".rtttl", SONIVOX_PLAYER}, {".rtx", SONIVOX_PLAYER}, {".ota", SONIVOX_PLAYER}, - {".ogg", VORBIS_PLAYER}, - {".oga", VORBIS_PLAYER}, #ifndef NO_OPENCORE {".wma", PV_PLAYER}, {".wmv", PV_PLAYER}, @@ -228,14 +225,10 @@ MediaPlayerService::~MediaPlayerService() sp<IMediaRecorder> MediaPlayerService::createMediaRecorder(pid_t pid) { -#ifndef NO_OPENCORE sp<MediaRecorderClient> recorder = new MediaRecorderClient(this, pid); wp<MediaRecorderClient> w = recorder; Mutex::Autolock lock(mLock); mMediaRecorderClients.add(w); -#else - sp<MediaRecorderClient> recorder = NULL; -#endif LOGV("Create new media recorder client from pid %d", pid); return recorder; } @@ -256,11 +249,12 @@ sp<IMediaMetadataRetriever> MediaPlayerService::createMetadataRetriever(pid_t pi sp<IMediaPlayer> MediaPlayerService::create( pid_t pid, const sp<IMediaPlayerClient>& client, const char* url, - const KeyedVector<String8, String8> *headers) + const KeyedVector<String8, String8> *headers, int audioSessionId) { 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); + sp<Client> c = new Client(this, pid, connId, client, audioSessionId); + LOGV("Create new client(%d) from pid %d, url=%s, connId=%d, audioSessionId=%d", + connId, pid, url, connId, audioSessionId); if (NO_ERROR != c->setDataSource(url, headers)) { c.clear(); @@ -273,12 +267,12 @@ sp<IMediaPlayer> MediaPlayerService::create( } sp<IMediaPlayer> MediaPlayerService::create(pid_t pid, const sp<IMediaPlayerClient>& client, - int fd, int64_t offset, int64_t length) + int fd, int64_t offset, int64_t length, int audioSessionId) { int32_t connId = android_atomic_inc(&mNextConnId); - sp<Client> c = new Client(this, pid, connId, client); - LOGV("Create new client(%d) from pid %d, fd=%d, offset=%lld, length=%lld", - connId, pid, fd, offset, length); + sp<Client> c = new Client(this, pid, connId, client, audioSessionId); + LOGV("Create new client(%d) from pid %d, fd=%d, offset=%lld, length=%lld, audioSessionId=%d", + connId, pid, fd, offset, length, audioSessionId); if (NO_ERROR != c->setDataSource(fd, offset, length)) { c.clear(); } else { @@ -335,6 +329,10 @@ status_t MediaPlayerService::AudioOutput::dump(int fd, const Vector<String16>& a snprintf(buffer, 255, " msec per frame(%f), latency (%d)\n", mMsecsPerFrame, mLatency); result.append(buffer); + snprintf(buffer, 255, " aux effect id(%d), send level (%f)\n", + mAuxEffectId, mSendLevel); + result.append(buffer); + ::write(fd, result.string(), result.size()); if (mTrack != 0) { mTrack->dump(fd, args); @@ -517,11 +515,17 @@ status_t MediaPlayerService::dump(int fd, const Vector<String16>& args) sp<Client> c = mClients[i].promote(); if (c != 0) c->dump(fd, args); } - for (int i = 0, n = mMediaRecorderClients.size(); i < n; ++i) { - result.append(" MediaRecorderClient\n"); - sp<MediaRecorderClient> c = mMediaRecorderClients[i].promote(); - snprintf(buffer, 255, " pid(%d)\n\n", c->mPid); - result.append(buffer); + if (mMediaRecorderClients.size() == 0) { + result.append(" No media recorder client\n\n"); + } else { + for (int i = 0, n = mMediaRecorderClients.size(); i < n; ++i) { + sp<MediaRecorderClient> c = mMediaRecorderClients[i].promote(); + snprintf(buffer, 255, " MediaRecorderClient pid(%d)\n", c->mPid); + result.append(buffer); + write(fd, result.string(), result.size()); + result = "\n"; + c->dump(fd, args); + } } result.append(" Files opened and/or mapped:\n"); @@ -613,7 +617,7 @@ void MediaPlayerService::removeClient(wp<Client> client) } MediaPlayerService::Client::Client(const sp<MediaPlayerService>& service, pid_t pid, - int32_t connId, const sp<IMediaPlayerClient>& client) + int32_t connId, const sp<IMediaPlayerClient>& client, int audioSessionId) { LOGV("Client(%d) constructor", connId); mPid = pid; @@ -622,6 +626,8 @@ MediaPlayerService::Client::Client(const sp<MediaPlayerService>& service, pid_t mClient = client; mLoop = false; mStatus = NO_INIT; + mAudioSessionId = audioSessionId; + #if CALLBACK_ANTAGONIZER LOGD("create Antagonizer"); mAntagonizer = new Antagonizer(notify, this); @@ -667,37 +673,9 @@ void MediaPlayerService::Client::disconnect() } static player_type getDefaultPlayerType() { -#if BUILD_WITH_FULL_STAGEFRIGHT - char value[PROPERTY_VALUE_MAX]; - if (property_get("media.stagefright.enable-player", value, NULL) - && (!strcmp(value, "1") || !strcasecmp(value, "true"))) { - return STAGEFRIGHT_PLAYER; - } -#endif - - 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; + return STAGEFRIGHT_PLAYER; } - player_type getPlayerType(int fd, int64_t offset, int64_t length) { char buf[20]; @@ -709,7 +687,7 @@ player_type getPlayerType(int fd, int64_t offset, int64_t length) // Ogg vorbis? if (ident == 0x5367674f) // 'OggS' - return OverrideStagefrightForVorbis(VORBIS_PLAYER); + return STAGEFRIGHT_PLAYER; #ifndef NO_OPENCORE if (ident == 0x75b22630) { @@ -745,13 +723,6 @@ 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) { @@ -759,27 +730,21 @@ player_type getPlayerType(const char* url) int start = lenURL - len; if (start > 0) { if (!strncasecmp(url + start, FILE_EXTS[i].extension, len)) { - if (FILE_EXTS[i].playertype == VORBIS_PLAYER - && !strncasecmp(url, "http://", 7) - && useStagefrightForHTTP) { - return STAGEFRIGHT_PLAYER; - } - return OverrideStagefrightForVorbis(FILE_EXTS[i].playertype); + return FILE_EXTS[i].playertype; } } } - if (!strncasecmp(url, "http://", 7)) { - if (!useStagefrightForHTTP) { + if (!strncasecmp(url, "rtsp://", 7)) { + char value[PROPERTY_VALUE_MAX]; + if (!property_get("media.stagefright.enable-rtsp", value, NULL) + || (strcmp(value, "1") && strcasecmp(value, "true"))) { + // For now, we're going to use PV for rtsp-based playback + // by default until we can clear up a few more issues. return PV_PLAYER; } } - // Use PV_PLAYER for rtsp for now - if (!strncasecmp(url, "rtsp://", 7)) { - return PV_PLAYER; - } - return getDefaultPlayerType(); } @@ -798,16 +763,10 @@ static sp<MediaPlayerBase> createPlayer(player_type playerType, void* cookie, LOGV(" create MidiFile"); p = new MidiFile(); break; - case VORBIS_PLAYER: - LOGV(" create VorbisPlayer"); - p = new VorbisPlayer(); - break; -#if BUILD_WITH_FULL_STAGEFRIGHT case STAGEFRIGHT_PLAYER: LOGV(" create StagefrightPlayer"); p = new StagefrightPlayer; break; -#endif case TEST_PLAYER: LOGV("Create Test Player stub"); p = new TestPlayerStub(); @@ -870,7 +829,7 @@ status_t MediaPlayerService::Client::setDataSource( if (p == NULL) return NO_INIT; if (!p->hardwareOutput()) { - mAudioOutput = new AudioOutput(); + mAudioOutput = new AudioOutput(mAudioSessionId); static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput); } @@ -920,7 +879,7 @@ status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64 if (p == NULL) return NO_INIT; if (!p->hardwareOutput()) { - mAudioOutput = new AudioOutput(); + mAudioOutput = new AudioOutput(mAudioSessionId); static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput); } @@ -1138,6 +1097,21 @@ status_t MediaPlayerService::Client::setVolume(float leftVolume, float rightVolu return NO_ERROR; } +status_t MediaPlayerService::Client::setAuxEffectSendLevel(float level) +{ + LOGV("[%d] setAuxEffectSendLevel(%f)", mConnId, level); + Mutex::Autolock l(mLock); + if (mAudioOutput != 0) return mAudioOutput->setAuxEffectSendLevel(level); + return NO_ERROR; +} + +status_t MediaPlayerService::Client::attachAuxEffect(int effectId) +{ + LOGV("[%d] attachAuxEffect(%d)", mConnId, effectId); + Mutex::Autolock l(mLock); + if (mAudioOutput != 0) return mAudioOutput->attachAuxEffect(effectId); + return NO_ERROR; +} void MediaPlayerService::Client::notify(void* cookie, int msg, int ext1, int ext2) { @@ -1316,111 +1290,22 @@ 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 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 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++) { - mem[i] = new MemoryBase(heap, VIZBUFFRAMES * 2 * i, VIZBUFFRAMES * 2); - } - endTime = 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(); - - // if there is no recent buffer (yet), just return empty handed - if (lastWriteTime + TOTALBUFTIMEMSEC < lastReadTime) { - //LOGI("@@@@ no audio data to look at yet: %d + %d < %d", (int)lastWriteTime, TOTALBUFTIMEMSEC, (int)lastReadTime); - return NULL; - } - - 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 - 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)); -} - -sp<IMemory> MediaPlayerService::snoop() -{ - sp<MemoryBase> mem = getVizBuffer(); - return mem; -} - #undef LOG_TAG #define LOG_TAG "AudioSink" -MediaPlayerService::AudioOutput::AudioOutput() +MediaPlayerService::AudioOutput::AudioOutput(int sessionId) : mCallback(NULL), - mCallbackCookie(NULL) { + mCallbackCookie(NULL), + mSessionId(sessionId) { + LOGV("AudioOutput(%d)", sessionId); mTrack = 0; mStreamType = AudioSystem::MUSIC; mLeftVolume = 1.0; mRightVolume = 1.0; mLatency = 0; mMsecsPerFrame = 0; - mNumFramesWritten = 0; + mAuxEffectId = 0; + mSendLevel = 0.0; setMinBufferCount(); } @@ -1503,7 +1388,7 @@ status_t MediaPlayerService::AudioOutput::open( bufferCount = mMinBufferCount; } - LOGV("open(%u, %d, %d, %d)", sampleRate, channelCount, format, bufferCount); + LOGV("open(%u, %d, %d, %d, %d)", sampleRate, channelCount, format, bufferCount,mSessionId); if (mTrack) close(); int afSampleRate; int afFrameCount; @@ -1528,14 +1413,21 @@ status_t MediaPlayerService::AudioOutput::open( frameCount, 0 /* flags */, CallbackWrapper, - this); + this, + 0, + mSessionId); } else { t = new AudioTrack( mStreamType, sampleRate, format, (channelCount == 2) ? AudioSystem::CHANNEL_OUT_STEREO : AudioSystem::CHANNEL_OUT_MONO, - frameCount); + frameCount, + 0, + NULL, + NULL, + 0, + mSessionId); } if ((t == 0) || (t->initCheck() != NO_ERROR)) { @@ -1546,10 +1438,13 @@ status_t MediaPlayerService::AudioOutput::open( LOGV("setVolume"); t->setVolume(mLeftVolume, mRightVolume); + mMsecsPerFrame = 1.e3 / (float) sampleRate; mLatency = t->latency(); mTrack = t; - return NO_ERROR; + + t->setAuxEffectSendLevel(mSendLevel); + return t->attachAuxEffect(mAuxEffectId);; } void MediaPlayerService::AudioOutput::start() @@ -1557,31 +1452,11 @@ void MediaPlayerService::AudioOutput::start() LOGV("start"); if (mTrack) { mTrack->setVolume(mLeftVolume, mRightVolume); + mTrack->setAuxEffectSendLevel(mSendLevel); mTrack->start(); - mTrack->getPosition(&mNumFramesWritten); } } -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) @@ -1590,9 +1465,7 @@ ssize_t MediaPlayerService::AudioOutput::write(const void* buffer, size_t size) //LOGV("write(%p, %u)", buffer, size); if (mTrack) { - snoopWrite(buffer, size); ssize_t ret = mTrack->write(buffer, size); - mNumFramesWritten += ret / 4; // assume 16 bit stereo return ret; } return NO_INIT; @@ -1602,7 +1475,6 @@ void MediaPlayerService::AudioOutput::stop() { LOGV("stop"); if (mTrack) mTrack->stop(); - lastWriteTime = 0; } void MediaPlayerService::AudioOutput::flush() @@ -1615,7 +1487,6 @@ void MediaPlayerService::AudioOutput::pause() { LOGV("pause"); if (mTrack) mTrack->pause(); - lastWriteTime = 0; } void MediaPlayerService::AudioOutput::close() @@ -1635,6 +1506,26 @@ void MediaPlayerService::AudioOutput::setVolume(float left, float right) } } +status_t MediaPlayerService::AudioOutput::setAuxEffectSendLevel(float level) +{ + LOGV("setAuxEffectSendLevel(%f)", level); + mSendLevel = level; + if (mTrack) { + return mTrack->setAuxEffectSendLevel(level); + } + return NO_ERROR; +} + +status_t MediaPlayerService::AudioOutput::attachAuxEffect(int effectId) +{ + LOGV("attachAuxEffect(%d)", effectId); + mAuxEffectId = effectId; + if (mTrack) { + return mTrack->attachAuxEffect(effectId); + } + return NO_ERROR; +} + // static void MediaPlayerService::AudioOutput::CallbackWrapper( int event, void *cookie, void *info) { @@ -1651,9 +1542,6 @@ void MediaPlayerService::AudioOutput::CallbackWrapper( buffer->size = actualSize; - if (actualSize > 0) { - me->snoopWrite(buffer->raw, actualSize); - } } #undef LOG_TAG diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h index 2408c62..a967ee2 100644 --- a/media/libmediaplayerservice/MediaPlayerService.h +++ b/media/libmediaplayerservice/MediaPlayerService.h @@ -65,7 +65,7 @@ class MediaPlayerService : public BnMediaPlayerService class AudioOutput : public MediaPlayerBase::AudioSink { public: - AudioOutput(); + AudioOutput(int sessionId); virtual ~AudioOutput(); virtual bool ready() const { return mTrack != NULL; } @@ -91,6 +91,8 @@ class MediaPlayerService : public BnMediaPlayerService virtual void close(); void setAudioStreamType(int streamType) { mStreamType = streamType; } void setVolume(float left, float right); + status_t setAuxEffectSendLevel(float level); + status_t attachAuxEffect(int effectId); virtual status_t dump(int fd, const Vector<String16>& args) const; static bool isOnEmulator(); @@ -108,13 +110,12 @@ class MediaPlayerService : public BnMediaPlayerService float mRightVolume; float mMsecsPerFrame; uint32_t mLatency; - + int mSessionId; + float mSendLevel; + int mAuxEffectId; static bool mIsOnEmulator; static int mMinBufferCount; // 12 for emulator; otherwise 4 - public: // visualization hack support - uint32_t mNumFramesWritten; - void snoopWrite(const void*, size_t); }; class AudioCache : public MediaPlayerBase::AudioSink @@ -185,12 +186,11 @@ public: // House keeping for media player clients virtual sp<IMediaPlayer> create( pid_t pid, const sp<IMediaPlayerClient>& client, const char* url, - const KeyedVector<String8, String8> *headers); + const KeyedVector<String8, String8> *headers, int audioSessionId); - virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, int fd, int64_t offset, int64_t length); + virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, int fd, int64_t offset, int64_t length, int audioSessionId); 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> getOMX(); virtual status_t dump(int fd, const Vector<String16>& args); @@ -224,6 +224,8 @@ private: Parcel *reply); virtual status_t suspend(); virtual status_t resume(); + virtual status_t setAuxEffectSendLevel(float level); + virtual status_t attachAuxEffect(int effectId); sp<MediaPlayerBase> createPlayer(player_type playerType); @@ -237,12 +239,15 @@ private: pid_t pid() const { return mPid; } virtual status_t dump(int fd, const Vector<String16>& args) const; + int getAudioSessionId() { return mAudioSessionId; } + private: friend class MediaPlayerService; Client( const sp<MediaPlayerService>& service, pid_t pid, int32_t connId, - const sp<IMediaPlayerClient>& client); + const sp<IMediaPlayerClient>& client, + int audioSessionId); Client(); virtual ~Client(); @@ -271,6 +276,7 @@ private: status_t mStatus; bool mLoop; int32_t mConnId; + int mAudioSessionId; // Metadata filters. media::Metadata::Filter mMetadataAllow; // protected by mLock diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp index 12de0d9..73862c3 100644 --- a/media/libmediaplayerservice/MediaRecorderClient.cpp +++ b/media/libmediaplayerservice/MediaRecorderClient.cpp @@ -294,13 +294,11 @@ MediaRecorderClient::MediaRecorderClient(const sp<MediaPlayerService>& service, LOGV("Client constructor"); mPid = pid; -#if BUILD_WITH_FULL_STAGEFRIGHT char value[PROPERTY_VALUE_MAX]; if (property_get("media.stagefright.enable-record", value, NULL) && (!strcmp(value, "1") || !strcasecmp(value, "true"))) { mRecorder = new StagefrightRecorder; } else -#endif #ifndef NO_OPENCORE { mRecorder = new PVMediaRecorder(); @@ -320,7 +318,7 @@ MediaRecorderClient::~MediaRecorderClient() release(); } -status_t MediaRecorderClient::setListener(const sp<IMediaPlayerClient>& listener) +status_t MediaRecorderClient::setListener(const sp<IMediaRecorderClient>& listener) { LOGV("setListener"); Mutex::Autolock lock(mLock); @@ -331,5 +329,12 @@ status_t MediaRecorderClient::setListener(const sp<IMediaPlayerClient>& listener return mRecorder->setListener(listener); } +status_t MediaRecorderClient::dump(int fd, const Vector<String16>& args) const { + if (mRecorder != NULL) { + return mRecorder->dump(fd, args); + } + return OK; +} + }; // namespace android diff --git a/media/libmediaplayerservice/MediaRecorderClient.h b/media/libmediaplayerservice/MediaRecorderClient.h index 805005d..1d1913d 100644 --- a/media/libmediaplayerservice/MediaRecorderClient.h +++ b/media/libmediaplayerservice/MediaRecorderClient.h @@ -28,7 +28,7 @@ class MediaPlayerService; class MediaRecorderClient : public BnMediaRecorder { public: - virtual status_t setCamera(const sp<ICamera>& camera); + virtual status_t setCamera(const sp<ICamera>& camera); virtual status_t setPreviewSurface(const sp<ISurface>& surface); virtual status_t setVideoSource(int vs); virtual status_t setAudioSource(int as); @@ -40,26 +40,27 @@ public: virtual status_t setVideoSize(int width, int height); virtual status_t setVideoFrameRate(int frames_per_second); virtual status_t setParameters(const String8& params); - virtual status_t setListener(const sp<IMediaPlayerClient>& listener); + virtual status_t setListener(const sp<IMediaRecorderClient>& listener); virtual status_t prepare(); virtual status_t getMaxAmplitude(int* max); virtual status_t start(); virtual status_t stop(); - virtual status_t reset(); + virtual status_t reset(); virtual status_t init(); virtual status_t close(); virtual status_t release(); + virtual status_t dump(int fd, const Vector<String16>& args) const; private: - friend class MediaPlayerService; // for accessing private constructor + friend class MediaPlayerService; // for accessing private constructor - MediaRecorderClient(const sp<MediaPlayerService>& service, pid_t pid); - virtual ~MediaRecorderClient(); + MediaRecorderClient(const sp<MediaPlayerService>& service, pid_t pid); + virtual ~MediaRecorderClient(); - pid_t mPid; - Mutex mLock; - MediaRecorderBase *mRecorder; - sp<MediaPlayerService> mMediaPlayerService; + pid_t mPid; + Mutex mLock; + MediaRecorderBase *mRecorder; + sp<MediaPlayerService> mMediaPlayerService; }; }; // namespace android diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp index 550b84d..ca229fa 100644 --- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp +++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp @@ -37,7 +37,6 @@ #include <media/MediaPlayerInterface.h> #include <media/PVMetadataRetriever.h> #include <private/media/VideoFrame.h> -#include "VorbisMetadataRetriever.h" #include "MidiMetadataRetriever.h" #include "MetadataRetrieverClient.h" #include "StagefrightMetadataRetriever.h" @@ -103,30 +102,17 @@ static sp<MediaMetadataRetrieverBase> createRetriever(player_type playerType) { sp<MediaMetadataRetrieverBase> p; switch (playerType) { -#if BUILD_WITH_FULL_STAGEFRIGHT case STAGEFRIGHT_PLAYER: { - char value[PROPERTY_VALUE_MAX]; - if (property_get("media.stagefright.enable-meta", value, NULL) - && (!strcmp(value, "1") || !strcasecmp(value, "true"))) { - LOGV("create StagefrightMetadataRetriever"); - p = new StagefrightMetadataRetriever; - break; - } - - // fall through + p = new StagefrightMetadataRetriever; + break; } -#endif #ifndef NO_OPENCORE case PV_PLAYER: LOGV("create pv metadata retriever"); p = new PVMetadataRetriever(); break; #endif - case VORBIS_PLAYER: - LOGV("create vorbis metadata retriever"); - p = new VorbisMetadataRetriever(); - break; case SONIVOX_PLAYER: LOGV("create midi metadata retriever"); p = new MidiMetadataRetriever(); diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp index 531fd11..f26676d 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.cpp +++ b/media/libmediaplayerservice/StagefrightRecorder.cpp @@ -20,6 +20,7 @@ #include "StagefrightRecorder.h" +#include <binder/IPCThreadState.h> #include <media/stagefright/AudioSource.h> #include <media/stagefright/AMRWriter.h> #include <media/stagefright/CameraSource.h> @@ -29,17 +30,28 @@ #include <media/stagefright/MetaData.h> #include <media/stagefright/OMXClient.h> #include <media/stagefright/OMXCodec.h> +#include <media/MediaProfiles.h> #include <camera/ICamera.h> +#include <camera/Camera.h> +#include <camera/CameraParameters.h> #include <surfaceflinger/ISurface.h> #include <utils/Errors.h> +#include <sys/types.h> +#include <unistd.h> +#include <ctype.h> namespace android { -StagefrightRecorder::StagefrightRecorder() { +StagefrightRecorder::StagefrightRecorder() + : mWriter(NULL), + mOutputFd(-1) { + + LOGV("Constructor"); reset(); } StagefrightRecorder::~StagefrightRecorder() { + LOGV("Destructor"); stop(); if (mOutputFd >= 0) { @@ -49,40 +61,103 @@ StagefrightRecorder::~StagefrightRecorder() { } status_t StagefrightRecorder::init() { + LOGV("init"); return OK; } status_t StagefrightRecorder::setAudioSource(audio_source as) { - mAudioSource = as; + LOGV("setAudioSource: %d", as); + if (as < AUDIO_SOURCE_DEFAULT || + as >= AUDIO_SOURCE_LIST_END) { + LOGE("Invalid audio source: %d", as); + return BAD_VALUE; + } + + if (as == AUDIO_SOURCE_DEFAULT) { + mAudioSource = AUDIO_SOURCE_MIC; + } else { + mAudioSource = as; + } return OK; } status_t StagefrightRecorder::setVideoSource(video_source vs) { - mVideoSource = vs; + LOGV("setVideoSource: %d", vs); + if (vs < VIDEO_SOURCE_DEFAULT || + vs >= VIDEO_SOURCE_LIST_END) { + LOGE("Invalid video source: %d", vs); + return BAD_VALUE; + } + + if (vs == VIDEO_SOURCE_DEFAULT) { + mVideoSource = VIDEO_SOURCE_CAMERA; + } else { + mVideoSource = vs; + } return OK; } status_t StagefrightRecorder::setOutputFormat(output_format of) { - mOutputFormat = of; + LOGV("setOutputFormat: %d", of); + if (of < OUTPUT_FORMAT_DEFAULT || + of >= OUTPUT_FORMAT_LIST_END) { + LOGE("Invalid output format: %d", of); + return BAD_VALUE; + } + + if (of == OUTPUT_FORMAT_DEFAULT) { + mOutputFormat = OUTPUT_FORMAT_THREE_GPP; + } else { + mOutputFormat = of; + } return OK; } status_t StagefrightRecorder::setAudioEncoder(audio_encoder ae) { - mAudioEncoder = ae; + LOGV("setAudioEncoder: %d", ae); + if (ae < AUDIO_ENCODER_DEFAULT || + ae >= AUDIO_ENCODER_LIST_END) { + LOGE("Invalid audio encoder: %d", ae); + return BAD_VALUE; + } + + if (ae == AUDIO_ENCODER_DEFAULT) { + mAudioEncoder = AUDIO_ENCODER_AMR_NB; + } else { + mAudioEncoder = ae; + } return OK; } status_t StagefrightRecorder::setVideoEncoder(video_encoder ve) { - mVideoEncoder = ve; + LOGV("setVideoEncoder: %d", ve); + if (ve < VIDEO_ENCODER_DEFAULT || + ve >= VIDEO_ENCODER_LIST_END) { + LOGE("Invalid video encoder: %d", ve); + return BAD_VALUE; + } + + if (ve == VIDEO_ENCODER_DEFAULT) { + mVideoEncoder = VIDEO_ENCODER_H263; + } else { + mVideoEncoder = ve; + } return OK; } status_t StagefrightRecorder::setVideoSize(int width, int height) { + LOGV("setVideoSize: %dx%d", width, height); + if (width <= 0 || height <= 0) { + LOGE("Invalid video size: %dx%d", width, height); + return BAD_VALUE; + } + + // Additional check on the dimension will be performed later mVideoWidth = width; mVideoHeight = height; @@ -90,35 +165,70 @@ status_t StagefrightRecorder::setVideoSize(int width, int height) { } status_t StagefrightRecorder::setVideoFrameRate(int frames_per_second) { + LOGV("setVideoFrameRate: %d", frames_per_second); + if (frames_per_second <= 0 || frames_per_second > 30) { + LOGE("Invalid video frame rate: %d", frames_per_second); + return BAD_VALUE; + } + + // Additional check on the frame rate will be performed later mFrameRate = frames_per_second; return OK; } status_t StagefrightRecorder::setCamera(const sp<ICamera> &camera) { - mCamera = camera; + LOGV("setCamera"); + if (camera == 0) { + LOGE("camera is NULL"); + return BAD_VALUE; + } + + int64_t token = IPCThreadState::self()->clearCallingIdentity(); + mFlags &= ~FLAGS_HOT_CAMERA; + mCamera = Camera::create(camera); + if (mCamera == 0) { + LOGE("Unable to connect to camera"); + IPCThreadState::self()->restoreCallingIdentity(token); + return -EBUSY; + } + + LOGV("Connected to camera"); + if (mCamera->previewEnabled()) { + LOGV("camera is hot"); + mFlags |= FLAGS_HOT_CAMERA; + } + IPCThreadState::self()->restoreCallingIdentity(token); return OK; } status_t StagefrightRecorder::setPreviewSurface(const sp<ISurface> &surface) { + LOGV("setPreviewSurface: %p", surface.get()); mPreviewSurface = surface; return OK; } status_t StagefrightRecorder::setOutputFile(const char *path) { + LOGE("setOutputFile(const char*) must not be called"); // We don't actually support this at all, as the media_server process // no longer has permissions to create files. - return UNKNOWN_ERROR; + return -EPERM; } status_t StagefrightRecorder::setOutputFile(int fd, int64_t offset, int64_t length) { + LOGV("setOutputFile: %d, %lld, %lld", fd, offset, length); // These don't make any sense, do they? CHECK_EQ(offset, 0); CHECK_EQ(length, 0); + if (fd < 0) { + LOGE("Invalid file descriptor: %d", fd); + return -EBADF; + } + if (mOutputFd >= 0) { ::close(mOutputFd); } @@ -127,13 +237,366 @@ status_t StagefrightRecorder::setOutputFile(int fd, int64_t offset, int64_t leng return OK; } -status_t StagefrightRecorder::setParameters(const String8 ¶ms) { - mParams = params; +// Attempt to parse an int64 literal optionally surrounded by whitespace, +// returns true on success, false otherwise. +static bool safe_strtoi64(const char *s, int64_t *val) { + char *end; + *val = strtoll(s, &end, 10); + + if (end == s || errno == ERANGE) { + return false; + } + + // Skip trailing whitespace + while (isspace(*end)) { + ++end; + } + + // For a successful return, the string must contain nothing but a valid + // int64 literal optionally surrounded by whitespace. + + return *end == '\0'; +} + +// Return true if the value is in [0, 0x007FFFFFFF] +static bool safe_strtoi32(const char *s, int32_t *val) { + int64_t temp; + if (safe_strtoi64(s, &temp)) { + if (temp >= 0 && temp <= 0x007FFFFFFF) { + *val = static_cast<int32_t>(temp); + return true; + } + } + return false; +} + +// Trim both leading and trailing whitespace from the given string. +static void TrimString(String8 *s) { + size_t num_bytes = s->bytes(); + const char *data = s->string(); + + size_t leading_space = 0; + while (leading_space < num_bytes && isspace(data[leading_space])) { + ++leading_space; + } + + size_t i = num_bytes; + while (i > leading_space && isspace(data[i - 1])) { + --i; + } + + s->setTo(String8(&data[leading_space], i - leading_space)); +} + +status_t StagefrightRecorder::setParamAudioSamplingRate(int32_t sampleRate) { + LOGV("setParamAudioSamplingRate: %d", sampleRate); + if (sampleRate <= 0) { + LOGE("Invalid audio sampling rate: %d", sampleRate); + return BAD_VALUE; + } + + // Additional check on the sample rate will be performed later. + mSampleRate = sampleRate; + return OK; +} + +status_t StagefrightRecorder::setParamAudioNumberOfChannels(int32_t channels) { + LOGV("setParamAudioNumberOfChannels: %d", channels); + if (channels <= 0 || channels >= 3) { + LOGE("Invalid number of audio channels: %d", channels); + return BAD_VALUE; + } + + // Additional check on the number of channels will be performed later. + mAudioChannels = channels; + return OK; +} + +status_t StagefrightRecorder::setParamAudioEncodingBitRate(int32_t bitRate) { + LOGV("setParamAudioEncodingBitRate: %d", bitRate); + if (bitRate <= 0) { + LOGE("Invalid audio encoding bit rate: %d", bitRate); + return BAD_VALUE; + } + + // The target bit rate may not be exactly the same as the requested. + // It depends on many factors, such as rate control, and the bit rate + // range that a specific encoder supports. The mismatch between the + // the target and requested bit rate will NOT be treated as an error. + mAudioBitRate = bitRate; + return OK; +} + +status_t StagefrightRecorder::setParamVideoEncodingBitRate(int32_t bitRate) { + LOGV("setParamVideoEncodingBitRate: %d", bitRate); + if (bitRate <= 0) { + LOGE("Invalid video encoding bit rate: %d", bitRate); + return BAD_VALUE; + } + + // The target bit rate may not be exactly the same as the requested. + // It depends on many factors, such as rate control, and the bit rate + // range that a specific encoder supports. The mismatch between the + // the target and requested bit rate will NOT be treated as an error. + mVideoBitRate = bitRate; + return OK; +} + +status_t StagefrightRecorder::setParamMaxFileDurationUs(int64_t timeUs) { + LOGV("setParamMaxFileDurationUs: %lld us", timeUs); + if (timeUs <= 1000000LL) { // XXX: 1 second + LOGE("Max file duration is too short: %lld us", timeUs); + return BAD_VALUE; + } + mMaxFileDurationUs = timeUs; + return OK; +} + +status_t StagefrightRecorder::setParamMaxFileSizeBytes(int64_t bytes) { + LOGV("setParamMaxFileSizeBytes: %lld bytes", bytes); + if (bytes <= 1024) { // XXX: 1 kB + LOGE("Max file size is too small: %lld bytes", bytes); + return BAD_VALUE; + } + mMaxFileSizeBytes = bytes; + return OK; +} +status_t StagefrightRecorder::setParamInterleaveDuration(int32_t durationUs) { + LOGV("setParamInterleaveDuration: %d", durationUs); + if (durationUs <= 500000) { // 500 ms + // If interleave duration is too small, it is very inefficient to do + // interleaving since the metadata overhead will count for a significant + // portion of the saved contents + LOGE("Audio/video interleave duration is too small: %d us", durationUs); + return BAD_VALUE; + } else if (durationUs >= 10000000) { // 10 seconds + // If interleaving duration is too large, it can cause the recording + // session to use too much memory since we have to save the output + // data before we write them out + LOGE("Audio/video interleave duration is too large: %d us", durationUs); + return BAD_VALUE; + } + mInterleaveDurationUs = durationUs; + return OK; +} + +// If seconds < 0, only the first frame is I frame, and rest are all P frames +// If seconds == 0, all frames are encoded as I frames. No P frames +// If seconds > 0, it is the time spacing (seconds) between 2 neighboring I frames +status_t StagefrightRecorder::setParamVideoIFramesInterval(int32_t seconds) { + LOGV("setParamVideoIFramesInterval: %d seconds", seconds); + mIFramesIntervalSec = seconds; + return OK; +} + +status_t StagefrightRecorder::setParam64BitFileOffset(bool use64Bit) { + LOGV("setParam64BitFileOffset: %s", + use64Bit? "use 64 bit file offset": "use 32 bit file offset"); + mUse64BitFileOffset = use64Bit; + return OK; +} + +status_t StagefrightRecorder::setParamVideoCameraId(int32_t cameraId) { + LOGV("setParamVideoCameraId: %d", cameraId); + if (cameraId < 0) { + return BAD_VALUE; + } + mCameraId = cameraId; + return OK; +} + +status_t StagefrightRecorder::setParamTrackTimeStatus(int64_t timeDurationUs) { + LOGV("setParamTrackTimeStatus: %lld", timeDurationUs); + if (timeDurationUs < 20000) { // Infeasible if shorter than 20 ms? + LOGE("Tracking time duration too short: %lld us", timeDurationUs); + return BAD_VALUE; + } + mTrackEveryTimeDurationUs = timeDurationUs; return OK; } -status_t StagefrightRecorder::setListener(const sp<IMediaPlayerClient> &listener) { +status_t StagefrightRecorder::setParamVideoEncoderProfile(int32_t profile) { + LOGV("setParamVideoEncoderProfile: %d", profile); + + // Additional check will be done later when we load the encoder. + // For now, we are accepting values defined in OpenMAX IL. + mVideoEncoderProfile = profile; + return OK; +} + +status_t StagefrightRecorder::setParamVideoEncoderLevel(int32_t level) { + LOGV("setParamVideoEncoderLevel: %d", level); + + // Additional check will be done later when we load the encoder. + // For now, we are accepting values defined in OpenMAX IL. + mVideoEncoderLevel = level; + return OK; +} + +status_t StagefrightRecorder::setParamMovieTimeScale(int32_t timeScale) { + LOGV("setParamMovieTimeScale: %d", timeScale); + + // The range is set to be the same as the audio's time scale range + // since audio's time scale has a wider range. + if (timeScale < 600 || timeScale > 96000) { + LOGE("Time scale (%d) for movie is out of range [600, 96000]", timeScale); + return BAD_VALUE; + } + mMovieTimeScale = timeScale; + return OK; +} + +status_t StagefrightRecorder::setParamVideoTimeScale(int32_t timeScale) { + LOGV("setParamVideoTimeScale: %d", timeScale); + + // 60000 is chosen to make sure that each video frame from a 60-fps + // video has 1000 ticks. + if (timeScale < 600 || timeScale > 60000) { + LOGE("Time scale (%d) for video is out of range [600, 60000]", timeScale); + return BAD_VALUE; + } + mVideoTimeScale = timeScale; + return OK; +} + +status_t StagefrightRecorder::setParamAudioTimeScale(int32_t timeScale) { + LOGV("setParamAudioTimeScale: %d", timeScale); + + // 96000 Hz is the highest sampling rate support in AAC. + if (timeScale < 600 || timeScale > 96000) { + LOGE("Time scale (%d) for audio is out of range [600, 96000]", timeScale); + return BAD_VALUE; + } + mAudioTimeScale = timeScale; + return OK; +} + +status_t StagefrightRecorder::setParameter( + const String8 &key, const String8 &value) { + LOGV("setParameter: key (%s) => value (%s)", key.string(), value.string()); + if (key == "max-duration") { + int64_t max_duration_ms; + if (safe_strtoi64(value.string(), &max_duration_ms)) { + return setParamMaxFileDurationUs(1000LL * max_duration_ms); + } + } else if (key == "max-filesize") { + int64_t max_filesize_bytes; + if (safe_strtoi64(value.string(), &max_filesize_bytes)) { + return setParamMaxFileSizeBytes(max_filesize_bytes); + } + } else if (key == "interleave-duration-us") { + int32_t durationUs; + if (safe_strtoi32(value.string(), &durationUs)) { + return setParamInterleaveDuration(durationUs); + } + } else if (key == "param-movie-time-scale") { + int32_t timeScale; + if (safe_strtoi32(value.string(), &timeScale)) { + return setParamMovieTimeScale(timeScale); + } + } else if (key == "param-use-64bit-offset") { + int32_t use64BitOffset; + if (safe_strtoi32(value.string(), &use64BitOffset)) { + return setParam64BitFileOffset(use64BitOffset != 0); + } + } else if (key == "param-track-time-status") { + int64_t timeDurationUs; + if (safe_strtoi64(value.string(), &timeDurationUs)) { + return setParamTrackTimeStatus(timeDurationUs); + } + } else if (key == "audio-param-sampling-rate") { + int32_t sampling_rate; + if (safe_strtoi32(value.string(), &sampling_rate)) { + return setParamAudioSamplingRate(sampling_rate); + } + } else if (key == "audio-param-number-of-channels") { + int32_t number_of_channels; + if (safe_strtoi32(value.string(), &number_of_channels)) { + return setParamAudioNumberOfChannels(number_of_channels); + } + } else if (key == "audio-param-encoding-bitrate") { + int32_t audio_bitrate; + if (safe_strtoi32(value.string(), &audio_bitrate)) { + return setParamAudioEncodingBitRate(audio_bitrate); + } + } else if (key == "audio-param-time-scale") { + int32_t timeScale; + if (safe_strtoi32(value.string(), &timeScale)) { + return setParamAudioTimeScale(timeScale); + } + } else if (key == "video-param-encoding-bitrate") { + int32_t video_bitrate; + if (safe_strtoi32(value.string(), &video_bitrate)) { + return setParamVideoEncodingBitRate(video_bitrate); + } + } else if (key == "video-param-i-frames-interval") { + int32_t seconds; + if (safe_strtoi32(value.string(), &seconds)) { + return setParamVideoIFramesInterval(seconds); + } + } else if (key == "video-param-encoder-profile") { + int32_t profile; + if (safe_strtoi32(value.string(), &profile)) { + return setParamVideoEncoderProfile(profile); + } + } else if (key == "video-param-encoder-level") { + int32_t level; + if (safe_strtoi32(value.string(), &level)) { + return setParamVideoEncoderLevel(level); + } + } else if (key == "video-param-camera-id") { + int32_t cameraId; + if (safe_strtoi32(value.string(), &cameraId)) { + return setParamVideoCameraId(cameraId); + } + } else if (key == "video-param-time-scale") { + int32_t timeScale; + if (safe_strtoi32(value.string(), &timeScale)) { + return setParamVideoTimeScale(timeScale); + } + } else { + LOGE("setParameter: failed to find key %s", key.string()); + } + return BAD_VALUE; +} + +status_t StagefrightRecorder::setParameters(const String8 ¶ms) { + LOGV("setParameters: %s", params.string()); + const char *cparams = params.string(); + const char *key_start = cparams; + for (;;) { + const char *equal_pos = strchr(key_start, '='); + if (equal_pos == NULL) { + LOGE("Parameters %s miss a value", cparams); + return BAD_VALUE; + } + String8 key(key_start, equal_pos - key_start); + TrimString(&key); + if (key.length() == 0) { + LOGE("Parameters %s contains an empty key", cparams); + return BAD_VALUE; + } + const char *value_start = equal_pos + 1; + const char *semicolon_pos = strchr(value_start, ';'); + String8 value; + if (semicolon_pos == NULL) { + value.setTo(value_start); + } else { + value.setTo(value_start, semicolon_pos - value_start); + } + if (setParameter(key, value) != OK) { + return BAD_VALUE; + } + if (semicolon_pos == NULL) { + break; // Reaches the end + } + key_start = semicolon_pos + 1; + } + return OK; +} + +status_t StagefrightRecorder::setListener(const sp<IMediaRecorderClient> &listener) { mListener = listener; return OK; @@ -144,7 +607,10 @@ status_t StagefrightRecorder::prepare() { } status_t StagefrightRecorder::start() { + CHECK(mOutputFd >= 0); + if (mWriter != NULL) { + LOGE("File writer is not avaialble"); return UNKNOWN_ERROR; } @@ -158,40 +624,58 @@ status_t StagefrightRecorder::start() { case OUTPUT_FORMAT_AMR_WB: return startAMRRecording(); + case OUTPUT_FORMAT_AAC_ADIF: + case OUTPUT_FORMAT_AAC_ADTS: + return startAACRecording(); + default: + LOGE("Unsupported output file format: %d", mOutputFormat); return UNKNOWN_ERROR; } } -sp<MediaSource> StagefrightRecorder::createAMRAudioSource() { - uint32_t sampleRate = - mAudioEncoder == AUDIO_ENCODER_AMR_NB ? 8000 : 16000; - +sp<MediaSource> StagefrightRecorder::createAudioSource() { sp<AudioSource> audioSource = new AudioSource( mAudioSource, - sampleRate, - AudioSystem::CHANNEL_IN_MONO); + mSampleRate, + mAudioChannels); status_t err = audioSource->initCheck(); if (err != OK) { + LOGE("audio source is not initialized"); return NULL; } sp<MetaData> encMeta = new MetaData; - encMeta->setCString( - kKeyMIMEType, - mAudioEncoder == AUDIO_ENCODER_AMR_NB - ? MEDIA_MIMETYPE_AUDIO_AMR_NB : MEDIA_MIMETYPE_AUDIO_AMR_WB); + const char *mime; + switch (mAudioEncoder) { + case AUDIO_ENCODER_AMR_NB: + case AUDIO_ENCODER_DEFAULT: + mime = MEDIA_MIMETYPE_AUDIO_AMR_NB; + break; + case AUDIO_ENCODER_AMR_WB: + mime = MEDIA_MIMETYPE_AUDIO_AMR_WB; + break; + case AUDIO_ENCODER_AAC: + mime = MEDIA_MIMETYPE_AUDIO_AAC; + break; + default: + LOGE("Unknown audio encoder: %d", mAudioEncoder); + return NULL; + } + encMeta->setCString(kKeyMIMEType, mime); int32_t maxInputSize; CHECK(audioSource->getFormat()->findInt32( kKeyMaxInputSize, &maxInputSize)); encMeta->setInt32(kKeyMaxInputSize, maxInputSize); - encMeta->setInt32(kKeyChannelCount, 1); - encMeta->setInt32(kKeySampleRate, sampleRate); + encMeta->setInt32(kKeyChannelCount, mAudioChannels); + encMeta->setInt32(kKeySampleRate, mSampleRate); + encMeta->setInt32(kKeyBitRate, mAudioBitRate); + encMeta->setInt32(kKeyTimeScale, mAudioTimeScale); OMXClient client; CHECK_EQ(client.connect(), OK); @@ -199,144 +683,481 @@ sp<MediaSource> StagefrightRecorder::createAMRAudioSource() { sp<MediaSource> audioEncoder = OMXCodec::Create(client.interface(), encMeta, true /* createEncoder */, audioSource); + mAudioSourceNode = audioSource; return audioEncoder; } +status_t StagefrightRecorder::startAACRecording() { + CHECK(mOutputFormat == OUTPUT_FORMAT_AAC_ADIF || + mOutputFormat == OUTPUT_FORMAT_AAC_ADTS); + + CHECK(mAudioEncoder == AUDIO_ENCODER_AAC); + CHECK(mAudioSource != AUDIO_SOURCE_LIST_END); + + CHECK(0 == "AACWriter is not implemented yet"); + + return OK; +} + status_t StagefrightRecorder::startAMRRecording() { - if (mAudioSource == AUDIO_SOURCE_LIST_END - || mVideoSource != VIDEO_SOURCE_LIST_END) { - return UNKNOWN_ERROR; + CHECK(mOutputFormat == OUTPUT_FORMAT_AMR_NB || + mOutputFormat == OUTPUT_FORMAT_AMR_WB); + + if (mOutputFormat == OUTPUT_FORMAT_AMR_NB) { + if (mAudioEncoder != AUDIO_ENCODER_DEFAULT && + mAudioEncoder != AUDIO_ENCODER_AMR_NB) { + LOGE("Invalid encoder %d used for AMRNB recording", + mAudioEncoder); + return BAD_VALUE; + } + if (mSampleRate != 8000) { + LOGE("Invalid sampling rate %d used for AMRNB recording", + mSampleRate); + return BAD_VALUE; + } + } else { // mOutputFormat must be OUTPUT_FORMAT_AMR_WB + if (mAudioEncoder != AUDIO_ENCODER_AMR_WB) { + LOGE("Invlaid encoder %d used for AMRWB recording", + mAudioEncoder); + return BAD_VALUE; + } + if (mSampleRate != 16000) { + LOGE("Invalid sample rate %d used for AMRWB recording", + mSampleRate); + return BAD_VALUE; + } + } + if (mAudioChannels != 1) { + LOGE("Invalid number of audio channels %d used for amr recording", + mAudioChannels); + return BAD_VALUE; } - if (mOutputFormat == OUTPUT_FORMAT_AMR_NB - && mAudioEncoder != AUDIO_ENCODER_DEFAULT - && mAudioEncoder != AUDIO_ENCODER_AMR_NB) { - return UNKNOWN_ERROR; - } else if (mOutputFormat == OUTPUT_FORMAT_AMR_WB - && mAudioEncoder != AUDIO_ENCODER_AMR_WB) { - return UNKNOWN_ERROR; + if (mAudioSource >= AUDIO_SOURCE_LIST_END) { + LOGE("Invalid audio source: %d", mAudioSource); + return BAD_VALUE; } - sp<MediaSource> audioEncoder = createAMRAudioSource(); + sp<MediaSource> audioEncoder = createAudioSource(); if (audioEncoder == NULL) { return UNKNOWN_ERROR; } - CHECK(mOutputFd >= 0); mWriter = new AMRWriter(dup(mOutputFd)); mWriter->addSource(audioEncoder); + + if (mMaxFileDurationUs != 0) { + mWriter->setMaxFileDuration(mMaxFileDurationUs); + } + if (mMaxFileSizeBytes != 0) { + mWriter->setMaxFileSize(mMaxFileSizeBytes); + } + mWriter->setListener(mListener); mWriter->start(); return OK; } -status_t StagefrightRecorder::startMPEG4Recording() { - mWriter = new MPEG4Writer(dup(mOutputFd)); +void StagefrightRecorder::clipVideoFrameRate() { + LOGV("clipVideoFrameRate: encoder %d", mVideoEncoder); + int minFrameRate = mEncoderProfiles->getVideoEncoderParamByName( + "enc.vid.fps.min", mVideoEncoder); + int maxFrameRate = mEncoderProfiles->getVideoEncoderParamByName( + "enc.vid.fps.max", mVideoEncoder); + if (mFrameRate < minFrameRate) { + LOGW("Intended video encoding frame rate (%d fps) is too small" + " and will be set to (%d fps)", mFrameRate, minFrameRate); + mFrameRate = minFrameRate; + } else if (mFrameRate > maxFrameRate) { + LOGW("Intended video encoding frame rate (%d fps) is too large" + " and will be set to (%d fps)", mFrameRate, maxFrameRate); + mFrameRate = maxFrameRate; + } +} - if (mVideoSource == VIDEO_SOURCE_DEFAULT - || mVideoSource == VIDEO_SOURCE_CAMERA) { - CHECK(mCamera != NULL); +void StagefrightRecorder::clipVideoBitRate() { + LOGV("clipVideoBitRate: encoder %d", mVideoEncoder); + int minBitRate = mEncoderProfiles->getVideoEncoderParamByName( + "enc.vid.bps.min", mVideoEncoder); + int maxBitRate = mEncoderProfiles->getVideoEncoderParamByName( + "enc.vid.bps.max", mVideoEncoder); + if (mVideoBitRate < minBitRate) { + LOGW("Intended video encoding bit rate (%d bps) is too small" + " and will be set to (%d bps)", mVideoBitRate, minBitRate); + mVideoBitRate = minBitRate; + } else if (mVideoBitRate > maxBitRate) { + LOGW("Intended video encoding bit rate (%d bps) is too large" + " and will be set to (%d bps)", mVideoBitRate, maxBitRate); + mVideoBitRate = maxBitRate; + } +} - sp<CameraSource> cameraSource = - CameraSource::CreateFromICamera(mCamera); +void StagefrightRecorder::clipVideoFrameWidth() { + LOGV("clipVideoFrameWidth: encoder %d", mVideoEncoder); + int minFrameWidth = mEncoderProfiles->getVideoEncoderParamByName( + "enc.vid.width.min", mVideoEncoder); + int maxFrameWidth = mEncoderProfiles->getVideoEncoderParamByName( + "enc.vid.width.max", mVideoEncoder); + if (mVideoWidth < minFrameWidth) { + LOGW("Intended video encoding frame width (%d) is too small" + " and will be set to (%d)", mVideoWidth, minFrameWidth); + mVideoWidth = minFrameWidth; + } else if (mVideoWidth > maxFrameWidth) { + LOGW("Intended video encoding frame width (%d) is too large" + " and will be set to (%d)", mVideoWidth, maxFrameWidth); + mVideoWidth = maxFrameWidth; + } +} - CHECK(cameraSource != NULL); +status_t StagefrightRecorder::setupCameraSource() { + clipVideoBitRate(); + clipVideoFrameRate(); + clipVideoFrameWidth(); + clipVideoFrameHeight(); + + int64_t token = IPCThreadState::self()->clearCallingIdentity(); + if (mCamera == 0) { + mCamera = Camera::connect(mCameraId); + if (mCamera == 0) { + LOGE("Camera connection could not be established."); + return -EBUSY; + } + mFlags &= ~FLAGS_HOT_CAMERA; + mCamera->lock(); + } - cameraSource->setPreviewSurface(mPreviewSurface); + // Set the actual video recording frame size + CameraParameters params(mCamera->getParameters()); + params.setPreviewSize(mVideoWidth, mVideoHeight); + params.setPreviewFrameRate(mFrameRate); + String8 s = params.flatten(); + CHECK_EQ(OK, mCamera->setParameters(s)); + CameraParameters newCameraParams(mCamera->getParameters()); + + // Check on video frame size + int frameWidth = 0, frameHeight = 0; + newCameraParams.getPreviewSize(&frameWidth, &frameHeight); + if (frameWidth < 0 || frameWidth != mVideoWidth || + frameHeight < 0 || frameHeight != mVideoHeight) { + LOGE("Failed to set the video frame size to %dx%d", + mVideoWidth, mVideoHeight); + IPCThreadState::self()->restoreCallingIdentity(token); + return UNKNOWN_ERROR; + } - sp<MetaData> enc_meta = new MetaData; - switch (mVideoEncoder) { - case VIDEO_ENCODER_H263: - enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263); - break; + // Check on video frame rate + int frameRate = newCameraParams.getPreviewFrameRate(); + if (frameRate < 0 || (frameRate - mFrameRate) != 0) { + LOGE("Failed to set frame rate to %d fps. The actual " + "frame rate is %d", mFrameRate, frameRate); + } - case VIDEO_ENCODER_MPEG_4_SP: - enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4); - break; + CHECK_EQ(OK, mCamera->setPreviewDisplay(mPreviewSurface)); + IPCThreadState::self()->restoreCallingIdentity(token); + return OK; +} - case VIDEO_ENCODER_H264: - enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC); - break; +void StagefrightRecorder::clipVideoFrameHeight() { + LOGV("clipVideoFrameHeight: encoder %d", mVideoEncoder); + int minFrameHeight = mEncoderProfiles->getVideoEncoderParamByName( + "enc.vid.height.min", mVideoEncoder); + int maxFrameHeight = mEncoderProfiles->getVideoEncoderParamByName( + "enc.vid.height.max", mVideoEncoder); + if (mVideoHeight < minFrameHeight) { + LOGW("Intended video encoding frame height (%d) is too small" + " and will be set to (%d)", mVideoHeight, minFrameHeight); + mVideoHeight = minFrameHeight; + } else if (mVideoHeight > maxFrameHeight) { + LOGW("Intended video encoding frame height (%d) is too large" + " and will be set to (%d)", mVideoHeight, maxFrameHeight); + mVideoHeight = maxFrameHeight; + } +} - default: - CHECK(!"Should not be here, unsupported video encoding."); - break; - } +status_t StagefrightRecorder::setupVideoEncoder(const sp<MediaWriter>& writer) { + status_t err = setupCameraSource(); + if (err != OK) return err; - sp<MetaData> meta = cameraSource->getFormat(); + sp<CameraSource> cameraSource = CameraSource::CreateFromCamera(mCamera); + CHECK(cameraSource != NULL); - int32_t width, height; - CHECK(meta->findInt32(kKeyWidth, &width)); - CHECK(meta->findInt32(kKeyHeight, &height)); + sp<MetaData> enc_meta = new MetaData; + enc_meta->setInt32(kKeyBitRate, mVideoBitRate); + enc_meta->setInt32(kKeySampleRate, mFrameRate); - enc_meta->setInt32(kKeyWidth, width); - enc_meta->setInt32(kKeyHeight, height); + switch (mVideoEncoder) { + case VIDEO_ENCODER_H263: + enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263); + break; - OMXClient client; - CHECK_EQ(client.connect(), OK); + case VIDEO_ENCODER_MPEG_4_SP: + enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4); + break; - sp<MediaSource> encoder = - OMXCodec::Create( - client.interface(), enc_meta, - true /* createEncoder */, cameraSource); + case VIDEO_ENCODER_H264: + enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC); + break; - CHECK(mOutputFd >= 0); - mWriter->addSource(encoder); + default: + CHECK(!"Should not be here, unsupported video encoding."); + break; } - if (mAudioSource != AUDIO_SOURCE_LIST_END) { - sp<MediaSource> audioEncoder = createAMRAudioSource(); + sp<MetaData> meta = cameraSource->getFormat(); + + int32_t width, height, stride, sliceHeight, colorFormat; + CHECK(meta->findInt32(kKeyWidth, &width)); + CHECK(meta->findInt32(kKeyHeight, &height)); + CHECK(meta->findInt32(kKeyStride, &stride)); + CHECK(meta->findInt32(kKeySliceHeight, &sliceHeight)); + CHECK(meta->findInt32(kKeyColorFormat, &colorFormat)); + + enc_meta->setInt32(kKeyWidth, width); + enc_meta->setInt32(kKeyHeight, height); + enc_meta->setInt32(kKeyIFramesInterval, mIFramesIntervalSec); + enc_meta->setInt32(kKeyStride, stride); + enc_meta->setInt32(kKeySliceHeight, sliceHeight); + enc_meta->setInt32(kKeyColorFormat, colorFormat); + enc_meta->setInt32(kKeyTimeScale, mVideoTimeScale); + if (mVideoEncoderProfile != -1) { + enc_meta->setInt32(kKeyVideoProfile, mVideoEncoderProfile); + } + if (mVideoEncoderLevel != -1) { + enc_meta->setInt32(kKeyVideoLevel, mVideoEncoderLevel); + } - if (audioEncoder == NULL) { + OMXClient client; + CHECK_EQ(client.connect(), OK); + + sp<MediaSource> encoder = OMXCodec::Create( + client.interface(), enc_meta, + true /* createEncoder */, cameraSource); + if (encoder == NULL) { + return UNKNOWN_ERROR; + } + + writer->addSource(encoder); + return OK; +} + +status_t StagefrightRecorder::setupAudioEncoder(const sp<MediaWriter>& writer) { + sp<MediaSource> audioEncoder; + switch(mAudioEncoder) { + case AUDIO_ENCODER_AMR_NB: + case AUDIO_ENCODER_AMR_WB: + case AUDIO_ENCODER_AAC: + audioEncoder = createAudioSource(); + break; + default: + LOGE("Unsupported audio encoder: %d", mAudioEncoder); return UNKNOWN_ERROR; - } + } - mWriter->addSource(audioEncoder); + if (audioEncoder == NULL) { + return UNKNOWN_ERROR; } - mWriter->start(); + writer->addSource(audioEncoder); return OK; } -status_t StagefrightRecorder::stop() { +status_t StagefrightRecorder::startMPEG4Recording() { + int32_t totalBitRate = 0; + status_t err = OK; + sp<MediaWriter> writer = new MPEG4Writer(dup(mOutputFd)); + + // Add audio source first if it exists + if (mAudioSource != AUDIO_SOURCE_LIST_END) { + err = setupAudioEncoder(writer); + if (err != OK) return err; + totalBitRate += mAudioBitRate; + } + if (mVideoSource == VIDEO_SOURCE_DEFAULT + || mVideoSource == VIDEO_SOURCE_CAMERA) { + err = setupVideoEncoder(writer); + if (err != OK) return err; + totalBitRate += mVideoBitRate; + } + + if (mInterleaveDurationUs > 0) { + reinterpret_cast<MPEG4Writer *>(writer.get())-> + setInterleaveDuration(mInterleaveDurationUs); + } + + if (mMaxFileDurationUs != 0) { + writer->setMaxFileDuration(mMaxFileDurationUs); + } + if (mMaxFileSizeBytes != 0) { + writer->setMaxFileSize(mMaxFileSizeBytes); + } + sp<MetaData> meta = new MetaData; + meta->setInt64(kKeyTime, systemTime() / 1000); + meta->setInt32(kKeyFileType, mOutputFormat); + meta->setInt32(kKeyBitRate, totalBitRate); + meta->setInt32(kKey64BitFileOffset, mUse64BitFileOffset); + meta->setInt32(kKeyTimeScale, mMovieTimeScale); + if (mTrackEveryTimeDurationUs > 0) { + meta->setInt64(kKeyTrackTimeStatus, mTrackEveryTimeDurationUs); + } + writer->setListener(mListener); + mWriter = writer; + return mWriter->start(meta.get()); +} + +status_t StagefrightRecorder::pause() { + LOGV("pause"); if (mWriter == NULL) { return UNKNOWN_ERROR; } + mWriter->pause(); + return OK; +} - mWriter->stop(); - mWriter = NULL; +status_t StagefrightRecorder::stop() { + LOGV("stop"); + if (mWriter != NULL) { + mWriter->stop(); + mWriter.clear(); + } + + if (mCamera != 0) { + LOGV("Disconnect camera"); + int64_t token = IPCThreadState::self()->clearCallingIdentity(); + if ((mFlags & FLAGS_HOT_CAMERA) == 0) { + LOGV("Camera was cold when we started, stopping preview"); + mCamera->stopPreview(); + } + mCamera->unlock(); + mCamera.clear(); + IPCThreadState::self()->restoreCallingIdentity(token); + mFlags = 0; + } return OK; } status_t StagefrightRecorder::close() { + LOGV("close"); stop(); return OK; } status_t StagefrightRecorder::reset() { + LOGV("reset"); stop(); + // No audio or video source by default mAudioSource = AUDIO_SOURCE_LIST_END; mVideoSource = VIDEO_SOURCE_LIST_END; - mOutputFormat = OUTPUT_FORMAT_LIST_END; - mAudioEncoder = AUDIO_ENCODER_LIST_END; - mVideoEncoder = VIDEO_ENCODER_LIST_END; - mVideoWidth = -1; - mVideoHeight = -1; - mFrameRate = -1; + + // Default parameters + mOutputFormat = OUTPUT_FORMAT_THREE_GPP; + mAudioEncoder = AUDIO_ENCODER_AMR_NB; + mVideoEncoder = VIDEO_ENCODER_H263; + mVideoWidth = 176; + mVideoHeight = 144; + mFrameRate = 20; + mVideoBitRate = 192000; + mSampleRate = 8000; + mAudioChannels = 1; + mAudioBitRate = 12200; + mInterleaveDurationUs = 0; + mIFramesIntervalSec = 1; + mAudioSourceNode = 0; + mUse64BitFileOffset = false; + mMovieTimeScale = 1000; + mAudioTimeScale = 1000; + mVideoTimeScale = 1000; + mCameraId = 0; + mVideoEncoderProfile = -1; + mVideoEncoderLevel = -1; + mMaxFileDurationUs = 0; + mMaxFileSizeBytes = 0; + mTrackEveryTimeDurationUs = 0; + mEncoderProfiles = MediaProfiles::getInstance(); + mOutputFd = -1; + mFlags = 0; return OK; } status_t StagefrightRecorder::getMaxAmplitude(int *max) { - *max = 0; + LOGV("getMaxAmplitude"); + + if (max == NULL) { + LOGE("Null pointer argument"); + return BAD_VALUE; + } + + if (mAudioSourceNode != 0) { + *max = mAudioSourceNode->getMaxAmplitude(); + } else { + *max = 0; + } return OK; } +status_t StagefrightRecorder::dump(int fd, const Vector<String16>& args) const { + const size_t SIZE = 256; + char buffer[SIZE]; + String8 result; + snprintf(buffer, SIZE, " Recorder: %p", this); + snprintf(buffer, SIZE, " Output file (fd %d):\n", mOutputFd); + result.append(buffer); + snprintf(buffer, SIZE, " File format: %d\n", mOutputFormat); + result.append(buffer); + snprintf(buffer, SIZE, " Max file size (bytes): %lld\n", mMaxFileSizeBytes); + result.append(buffer); + snprintf(buffer, SIZE, " Max file duration (us): %lld\n", mMaxFileDurationUs); + result.append(buffer); + snprintf(buffer, SIZE, " File offset length (bits): %d\n", mUse64BitFileOffset? 64: 32); + result.append(buffer); + snprintf(buffer, SIZE, " Interleave duration (us): %d\n", mInterleaveDurationUs); + result.append(buffer); + snprintf(buffer, SIZE, " Progress notification: %lld us\n", mTrackEveryTimeDurationUs); + result.append(buffer); + snprintf(buffer, SIZE, " Audio\n"); + result.append(buffer); + snprintf(buffer, SIZE, " Source: %d\n", mAudioSource); + result.append(buffer); + snprintf(buffer, SIZE, " Encoder: %d\n", mAudioEncoder); + result.append(buffer); + snprintf(buffer, SIZE, " Bit rate (bps): %d\n", mAudioBitRate); + result.append(buffer); + snprintf(buffer, SIZE, " Sampling rate (hz): %d\n", mSampleRate); + result.append(buffer); + snprintf(buffer, SIZE, " Number of channels: %d\n", mAudioChannels); + result.append(buffer); + snprintf(buffer, SIZE, " Max amplitude: %d\n", mAudioSourceNode == 0? 0: mAudioSourceNode->getMaxAmplitude()); + result.append(buffer); + snprintf(buffer, SIZE, " Video\n"); + result.append(buffer); + snprintf(buffer, SIZE, " Source: %d\n", mVideoSource); + result.append(buffer); + snprintf(buffer, SIZE, " Camera Id: %d\n", mCameraId); + result.append(buffer); + snprintf(buffer, SIZE, " Camera flags: %d\n", mFlags); + result.append(buffer); + snprintf(buffer, SIZE, " Encoder: %d\n", mVideoEncoder); + result.append(buffer); + snprintf(buffer, SIZE, " Encoder profile: %d\n", mVideoEncoderProfile); + result.append(buffer); + snprintf(buffer, SIZE, " Encoder level: %d\n", mVideoEncoderLevel); + result.append(buffer); + snprintf(buffer, SIZE, " I frames interval (s): %d\n", mIFramesIntervalSec); + result.append(buffer); + snprintf(buffer, SIZE, " Frame size (pixels): %dx%d\n", mVideoWidth, mVideoHeight); + result.append(buffer); + snprintf(buffer, SIZE, " Frame rate (fps): %d\n", mFrameRate); + result.append(buffer); + snprintf(buffer, SIZE, " Bit rate (bps): %d\n", mVideoBitRate); + result.append(buffer); + ::write(fd, result.string(), result.size()); + return OK; +} } // namespace android diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h index 7ec412d..b4c5900 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.h +++ b/media/libmediaplayerservice/StagefrightRecorder.h @@ -23,8 +23,11 @@ namespace android { +class Camera; struct MediaSource; struct MediaWriter; +struct AudioSource; +class MediaProfiles; struct StagefrightRecorder : public MediaRecorderBase { StagefrightRecorder(); @@ -43,33 +46,88 @@ struct StagefrightRecorder : public MediaRecorderBase { virtual status_t setOutputFile(const char *path); virtual status_t setOutputFile(int fd, int64_t offset, int64_t length); virtual status_t setParameters(const String8& params); - virtual status_t setListener(const sp<IMediaPlayerClient>& listener); + virtual status_t setListener(const sp<IMediaRecorderClient>& listener); virtual status_t prepare(); virtual status_t start(); + virtual status_t pause(); virtual status_t stop(); virtual status_t close(); virtual status_t reset(); virtual status_t getMaxAmplitude(int *max); + virtual status_t dump(int fd, const Vector<String16>& args) const; private: - sp<ICamera> mCamera; + enum CameraFlags { + FLAGS_SET_CAMERA = 1L << 0, + FLAGS_HOT_CAMERA = 1L << 1, + }; + + sp<Camera> mCamera; sp<ISurface> mPreviewSurface; - sp<IMediaPlayerClient> mListener; + sp<IMediaRecorderClient> mListener; sp<MediaWriter> mWriter; + sp<AudioSource> mAudioSourceNode; audio_source mAudioSource; video_source mVideoSource; output_format mOutputFormat; audio_encoder mAudioEncoder; video_encoder mVideoEncoder; - int mVideoWidth, mVideoHeight; - int mFrameRate; + bool mUse64BitFileOffset; + int32_t mVideoWidth, mVideoHeight; + int32_t mFrameRate; + int32_t mVideoBitRate; + int32_t mAudioBitRate; + int32_t mAudioChannels; + int32_t mSampleRate; + int32_t mInterleaveDurationUs; + int32_t mIFramesIntervalSec; + int32_t mCameraId; + int32_t mVideoEncoderProfile; + int32_t mVideoEncoderLevel; + int32_t mMovieTimeScale; + int32_t mVideoTimeScale; + int32_t mAudioTimeScale; + int64_t mMaxFileSizeBytes; + int64_t mMaxFileDurationUs; + int64_t mTrackEveryTimeDurationUs; + String8 mParams; int mOutputFd; + int32_t mFlags; + + MediaProfiles *mEncoderProfiles; status_t startMPEG4Recording(); status_t startAMRRecording(); - sp<MediaSource> createAMRAudioSource(); + status_t startAACRecording(); + sp<MediaSource> createAudioSource(); + status_t setupCameraSource(); + status_t setupAudioEncoder(const sp<MediaWriter>& writer); + status_t setupVideoEncoder(const sp<MediaWriter>& writer); + + // Encoding parameter handling utilities + status_t setParameter(const String8 &key, const String8 &value); + status_t setParamAudioEncodingBitRate(int32_t bitRate); + status_t setParamAudioNumberOfChannels(int32_t channles); + status_t setParamAudioSamplingRate(int32_t sampleRate); + status_t setParamAudioTimeScale(int32_t timeScale); + status_t setParamVideoEncodingBitRate(int32_t bitRate); + status_t setParamVideoIFramesInterval(int32_t seconds); + status_t setParamVideoEncoderProfile(int32_t profile); + status_t setParamVideoEncoderLevel(int32_t level); + status_t setParamVideoCameraId(int32_t cameraId); + status_t setParamVideoTimeScale(int32_t timeScale); + status_t setParamTrackTimeStatus(int64_t timeDurationUs); + status_t setParamInterleaveDuration(int32_t durationUs); + status_t setParam64BitFileOffset(bool use64BitFileOffset); + status_t setParamMaxFileDurationUs(int64_t timeUs); + status_t setParamMaxFileSizeBytes(int64_t bytes); + status_t setParamMovieTimeScale(int32_t timeScale); + void clipVideoBitRate(); + void clipVideoFrameRate(); + void clipVideoFrameWidth(); + void clipVideoFrameHeight(); StagefrightRecorder(const StagefrightRecorder &); StagefrightRecorder &operator=(const StagefrightRecorder &); diff --git a/media/libmediaplayerservice/VorbisMetadataRetriever.cpp b/media/libmediaplayerservice/VorbisMetadataRetriever.cpp deleted file mode 100644 index eac74fc..0000000 --- a/media/libmediaplayerservice/VorbisMetadataRetriever.cpp +++ /dev/null @@ -1,87 +0,0 @@ -/* -** -** Copyright 2009, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -//#define LOG_NDEBUG 0 -#define LOG_TAG "VorbisMetadataRetriever" -#include <utils/Log.h> - -#include "VorbisMetadataRetriever.h" -#include <media/mediametadataretriever.h> -# - -namespace android { - -void VorbisMetadataRetriever::clearMetadataValues() -{ - LOGV("cleearMetadataValues"); - mMetadataValues[0][0] = '\0'; -} - -status_t VorbisMetadataRetriever::setDataSource(const char *url) -{ - LOGV("setDataSource: url(%s)", url? url: "NULL pointer"); - Mutex::Autolock lock(mLock); - clearMetadataValues(); - if (mVorbisPlayer == 0) { - mVorbisPlayer = new VorbisPlayer(); - } - // TODO: support headers in MetadataRetriever interface! - return mVorbisPlayer->setDataSource(url, NULL /* headers */); -} - -status_t VorbisMetadataRetriever::setDataSource(int fd, int64_t offset, int64_t length) -{ - LOGV("setDataSource: fd(%d), offset(%lld), and length(%lld)", fd, offset, length); - Mutex::Autolock lock(mLock); - clearMetadataValues(); - if (mVorbisPlayer == 0) { - mVorbisPlayer = new VorbisPlayer(); - } - return mVorbisPlayer->setDataSource(fd, offset, length); -} - -const char* VorbisMetadataRetriever::extractMetadata(int keyCode) -{ - LOGV("extractMetadata: key(%d)", keyCode); - Mutex::Autolock lock(mLock); - if (mVorbisPlayer == 0 || mVorbisPlayer->initCheck() != NO_ERROR) { - LOGE("no vorbis player is initialized yet"); - return NULL; - } - switch (keyCode) { - case METADATA_KEY_DURATION: - { - if (mMetadataValues[0][0] == '\0') { - int duration = -1; - if (mVorbisPlayer->getDuration(&duration) != NO_ERROR) { - LOGE("failed to get duration"); - return NULL; - } - snprintf(mMetadataValues[0], MAX_METADATA_STRING_LENGTH, "%d", duration); - } - LOGV("duration: %s ms", mMetadataValues[0]); - return mMetadataValues[0]; - } - default: - LOGE("Unsupported key code (%d)", keyCode); - return NULL; - } - return NULL; -} - -}; - diff --git a/media/libmediaplayerservice/VorbisMetadataRetriever.h b/media/libmediaplayerservice/VorbisMetadataRetriever.h deleted file mode 100644 index 1c57fe3..0000000 --- a/media/libmediaplayerservice/VorbisMetadataRetriever.h +++ /dev/null @@ -1,49 +0,0 @@ -/* -** -** Copyright 2009, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -#ifndef ANDROID_VORBISMETADATARETRIEVER_H -#define ANDROID_VORBISMETADATARETRIEVER_H - -#include <utils/threads.h> -#include <utils/Errors.h> -#include <media/MediaMetadataRetrieverInterface.h> - -#include "VorbisPlayer.h" - -namespace android { - -class VorbisMetadataRetriever : public MediaMetadataRetrieverInterface { -public: - VorbisMetadataRetriever() {} - ~VorbisMetadataRetriever() {} - - virtual status_t setDataSource(const char *url); - virtual status_t setDataSource(int fd, int64_t offset, int64_t length); - virtual const char* extractMetadata(int keyCode); - -private: - static const uint32_t MAX_METADATA_STRING_LENGTH = 128; - void clearMetadataValues(); - - Mutex mLock; - sp<VorbisPlayer> mVorbisPlayer; - char mMetadataValues[1][MAX_METADATA_STRING_LENGTH]; -}; - -}; // namespace android - -#endif // ANDROID_VORBISMETADATARETRIEVER_H diff --git a/media/libmediaplayerservice/VorbisPlayer.cpp b/media/libmediaplayerservice/VorbisPlayer.cpp deleted file mode 100644 index 8181999..0000000 --- a/media/libmediaplayerservice/VorbisPlayer.cpp +++ /dev/null @@ -1,529 +0,0 @@ -/* -** Copyright 2007, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -//#define LOG_NDEBUG 0 -#define LOG_TAG "VorbisPlayer" -#include "utils/Log.h" - -#include <stdio.h> -#include <assert.h> -#include <limits.h> -#include <unistd.h> -#include <fcntl.h> -#include <sched.h> -#include <sys/types.h> -#include <sys/stat.h> - - -#include "VorbisPlayer.h" - -#ifdef HAVE_GETTID -static pid_t myTid() { return gettid(); } -#else -static pid_t myTid() { return getpid(); } -#endif - -// ---------------------------------------------------------------------------- - -namespace android { - -// ---------------------------------------------------------------------------- - -// TODO: Determine appropriate return codes -static status_t ERROR_NOT_OPEN = -1; -static status_t ERROR_OPEN_FAILED = -2; -static status_t ERROR_ALLOCATE_FAILED = -4; -static status_t ERROR_NOT_SUPPORTED = -8; -static status_t ERROR_NOT_READY = -16; -static status_t STATE_INIT = 0; -static status_t STATE_ERROR = 1; -static status_t STATE_OPEN = 2; - - -VorbisPlayer::VorbisPlayer() : - mAudioBuffer(NULL), mPlayTime(-1), mDuration(-1), mState(STATE_ERROR), - mStreamType(AudioSystem::MUSIC), mLoop(false), mAndroidLoop(false), - mExit(false), mPaused(false), mRender(false), mRenderTid(-1) -{ - LOGV("constructor\n"); - memset(&mVorbisFile, 0, sizeof mVorbisFile); -} - -void VorbisPlayer::onFirstRef() -{ - LOGV("onFirstRef"); - // create playback thread - Mutex::Autolock l(mMutex); - createThreadEtc(renderThread, this, "vorbis decoder", ANDROID_PRIORITY_AUDIO); - mCondition.wait(mMutex); - if (mRenderTid > 0) { - LOGV("render thread(%d) started", mRenderTid); - mState = STATE_INIT; - } -} - -status_t VorbisPlayer::initCheck() -{ - if (mState != STATE_ERROR) return NO_ERROR; - return ERROR_NOT_READY; -} - -VorbisPlayer::~VorbisPlayer() { - LOGV("VorbisPlayer destructor\n"); - release(); -} - -status_t VorbisPlayer::setDataSource( - const char *uri, const KeyedVector<String8, String8> *headers) { - return setdatasource(uri, -1, 0, 0x7ffffffffffffffLL); // intentionally less than LONG_MAX -} - -status_t VorbisPlayer::setDataSource(int fd, int64_t offset, int64_t length) -{ - return setdatasource(NULL, fd, offset, length); -} - -size_t VorbisPlayer::vp_fread(void *buf, size_t size, size_t nmemb, void *me) { - VorbisPlayer *self = (VorbisPlayer*) me; - - long curpos = vp_ftell(me); - while (nmemb != 0 && (curpos + size * nmemb) > self->mLength) { - nmemb--; - } - return fread(buf, size, nmemb, self->mFile); -} - -int VorbisPlayer::vp_fseek(void *me, ogg_int64_t off, int whence) { - VorbisPlayer *self = (VorbisPlayer*) me; - if (whence == SEEK_SET) - return fseek(self->mFile, off + self->mOffset, whence); - else if (whence == SEEK_CUR) - return fseek(self->mFile, off, whence); - else if (whence == SEEK_END) - return fseek(self->mFile, self->mOffset + self->mLength + off, SEEK_SET); - return -1; -} - -int VorbisPlayer::vp_fclose(void *me) { - LOGV("vp_fclose"); - VorbisPlayer *self = (VorbisPlayer*) me; - int ret = fclose (self->mFile); - self->mFile = NULL; - return ret; -} - -long VorbisPlayer::vp_ftell(void *me) { - VorbisPlayer *self = (VorbisPlayer*) me; - return ftell(self->mFile) - self->mOffset; -} - -status_t VorbisPlayer::setdatasource(const char *path, int fd, int64_t offset, int64_t length) -{ - LOGV("setDataSource url=%s, fd=%d\n", path, fd); - - // file still open? - Mutex::Autolock l(mMutex); - if (mState == STATE_OPEN) { - reset_nosync(); - } - - // open file and set paused state - if (path) { - mFile = fopen(path, "r"); - } else { - mFile = fdopen(dup(fd), "r"); - } - if (mFile == NULL) { - return ERROR_OPEN_FAILED; - } - - struct stat sb; - int ret; - if (path) { - ret = stat(path, &sb); - } else { - ret = fstat(fd, &sb); - } - if (ret != 0) { - mState = STATE_ERROR; - fclose(mFile); - return ERROR_OPEN_FAILED; - } - if (sb.st_size > (length + offset)) { - mLength = length; - } else { - mLength = sb.st_size - offset; - } - - ov_callbacks callbacks = { - (size_t (*)(void *, size_t, size_t, void *)) vp_fread, - (int (*)(void *, ogg_int64_t, int)) vp_fseek, - (int (*)(void *)) vp_fclose, - (long (*)(void *)) vp_ftell - }; - - mOffset = offset; - fseek(mFile, offset, SEEK_SET); - - int result = ov_open_callbacks(this, &mVorbisFile, NULL, 0, callbacks); - if (result < 0) { - LOGE("ov_open() failed: [%d]\n", (int)result); - mState = STATE_ERROR; - fclose(mFile); - return ERROR_OPEN_FAILED; - } - - // look for the android loop tag (for ringtones) - char **ptr = ov_comment(&mVorbisFile,-1)->user_comments; - while(*ptr) { - // does the comment start with ANDROID_LOOP_TAG - if(strncmp(*ptr, ANDROID_LOOP_TAG, strlen(ANDROID_LOOP_TAG)) == 0) { - // read the value of the tag - char *val = *ptr + strlen(ANDROID_LOOP_TAG) + 1; - mAndroidLoop = (strncmp(val, "true", 4) == 0); - } - // we keep parsing even after finding one occurence of ANDROID_LOOP_TAG, - // as we could find another one (the tag might have been appended more than once). - ++ptr; - } - LOGV_IF(mAndroidLoop, "looped sound"); - - mState = STATE_OPEN; - return NO_ERROR; -} - -status_t VorbisPlayer::prepare() -{ - LOGV("prepare\n"); - if (mState != STATE_OPEN ) { - return ERROR_NOT_OPEN; - } - return NO_ERROR; -} - -status_t VorbisPlayer::prepareAsync() { - LOGV("prepareAsync\n"); - // can't hold the lock here because of the callback - // it's safe because we don't change state - if (mState != STATE_OPEN ) { - sendEvent(MEDIA_ERROR); - return NO_ERROR; - } - sendEvent(MEDIA_PREPARED); - return NO_ERROR; -} - -status_t VorbisPlayer::start() -{ - LOGV("start\n"); - Mutex::Autolock l(mMutex); - if (mState != STATE_OPEN) { - return ERROR_NOT_OPEN; - } - - mPaused = false; - mRender = true; - - // wake up render thread - LOGV(" wakeup render thread\n"); - mCondition.signal(); - return NO_ERROR; -} - -status_t VorbisPlayer::stop() -{ - LOGV("stop\n"); - Mutex::Autolock l(mMutex); - if (mState != STATE_OPEN) { - return ERROR_NOT_OPEN; - } - mPaused = true; - mRender = false; - return NO_ERROR; -} - -status_t VorbisPlayer::seekTo(int position) -{ - LOGV("seekTo %d\n", position); - Mutex::Autolock l(mMutex); - if (mState != STATE_OPEN) { - return ERROR_NOT_OPEN; - } - - int result = ov_time_seek(&mVorbisFile, position); - if (result != 0) { - LOGE("ov_time_seek() returned %d\n", result); - return result; - } - sendEvent(MEDIA_SEEK_COMPLETE); - return NO_ERROR; -} - -status_t VorbisPlayer::pause() -{ - LOGV("pause\n"); - Mutex::Autolock l(mMutex); - if (mState != STATE_OPEN) { - return ERROR_NOT_OPEN; - } - mPaused = true; - return NO_ERROR; -} - -bool VorbisPlayer::isPlaying() -{ - LOGV("isPlaying\n"); - if (mState == STATE_OPEN) { - return mRender; - } - return false; -} - -status_t VorbisPlayer::getCurrentPosition(int* position) -{ - LOGV("getCurrentPosition\n"); - Mutex::Autolock l(mMutex); - if (mState != STATE_OPEN) { - LOGE("getCurrentPosition(): file not open"); - return ERROR_NOT_OPEN; - } - *position = ov_time_tell(&mVorbisFile); - if (*position < 0) { - LOGE("getCurrentPosition(): ov_time_tell returned %d", *position); - return *position; - } - return NO_ERROR; -} - -status_t VorbisPlayer::getDuration(int* duration) -{ - LOGV("getDuration\n"); - Mutex::Autolock l(mMutex); - if (mState != STATE_OPEN) { - return ERROR_NOT_OPEN; - } - - int ret = ov_time_total(&mVorbisFile, -1); - if (ret == OV_EINVAL) { - return -1; - } - - *duration = ret; - return NO_ERROR; -} - -status_t VorbisPlayer::release() -{ - LOGV("release\n"); - Mutex::Autolock l(mMutex); - reset_nosync(); - - // TODO: timeout when thread won't exit - // wait for render thread to exit - if (mRenderTid > 0) { - mExit = true; - mCondition.signal(); - mCondition.wait(mMutex); - } - return NO_ERROR; -} - -status_t VorbisPlayer::reset() -{ - LOGV("reset\n"); - Mutex::Autolock l(mMutex); - return reset_nosync(); -} - -// always call with lock held -status_t VorbisPlayer::reset_nosync() -{ - // close file - if (mFile != NULL) { - ov_clear(&mVorbisFile); // this also closes the FILE - if (mFile != NULL) { - LOGV("OOPS! Vorbis didn't close the file"); - fclose(mFile); - mFile = NULL; - } - } - mState = STATE_ERROR; - - mPlayTime = -1; - mDuration = -1; - mLoop = false; - mAndroidLoop = false; - mPaused = false; - mRender = false; - return NO_ERROR; -} - -status_t VorbisPlayer::setLooping(int loop) -{ - LOGV("setLooping\n"); - Mutex::Autolock l(mMutex); - mLoop = (loop != 0); - return NO_ERROR; -} - -status_t VorbisPlayer::createOutputTrack() { - // open audio track - vorbis_info *vi = ov_info(&mVorbisFile, -1); - - LOGV("Create AudioTrack object: rate=%ld, channels=%d\n", - vi->rate, vi->channels); - if (mAudioSink->open(vi->rate, vi->channels, AudioSystem::PCM_16_BIT, DEFAULT_AUDIOSINK_BUFFERCOUNT) != NO_ERROR) { - LOGE("mAudioSink open failed"); - return ERROR_OPEN_FAILED; - } - return NO_ERROR; -} - -int VorbisPlayer::renderThread(void* p) { - return ((VorbisPlayer*)p)->render(); -} - -#define AUDIOBUFFER_SIZE 4096 - -int VorbisPlayer::render() { - int result = -1; - int temp; - int current_section = 0; - bool audioStarted = false; - - LOGV("render\n"); - - // allocate render buffer - mAudioBuffer = new char[AUDIOBUFFER_SIZE]; - if (!mAudioBuffer) { - LOGE("mAudioBuffer allocate failed\n"); - goto threadExit; - } - - // let main thread know we're ready - { - Mutex::Autolock l(mMutex); - mRenderTid = myTid(); - mCondition.signal(); - } - - while (1) { - long numread = 0; - { - Mutex::Autolock l(mMutex); - - // pausing? - if (mPaused) { - if (mAudioSink->ready()) mAudioSink->pause(); - mRender = false; - audioStarted = false; - } - - // nothing to render, wait for client thread to wake us up - if (!mExit && !mRender) { - LOGV("render - signal wait\n"); - mCondition.wait(mMutex); - LOGV("render - signal rx'd\n"); - } - if (mExit) break; - - // We could end up here if start() is called, and before we get a - // chance to run, the app calls stop() or reset(). Re-check render - // flag so we don't try to render in stop or reset state. - if (!mRender) continue; - - // render vorbis data into the input buffer - numread = ov_read(&mVorbisFile, mAudioBuffer, AUDIOBUFFER_SIZE, ¤t_section); - if (numread == 0) { - // end of file, do we need to loop? - // ... - if (mLoop || mAndroidLoop) { - ov_time_seek(&mVorbisFile, 0); - current_section = 0; - numread = ov_read(&mVorbisFile, mAudioBuffer, AUDIOBUFFER_SIZE, ¤t_section); - } else { - mAudioSink->stop(); - audioStarted = false; - mRender = false; - mPaused = true; - int endpos = ov_time_tell(&mVorbisFile); - - LOGV("send MEDIA_PLAYBACK_COMPLETE"); - sendEvent(MEDIA_PLAYBACK_COMPLETE); - - // wait until we're started again - LOGV("playback complete - wait for signal"); - mCondition.wait(mMutex); - LOGV("playback complete - signal rx'd"); - if (mExit) break; - - // if we're still at the end, restart from the beginning - if (mState == STATE_OPEN) { - int curpos = ov_time_tell(&mVorbisFile); - if (curpos == endpos) { - ov_time_seek(&mVorbisFile, 0); - } - current_section = 0; - numread = ov_read(&mVorbisFile, mAudioBuffer, AUDIOBUFFER_SIZE, ¤t_section); - } - } - } - } - - // codec returns negative number on error - if (numread < 0) { - LOGE("Error in Vorbis decoder"); - sendEvent(MEDIA_ERROR); - break; - } - - // create audio output track if necessary - if (!mAudioSink->ready()) { - LOGV("render - create output track\n"); - if (createOutputTrack() != NO_ERROR) - break; - } - - // Write data to the audio hardware - if ((temp = mAudioSink->write(mAudioBuffer, numread)) < 0) { - LOGE("Error in writing:%d",temp); - result = temp; - break; - } - - // start audio output if necessary - if (!audioStarted && !mPaused && !mExit) { - LOGV("render - starting audio\n"); - mAudioSink->start(); - audioStarted = true; - } - } - -threadExit: - mAudioSink.clear(); - if (mAudioBuffer) { - delete [] mAudioBuffer; - mAudioBuffer = NULL; - } - - // tell main thread goodbye - Mutex::Autolock l(mMutex); - mRenderTid = -1; - mCondition.signal(); - return result; -} - -} // end namespace android diff --git a/media/libmediaplayerservice/VorbisPlayer.h b/media/libmediaplayerservice/VorbisPlayer.h deleted file mode 100644 index 4a50835..0000000 --- a/media/libmediaplayerservice/VorbisPlayer.h +++ /dev/null @@ -1,94 +0,0 @@ -/* -** -** Copyright 2008, 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 ANDROID_VORBISPLAYER_H -#define ANDROID_VORBISPLAYER_H - -#include <utils/threads.h> - -#include <media/MediaPlayerInterface.h> -#include <media/AudioTrack.h> - -#include "ivorbiscodec.h" -#include "ivorbisfile.h" - -#define ANDROID_LOOP_TAG "ANDROID_LOOP" - -namespace android { - -class VorbisPlayer : public MediaPlayerInterface { -public: - VorbisPlayer(); - ~VorbisPlayer(); - - virtual void onFirstRef(); - virtual status_t initCheck(); - - virtual status_t setDataSource( - const char *uri, const KeyedVector<String8, String8> *headers); - - virtual status_t setDataSource(int fd, int64_t offset, int64_t length); - virtual status_t setVideoSurface(const sp<ISurface>& surface) { return UNKNOWN_ERROR; } - virtual status_t prepare(); - virtual status_t prepareAsync(); - virtual status_t start(); - virtual status_t stop(); - virtual status_t seekTo(int msec); - virtual status_t pause(); - virtual bool isPlaying(); - virtual status_t getCurrentPosition(int* msec); - virtual status_t getDuration(int* msec); - virtual status_t release(); - virtual status_t reset(); - virtual status_t setLooping(int loop); - virtual player_type playerType() { return VORBIS_PLAYER; } - virtual status_t invoke(const Parcel& request, Parcel *reply) {return INVALID_OPERATION;} - -private: - status_t setdatasource(const char *path, int fd, int64_t offset, int64_t length); - status_t reset_nosync(); - status_t createOutputTrack(); - static int renderThread(void*); - int render(); - - static size_t vp_fread(void *, size_t, size_t, void *); - static int vp_fseek(void *, ogg_int64_t, int); - static int vp_fclose(void *); - static long vp_ftell(void *); - - Mutex mMutex; - Condition mCondition; - FILE* mFile; - int64_t mOffset; - int64_t mLength; - OggVorbis_File mVorbisFile; - char* mAudioBuffer; - int mPlayTime; - int mDuration; - status_t mState; - int mStreamType; - bool mLoop; - bool mAndroidLoop; - volatile bool mExit; - bool mPaused; - volatile bool mRender; - pid_t mRenderTid; -}; - -}; // namespace android - -#endif // ANDROID_VORBISPLAYER_H |