视频数据流的获取

Android设备视频数据的获取,是调用Camera,所以需要在AndroidManifest中添加以下的权限:

如果当前设备不支持自动对焦,则相关的设置将不起作用。

首先,是拿到Camera对象并且设置摄像头采集的参数配置:

mCamera = Camera.open(mCamId);Camera.Parameters params = mCamera.getParameters();//摄像头的参数

参数如果不设置的话,一般会采用默认值,但现在市面上的所有设备配置不相同,如果全部按照默认的来可能出现未知的错误。例如相机拍照和预览的分辨率设置,如果和真实的手机不一样就会报错。

params.setPictureSize(mEncoder.getPreviewWidth(), mEncoder.getPreviewHeight());//保存的照片的尺寸params.setPreviewSize(mEncoder.getPreviewWidth(), mEncoder.getPreviewHeight());//预览分辨率

如果你不知道自己的设备支持哪些拍照或者是预览时的分辨率,Camera提供了相应的方法:

for(int num = 0; num < params.getSupportedPreviewSizes().size(); num++){           Log.d(TAG,params.getSupportedPreviewSizes().get(num).width+"*"        +params.getSupportedPreviewSizes().get(num).height);    }

上面的代码获取的是设备支持的所有的预览分辨率。下面贴一下我们设备相应的分辨率:

除了设置采集的视频数据流的分辨率,还可以设置以下的相应参数:

params.setPreviewSize(mEncoder.getPreviewWidth(), mEncoder.getPreviewHeight());//设置预览分辨率    params.setPreviewFpsRange(int min, int max);//设置摄像头采集时的帧率

之前的setPreviewFrameRate方法被现在的setPreviewFpsRange方法取代,该方法是设置摄像头每秒采集多少帧的视频数据流,min一般是用户自己预期设置的值,max是设备所能支持的最大帧数值(我的设备帧数的支持7.5到30),这个值计算时需要再*1000.

当然设备支持的帧率也可以通过Camera提供的相应的方法获得:

    for(int num = 0; num < params.getSupportedPreviewFpsRange().size(); num++)    {        int[] SupPreRange = params.getSupportedPreviewFpsRange().get(num);       Log.d(TAG, "< " + num + " >" + " Min = " + SupPreRange[0]                + "  Max = " + SupPreRange[1]);    }    params.setPreviewFormat(ImageFormat.NV21);//NV21 设置预览帧格式 默认是NV21(YUV420SP)格式    关于这些我的上篇博客有着更加详细的介绍    [上篇博客链接](http://blog.csdn.net/qq_26986211)    params.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);//关闭闪光灯    params.setWhiteBalance(Camera.Parameters.WHITE_BALANCE_AUTO);//曝光平衡    params.setSceneMode(Camera.Parameters.SCENE_MODE_AUTO);//设置场景模式    if (!params.getSupportedFocusModes().isEmpty()) {        params.setFocusMode(params.getSupportedFocusModes().get(0));//自动对焦的效果    }

当然了,这些参数不一定在所有的设备上都是通用的,需要根据自的情况而定。如果你设置了相关的参数,而设备又不支持,那么这么的方法就不会被执行。

 mCamera.setParameters(params);//设置配置的参数mCamera.setDisplayOrientation(mPreviewRotation);//设置屏幕的旋转角度

上面主要是针对垂直来说,因为这样设置的话一般是设置90,180,270。所以当用户大幅度转动设备的时候,设备就直接旋转了,如果需要自适应预览接连始终是正确的(这里的正确是指,无论用户怎么旋转,设备不会出现大幅度的旋转,保证了预览界面是正常的),就需要将重写setDisplayOrientation方法:

  public static void setCameraDisplayOrientation ( Activity activity ,      int cameraId , android . hardware . Camera camera ) {     android . hardware . Camera . CameraInfo info =          new android . hardware . Camera . CameraInfo ();     android . hardware . Camera . getCameraInfo ( cameraId , info );  int rotation = activity . getWindowManager (). getDefaultDisplay ()          . getRotation ();  int degrees = 0 ;  switch ( rotation ) {      case Surface . ROTATION_0 : degrees = 0 ; break ;      case Surface . ROTATION_90 : degrees = 90 ; break ;      case Surface . ROTATION_180 : degrees = 180 ; break ;      case Surface . ROTATION_270 : degrees = 270 ; break ;  }  int result ;  if ( info . facing == Camera . CameraInfo . CAMERA_FACING_FRONT ) {     result = ( info . orientation + degrees ) % 360 ;     result = ( 360 - result ) % 360 ;   // compensate the mirror  } else {   // back-facing     result = ( info . orientation - degrees + 360 ) % 360 ;  } camera . setDisplayOrientation ( result );

}

接下就是预览回调的注册了,在Camera提供了三种方法:

            setPreviewCallback(Camera.PreviewCallback)             setOneShotPreviewCallback(Camera.PreviewCallback)             setPreviewCallbackWithBuffer(Camera.PreviewCallback)

setPreviewCallback(Camera.PreviewCallback) 。这个方法不需要用户自己分配相应的Buffer数组,由系统默认自动分配。只要预览帧可用,该方法就会一直被调用,此时其他的回调函数将会被覆盖。

setOneShotPreviewCallback(Camera.PreviewCallback)。这个方法也不需要用户自己分配数组大小,从字面上也可以理解出来,调用一次之后,数据将会被清楚,但该方法可以随时被调用,执行此函数时,其他的回调函数将会被覆盖。

setPreviewCallbackWithBuffer(Camera.PreviewCallback)。使用该函数之前我们需要指定一个字节数组作为缓冲区,大小一般也是有用户自己根据实际情况自己设置的。由于摄像头采集的数据流是YUV格式的,一般 Y = width*height,U = Y/4,V = Y/4;所以YUV数据的大小是width*height*3/2,所以字节数组的大小一般是width*height*3/2。需要先调mCamera.addCallbackBuffer()方法,参数是分配大小的字节数组。所以这两个方法是绑定在一起的使用的。

回调函数的具体注册使用如下:以setPreviewCallbackWithBuffer为例

mCamera.setPreviewCallbackWithBuffer(this);

接下来就是视频真正开始预览,获取数据了

mCamera.startPreview();

开始预览之后,同时之前也设置了回调函数,程序就会自动调用onPreviewFrame函数,在主类继承了implements SurfaceHolder.Callback, Camera.PreviewCallback。系统就会重载onPreviewFrame函数。

public void onPreviewFrame(byte[] data, Camera camera) {    //将取得的视频数据发送出去,在这了你也可以实现别的功能    onGetYuvFrame(data);    //这个接口调用前,我们需要提前分配一块buffer,并且这个接口调用一定要放在onPreviewFrame()回调中:    camera.addCallbackBuffer(mYuvPreviewFrame);}

该函数的参数中 data就是最原始的视频数据流,如果你需要进行预览时的一些摄像头操作,一般也可以在onPreviewFrame函数中进行设置,例如人脸识别,但与视频数据打交道的时候,算法一般是非常的复杂的,所以一般是开启新的线程进行后续的操作。

最后,摄像头不用的时候一定要释放资源:如果程序中加入了previewCallback,在surfaceDestroy释放camera的时候,最好执行myCamera.setOneShotPreviewCallback(null); 或者myCamera.setPreviewCallback(null);中止这种回调,然后再释放camera更安全。否则可能会报错。

//关闭摄像头private void stopCamera() {    if (mCamera != null) {        // 停止预览前需要将摄像头的回调函数设置为空        mCamera.setPreviewCallback(null);        mCamera.stopPreview();        mCamera.release();        mCamera = null;    }}

音频数据流的获取

Android音频设备是麦克风,使用时需要添加以下权限:

音频的获取相比较视频获取来说,步骤简单得多,并没有太多复杂的配置:

if (mic != null) {        return;    }    //根据自己设置的音频格式配置相应的数组大小,用于存储数据,同时可以提高效率,节约空间    int bufferSize = 2 * AudioRecord.getMinBufferSize(SrsEncoder.ASAMPLERATE, SrsEncoder.ACHANNEL, AudioFormat.ENCODING_PCM_16BIT);    mic = new AudioRecord(MediaRecorder.AudioSource.MIC, SrsEncoder.ASAMPLERATE, SrsEncoder.ACHANNEL, AudioFormat.ENCODING_PCM_16BIT, bufferSize);    mic.startRecording();    byte pcmBuffer[] = new byte[2048];    while (aloop && !Thread.interrupted()) {        int size = mic.read(pcmBuffer, 0, pcmBuffer.length);        if (size <= 0) {            break;        }        //将获取的数据发送出去        mEncoder.onGetPcmFrame(pcmBuffer, size);    }

这里介绍一下参数:

ASAMPLERATE:音频采样率,有44100、22050、11025、4000、8000 等,代表了采样的品质高低,采样率越高品质越高。
ACHANNEL:声道设置:android支持双声道立体声和单声道。MONO单声道,STEREO立体声
AudioFormat.ENCODING_PCM_16BIT:采样大小为16bit 还可以设置成8bit

这列涉及到要算一个PCM音频流的码率,采样率值×采样大小值×声道数bps。一个采样率为44.1KHz,采样大小为16bit,双声道的PCM编码的WAV文件,它的数据速率则为 44.1K×16×2 =1411.2 Kbps。我们常说128K的MP3,对应的WAV的参数,就是这个1411.2 Kbps,这个参数也被称为数据带宽,它和ADSL中的带宽是一个概念。将码率除以8,就可以得到这个WAV的数据速率,即176.4KB/s。这表示存储一秒钟采样率为44.1KHz,采样大小为16bit,双声道的PCM编码的音频信号,需要176.4KB的空间,1分钟则约为10.34M,这对大部分用户是不可接受的,尤其是喜欢在电脑上听音乐的朋友,要降低磁盘占用,只有2种方法,降低采样指标或者压缩。降低指标是不可取的,因此专家们研发了各种压缩方案。也就是我们后来说到的编码压缩。

总结一下,如有不足之处请大家见谅,望指出批评。我是Mr.小艾

更多相关文章

  1. android中怎么调整字体的间距和行间距
  2. 【Android】Android插件开发 —— 打开插件的Activity(Hook系统方
  3. Android中系统状态栏的隐藏和显示
  4. Android访问WCF服务(上篇)-服务端开发
  5. Android(安卓)NullPointerException解决方法(空指针异常)
  6. Android重要类学习之——Activity
  7. Android布局管理器 - 详细解析布局实现
  8. 浅谈Java中Collections.sort对List排序的两种方法
  9. Python list sort方法的具体使用

随机推荐

  1. Android重写菜单增加系统自带返回键
  2. LINUX下Android(安卓)NDK下载并配置
  3. 《Android开发从零开始》――22.数据存储
  4. Android实现ListView异步加载图片总结
  5. Android(安卓)ViewFliper实现屏幕切换
  6. android PhoneGap 自定义插件
  7. cocos2dx使用Jsoncpp在android运行的问题
  8. Android(安卓)adb 模拟滑动 按键 点击事
  9. android 3D 游戏实现之综合实例(初步)
  10. 解决Debug certificate expired问题