Android获取音视频原始流数据方法详解

视频数据流的获取

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

<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />

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

首先,是拿到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.小艾

发布了16 篇原创文章 · 获赞 30 · 访问量 4万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览