音视频之进程间传递 YUV 格式视频流,解决不能同时调用 Camera 问题

栏目: IOS · Android · 发布时间: 7年前

内容简介:由于项目需求,需要在执法仪本地录像的时候,执法软件能正常的使用设备本身的 Camera 资源。由于 Android 系统自身不允许多个软件同时使用 Camera 资源,故开发一套

由于项目需求,需要在执法仪本地录像的时候,执法软件能正常的使用设备本身的 Camera 资源。由于 Android 系统自身不允许多个软件同时使用 Camera 资源,故开发一套 内存共享 子码流传输协议,当执法软件需要视频流的时候,向执法仪设备请求往 MemoryFile 中写入 YUV 格式的视频流,执法软件每隔一段时间循环的去指定的内存中 read YUV 视频流。

完整代码入口

流程图

音视频之进程间传递 YUV 格式视频流,解决不能同时调用 Camera 问题

效果图

  • 本地相机未打开

    音视频之进程间传递 YUV 格式视频流,解决不能同时调用 Camera 问题
  • 本地相机打开

    音视频之进程间传递 YUV 格式视频流,解决不能同时调用 Camera 问题

简要流程及示例代码说明

  1. 执法仪服务端收到客户端的开启视频流写入内存的指令

    //处理客服端发送过来的需要子码流的数据
        private void onHandleAction(Context context, Intent intent) {
            switch (intent.getAction()) {
                /**
                 * 需要子码流
                 */
                case Constants.ACTION_CAMERE_CORE_SHOW:
                    //如果正在发送视频流,就不需要执行后面代码了
                    if (!MemoryFileServiceManager.getInsta(context).isSendVideoFrame())
                        MemoryFileServiceManager.getInsta(context).setSendVideoFrame(true, intent);
                    break;
            }
        }
    复制代码
  2. 服务端获取开启视频的条件

    private void sendVideoFrame(Intent intent) {
            if (intent != null && intent.getExtras() != null) {
                Bundle extras = intent.getExtras();
                //获取需要预览的宽
                Constants.PREVIEWHEIGHT = extras.getInt(Constants.Config.PREVIEW_WIDTH, 1280);
                //获取需要预览的高
                Constants.PREVIEWHEIGHT = extras.getInt(Constants.Config.PREVIEW_HEIGHT, 720);
                //需要绑定对方服务的进程
                Constants.BIND_OTHER_SERVICE_PCK = extras.getString(Constants.Config.BIND_OTHER_SERVICE_PCK, "");
                //需要绑定对方服务的全路径
                Constants.BIND_OTHER_SERVICE_CLASS = extras.getString(Constants.Config.BIND_OTHER_SERVICE_CLASS, "");
                //需要开启 Camera ID 的前置还是后置 0:后置 1:前置
                Constants.CAMERA_ID = extras.getInt(Constants.Config.CAMERA_ID, 0);
            }
        }
    复制代码
  3. 服务器是否开启相机,如果已经开启则不需要开启

    //是否摄像头
            if (mCamera == null)
                openCamera();
    复制代码
  4. 服务端初始化一块内存,用于写入 YUV 视频流。

    mMemoryFile = initMemoryFile(Constants.MEMORY_FILE_NAME, Constants.MEMORY_SIZE);
    复制代码
  5. 绑定对方服务,提供文件描述符号

    /**
         * 绑定对方服务,提供 文件描述符
         */
        private void bindOtherService() {
            try {
                if (TextUtils.isEmpty(Constants.BIND_OTHER_SERVICE_PCK) || TextUtils.isEmpty(Constants.BIND_OTHER_SERVICE_CLASS))
                    throw new NullPointerException("PCK or CLSS is null ?");
                Intent intent = new Intent();
                ComponentName cmp = new ComponentName(Constants.BIND_OTHER_SERVICE_PCK, Constants.BIND_OTHER_SERVICE_CLASS);
                intent.setComponent(cmp);
                context.bindService(intent, mCameraServiceConnection, Context.BIND_AUTO_CREATE);
            } catch (Exception e) {
                Log.e(TAG, e.getMessage());
            }
        }
    复制代码
  6. 绑定对方服务成功,交于文件描述符 ParcelFileDescriptor

    mCameraService = ICameraCoreService.Stub.asInterface(binder);
                if (mMemoryFile != null) {
                    try {
                        //反射拿到文件描述符号
                        mParcelFileDescriptor = MemoryFileHelper.getParcelFileDescriptor(mMemoryFile);
                        if (mParcelFileDescriptor != null) {
                            mCameraService.addExportMemoryFile(mParcelFileDescriptor, Constants.PREVIEWWIDTH, Constants.PREVIEWHEIGHT, Constants.MEMORY_SIZE);
    
                        }
    复制代码
  7. 发送数据,当标志位为 byte[0] == 0 代表服务端可将 YUV 写入内存, == 1 ,代表客服端可以读取可用的 YUV 数据。

    /**
         * 读标志位 写入视频流
         *
         * @param memoryFile
         */
        public void writeBytes(MemoryFile memoryFile) {
            try {
                if (mYUVQueue.size() > 0) {
                    BufferBean mBufferBean = new BufferBean(Constants.BUFFER_SIZE);
                    //读取标志符号
                    memoryFile.readBytes(mBufferBean.isCanRead, 0, 0, 1);
                    //当第一位为 0 的时候,代表客服端已经读取了,可以正常将视频流写入内存中
                    if (mBufferBean.isCanRead[0] == 0) {
                        //拿到视频流
                        byte[] video = mYUVQueue.poll();
                        if (video != null)
                            //将视频流写入内存中
                            memoryFile.writeBytes(video, 0, 0, video.length);
                        //标志位复位,等待客服端读取视频流
                        mBufferBean.isCanRead[0] = 1;
                        memoryFile.writeBytes(mBufferBean.isCanRead, 0, 0, 1);
                    } else {
                        Log.d(TAG, "readShareBufferMsg isCanRead:" + mBufferBean.isCanRead[0] + ";length:"
                                + mBufferBean.mBuffer.length);
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
                sendBroadcast(Constants.ACTION_FEEDBACK, e.getMessage());
            }
        }
    复制代码
  8. 开启成功或者失败等其他错误消息反馈给客服端

    //返回给客服端   
    public void sendBroadcast(String action,String content) {
            Intent intent = new Intent();
            intent.setAction(action);
            ComponentName componentName = new ComponentName("com.t01.sharevideostream",
                    "com.t01.sharevideostream.revices.FeedBackReceiver");
            intent.setComponent(componentName);
            Bundle extras = new Bundle();
            extras.putString(Constants.ACTION_FEEDBACK_CONTENT, content);
            intent.putExtras(extras);
            context.sendBroadcast(intent);
        }
    复制代码

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。

知识的边界

知识的边界

[美] 戴维·温伯格 / 胡泳、高美 / 山西人民出版社 / 2014-12-1 / 42.00元

大数据时代反思知识 因为事实不再是事实,专家随处可见 所有确定性都被连根拔起,话题再无边界,没有人对任何事情能达成一致。 在互联网的引领下,知识现在已经具有了社交性,流动且开放。温伯格向我们展示了这些特点如何可以为我们所用。 ——马克•贝尼奥夫(云计算之父,著有《云攻略》) 这本富有洞见的著作,奠定了温伯格作为数字时代最重要的思想家之一的地位。如果你想要理解信息洪流涌......一起来看看 《知识的边界》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具