您的位置:首页 > 移动开发

Android Camera 使用一例,视频聊天app

2014-07-07 13:54 225 查看
/article/8657107.html

视频聊天的应用可以从下面的框图示意。





所以需要从camera获取视频数据(YUV420sp),压缩成H264/MPEG4/H263的包,再传递到对方。接收对方的压缩包,解压出来显示到LCD上。

Android里通过给camera设定 previewcallback函数可以获取每一个Peview帧的yuv数据。

我们现在看看如何按照你想要求的预览尺寸打开camera的并且获取视频数据的。

下面是打开camera的代码片断,他包在一个VideoCameraView类里面。

public class VideoCameraView extends SurfaceView implements SurfaceHolder.Callback,

android.hardware.Camera.PreviewCallback {

...

private android.hardware.Camera mCamera = null ;

private double mAspectRatio = 3.0 / 3.0;

private int preview_w ;

private int preview_h ;

private int preview_yuvbytes ;

private byte[] bu ;

private boolean buffFilled = false ;

private boolean mRec = false ;

public void openCamera(int w , int h){

mRec = false ;

if( surfaceHolder == null )

return ;

mCamera = android.hardware.Camera.open() ;

try {

mCamera.setPreviewDisplay(surfaceHolder);

}catch(IOException e ){

Log.e(TAG,"mCamera.setPreviewDisplay( " + surfaceHolder +") fail" ) ;

return ;

}

android.hardware.Camera.Parameters p = mCamera.getParameters() ;

////得到最接近要求的尺寸

List<android.hardware.Camera.Size> listPreview = p.getSupportedPreviewSizes() ;

Log.v(TAG, "preview size is "+listPreview) ;

int ii = -1 ;

int delta = 0x7fffff ;

for( int i = 0 ; i < listPreview.size() ; i ++) {

android.hardware.Camera.Size size = listPreview.get(i) ;

String ws = Integer.toString(size.width);

String hs = Integer.toString(size.height) ;

Log.v(TAG, "elements "+i+":"+ws+"x"+hs) ;

if( java.lang.Math.abs(size.width - w ) < delta ) {

delta = java.lang.Math.abs(size.width - w ) ;

ii = i ;

}

}

preview_w = listPreview.get(ii).width ;

preview_h = listPreview.get(ii).height ;

preview_yuvbytes = preview_w*preview_h*3/2 ;

mAspectRatio = (double)preview_w / preview_h;

p.setPreviewSize( preview_w , preview_h ) ;

List<int[]> fpRange = p.getSupportedPreviewFpsRange() ;

int max = 100 ;

int min = 0 ;

for(int i = 0 ; i < fpRange.size() ; i ++ ) {

int[] fpr = fpRange.get(i) ;

Log.v(TAG, "min "+ fpr[0]+ " max " + fpr[1]) ;

}

mCamera.setParameters(p);

bu = new byte[preview_yuvbytes] ;

mCamera.setPreviewCallbackWithBuffer( this ) ;

android.hardware.Camera.CameraInfo cameraInfo = new android.hardware.Camera.CameraInfo() ;

mCamera.getCameraInfo( 0 , cameraInfo ) ;

rotateAngle = cameraInfo.orientation ;

Log.v(TAG,"Camera.CameraInfo.orientation="+ cameraInfo.orientation );

//mCamera.setDisplayOrientation(cameraInfo.orientation) ;

//prepareCapture();

requestLayout() ;

timeStart = System.currentTimeMillis() ;

onPreviewCalled = 0 ;

mCamera.startPreview();

}

}

这里有几个问题需要说明一下:

1 你传进来的尺寸可能不是camera支持的,所以要找一个最靠近你要求的尺寸。

2 预览的长宽比可能和你开始布局的长宽比不一致,这样预览到的画面就会变形,所以需要requestLayout() ,并且要重写onMeasure函数,如下:

protected void onMeasure(int widthSpec, int heightSpec) {

int previewWidth = MeasureSpec.getSize(widthSpec);

int previewHeight = MeasureSpec.getSize(heightSpec);

if (previewWidth > previewHeight * mAspectRatio) {

previewWidth = (int) (previewHeight * mAspectRatio + .5);

} else {

previewHeight = (int) (previewWidth / mAspectRatio + .5);

}

// Ask children to follow the new preview dimension.

super.onMeasure(MeasureSpec.makeMeasureSpec(previewWidth, MeasureSpec.EXACTLY),

MeasureSpec.makeMeasureSpec(previewHeight, MeasureSpec.EXACTLY));

}

请注意:mAspectRatio 是我们在openCamera时计算得到的。

3 需要在应用层new一个preview_yuvbytes大小的内存通过 addCallbackBuffer 传到android系统里去,然后使用setPreviewCallbackWithBuffer来设定回调函数。要是setPreviewCallback来设回调函数的话,那么GC会被频繁启动,因为回调送来的内存块是每次都重新分配的,很容易到达需要垃圾处理的门槛,性能会大大降低。而我们采用setPreviewCallbackWithBuffer并且在openCamera时分配这块内存,每次把这块内存压缩使用之后,又重新addCallbackBuffer
到系统里去,就不会大量分配内存,GC也不会启动。请看下面的代码片:

public void startRec() {

mRec = true ;

mCamera.addCallbackBuffer( bu ) ;

}

public void onPreviewFrame (byte[] data, android.hardware.Camera camera){

if( mRec )

buffFilled = true ;

}

public int encodeOneFrame(byte[] bitstream , int bitStreamLength){

int i = 0 ;

while( (i++ < 10) && (buffFilled == false) ) {

try {

Thread.sleep(10) ;

}catch( InterruptedException e) {

}

}

if( buffFilled == false )

return 0 ;

int nn = nativeEncodeOneFrameH264( bu , bitstream , bitStreamLength ,..... ) ;

buffFilled = false ;

mCamera.addCallbackBuffer( bu ) ;

return nn ;

}

更多0

上一篇GetByteArrayElements
在DalVik的实现

下一篇Android
中H.264/AVC codec的开发
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: