android视频数据采样率,Android获取音视频原始流数据方法详解

视频数据流的获取

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);

}

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

ad6b904f9669a16bd03e03ca3c347dc4.png

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

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.小艾

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值