日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android之mediarecorder中的方法以及工作流程的过程

發布時間:2023/12/4 Android 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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中的方法以及工作流程的过程的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。