EasyPusher进行Android UVC外接摄像头直播推送实现方法

来源:互联网 发布:淘宝win10激活码来源 编辑:程序博客网 时间:2024/05/16 12:39

最近EasyPusher针对UVC摄像头做了适配.我们结合了UVCCamera与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工程说明.如下:

<activity android:name=".UVCActivity" android:launchMode="singleInstance">            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>            <intent-filter>                <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />            </intent-filter>            <intent-filter>                <action android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" />            </intent-filter>            <meta-data                android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"                android:resource="@xml/device_filter" />        </activity>

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

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

    public void onPush(View view) {      // 异步获取到MediaStream对象.        getMediaStream().subscribe(new Consumer<MediaStream>() {            @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<Object>() {                        @Override                        public void accept(Object o) throws Exception {                          // 开启成功,进行推送.                            // ...                            mediaStream.startStream("cloud.easydarwin.org", "554", id);                        }                    }, new Consumer<Throwable>() {                        @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<MediaStream>() {            @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);}

## 获取更多信息 ##

邮件:support@easydarwin.org

EasyDarwin开源流媒体服务器:www.EasyDarwin.org

EasyDSS商用流媒体解决方案:www.EasyDSS.com

EasyNVR无插件直播方案:www.EasyNVR.com

Copyright © EasyDarwin Team 2012-2017

EasyDarwin

阅读全文
'); })();
0 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 昌河福瑞达单排 昌河利亚纳怎么样 2009款昌河福瑞达 二手昌河爱迪尔 昌河q7图片及价格 昌河福瑞达1.2 04昌河爱迪尔 昌河北斗星新款2018款 昌河q25为什么销量不佳 昌河面包车报价 昌河面包车图片 昌河商务车7座图片及价格 昌河铃木汽车 昌河汽车图片 老昌河面包车图片 昌河汽车新款 江西昌河汽车有限责任公司 昌河面包车价格 昌河面包车报价图片 昌河福瑞达m50s怎么样 昌河福瑞达m50s报价 昌河福瑞达面包车价格 昌河福瑞达加长版 昌河福瑞达单排小货车 昌河福瑞达面包车怎么样 昌河福瑞达价格 昌河福瑞达报价 昌河福瑞达双排 昌河福瑞达m50 昌河福瑞达双排货车价格 昌河汽车怎么样 昌河铃木利亚纳a6两厢 昌河铃木价格表 昌河汽车福瑞达 昌河福瑞达面包车配件 昌河利亚纳a6两厢 昌河福瑞达50s 昌河利亚纳a6怎么样 昌河福瑞达发动机 昌河福瑞达轮胎型号 昌河铃木利亚纳a6三厢