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

系统代码如下:
一、android手机客户端

(1)AndroidManifest.xml文件。添加camera和socket权限,并设置了程序开始执行的activity

  1. <font size="3"><?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android="<a href="http://schemas.android.com/apk/res/android">http://schemas.android.com/apk/res/android</a>"
  3. package="org.wanghai.CameraTest"
  4. android:versionCode="1"
  5. android:versionName="1.0" >
  6. <uses-sdk android:minSdkVersion="15" />

  7. <!-- 授予程序使用摄像头的权限 -->
  8. <uses-permission android:name="android.permission.CAMERA" />
  9. <uses-feature android:name="android.hardware.camera" />
  10. <uses-feature android:name="android.hardware.camera.autofocus" />
  11. <uses-permission android:name="android.permission.INTERNET"/>
  12. <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES"/>
  13. <uses-permission android:name="android.permission.RESTART_PACKAGES"/>
  14. <application
  15. android:icon="@drawable/ic_launcher"
  16. android:label="@string/app_name" >

  17. <activity
  18. android:name=".GetIP"
  19. android:screenOrientation="landscape"
  20. android:label="@string/app_name" >
  21. <intent-filter>
  22. <action android:name="android.intent.action.MAIN" />
  23. <category android:name="android.intent.category.LAUNCHER" />
  24. </intent-filter>
  25. </activity>
  26. <activity
  27. android:name=".CameraTest"
  28. android:screenOrientation="landscape"
  29. android:label="@string/app_name" >[/size][/size]
  30. </activity>

  31. </application>
  32. </manifest>
  33. </font>
复制代码 (2)main.xml 设置surfaceview用于摄像头采集图像的预览

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="<a href="http://schemas.android.com/apk/res/android">http://schemas.android.com/apk/res/android</a>"
  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="<a href="http://schemas.android.com/apk/res/android">http://schemas.android.com/apk/res/android</a>"
  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. final Builder builder = new AlertDialog.Builder(this); //定义一个AlertDialog.Builder对象
  11. builder.setTitle("登录服务器对话框"); // 设置对话框的标题

  12. //装载/res/layout/login.xml界面布局
  13. TableLayout loginForm = (TableLayout)getLayoutInflater().inflate( R.layout.login, null);
  14. final EditText iptext = (EditText)loginForm.findViewById(R.id.ipedittext);
  15. builder.setView(loginForm); // 设置对话框显示的View对象
  16. // 为对话框设置一个“登录”按钮
  17. builder.setPositiveButton("登录"
  18. // 为按钮设置监听器
  19. , new OnClickListener() {
  20. @Override
  21. public void onClick(DialogInterface dialog, int which) {
  22. //此处可执行登录处理
  23. ipname = iptext.getText().toString().trim();
  24. Bundle data = new Bundle();
  25. data.putString("ipname",ipname);
  26. Intent intent = new Intent(GetIP.this,CameraTest.class);
  27. intent.putExtras(data);
  28. startActivity(intent);
  29. }
  30. });
  31. // 为对话框设置一个“取消”按钮
  32. builder.setNegativeButton("取消"
  33. ,new OnClickListener()
  34. {
  35. @Override
  36. public void onClick(DialogInterface dialog, int which)
  37. {
  38. //取消登录,不做任何事情。
  39. System.exit(1);
  40. }
  41. });
  42. //创建、并显示对话框
  43. builder.create().show();
  44. }
  45. }

复制代码
(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. // 获取IP地址
  17. Intent intent = getIntent();
  18. Bundle data = intent.getExtras();
  19. ipname = data.getString("ipname");

  20. screenWidth = 640;
  21. screenHeight = 480;
  22. sView = (SurfaceView) findViewById(R.id.sView); // 获取界面中SurfaceView组件
  23. surfaceHolder = sView.getHolder(); // 获得SurfaceView的SurfaceHolder

  24. // 为surfaceHolder添加一个回调监听器
  25. surfaceHolder.addCallback(new Callback() {
  26. @Override
  27. public void surfaceChanged(SurfaceHolder holder, int format, int width,int height) {
  28. }
  29. @Override
  30. public void surfaceCreated(SurfaceHolder holder) {
  31. initCamera(); // 打开摄像头
  32. }
  33. @Override
  34. public void surfaceDestroyed(SurfaceHolder holder) {
  35. // 如果camera不为null ,释放摄像头
  36. if (camera != null) {
  37. if (isPreview)
  38. camera.stopPreview();
  39. camera.release();
  40. camera = null;
  41. }
  42. System.exit(0);
  43. }
  44. });
  45. // 设置该SurfaceView自己不维护缓冲
  46. surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

  47. }

  48. private void initCamera() {
  49. if (!isPreview) {
  50. camera = Camera.open();
  51. }
  52. if (camera != null && !isPreview) {
  53. try{
  54. Camera.Parameters parameters = camera.getParameters();
  55. parameters.setPreviewSize(screenWidth, screenHeight); // 设置预览照片的大小
  56. parameters.setPreviewFpsRange(20,30); // 每秒显示20~30帧
  57. parameters.setPictureFormat(ImageFormat.NV21); // 设置图片格式
  58. parameters.setPictureSize(screenWidth, screenHeight); // 设置照片的大小
  59. //camera.setParameters(parameters); // android2.3.3以后不需要此行代码
  60. camera.setPreviewDisplay(surfaceHolder); // 通过SurfaceView显示取景画面
  61. camera.setPreviewCallback(new StreamIt(ipname)); // 设置回调的类
  62. camera.startPreview(); // 开始预览
  63. camera.autoFocus(null); // 自动对焦
  64. } catch (Exception e) {
  65. e.printStackTrace();
  66. }
  67. isPreview = true;
  68. }
  69. }

  70. }
  71. class StreamIt implements Camera.PreviewCallback {
  72. private String ipname;
  73. public StreamIt(String ipname){
  74. this.ipname = ipname;
  75. }

  76. @Override
  77. public void onPreviewFrame(byte[] data, Camera camera) {
  78. Size size = camera.getParameters().getPreviewSize();
  79. try{
  80. //调用image.compressToJpeg()将YUV格式图像数据data转为jpg格式
  81. YuvImage image = new YuvImage(data, ImageFormat.NV21, size.width, size.height, null);
  82. if(image!=null){
  83. ByteArrayOutputStream outstream = new ByteArrayOutputStream();
  84. image.compressToJpeg(new Rect(0, 0, size.width, size.height), 80, outstream);
  85. outstream.flush();
  86. //启用线程将图像数据发送出去
  87. Thread th = new MyThread(outstream,ipname);
  88. th.start();
  89. }
  90. }catch(Exception ex){
  91. Log.e("Sys","Error:"+ex.getMessage());
  92. }
  93. }
  94. }

  95. class MyThread extends Thread{
  96. private byte byteBuffer[] = new byte[1024];
  97. private OutputStream outsocket;
  98. private ByteArrayOutputStream myoutputstream;
  99. private String ipname;

  100. public MyThread(ByteArrayOutputStream myoutputstream,String ipname){
  101. this.myoutputstream = myoutputstream;
  102. this.ipname = ipname;
  103. try {
  104. myoutputstream.close();
  105. } catch (IOException e) {
  106. e.printStackTrace();
  107. }
  108. }

  109. public void run() {
  110. try{
  111. //将图像数据通过Socket发送出去
  112. Socket tempSocket = new Socket(ipname, 6000);
  113. outsocket = tempSocket.getOutputStream();
  114. ByteArrayInputStream inputstream = new ByteArrayInputStream(myoutputstream.toByteArray());
  115. int amount;
  116. while ((amount = inputstream.read(byteBuffer)) != -1) {
  117. outsocket.write(byteBuffer, 0, amount);
  118. }
  119. myoutputstream.flush();
  120. myoutputstream.close();
  121. tempSocket.close();
  122. } catch (IOException e) {
  123. e.printStackTrace();
  124. }
  125. }
  126. }

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


  1. public class ImageServer {
  2. public static ServerSocket ss = null;

  3. public static void main(String args[]) throws IOException{
  4. ss = new ServerSocket(6000);

  5. final ImageFrame frame = new ImageFrame(ss);
  6. frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  7. frame.setVisible(true);

  8. while(true){
  9. frame.panel.getimage();
  10. frame.repaint();
  11. }
  12. }

  13. }
  14. /**
  15. A frame with an image panel
  16. */
  17. @SuppressWarnings("serial")
  18. class ImageFrame extends JFrame{
  19. public ImagePanel panel;
  20. public JButton jb;

  21. public ImageFrame(ServerSocket ss){
  22. // get screen dimensions
  23. Toolkit kit = Toolkit.getDefaultToolkit();
  24. Dimension screenSize = kit.getScreenSize();
  25. int screenHeight = screenSize.height;
  26. int screenWidth = screenSize.width;
  27. // center frame in screen
  28. setTitle("ImageTest");
  29. setLocation((screenWidth - DEFAULT_WIDTH) / 2, (screenHeight - DEFAULT_HEIGHT) / 2);
  30. setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
  31. // add panel to frame
  32. this.getContentPane().setLayout(null);
  33. panel = new ImagePanel(ss);
  34. panel.setSize(640,480);
  35. panel.setLocation(0, 0);
  36. add(panel);
  37. jb = new JButton("拍照");
  38. jb.setBounds(0,480,640,50);
  39. add(jb);
  40. saveimage saveaction = new saveimage(ss);
  41. jb.addActionListener(saveaction);
  42. }
  43. public static final int DEFAULT_WIDTH = 640;
  44. public static final int DEFAULT_HEIGHT = 560;
  45. }
  46. /**
  47. A panel that displays a tiled image
  48. */
  49. @SuppressWarnings("serial")
  50. class ImagePanel extends JPanel {
  51. private ServerSocket ss;
  52. private Image image;
  53. private InputStream ins;

  54. public ImagePanel(ServerSocket ss) {
  55. this.ss = ss;
  56. }

  57. public void getimage() throws IOException{
  58. Socket s = this.ss.accept();
  59. System.out.println("连接成功!");
  60. this.ins = s.getInputStream();
  61. this.image = ImageIO.read(ins);
  62. this.ins.close();
  63. }

  64. public void paintComponent(Graphics g){
  65. super.paintComponent(g);
  66. if (image == null) return;
  67. g.drawImage(image, 0, 0, null);
  68. }
  69. }
  70. class saveimage implements ActionListener {
  71. RandomAccessFile inFile = null;
  72. byte byteBuffer[] = new byte[1024];
  73. InputStream ins;
  74. private ServerSocket ss;

  75. public saveimage(ServerSocket ss){
  76. this.ss = ss;
  77. }

  78. public void actionPerformed(ActionEvent event){
  79. try {
  80. Socket s = ss.accept();
  81. ins = s.getInputStream();

  82. // 文件选择器以当前的目录打开
  83. JFileChooser jfc = new JFileChooser(".");
  84. jfc.showSaveDialog(new javax.swing.JFrame());
  85. // 获取当前的选择文件引用
  86. File savedFile = jfc.getSelectedFile();

  87. // 已经选择了文件
  88. if (savedFile != null) {
  89. // 读取文件的数据,可以每次以快的方式读取数据
  90. try {
  91. inFile = new RandomAccessFile(savedFile, "rw");
  92. } catch (FileNotFoundException e) {
  93. e.printStackTrace();
  94. }
  95. }
  96. int amount;
  97. while ((amount = ins.read(byteBuffer)) != -1) {
  98. inFile.write(byteBuffer, 0, amount);
  99. }
  100. inFile.close();
  101. ins.close();
  102. s.close();
  103. javax.swing.JOptionPane.showMessageDialog(new javax.swing.JFrame(),
  104. "已接保存成功", "提示!", javax.swing.JOptionPane.PLAIN_MESSAGE);
  105. } catch (IOException e) {[/size]
  106. e.printStackTrace();
  107. }
  108. }
  109. }

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

eoeandroid 推荐:

Android 远程视频监控程序源码
http://www.eoeandroid.com/thread-173116-1-1.html

更多相关文章

  1. Android Studio代码调试大全
  2. Android 实现闪屏页和右上角的倒计时跳转实例代码
  3. android语音识别方法示例代码
  4. Linux 3.3内核发布 融合Android源代码
  5. Android的代码都得自己一个个敲一遍吗?
  6. Android 电子书应用完全开源代码

随机推荐

  1. Android(安卓)Material Design初步认识
  2. MediaPlayer的使用 带有seekBar
  3. Android(安卓)Studio忽略文件配置
  4. android Watchdog 实现剖析
  5. ADT 0.9下载
  6. android图像绘制(一)多种方法做图像镜像
  7. android判断是否加载SD卡
  8. android Webview加载网络图片
  9. UBUNTU 10.10 编译Android(安卓)2.3.1源
  10. android中利用GPS获取位置信息的源码分析