MediaRecorder类介绍
找到个MediaRecorder类介绍和大家分享一下。
Mediarecorder类在官网的介绍和在系统代码中的运用
四、audioflinger层和audiorecord. 14
1 类得介绍
它用来记录音频和视频,记录控制基于一个简单的状态机,下边的图片是整个流程
2 嵌套、关联的类
|
class |
定义音频编码 |
|
|
class |
定义声音资源 |
|
|
interface |
Interface definition for a callback to be invoked when an error occurs while recording. |
|
|
interface |
Interface definition for a callback to be invoked when an error occurs while recording. |
|
|
class |
定义输出格式 |
|
|
class |
定义视频编码 |
|
|
class |
定义视频source |
|
3 主要方法:
|
final static int |
Gets the maximum value for audio sources. 获取音频信号源的最高值。 |
|
int |
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 Pass in the file descriptor for the auxiliary time lapse video. 在文件描述符传递的辅助时间的推移视频 |
|
void |
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 Register a callback to be invoked when an error occurs while recording. 注册一个回调被调用发生错误时,同时录制 |
|
void |
setOnInfoListener(MediaRecorder.OnInfoListener 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 |
Sets a Surface to show a preview of recorded media (video). 表面设置显示记录媒体(视频)的预览 |
|
void |
setProfile(CamcorderProfile 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.
MediaRecorder类介绍的更多相关文章
- Android开发之MediaRecorder类详解
MediaRecorder类介绍: MediaRecorder类是Android sdk提供的一个专门用于音视频录制,一般利用手机麦克风采集音频,摄像头采集图片信息. MediaRecorder主要函 ...
- CYQ.Data.Orm.DBFast 新增类介绍(含类的源码及新版本配置工具源码)
前言: 以下功能在国庆期就完成并提前发布了,但到今天才有时间写文介绍,主要是国庆后还是选择就职了,悲催的是上班的地方全公司都能上网,唯独开发部竟不让上网,是个局域网. 也不是全不能上,房间里有三台能上 ...
- Object类介绍
一.Object类介绍
- istringstream、ostringstream、stringstream 类介绍 .
istringstream.ostringstream.stringstream 类介绍 . 转自:http://www.cnblogs.com/gamesky/archive/2013/01/09/ ...
- C#中的Dictionary字典类介绍
Dictionary字典类介绍 必须包含名空间System.Collection.Generic Dictionary里面的每一个元素都是一个键值对(由二个元素组成:键和值) 键必须是 ...
- POI 导出导入工具类介绍
介绍: Apache POI是Apache软件基金会的开源项目,POI提供API给Java程序对Microsoft Office格式档案读和写的功能. .NET的开发人员则可以利用NPOI (POI ...
- Android Paint类介绍以及浮雕和阴影效果的设置
Paint类介绍 Paint即画笔,在绘制文本和图形用它来设置图形颜色, 样式等绘制信息. 1.图形绘制 setARGB(int a,int r,int g,int b); 设置绘制的颜色,a代表透明 ...
- Unity3D核心类介绍
脚本介绍与Unity核心类介绍 -------------------------------------------------------------------------------- 脚本介 ...
- istringstream、ostringstream、stringstream 类介绍 和 stringstream类 clear函数的真正用途
istringstream.ostringstream.stringstream 类介绍 和 stringstream类 clear函数的真正用途 来源: http://blog.csdn.net/T ...
随机推荐
- Android进阶笔记19:onInterceptTouchEvent、onTouchEvent与onTouch
1.onTouch方法:onTouch方法是View的 OnTouchListener借口中定义的方法,处理View及其子类被touch是的事件处理.当一个View绑定了OnTouchLister后, ...
- Java基础知识强化之IO流笔记75:NIO之 Scatter / Gather
1. Java NIO开始支持scatter/gather,scatter/gather用于描述从Channel(译者注:Channel在中文经常翻译为通道)中读取或者写入到Channel的操作. 分 ...
- 【Android 界面效果39】android:inputType问题
1. 在XML代码中实现比较简单, 直接设置android:inputType="textMultiLine": [mw_shl_code=java,true]<EditT ...
- OnTouchListener事件监听实现方式之GestureDetector
当用户触摸屏幕的时候,会产生许多手势,例如down,up,scroll,filing等等. 一般情况下,我们知道View类有个View.OnTouchListener内部接口,通过重写他的onTouc ...
- self.view添加UIView时添加动画
CATransition *animation = [CATransition animation]; animation.delegate = self; animation.duration = ...
- 【trim()】去掉字符串开头和结尾的空格,防止不必要的空格导致的错误。
去掉字符串开头和结尾的空格,防止不必要的空格导致的错误. public static void main(String arg[]){ String a=" abc"; Strin ...
- springMVC第一课--配置文件
刚学springMVC,记录下学习过程,供以后查阅(githup源码). 1,新建一个web工程.(其他按常规来) 如下:添加applicationContext.xml,webmvc-servlet ...
- 北大ACM(POJ1008-Maya Calendar)
Question:http://poj.org/problem?id=1008 问题点:日历转换. Memory: 280K Time: 16MS Language: C++ Result: Acce ...
- Zend studio 12.5.1破解过程
开始学习php了 今天又安装了一下Zend 之前找了很久的教程终于成了 , 今天换了一台电脑需要重新安装一下 又点忘记了. 就讲这个过程写下来 1.安装zend studio 12.5.1.这个过程 ...
- wsus安装与部署——下
转载请注明原出处 write by xiaoyang 一. 测试 1. 使用客户机或者在域环境下编辑GPO打开组策略 2. 配置自动更新 3. ...