The application of video chat can be shown in the following block diagram.
So we need to get video data (YUV420SP) from camera, compress it into h264/mpeg4/h263 package, and then pass it to the other side. Receive the other party's compression package, extract it to display on the LCD.
In Android, you can get YUV data for each Peview frame by setting the Previewcallback function for camera.
We will now look at how to open the camera and get the video data according to the size of the preview you want to request.
Here is the code snippet that opens the camera, which is wrapped in a Videocameraview class.
1 Public classVideocameraview extends Surfaceview implements Surfaceholder.callback,2 Android.hardware.Camera.PreviewCallback {3 4 ...5 6 7 8 PrivateAndroid.hardware.Camera Mcamera =NULL ;9 Ten Private DoubleMaspectratio =3.0/3.0; One A Private intPreview_w; - Private intPreview_h; - Private intpreview_yuvbytes; the Private byte[] bu; - - PrivateBoolean bufffilled =false ; - + PrivateBoolean MREC =false ; - + Public voidOpencamera (intU ninth) { A atMRec =false ; - - if(Surfaceholder = =NULL ) - return ; -Mcamera =Android.hardware.Camera.open (); - Try { in Mcamera.setpreviewdisplay (surfaceholder); -}Catch(IOException e) { toLOG.E (TAG,"Mcamera.setpreviewdisplay ("+ Surfaceholder +") Fail" ) ; + return ; - } the *Android.hardware.Camera.Parameters p =mcamera.getparameters (); $ Panax Notoginseng ////Get the closest required size -List<android.hardware.camera.size> Listpreview =p.getsupportedpreviewsizes (); theLOG.V (TAG,"Preview Size is"+Listpreview); + intII =-1 ; A intDelta =0x7fffff ; the for(inti =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); theII =i; - }Wuyi } thePreview_w = Listpreview.Get(ii). width; -Preview_h = Listpreview.Get(ii). Height; WuPreview_yuvbytes = preview_w*preview_h*3/2 ; - About $Maspectratio = (Double) Preview_w/Preview_h; - p.setpreviewsize (Preview_w, preview_h); - -list<int[]> Fprange =P.getsupportedpreviewfpsrange (); A intMax = - ; + intMin =0 ; the for(inti =0; I < fprange.size (); i + + ) { - int[] FPR = Fprange.Get(i); $LOG.V (TAG,"min"+ fpr[0]+"Max"+ fpr[1]) ; the } the the mcamera.setparameters (P); theBU =New byte[preview_yuvbytes]; - inMcamera.setpreviewcallbackwithbuffer ( This ) ; the theAndroid.hardware.Camera.CameraInfo Camerainfo =Newandroid.hardware.Camera.CameraInfo (); AboutMcamera.getcamerainfo (0, camerainfo); theRotateangle =camerainfo.orientation; theLOG.V (TAG,"camera.camerainfo.orientation="+camerainfo.orientation); the //mcamera.setdisplayorientation (camerainfo.orientation); + //preparecapture (); - requestlayout (); theTimestart =System.currenttimemillis ();Bayionpreviewcalled =0 ; the Mcamera.startpreview (); the } - -}
Here are a few questions to explain:
1 The size you pass in may not be supported by the camera, so find a size that is closest to your requirements.
The aspect ratio of the 2 preview may not be the same as the aspect ratio of your start layout, so the preview to the screen will deform, so you need to requestlayout () and rewrite the Onmeasure function as follows:
1 protected voidOnmeasure (intWidthspec,intHeightspec) {2 intPreviewwidth =measurespec.getsize (widthspec);3 intPreviewheight =measurespec.getsize (heightspec);4 5 if(Previewwidth > Previewheight *maspectratio) {6Previewwidth = (int) (Previewheight * maspectratio +.5);7}Else {8Previewheight = (int) (Previewwidth/maspectratio +.5);9 }Ten One //Ask Children to follow the new preview dimension. A super.onmeasure (Measurespec.makemeasurespec (Previewwidth, measurespec.exactly), - Measurespec.makemeasurespec (Previewheight, measurespec.exactly)); -}
Please note: Maspectratio is calculated when we are opencamera.
3 need to be in the application layer new a preview_yuvbytes size of memory through Addcallbackbuffer to the Android system, Then use Setpreviewcallbackwithbuffer to set the callback function . If Setpreviewcallback to set the callback function, then the GC will be frequently started, because the callback to send the memory block is redistributed each time, it is easy to reach the threshold of garbage processing, performance will be greatly reduced. And we use Setpreviewcallbackwithbuffer and allocate this memory in Opencamera, each time the memory is compressed, and then re-addcallbackbuffer into the system, it will not be allocated a lot of memory, The GC also does not start. Take a look at the following code slices:
1 Public voidStartrec () {2MRec =true ; 3 Mcamera.addcallbackbuffer (BU);4 }5 6 Public voidOnpreviewframe (byte[] data, Android.hardware.Camera Camera) {7 if(MREC)8bufffilled =true ; 9 }Ten One A - Public intEncodeoneframe (byte[] bitstream,intbitstreamlength) { - inti =0 ; the while((i++ <Ten) && (bufffilled = =false) ) { - Try { -Thread.Sleep (Ten) ; -}Catch(interruptedexception e) { + - } + } A if(bufffilled = =false ) at return 0 ; - intnn =nativeEncodeOneFrameH264 (BU, bitstream, bitstreamlength, ...); -bufffilled =false ; - Mcamera.addcallbackbuffer (BU); - returnnn; -}
Demo Link: http://nchc.dl.sourceforge.net/project/avccodecdemo/avccodecDemo-src-apk.zip
Original link: http://blog.csdn.net/brooknew/article/details/7998833
Android Camera Using one example, video chat app