#Testin杯#基于android的远程视频监控系统——学习第一步:实现Camera预览

116 篇文章 0 订阅
28 篇文章 0 订阅
http://www.apkbus.com/android-57452-1-1.html


本文参与:Testin—安卓巴士Android开发原创教程大赛
基本过程是android作为socket客户端将采集到的每一帧图像数据发送出去,PC作为服务器接收并显示每一帧图像实现远程监控。图片如下(后来PC端加了个拍照功能)。。。
 
(PS。刚学android和java不久很多东西还不懂,高手若是知道哪些地方可以继续优化的话还请多多指点下啊)
此贴是这个系统的介绍,没有基础的朋友可以参考下面教程(会陆续补充完整,让大家都学会如何实现整个功能):
(1)#Testin杯#基于android的远程视频监控系统——学习第一步实现Camera预览


系统代码如下:
一、android手机客户端
(1)AndroidManifest.xml文件。添加camera和socket权限,并设置了程序开始执行的activity
  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.     <uses-sdk android:minSdkVersion="15" />
  7.     
  8.     <!-- 授予程序使用摄像头的权限 -->
  9.         <uses-permission android:name="android.permission.CAMERA" /> 
  10.         <uses-feature android:name="android.hardware.camera" /> 
  11.         <uses-feature android:name="android.hardware.camera.autofocus" />
  12.         <uses-permission android:name="android.permission.INTERNET"/>
  13.     <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES"/>
  14.     <uses-permission android:name="android.permission.RESTART_PACKAGES"/>

  15.     <application
  16.         android:icon="@drawable/ic_launcher"
  17.         android:label="@string/app_name" >
  18.                 
  19.         <activity
  20.             android:name=".GetIP"
  21.             android:screenOrientation="landscape"
  22.             android:label="@string/app_name" >
  23.             <intent-filter>
  24.                 <action android:name="android.intent.action.MAIN" />
  25.                 <category android:name="android.intent.category.LAUNCHER" />
  26.             </intent-filter>
  27.         </activity>
  28.         <activity
  29.             android:name=".CameraTest"
  30.             android:screenOrientation="landscape"
  31.             android:label="@string/app_name" >

  32.         </activity>
  33.         
  34.     </application>

  35. </manifest>
复制代码
(2)main.xml 设置surfaceview用于摄像头采集图像的预览
  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.    <SurfaceView
  7.         android:id="@+id/sView"
  8.         android:layout_width="fill_parent" 
  9.         android:layout_height="fill_parent"
  10.         android:scaleType="fitCenter"/>

  11. </LinearLayout>
复制代码
(3)login.xml 登录界面,用于输入服务器IP
  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. <TableRow>            
  9. <TextView
  10.         android:layout_width="fill_parent"
  11.         android:layout_height="wrap_content"
  12.         android:text="IP:"
  13.         android:textSize="10pt"
  14.         />
  15. <!-- 输入用户名的文本框 -->
  16. <EditText
  17.     android:id="@+id/ipedittext"
  18.         android:layout_width="fill_parent"
  19.         android:layout_height="wrap_content"
  20.         android:digits="0123456789."
  21.         android:hint="请填写服务器IP"
  22.         android:selectAllOnFocus="true"
  23.         />
  24. </TableRow>

  25. </TableLayout>
复制代码
(4)GetIP.java 获得服务器IP后,通过Intent启动CameraTest的activity,ip信息通过Bundle传递
  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发送出去。
  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.         @SuppressWarnings("deprecation")
  9.         @Override
  10.     public void onCreate(Bundle savedInstanceState) {
  11.         super.onCreate(savedInstanceState);
  12.         // 设置全屏
  13.              requestWindowFeature(Window.FEATURE_NO_TITLE);
  14.              getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
  15.         setContentView(R.layout.main);
  16.         
  17.         // 获取IP地址
  18.         Intent intent = getIntent();
  19.         Bundle data = intent.getExtras();
  20.         ipname = data.getString("ipname");
  21.                         
  22.                 screenWidth = 640;
  23.                 screenHeight = 480;                
  24.                 sView = (SurfaceView) findViewById(R.id.sView);                  // 获取界面中SurfaceView组件                
  25.                 surfaceHolder = sView.getHolder();                               // 获得SurfaceView的SurfaceHolder
  26.                 
  27.                 // 为surfaceHolder添加一个回调监听器
  28.                 surfaceHolder.addCallback(new Callback() {
  29.                         @Override
  30.                         public void surfaceChanged(SurfaceHolder holder, int format, int width,int height) {                                
  31.                         }
  32.                         @Override
  33.                         public void surfaceCreated(SurfaceHolder holder) {                                                        
  34.                                 initCamera();                                            // 打开摄像头
  35.                         }
  36.                         @Override
  37.                         public void surfaceDestroyed(SurfaceHolder holder) {
  38.                                 // 如果camera不为null ,释放摄像头
  39.                                 if (camera != null) {
  40.                                         if (isPreview)
  41.                                                 camera.stopPreview();
  42.                                         camera.release();
  43.                                         camera = null;
  44.                                 }
  45.                             System.exit(0);
  46.                         }                
  47.                 });
  48.                 // 设置该SurfaceView自己不维护缓冲    
  49.                 surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
  50.                 
  51.     }
  52.     
  53.     private void initCamera() {
  54.             if (!isPreview) {
  55.                         camera = Camera.open();
  56.                 }
  57.                 if (camera != null && !isPreview) {
  58.                         try{
  59.                                 Camera.Parameters parameters = camera.getParameters();                                
  60.                                 parameters.setPreviewSize(screenWidth, screenHeight);    // 设置预览照片的大小                                
  61.                                 parameters.setPreviewFpsRange(20,30);                    // 每秒显示20~30帧                                
  62.                                 parameters.setPictureFormat(ImageFormat.NV21);           // 设置图片格式                                
  63.                                 parameters.setPictureSize(screenWidth, screenHeight);    // 设置照片的大小
  64.                                 //camera.setParameters(parameters);                      // android2.3.3以后不需要此行代码
  65.                                 camera.setPreviewDisplay(surfaceHolder);                 // 通过SurfaceView显示取景画面                                
  66.                         camera.setPreviewCallback(new StreamIt(ipname));         // 设置回调的类                                
  67.                                 camera.startPreview();                                   // 开始预览                                
  68.                                 camera.autoFocus(null);                                  // 自动对焦
  69.                         } catch (Exception e) {
  70.                                 e.printStackTrace();
  71.                         }
  72.                         isPreview = true;
  73.                 }
  74.     }
  75.     
  76. }

  77. class StreamIt implements Camera.PreviewCallback {
  78.         private String ipname;
  79.         public StreamIt(String ipname){
  80.                 this.ipname = ipname;
  81.         }
  82.         
  83.     @Override
  84.     public void onPreviewFrame(byte[] data, Camera camera) {
  85.         Size size = camera.getParameters().getPreviewSize();          
  86.         try{ 
  87.                 //调用image.compressToJpeg()将YUV格式图像数据data转为jpg格式
  88.             YuvImage image = new YuvImage(data, ImageFormat.NV21, size.width, size.height, null);  
  89.             if(image!=null){
  90.                     ByteArrayOutputStream outstream = new ByteArrayOutputStream();
  91.                 image.compressToJpeg(new Rect(0, 0, size.width, size.height), 80, outstream); 
  92.                 outstream.flush();
  93.                 //启用线程将图像数据发送出去
  94.                 Thread th = new MyThread(outstream,ipname);
  95.                 th.start();               
  96.             }  
  97.         }catch(Exception ex){  
  98.             Log.e("Sys","Error:"+ex.getMessage());  
  99.         }        
  100.     }
  101. }
  102.     
  103. class MyThread extends Thread{        
  104.         private byte byteBuffer[] = new byte[1024];
  105.         private OutputStream outsocket;        
  106.         private ByteArrayOutputStream myoutputstream;
  107.         private String ipname;
  108.         
  109.         public MyThread(ByteArrayOutputStream myoutputstream,String ipname){
  110.                 this.myoutputstream = myoutputstream;
  111.                 this.ipname = ipname;
  112.         try {
  113.                         myoutputstream.close();
  114.                 } catch (IOException e) {
  115.                         e.printStackTrace();
  116.                 }
  117.         }
  118.         
  119.     public void run() {
  120.         try{
  121.                 //将图像数据通过Socket发送出去
  122.             Socket tempSocket = new Socket(ipname, 6000);
  123.             outsocket = tempSocket.getOutputStream();
  124.             ByteArrayInputStream inputstream = new ByteArrayInputStream(myoutputstream.toByteArray());
  125.             int amount;
  126.             while ((amount = inputstream.read(byteBuffer)) != -1) {
  127.                 outsocket.write(byteBuffer, 0, amount);
  128.             }
  129.             myoutputstream.flush();
  130.             myoutputstream.close();
  131.             tempSocket.close();                   
  132.         } catch (IOException e) {
  133.             e.printStackTrace();
  134.         }
  135.     }

  136. }
复制代码
二、PC服务器端
ImageServer.java 用于显示图像,并且可以拍照
  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.     A frame with an image panel
  20. */
  21. @SuppressWarnings("serial")
  22. class ImageFrame extends JFrame{
  23.         public ImagePanel panel;
  24.         public JButton jb;
  25.    
  26.     public ImageFrame(ServerSocket ss){
  27.                // get screen dimensions              
  28.                Toolkit kit = Toolkit.getDefaultToolkit();
  29.         Dimension screenSize = kit.getScreenSize();
  30.         int screenHeight = screenSize.height;
  31.         int screenWidth = screenSize.width;

  32.         // center frame in screen
  33.         setTitle("ImageTest");
  34.         setLocation((screenWidth - DEFAULT_WIDTH) / 2, (screenHeight - DEFAULT_HEIGHT) / 2);
  35.         setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);

  36.         // add panel to frame
  37.         this.getContentPane().setLayout(null);
  38.         panel = new ImagePanel(ss);
  39.         panel.setSize(640,480);
  40.         panel.setLocation(0, 0);
  41.         add(panel);
  42.         jb = new JButton("拍照");
  43.         jb.setBounds(0,480,640,50);
  44.         add(jb);
  45.         saveimage saveaction = new saveimage(ss);
  46.         jb.addActionListener(saveaction);
  47.     }

  48.     public static final int DEFAULT_WIDTH = 640;
  49.     public static final int DEFAULT_HEIGHT = 560;  
  50. }

  51. /**
  52.    A panel that displays a tiled image
  53. */
  54. @SuppressWarnings("serial")
  55. class ImagePanel extends JPanel {     
  56.     private ServerSocket ss;
  57.     private Image image;
  58.     private InputStream ins;
  59.          
  60.     public ImagePanel(ServerSocket ss) {  
  61.             this.ss = ss;
  62.     }
  63.     
  64.     public void getimage() throws IOException{
  65.             Socket s = this.ss.accept();
  66.         System.out.println("连接成功!");
  67.         this.ins = s.getInputStream();
  68.                 this.image = ImageIO.read(ins);
  69.                 this.ins.close();
  70.     }
  71.    
  72.     public void paintComponent(Graphics g){  
  73.         super.paintComponent(g);    
  74.         if (image == null) return;
  75.         g.drawImage(image, 0, 0, null);
  76.     }

  77. }

  78. class saveimage implements ActionListener {
  79.         RandomAccessFile inFile = null;
  80.         byte byteBuffer[] = new byte[1024];
  81.         InputStream ins;
  82.         private ServerSocket ss;
  83.         
  84.         public saveimage(ServerSocket ss){
  85.                 this.ss = ss;
  86.         }
  87.         
  88.         public void actionPerformed(ActionEvent event){
  89.         try {
  90.                         Socket s = ss.accept();
  91.                         ins = s.getInputStream();
  92.                         
  93.                         // 文件选择器以当前的目录打开
  94.                 JFileChooser jfc = new JFileChooser(".");
  95.                 jfc.showSaveDialog(new javax.swing.JFrame());
  96.                 // 获取当前的选择文件引用
  97.                 File savedFile = jfc.getSelectedFile();
  98.                 
  99.                 // 已经选择了文件
  100.                 if (savedFile != null) {
  101.                     // 读取文件的数据,可以每次以快的方式读取数据
  102.                     try {
  103.                                         inFile = new RandomAccessFile(savedFile, "rw");
  104.                                 } catch (FileNotFoundException e) {
  105.                                         e.printStackTrace();
  106.                                 }
  107.                 }

  108.             int amount;
  109.             while ((amount = ins.read(byteBuffer)) != -1) {
  110.                 inFile.write(byteBuffer, 0, amount);
  111.             }
  112.             inFile.close();
  113.             ins.close();
  114.             s.close();
  115.             javax.swing.JOptionPane.showMessageDialog(new javax.swing.JFrame(),
  116.                     "已接保存成功", "提示!", javax.swing.JOptionPane.PLAIN_MESSAGE);
  117.                 } catch (IOException e) {

  118.                         e.printStackTrace();
  119.                 }
  120.         }
  121. }
复制代码
开放源码如下(android我使用的是4.03的SDK,其它版本请自行更改。2.3.3版本以下的请注意initCamera()里被注释掉的哪一行)
游客,如果您要查看本帖隐藏内容请 回复


Testin ID:m15271812941@163.com。刚刚把这个程序的apk上传测试了下,只能在android4.04系统的手机上运行成功哦。测试的各个参数蛮丰富的,机型也多,手上手机不多的在上面测试下确实挺实用。下面是测试成功时的启动画面
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值