车载应用--AUXIN 利用 surfaceView 预览 Camera 数据

前文介绍了倒车后视,主要是利用 WindowManager 来加载布局,在布局中增加 SurfaceView 来预览 camera 数据。车载倒车后视–利用 WindowManager 预览 camera 数据
本文将介绍关于 camera 的另一个应用 AUXIN。

概念介绍

1.AUX

AUX 是“Auxiliary(辅助)”的缩写,它是一种额外的讯号线路设计。它是外接音视频设备的接续端,例如在车上要使用 MP3、MP4 等播放器,就可以通过这种端子来完成。这种预备端子或线路,不论输出或输入,我们统称它为AUX。也可以到电脑配件市场买一个两头都跟耳机插头一样的连接线就可以使用它了,一端连接汽车,另一端连接手机,这样就可以用车载音响听手机里面的音乐了,播放的效果也是非常好的。

2.数字摄像头和模拟摄像头

这两个摄像头的区别困扰我很久,因为我总是把这两种摄像头的区别归因于所选的感光元件的差异,其实是大错特错。

  • 输出。其实不管你选择 CCD 还是 CMOS,只要你输出的信号是数字的,就称为数字摄像头;输出的是标准模拟信号的,就是模拟摄像头,或多称为模拟摄像机。
  • 接口。数字摄像头有 USB接口(聊天用的),1394火线(高分辨率),千兆网接口(网络摄像头);模拟摄像头(机)多采用 AV 视频端子(信号线+地线)或 S-VIDEO 端子(俗称莲花头),输出标准电视信号 (PAL或NTSC)。
  • 分辨率。这个区别是很显著的。模拟摄像头的感光器件,其象素指标一般都维持在752(H)×582(V)左右这个水平,像素数也就是41W左右。数字摄像头的分辨率(这里说分辨率指的都是感光器件而不是采集到的图像的)有市面上常看到的百万级的像素数。但这并不能说数字摄像头的成像分辨率就比模拟摄像头的高,原因在于模拟摄像头输出的是模拟视频信号,它输出的模拟信号直接输入至电视或监视器,其感光器件的分辨率与电视信号的扫描线数呈一定的换算关系,图象的显示介质已经确定,因此模拟摄像机没有必要采用高分辨率的感光器件,换句话说,模拟摄像头的感光器件分辨率不是不能做高,而是没必要做高。
3.CVBS接口

CVBS接口是AV接口中的视频信号(单根黄色线),特指能兼容黑白电视的彩色电视信号。
1.CVBS是英文“Composite Video Broadcast Signal”的缩写,中文名字叫复合视频广播信号或复合视频消隐和同步。

2.CVBS是被广泛使用的标准,也叫做基带视频或RCA视频,是(美国)国家电视标准委员会(NTSC)电视信号的传统图像数据传输方法,它以模拟波形来传输数据。复合视频包含色差(色调和饱和度)和亮度(光亮)信息,并将它们同步在消隐脉冲中,用同一信号传输。

3.CVBS是一种比较老的显示方式,更准确的说是第一代视频显示输出方式(第二代是S-VIDEO,第三代是VGA,第四代是DVI,第五代是HDMI)。
  

4.AV接口

1.AV接口算是出现比较早的一种接口,它由红、白、黄三种颜色的线组成,其中黄线为视频传输线,红色和白色则是负责左右声道的声音传输。AV就是英文“Audio”和“Video”的缩写,中文意思就是音频和视频。

2.AV接口又称RCA接口,是指目前一些DVD、电视盒、多媒体播放器等设备,通过自身携带的音、视频端子,连接AV线路将自身的数据图像声音等,输出到其它显示及视听设备上,如外接显示器、耳机等,接口主要有AV复合端子,S-VIDEO端子,耳机接口等。它可以算是TV的改进型接口,外观方面有了很大不同。分为3条线,分别为:音频接口(红色与白色线,组成左右声道)和视频接口(黄色)。

3.由于AV输出仍然是将亮度与色度混合的视频信号,所以依旧需要显示设备进行亮度和色彩分离,并且解码才能成像。这样的做法必然对画质会造成损失,所以AV接口的画质依然不能让人满意。在连接方面非常的简单,只需将3种颜色的AV线与电视端的3种颜色的接口对应连接即可。

总体来说,AV接口把视频和音频进行了分离传输,从而避免了音频和视频的互相干扰。但是由于在视频传输上还需要把亮度和色度进行解码显示,所以视频传输还是存在损失的,所以目前的高清视频播放基本都放弃了AV接口。

需求分析
对于 app 端而言,auxin 主要是用来显示音频和视频,当只插入音频线时,打开 auxin 应用,可能就只是一个简简单单的图片,而后台却在播放音频。
这里写图片描述
如果只接入视频线,播放的视频流,但没声音;如果同时接入视频线和音频线,播放的是视频画面,而后台播放的声音是音频接入流,不一定是视频的声音。
在这里,我们只考虑视频画面的显示。而这视频信息从何而来才是我们开发应该考虑的。


咨询了好多人,都说不明白,因为这跟 os 相关,告诉我的是把它当做摄像头来使用就是了。好吧,暂时放一放,后续再来补充!


总之,就是把 auxin 视频输入当做摄像头来使用,也就是,当我们插入 auxin 视频输入线时就相当于接入了一个 camera ,当拔出 auxin 视频输入线时少了一个 camera 设备。
在应用开发中的体现就是:点击 auxin 图标,判断是否有摄像头(auxin 视频线是否连接),如果 auxin 视频线连接了,则存在该摄像头了。后续的操作步骤与操作一个 androd 摄像头没任何差异,都是直接调用 android 提供的 API 来开发自定义的摄像头,仅仅只是实现预览功能而已。

代码如下:

public class CameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback, Camera.PreviewCallback {
    private static final String TAG = "Bradley";  
    private Context mContext;  
    SurfaceHolder mSurfaceHolder;
    private Camera mCamera;
    private long mOpenCameraOkMillis;
    public CameraSurfaceView(Context context, AttributeSet attrs) {  
        super(context, attrs);  
        mContext = context;  
        mSurfaceHolder = getHolder();       
        mSurfaceHolder.setFormat(PixelFormat.TRANSLUCENT);//translucent半透明 transparent透明  
        mSurfaceHolder.addCallback(this); 
    }  

    @Override  
    public void surfaceCreated(SurfaceHolder holder) {  
        Log.i(TAG, "surfaceCreated...");
        startCamera(holder);
    }  

    @Override  
    public void surfaceChanged(SurfaceHolder holder, int format, int width,  
            int height) {  
        Log.i(TAG, "surfaceChanged...");  
    }  


    @Override  
    public void surfaceDestroyed(SurfaceHolder holder) {  
        Log.i(TAG, "surfaceDestroyed...");
    }  

    public SurfaceHolder getSurfaceHolder(){  
        return mSurfaceHolder;  
    }

    private void startCamera(SurfaceHolder holder) {
        if(checkCameraHardware(mContext)){
            mCamera = getCameraInstance();
            if(mCamera!=null){
                try {
                    mOpenCameraOkMillis = SystemClock.elapsedRealtime();
                    mCamera.setPreviewCallback(this);
                    mCamera.setPreviewDisplay(holder);
                    mCamera.startPreview();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /** Check if this device has a camera */
    private boolean checkCameraHardware(Context context) {
        if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
            // this device has a camera
            return true;
        } else {
            // no camera on this device
            return false;
        }
    }

    /** A safe way to get an instance of the Camera object. */
    private Camera getCameraInstance(){
        Camera c = null;
        try {
            c = Camera.open(); // attempt to get a Camera instance
        }
        catch (Exception e){
            // Camera is not available (in use or does not exist)
        }
        return c; // returns null if camera is unavailable
    }

    @Override
    public void onPreviewFrame(byte[] data, Camera camera) {
        boolean isCvbsIn = true;
        boolean isALL_16 = true; //前面10个数据是否都是16,是的话表示无信号
        if(data.length >= 10){
            for(int i = 0;i < 10;i++){
                if(data[i] != data[i+1]){
                    isALL_16 = false;
                    break;
                }
            }
        }

        if(isALL_16 && (data[0] == 16)){
            isCvbsIn = false;
        }

        if(SystemClock.elapsedRealtime() - mOpenCameraOkMillis  < 200){
            LogUtil.v(TAG, "Camera check cvbs too fast isCvbsIn =" + isCvbsIn + "  mIsCVBSIn = " );
            return;
        }

        if(isCvbsIn){
            ViewGroup.LayoutParams params = getLayoutParams();
            if (isCvbsIn) {
                params.width = ViewGroup.LayoutParams.MATCH_PARENT;
                params.height = ViewGroup.LayoutParams.MATCH_PARENT;
            } else {
                params.width = 1;
                params.height = 1;
            }
            setLayoutParams(params);
        }

    }

    public void onStop() {
        if(mCamera!=null){
            mCamera.setPreviewCallback(null);
            mCamera.stopPreview();
            mCamera.release();
        }
    }
}

整体代码与前文基本没有什么区别,当 surfaceView 创建的时候,打开摄像头同时预览,但有一个小小的细节需要特别提醒一下:
1. Camera.open 对于应用而言是能获取得到 camera 实例的,无论当前是否外接有视频线。当点击应用图标进入 auxin 界面时,应用汇通知 os 当前进入了 auxin 界面,此时 os 会将 camera 的通道与 auxin 通道相关联,也就是此时 camera 的数据此时是从 auxin 输入的。open 的实现是判断 camera 的节点存不存在,这个节点是一直存在的,只是数据来源不同,即使那一路通路给的数据。
2. 视频画面防抖处理。我们给预览画面设置一个预览回调 setPreviewCallback ,在回调函数 onPreviewFrame 中,对数据进行分析,前面10个数据都是16 的话,表示无信号。此时应该讲 surfaceView 隐藏,显示无信号了解。
之所以设置 width 和 height 为1 ,是因为当有信号输入时,此时设置全屏,画面会抖动,为了防止此现象,才将 width 和 height 设置为 1。


happy a nice day!

猜你喜欢

转载自blog.csdn.net/liqianwei1230/article/details/78431363