summaryrefslogtreecommitdiffstats
path: root/media/libmediaplayerservice
diff options
context:
space:
mode:
Diffstat (limited to 'media/libmediaplayerservice')
-rw-r--r--media/libmediaplayerservice/Android.mk17
-rw-r--r--media/libmediaplayerservice/MediaPlayerService.cpp298
-rw-r--r--media/libmediaplayerservice/MediaPlayerService.h24
-rw-r--r--media/libmediaplayerservice/MediaRecorderClient.cpp11
-rw-r--r--media/libmediaplayerservice/MediaRecorderClient.h21
-rw-r--r--media/libmediaplayerservice/MetadataRetrieverClient.cpp18
-rw-r--r--media/libmediaplayerservice/StagefrightRecorder.cpp999
-rw-r--r--media/libmediaplayerservice/StagefrightRecorder.h70
-rw-r--r--media/libmediaplayerservice/VorbisMetadataRetriever.cpp87
-rw-r--r--media/libmediaplayerservice/VorbisMetadataRetriever.h49
-rw-r--r--media/libmediaplayerservice/VorbisPlayer.cpp529
-rw-r--r--media/libmediaplayerservice/VorbisPlayer.h94
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 &params) {
- 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 &params) {
+ 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, &current_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, &current_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, &current_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