MediaRecorder音视频框架

MediaRecorder音视频框架
阅代码工具:Source Insight
一、API简要说明
1.1 它Android平台上的一套多媒体API,负责音视频编码。里面编码格式集成丰富,视频录制、录音都可以使用它。作为纯APP开发的话,了解一些音视频参数设置及设置顺序就可以使用了。如果是基于平台去做定制的话,就需要对整个框架流程需要一定的熟悉,假如要扩展一个新的接口,或者更改某个接口功能。那么接下来一起来跟读吧。

二、框架图


三、代码跟读流程分析
MediaRecorder.java—>android_media_MediaRecorder.cpp—>mediarecorder.cpp—>
IMediaRecorder.cpp—>MediaRecorderClient.cpp—>StagefrightRecorder.cpp—>MPEG4Writer.cpp

3.1 MediaRecorder.java--SDK上封装的接口类
源码路径:frameworks/base/media/java/android/media/MediaRecorder.java
3.1.1 采用setCamera这个接口来进行跟读,注意Camera参数这个比较特殊。 System.loadLibrary("media_jni");调用JNI编译出来的libmedia_jni.so库
public class MediaRecorder
{
    static {
        System.loadLibrary("media_jni");
        native_init();
    }
    ...
    public native void setCamera(Camera c);
    ...
}

3.2  android_media_MediaRecorder.cpp--JNI接口类。库名:libmedia_jni.so
源码路径:frameworks/base/media/jni/android_media_MediaRecorder.cpp
3.2.1 MediaRecorder.java里面setCamera的JNI接口
static void android_media_MediaRecorder_setCamera(JNIEnv* env, jobject thiz, jobject camera)
{
    // we should not pass a null camera to get_native_camera() call.
    if (camera == NULL) {
        jniThrowNullPointerException(env, "camera object is a NULL pointer");
        return;
    }
    sp<Camera> c = get_native_camera(env, camera, NULL);
    if (c == NULL) {
        // get_native_camera will throw an exception in this case
        return;
    }
    sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
    process_media_recorder_call(env, mr->setCamera(c->remote(), c->getRecordingProxy()),
            "java/lang/RuntimeException", "setCamera failed.");
}
3.2.2 通过getMediaRecorder获取对象实例,调用下一层setCamera接口。const修饰类类型变量指针,表示其不可重新赋值,一次会话只能实例化一次内存地址。
static sp<MediaRecorder> getMediaRecorder(JNIEnv* env, jobject thiz)
{
    Mutex::Autolock l(sLock);
    MediaRecorder* const p = (MediaRecorder*)env->GetLongField(thiz, fields.context);
    return sp<MediaRecorder>(p);
}
3.2.3 JNI里面添加函数需要注册
static JNINativeMethod gMethods[] = {
    {"setCamera",            "(Landroid/hardware/Camera;)V",    (void *)android_media_MediaRecorder_setCamera},
    ...
};
1、第一个字符串表示java层函数名
2、()里面java层函数参数类型(L+包名;),括号外面是返回值类型V表示void
3、JNI函数指针
// 注册位置
// This function only registers the native methods, and is called from
// JNI_OnLoad in android_media_MediaPlayer.cpp
int register_android_media_MediaRecorder(JNIEnv *env)
{
    return AndroidRuntime::registerNativeMethods(env,
                "android/media/MediaRecorder", gMethods, NELEM(gMethods));
}

3.3  mediarecorder.cpp--就是上一层getMediaRecorder实例化的对象
源码路径:frameworks/av/media/libmedia/mediarecorder.cpp
3.3.1 上面JNI中的 android_media_MediaRecorder_setCamera函数 mr->setCamera(c->remote(), c->getRecordingProxy()
status_t MediaRecorder::setCamera(const sp<ICamera>& camera, const sp<ICameraRecordingProxy>& proxy)
{
    ALOGV("setCamera(%p,%p)", camera.get(), proxy.get());
    if (mMediaRecorder == NULL) {
        ALOGE("media recorder is not initialized yet");
        return INVALID_OPERATION;
    }
    if (!(mCurrentState & MEDIA_RECORDER_IDLE)) {
        ALOGE("setCamera called in an invalid state(%d)", mCurrentState);
        return INVALID_OPERATION;
    }

    status_t ret = mMediaRecorder->setCamera(camera, proxy);
    if (OK != ret) {
        ALOGV("setCamera failed: %d", ret);
        mCurrentState = MEDIA_RECORDER_ERROR;
        return ret;
    }
    return ret;
}
3.3.2 这部分不是JNI语法,已经是标准C++语法。所以必须要在头文件种声明函数原型。
结合头部文件可以看出,cpp函数里面调用到了IMediaRecorder对象中的setCamera
3.3.3 源码路径: frameworks/av/include/media/mediarecorder.h
class MediaRecorder : public BnMediaRecorderClient,
                      public virtual IMediaDeathNotifier
{
public:
...
    status_t    setCamera(const sp<ICamera>& camera, const sp<ICameraRecordingProxy>& proxy);
...

private:
...
    sp<IMediaRecorder>          mMediaRecorder;
...
};

3.4  IMediaRecorder.cpp--这部分采用了IBinder通信
源码路径:frameworks/av/media/libmedia/IMediaRecorder.cpp
3.4.1 首先得在枚举量中添加一个符号常量
enum {
    RELEASE = IBinder::FIRST_CALL_TRANSACTION,
...
    SET_CAMERA,
...
};
3.4.2 实现函数部分
class BpMediaRecorder: public BpInterface<IMediaRecorder>
{
public:
...
    status_t setCamera(const sp<ICamera>& camera, const sp<ICameraRecordingProxy>& proxy)
    {
        ALOGV("setCamera(%p,%p)", camera.get(), proxy.get());
        Parcel data, reply;
        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
        data.writeStrongBinder(camera->asBinder());
        data.writeStrongBinder(proxy->asBinder());
        remote()->transact(SET_CAMERA, data, &reply);
        return reply.readInt32();
    }
...
};
3.4.3 transact调用
status_t BnMediaRecorder::onTransact(
                                     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    switch (code) {
        case SET_CAMERA: {
            ALOGV("SET_CAMERA");
            CHECK_INTERFACE(IMediaRecorder, data, reply);
            sp<ICamera> camera = interface_cast<ICamera>(data.readStrongBinder());
            sp<ICameraRecordingProxy> proxy =
                interface_cast<ICameraRecordingProxy>(data.readStrongBinder());
            reply->writeInt32(setCamera(camera, proxy));
            return NO_ERROR;
        } break;
        default:
            return BBinder::onTransact(code, data, reply, flags);
    }
}
3.4.4 函数原型
源码路径:frameworks/av/include/media/IMediaRecorder.h
class IMediaRecorder: public IInterface
{
public:
    ...
    virtual status_t setCamera(const sp<ICamera>& camera,
                               const sp<ICameraRecordingProxy>& proxy) = 0;
    ...
};

3.5  MediaRecorderClient.cpp
源码路径:frameworks/av/media/libmediaplayerservice/MediaRecorderClient.cpp
3.5.1 这里的mRecorder是MediaRecorderBase类变量指针,而MediaRecorderBase只是一个.h头文件。
它是一个基类,定义了函数原型,由StagefrightRecorder去继承实现,从这里看出接下来调到了StagefrightRecorder里面的setCamera具体实现。
status_t MediaRecorderClient::setCamera(const sp<ICamera>& camera,
                                        const sp<ICameraRecordingProxy>& proxy)
{
    ALOGV("setCamera");
    Mutex::Autolock lock(mLock);
    if (mRecorder == NULL) {
        ALOGE("recorder is not initialized");
        return NO_INIT;
    }
    return mRecorder->setCamera(camera, proxy);
}
3.5.2  MediaRecorderClient.cpp函数原型
源码路径: frameworks/av/media/libmediaplayerservice/MediaRecorderClient.h
class MediaRecorderClient : public BnMediaRecorder
{
public:
    virtual     status_t   setCamera(const sp<ICamera>& camera,
                                    const sp<ICameraRecordingProxy>& proxy);
    ...
    MediaRecorderBase      *mRecorder;
};

3.6  StagefrightRecorder.cpp--看到了这里也就马上到尽头了,MPEG4Writer封装类就是在这里实例化的。
源码路径:frameworks/av/media/libmediaplayerservice/StagefrightRecorder.cpp
3.6.1 mCamera这个全局首先会在setupCameraSource配置, setupCameraSource会在setupMediaSource进行调用,这里不co代码出来了。
status_t StagefrightRecorder::setCamera(const sp<ICamera> &camera,
                                        const sp<ICameraRecordingProxy> &proxy) {
    ALOGV("setCamera");
    if (camera == 0) {
        ALOGE("camera is NULL");
        return BAD_VALUE;
    }
    if (proxy == 0) {
        ALOGE("camera proxy is NULL");
        return BAD_VALUE;
    }

    mCamera = camera;
    mCameraProxy = proxy;
    return OK;
}
3.6.2 实例化文件封装类,准备进入封装流程
status_t StagefrightRecorder::setupMPEG4orWEBMRecording() {
    ...
    writer = new MPEG4Writer(mOutputFd);
    ...
    // 实例化对象之后调用setupMediaSource把参数设置下去
}
3.6.3 函数原型:
源码路径:frameworks/av/media/libmediaplayerservice/StagefrightRecorder.h
<span style="font-size:14px;">struct StagefrightRecorder : public MediaRecorderBase {
    ...
    virtual status_t setCamera(const sp<ICamera>& camera, const sp<ICameraRecordingProxy>& proxy);
    ...
}</span>
3.6.4 跟读到这差不多了,根据流程可以添加自己想要添加的接口了。从这里就可以调用到MPEG4Writer.cpp
例如:
status_t StagefrightRecorder::test() {
    if (mWriter == NULL) {
        ALOGE("File writer is not avaialble");
    }
    mWriter->test();
    return OK;
}

3.7 MPEG4Writer.cpp--媒体文件封装类,这个cpp需要单独拿出来讲,所以这里不做过多介绍。阅读此封装类之前需要熟悉多媒体文件封装流程。
源码路径:frameworks/av/media/libstagefright/MPEG4Writer.cpp
源码路径:frameworks/av/include/media/stagefright/MPEG4Writer.h

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值