zoukankan      html  css  js  c++  java
  • Android Camera 使用一例,视频聊天app

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

     

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

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

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

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

     1 public class VideoCameraView extends SurfaceView  implements SurfaceHolder.Callback,
     2         android.hardware.Camera.PreviewCallback {
     3 
     4 ...
     5 
     6  
     7 
     8 private android.hardware.Camera mCamera = null ;
     9 
    10  private double mAspectRatio = 3.0 / 3.0;
    11 
    12  private int preview_w ;
    13  private int preview_h ;
    14  private int preview_yuvbytes ; 
    15  private byte[] bu  ;
    16 
    17  private boolean buffFilled = false ;
    18 
    19  private boolean mRec = false ;
    20 
    21  public void openCamera(int w , int h){
    22 
    23   mRec = false ;
    24   
    25   if( surfaceHolder == null  )
    26    return ;
    27   mCamera = android.hardware.Camera.open() ;
    28   try {
    29    mCamera.setPreviewDisplay(surfaceHolder);
    30   }catch(IOException e ){
    31    Log.e(TAG,"mCamera.setPreviewDisplay( " + surfaceHolder +") fail"  ) ;
    32    return ;
    33   }
    34 
    35   android.hardware.Camera.Parameters p = mCamera.getParameters() ;
    36 
    37 ////得到最接近要求的尺寸
    38   List<android.hardware.Camera.Size>  listPreview = p.getSupportedPreviewSizes() ;
    39   Log.v(TAG, "preview size is "+listPreview) ;
    40   int ii = -1 ; 
    41   int delta = 0x7fffff ;
    42   for( int i = 0 ; i < listPreview.size() ; i ++) {
    43    android.hardware.Camera.Size size = listPreview.get(i) ;
    44    String ws = Integer.toString(size.width);
    45    String hs = Integer.toString(size.height) ;   
    46    Log.v(TAG, "elements "+i+":"+ws+"x"+hs) ;
    47    if( java.lang.Math.abs(size.width - w ) < delta ) {
    48     delta = java.lang.Math.abs(size.width - w ) ;
    49     ii = i ;
    50    }
    51   }
    52   preview_w = listPreview.get(ii).width ;
    53   preview_h = listPreview.get(ii).height ;
    54   preview_yuvbytes = preview_w*preview_h*3/2 ;
    55 
    56 
    57   mAspectRatio = (double)preview_w / preview_h;
    58   p.setPreviewSize( preview_w , preview_h ) ;
    59 
    60   List<int[]>  fpRange = p.getSupportedPreviewFpsRange() ;
    61   int max = 100 ;
    62   int min = 0 ;
    63   for(int i = 0  ; i < fpRange.size() ; i ++ ) {
    64    int[] fpr = fpRange.get(i) ;
    65    Log.v(TAG, "min "+ fpr[0]+ " max " + fpr[1]) ;   
    66   }  
    67 
    68   mCamera.setParameters(p);  
    69   bu = new byte[preview_yuvbytes] ;
    70    
    71   mCamera.setPreviewCallbackWithBuffer( this ) ;  
    72   
    73   android.hardware.Camera.CameraInfo cameraInfo = new android.hardware.Camera.CameraInfo() ; 
    74   mCamera.getCameraInfo( 0 , cameraInfo ) ;
    75   rotateAngle = cameraInfo.orientation ;
    76   Log.v(TAG,"Camera.CameraInfo.orientation="+ cameraInfo.orientation );  
    77   //mCamera.setDisplayOrientation(cameraInfo.orientation) ;
    78   //prepareCapture();
    79   requestLayout() ;  
    80   timeStart = System.currentTimeMillis() ;
    81   onPreviewCalled = 0 ;
    82   mCamera.startPreview();
    83  }
    84 
    85 }

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

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

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

      

     1   protected void onMeasure(int widthSpec, int heightSpec) {
     2         int previewWidth = MeasureSpec.getSize(widthSpec);
     3         int previewHeight = MeasureSpec.getSize(heightSpec);
     4 
     5         if (previewWidth > previewHeight * mAspectRatio) {
     6             previewWidth = (int) (previewHeight * mAspectRatio + .5);
     7         } else {
     8             previewHeight = (int) (previewWidth / mAspectRatio + .5);
     9         }
    10 
    11         // Ask children to follow the new preview dimension.
    12         super.onMeasure(MeasureSpec.makeMeasureSpec(previewWidth, MeasureSpec.EXACTLY),
    13                 MeasureSpec.makeMeasureSpec(previewHeight, MeasureSpec.EXACTLY));
    14     }

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

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

     1 public void startRec() {
     2   mRec = true ; 
     3   mCamera.addCallbackBuffer( bu ) ;
     4  }
     5 
     6  public void onPreviewFrame (byte[] data, android.hardware.Camera camera){
     7     if( mRec )
     8       buffFilled = true ;    
     9  }
    10 
    11  
    12 
    13  public int  encodeOneFrame(byte[] bitstream , int bitStreamLength){
    14   int i = 0 ;
    15   while( (i++ < 10) && (buffFilled == false) ) {
    16    try {
    17     Thread.sleep(10) ;
    18    }catch( InterruptedException e) {
    19     
    20    }   
    21   }
    22   if( buffFilled == false )
    23    return 0 ;
    24   int nn = nativeEncodeOneFrameH264( bu , bitstream ,  bitStreamLength ,..... ) ;
    25   buffFilled =  false ;
    26   mCamera.addCallbackBuffer( bu ) ;
    27   return nn ;
    28  }

     demo链接:http://nchc.dl.sourceforge.net/project/avccodecdemo/avccodecDemo-src-apk.zip

    原文链接:http://blog.csdn.net/brooknew/article/details/7998833

  • 相关阅读:
    springboot框架
    java是什么
    Java文件读写
    Spring Cloud学习入门路线方案
    Spring Cloud学习路线
    Lucene——索引过程分析Index
    Lucene学习入门——核心类API
    爬虫技术框架——Heritrix
    Spring Cloud入门程序——注册服务提供者
    Spring Cloud入门程序
  • 原文地址:https://www.cnblogs.com/Sharley/p/5605485.html
Copyright © 2011-2022 走看看