基于android的远程视频监控系统

基本过程是android作为socket客户端将采集到的每一帧图像数据发送出去,PC作为服务器接收并显示每一帧图像实现远程监控。图片如下(后来PC端加了个拍照功能)。。。

 

(PS。刚学android和java不久很多东西还不懂,高手若是知道哪些地方可以继续优化的话还请多多指点下啊)

系统代码如下:
一、android手机客户端
(1)AndroidManifest.xml文件。添加camera和socket权限,并设置了程序开始执行的activity、

<?xml version= "1.0"  encoding= "utf-8" ?>
<manifest xmlns:android= "http://schemas.android.com/apk/res/android"
     package = "org.wanghai.CameraTest"
     android:versionCode= "1"
     android:versionName= "1.0"  >
 
     <uses-sdk android:minSdkVersion= "15"  />
     
     <!-- 授予程序使用摄像头的权限 -->
         <uses-permission android:name= "android.permission.CAMERA"  />
         <uses-feature android:name= "android.hardware.camera"  />
         <uses-feature android:name= "android.hardware.camera.autofocus"  />
         <uses-permission android:name= "android.permission.INTERNET" />
     <uses-permission android:name= "android.permission.KILL_BACKGROUND_PROCESSES" />
     <uses-permission android:name= "android.permission.RESTART_PACKAGES" />
 
     <application
         android:icon= "@drawable/ic_launcher"
         android:label= "@string/app_name"  >
                 
         <activity
             android:name= ".GetIP"
             android:screenOrientation= "landscape"
             android:label= "@string/app_name"  >
             <intent-filter>
                 <action android:name= "android.intent.action.MAIN"  />
                 <category android:name= "android.intent.category.LAUNCHER"  />
             </intent-filter>
         </activity>
         <activity
             android:name= ".CameraTest"
             android:screenOrientation= "landscape"
             android:label= "@string/app_name"  >
 
         </activity>
         
     </application>
 
</manifest>

  (2)main.xml 设置surfaceview用于摄像头采集图像的预览

<?xml version= "1.0"  encoding= "utf-8" ?>
<LinearLayout xmlns:android= "http://schemas.android.com/apk/res/android"
     android:layout_width= "fill_parent"
     android:layout_height= "fill_parent"
     android:orientation= "vertical"  >
 
    <SurfaceView
         android:id= "@+id/sView"
         android:layout_width= "fill_parent"
         android:layout_height= "fill_parent"
         android:scaleType= "fitCenter" />
 
</LinearLayout>

  (3)login.xml 登录界面,用于输入服务器IP

<?xml version= "1.0"  encoding= "utf-8" ?>
<TableLayout xmlns:android= "http://schemas.android.com/apk/res/android"
         android:id= "@+id/loginForm"
         android:orientation= "vertical"
         android:layout_width= "fill_parent"
         android:layout_height= "fill_parent"
         >
 
<TableRow>           
<TextView
         android:layout_width= "fill_parent"
         android:layout_height= "wrap_content"
         android:text= "IP:"
         android:textSize= "10pt"
         />
<!-- 输入用户名的文本框 -->
<EditText
     android:id= "@+id/ipedittext"
         android:layout_width= "fill_parent"
         android:layout_height= "wrap_content"
         android:digits= "0123456789."
         android:hint= "请填写服务器IP"
         android:selectAllOnFocus= "true"
         />
</TableRow>
 
</TableLayout>

  (4)GetIP.java 获得服务器IP后,通过Intent启动CameraTest的activity,ip信息通过Bundle传递

public  class  GetIP extends  Activity {
         String ipname = null ;
         @Override
     public  void  onCreate(Bundle savedInstanceState) {
         super .onCreate(savedInstanceState);
         // 设置全屏
         requestWindowFeature(Window.FEATURE_NO_TITLE);
              getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
         setContentView(R.layout.main);       
       
               final  Builder builder = new  AlertDialog.Builder( this );   //定义一个AlertDialog.Builder对象                                        
                 builder.setTitle( "登录服务器对话框" );                          // 设置对话框的标题
                 
                 //装载/res/layout/login.xml界面布局
                 TableLayout loginForm = (TableLayout)getLayoutInflater().inflate( R.layout.login, null );               
                 final  EditText iptext = (EditText)loginForm.findViewById(R.id.ipedittext);                               
                 builder.setView(loginForm);                              // 设置对话框显示的View对象
                 // 为对话框设置一个“登录”按钮
                 builder.setPositiveButton( "登录"
                         // 为按钮设置监听器
                         , new  OnClickListener() {
                                 @Override
                                 public  void  onClick(DialogInterface dialog, int  which) {
                                         //此处可执行登录处理
                                         ipname = iptext.getText().toString().trim();
                                         Bundle data = new  Bundle();
                                         data.putString( "ipname" ,ipname);                                       
                                         Intent intent = new  Intent(GetIP. this ,CameraTest. class );
                                         intent.putExtras(data);
                                         startActivity(intent);
                                 }
                         });
                 // 为对话框设置一个“取消”按钮
                 builder.setNegativeButton( "取消"
                         new  OnClickListener()
                         {
                                 @Override
                                 public  void  onClick(DialogInterface dialog, int  which)
                                 {
                                         //取消登录,不做任何事情。
                                         System.exit( 1 );
                                 }
                         });
                 //创建、并显示对话框
                 builder.create().show();
         }
}

  (5)CameraTest.java 程序主体。设置PreviewCallback后,每当一帧图像数据采集完成后将调用PreviewCallback的onPreviewFrame函数。在这里我们将YUV格式数据转为jpg,再启用线程将数据通过socket发送出去。

public  class  CameraTest extends  Activity {
         SurfaceView sView;
         SurfaceHolder surfaceHolder;
         int  screenWidth, screenHeight;       
         Camera camera;                    // 定义系统所用的照相机       
         boolean  isPreview = false ;        //是否在浏览中
         private  String ipname;
 
         @SuppressWarnings ( "deprecation" )
         @Override
     public  void  onCreate(Bundle savedInstanceState) {
         super .onCreate(savedInstanceState);
         // 设置全屏
              requestWindowFeature(Window.FEATURE_NO_TITLE);
              getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
         setContentView(R.layout.main);
         
         // 获取IP地址
         Intent intent = getIntent();
         Bundle data = intent.getExtras();
         ipname = data.getString( "ipname" );
                         
                 screenWidth = 640 ;
                 screenHeight = 480 ;               
                 sView = (SurfaceView) findViewById(R.id.sView);                  // 获取界面中SurfaceView组件               
                 surfaceHolder = sView.getHolder();                               // 获得SurfaceView的SurfaceHolder
                 
                 // 为surfaceHolder添加一个回调监听器
                 surfaceHolder.addCallback( new  Callback() {
                         @Override
                         public  void  surfaceChanged(SurfaceHolder holder, int  format, int  width, int  height) {                               
                         }
                         @Override
                         public  void  surfaceCreated(SurfaceHolder holder) {                                                       
                                 initCamera();                                            // 打开摄像头
                         }
                         @Override
                         public  void  surfaceDestroyed(SurfaceHolder holder) {
                                 // 如果camera不为null ,释放摄像头
                                 if  (camera != null ) {
                                         if  (isPreview)
                                                 camera.stopPreview();
                                         camera.release();
                                         camera = null ;
                                 }
                             System.exit( 0 );
                         }               
                 });
                 // 设置该SurfaceView自己不维护缓冲   
                 surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
                 
     }
     
     private  void  initCamera() {
             if  (!isPreview) {
                         camera = Camera.open();
                 }
                 if  (camera != null  && !isPreview) {
                         try {
                                 Camera.Parameters parameters = camera.getParameters();                               
                                 parameters.setPreviewSize(screenWidth, screenHeight);    // 设置预览照片的大小                               
                                 parameters.setPreviewFpsRange( 20 , 30 );                    // 每秒显示20~30帧                               
                                 parameters.setPictureFormat(ImageFormat.NV21);           // 设置图片格式                               
                                 parameters.setPictureSize(screenWidth, screenHeight);    // 设置照片的大小
                                 //camera.setParameters(parameters);                      // android2.3.3以后不需要此行代码
                                 camera.setPreviewDisplay(surfaceHolder);                 // 通过SurfaceView显示取景画面                               
                         camera.setPreviewCallback( new  StreamIt(ipname));         // 设置回调的类                               
                                 camera.startPreview();                                   // 开始预览                               
                                 camera.autoFocus( null );                                  // 自动对焦
                         } catch  (Exception e) {
                                 e.printStackTrace();
                         }
                         isPreview = true ;
                 }
     }
     
}
 
class  StreamIt implements  Camera.PreviewCallback {
         private  String ipname;
         public  StreamIt(String ipname){
                 this .ipname = ipname;
         }
         
     @Override
     public  void  onPreviewFrame( byte [] data, Camera camera) {
         Size size = camera.getParameters().getPreviewSize();         
         try {
                 //调用image.compressToJpeg()将YUV格式图像数据data转为jpg格式
             YuvImage image = new  YuvImage(data, ImageFormat.NV21, size.width, size.height, null ); 
             if (image!= null ){
                     ByteArrayOutputStream outstream = new  ByteArrayOutputStream();
                 image.compressToJpeg( new  Rect( 0 , 0 , size.width, size.height), 80 , outstream);
                 outstream.flush();
                 //启用线程将图像数据发送出去
                 Thread th = new  MyThread(outstream,ipname);
                 th.start();              
            
         } catch (Exception ex){ 
             Log.e( "Sys" , "Error:" +ex.getMessage()); 
         }       
     }
}
     
class  MyThread extends  Thread{       
         private  byte  byteBuffer[] = new  byte [ 1024 ];
         private  OutputStream outsocket;       
         private  ByteArrayOutputStream myoutputstream;
         private  String ipname;
         
         public  MyThread(ByteArrayOutputStream myoutputstream,String ipname){
                 this .myoutputstream = myoutputstream;
                 this .ipname = ipname;
         try  {
                         myoutputstream.close();
                 } catch  (IOException e) {
                         e.printStackTrace();
                 }
         }
         
     public  void  run() {
         try {
                 //将图像数据通过Socket发送出去
             Socket tempSocket = new  Socket(ipname, 6000 );
             outsocket = tempSocket.getOutputStream();
             ByteArrayInputStream inputstream = new  ByteArrayInputStream(myoutputstream.toByteArray());
             int  amount;
             while  ((amount = inputstream.read(byteBuffer)) != - 1 ) {
                 outsocket.write(byteBuffer, 0 , amount);
             }
             myoutputstream.flush();
             myoutputstream.close();
             tempSocket.close();                  
         } catch  (IOException e) {
             e.printStackTrace();
         }
     }
 
}

  二、PC服务器端
ImageServer.java 用于显示图像,并且可以拍照

public  class  ImageServer {       
     public  static  ServerSocket ss = null ;
     
     public  static  void  main(String args[]) throws  IOException{   
             ss = new  ServerSocket( 6000 );
         
         final  ImageFrame frame = new  ImageFrame(ss);
         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
         frame.setVisible( true );
        
         while ( true ){
                 frame.panel.getimage();
             frame.repaint();
         }       
     }
        
}
 
/**
     A frame with an image panel
*/
@SuppressWarnings ( "serial" )
class  ImageFrame extends  JFrame{
         public  ImagePanel panel;
         public  JButton jb;
    
     public  ImageFrame(ServerSocket ss){
                // get screen dimensions             
                Toolkit kit = Toolkit.getDefaultToolkit();
         Dimension screenSize = kit.getScreenSize();
         int  screenHeight = screenSize.height;
         int  screenWidth = screenSize.width;
 
         // center frame in screen
         setTitle( "ImageTest" );
         setLocation((screenWidth - DEFAULT_WIDTH) / 2 , (screenHeight - DEFAULT_HEIGHT) / 2 );
         setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
 
         // add panel to frame
         this .getContentPane().setLayout( null );
         panel = new  ImagePanel(ss);
         panel.setSize( 640 , 480 );
         panel.setLocation( 0 , 0 );
         add(panel);
         jb = new  JButton( "拍照" );
         jb.setBounds( 0 , 480 , 640 , 50 );
         add(jb);
         saveimage saveaction = new  saveimage(ss);
         jb.addActionListener(saveaction);
     }
 
     public  static  final  int  DEFAULT_WIDTH = 640 ;
     public  static  final  int  DEFAULT_HEIGHT = 560
}
 
/**
    A panel that displays a tiled image
*/
@SuppressWarnings ( "serial" )
class  ImagePanel extends  JPanel {    
     private  ServerSocket ss;
     private  Image image;
     private  InputStream ins;
          
     public  ImagePanel(ServerSocket ss) { 
             this .ss = ss;
     }
     
     public  void  getimage() throws  IOException{
             Socket s = this .ss.accept();
         System.out.println( "连接成功!" );
         this .ins = s.getInputStream();
                 this .image = ImageIO.read(ins);
                 this .ins.close();
     }
    
     public  void  paintComponent(Graphics g){ 
         super .paintComponent(g);   
         if  (image == null ) return ;
         g.drawImage(image, 0 , 0 , null );
     }
 
}
 
class  saveimage implements  ActionListener {
         RandomAccessFile inFile = null ;
         byte  byteBuffer[] = new  byte [ 1024 ];
         InputStream ins;
         private  ServerSocket ss;
         
         public  saveimage(ServerSocket ss){
                 this .ss = ss;
         }
         
         public  void  actionPerformed(ActionEvent event){
         try  {
                         Socket s = ss.accept();
                         ins = s.getInputStream();
                         
                         // 文件选择器以当前的目录打开
                 JFileChooser jfc = new  JFileChooser( "." );
                 jfc.showSaveDialog( new  javax.swing.JFrame());
                 // 获取当前的选择文件引用
                 File savedFile = jfc.getSelectedFile();
                 
                 // 已经选择了文件
                 if  (savedFile != null ) {
                     // 读取文件的数据,可以每次以快的方式读取数据
                     try  {
                                         inFile = new  RandomAccessFile(savedFile, "rw" );
                                 } catch  (FileNotFoundException e) {
                                         e.printStackTrace();
                                 }
                 }
 
             int  amount;
             while  ((amount = ins.read(byteBuffer)) != - 1 ) {
                 inFile.write(byteBuffer, 0 , amount);
             }
             inFile.close();
             ins.close();
             s.close();
             javax.swing.JOptionPane.showMessageDialog( new  javax.swing.JFrame(),
                     "已接保存成功" , "提示!" , javax.swing.JOptionPane.PLAIN_MESSAGE);
                 } catch  (IOException e) {
 
                         e.printStackTrace();
                 }
         }
}

  开放源码如下(android我使用的是4.03的SDK,其它版本请自行更改。2.3.3版本以下的请注意initCamera()里被注释掉的哪一行)

只能在android4.04系统的手机上运行成功哦。

下面是测试成功时的启动画面:

 

 源码链接:

http://files.cnblogs.com/feifei1010/%E5%9F%BA%E4%BA%8Eandroid%E6%89%8B%E6%9C%BA%E7%9A%84%E8%BF%9C%E7%A8%8B%E8%A7%86%E9%A2%91%E7%9B%91%E6%8E%A7%E7%B3%BB%E7%BB%9F.rar  

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页