Android之mediarecorder中的方法以及工作流程的过程
?
|   class  |   MediaRecorder.AudioEncoder  |   定義音頻編碼  | 
|   class  |   MediaRecorder.AudioSource  |   定義聲音資源  | 
|   interface  |   MediaRecorder.OnErrorListener  |   Interface definition for a callback to be invoked when an error occurs while recording.?  | 
|   interface  |   MediaRecorder.OnInfoListener  |   Interface definition for a callback to be invoked when an error occurs while recording.?  | 
|   class  |   MediaRecorder.OutputFormat  |   定義輸出格式  | 
|   class  |   MediaRecorder.VideoEncoder  |   定義視頻編碼  | 
|   class  |   MediaRecorder.VideoSource  |   定義視頻source  | 
|   ?  |   ?  |   ?  | 
?
?
3?主要方法:
|   final static int  |   getAudioSourceMax() Gets the maximum value for audio sources. 獲取音頻信號源的最高值。 ?  | 
|   int  |   getMaxAmplitude() Returns the maximum absolute amplitude that was sampled since the last call to this method. 最后調用這個方法采樣的時候返回最大振幅的絕對值  | 
|   void  |   prepare() Prepares the recorder to begin capturing and encoding data. 準備recorder 開始捕獲和編碼數據  | 
|   void  |   release() Releases resources associated with this MediaRecorder object. 發布與此MediaRecorder對象關聯的資源  | 
|   void  |   reset() Restarts the MediaRecorder to its idle state. 重新啟動mediarecorder到空閑狀態  | 
|   void  |   setAudioChannels(int numChannels) Sets the number of audio channels for recording. 設置錄制的音頻通道數。 ?  | 
|   void  |   setAudioEncoder(int audio_encoder) Sets the audio encoder to be used for recording. 設置audio的編碼格式  | 
|   void  |   setAudioEncodingBitRate(int bitRate) Sets the audio encoding bit rate for recording. 設置錄制的音頻編碼比特率 ?  | 
|   void  |   setAudioSamplingRate(int samplingRate) Sets the audio sampling rate for recording. 設置錄制的音頻采樣率。 ?  | 
|   void  |   setAudioSource(int audio_source) Sets the audio source to be used for recording. 設置用于錄制的音源。 ?  | 
|   void  |   setAuxiliaryOutputFile(String?path) Pass in the file path for the auxiliary time lapse video. 輔助時間的推移視頻文件的路徑傳遞。  | 
|   void  |   setAuxiliaryOutputFile(FileDescriptor?fd) Pass in the file descriptor for the auxiliary time lapse video. 在文件描述符傳遞的輔助時間的推移視頻 ?  | 
|   void  |   setCamera(Camera?c) Sets a Camera to use for recording. 設置一個recording的攝像頭  | 
|   void  |   setCaptureRate(double fps) Set video frame capture rate. 設置視頻幀的捕獲率  | 
|   void  |   setMaxDuration(int max_duration_ms) Sets the maximum duration (in ms) of the recording session. 設置記錄會話的最大持續時間(毫秒)  | 
|   void  |   setMaxFileSize(long max_filesize_bytes) Sets the maximum filesize (in bytes) of the recording session. 設置記錄會話的最大大小(以字節為單位)  | 
|   void  |   setOnErrorListener(MediaRecorder.OnErrorListener?l) Register a callback to be invoked when an error occurs while recording. 注冊一個回調被調用發生錯誤時,同時錄制  | 
|   void  |   setOnInfoListener(MediaRecorder.OnInfoListener?listener) Register a callback to be invoked when an informational event occurs while recording. 注冊要同時記錄一個信息事件發生時調用的回調。 ?  | 
|   void  |   setOrientationHint(int degrees) Sets the orientation hint for output video playback. 設置輸出的視頻播放的方向提示  | 
|   void  |   setOutputFile(FileDescriptor?fd) Pass in the file descriptor of the file to be written. 傳遞要寫入的文件的文件描述符  | 
|   void  |   setOutputFile(String?path) Sets the path of the output file to be produced. 設置輸出文件的路徑  | 
|   void  |   setOutputFormat(int output_format) Sets the format of the output file produced during recording. 設置在錄制過程中產生的輸出文件的格式 ?  | 
|   void  |   setPreviewDisplay(Surface?sv) Sets a Surface to show a preview of recorded media (video). 表面設置顯示記錄媒體(視頻)的預覽  | 
|   void  |   setProfile(CamcorderProfile?profile) Uses the settings from a CamcorderProfile object for recording. 從一個記錄CamcorderProfile對象的使用設置  | 
|   void  |   setVideoEncoder(int video_encoder) Sets the video encoder to be used for recording. 設置視頻編碼器,用于錄制  | 
|   void  |   setVideoEncodingBitRate(int bitRate) Sets the video encoding bit rate for recording. 設置錄制的視頻編碼比特率。 ?  | 
|   void  |   setVideoFrameRate(int rate) Sets the frame rate of the video to be captured. 設置要捕獲的視頻幀速率  | 
|   void  |   setVideoSize(int width, int height) Sets the width and height of the video to be captured. 設置要捕獲的視頻的寬度和高度  | 
|   void  |   setVideoSource(int video_source) Sets the video source to be used for recording. 開始捕捉和編碼數據到setOutputFile(指定的文件)  | 
|   void  |   start() Begins capturing and encoding data to the file specified with setOutputFile(). ?  | 
|   void  |   stop() Stops recording. 停止recording  | 
?
?
視頻編碼格式:default,H263,H264,MPEG_4_SP
獲得視頻資源:default,CAMERA
音頻編碼格式:default,AAC,AMR_NB,AMR_WB,
獲得音頻資源:defalut,camcorder,mic,voice_call,voice_communication,voice_downlink, voice_recognition,? voice_uplink;
輸出方式:amr_nb,amr_wb,default,mpeg_4,raw_amr,three_gpp.
?
?
4?流程分析
一、 java層
media recorder state machine:
1、java應用層
java應用層主要是一些接口的調用,它并沒有具體功能代碼的實現,java應用層的代碼路徑為:
android/packages/apps/SoundRecorder/src/com/android/soundrecorder/
該目錄下有文件: SoundRecorder.java Recorder.java VUMeter.java
soundrecorder.java是程序的入口文件,我們在可以在里面設置文件輸出編碼格式的格式,現在系統默認支持兩種格式amr和3gpp格式。設置代碼如下:
mRequestedType =AUDIO_3GPP; //02 AUDIO_AMR;
接著運行mRecorder = new Recorder();創建一個Recorder類。Recorder類在Recorder.java中定義。
Recorder的startRecording方法啟動了java層的錄音。startRecording方法中首先創建一個Mediarecorder的類,然后調用Mediarecorder的方法完成設置audio源、設置輸出文件格式、audio編碼格式、設置輸出文件,然后檢查MediaRecorder是否準備好了。如果準備好就啟動。如果沒有準備好就拋出異常然后重新設置MediaRecorder和釋放MediaRecorder。代碼如下所示:
mRecorder = new MediaRecorder();
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mRecorder.setOutputFormat(outputfileformat);
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mRecorder.setOutputFile(mSampleFile.getAbsolutePath());
// Handle IOException
try {
mRecorder.prepare();
} catch(IOException exception) {
setError(INTERNAL_ERROR);
mRecorder.reset();
mRecorder.release();
mRecorder = null;
return;
}
mRecorder.start();
2、JAVA Framework層
Java的framework層代碼位于:
frameworks/base/media/java/android/media/MediaRecorder.java
它沒有具體的實現只是一個接口而已。
3、JAVA本地調用部分(JNI):
frameworks/base/media/jni/android_media_MediaRecorder.cpp
jni層的只是實現了方法的注冊,為java層調用C++程序提供一種注冊。
這三給部分的程序會編譯成一個libmedia_jni.so庫,java層序的調用都是調用該庫中的接口。具體的實現要要在我們的多媒體底層庫。
二、?多媒體底層庫
1、ImediaRecorder.cpp
Imediarecorder.cpp文件中實現了BP功能。BP和BN是通過binder來通信的。Bp主要是用來處理java層傳下來的服務請求。然后通過transact將處理請求傳給bn(通過binder)。其接口如下所示:
class BpMediaRecorder: public BpInterface
{
BpMediaRecorder(const sp& impl) : BpInterface(impl) {}
status_t setCamera(const sp& camera);
status_t setPreviewSurface(const sp& surface);
status_t init();
status_t setVideoSource(int vs);
status_t setAudioSource(int as);
status_t setOutputFormat(int of);
status_t setAudioEncoder(int ae);
status_t setOutputFile(const char* path);
status_t prepare();
status_t getMaxAmplitude(int* max);
…………………………
}
上面的每個函數中都用transact方法來向bn發出請求。然后調用return reply.readInt32();將從bn返回的數據傳送個他們的調用函數。
2、Mediarecorder.cpp
Bn的實現是在Mediarecorder.cpp文件中。BN是用來處理bp的請求,當bn將數將處理完后將數據通過transact傳給回bp(通過binder)。MediaRecorder.cpp文件的實現方法與ImediaRecorder,cpp對應,主要是用來接收ImediaRecorder發送過來的請求。
MediaRecorder::MediaRecorder()
{ LOGV("constructor");
sp sm = defaultServiceManager();
sp binder;
do {
binder =sm->getService(String16("media.player"));
if (binder != NULL) {
break;
}
usleep(500000); // 0.5 s
} while(true);
sp service = interface_cast(binder);
if (service != NULL) {
mMediaRecorder = service->createMediaRecorder(getpid());
}
if (mMediaRecorder != NULL) {
mCurrentState = MEDIA_RECORDER_IDLE;
}
doCleanUp();
}
該文件操作的方法是mMediaRecorder的方法,它主要是同過binder機制將請求傳輸送給mediarecorder的服務進程。
3、多媒體服務部分
mediaRecorder的服務文件是MediaRecorderClient.cpp,它主要調用的是PVMediaRecorder的實現方法,在此請求opencore的服務。
MediaRecorderClient::MediaRecorderClient(pid_t pid)
{
LOGV("Client constructor");
mPid = pid;
mRecorder = new PVMediaRecorder();
}
三、Opencore
我們先從pvmediarecorder.cpp文件分析。
在PVMediaRecorder中首先創建一個AuthorDriverWrapper的對象。PVMediaRecorder將它的方法通過author_command包裝。然后通過AuthorDriverWrapper的enqueueCommand將命令發送請求隊列中。
PVMediaRecorder的setOutputFile方法會打開我們上面指定的文件路徑下的文件,為寫文件作好準備。代碼如下:
int fd = open(path, O_RDWR | O_CREAT );
接著分析authordriver.cpp文件
AuthorDriverWrapper::AuthorDriverWrapper()
{
mAuthorDriver = new AuthorDriver();
}
我們在AuthorDriverWrapper首先創建一個AuthorDriver的對象.。我們來看AuthorDriverWrapper的enqueueCommand方法,可以看到,我們在pvmediarecorder中調用的enqueuecommand實際上調用的是authordriver的enqueuecommand方法。
status_t AuthorDriverWrapper::enqueueCommand(author_command*ac, media_completion_f comp, void *cookie)
{ if (mAuthorDriver) {
return mAuthorDriver->enqueueCommand(ac, comp, cookie);
}
return NO_INIT;
}
四、audioflinger層和audiorecord
1、AudioRecord
音頻系統的對外接口是AudioRecord,它通過iBinder來遠程調用Audioflinger的openRecorder函數。AudioRecord構造函數如下:
1:AudioRecord
AudioRecord::AudioRecord(
int streamType,
uint32_t sampleRate,
int format,
int channelCount,
int frameCount,
uint32_t flags,
callback_t cbf,
void* user,
int notificationFrames)
: mStatus(NO_INIT)
{
log_wj("ENTERIN::--%s---%s---\n",__FILE__,__FUNCTION__);
mStatus = set(streamType, sampleRate, format, channelCount,
frameCount, flags, cbf, user, notificationFrames);
}
調用:
status_t AudioRecord::set(int streamType,
uint32_t sampleRate,
int format,
int channelCount,
int frameCount,
uint32_t flags,
callback_t cbf,
void* user,
int notificationFrames,
bool threadCanCallJava)
{
const sp& audioFlinger = AudioSystem::get_audio_flinger();
//獲取緩存大小,間接調用我們修改過該函數(經過三次調用中轉),返回值為//channelCount*320
AudioSystem::getInputBufferSize(sampleRate, format,channelCount, &inputBuffSizeInBytes);
//遠程調用audioFlinger的openrecord函數,openRecord相當于audioflinger為audioRecord
//開辟相應的服務窗口
sp record = audioFlinger->openRecord(getpid(),streamType,
sampleRate, format,
channelCount,
frameCount,
((uint16_t)flags) << 16,
&status);
//創建一個線程用來處理
mClientRecordThread = new ClientRecordThread(*this,threadCanCallJava);
}
AudioRecord相當于一個代理,它的線程是用來處理其它客戶的請求。
2、AudioFlinger
sp AudioFlinger::openRecord(
pid_t pid,
int streamType,
uint32_t sampleRate,
int format,
int channelCount,
int frameCount,
uint32_t flags,
status_t *status)
{
// AudioRecord線程
if (mAudioRecordThread == 0) {
LOGE("Audio record thread not started");
lStatus = NO_INIT;
goto Exit;
}
// add client to list
{ // scope for mLock
Mutex::Autolock _l(mLock);
wclient = mClients.valueFor(pid);
if (wclient != NULL) {
client = wclient.promote();
} else {
client = new Client(this, pid);
mClients.add(pid, client);
}
// create new record track. The record track uses one trackin mHardwareMixerThread by //convention.
//生成一個recordTrack用來作為數據的中轉(audioflinger與audiorecord之間)。
//他們使用audio_track_cblk_t數據結構來傳輸數據。
recordTrack = new MixerThread::RecordTrack(mHardwareMixerThread,client, streamType, sampleRate, format, channelCount, frameCount, flags);
if (recordTrack->getCblk() == NULL) {
recordTrack.clear();
lStatus = NO_MEMORY;
goto Exit;
}
// return to handle to client------我們的audiorecord。
recordHandle = new RecordHandle(recordTrack);
}
AudioRecord和AudioFlinger操作的都是RecordTrack實例,AudioRecord通過它的執行控制操作(start/stop)和讀取操作(read)。Audiorecord的start/stop操作可以理解為一個開關,控制的是AudiorecordThread的運行與否。
Audioflinger則負責從音頻設備讀取數據放置到audio_track_cblk_t數據結構中。
Audioflinger對數據的讀取在AudioFlinger::AudioRecordThread::threadLoop()函數中。在第一次啟動的時候會打開一個AudioStreamIn的對象,并設置參數。
input =mAudioHardware->openInputStream(mRecordTrack->format(),
mRecordTrack->channelCount(),mRecordTrack->sampleRate(),
&mStartStatus,
(AudioSystem::audio_in_acoustics)(mRecordTrack->mFlags>> 16));
讀取數據的代碼如下:
if (LIKELY(mRecordTrack->getNextBuffer(&buffer) ==NO_ERROR&&
(int)buffer.frameCount == inFrameCount) ) {
ssize_t bytesRead = input->read(buffer.raw,inBufferSize);
mRecordTrack->releaseBuffer(&buffer);
mRecordTrack->overflow();
}
首先從audio_track_cblk_t取得緩沖區,然后調用input的read方法讀取數據,最后釋放緩沖區,檢查是否溢出。
五、?硬件抽象層
硬件抽象層主要實現了AudioStreamInALSA和AudioStreamOutALSA兩個類,這兩個類又會調用該文件下的ALSAStreamOps類的方法。AudioStreamInALSA是錄音部分調用的路徑。在AudioStreamInALSA的構造函數中會對alsa進行一些初始化參數設置。AudioStreamInALSA的read方法是最主要的方法,audioflinger層的read調用就是對AudioStreamInALSA的read的調用。由于錄音部分出現單聲道和雙聲道數據傳輸的問題,修改read方法如下,即可實現了錄音功能正常,避免了在編碼的時候修改數據時其他編碼仍不能工作的弊端。
ssize_t AudioStreamInALSA::read(void *buffer, ssize_tbytes)
{ snd_pcm_sframes_t n;
status_t err;
short int *tmp1,*tmp2;
int i;
AutoMutex lock(mLock);
tmp1=(short int *)malloc(bytes*2);
n = snd_pcm_readi(mHandle, tmp1,snd_pcm_bytes_to_frames(mHandle, bytes*2));
if (n < 0 && mHandle) {
n = snd_pcm_recover(mHandle, n, 0);
}
tmp2=(short int *)buffer;
for(i=0;i
{
tmp2[i]=tmp1[2*i];
}
free(tmp1);
return static_cast(n/2);
}
snd_pcm_readi調用的是alsa庫函數,跟蹤執行最終會調用alsa庫下的snd_pcm_hw_readi函數。snd_pcm_hw_readi會調用err = ioctl(fd,SNDRV_PCM_IOCTL_READI_FRAMES, &xferi);最終與kernel相聯系。
?
?
?
5主要能設置列舉
1 setAudioChannels(int numChannels) 設置錄制的音頻通道數。
2 setAudioEncoder(int audio_encoder) 設置audio的編碼格式
3 setAudioEncodingBitRate(int bitRate)? 設置錄制的音頻編碼比特率
4 setAudioSamplingRate(int samplingRate) 設置錄制的音頻采樣率。
5 setAudioSource(int audio_source) 設置用于錄制的音源。
6 setAuxiliaryOutputFile(String path)? 輔助時間的推移視頻文件的路徑傳遞。
7 setAuxiliaryOutputFile(FileDescriptor fd)在文件描述符傳遞的輔助時間的推移視頻
8 setCamera(Camera c) 設置一個recording的攝像頭
9 setCaptureRate(double fps) 設置視頻幀的捕獲率
10 setMaxDuration(int max_duration_ms) 設置記錄會話的最大持續時間(毫秒)
11 setMaxFileSize(long max_filesize_bytes) 設置記錄會話的最大大小(以字節為單位)
12 setOutputFile(FileDescriptor fd) 傳遞要寫入的文件的文件描述符
13 setOutputFile(String path)? 設置輸出文件的路徑
14 setOutputFormat(int output_format) 設置在錄制過程中產生的輸出文件的格式
15 setPreviewDisplay(Surface sv) 表面設置顯示記錄媒體(視頻)的預覽
16 setVideoEncoder(int video_encoder) 設置視頻編碼器,用于錄制
17 setVideoEncodingBitRate(int bitRate) 設置錄制的視頻編碼比特率。
18 setVideoFrameRate(int rate) 設置要捕獲的視頻幀速率
19 setVideoSize(int width, int height) 設置要捕獲的視頻的寬度和高度
20 setVideoSource(int video_source)? 開始捕捉和編碼數據到setOutputFile(指定的文件)
?
?
?
視頻編碼格式:default,H263,H264,MPEG_4_SP
獲得視頻資源:default,CAMERA
音頻編碼格式:default,AAC,AMR_NB,AMR_WB,
獲得音頻資源:defalut,camcorder,mic,voice_call,voice_communication,voice_downlink,
voice_recognition,? voice_uplink;
輸出方式:amr_nb,amr_wb,default,mpeg_4,raw_amr,three_gpp.
總結
以上是生活随笔為你收集整理的Android之mediarecorder中的方法以及工作流程的过程的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: C++ exception类
 - 下一篇: Android之用jadx进行反编译