把Android手机变成远程监控摄像头
生活随笔
收集整理的這篇文章主要介紹了
把Android手机变成远程监控摄像头
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
基本過程是android作為socket客戶端將采集到的每一幀圖像數據發送出去,PC作為服務器接收并顯示每一幀圖像實現遠程監控。圖片如下(后來PC端加了個拍照功能)。。。
?
(PS。剛學android和java不久很多東西還不懂,高手若是知道哪些地方可以繼續優化的話還請多多指點下啊)
系統代碼如下:
一、android手機客戶端
(1)AndroidManifest.xml文件。添加camera和socket權限,并設置了程序開始執行的activity、
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" ????package="org.wanghai.CameraTest" ????android:versionCode="1" ????android:versionName="1.0" > ?? ????<uses-sdk android:minSdkVersion="15" /> ?????? ????<!-- 授予程序使用攝像頭的權限 --> ????????<uses-permission android:name="android.permission.CAMERA" /> ????????<uses-feature android:name="android.hardware.camera" /> ????????<uses-feature android:name="android.hardware.camera.autofocus" /> ????????<uses-permission android:name="android.permission.INTERNET"/> ????<uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES"/> ????<uses-permission android: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> ????????????????<action android:name="android.intent.action.MAIN" /> ????????????????<category android: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用于攝像頭采集圖像的預覽 ? <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns: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 ? <?xml version="1.0" encoding="utf-8"?> <TableLayout xmlns: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> |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 | ????????(4)GetIP.java 獲得服務器IP后,通過Intent啟動CameraTest的activity,ip信息通過Bundle傳遞 ? public class GetIP?extends Activity { ????????String ipname =?null; ????????@Override ????public void onCreate(Bundle savedInstanceState) { ????????super.onCreate(savedInstanceState); ????????// 設置全屏 ????????requestWindowFeature(Window.FEATURE_NO_TITLE); ?????????????getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN); ????????setContentView(R.layout.main);?????? ???????? ??????????????final Builder builder =?new AlertDialog.Builder(this);???//定義一個AlertDialog.Builder對象??????????????????????????????????????? ????????????????builder.setTitle("登錄服務器對話框");??????????????????????????// 設置對話框的標題 ?????????????????? ????????????????//裝載/res/layout/login.xml界面布局 ????????????????TableLayout loginForm = (TableLayout)getLayoutInflater().inflate( R.layout.login,?null);?????????????? ????????????????final EditText iptext = (EditText)loginForm.findViewById(R.id.ipedittext);?????????????????????????????? ????????????????builder.setView(loginForm);??????????????????????????????// 設置對話框顯示的View對象 ????????????????// 為對話框設置一個“登錄”按鈕 ????????????????builder.setPositiveButton("登錄" ????????????????????????// 為按鈕設置監聽器 ????????????????????????,?new OnClickListener() { ????????????????????????????????@Override ????????????????????????????????public void onClick(DialogInterface dialog,?int which) { ????????????????????????????????????????//此處可執行登錄處理 ????????????????????????????????????????ipname = iptext.getText().toString().trim(); ????????????????????????????????????????Bundle data =?new Bundle(); ????????????????????????????????????????data.putString("ipname",ipname);?????????????????????????????????????? ????????????????????????????????????????Intent intent =?new Intent(GetIP.this,CameraTest.class); ????????????????????????????????????????intent.putExtras(data); ????????????????????????????????????????startActivity(intent); ????????????????????????????????} ????????????????????????}); ????????????????// 為對話框設置一個“取消”按鈕 ????????????????builder.setNegativeButton("取消" ????????????????????????,??new OnClickListener() ????????????????????????{ ????????????????????????????????@Override ????????????????????????????????public void onClick(DialogInterface dialog,?int which) ????????????????????????????????{ ????????????????????????????????????????//取消登錄,不做任何事情。 ????????????????????????????????????????System.exit(1); ????????????????????????????????} ????????????????????????}); ????????????????//創建、并顯示對話框 ????????????????builder.create().show(); ????????} } ????????(5)CameraTest.java 程序主體。設置PreviewCallback后,每當一幀圖像數據采集完成后將調用PreviewCallback的onPreviewFrame函數。在這里我們將YUV格式數據轉為jpg,再啟用線程將數據通過socket發送出去。 ? public class CameraTest?extends Activity { ????????SurfaceView sView; ????????SurfaceHolder surfaceHolder; ????????int screenWidth, screenHeight;?????? ????????Camera camera;????????????????????// 定義系統所用的照相機?????? ????????boolean isPreview =?false;????????//是否在瀏覽中 ????????private String ipname; ?? ????????@SuppressWarnings("deprecation") ????????@Override ????public void onCreate(Bundle savedInstanceState) { ????????super.onCreate(savedInstanceState); ????????// 設置全屏 ?????????????requestWindowFeature(Window.FEATURE_NO_TITLE); ?????????????getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN); ????????setContentView(R.layout.main); ?????????? ????????// 獲取IP地址 ????????Intent intent = getIntent(); ????????Bundle data = 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(new Callback() { ????????????????????????@Override ????????????????????????public void surfaceChanged(SurfaceHolder holder,?int format,?int width,int height) {?????????????????????????????? ????????????????????????} ????????????????????????@Override ????????????????????????public void surfaceCreated(SurfaceHolder holder) {?????????????????????????????????????????????????????? ????????????????????????????????initCamera();????????????????????????????????????????????// 打開攝像頭 ????????????????????????} ????????????????????????@Override ????????????????????????public void surfaceDestroyed(SurfaceHolder holder) { ????????????????????????????????// 如果camera不為null ,釋放攝像頭 ????????????????????????????????if (camera !=?null) { ????????????????????????????????????????if (isPreview) ????????????????????????????????????????????????camera.stopPreview(); ????????????????????????????????????????camera.release(); ????????????????????????????????????????camera =?null; ????????????????????????????????} ????????????????????????????System.exit(0); ????????????????????????}?????????????? ????????????????}); ????????????????// 設置該SurfaceView自己不維護緩沖?? ????????????????surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); ?????????????????? ????} ?????? ????private void initCamera() { ????????????if (!isPreview) { ????????????????????????camera = Camera.open(); ????????????????} ????????????????if (camera !=?null && !isPreview) { ????????????????????????try{ ????????????????????????????????Camera.Parameters parameters = 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(new StreamIt(ipname));?????????// 設置回調的類?????????????????????????????? ????????????????????????????????camera.startPreview();???????????????????????????????????// 開始預覽?????????????????????????????? ????????????????????????????????camera.autoFocus(null);??????????????????????????????????// 自動對焦 ????????????????????????}?catch (Exception e) { ????????????????????????????????e.printStackTrace(); ????????????????????????} ????????????????????????isPreview =?true; ????????????????} ????} ?????? } ?? class StreamIt?implements Camera.PreviewCallback { ????????private String ipname; ????????public StreamIt(String ipname){ ????????????????this.ipname = ipname; ????????} ?????????? ????@Override ????public void onPreviewFrame(byte[] data, Camera camera) { ????????Size size = camera.getParameters().getPreviewSize();???????? ????????try{ ????????????????//調用image.compressToJpeg()將YUV格式圖像數據data轉為jpg格式 ????????????YuvImage image =?new YuvImage(data, ImageFormat.NV21, size.width, size.height,?null); ????????????if(image!=null){ ????????????????????ByteArrayOutputStream outstream =?new ByteArrayOutputStream(); ????????????????image.compressToJpeg(new Rect(0,?0, size.width, size.height),?80, outstream); ????????????????outstream.flush(); ????????????????//啟用線程將圖像數據發送出去 ????????????????Thread th =?new MyThread(outstream,ipname); ????????????????th.start();????????????? ????????????} ????????}catch(Exception ex){ ????????????Log.e("Sys","Error:"+ex.getMessage()); ????????}?????? ????} } ?????? class MyThread?extends Thread{?????? ????????private byte byteBuffer[] =?new byte[1024]; ????????private OutputStream outsocket;?????? ????????private ByteArrayOutputStream myoutputstream; ????????private String ipname; ?????????? ????????public MyThread(ByteArrayOutputStream myoutputstream,String ipname){ ????????????????this.myoutputstream = myoutputstream; ????????????????this.ipname = ipname; ????????try { ????????????????????????myoutputstream.close(); ????????????????}?catch (IOException e) { ????????????????????????e.printStackTrace(); ????????????????} ????????} ?????????? ????public void run() { ????????try{ ????????????????//將圖像數據通過Socket發送出去 ????????????Socket tempSocket =?new Socket(ipname,?6000); ????????????outsocket = tempSocket.getOutputStream(); ????????????ByteArrayInputStream inputstream =?new ByteArrayInputStream(myoutputstream.toByteArray()); ????????????int amount; ????????????while ((amount = inputstream.read(byteBuffer)) != -1) { ????????????????outsocket.write(byteBuffer,?0, amount); ????????????} ????????????myoutputstream.flush(); ????????????myoutputstream.close(); ????????????tempSocket.close();????????????????? ????????}?catch (IOException e) { ????????????e.printStackTrace(); ????????} ????} ?? } ????????二、PC服務器端 ImageServer.java 用于顯示圖像,并且可以拍照 ? public class ImageServer {?????? ????public static ServerSocket ss =?null; ?????? ????public static void main(String args[])?throws IOException{?? ????????????ss =?new ServerSocket(6000); ?????????? ????????final ImageFrame frame =?new ImageFrame(ss); ????????frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); ????????frame.setVisible(true); ????????? ????????while(true){ ????????????????frame.panel.getimage(); ????????????frame.repaint(); ????????}?????? ????} ????????? } ?? /** ????A frame with an image panel */ @SuppressWarnings("serial") class ImageFrame?extends JFrame{ ????????public ImagePanel panel; ????????public JButton jb; ????? ????public ImageFrame(ServerSocket ss){ ???????????????// get screen dimensions???????????? ???????????????Toolkit kit = Toolkit.getDefaultToolkit(); ????????Dimension screenSize = kit.getScreenSize(); ????????int screenHeight = screenSize.height; ????????int screenWidth = screenSize.width; ?? ????????// center frame in screen ????????setTitle("ImageTest"); ????????setLocation((screenWidth - DEFAULT_WIDTH) /?2, (screenHeight - DEFAULT_HEIGHT) /?2); ????????setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT); ?? ????????// add panel to frame ????????this.getContentPane().setLayout(null); ????????panel =?new ImagePanel(ss); ????????panel.setSize(640,480); ????????panel.setLocation(0,?0); ????????add(panel); ????????jb =?new JButton("拍照"); ????????jb.setBounds(0,480,640,50); ????????add(jb); ????????saveimage saveaction =?new saveimage(ss); ????????jb.addActionListener(saveaction); ????} ?? ????public static final int DEFAULT_WIDTH =?640; ????public static final int DEFAULT_HEIGHT =?560; } ?? /** ???A panel that displays a tiled image */ @SuppressWarnings("serial") class ImagePanel?extends JPanel {??? ????private ServerSocket ss; ????private Image image; ????private InputStream ins; ??????????? ????public ImagePanel(ServerSocket ss) { ????????????this.ss = ss; ????} ?????? ????public void getimage()?throws IOException{ ????????????Socket s =?this.ss.accept(); ????????System.out.println("連接成功!"); ????????this.ins = s.getInputStream(); ????????????????this.image = ImageIO.read(ins); ????????????????this.ins.close(); ????} ????? ????public void paintComponent(Graphics g){ ????????super.paintComponent(g);?? ????????if (image ==?null)?return; ????????g.drawImage(image,?0,?0,?null); ????} ?? } ?? class saveimage?implements ActionListener { ????????RandomAccessFile inFile =?null; ????????byte byteBuffer[] =?new byte[1024]; ????????InputStream ins; ????????private ServerSocket ss; ?????????? ????????public saveimage(ServerSocket ss){ ????????????????this.ss = ss; ????????} ?????????? ????????public void actionPerformed(ActionEvent event){ ????????try { ????????????????????????Socket s = ss.accept(); ????????????????????????ins = s.getInputStream(); ?????????????????????????? ????????????????????????// 文件選擇器以當前的目錄打開 ????????????????JFileChooser jfc =?new JFileChooser("."); ????????????????jfc.showSaveDialog(new javax.swing.JFrame()); ????????????????// 獲取當前的選擇文件引用 ????????????????File savedFile = jfc.getSelectedFile(); ?????????????????? ????????????????// 已經選擇了文件 ????????????????if (savedFile !=?null) { ????????????????????// 讀取文件的數據,可以每次以快的方式讀取數據 ????????????????????try { ????????????????????????????????????????inFile =?new RandomAccessFile(savedFile,?"rw"); ????????????????????????????????}?catch (FileNotFoundException e) { ????????????????????????????????????????e.printStackTrace(); ????????????????????????????????} ????????????????} ?? ????????????int amount; ????????????while ((amount = ins.read(byteBuffer)) != -1) { ????????????????inFile.write(byteBuffer,?0, amount); ????????????} ????????????inFile.close(); ????????????ins.close(); ????????????s.close(); ????????????javax.swing.JOptionPane.showMessageDialog(new javax.swing.JFrame(), ????????????????????"已接保存成功",?"提示!", javax.swing.JOptionPane.PLAIN_MESSAGE); ????????????????}?catch (IOException e) { ?? ????????????????????????e.printStackTrace(); ????????????????} ????????} } |
????????開放源碼如下(android我使用的是4.03的SDK,其它版本請自行更改。2.3.3版本以下的請注意initCamera()里被注釋掉的哪一行)
只能在android4.04系統的手機上運行成功哦。
下面是測試成功時的啟動畫面:
?android_video.rar
總結
以上是生活随笔為你收集整理的把Android手机变成远程监控摄像头的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HTML期末作业 蛋糕bootstrap
- 下一篇: 滤波电路