Android Camera video 数据流Surface设置原理

https://blog.csdn.net/haiping1224746757/article/details/107506453
继续之前的Video数据流进一步分析Surface的原理解析

private void startRecordingVideo() {
    if (null == mCameraDevice || !mTextureView.isAvailable() || null == mPreviewSize) {
        return;
    }
    try {
        // 关闭之前的会话,新的会话会添加录像的Target
        closePreviewSession();
        // 配置MediaRecorder,音频、视频来源,编码格式等
        setUpMediaRecorder();
        SurfaceTexture texture = mTextureView.getSurfaceTexture();
        assert texture != null;
        texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
        // 创建一个适合视频录制的请求
        mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
        List<Surface> surfaces = new ArrayList<>();

        // Set up Surface for the camera preview
        Surface previewSurface = new Surface(texture);
        surfaces.add(previewSurface);
        mPreviewBuilder.addTarget(previewSurface);

        // Set up Surface for the MediaRecorder 重要的一步,视频信息会交给mMediaRecorder处理
        Surface recorderSurface = mMediaRecorder.getSurface();
        surfaces.add(recorderSurface);
        mPreviewBuilder.addTarget(recorderSurface);

        // Start a capture session
        // Once the session starts, we can update the UI and start recording
        mCameraDevice.createCaptureSession(surfaces, new CameraCaptureSession.StateCallback() {

            @Override
            public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
                mPreviewSession = cameraCaptureSession;
                updatePreview();
                getActivity().runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        // UI
                        mButtonVideo.setText(R.string.stop);
                        mIsRecordingVideo = true;

                        // 开始录制
                        mMediaRecorder.start();
                    }
                });
            }

            @Override
            public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {
                Activity activity = getActivity();
                if (null != activity) {
                    Toast.makeText(activity, "Failed", Toast.LENGTH_SHORT).show();
                }
            }
        }, mBackgroundHandler);
    } catch (CameraAccessException | IOException e) {
        e.printStackTrace();
    }

}

在上面的代码中有一个地方,不知道有没有注意到:

  Surface recorderSurface = mMediaRecorder.getSurface();
        surfaces.add(recorderSurface);
        mPreviewBuilder.addTarget(recorderSurface);

这里的Surface是哪里来的,怎么MediaRecorder会get出Surface来,带着疑问往下看:
先进入MediaRecorder.java,主要讲述构造函数MediaRecorder()和prepare()函数

 //frameworks\base\media\java\android\media\MediaRecorder.java
       public MediaRecorder() {
       ....
        String packageName = ActivityThread.currentPackageName();
        /* Native setup requires a weak reference to our object.
         * It's easier to create it here than in C++.
         */
        native_setup(new WeakReference<MediaRecorder>(this), packageName,
                ActivityThread.currentOpPackageName());
    }
    
    public void prepare() throws IllegalStateException, IOException
    {  
        ...
        _prepare();
    }

_prepare是native 方法,定义如下:

//frameworks\base\media\java\android\media\MediaRecorder.java
  
    private native final void native_setup(Object mediarecorder_this,
            String clientName, String opPackageName) throws IllegalStateException;
            
    private native void _prepare() throws IllegalStateException, IOException;

咱们进入JNI 层具体看看实现

//frameworks\base\media\jni\android_media_MediaRecorder.cpp
static void android_media_MediaRecorder_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
                                       jstring packageName, jstring opPackageName)
{

  ...
  // 创建MediaRecorder
  sp<MediaRecorder> mr = new MediaRecorder(String16(opPackageNameStr.c_str()));

  // create new listener and give it to MediaRecorder
  sp<JNIMediaRecorderListener> listener = new JNIMediaRecorderListener(env, thiz, weak_this);
  mr->setListener(listener);

  // pass client package name for permissions tracking
  mr->setClientName(clientName);

}

static void android_media_MediaRecorder_prepare(JNIEnv *env, jobject thiz)
{

  sp<MediaRecorder> mr = getMediaRecorder(env, thiz);

//该处获取的surface为null
  jobject surface = env->GetObjectField(thiz, fields.surface);
  if (surface != NULL) {
     ....
  }
  //调用mr->prepare(),mediarecoder的surface是在该方法中完成创建的。
  process_media_recorder_call(env, mr->prepare(), "java/io/IOException", "prepare failed.");
}

进到mediarecorder.cpp类

//frameworks\av\media\libmedia\mediarecorder.cpp
//构造函数
MediaRecorder::MediaRecorder(const String16& opPackageName) : mSurfaceMediaSource(NULL)
{
    ALOGV("constructor");
   //获取IMediaPlayerService服务代理对象(实际是BpMediaPlayerService类对象)
    const sp<IMediaPlayerService> service(getMediaPlayerService());
    if (service != NULL) {
       //通过IMediaPlayerService服务创建IMediaRecorder(实际是BpMediaRecorder类)对象mMediaRecorder
        mMediaRecorder = service->createMediaRecorder(opPackageName);
    }
    if (mMediaRecorder != NULL) {
        mCurrentState = MEDIA_RECORDER_IDLE;
    }


    doCleanUp();
}

prepare 方法

//frameworks\av\media\libmedia\mediarecorder.cpp
status_t MediaRecorder::prepare()
{
    ALOGV("prepare");
    ...
    status_t ret = mMediaRecorder->prepare();
   ...
    return ret;
}

获取IMediaPlayerService服务代理的实现 代码:

// establish binder interface to MediaPlayerService
/*static*/const sp<IMediaPlayerService>
IMediaDeathNotifier::getMediaPlayerService()
{
    ALOGV("getMediaPlayerService");
    Mutex::Autolock _l(sServiceLock);
    if (sMediaPlayerService == 0) {
        sp<IServiceManager> sm = defaultServiceManager();
        sp<IBinder> binder;
        do {
            binder = sm->getService(String16("media.player"));
            if (binder != 0) {
                break;
            }
            ALOGW("Media player service not published, waiting...");
            usleep(500000); // 0.5 s
        } while (true);

        if (sDeathNotifier == NULL) {
            sDeathNotifier = new DeathNotifier();
        }
        binder->linkToDeath(sDeathNotifier);
        sMediaPlayerService = interface_cast<IMediaPlayerService>(binder);
    }
    ALOGE_IF(sMediaPlayerService == 0, "no media player service!?");
    return sMediaPlayerService;
}

IMediaPlayerService服务实现代码:

//rc 文件
//frameworks\av\media\mediaserver\mediaserver.rc
service media /system/bin/mediaserver
    class main
    user media
    group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrm
    ioprio rt 4
    writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks

至此,可见mMediaRecorder.getSurface()获取的surface实际上获取的是MediaCodecSource.cpp类成员变量mGraphicBufferProducer封装成 的surface对象。

//frameworks\av\media\libstagefright\MediaCodec.cpp
status_t MediaCodec::createInputSurface(
        sp<IGraphicBufferProducer>* bufferProducer) {
    sp<AMessage> msg = new AMessage(kWhatCreateInputSurface, this);

    sp<AMessage> response;
    //是通过发消息kWhatCreateInputSurface来创建的surface的
    //靠,还需要研究下AMessage的发送接收!!!哥已晕
    status_t err = PostAndAwaitResponse(msg, &response);
    if (err == NO_ERROR) {
        // unwrap the sp<IGraphicBufferProducer>
        sp<RefBase> obj;
        bool found = response->findObject("input-surface", &obj);
        CHECK(found);
        sp<BufferProducerWrapper> wrapper(
                static_cast<BufferProducerWrapper*>(obj.get()));
        *bufferProducer = wrapper->getBufferProducer();
    } else {
        ALOGW("createInputSurface failed, err=%d", err);
    }
    return err;
}

进如创建surface的流程

//frameworks\av\media\libstagefright\ACodec.cpp
void ACodec::LoadedState::onCreateInputSurface(
        const sp<AMessage> & /* msg */) {
    ALOGV("onCreateInputSurface");
     //创建surface
    sp<IGraphicBufferProducer> bufferProducer;
    //mOMX类型是sp<IOMX> mOMX,接下来分析下其创建过程
    status_t err = mCodec->mOMX->createInputSurface(
            &bufferProducer, &mCodec->mGraphicBufferSource);

    ...
}

继续分析surface 创建,现在进入OMX createInputSurface创建surface

//frameworks\av\media\libstagefright\omx\OMX.cpp
status_t OMX::createInputSurface(
        sp<IGraphicBufferProducer> *bufferProducer,
        sp<IGraphicBufferSource> *bufferSource) {
    if (bufferProducer == NULL || bufferSource == NULL) {
        ALOGE("b/25884056");
        return BAD_VALUE;
    }
   //创建GraphicBufferSource对象,surface就是在该方法创建出来的
    sp<GraphicBufferSource> graphicBufferSource = new GraphicBufferSource();
    status_t err = graphicBufferSource->initCheck();
    if (err != OK) {
        ALOGE("Failed to create persistent input surface: %s (%d)",
                strerror(-err), err);
        return err;
    }

    *bufferProducer = graphicBufferSource->getIGraphicBufferProducer();
    *bufferSource = new BWGraphicBufferSource(graphicBufferSource);

    return OK;
}
//frameworks\av\media\libstagefright\omx\GraphicBufferSource.cpp
GraphicBufferSource::GraphicBufferSource() {
    ALOGV("GraphicBufferSource");

    String8 name("GraphicBufferSource");
    //创建surface,千辛万苦,终于看到了surface的创建的地方了
    BufferQueue::createBufferQueue(&mProducer, &mConsumer);
    mConsumer->setConsumerName(name);

    // Note that we can't create an sp<...>(this) in a ctor that will not keep a
    // reference once the ctor ends, as that would cause the refcount of 'this'
    // dropping to 0 at the end of the ctor.  Since all we need is a wp<...>
    // that's what we create.
    wp<BufferQueue::ConsumerListener> listener =
            static_cast<BufferQueue::ConsumerListener*>(this);
    sp<IConsumerListener> proxy =
            new BufferQueue::ProxyConsumerListener(listener);

    mInitCheck = mConsumer->consumerConnect(proxy, false);

}

至此分析完成,mediarecorder创建其内部的surface流程

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
设置Android相机的镜像效果,您可以使用Camera.Parameters类中的setPreviewSize()方法来设置预览大小,然后调用setPreviewFpsRange()方法设置预览帧率范围。在设置预览大小和帧率之后,您可以使用setPreviewDisplay()方法将SurfaceView与相机绑定,并调用startPreview()方法开始预览。 如果您想要设置镜像效果,可以使用setPreviewSize()方法设置预览大小,并在Camera.Parameters类中使用setPreviewFlipped()方法来设置是否翻转预览。如果您想要水平翻转预览,可以将setPreviewFlipped()方法的第一个参数设置为true,第二个参数设置为false。如果您想要垂直翻转预览,可以将setPreviewFlipped()方法的第一个参数设置为false,第二个参数设置为true。 以下是一个示例代码片段,演示如何设置相机的镜像效果: ```java Camera camera = Camera.open(); Camera.Parameters parameters = camera.getParameters(); // 设置预览大小 parameters.setPreviewSize(640, 480); // 设置水平翻转预览 parameters.setPreviewFlipped(true, false); camera.setParameters(parameters); // 绑定SurfaceView并开始预览 SurfaceView surfaceView = findViewById(R.id.surface_view); SurfaceHolder surfaceHolder = surfaceView.getHolder(); camera.setPreviewDisplay(surfaceHolder); camera.startPreview(); ``` 在上面的代码中,我们使用setPreviewSize()方法设置预览大小为640x480,然后使用setPreviewFlipped()方法设置水平翻转预览。最后,我们将SurfaceView与相机绑定,并调用startPreview()方法开始预览。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值