资料:本文基于android 7.1.2 版本源码分析。
功能:MediaRecorder即可以录制音频,也可以录制视频。
附上相关内容:
【二】Android MediaRecorder C++底层架构音视频处理过程和音视频同步源码分析
【三】Android MediaRecorder C++底层架构音视频处理过程和音视频同步源码分析
【四】Android MediaRecorder C++底层架构音视频处理过程和音视频同步源码分析
【五】Android MediaRecorder C++底层架构音视频处理过程和音视频同步源码分析
一、 MediaRecorder整体框架图
1.1、 MediaRecorder整体层级关系图 – 各个具体类之间的依赖关系图:
概要总结:
如上在运行时,整个MediaRecorder大致上可以分为Client和Server两个部分,分别在两个进程中运行,它们之间使用Binder机制实现IPC通信。
MediaPlayerService是多媒体框架中非常重要的一个服务,从框架图中可以看出,MediaRecorder是客户端,MediaPlayerService和MediaRecorderClient是服务器端,MediaPlayerService实现了IMediaPlayerService(接口类)定义的业务逻辑。MediaRecorderClient实现了IMediaRecorder(接口类)定义的业务逻辑,其主要功能包括prepare、start、pause、resume、stop、reset、release等。
C++/JNI层回调事件(JNI层:mr->setListener(listener):将回调接口类MediaRecorderListener设置给MediaRecorder)通知JAVA层是使用JNIMediaRecorderListener::notify(int msg, int ext1, int ext2),该方法通过调用MediaRecoder.java类中private static void postEventFromNative(Object mediarecorder_ref, int what, int arg1, int arg2, Object obj)方法在JNI中的方法句柄,把Native事件回调到Java层,然后使用EventHandler.java类 post 事件回到主线层。
C++层Binder通信总结:【另外章节分析】
Android C++底层Binder通信机制原理总结
1.2、 MediaRecorder State diagram 状态流转图:(一个简单的状态机)
此处图片直接引用于官方文档MediaRecorder.java简介:
https://developer.android.google.cn/reference/android/media/MediaRecorder.html#summary
这个状态迁移这里就不详细描述了,主要根据各个状态和触发的条件进行状态转换,图上是一个状态机的实现的说明已经足够了,不过值得注意的是还有两个状态函数是pause()【暂停】和resume()【恢复】录制功能,图上没有的。
二、 流程实现浅析
该部分主要是根据MediaRecorder在使用中的主要的各模块和代码层的调用流程来进行分析整体架构中涉及到的主要类关系及其实现关系等。
主要根据一个基本的录制音视频的调用流程开始分析:
1、创建:new MediaRecorder();
2、设置Camera:mRecorder.setCamera();
3、设置音频源(采集方式):mRecorder.setAudioSource();
4、设置视频源(采集方式):mRecorder.setVideoSource();
5、设置文件的输出格式:mRecorder.setOutputFormat();
6、设置Audio的编码格式(生成对应的编码器):mRecorder.setAudioEncoder();
7、设置Video的编码格式(生成对应的编码器):mRecorder.setVideoEncoder();
8、设置录制的视频编码比特率(每秒编码多少位bit):mRecorder.setVideoEncodingBitRate();
9、设置录制的视频帧率:mRecorder.setVideoFrameRate();
10、设置要捕获的视频的宽度和高度:mRecorder.setVideoSize();
11、设置记录会话的最大持续时间(毫秒):mRecorder.setMaxDuration();
12、设置一个Surface进行预览显示:mRecorder.setPreviewDisplay();
13、设置输出文件路径:mRecorder.setOutputFile();
14、准备录制:mRecorder.prepare();
15、开始录制:mRecorder.start();
16、暂停或恢复录制:mRecorder.pause()/resume();
17、停止录制:mRecorder.stop();
18、重置Recorder:mRecorder.reset();
19、释放Recorder资源:mRecorder.release();
如上:
1、 创建:new MediaRecorder() 源码
/**
* Default constructor.
*/
public MediaRecorder() {
// 定义一个Looper,当前线程或主线程中的Looper实现者,主要用于JNI层回调时切换到当前App端线程中
Looper looper;
if ((looper = Looper.myLooper()) != null) {
mEventHandler = new EventHandler(this, looper);
} else if ((looper = Looper.getMainLooper()) != null) {
mEventHandler = new EventHandler(this, looper);
} else {
mEventHandler = null;
}
String packageName = ActivityThread.currentPackageName();
// 创建MediaPlayer,在Native实现,使用弱引用
native_setup(new WeakReference<MediaRecorder>(this), packageName,
ActivityThread.currentOpPackageName());
}
// 静态代码中,加载和链接media_jni.so文件
static {
System.loadLibrary("media_jni");
native_init();
}
进入JNI层android_media_MediaRecorder.cpp的native_init()方法:
static void
android_media_MediaRecorder_native_init(JNIEnv *env)
{
// JNIEnv该类可以理解为一个万能指针表,通过操作符(->)访问JNI中的函数
// 类的class句柄
jclass clazz;
// 通过JNI层调用并获取JAVA层MediaRecorder对象
clazz = env->FindClass("android/media/MediaRecorder");
if (clazz == NULL) {
return;
}
// 获取java层成员变量mNativeContext,long类型,实际对应一个内存地址即Native层的MediaRecorder对象实例指针变量值转换的内存地址,用于缓存
fields.context = env->GetFieldID(clazz, "mNativeContext", "J");
if (fields.context == NULL) {
return;
}
// 获取java层成员变量mSurface
fields.surface = env->GetFieldID(clazz, "mSurface", "Landroid/view/Surface;");
if (fields.surface == NULL) {
return;
}
// 获取并存储一个回调JAVA层的静态回调函数,将native事件回调到java层
fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",
"(Ljava/lang/Object;IIILjava/lang/Object;)V");
if (fields.post_event == NULL) {
return;
}
}
// JNI层对应调用的Java 层静态方法回调函数,将native事件回调到java层,用弱引用指向原生的MediaRecorder对象,来保证native代码安全的,并使用Handler机制切换线程到主线程中。
private static void postEventFromNative(Object mediarecorder_ref,
int what, int arg1, int arg2, Object obj)
{
MediaRecorder mr = (MediaRecorder)((WeakReference)mediarecorder_ref).get();
if (mr == null) {
return;
}
if (mr.mEventHandler != null) {
Message m = mr.mEventHandler.obtainMessage(what, arg1, arg2, obj);
mr.mEventHandler.sendMessage(m);
}
}
前面构造函数中:native_setup实现函数分析
static void
android_media_MediaRecorder_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
jstring packageName, jstring opPackageName)
{
// 创建JNI层MediaRecorder实例
sp<MediaRecorder> mr = new MediaRecorder(String16(opPackageNameStr.c_str()));
// create new listener and give it to MediaRecorder
// 回调事件监听并设置,如此java层的回调监听就能起作用
sp<JNIMediaRecorderListener> listener = new JNIMediaRecorderListener(env, thiz, weak_this);
mr->setListener(listener);
// 该方法就是缓存当前创建的native层的MediaRecorder对象的指针变量值,用于缓存取用
setMediaRecorder(env, thiz, mr);
}
如此便设置了一些监听并创建了C++层对应实现的MediaRecorder对象。
再看C++层MediaRecorder构造函数
MediaRecorder::MediaRecorder(const String16& opPackageName) : mSurfaceMediaSource(NULL)
{