M7350v1_en_gpl

This commit is contained in:
T
2024-09-09 08:52:07 +00:00
commit f9cc65cfda
65988 changed files with 26357421 additions and 0 deletions
@@ -0,0 +1,68 @@
LOCAL_PATH:= $(call my-dir)
#
# libmediaplayerservice
#
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
MediaRecorderClient.cpp \
MediaPlayerService.cpp \
MetadataRetrieverClient.cpp \
TestPlayerStub.cpp \
MidiMetadataRetriever.cpp \
MidiFile.cpp \
StagefrightPlayer.cpp \
StagefrightRecorder.cpp
ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true)
LOCAL_LDLIBS += -ldl -lpthread
endif
LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
libbinder \
libvorbisidec \
libsonivox \
libmedia \
libcamera_client \
libandroid_runtime \
libstagefright \
libstagefright_omx \
libstagefright_color_conversion \
libstagefright_foundation \
libsurfaceflinger_client
LOCAL_STATIC_LIBRARIES := \
libstagefright_rtsp
ifneq ($(BUILD_WITHOUT_PV),true)
LOCAL_SHARED_LIBRARIES += \
libopencore_player \
libopencore_author
else
LOCAL_CFLAGS += -DNO_OPENCORE
endif
ifeq ($(WEBCORE_INPAGE_VIDEO), true)
LOCAL_CFLAGS += -DYUVCLIENT
endif
ifneq ($(TARGET_SIMULATOR),true)
LOCAL_SHARED_LIBRARIES += libdl
endif
LOCAL_C_INCLUDES := \
$(JNI_H_INCLUDE) \
$(call include-path-for, graphics corecg) \
$(TOP)/frameworks/base/include/media/stagefright/openmax \
$(TOP)/frameworks/base/media/libstagefright/include \
$(TOP)/frameworks/base/media/libstagefright/rtsp \
$(TOP)/external/tremolo/Tremolo
LOCAL_MODULE:= libmediaplayerservice
include $(BUILD_SHARED_LIBRARY)
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,323 @@
/*
**
** Copyright 2008, The Android Open Source Project
** Copyright (c) 2009-2011, The Linux Foundation. All rights reserved.
**
** 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_MEDIAPLAYERSERVICE_H
#define ANDROID_MEDIAPLAYERSERVICE_H
#include <utils/Log.h>
#include <utils/threads.h>
#include <utils/List.h>
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
#include <utils/String8.h>
#include <utils/Vector.h>
#include <media/IMediaPlayerService.h>
#include <media/MediaPlayerInterface.h>
#include <media/Metadata.h>
namespace android {
class IMediaRecorder;
class IMediaMetadataRetriever;
class IOMX;
class MediaRecorderClient;
#define CALLBACK_ANTAGONIZER 0
#if CALLBACK_ANTAGONIZER
class Antagonizer {
public:
Antagonizer(notify_callback_f cb, void* client);
void start() { mActive = true; }
void stop() { mActive = false; }
void kill();
private:
static const int interval;
Antagonizer();
static int callbackThread(void* cookie);
Mutex mLock;
Condition mCondition;
bool mExit;
bool mActive;
void* mClient;
notify_callback_f mCb;
};
#endif
class MediaPlayerService : public BnMediaPlayerService
{
class Client;
class AudioOutput : public MediaPlayerBase::AudioSink
{
public:
AudioOutput(int sessionId);
virtual ~AudioOutput();
virtual bool ready() const { return mTrack != NULL; }
virtual bool realtime() const { return true; }
virtual ssize_t bufferSize() const;
virtual ssize_t frameCount() const;
virtual ssize_t channelCount() const;
virtual ssize_t frameSize() const;
virtual uint32_t latency() const;
virtual float msecsPerFrame() const;
virtual status_t getPosition(uint32_t *position);
virtual int getSessionId();
virtual status_t open(
uint32_t sampleRate, int channelCount,
int format, int bufferCount,
AudioCallback cb, void *cookie);
virtual status_t openSession(
int format, int sessionId, uint32_t sampleRate, int channels);
virtual void start();
virtual ssize_t write(const void* buffer, size_t size);
virtual void stop();
virtual void flush();
virtual void pause();
virtual void pauseSession();
virtual void resumeSession();
virtual void close();
virtual void closeSession();
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();
static int getMinBufferCount();
private:
static void setMinBufferCount();
static void CallbackWrapper(
int event, void *me, void *info);
AudioTrack* mTrack;
AudioTrack* mSession;
AudioCallback mCallback;
void * mCallbackCookie;
int mStreamType;
float mLeftVolume;
float mRightVolume;
float mMsecsPerFrame;
uint32_t mLatency;
int mSessionId;
float mSendLevel;
int mAuxEffectId;
static bool mIsOnEmulator;
static int mMinBufferCount; // 12 for emulator; otherwise 4
};
class AudioCache : public MediaPlayerBase::AudioSink
{
public:
AudioCache(const char* name);
virtual ~AudioCache() {}
virtual bool ready() const { return (mChannelCount > 0) && (mHeap->getHeapID() > 0); }
virtual bool realtime() const { return false; }
virtual ssize_t bufferSize() const { return frameSize() * mFrameCount; }
virtual ssize_t frameCount() const { return mFrameCount; }
virtual ssize_t channelCount() const { return (ssize_t)mChannelCount; }
virtual ssize_t frameSize() const { return ssize_t(mChannelCount * ((mFormat == AudioSystem::PCM_16_BIT)?sizeof(int16_t):sizeof(u_int8_t))); }
virtual uint32_t latency() const;
virtual float msecsPerFrame() const;
virtual status_t getPosition(uint32_t *position);
virtual int getSessionId();
virtual status_t open(
uint32_t sampleRate, int channelCount, int format,
int bufferCount = 1,
AudioCallback cb = NULL, void *cookie = NULL);
virtual void start();
virtual ssize_t write(const void* buffer, size_t size);
virtual void stop();
virtual void flush() {}
virtual void pause() {}
virtual void close() {}
void setAudioStreamType(int streamType) {}
void setVolume(float left, float right) {}
uint32_t sampleRate() const { return mSampleRate; }
uint32_t format() const { return (uint32_t)mFormat; }
size_t size() const { return mSize; }
status_t wait();
sp<IMemoryHeap> getHeap() const { return mHeap; }
static void notify(void* cookie, int msg, int ext1, int ext2);
virtual status_t dump(int fd, const Vector<String16>& args) const;
private:
AudioCache();
Mutex mLock;
Condition mSignal;
sp<MemoryHeapBase> mHeap;
float mMsecsPerFrame;
uint16_t mChannelCount;
uint16_t mFormat;
ssize_t mFrameCount;
uint32_t mSampleRate;
uint32_t mSize;
int mError;
bool mCommandComplete;
sp<Thread> mCallbackThread;
};
public:
static void instantiate();
// IMediaPlayerService interface
virtual sp<IMediaRecorder> createMediaRecorder(pid_t pid);
void removeMediaRecorderClient(wp<MediaRecorderClient> client);
virtual sp<IMediaMetadataRetriever> createMetadataRetriever(pid_t pid);
// 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, int audioSessionId);
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<IOMX> getOMX();
virtual status_t dump(int fd, const Vector<String16>& args);
void removeClient(wp<Client> client);
private:
class Client : public BnMediaPlayer {
// IMediaPlayer interface
virtual void disconnect();
virtual status_t setVideoSurface(const sp<ISurface>& surface);
virtual status_t prepareAsync();
virtual status_t start();
virtual status_t stop();
virtual status_t pause();
virtual status_t isPlaying(bool* state);
virtual status_t seekTo(int msec);
virtual status_t getCurrentPosition(int* msec);
virtual status_t getDuration(int* msec);
virtual status_t reset();
virtual status_t setAudioStreamType(int type);
virtual status_t setLooping(int loop);
virtual status_t setVolume(float leftVolume, float rightVolume);
virtual status_t invoke(const Parcel& request, Parcel *reply);
virtual status_t setMetadataFilter(const Parcel& filter);
virtual status_t getMetadata(bool update_only,
bool apply_filter,
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);
status_t setDataSource(
const char *url,
const KeyedVector<String8, String8> *headers);
status_t setDataSource(int fd, int64_t offset, int64_t length);
static void notify(void* cookie, int msg, int ext1, int ext2);
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,
int audioSessionId);
Client();
virtual ~Client();
void deletePlayer();
sp<MediaPlayerBase> getPlayer() const { Mutex::Autolock lock(mLock); return mPlayer; }
// @param type Of the metadata to be tested.
// @return true if the metadata should be dropped according to
// the filters.
bool shouldDropMetadata(media::Metadata::Type type) const;
// Add a new element to the set of metadata updated. Noop if
// the element exists already.
// @param type Of the metadata to be recorded.
void addNewMetadataUpdate(media::Metadata::Type type);
mutable Mutex mLock;
sp<MediaPlayerBase> mPlayer;
sp<MediaPlayerService> mService;
sp<IMediaPlayerClient> mClient;
sp<AudioOutput> mAudioOutput;
pid_t mPid;
status_t mStatus;
bool mLoop;
int32_t mConnId;
int mAudioSessionId;
// Metadata filters.
media::Metadata::Filter mMetadataAllow; // protected by mLock
media::Metadata::Filter mMetadataDrop; // protected by mLock
// Metadata updated. For each MEDIA_INFO_METADATA_UPDATE
// notification we try to update mMetadataUpdated which is a
// set: no duplicate.
// getMetadata clears this set.
media::Metadata::Filter mMetadataUpdated; // protected by mLock
#if CALLBACK_ANTAGONIZER
Antagonizer* mAntagonizer;
#endif
virtual status_t setParameters(const String8& params);
};
// ----------------------------------------------------------------------------
MediaPlayerService();
virtual ~MediaPlayerService();
mutable Mutex mLock;
SortedVector< wp<Client> > mClients;
SortedVector< wp<MediaRecorderClient> > mMediaRecorderClients;
int32_t mNextConnId;
sp<IOMX> mOMX;
};
// ----------------------------------------------------------------------------
}; // namespace android
#endif // ANDROID_MEDIAPLAYERSERVICE_H
@@ -0,0 +1,435 @@
/*
** Copyright 2008, The Android Open Source Project
** Copyright (c) 2011, The Linux Foundation. All rights reserved.
**
** 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 "MediaRecorderService"
#include <utils/Log.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
#include <string.h>
#include <cutils/atomic.h>
#include <cutils/properties.h> // for property_get
#include <android_runtime/ActivityManager.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/MemoryHeapBase.h>
#include <binder/MemoryBase.h>
#ifndef NO_OPENCORE
#include <media/PVMediaRecorder.h>
#endif
#include <utils/String16.h>
#include <media/AudioTrack.h>
#include "MediaRecorderClient.h"
#include "MediaPlayerService.h"
#include "StagefrightRecorder.h"
namespace android {
const char* cameraPermission = "android.permission.CAMERA";
const char* recordAudioPermission = "android.permission.RECORD_AUDIO";
static bool checkPermission(const char* permissionString) {
#ifndef HAVE_ANDROID_OS
return true;
#endif
if (getpid() == IPCThreadState::self()->getCallingPid()) return true;
bool ok = checkCallingPermission(String16(permissionString));
if (!ok) LOGE("Request requires %s", permissionString);
return ok;
}
status_t MediaRecorderClient::setCamera(const sp<ICamera>& camera)
{
LOGV("setCamera");
Mutex::Autolock lock(mLock);
if (mRecorder == NULL) {
LOGE("recorder is not initialized");
return NO_INIT;
}
return mRecorder->setCamera(camera);
}
status_t MediaRecorderClient::setPreviewSurface(const sp<ISurface>& surface)
{
LOGV("setPreviewSurface");
Mutex::Autolock lock(mLock);
if (mRecorder == NULL) {
LOGE("recorder is not initialized");
return NO_INIT;
}
return mRecorder->setPreviewSurface(surface);
}
status_t MediaRecorderClient::setVideoSource(int vs)
{
LOGV("setVideoSource(%d)", vs);
if (!checkPermission(cameraPermission)) {
return PERMISSION_DENIED;
}
Mutex::Autolock lock(mLock);
if (mRecorder == NULL) {
LOGE("recorder is not initialized");
return NO_INIT;
}
mVideoSource = (video_source)vs;
return mRecorder->setVideoSource((video_source)vs);
}
status_t MediaRecorderClient::setAudioSource(int as)
{
LOGV("setAudioSource(%d)", as);
if (!checkPermission(recordAudioPermission)) {
return PERMISSION_DENIED;
}
Mutex::Autolock lock(mLock);
if (mRecorder == NULL) {
LOGE("recorder is not initialized");
return NO_INIT;
}
mAudioSource = (audio_source)as;
return mRecorder->setAudioSource((audio_source)as);
}
status_t MediaRecorderClient::setOutputFormat(int of)
{
LOGV("setOutputFormat(%d)", of);
Mutex::Autolock lock(mLock);
if (mRecorder == NULL) {
LOGE("recorder is not initialized");
return NO_INIT;
}
mOutputFormat = (output_format)of;
return mRecorder->setOutputFormat((output_format)of);
}
status_t MediaRecorderClient::setVideoEncoder(int ve)
{
LOGV("setVideoEncoder(%d)", ve);
Mutex::Autolock lock(mLock);
if (mRecorder == NULL) {
LOGE("recorder is not initialized");
return NO_INIT;
}
mVideoEncoder = (video_encoder)ve;
return mRecorder->setVideoEncoder((video_encoder)ve);
}
status_t MediaRecorderClient::setAudioEncoder(int ae)
{
LOGV("setAudioEncoder(%d)", ae);
Mutex::Autolock lock(mLock);
if (mRecorder == NULL) {
LOGE("recorder is not initialized");
return NO_INIT;
}
mAudioEncoder = (audio_encoder)ae;
return mRecorder->setAudioEncoder((audio_encoder)ae);
}
status_t MediaRecorderClient::setOutputFile(const char* path)
{
LOGV("setOutputFile(%s)", path);
Mutex::Autolock lock(mLock);
if (mRecorder == NULL) {
LOGE("recorder is not initialized");
return NO_INIT;
}
mPath = path;
return mRecorder->setOutputFile(path);
}
status_t MediaRecorderClient::setOutputFile(int fd, int64_t offset, int64_t length)
{
LOGV("setOutputFile(%d, %lld, %lld)", fd, offset, length);
Mutex::Autolock lock(mLock);
if (mRecorder == NULL) {
LOGE("recorder is not initialized");
return NO_INIT;
}
mFd = ::dup(fd);
mOffset = offset;
mLength = length;
return mRecorder->setOutputFile(fd, offset, length);
}
status_t MediaRecorderClient::setVideoSize(int width, int height)
{
LOGV("setVideoSize(%dx%d)", width, height);
Mutex::Autolock lock(mLock);
if (mRecorder == NULL) {
LOGE("recorder is not initialized");
return NO_INIT;
}
return mRecorder->setVideoSize(width, height);
}
status_t MediaRecorderClient::setVideoFrameRate(int frames_per_second)
{
LOGV("setVideoFrameRate(%d)", frames_per_second);
Mutex::Autolock lock(mLock);
if (mRecorder == NULL) {
LOGE("recorder is not initialized");
return NO_INIT;
}
return mRecorder->setVideoFrameRate(frames_per_second);
}
status_t MediaRecorderClient::setParameters(const String8& params) {
LOGV("setParameters(%s)", params.string());
Mutex::Autolock lock(mLock);
if (mRecorder == NULL) {
LOGE("recorder is not initialized");
return NO_INIT;
}
mParams = params;
return mRecorder->setParameters(params);
}
status_t MediaRecorderClient::setCameraParameters(const String8& params) {
LOGV("setCameraParameters(%s)", params.string());
Mutex::Autolock lock(mLock);
if (mRecorder == NULL) {
LOGE("recorder is not initialized");
return NO_INIT;
}
return mRecorder->setCameraParameters(params);
}
status_t MediaRecorderClient::prepare()
{
char value[PROPERTY_VALUE_MAX];
LOGV("prepare");
Mutex::Autolock lock(mLock);
if (mRecorder == NULL) {
LOGE("recorder is not initialized");
return NO_INIT;
}
if( mVideoSource == VIDEO_SOURCE_LIST_END &&
mVideoEncoder == VIDEO_ENCODER_LIST_END ) {
if(mAudioSource == AUDIO_SOURCE_LIST_END ||
mAudioEncoder == AUDIO_ENCODER_LIST_END ){
return BAD_VALUE;
}
// For 7627 target switch to OC for voice call recording
property_get("ro.board.platform",value,"0");
int useSFforFmA2DP = false;
if (property_get("media.stagefright.enable-fma2dp", value, NULL)
&& (!strcmp(value, "1") || !strcasecmp(value, "true"))){
LOGW("FM Over A2DP Using SF");
useSFforFmA2DP = true;
}
if(((mAudioSource == AUDIO_SOURCE_VOICE_CALL ||
mAudioSource == AUDIO_SOURCE_VOICE_DOWNLINK) &&
(strcmp("msm7627_surf",value) == 0 ||
strcmp("msm7627_ffa",value) == 0)) ||
(!useSFforFmA2DP &&
mAudioSource == AUDIO_SOURCE_FM_RX_A2DP )){
LOGW("FM_A2DP recording or voice call \
recording, switching to OC");
MediaRecorderBase * sfRecorder = mRecorder;
mRecorder = new PVMediaRecorder( );
mRecorder->init( );
mRecorder->setAudioSource( mAudioSource );
mRecorder->setOutputFormat( mOutputFormat );
mRecorder->setAudioEncoder( mAudioEncoder );
mRecorder->setListener(mListener);
mRecorder->setParameters(mParams);
mRecorder->setOutputFile( mFd, mOffset, mLength );
delete sfRecorder;
}
}
return mRecorder->prepare();
}
status_t MediaRecorderClient::getMaxAmplitude(int* max)
{
LOGV("getMaxAmplitude");
Mutex::Autolock lock(mLock);
if (mRecorder == NULL) {
LOGE("recorder is not initialized");
return NO_INIT;
}
return mRecorder->getMaxAmplitude(max);
}
status_t MediaRecorderClient::start()
{
LOGV("start");
Mutex::Autolock lock(mLock);
if (mRecorder == NULL) {
LOGE("recorder is not initialized");
return NO_INIT;
}
return mRecorder->start();
}
status_t MediaRecorderClient::takeLiveSnapshot()
{
LOGV("MediaRecorderClient::takeLiveSnapshot");
Mutex::Autolock lock(mLock);
if (mRecorder == NULL) {
LOGE("recorder is not initialized");
return NO_INIT;
}
return mRecorder->takeLiveSnapshot();
}
status_t MediaRecorderClient::stop()
{
LOGV("stop");
Mutex::Autolock lock(mLock);
if (mRecorder == NULL) {
LOGE("recorder is not initialized");
return NO_INIT;
}
return mRecorder->stop();
}
status_t MediaRecorderClient::init()
{
LOGV("init");
Mutex::Autolock lock(mLock);
if (mRecorder == NULL) {
LOGE("recorder is not initialized");
return NO_INIT;
}
return mRecorder->init();
}
status_t MediaRecorderClient::close()
{
LOGV("close");
Mutex::Autolock lock(mLock);
if (mRecorder == NULL) {
LOGE("recorder is not initialized");
return NO_INIT;
}
return mRecorder->close();
}
status_t MediaRecorderClient::reset()
{
LOGV("reset");
Mutex::Autolock lock(mLock);
if (mRecorder == NULL) {
LOGE("recorder is not initialized");
return NO_INIT;
}
return mRecorder->reset();
}
status_t MediaRecorderClient::release()
{
LOGV("release");
Mutex::Autolock lock(mLock);
if (mRecorder != NULL) {
delete mRecorder;
mRecorder = NULL;
mListener = NULL;
wp<MediaRecorderClient> client(this);
mMediaPlayerService->removeMediaRecorderClient(client);
}
if( mFd != -1 ){
::close( mFd );
mFd = -1;
}
return NO_ERROR;
}
MediaRecorderClient::MediaRecorderClient(const sp<MediaPlayerService>& service, pid_t pid)
{
LOGV("Client constructor");
mPid = pid;
char value[PROPERTY_VALUE_MAX];
//changing default to stagefright by setting it as 1, if want to fallback, please change
//it to NULL
if (!property_get("media.stagefright.enable-record", value, "1")
|| !strcmp(value, "1") || !strcasecmp(value, "true")) {
mRecorder = new StagefrightRecorder;
} else
#ifndef NO_OPENCORE
{
mRecorder = new PVMediaRecorder();
}
#else
{
mRecorder = NULL;
}
#endif
mMediaPlayerService = service;
mAudioSource = AUDIO_SOURCE_LIST_END;
mVideoSource = VIDEO_SOURCE_LIST_END;
mAudioEncoder = AUDIO_ENCODER_LIST_END;
mVideoEncoder = VIDEO_ENCODER_LIST_END;
mOutputFormat = OUTPUT_FORMAT_LIST_END;
mFd = -1;
mOffset = 0;
mLength = 0;
}
MediaRecorderClient::~MediaRecorderClient()
{
LOGV("Client destructor");
release();
}
status_t MediaRecorderClient::setListener(const sp<IMediaRecorderClient>& listener)
{
LOGV("setListener");
Mutex::Autolock lock(mLock);
if (mRecorder == NULL) {
LOGE("recorder is not initialized");
return NO_INIT;
}
mListener = 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
@@ -0,0 +1,87 @@
/*
**
** Copyright 2008, The Android Open Source Project
** Copyright (c) 2011, The Linux Foundation. All rights reserved.
**
** 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_MEDIARECORDERCLIENT_H
#define ANDROID_MEDIARECORDERCLIENT_H
#include <media/IMediaRecorder.h>
namespace android {
class MediaRecorderBase;
class MediaPlayerService;
class MediaRecorderClient : public BnMediaRecorder
{
public:
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);
virtual status_t setOutputFormat(int of);
virtual status_t setVideoEncoder(int ve);
virtual status_t setAudioEncoder(int ae);
virtual status_t setOutputFile(const char* path);
virtual status_t setOutputFile(int fd, int64_t offset, int64_t length);
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<IMediaRecorderClient>& listener);
virtual status_t setCameraParameters(const String8& params);
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 init();
virtual status_t close();
virtual status_t release();
virtual status_t dump(int fd, const Vector<String16>& args) const;
virtual status_t takeLiveSnapshot();
private:
friend class MediaPlayerService; // for accessing private constructor
MediaRecorderClient(const sp<MediaPlayerService>& service, pid_t pid);
virtual ~MediaRecorderClient();
pid_t mPid;
Mutex mLock;
MediaRecorderBase *mRecorder;
sp<MediaPlayerService> mMediaPlayerService;
audio_source mAudioSource;
audio_encoder mAudioEncoder;
video_source mVideoSource;
video_encoder mVideoEncoder;
String8 mParams;
sp<IMediaRecorderClient> mListener;
output_format mOutputFormat;
String8 mPath;
int mFd;
int64_t mOffset;
int64_t mLength;
};
}; // namespace android
#endif // ANDROID_MEDIARECORDERCLIENT_H
@@ -0,0 +1,288 @@
/*
**
** Copyright (C) 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.
*/
//#define LOG_NDEBUG 0
#define LOG_TAG "MetadataRetrieverClient"
#include <utils/Log.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/resource.h>
#include <dirent.h>
#include <unistd.h>
#include <string.h>
#include <cutils/atomic.h>
#include <cutils/properties.h>
#include <binder/MemoryBase.h>
#include <binder/MemoryHeapBase.h>
#include <android_runtime/ActivityManager.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <media/MediaMetadataRetrieverInterface.h>
#include <media/MediaPlayerInterface.h>
#include <media/PVMetadataRetriever.h>
#include <private/media/VideoFrame.h>
#include "MidiMetadataRetriever.h"
#include "MetadataRetrieverClient.h"
#include "StagefrightMetadataRetriever.h"
/* desktop Linux needs a little help with gettid() */
#if defined(HAVE_GETTID) && !defined(HAVE_ANDROID_OS)
#define __KERNEL__
# include <linux/unistd.h>
#ifdef _syscall0
_syscall0(pid_t,gettid)
#else
pid_t gettid() { return syscall(__NR_gettid);}
#endif
#undef __KERNEL__
#endif
namespace android {
extern player_type getPlayerType(const char* url);
extern player_type getPlayerType(int fd, int64_t offset, int64_t length);
MetadataRetrieverClient::MetadataRetrieverClient(pid_t pid)
{
LOGV("MetadataRetrieverClient constructor pid(%d)", pid);
mPid = pid;
mThumbnail = NULL;
mAlbumArt = NULL;
mRetriever = NULL;
}
MetadataRetrieverClient::~MetadataRetrieverClient()
{
LOGV("MetadataRetrieverClient destructor");
disconnect();
}
status_t MetadataRetrieverClient::dump(int fd, const Vector<String16>& args) const
{
const size_t SIZE = 256;
char buffer[SIZE];
String8 result;
result.append(" MetadataRetrieverClient\n");
snprintf(buffer, 255, " pid(%d)\n", mPid);
result.append(buffer);
write(fd, result.string(), result.size());
write(fd, "\n", 1);
return NO_ERROR;
}
void MetadataRetrieverClient::disconnect()
{
LOGV("disconnect from pid %d", mPid);
Mutex::Autolock lock(mLock);
mRetriever.clear();
mThumbnail.clear();
mAlbumArt.clear();
IPCThreadState::self()->flushCommands();
}
static sp<MediaMetadataRetrieverBase> createRetriever(player_type playerType)
{
sp<MediaMetadataRetrieverBase> p;
switch (playerType) {
case STAGEFRIGHT_PLAYER:
{
p = new StagefrightMetadataRetriever;
break;
}
#ifndef NO_OPENCORE
case PV_PLAYER:
LOGV("create pv metadata retriever");
p = new PVMetadataRetriever();
break;
#endif
case SONIVOX_PLAYER:
LOGV("create midi metadata retriever");
p = new MidiMetadataRetriever();
break;
default:
// TODO:
// support for TEST_PLAYER
LOGE("player type %d is not supported", playerType);
break;
}
if (p == NULL) {
LOGE("failed to create a retriever object");
}
return p;
}
status_t MetadataRetrieverClient::setDataSource(const char *url)
{
LOGW("setDataSource(%s)", url);
Mutex::Autolock lock(mLock);
if (url == NULL) {
return UNKNOWN_ERROR;
}
player_type playerType;
playerType = getPlayerType(url);
char curr_target[128] = {0};
char target[] = "msm8660";
property_get("ro.board.platform", curr_target, "0");
if((!strncmp(target, curr_target, sizeof(target) - 1)) && (playerType == PV_PLAYER)) {
LOGW("Switch to Stagefright Player if PV player is returned in Metadata retriever");
playerType = STAGEFRIGHT_PLAYER;
}
LOGV("player type = %d", playerType);
sp<MediaMetadataRetrieverBase> p = createRetriever(playerType);
if (p == NULL) return NO_INIT;
status_t ret = p->setDataSource(url);
if (ret == NO_ERROR) mRetriever = p;
return ret;
}
status_t MetadataRetrieverClient::setDataSource(int fd, int64_t offset, int64_t length)
{
LOGV("setDataSource fd=%d, offset=%lld, length=%lld", fd, offset, length);
Mutex::Autolock lock(mLock);
struct stat sb;
int ret = fstat(fd, &sb);
if (ret != 0) {
LOGE("fstat(%d) failed: %d, %s", fd, ret, strerror(errno));
return BAD_VALUE;
}
LOGV("st_dev = %llu", sb.st_dev);
LOGV("st_mode = %u", sb.st_mode);
LOGV("st_uid = %lu", sb.st_uid);
LOGV("st_gid = %lu", sb.st_gid);
LOGV("st_size = %llu", sb.st_size);
if (offset >= sb.st_size) {
LOGE("offset (%lld) bigger than file size (%llu)", offset, sb.st_size);
::close(fd);
return BAD_VALUE;
}
if (offset + length > sb.st_size) {
length = sb.st_size - offset;
LOGV("calculated length = %lld", length);
}
player_type playerType;
playerType = getPlayerType(fd, offset, length);
char curr_target[128] = {0};
char target[] = "msm8660";
property_get("ro.board.platform", curr_target, "0");
if((!strncmp(target, curr_target, sizeof(target) - 1)) && (playerType == PV_PLAYER)) {
LOGW("Switch to Stagefright Player if PV player is returned in Metadata retriever");
playerType = STAGEFRIGHT_PLAYER;
}
LOGV("player type = %d", playerType);
sp<MediaMetadataRetrieverBase> p = createRetriever(playerType);
if (p == NULL) {
::close(fd);
return NO_INIT;
}
status_t status = p->setDataSource(fd, offset, length);
if (status == NO_ERROR) mRetriever = p;
::close(fd);
return status;
}
sp<IMemory> MetadataRetrieverClient::getFrameAtTime(int64_t timeUs, int option)
{
LOGV("getFrameAtTime: time(%lld us) option(%d)", timeUs, option);
Mutex::Autolock lock(mLock);
mThumbnail.clear();
if (mRetriever == NULL) {
LOGE("retriever is not initialized");
return NULL;
}
VideoFrame *frame = mRetriever->getFrameAtTime(timeUs, option);
if (frame == NULL) {
LOGE("failed to capture a video frame");
return NULL;
}
size_t size = sizeof(VideoFrame) + frame->mSize;
sp<MemoryHeapBase> heap = new MemoryHeapBase(size, 0, "MetadataRetrieverClient");
if (heap == NULL) {
LOGE("failed to create MemoryDealer");
delete frame;
return NULL;
}
mThumbnail = new MemoryBase(heap, 0, size);
if (mThumbnail == NULL) {
LOGE("not enough memory for VideoFrame size=%u", size);
delete frame;
return NULL;
}
VideoFrame *frameCopy = static_cast<VideoFrame *>(mThumbnail->pointer());
frameCopy->mWidth = frame->mWidth;
frameCopy->mHeight = frame->mHeight;
frameCopy->mDisplayWidth = frame->mDisplayWidth;
frameCopy->mDisplayHeight = frame->mDisplayHeight;
frameCopy->mSize = frame->mSize;
frameCopy->mRotationAngle = frame->mRotationAngle;
LOGV("rotation: %d", frameCopy->mRotationAngle);
frameCopy->mData = (uint8_t *)frameCopy + sizeof(VideoFrame);
memcpy(frameCopy->mData, frame->mData, frame->mSize);
delete frame; // Fix memory leakage
return mThumbnail;
}
sp<IMemory> MetadataRetrieverClient::extractAlbumArt()
{
LOGV("extractAlbumArt");
Mutex::Autolock lock(mLock);
mAlbumArt.clear();
if (mRetriever == NULL) {
LOGE("retriever is not initialized");
return NULL;
}
MediaAlbumArt *albumArt = mRetriever->extractAlbumArt();
if (albumArt == NULL) {
LOGE("failed to extract an album art");
return NULL;
}
size_t size = sizeof(MediaAlbumArt) + albumArt->mSize;
sp<MemoryHeapBase> heap = new MemoryHeapBase(size, 0, "MetadataRetrieverClient");
if (heap == NULL) {
LOGE("failed to create MemoryDealer object");
delete albumArt;
return NULL;
}
mAlbumArt = new MemoryBase(heap, 0, size);
if (mAlbumArt == NULL) {
LOGE("not enough memory for MediaAlbumArt size=%u", size);
delete albumArt;
return NULL;
}
MediaAlbumArt *albumArtCopy = static_cast<MediaAlbumArt *>(mAlbumArt->pointer());
albumArtCopy->mSize = albumArt->mSize;
albumArtCopy->mData = (uint8_t *)albumArtCopy + sizeof(MediaAlbumArt);
memcpy(albumArtCopy->mData, albumArt->mData, albumArt->mSize);
delete albumArt; // Fix memory leakage
return mAlbumArt;
}
const char* MetadataRetrieverClient::extractMetadata(int keyCode)
{
LOGV("extractMetadata");
Mutex::Autolock lock(mLock);
if (mRetriever == NULL) {
LOGE("retriever is not initialized");
return NULL;
}
return mRetriever->extractMetadata(keyCode);
}
}; // namespace android
@@ -0,0 +1,70 @@
/*
**
** Copyright (C) 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_MEDIAMETADATARETRIEVERSERVICE_H
#define ANDROID_MEDIAMETADATARETRIEVERSERVICE_H
#include <utils/Log.h>
#include <utils/threads.h>
#include <utils/List.h>
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
#include <binder/IMemory.h>
#include <media/MediaMetadataRetrieverInterface.h>
namespace android {
class IMediaPlayerService;
class MemoryDealer;
class MetadataRetrieverClient : public BnMediaMetadataRetriever
{
public:
MetadataRetrieverClient(const sp<IMediaPlayerService>& service, pid_t pid, int32_t connId);
// Implements IMediaMetadataRetriever interface
// These methods are called in IMediaMetadataRetriever.cpp?
virtual void disconnect();
virtual status_t setDataSource(const char *url);
virtual status_t setDataSource(int fd, int64_t offset, int64_t length);
virtual sp<IMemory> getFrameAtTime(int64_t timeUs, int option);
virtual sp<IMemory> extractAlbumArt();
virtual const char* extractMetadata(int keyCode);
virtual status_t dump(int fd, const Vector<String16>& args) const;
private:
friend class MediaPlayerService;
explicit MetadataRetrieverClient(pid_t pid);
virtual ~MetadataRetrieverClient();
mutable Mutex mLock;
sp<MediaMetadataRetrieverBase> mRetriever;
pid_t mPid;
// Keep the shared memory copy of album art and capture frame (for thumbnail)
sp<IMemory> mAlbumArt;
sp<IMemory> mThumbnail;
};
}; // namespace android
#endif // ANDROID_MEDIAMETADATARETRIEVERSERVICE_H
@@ -0,0 +1,564 @@
/* MidiFile.cpp
**
** 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 "MidiFile"
#include "utils/Log.h"
#include <stdio.h>
#include <assert.h>
#include <limits.h>
#include <unistd.h>
#include <fcntl.h>
#include <sched.h>
#include <utils/threads.h>
#include <libsonivox/eas_reverb.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "MidiFile.h"
#ifdef HAVE_GETTID
static pid_t myTid() { return gettid(); }
#else
static pid_t myTid() { return getpid(); }
#endif
// ----------------------------------------------------------------------------
namespace android {
// ----------------------------------------------------------------------------
// The midi engine buffers are a bit small (128 frames), so we batch them up
static const int NUM_BUFFERS = 4;
// TODO: Determine appropriate return codes
static status_t ERROR_NOT_OPEN = -1;
static status_t ERROR_OPEN_FAILED = -2;
static status_t ERROR_EAS_FAILURE = -3;
static status_t ERROR_ALLOCATE_FAILED = -4;
static const S_EAS_LIB_CONFIG* pLibConfig = NULL;
MidiFile::MidiFile() :
mEasData(NULL), mEasHandle(NULL), mAudioBuffer(NULL),
mPlayTime(-1), mDuration(-1), mState(EAS_STATE_ERROR),
mStreamType(AudioSystem::MUSIC), mLoop(false), mExit(false),
mPaused(false), mRender(false), mTid(-1)
{
LOGV("constructor");
mFileLocator.path = NULL;
mFileLocator.fd = -1;
mFileLocator.offset = 0;
mFileLocator.length = 0;
// get the library configuration and do sanity check
if (pLibConfig == NULL)
pLibConfig = EAS_Config();
if ((pLibConfig == NULL) || (LIB_VERSION != pLibConfig->libVersion)) {
LOGE("EAS library/header mismatch");
goto Failed;
}
// initialize EAS library
if (EAS_Init(&mEasData) != EAS_SUCCESS) {
LOGE("EAS_Init failed");
goto Failed;
}
// select reverb preset and enable
EAS_SetParameter(mEasData, EAS_MODULE_REVERB, EAS_PARAM_REVERB_PRESET, EAS_PARAM_REVERB_CHAMBER);
EAS_SetParameter(mEasData, EAS_MODULE_REVERB, EAS_PARAM_REVERB_BYPASS, EAS_FALSE);
// create playback thread
{
Mutex::Autolock l(mMutex);
createThreadEtc(renderThread, this, "midithread", ANDROID_PRIORITY_AUDIO);
mCondition.wait(mMutex);
LOGV("thread started");
}
// indicate success
if (mTid > 0) {
LOGV(" render thread(%d) started", mTid);
mState = EAS_STATE_READY;
}
Failed:
return;
}
status_t MidiFile::initCheck()
{
if (mState == EAS_STATE_ERROR) return ERROR_EAS_FAILURE;
return NO_ERROR;
}
MidiFile::~MidiFile() {
LOGV("MidiFile destructor");
release();
}
status_t MidiFile::setDataSource(
const char* path, const KeyedVector<String8, String8> *) {
LOGV("MidiFile::setDataSource url=%s", path);
Mutex::Autolock lock(mMutex);
// file still open?
if (mEasHandle) {
reset_nosync();
}
// open file and set paused state
mFileLocator.path = strdup(path);
mFileLocator.fd = -1;
mFileLocator.offset = 0;
mFileLocator.length = 0;
EAS_RESULT result = EAS_OpenFile(mEasData, &mFileLocator, &mEasHandle);
if (result == EAS_SUCCESS) {
updateState();
}
if (result != EAS_SUCCESS) {
LOGE("EAS_OpenFile failed: [%d]", (int)result);
mState = EAS_STATE_ERROR;
return ERROR_OPEN_FAILED;
}
mState = EAS_STATE_OPEN;
mPlayTime = 0;
return NO_ERROR;
}
status_t MidiFile::setDataSource(int fd, int64_t offset, int64_t length)
{
LOGV("MidiFile::setDataSource fd=%d", fd);
Mutex::Autolock lock(mMutex);
// file still open?
if (mEasHandle) {
reset_nosync();
}
// open file and set paused state
mFileLocator.fd = dup(fd);
mFileLocator.offset = offset;
mFileLocator.length = length;
EAS_RESULT result = EAS_OpenFile(mEasData, &mFileLocator, &mEasHandle);
updateState();
if (result != EAS_SUCCESS) {
LOGE("EAS_OpenFile failed: [%d]", (int)result);
mState = EAS_STATE_ERROR;
return ERROR_OPEN_FAILED;
}
mState = EAS_STATE_OPEN;
mPlayTime = 0;
return NO_ERROR;
}
status_t MidiFile::prepare()
{
LOGV("MidiFile::prepare");
Mutex::Autolock lock(mMutex);
if (!mEasHandle) {
return ERROR_NOT_OPEN;
}
EAS_RESULT result;
if ((result = EAS_Prepare(mEasData, mEasHandle)) != EAS_SUCCESS) {
LOGE("EAS_Prepare failed: [%ld]", result);
return ERROR_EAS_FAILURE;
}
updateState();
return NO_ERROR;
}
status_t MidiFile::prepareAsync()
{
LOGV("MidiFile::prepareAsync");
status_t ret = prepare();
// don't hold lock during callback
if (ret == NO_ERROR) {
sendEvent(MEDIA_PREPARED);
} else {
sendEvent(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ret);
}
return ret;
}
status_t MidiFile::start()
{
LOGV("MidiFile::start");
Mutex::Autolock lock(mMutex);
if (!mEasHandle) {
return ERROR_NOT_OPEN;
}
// resuming after pause?
if (mPaused) {
if (EAS_Resume(mEasData, mEasHandle) != EAS_SUCCESS) {
return ERROR_EAS_FAILURE;
}
mPaused = false;
updateState();
}
mRender = true;
// wake up render thread
LOGV(" wakeup render thread");
mCondition.signal();
return NO_ERROR;
}
status_t MidiFile::stop()
{
LOGV("MidiFile::stop");
Mutex::Autolock lock(mMutex);
if (!mEasHandle) {
return ERROR_NOT_OPEN;
}
if (!mPaused && (mState != EAS_STATE_STOPPED)) {
EAS_RESULT result = EAS_Pause(mEasData, mEasHandle);
if (result != EAS_SUCCESS) {
LOGE("EAS_Pause returned error %ld", result);
return ERROR_EAS_FAILURE;
}
}
mPaused = false;
return NO_ERROR;
}
status_t MidiFile::seekTo(int position)
{
LOGV("MidiFile::seekTo %d", position);
// hold lock during EAS calls
{
Mutex::Autolock lock(mMutex);
if (!mEasHandle) {
return ERROR_NOT_OPEN;
}
EAS_RESULT result;
if ((result = EAS_Locate(mEasData, mEasHandle, position, false))
!= EAS_SUCCESS)
{
LOGE("EAS_Locate returned %ld", result);
return ERROR_EAS_FAILURE;
}
EAS_GetLocation(mEasData, mEasHandle, &mPlayTime);
}
sendEvent(MEDIA_SEEK_COMPLETE);
return NO_ERROR;
}
status_t MidiFile::pause()
{
LOGV("MidiFile::pause");
Mutex::Autolock lock(mMutex);
if (!mEasHandle) {
return ERROR_NOT_OPEN;
}
if ((mState == EAS_STATE_PAUSING) || (mState == EAS_STATE_PAUSED)) return NO_ERROR;
if (EAS_Pause(mEasData, mEasHandle) != EAS_SUCCESS) {
return ERROR_EAS_FAILURE;
}
mPaused = true;
return NO_ERROR;
}
bool MidiFile::isPlaying()
{
LOGV("MidiFile::isPlaying, mState=%d", int(mState));
if (!mEasHandle || mPaused) return false;
return (mState == EAS_STATE_PLAY);
}
status_t MidiFile::getCurrentPosition(int* position)
{
LOGV("MidiFile::getCurrentPosition");
if (!mEasHandle) {
LOGE("getCurrentPosition(): file not open");
return ERROR_NOT_OPEN;
}
if (mPlayTime < 0) {
LOGE("getCurrentPosition(): mPlayTime = %ld", mPlayTime);
return ERROR_EAS_FAILURE;
}
*position = mPlayTime;
return NO_ERROR;
}
status_t MidiFile::getDuration(int* duration)
{
LOGV("MidiFile::getDuration");
{
Mutex::Autolock lock(mMutex);
if (!mEasHandle) return ERROR_NOT_OPEN;
*duration = mDuration;
}
// if no duration cached, get the duration
// don't need a lock here because we spin up a new engine
if (*duration < 0) {
EAS_I32 temp;
EAS_DATA_HANDLE easData = NULL;
EAS_HANDLE easHandle = NULL;
EAS_RESULT result = EAS_Init(&easData);
if (result == EAS_SUCCESS) {
result = EAS_OpenFile(easData, &mFileLocator, &easHandle);
}
if (result == EAS_SUCCESS) {
result = EAS_Prepare(easData, easHandle);
}
if (result == EAS_SUCCESS) {
result = EAS_ParseMetaData(easData, easHandle, &temp);
}
if (easHandle) {
EAS_CloseFile(easData, easHandle);
}
if (easData) {
EAS_Shutdown(easData);
}
if (result != EAS_SUCCESS) {
return ERROR_EAS_FAILURE;
}
// cache successful result
mDuration = *duration = int(temp);
}
return NO_ERROR;
}
status_t MidiFile::release()
{
LOGV("MidiFile::release");
Mutex::Autolock l(mMutex);
reset_nosync();
// wait for render thread to exit
mExit = true;
mCondition.signal();
// wait for thread to exit
if (mAudioBuffer) {
mCondition.wait(mMutex);
}
// release resources
if (mEasData) {
EAS_Shutdown(mEasData);
mEasData = NULL;
}
return NO_ERROR;
}
status_t MidiFile::reset()
{
LOGV("MidiFile::reset");
Mutex::Autolock lock(mMutex);
return reset_nosync();
}
// call only with mutex held
status_t MidiFile::reset_nosync()
{
LOGV("MidiFile::reset_nosync");
// close file
if (mEasHandle) {
EAS_CloseFile(mEasData, mEasHandle);
mEasHandle = NULL;
}
if (mFileLocator.path) {
free((void*)mFileLocator.path);
mFileLocator.path = NULL;
}
if (mFileLocator.fd >= 0) {
close(mFileLocator.fd);
}
mFileLocator.fd = -1;
mFileLocator.offset = 0;
mFileLocator.length = 0;
mPlayTime = -1;
mDuration = -1;
mLoop = false;
mPaused = false;
mRender = false;
return NO_ERROR;
}
status_t MidiFile::setLooping(int loop)
{
LOGV("MidiFile::setLooping");
Mutex::Autolock lock(mMutex);
if (!mEasHandle) {
return ERROR_NOT_OPEN;
}
loop = loop ? -1 : 0;
if (EAS_SetRepeat(mEasData, mEasHandle, loop) != EAS_SUCCESS) {
return ERROR_EAS_FAILURE;
}
return NO_ERROR;
}
status_t MidiFile::createOutputTrack() {
if (mAudioSink->open(pLibConfig->sampleRate, pLibConfig->numChannels, AudioSystem::PCM_16_BIT, 2) != NO_ERROR) {
LOGE("mAudioSink open failed");
return ERROR_OPEN_FAILED;
}
return NO_ERROR;
}
int MidiFile::renderThread(void* p) {
return ((MidiFile*)p)->render();
}
int MidiFile::render() {
EAS_RESULT result = EAS_FAILURE;
EAS_I32 count;
int temp;
bool audioStarted = false;
LOGV("MidiFile::render");
// allocate render buffer
mAudioBuffer = new EAS_PCM[pLibConfig->mixBufferSize * pLibConfig->numChannels * NUM_BUFFERS];
if (!mAudioBuffer) {
LOGE("mAudioBuffer allocate failed");
goto threadExit;
}
// signal main thread that we started
{
Mutex::Autolock l(mMutex);
mTid = myTid();
LOGV("render thread(%d) signal", mTid);
mCondition.signal();
}
while (1) {
mMutex.lock();
// nothing to render, wait for client thread to wake us up
while (!mRender && !mExit)
{
LOGV("MidiFile::render - signal wait");
mCondition.wait(mMutex);
LOGV("MidiFile::render - signal rx'd");
}
if (mExit) {
mMutex.unlock();
break;
}
// render midi data into the input buffer
//LOGV("MidiFile::render - rendering audio");
int num_output = 0;
EAS_PCM* p = mAudioBuffer;
for (int i = 0; i < NUM_BUFFERS; i++) {
result = EAS_Render(mEasData, p, pLibConfig->mixBufferSize, &count);
if (result != EAS_SUCCESS) {
LOGE("EAS_Render returned %ld", result);
}
p += count * pLibConfig->numChannels;
num_output += count * pLibConfig->numChannels * sizeof(EAS_PCM);
}
// update playback state and position
// LOGV("MidiFile::render - updating state");
EAS_GetLocation(mEasData, mEasHandle, &mPlayTime);
EAS_State(mEasData, mEasHandle, &mState);
if((mState != EAS_STATE_STOPPED) && (mPlayTime >= mDuration))
mState = EAS_STATE_STOPPED;
mMutex.unlock();
// create audio output track if necessary
if (!mAudioSink->ready()) {
LOGV("MidiFile::render - create output track");
if (createOutputTrack() != NO_ERROR)
goto threadExit;
}
// Write data to the audio hardware
// LOGV("MidiFile::render - writing to audio output");
if ((temp = mAudioSink->write(mAudioBuffer, num_output)) < 0) {
LOGE("Error in writing:%d",temp);
return temp;
}
// start audio output if necessary
if (!audioStarted) {
//LOGV("MidiFile::render - starting audio");
mAudioSink->start();
audioStarted = true;
}
// still playing?
if ((mState == EAS_STATE_STOPPED) || (mState == EAS_STATE_ERROR) ||
(mState == EAS_STATE_PAUSED))
{
switch(mState) {
case EAS_STATE_STOPPED:
{
LOGV("MidiFile::render - stopped");
sendEvent(MEDIA_PLAYBACK_COMPLETE);
break;
}
case EAS_STATE_ERROR:
{
LOGE("MidiFile::render - error");
sendEvent(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN);
break;
}
case EAS_STATE_PAUSED:
LOGV("MidiFile::render - paused");
break;
default:
break;
}
mAudioSink->stop();
audioStarted = false;
mRender = false;
}
}
threadExit:
mAudioSink.clear();
if (mAudioBuffer) {
delete [] mAudioBuffer;
mAudioBuffer = NULL;
}
mMutex.lock();
mTid = -1;
mCondition.signal();
mMutex.unlock();
return result;
}
status_t MidiFile::setParameters(const String8& params) {
return NO_ERROR;
}
} // end namespace android
@@ -0,0 +1,83 @@
/*
**
** 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_MIDIFILE_H
#define ANDROID_MIDIFILE_H
#include <media/MediaPlayerInterface.h>
#include <media/AudioTrack.h>
#include <libsonivox/eas.h>
namespace android {
class MidiFile : public MediaPlayerInterface {
public:
MidiFile();
~MidiFile();
virtual status_t initCheck();
virtual status_t setDataSource(
const char* path, 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 SONIVOX_PLAYER; }
virtual status_t invoke(const Parcel& request, Parcel *reply) {
return INVALID_OPERATION;
}
virtual status_t setParameters(const String8& params);
private:
status_t createOutputTrack();
status_t reset_nosync();
static int renderThread(void*);
int render();
void updateState(){ EAS_State(mEasData, mEasHandle, &mState); }
Mutex mMutex;
Condition mCondition;
EAS_DATA_HANDLE mEasData;
EAS_HANDLE mEasHandle;
EAS_PCM* mAudioBuffer;
EAS_I32 mPlayTime;
EAS_I32 mDuration;
EAS_STATE mState;
EAS_FILE mFileLocator;
int mStreamType;
bool mLoop;
volatile bool mExit;
bool mPaused;
volatile bool mRender;
pid_t mTid;
};
}; // namespace android
#endif // ANDROID_MIDIFILE_H
@@ -0,0 +1,92 @@
/*
**
** 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 "MidiMetadataRetriever"
#include <utils/Log.h>
#include "MidiMetadataRetriever.h"
#include <media/mediametadataretriever.h>
namespace android {
static status_t ERROR_NOT_OPEN = -1;
static status_t ERROR_OPEN_FAILED = -2;
static status_t ERROR_EAS_FAILURE = -3;
static status_t ERROR_ALLOCATE_FAILED = -4;
void MidiMetadataRetriever::clearMetadataValues()
{
LOGV("clearMetadataValues");
mMetadataValues[0][0] = '\0';
}
status_t MidiMetadataRetriever::setDataSource(const char *url)
{
LOGV("setDataSource: %s", url? url: "NULL pointer");
Mutex::Autolock lock(mLock);
clearMetadataValues();
if (mMidiPlayer == 0) {
mMidiPlayer = new MidiFile();
}
// TODO: support headers in MetadataRetriever interface!
return mMidiPlayer->setDataSource(url, NULL /* headers */);
}
status_t MidiMetadataRetriever::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 (mMidiPlayer == 0) {
mMidiPlayer = new MidiFile();
}
return mMidiPlayer->setDataSource(fd, offset, length);;
}
const char* MidiMetadataRetriever::extractMetadata(int keyCode)
{
LOGV("extractMetdata: key(%d)", keyCode);
Mutex::Autolock lock(mLock);
if (mMidiPlayer == 0 || mMidiPlayer->initCheck() != NO_ERROR) {
LOGE("Midi player is not initialized yet");
return NULL;
}
switch (keyCode) {
case METADATA_KEY_DURATION:
{
if (mMetadataValues[0][0] == '\0') {
int duration = -1;
if (mMidiPlayer->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;
}
};
@@ -0,0 +1,49 @@
/*
**
** 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_MIDIMETADATARETRIEVER_H
#define ANDROID_MIDIMETADATARETRIEVER_H
#include <utils/threads.h>
#include <utils/Errors.h>
#include <media/MediaMetadataRetrieverInterface.h>
#include "MidiFile.h"
namespace android {
class MidiMetadataRetriever : public MediaMetadataRetrieverInterface {
public:
MidiMetadataRetriever() {}
~MidiMetadataRetriever() {}
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<MidiFile> mMidiPlayer;
char mMetadataValues[1][MAX_METADATA_STRING_LENGTH];
};
}; // namespace android
#endif // ANDROID_MIDIMETADATARETRIEVER_H
@@ -0,0 +1,255 @@
/*
* Modified by The Linux Foundation
*
* Copyright (c) 2011, The Linux Foundation. All rights reserved.
*
* 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 "StagefrightPlayer"
#include <utils/Log.h>
#include "StagefrightPlayer.h"
#include "AwesomePlayer.h"
#include <media/Metadata.h>
#include <media/stagefright/MediaExtractor.h>
namespace android {
StagefrightPlayer::StagefrightPlayer()
: mPlayer(new AwesomePlayer) {
LOGV("StagefrightPlayer");
mPlayer->setListener(this);
}
StagefrightPlayer::~StagefrightPlayer() {
LOGV("~StagefrightPlayer");
reset();
delete mPlayer;
mPlayer = NULL;
}
status_t StagefrightPlayer::initCheck() {
LOGV("initCheck");
return OK;
}
status_t StagefrightPlayer::setDataSource(
const char *url, const KeyedVector<String8, String8> *headers) {
LOGI("setDataSource('%s')", url);
return mPlayer->setDataSource(url, headers);
}
// Warning: The filedescriptor passed into this method will only be valid until
// the method returns, if you want to keep it, dup it!
status_t StagefrightPlayer::setDataSource(int fd, int64_t offset, int64_t length) {
LOGV("setDataSource(%d, %lld, %lld)", fd, offset, length);
return mPlayer->setDataSource(dup(fd), offset, length);
}
status_t StagefrightPlayer::setVideoSurface(const sp<ISurface> &surface) {
LOGV("setVideoSurface");
mPlayer->setISurface(surface);
return OK;
}
status_t StagefrightPlayer::prepare() {
return mPlayer->prepare();
}
status_t StagefrightPlayer::prepareAsync() {
return mPlayer->prepareAsync();
}
status_t StagefrightPlayer::start() {
LOGV("start");
return mPlayer->play();
}
status_t StagefrightPlayer::stop() {
LOGV("stop");
return pause(); // what's the difference?
}
status_t StagefrightPlayer::pause() {
LOGV("pause");
return mPlayer->pause();
}
bool StagefrightPlayer::isPlaying() {
LOGV("isPlaying");
return mPlayer->isPlaying();
}
status_t StagefrightPlayer::seekTo(int msec) {
LOGV("seekTo");
status_t err = mPlayer->seekTo((int64_t)msec * 1000);
return err;
}
status_t StagefrightPlayer::getCurrentPosition(int *msec) {
LOGV("getCurrentPosition");
int64_t positionUs;
status_t err = mPlayer->getPosition(&positionUs);
if (err != OK) {
return err;
}
*msec = (positionUs + 500) / 1000;
return OK;
}
status_t StagefrightPlayer::getDuration(int *msec) {
LOGV("getDuration");
int64_t durationUs;
status_t err = mPlayer->getDuration(&durationUs);
if (err != OK) {
*msec = 0;
return OK;
}
*msec = (durationUs + 500) / 1000;
return OK;
}
status_t StagefrightPlayer::reset() {
LOGV("reset");
mPlayer->reset();
return OK;
}
status_t StagefrightPlayer::setLooping(int loop) {
LOGV("setLooping");
return mPlayer->setLooping(loop);
}
player_type StagefrightPlayer::playerType() {
LOGV("playerType");
return STAGEFRIGHT_PLAYER;
}
status_t StagefrightPlayer::suspend() {
LOGV("suspend");
return mPlayer->suspend();
}
status_t StagefrightPlayer::resume() {
LOGV("resume");
return mPlayer->resume();
}
status_t StagefrightPlayer::invoke(const Parcel &request, Parcel *reply) {
#ifndef YUVCLIENT
return INVALID_OPERATION;
#else
LOGV("invoke");
int msg = request.readInt32();
status_t err;
switch (msg) {
case MEDIA_INVOKE_REGISTER_BUFFERS:
{
int numFrames = request.readInt32(); // number of frame buffers
int frameSize = request.readInt32(); // size of frame buffers
sp<IMemoryHeap> memoryHeap = interface_cast<IMemoryHeap>(request.readStrongBinder());
LOGV("%d frame buffer of %d bytes registered, memoryHeap ID %d, base 0x%08lX, total size %d", numFrames, frameSize, memoryHeap->getHeapID(), memoryHeap->getBase(), memoryHeap->getSize());
err = mPlayer->registerFrameBufferHeap(memoryHeap, numFrames, frameSize);
break;
}
case MEDIA_INVOKE_UNREGISTER_BUFFERS:
LOGV("unregister buffers");
err = mPlayer->unregisterFrameBufferHeap();
break;
case MEDIA_INVOKE_QUEUE_BUFFER:
{
int frame = request.readInt32();
LOGV("frame buffer %d returned", frame);
err = mPlayer->queueFrameBuffer(frame);
break;
}
case MEDIA_INVOKE_QUERY_BUFFER_FORMAT:
{
int format;
err = mPlayer->queryBufferFormat(&format);
reply->writeInt32(format);
break;
}
default:
LOGV("unknown invoke message %d", msg);
return INVALID_OPERATION;
}
reply->writeInt32(static_cast<int32_t>(err));
return OK; // the transaction is always good if reaches here, the detailed request's reply is embedded in the reply parcel
#endif
}
void StagefrightPlayer::setAudioSink(const sp<AudioSink> &audioSink) {
MediaPlayerInterface::setAudioSink(audioSink);
mPlayer->setAudioSink(audioSink);
}
status_t StagefrightPlayer::getMetadata(
const media::Metadata::Filter& ids, Parcel *records) {
using media::Metadata;
uint32_t flags = mPlayer->flags();
Metadata metadata(records);
metadata.appendBool(
Metadata::kPauseAvailable,
flags & MediaExtractor::CAN_PAUSE);
metadata.appendBool(
Metadata::kSeekBackwardAvailable,
flags & MediaExtractor::CAN_SEEK_BACKWARD);
metadata.appendBool(
Metadata::kSeekForwardAvailable,
flags & MediaExtractor::CAN_SEEK_FORWARD);
metadata.appendBool(
Metadata::kSeekAvailable,
flags & MediaExtractor::CAN_SEEK);
return OK;
}
status_t StagefrightPlayer::setParameters(const String8& params) {
LOGV("setParameters(%s)", params.string());
return mPlayer->setParameters(params);
}
} // namespace android
@@ -0,0 +1,69 @@
/*
**
** 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_STAGEFRIGHTPLAYER_H
#define ANDROID_STAGEFRIGHTPLAYER_H
#include <media/MediaPlayerInterface.h>
namespace android {
struct AwesomePlayer;
class StagefrightPlayer : public MediaPlayerInterface {
public:
StagefrightPlayer();
virtual ~StagefrightPlayer();
virtual status_t initCheck();
virtual status_t setDataSource(
const char *url, 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);
virtual status_t prepare();
virtual status_t prepareAsync();
virtual status_t start();
virtual status_t stop();
virtual status_t pause();
virtual bool isPlaying();
virtual status_t seekTo(int msec);
virtual status_t getCurrentPosition(int *msec);
virtual status_t getDuration(int *msec);
virtual status_t reset();
virtual status_t setLooping(int loop);
virtual player_type playerType();
virtual status_t invoke(const Parcel &request, Parcel *reply);
virtual void setAudioSink(const sp<AudioSink> &audioSink);
virtual status_t suspend();
virtual status_t resume();
virtual status_t getMetadata(
const media::Metadata::Filter& ids, Parcel *records);
virtual status_t setParameters(const String8& params);
private:
AwesomePlayer *mPlayer;
StagefrightPlayer(const StagefrightPlayer &);
StagefrightPlayer &operator=(const StagefrightPlayer &);
};
} // namespace android
#endif // ANDROID_STAGEFRIGHTPLAYER_H
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,157 @@
/*
* Copyright (C) 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 STAGEFRIGHT_RECORDER_H_
#define STAGEFRIGHT_RECORDER_H_
#include <media/MediaRecorderBase.h>
#include <utils/String8.h>
namespace android {
class Camera;
struct MediaSource;
struct MediaWriter;
struct AudioSource;
class MediaProfiles;
struct StagefrightRecorder : public MediaRecorderBase {
StagefrightRecorder();
virtual ~StagefrightRecorder();
virtual status_t init();
virtual status_t setAudioSource(audio_source as);
virtual status_t setVideoSource(video_source vs);
virtual status_t setOutputFormat(output_format of);
virtual status_t setAudioEncoder(audio_encoder ae);
virtual status_t setVideoEncoder(video_encoder ve);
virtual status_t setVideoSize(int width, int height);
virtual status_t setVideoFrameRate(int frames_per_second);
virtual status_t setCamera(const sp<ICamera>& camera);
virtual status_t setPreviewSurface(const sp<ISurface>& surface);
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<IMediaRecorderClient>& listener);
virtual status_t setCameraParameters(const String8& params);
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;
virtual status_t takeLiveSnapshot();
private:
enum CameraFlags {
FLAGS_SET_CAMERA = 1L << 0,
FLAGS_HOT_CAMERA = 1L << 1,
};
sp<Camera> mCamera;
sp<ISurface> mPreviewSurface;
sp<IMediaRecorderClient> mListener;
sp<MediaWriter> mWriter;
sp<AudioSource> mAudioSourceNode;
audio_source mAudioSource;
video_source mVideoSource;
output_format mOutputFormat;
audio_encoder mAudioEncoder;
video_encoder mVideoEncoder;
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;
int32_t mRotationDegrees; // Clockwise
int32_t mLatitude;
int32_t mLongitude;
String8 mParams;
int mOutputFd;
int32_t mFlags;
MediaProfiles *mEncoderProfiles;
bool mDisableAudio;
bool mWriteCtts;
status_t startMPEG4Recording();
status_t startAMRRecording();
status_t startFMA2DPWriter();
status_t startAACRecording();
status_t startRTPRecording();
status_t startMPEG2TSRecording();
sp<MediaSource> createAudioSource();
status_t setupCameraSource();
status_t setupAudioEncoder(const sp<MediaWriter>& writer);
status_t setupVideoEncoder(sp<MediaSource> *source);
// 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 setParamVideoRotation(int32_t degrees);
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);
status_t setParamVideoLatitude(int32_t latitude);
status_t setParamVideoLongitude(int32_t longitude);
void clipVideoBitRate();
void clipVideoFrameRate();
void clipVideoFrameWidth();
void clipVideoFrameHeight();
StagefrightRecorder(const StagefrightRecorder &);
StagefrightRecorder &operator=(const StagefrightRecorder &);
/* extension */
status_t startExtendedRecording();
};
} // namespace android
#endif // STAGEFRIGHT_RECORDER_H_
@@ -0,0 +1,200 @@
/*
* Copyright (C) 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 "TestPlayerStub"
#include "utils/Log.h"
#include "TestPlayerStub.h"
#include <dlfcn.h> // for dlopen/dlclose
#include <stdlib.h>
#include <string.h>
#include <cutils/properties.h>
#include <utils/Errors.h> // for status_t
#include "media/MediaPlayerInterface.h"
namespace {
using android::status_t;
using android::MediaPlayerBase;
const char *kTestUrlScheme = "test:";
const char *kUrlParam = "url=";
const char *kBuildTypePropName = "ro.build.type";
const char *kEngBuild = "eng";
const char *kTestBuild = "test";
// @return true if the current build is 'eng' or 'test'.
bool isTestBuild()
{
char prop[PROPERTY_VALUE_MAX] = { '\0', };
property_get(kBuildTypePropName, prop, '\0');
return strcmp(prop, kEngBuild) == 0 || strcmp(prop, kTestBuild) == 0;
}
// @return true if the url scheme is 'test:'
bool isTestUrl(const char *url)
{
return url && strncmp(url, kTestUrlScheme, strlen(kTestUrlScheme)) == 0;
}
} // anonymous namespace
namespace android {
TestPlayerStub::TestPlayerStub()
:mUrl(NULL), mFilename(NULL), mContentUrl(NULL),
mHandle(NULL), mNewPlayer(NULL), mDeletePlayer(NULL),
mPlayer(NULL) { }
TestPlayerStub::~TestPlayerStub()
{
resetInternal();
}
status_t TestPlayerStub::initCheck()
{
return isTestBuild() ? OK : INVALID_OPERATION;
}
// Parse mUrl to get:
// * The library to be dlopened.
// * The url to be passed to the real setDataSource impl.
//
// mUrl is expected to be in following format:
//
// test:<name of the .so>?url=<url for setDataSource>
//
// The value of the url parameter is treated as a string (no
// unescaping of illegal charaters).
status_t TestPlayerStub::parseUrl()
{
if (strlen(mUrl) < strlen(kTestUrlScheme)) {
resetInternal();
return BAD_VALUE;
}
char *i = mUrl + strlen(kTestUrlScheme);
mFilename = i;
while (*i != '\0' && *i != '?') {
++i;
}
if (*i == '\0' || strncmp(i + 1, kUrlParam, strlen(kUrlParam)) != 0) {
resetInternal();
return BAD_VALUE;
}
*i = '\0'; // replace '?' to nul-terminate mFilename
mContentUrl = i + 1 + strlen(kUrlParam);
return OK;
}
// Load the dynamic library.
// Create the test player.
// Call setDataSource on the test player with the url in param.
status_t TestPlayerStub::setDataSource(
const char *url, const KeyedVector<String8, String8> *headers) {
if (!isTestUrl(url) || NULL != mHandle) {
return INVALID_OPERATION;
}
mUrl = strdup(url);
status_t status = parseUrl();
if (OK != status) {
resetInternal();
return status;
}
::dlerror(); // Clears any pending error.
// Load the test player from the url. dlopen will fail if the lib
// is not there. dls are under /system/lib
// None of the entry points should be NULL.
mHandle = ::dlopen(mFilename, RTLD_NOW | RTLD_GLOBAL);
if (!mHandle) {
LOGE("dlopen failed: %s", ::dlerror());
resetInternal();
return UNKNOWN_ERROR;
}
// Load the 2 entry points to create and delete instances.
const char *err;
mNewPlayer = reinterpret_cast<NEW_PLAYER>(dlsym(mHandle,
"newPlayer"));
err = ::dlerror();
if (err || mNewPlayer == NULL) {
// if err is NULL the string <null> is inserted in the logs =>
// mNewPlayer was NULL.
LOGE("dlsym for newPlayer failed %s", err);
resetInternal();
return UNKNOWN_ERROR;
}
mDeletePlayer = reinterpret_cast<DELETE_PLAYER>(dlsym(mHandle,
"deletePlayer"));
err = ::dlerror();
if (err || mDeletePlayer == NULL) {
LOGE("dlsym for deletePlayer failed %s", err);
resetInternal();
return UNKNOWN_ERROR;
}
mPlayer = (*mNewPlayer)();
return mPlayer->setDataSource(mContentUrl, headers);
}
// Internal cleanup.
status_t TestPlayerStub::resetInternal()
{
if(mUrl) {
free(mUrl);
mUrl = NULL;
}
mFilename = NULL;
mContentUrl = NULL;
if (mPlayer) {
LOG_ASSERT(mDeletePlayer != NULL, "mDeletePlayer is null");
(*mDeletePlayer)(mPlayer);
mPlayer = NULL;
}
if (mHandle) {
::dlclose(mHandle);
mHandle = NULL;
}
return OK;
}
/* static */ bool TestPlayerStub::canBeUsed(const char *url)
{
return isTestBuild() && isTestUrl(url);
}
status_t TestPlayerStub::setParameters(const String8& params) {
return NO_ERROR;
}
} // namespace android
@@ -0,0 +1,121 @@
/*
* Copyright (C) 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_FRAMEWORKS_BASE_MEDIA_LIBMEDIAPLAYERSERVICE_TESTPLAYERSTUB_H__
#define ANDROID_FRAMEWORKS_BASE_MEDIA_LIBMEDIAPLAYERSERVICE_TESTPLAYERSTUB_H__
#include <media/MediaPlayerInterface.h>
#include <utils/Errors.h>
namespace android {
class MediaPlayerBase; // in media/MediaPlayerInterface.h
// Wrapper around a test media player that gets dynamically loaded.
//
// The URL passed to setDataSource has this format:
//
// test:<name of the .so>?url=<url for the real setDataSource impl.>
//
// e.g:
// test:invoke_test_media_player.so?url=http://youtube.com/
// test:invoke_test_media_player.so?url=speedtest
//
// TestPlayerStub::setDataSource loads the library in the test url. 2
// entry points with C linkage are expected. One to create the test
// player and one to destroy it.
//
// extern "C" android::MediaPlayerBase* newPlayer();
// extern "C" android::status_t deletePlayer(android::MediaPlayerBase *p);
//
// Once the test player has been loaded, its setDataSource
// implementation is called with the value of the 'url' parameter.
//
// typical usage in a java test:
// ============================
//
// MediaPlayer p = new MediaPlayer();
// p.setDataSource("test:invoke_mock_media_player.so?url=http://youtube.com");
// p.prepare();
// ...
// p.release();
class TestPlayerStub : public MediaPlayerInterface {
public:
typedef MediaPlayerBase* (*NEW_PLAYER)();
typedef status_t (*DELETE_PLAYER)(MediaPlayerBase *);
TestPlayerStub();
virtual ~TestPlayerStub();
// Called right after the constructor. Check if the current build
// allows test players.
virtual status_t initCheck();
// @param url Should be a test url. See class comment.
virtual status_t setDataSource(
const char* url, const KeyedVector<String8, String8> *headers);
// Test player for a file descriptor source is not supported.
virtual status_t setDataSource(int, int64_t, int64_t) {
return INVALID_OPERATION;
}
// All the methods below wrap the mPlayer instance.
virtual status_t setVideoSurface(const android::sp<android::ISurface>& s) {
return mPlayer->setVideoSurface(s);
}
virtual status_t prepare() {return mPlayer->prepare();}
virtual status_t prepareAsync() {return mPlayer->prepareAsync();}
virtual status_t start() {return mPlayer->start();}
virtual status_t stop() {return mPlayer->stop();}
virtual status_t pause() {return mPlayer->pause();}
virtual bool isPlaying() {return mPlayer->isPlaying();}
virtual status_t seekTo(int msec) {return mPlayer->seekTo(msec);}
virtual status_t getCurrentPosition(int *p) {
return mPlayer->getCurrentPosition(p);
}
virtual status_t getDuration(int *d) {return mPlayer->getDuration(d);}
virtual status_t reset() {return mPlayer->reset();}
virtual status_t setLooping(int b) {return mPlayer->setLooping(b);}
virtual player_type playerType() {return mPlayer->playerType();}
virtual status_t invoke(const android::Parcel& in, android::Parcel *out) {
return mPlayer->invoke(in, out);
}
virtual status_t setParameters(const String8& params);
// @return true if the current build is 'eng' or 'test' and the
// url's scheme is 'test:'
static bool canBeUsed(const char *url);
private:
// Release the player, dlclose the library.
status_t resetInternal();
status_t parseUrl();
char *mUrl; // test:foo.so?url=http://bar
char *mFilename; // foo.so
char *mContentUrl; // http://bar
void *mHandle; // returned by dlopen
NEW_PLAYER mNewPlayer;
DELETE_PLAYER mDeletePlayer;
MediaPlayerBase *mPlayer; // wrapped player
};
} // namespace android
#endif