博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
EasyPusher进行Android UVC外接摄像头直播推送实现方法
阅读量:5239 次
发布时间:2019-06-14

本文共 7695 字,大约阅读时间需要 25 分钟。

最近EasyPusher针对UVC摄像头做了适配.我们结合了与EasyPusher,支持将UVC摄像头的视频推送到RTSP服务器上.在此特别感谢UVCCamera这个牛逼的项目!

来看看是怎么操作UVC摄像头的吧.我们实现了一个专门检测UVC摄像头的服务:UVCCameraService类,主要代码如下:

监听

mUSBMonitor = new USBMonitor(this, new USBMonitor.OnDeviceConnectListener() {            @Override            public void onAttach(final UsbDevice device) {                Log.v(TAG, "onAttach:" + device);                mUSBMonitor.requestPermission(device);            }            @Override            public void onConnect(final UsbDevice device, final USBMonitor.UsbControlBlock ctrlBlock, final boolean createNew) {                releaseCamera();                if (BuildConfig.DEBUG) Log.v(TAG, "onConnect:");                try {                    final UVCCamera camera = new MyUVCCamera();                    camera.open(ctrlBlock);                    camera.setStatusCallback(new IStatusCallback() {                    // ... uvc 摄像头链接成功                    Toast.makeText(UVCCameraService.this, "UVCCamera connected!", Toast.LENGTH_SHORT).show();                    if (device != null)                        cameras.append(device.getDeviceId(), camera);                }catch (Exception ex){                    ex.printStackTrace();                }            }            @Override            public void onDisconnect(final UsbDevice device, final USBMonitor.UsbControlBlock ctrlBlock) {              // ... uvc 摄像头断开链接                if (device != null) {                    UVCCamera camera = cameras.get(device.getDeviceId());                    if (mUVCCamera == camera) {                        mUVCCamera = null;                        Toast.makeText(UVCCameraService.this, "UVCCamera disconnected!", Toast.LENGTH_SHORT).show();                        liveData.postValue(null);                    }                    cameras.remove(device.getDeviceId());                }else {                    Toast.makeText(UVCCameraService.this, "UVCCamera disconnected!", Toast.LENGTH_SHORT).show();                    mUVCCamera = null;                    liveData.postValue(null);                }            }            @Override            public void onCancel(UsbDevice usbDevice) {                releaseCamera();            }            @Override            public void onDettach(final UsbDevice device) {                Log.v(TAG, "onDettach:");                releaseCamera();//                AppContext.getInstance().bus.post(new UVCCameraDisconnect());            }        });

这个类主要实现UVC摄像头的监听\链接\销毁\反监听.当有UVC摄像头链接成功后,会创建一个mUVCCamera对象.

然后在MediaStream里, 我们改造了switchCamera,当参数传2时,表示要切换到UVCCamera(0,1分别表示切换到后置\前置摄像头).

创建

在创建摄像头时,如果是要创建uvc摄像头,那直接从服务里面获取之前创建的mUVCCamera实例:

if (mCameraId == 2) {   UVCCamera value = UVCCameraService.liveData.getValue();   if (value != null) {     // uvc camera.     uvcCamera = value;     value.setPreviewSize(width, height,1, 30, UVCCamera.PIXEL_FORMAT_YUV420SP,1.0f);     return;     //            value.startPreview();   }else{     Log.i(TAG, "NO UVCCamera");     uvcError = new Exception("no uvccamera connected!");     return;   }   //            mCameraId = 0; }

预览

在预览时,如果uvc摄像头已经创建了,那执行uvc摄像头的预览操作:

UVCCamera value = uvcCamera;if (value != null) {  SurfaceTexture holder = mSurfaceHolderRef.get();  if (holder != null) {    value.setPreviewTexture(holder);  }  try {    value.setFrameCallback(uvcFrameCallback, UVCCamera.PIXEL_FORMAT_YUV420SP/*UVCCamera.PIXEL_FORMAT_NV21*/);    value.startPreview();    cameraPreviewResolution.postValue(new int[]{width, height});  }catch (Throwable e){    uvcError = e;  }}

这里我们选的colorFormat为PIXEL_FORMAT_YUV420SP 相当于标准摄像头的NV21格式.

关闭预览

同理,关闭时,调用的是uvc摄像头的关闭.

UVCCamera value = uvcCamera;        if (value != null) {            value.stopPreview();        }

销毁

因为我们这里并没有实质性的创建,所以销毁时也仅将实例置为null就可以了.

UVCCamera value = uvcCamera;if (value != null) {  //            value.destroy();  uvcCamera = null;}

有了这些操作,我们看看上层怎么调用,

首先需要在Manifest里面增加若干代码,具体详见UVCCamera工程说明.如下:

然后,的代码在UVCActivity里,这个类可以在library分支的myapplication工程里找到.即.

启动或者停止UVC摄像头推送:

public void onPush(View view) {      // 异步获取到MediaStream对象.        getMediaStream().subscribe(new Consumer
() { @Override public void accept(final MediaStream mediaStream) throws Exception { // 判断当前的推送状态. MediaStream.PushingState state = mediaStream.getPushingState(); if (state != null && state.state > 0) { // 当前正在推送,那终止推送和预览 mediaStream.stopStream(); mediaStream.closeCameraPreview(); }else{ // switch 0表示后置,1表示前置,2表示UVC摄像头 // 异步开启UVC摄像头 RxHelper.single(mediaStream.switchCamera(2), null).subscribe(new Consumer
() { @Override public void accept(Object o) throws Exception { // 开启成功,进行推送. // ... mediaStream.startStream("cloud.easydarwin.org", "554", id); } }, new Consumer
() { @Override public void accept(final Throwable t) throws Exception { // ooop...开启失败,提示下... t.printStackTrace(); runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(UVCActivity.this, "UVC摄像头启动失败.." + t.getMessage(), Toast.LENGTH_SHORT).show(); } }); } }); } } }); }

这样,整个推送就完成了.如果一切顺利,应当能在VLC播放出来UVC摄像头的视频了~~

我们再看看如何录像.也非常简单…

public void onRecord(View view) {       // 开始或结束录像.        final TextView txt = (TextView) view;        getMediaStream().subscribe(new Consumer
() { @Override public void accept(MediaStream mediaStream) throws Exception { if (mediaStream.isRecording()){ // 如果正在录像,那停止. mediaStream.stopRecord(); txt.setText("录像"); }else { // 没在录像,开始录像... // 表示最大录像时长为30秒,30秒后如果没有停止,会生成一个新文件.依次类推... // 文件格式为test_uvc_0.mp4,test_uvc_1.mp4,test_uvc_2.mp4,test_uvc_3.mp4 String path = getExternalFilesDir(Environment.DIRECTORY_MOVIES) + "/test_uvc.mp4"; mediaStream.startRecord(path, 30000); final TextView pushingStateText = findViewById(R.id.pushing_state); pushingStateText.append("\n录像地址:" + path); txt.setText("停止"); } } }); }

UVC摄像头还支持后台推送,即不预览的情况下进行推送,同时再切换到前台继续预览.只需要调用一个接口即可实现,如下:

@Overridepublic void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int i, int i1) {  ms.setSurfaceTexture(surfaceTexture); // 设置预览的surfaceTexture}@Overridepublic boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {  ms.setSurfaceTexture(null);           // 设置预览窗口为null,表示关闭预览功能  return true;}

如果要彻底退出uvc摄像头的预览\推送,那只需要同时退出服务即可.

public void onQuit(View view) {     // 退出  finish();  // 终止服务...  Intent intent = new Intent(this, MediaStream.class);  stopService(intent);}

## 获取更多信息 ##

邮件:

EasyDarwin开源流媒体服务器:

EasyDSS商用流媒体解决方案:

EasyNVR无插件直播方案:

Copyright © EasyDarwin Team 2012-2017

EasyDarwin

转载于:https://www.cnblogs.com/babosa/p/8206952.html

你可能感兴趣的文章
楼梯T-SQL:超越基础6级:使用CASE表达式和IIF函数
查看>>
CentOS下安装Subversion简记
查看>>
(转)使用零宽断言来匹配不包含连续字符串的行
查看>>
JQUERY1.9学习笔记 之基本过滤器(十) 非选择器
查看>>
SD第九届省赛B题 Bullet
查看>>
Codeforces 1132G Greedy Subsequences 线段树
查看>>
线段树
查看>>
【Leetcode】115. Distinct Subsequences
查看>>
系统子模块_MCU(LPC)整体流程
查看>>
【转载】儒林外史人物——严贡生和严监生(一)
查看>>
svn 结合rsync 的代码发布系统
查看>>
安装phpredis模块
查看>>
gitlab web登入密码忘记以后可以用如下方式修改密码
查看>>
android学习之LayoutInflater的用法,在myAdapter getView()里将多个TextView组件压缩成一个View控件,并在listView里显示...
查看>>
jquery获取dropdownlist的value和text值
查看>>
URL 生成带文字二维码
查看>>
MySQL 5.6 Replication 复制 FAQ
查看>>
《C专家编程》
查看>>
阿里云 Windows Server 2012 r2 部署asp.net mvc网站 平坑之旅
查看>>
sql逻辑查询 理论知识
查看>>