基于android的远程视频监控系统
16lz
2021-01-22
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、
- <?xmlversion="1.0"encoding="utf-8"?>
- <manifestxmlns:android="http://schemas.android.com/apk/res/android"
- package="org.wanghai.CameraTest"
- android:versionCode="1"
- android:versionName="1.0">
- <uses-sdkandroid:minSdkVersion="15"/>
- <!--授予程序使用摄像头的权限-->
- <uses-permissionandroid:name="android.permission.CAMERA"/>
- <uses-featureandroid:name="android.hardware.camera"/>
- <uses-featureandroid:name="android.hardware.camera.autofocus"/>
- <uses-permissionandroid:name="android.permission.INTERNET"/>
- <uses-permissionandroid:name="android.permission.KILL_BACKGROUND_PROCESSES"/>
- <uses-permissionandroid: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>
- <actionandroid:name="android.intent.action.MAIN"/>
- <categoryandroid: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用于摄像头采集图像的预览
[java]view plaincopy
- <?xmlversion="1.0"encoding="utf-8"?>
- <LinearLayoutxmlns: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
[html]view plaincopy
- <?xmlversion="1.0"encoding="utf-8"?>
- <TableLayoutxmlns: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传递
[java]view plaincopy
- publicclassGetIPextendsActivity{
- Stringipname=null;
- @Override
- publicvoidonCreate(BundlesavedInstanceState){
- super.onCreate(savedInstanceState);
- //设置全屏
- requestWindowFeature(Window.FEATURE_NO_TITLE);
- getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
- setContentView(R.layout.main);
- finalBuilderbuilder=newAlertDialog.Builder(this);//定义一个AlertDialog.Builder对象
- builder.setTitle("登录服务器对话框");//设置对话框的标题
- //装载/res/layout/login.xml界面布局
- TableLayoutloginForm=(TableLayout)getLayoutInflater().inflate(R.layout.login,null);
- finalEditTextiptext=(EditText)loginForm.findViewById(R.id.ipedittext);
- builder.setView(loginForm);//设置对话框显示的View对象
- //为对话框设置一个“登录”按钮
- builder.setPositiveButton("登录"
- //为按钮设置监听器
- ,newOnClickListener(){
- @Override
- publicvoidonClick(DialogInterfacedialog,intwhich){
- //此处可执行登录处理
- ipname=iptext.getText().toString().trim();
- Bundledata=newBundle();
- data.putString("ipname",ipname);
- Intentintent=newIntent(GetIP.this,CameraTest.class);
- intent.putExtras(data);
- startActivity(intent);
- }
- });
- //为对话框设置一个“取消”按钮
- builder.setNegativeButton("取消"
- ,newOnClickListener()
- {
- @Override
- publicvoidonClick(DialogInterfacedialog,intwhich)
- {
- //取消登录,不做任何事情。
- System.exit(1);
- }
- });
- //创建、并显示对话框
- builder.create().show();
- }
- }
(5)CameraTest.java 程序主体。设置PreviewCallback后,每当一帧图像数据采集完成后将调用PreviewCallback的onPreviewFrame函数。在这里我们将YUV格式数据转为jpg,再启用线程将数据通过socket发送出去。
[java]view plaincopy
- publicclassCameraTestextendsActivity{
- SurfaceViewsView;
- SurfaceHoldersurfaceHolder;
- intscreenWidth,screenHeight;
- Cameracamera;//定义系统所用的照相机
- booleanisPreview=false;//是否在浏览中
- privateStringipname;
- @SuppressWarnings("deprecation")
- @Override
- publicvoidonCreate(BundlesavedInstanceState){
- super.onCreate(savedInstanceState);
- //设置全屏
- requestWindowFeature(Window.FEATURE_NO_TITLE);
- getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
- setContentView(R.layout.main);
- //获取IP地址
- Intentintent=getIntent();
- Bundledata=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(newCallback(){
- @Override
- publicvoidsurfaceChanged(SurfaceHolderholder,intformat,intwidth,intheight){
- }
- @Override
- publicvoidsurfaceCreated(SurfaceHolderholder){
- initCamera();//打开摄像头
- }
- @Override
- publicvoidsurfaceDestroyed(SurfaceHolderholder){
- //如果camera不为null,释放摄像头
- if(camera!=null){
- if(isPreview)
- camera.stopPreview();
- camera.release();
- camera=null;
- }
- System.exit(0);
- }
- });
- //设置该SurfaceView自己不维护缓冲
- surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
- }
- privatevoidinitCamera(){
- if(!isPreview){
- camera=Camera.open();
- }
- if(camera!=null&&!isPreview){
- try{
- Camera.Parametersparameters=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(newStreamIt(ipname));//设置回调的类
- camera.startPreview();//开始预览
- camera.autoFocus(null);//自动对焦
- }catch(Exceptione){
- e.printStackTrace();
- }
- isPreview=true;
- }
- }
- }
- classStreamItimplementsCamera.PreviewCallback{
- privateStringipname;
- publicStreamIt(Stringipname){
- this.ipname=ipname;
- }
- @Override
- publicvoidonPreviewFrame(byte[]data,Cameracamera){
- Sizesize=camera.getParameters().getPreviewSize();
- try{
- //调用image.compressToJpeg()将YUV格式图像数据data转为jpg格式
- YuvImageimage=newYuvImage(data,ImageFormat.NV21,size.width,size.height,null);
- if(image!=null){
- ByteArrayOutputStreamoutstream=newByteArrayOutputStream();
- image.compressToJpeg(newRect(0,0,size.width,size.height),80,outstream);
- outstream.flush();
- //启用线程将图像数据发送出去
- Threadth=newMyThread(outstream,ipname);
- th.start();
- }
- }catch(Exceptionex){
- Log.e("Sys","Error:"+ex.getMessage());
- }
- }
- }
- classMyThreadextendsThread{
- privatebytebyteBuffer[]=newbyte[1024];
- privateOutputStreamoutsocket;
- privateByteArrayOutputStreammyoutputstream;
- privateStringipname;
- publicMyThread(ByteArrayOutputStreammyoutputstream,Stringipname){
- this.myoutputstream=myoutputstream;
- this.ipname=ipname;
- try{
- myoutputstream.close();
- }catch(IOExceptione){
- e.printStackTrace();
- }
- }
- publicvoidrun(){
- try{
- //将图像数据通过Socket发送出去
- SockettempSocket=newSocket(ipname,6000);
- outsocket=tempSocket.getOutputStream();
- ByteArrayInputStreaminputstream=newByteArrayInputStream(myoutputstream.toByteArray());
- intamount;
- while((amount=inputstream.read(byteBuffer))!=-1){
- outsocket.write(byteBuffer,0,amount);
- }
- myoutputstream.flush();
- myoutputstream.close();
- tempSocket.close();
- }catch(IOExceptione){
- e.printStackTrace();
- }
- }
- }
二、PC服务器端
ImageServer.java 用于显示图像,并且可以拍照
[java]view plaincopy
- publicclassImageServer{
- publicstaticServerSocketss=null;
- publicstaticvoidmain(Stringargs[])throwsIOException{
- ss=newServerSocket(6000);
- finalImageFrameframe=newImageFrame(ss);
- frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
- frame.setVisible(true);
- while(true){
- frame.panel.getimage();
- frame.repaint();
- }
- }
- }
- /**
- Aframewithanimagepanel
- */
- @SuppressWarnings("serial")
- classImageFrameextendsJFrame{
- publicImagePanelpanel;
- publicJButtonjb;
- publicImageFrame(ServerSocketss){
- //getscreendimensions
- Toolkitkit=Toolkit.getDefaultToolkit();
- DimensionscreenSize=kit.getScreenSize();
- intscreenHeight=screenSize.height;
- intscreenWidth=screenSize.width;
- //centerframeinscreen
- setTitle("ImageTest");
- setLocation((screenWidth-DEFAULT_WIDTH)/2,(screenHeight-DEFAULT_HEIGHT)/2);
- setSize(DEFAULT_WIDTH,DEFAULT_HEIGHT);
- //addpaneltoframe
- this.getContentPane().setLayout(null);
- panel=newImagePanel(ss);
- panel.setSize(640,480);
- panel.setLocation(0,0);
- add(panel);
- jb=newJButton("拍照");
- jb.setBounds(0,480,640,50);
- add(jb);
- saveimagesaveaction=newsaveimage(ss);
- jb.addActionListener(saveaction);
- }
- publicstaticfinalintDEFAULT_WIDTH=640;
- publicstaticfinalintDEFAULT_HEIGHT=560;
- }
- /**
- Apanelthatdisplaysatiledimage
- */
- @SuppressWarnings("serial")
- classImagePanelextendsJPanel{
- privateServerSocketss;
- privateImageimage;
- privateInputStreamins;
- publicImagePanel(ServerSocketss){
- this.ss=ss;
- }
- publicvoidgetimage()throwsIOException{
- Sockets=this.ss.accept();
- System.out.println("连接成功!");
- this.ins=s.getInputStream();
- this.image=ImageIO.read(ins);
- this.ins.close();
- }
- publicvoidpaintComponent(Graphicsg){
- super.paintComponent(g);
- if(image==null)return;
- g.drawImage(image,0,0,null);
- }
- }
- classsaveimageimplementsActionListener{
- RandomAccessFileinFile=null;
- bytebyteBuffer[]=newbyte[1024];
- InputStreamins;
- privateServerSocketss;
- publicsaveimage(ServerSocketss){
- this.ss=ss;
- }
- publicvoidactionPerformed(ActionEventevent){
- try{
- Sockets=ss.accept();
- ins=s.getInputStream();
- //文件选择器以当前的目录打开
- JFileChooserjfc=newJFileChooser(".");
- jfc.showSaveDialog(newjavax.swing.JFrame());
- //获取当前的选择文件引用
- FilesavedFile=jfc.getSelectedFile();
- //已经选择了文件
- if(savedFile!=null){
- //读取文件的数据,可以每次以快的方式读取数据
- try{
- inFile=newRandomAccessFile(savedFile,"rw");
- }catch(FileNotFoundExceptione){
- e.printStackTrace();
- }
- }
- intamount;
- while((amount=ins.read(byteBuffer))!=-1){
- inFile.write(byteBuffer,0,amount);
- }
- inFile.close();
- ins.close();
- s.close();
- javax.swing.JOptionPane.showMessageDialog(newjavax.swing.JFrame(),
- "已接保存成功","提示!",javax.swing.JOptionPane.PLAIN_MESSAGE);
- }catch(IOExceptione){
- 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%B
更多相关文章
- 背景图像颜色检测与Android油漆。
- 想在android中使用node.js和socket.io发送图像
- Android Picasso Dropbox:如何将图像加载到gridview中
- OpenCV4Android中图像预览旋转90度的问题
- Android图形图像处理之Bitmap和BitmapFactory
- 使用android的加速度计移动图像
- 在不同状态下使用两个图像切换按钮
- POST json和图像到服务器android
- java漏洞成黑客目标微软呼吁用户更新软件