android 远程视频监控系统

来源:互联网 发布:电脑制作音频软件 编辑:程序博客网 时间:2024/04/30 09:44

http://www.cnblogs.com/feifei1010/archive/2012/08/31/2664939.html

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

 

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

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

[html] view plain copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     package="org.wanghai.CameraTest"  
  4.     android:versionCode="1"  
  5.     android:versionName="1.0" >  
  6.    
  7.     <uses-sdk android:minSdkVersion="15" />  
  8.        
  9.     <!-- 授予程序使用摄像头的权限 -->  
  10.         <uses-permission android:name="android.permission.CAMERA" />   
  11.         <uses-feature android:name="android.hardware.camera" />   
  12.         <uses-feature android:name="android.hardware.camera.autofocus" />  
  13.         <uses-permission android:name="android.permission.INTERNET"/>  
  14.     <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES"/>  
  15.     <uses-permission android:name="android.permission.RESTART_PACKAGES"/>  
  16.    
  17.     <application  
  18.         android:icon="@drawable/ic_launcher"  
  19.         android:label="@string/app_name" >  
  20.                    
  21.         <activity  
  22.             android:name=".GetIP"  
  23.             android:screenOrientation="landscape"  
  24.             android:label="@string/app_name" >  
  25.             <intent-filter>  
  26.                 <action android:name="android.intent.action.MAIN" />  
  27.                 <category android:name="android.intent.category.LAUNCHER" />  
  28.             </intent-filter>  
  29.         </activity>  
  30.         <activity  
  31.             android:name=".CameraTest"  
  32.             android:screenOrientation="landscape"  
  33.             android:label="@string/app_name" >  
  34.    
  35.         </activity>  
  36.            
  37.     </application>  
  38.    
  39. </manifest>  

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

[java] view plain copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="fill_parent"  
  4.     android:layout_height="fill_parent"  
  5.     android:orientation="vertical" >  
  6.    
  7.    <SurfaceView  
  8.         android:id="@+id/sView"  
  9.         android:layout_width="fill_parent"  
  10.         android:layout_height="fill_parent"  
  11.         android:scaleType="fitCenter"/>  
  12.    
  13. </LinearLayout>  

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

[html] view plain copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <TableLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.         android:id="@+id/loginForm"  
  4.         android:orientation="vertical"  
  5.         android:layout_width="fill_parent"  
  6.         android:layout_height="fill_parent"  
  7.         >  
  8.    
  9. <TableRow>              
  10. <TextView  
  11.         android:layout_width="fill_parent"  
  12.         android:layout_height="wrap_content"  
  13.         android:text="IP:"  
  14.         android:textSize="10pt"  
  15.         />  
  16. <!-- 输入用户名的文本框 -->  
  17. <EditText  
  18.     android:id="@+id/ipedittext"  
  19.         android:layout_width="fill_parent"  
  20.         android:layout_height="wrap_content"  
  21.         android:digits="0123456789."  
  22.         android:hint="请填写服务器IP"  
  23.         android:selectAllOnFocus="true"  
  24.         />  
  25. </TableRow>  
  26.    
  27. </TableLayout>  

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

[java] view plain copy
  1. public class GetIP extends Activity {  
  2.         String ipname = null;  
  3.         @Override  
  4.     public void onCreate(Bundle savedInstanceState) {  
  5.         super.onCreate(savedInstanceState);  
  6.         // 设置全屏  
  7.         requestWindowFeature(Window.FEATURE_NO_TITLE);  
  8.              getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);  
  9.         setContentView(R.layout.main);          
  10.          
  11.               final Builder builder = new AlertDialog.Builder(this);   //定义一个AlertDialog.Builder对象                                           
  12.                 builder.setTitle("登录服务器对话框");                          // 设置对话框的标题  
  13.                    
  14.                 //装载/res/layout/login.xml界面布局  
  15.                 TableLayout loginForm = (TableLayout)getLayoutInflater().inflate( R.layout.login, null);                  
  16.                 final EditText iptext = (EditText)loginForm.findViewById(R.id.ipedittext);                                  
  17.                 builder.setView(loginForm);                              // 设置对话框显示的View对象  
  18.                 // 为对话框设置一个“登录”按钮  
  19.                 builder.setPositiveButton("登录"  
  20.                         // 为按钮设置监听器  
  21.                         , new OnClickListener() {  
  22.                                 @Override  
  23.                                 public void onClick(DialogInterface dialog, int which) {  
  24.                                         //此处可执行登录处理  
  25.                                         ipname = iptext.getText().toString().trim();  
  26.                                         Bundle data = new Bundle();  
  27.                                         data.putString("ipname",ipname);                                          
  28.                                         Intent intent = new Intent(GetIP.this,CameraTest.class);  
  29.                                         intent.putExtras(data);  
  30.                                         startActivity(intent);  
  31.                                 }  
  32.                         });  
  33.                 // 为对话框设置一个“取消”按钮  
  34.                 builder.setNegativeButton("取消"  
  35.                         ,  new OnClickListener()  
  36.                         {  
  37.                                 @Override  
  38.                                 public void onClick(DialogInterface dialog, int which)  
  39.                                 {  
  40.                                         //取消登录,不做任何事情。  
  41.                                         System.exit(1);  
  42.                                 }  
  43.                         });  
  44.                 //创建、并显示对话框  
  45.                 builder.create().show();  
  46.         }  
  47. }  

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

[java] view plain copy
  1. public class CameraTest extends Activity {  
  2.         SurfaceView sView;  
  3.         SurfaceHolder surfaceHolder;  
  4.         int screenWidth, screenHeight;          
  5.         Camera camera;                    // 定义系统所用的照相机          
  6.         boolean isPreview = false;        //是否在浏览中  
  7.         private String ipname;  
  8.    
  9.         @SuppressWarnings("deprecation")  
  10.         @Override  
  11.     public void onCreate(Bundle savedInstanceState) {  
  12.         super.onCreate(savedInstanceState);  
  13.         // 设置全屏  
  14.              requestWindowFeature(Window.FEATURE_NO_TITLE);  
  15.              getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);  
  16.         setContentView(R.layout.main);  
  17.            
  18.         // 获取IP地址  
  19.         Intent intent = getIntent();  
  20.         Bundle data = intent.getExtras();  
  21.         ipname = data.getString("ipname");  
  22.                            
  23.                 screenWidth = 640;  
  24.                 screenHeight = 480;                  
  25.                 sView = (SurfaceView) findViewById(R.id.sView);                  // 获取界面中SurfaceView组件                  
  26.                 surfaceHolder = sView.getHolder();                               // 获得SurfaceView的SurfaceHolder  
  27.                    
  28.                 // 为surfaceHolder添加一个回调监听器  
  29.                 surfaceHolder.addCallback(new Callback() {  
  30.                         @Override  
  31.                         public void surfaceChanged(SurfaceHolder holder, int format, int width,int height) {                                  
  32.                         }  
  33.                         @Override  
  34.                         public void surfaceCreated(SurfaceHolder holder) {                                                          
  35.                                 initCamera();                                            // 打开摄像头  
  36.                         }  
  37.                         @Override  
  38.                         public void surfaceDestroyed(SurfaceHolder holder) {  
  39.                                 // 如果camera不为null ,释放摄像头  
  40.                                 if (camera != null) {  
  41.                                         if (isPreview)  
  42.                                                 camera.stopPreview();  
  43.                                         camera.release();  
  44.                                         camera = null;  
  45.                                 }  
  46.                             System.exit(0);  
  47.                         }                  
  48.                 });  
  49.                 // 设置该SurfaceView自己不维护缓冲      
  50.                 surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);  
  51.                    
  52.     }  
  53.        
  54.     private void initCamera() {  
  55.             if (!isPreview) {  
  56.                         camera = Camera.open();  
  57.                 }  
  58.                 if (camera != null && !isPreview) {  
  59.                         try{  
  60.                                 Camera.Parameters parameters = camera.getParameters();                                  
  61.                                 parameters.setPreviewSize(screenWidth, screenHeight);    // 设置预览照片的大小                                  
  62.                                 parameters.setPreviewFpsRange(20,30);                    // 每秒显示20~30帧                                  
  63.                                 parameters.setPictureFormat(ImageFormat.NV21);           // 设置图片格式                                  
  64.                                 parameters.setPictureSize(screenWidth, screenHeight);    // 设置照片的大小  
  65.                                 //camera.setParameters(parameters);                      // android2.3.3以后不需要此行代码  
  66.                                 camera.setPreviewDisplay(surfaceHolder);                 // 通过SurfaceView显示取景画面                                  
  67.                         camera.setPreviewCallback(new StreamIt(ipname));         // 设置回调的类                                  
  68.                                 camera.startPreview();                                   // 开始预览                                  
  69.                                 camera.autoFocus(null);                                  // 自动对焦  
  70.                         } catch (Exception e) {  
  71.                                 e.printStackTrace();  
  72.                         }  
  73.                         isPreview = true;  
  74.                 }  
  75.     }  
  76.        
  77. }  
  78.    
  79. class StreamIt implements Camera.PreviewCallback {  
  80.         private String ipname;  
  81.         public StreamIt(String ipname){  
  82.                 this.ipname = ipname;  
  83.         }  
  84.            
  85.     @Override  
  86.     public void onPreviewFrame(byte[] data, Camera camera) {  
  87.         Size size = camera.getParameters().getPreviewSize();            
  88.         try{   
  89.                 //调用image.compressToJpeg()将YUV格式图像数据data转为jpg格式  
  90.             YuvImage image = new YuvImage(data, ImageFormat.NV21, size.width, size.height, null);    
  91.             if(image!=null){  
  92.                     ByteArrayOutputStream outstream = new ByteArrayOutputStream();  
  93.                 image.compressToJpeg(new Rect(00, size.width, size.height), 80, outstream);   
  94.                 outstream.flush();  
  95.                 //启用线程将图像数据发送出去  
  96.                 Thread th = new MyThread(outstream,ipname);  
  97.                 th.start();                 
  98.             }    
  99.         }catch(Exception ex){    
  100.             Log.e("Sys","Error:"+ex.getMessage());    
  101.         }          
  102.     }  
  103. }  
  104.        
  105. class MyThread extends Thread{          
  106.         private byte byteBuffer[] = new byte[1024];  
  107.         private OutputStream outsocket;          
  108.         private ByteArrayOutputStream myoutputstream;  
  109.         private String ipname;  
  110.            
  111.         public MyThread(ByteArrayOutputStream myoutputstream,String ipname){  
  112.                 this.myoutputstream = myoutputstream;  
  113.                 this.ipname = ipname;  
  114.         try {  
  115.                         myoutputstream.close();  
  116.                 } catch (IOException e) {  
  117.                         e.printStackTrace();  
  118.                 }  
  119.         }  
  120.            
  121.     public void run() {  
  122.         try{  
  123.                 //将图像数据通过Socket发送出去  
  124.             Socket tempSocket = new Socket(ipname, 6000);  
  125.             outsocket = tempSocket.getOutputStream();  
  126.             ByteArrayInputStream inputstream = new ByteArrayInputStream(myoutputstream.toByteArray());  
  127.             int amount;  
  128.             while ((amount = inputstream.read(byteBuffer)) != -1) {  
  129.                 outsocket.write(byteBuffer, 0, amount);  
  130.             }  
  131.             myoutputstream.flush();  
  132.             myoutputstream.close();  
  133.             tempSocket.close();                     
  134.         } catch (IOException e) {  
  135.             e.printStackTrace();  
  136.         }  
  137.     }  
  138.    
  139. }  

二、PC服务器端

ImageServer.java 用于显示图像,并且可以拍照

[java] view plain copy
  1. public class ImageServer {          
  2.     public static ServerSocket ss = null;  
  3.        
  4.     public static void main(String args[]) throws IOException{      
  5.             ss = new ServerSocket(6000);  
  6.            
  7.         final ImageFrame frame = new ImageFrame(ss);  
  8.         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  
  9.         frame.setVisible(true);  
  10.           
  11.         while(true){  
  12.                 frame.panel.getimage();  
  13.             frame.repaint();  
  14.         }          
  15.     }  
  16.           
  17. }  
  18.    
  19. /**  
  20.     A frame with an image panel 
  21. */  
  22. @SuppressWarnings("serial")  
  23. class ImageFrame extends JFrame{  
  24.         public ImagePanel panel;  
  25.         public JButton jb;  
  26.       
  27.     public ImageFrame(ServerSocket ss){  
  28.                // get screen dimensions                
  29.                Toolkit kit = Toolkit.getDefaultToolkit();  
  30.         Dimension screenSize = kit.getScreenSize();  
  31.         int screenHeight = screenSize.height;  
  32.         int screenWidth = screenSize.width;  
  33.    
  34.         // center frame in screen  
  35.         setTitle("ImageTest");  
  36.         setLocation((screenWidth - DEFAULT_WIDTH) / 2, (screenHeight - DEFAULT_HEIGHT) / 2);  
  37.         setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);  
  38.    
  39.         // add panel to frame  
  40.         this.getContentPane().setLayout(null);  
  41.         panel = new ImagePanel(ss);  
  42.         panel.setSize(640,480);  
  43.         panel.setLocation(00);  
  44.         add(panel);  
  45.         jb = new JButton("拍照");  
  46.         jb.setBounds(0,480,640,50);  
  47.         add(jb);  
  48.         saveimage saveaction = new saveimage(ss);  
  49.         jb.addActionListener(saveaction);  
  50.     }  
  51.    
  52.     public static final int DEFAULT_WIDTH = 640;  
  53.     public static final int DEFAULT_HEIGHT = 560;    
  54. }  
  55.    
  56. /** 
  57.    A panel that displays a tiled image 
  58. */  
  59. @SuppressWarnings("serial")  
  60. class ImagePanel extends JPanel {       
  61.     private ServerSocket ss;  
  62.     private Image image;  
  63.     private InputStream ins;  
  64.             
  65.     public ImagePanel(ServerSocket ss) {    
  66.             this.ss = ss;  
  67.     }  
  68.        
  69.     public void getimage() throws IOException{  
  70.             Socket s = this.ss.accept();  
  71.         System.out.println("连接成功!");  
  72.         this.ins = s.getInputStream();  
  73.                 this.image = ImageIO.read(ins);  
  74.                 this.ins.close();  
  75.     }  
  76.       
  77.     public void paintComponent(Graphics g){    
  78.         super.paintComponent(g);      
  79.         if (image == nullreturn;  
  80.         g.drawImage(image, 00null);  
  81.     }  
  82.    
  83. }  
  84.    
  85. class saveimage implements ActionListener {  
  86.         RandomAccessFile inFile = null;  
  87.         byte byteBuffer[] = new byte[1024];  
  88.         InputStream ins;  
  89.         private ServerSocket ss;  
  90.            
  91.         public saveimage(ServerSocket ss){  
  92.                 this.ss = ss;  
  93.         }  
  94.            
  95.         public void actionPerformed(ActionEvent event){  
  96.         try {  
  97.                         Socket s = ss.accept();  
  98.                         ins = s.getInputStream();  
  99.                            
  100.                         // 文件选择器以当前的目录打开  
  101.                 JFileChooser jfc = new JFileChooser(".");  
  102.                 jfc.showSaveDialog(new javax.swing.JFrame());  
  103.                 // 获取当前的选择文件引用  
  104.                 File savedFile = jfc.getSelectedFile();  
  105.                    
  106.                 // 已经选择了文件  
  107.                 if (savedFile != null) {  
  108.                     // 读取文件的数据,可以每次以快的方式读取数据  
  109.                     try {  
  110.                                         inFile = new RandomAccessFile(savedFile, "rw");  
  111.                                 } catch (FileNotFoundException e) {  
  112.                                         e.printStackTrace();  
  113.                                 }  
  114.                 }  
  115.    
  116.             int amount;  
  117.             while ((amount = ins.read(byteBuffer)) != -1) {  
  118.                 inFile.write(byteBuffer, 0, amount);  
  119.             }  
  120.             inFile.close();  
  121.             ins.close();  
  122.             s.close();  
  123.             javax.swing.JOptionPane.showMessageDialog(new javax.swing.JFrame(),  
  124.                     "已接保存成功""提示!", javax.swing.JOptionPane.PLAIN_MESSAGE);  
  125.                 } catch (IOException e) {  
  126.    
  127.                         e.printStackTrace();  
  128.                 }  
  129.         }  
  130. }  

  开放源码如下(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%B

0 0
原创粉丝点击