Android Camera 使用一例,视频聊天app
2016-06-22 00:00
465 查看
视频聊天的应用可以从下面的框图示意。
所以需要从camera获取视频数据(YUV420sp),压缩成H264/MPEG4/H263的包,再传递到对方。接收对方的压缩包,解压出来显示到LCD上。
Android里通过给camera设定 previewcallback函数可以获取每一个Peview帧的yuv数据。
我们现在看看如何按照你想要求的预览尺寸打开camera的并且获取视频数据的。
下面是打开camera的代码片断,他包在一个VideoCameraView类里面。
这里有几个问题需要说明一下:
1 你传进来的尺寸可能不是camera支持的,所以要找一个最靠近你要求的尺寸。
2 预览的长宽比可能和你开始布局的长宽比不一致,这样预览到的画面就会变形,所以需要requestLayout() ,并且要重写onMeasure函数,如下:
请注意:mAspectRatio 是我们在openCamera时计算得到的。
3 需要在应用层new一个preview_yuvbytes大小的内存通过 addCallbackBuffer 传到android系统里去,然后使用setPreviewCallbackWithBuffer来设定回调函数。要是setPreviewCallback来设回调函数的话,那么GC会被频繁启动,因为回调送来的内存块是每次都重新分配的,很容易到达需要垃圾处理的门槛,性能会大大降低。而我们采用setPreviewCallbackWithBuffer并且在openCamera时分配这块内存,每次把这块内存压缩使用之后,又重新addCallbackBuffer 到系统里去,就不会大量分配内存,GC也不会启动。请看下面的代码片:
demo链接:http://nchc.dl.sourceforge.net/project/avccodecdemo/avccodecDemo-src-apk.zip
原文链接:http://blog.csdn.net/brooknew/article/details/7998833
所以需要从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 ; }
demo链接:http://nchc.dl.sourceforge.net/project/avccodecdemo/avccodecDemo-src-apk.zip
原文链接:http://blog.csdn.net/brooknew/article/details/7998833
相关文章推荐
- 显示ProgressDialog
- 检查校准网址前缀
- Android换肤框架
- 自定义AdapterBase-ListView
- Activity启动模式
- android 动画入门(二)
- android ViewPager+Fragment之懒加载
- android ViewPager+Fragment之懒加载
- android ViewPager+Fragment之懒加载
- Android动态更改TextView的字体大小
- android 动态设置横竖屏切换 控制dialog等布局文件加载的方法
- TabHost的两种实现方式
- Activity生命周期解析
- Android Notification 用法
- android shape
- 我所理解的Android 启动模式
- 我所理解的Android 启动模式
- 我所理解的Android 启动模式
- Android ViewHolder的作用与用法
- android 全屏设置