基本过程是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 EditText设置不可写
  2. android“设置”里的版本号
  3. android studio Could not find com.android.support.constraint
  4. android ndk编译x264开源(用于android的ffmpeg中进行软编码)
  5. 在Fragment中设置控件点击方法,执行失败。
  6. Android(安卓)闹钟管理类的使用
  7. Android设置通知栏/状态栏透明改变通知栏颜色和app最上部分颜色
  8. android 设置中划线 下划线等
  9. Andorid Dialog 示例【慢慢更新】

随机推荐

  1. DataBing
  2. Android问题集(七)——TableLayout 中让Tab
  3. Android实现朋友圈多图显示功能
  4. AndroidManifest.xml - 【 manifest -> a
  5. 补间动画--缩放动画XML
  6. Android系统框架概述
  7. Android打开activity的时候,设置editText
  8. 鉴客 Android中如何生成带圆角的Bitmap图
  9. 安卓控件属性
  10. Android EditText的设置以及软键盘的各种