Akashic Records

Android HTTP Camera Live Preview Tutorial 본문

오래된글/Articles

Android HTTP Camera Live Preview Tutorial

Andrew's Akashic Records 2018. 4. 19. 14:14
728x90

원문: http://www.javacodegeeks.com/2011/03/android-http-camera-live-preview.html


Android SDK에는 Camera class가 포함되어 있습니다. 이 Class는 하드웨어 Camera 디바이스를 추상화 하여 쉽게 조작할 수 있게 해줍니다. 하지만 SDK에서는 Camera enulation이 지원되지 않아 테스트해보는데 어려움이 많습니다. 본 문서에서는 Live Camera Preview 기능의 가이드를 제공합니다.


Eclipse을 이용하여 Android Project을 만듭니다.


AndroidMainfest

CAMERA, INTERNET 사용 권한이 있어야 합니다.

<?xml version="1.0" encoding="utf-8"?>


<manifest xmlns:android="http://schemas.android.com/apk/res/android"

     package="com.javacodegeeks.android.camera"

     android:versionCode="1"

     android:versionName="1.0">

     

   <application android:icon="@drawable/icon" android:label="@string/app_name">

       <activity android:name=".MyCamAppActivity"

                 android:label="@string/app_name">

           <intent-filter>

               <action android:name="android.intent.action.MAIN" />

               <category android:name="android.intent.category.LAUNCHER" />

           </intent-filter>

       </activity>   

   </application>

   

   <uses-sdk android:minSdkVersion="3" />

   

   <uses-permission android:name="android.permission.CAMERA"/>

   <uses-permission android:name="android.permission.INTERNET" />


</manifest>


MyCamAppActivity

useHttpCamera 설정에 따라 WebServer로 부터 CAM Image을 받아오는 HttpCameraPreview을 이용하거나 local Mobile기기의 Camera을 보여주는 CameraPreview을 이용하게 됩니다.

package com.javacodegeeks.android.camera;


import android.app.Activity;

import android.os.Bundle;

import android.view.Display;

import android.view.SurfaceView;

import android.view.Window;


public class MyCamAppActivity extends Activity {

   

   private int viewWidth;

   private int viewHeight;

   

   private SurfaceView cameraPreview;

   

   private static final boolean useHttpCamera = true;


   @Override

   public void onCreate(Bundle savedInstanceState) {

       

       super.onCreate(savedInstanceState);

       requestWindowFeature(Window.FEATURE_NO_TITLE);

       

       calculateDisplayDimensions();

       

       if (useHttpCamera) {

           cameraPreview = new HttpCameraPreview(this, viewWidth, viewHeight);

       }

       else {

           cameraPreview = new CameraPreview(this);

       }

       setContentView(cameraPreview);

       

   }

   

   private void calculateDisplayDimensions() {

       Display display = getWindowManager().getDefaultDisplay();

       viewWidth = display.getWidth();

       viewHeight = display.getHeight();

   }

   

}


HttpCameraPreview

WebCAM으로 부터 받은 Image을 보여주는 View입니다. url은 WebCAM 주소가 됩니다.  내부 Thead을 생성하여 주기적으로 새 Image을 생성합니다.


SurfaceHolder.Callback으로 부터 상속 받은 3개의 Callback Method을 구현하여야 하며 각각은 아래와 같습니다.

  • surfaceCreated: surface가 최초 생성 후 즉각 호출.

  • surfaceChanged: surface에 어떤 변화(format, size)가 있은 직후 호출

  • surfaceDestoryed: surface가 소멸(Destroyed)되기 바로 전에 호출


package com.javacodegeeks.android.camera;


import android.content.Context;

import android.graphics.Canvas;

import android.util.Log;

import android.view.SurfaceHolder;

import android.view.SurfaceView;


public class HttpCameraPreview extends SurfaceView implements SurfaceHolder.Callback {

   

   private static final String url = "http://10.0.2.2:8080";

   

   private CanvasThread canvasThread;

   

   private SurfaceHolder holder;

   private HttpCamera camera;

   

   private int viewWidth;

   private int viewHeight;


   public HttpCameraPreview(Context context, int viewWidth, int viewHeight) {

       super(context);

       holder = getHolder();

       holder.addCallback(this);

       holder.setType(SurfaceHolder.SURFACE_TYPE_NORMAL);

       this.viewWidth = viewWidth;

       this.viewHeight = viewHeight;

       canvasThread = new CanvasThread();

   }


   @Override

   public void surfaceChanged(SurfaceHolder holder2, int format, int w, int h) {        

       try {         

           Canvas c = holder.lockCanvas(null);

           camera.captureAndDraw(c);

           

           if (c != null) {

               holder.unlockCanvasAndPost(c);

           }

       }

       catch (Exception e) {

           Log.e(getClass().getSimpleName(), "Error when surface changed", e);

           camera = null;

       }

   }


   @Override

   public void surfaceCreated(SurfaceHolder arg0) {

       try {

           camera = new HttpCamera(url, viewWidth, viewHeight, true);

           canvasThread.setRunning(true);

           canvasThread.start();

       }

       catch (Exception e) {

           Log.e(getClass().getSimpleName(), "Error while creating surface", e);

           camera = null;

       }

   }


   @Override

   public void surfaceDestroyed(SurfaceHolder arg0) {

       camera = null;

       boolean retry = true;

       canvasThread.setRunning(false);

       while (retry) {

           try {

               canvasThread.join();

               retry = false;

           } catch (InterruptedException e) {

           }

       }


   }

   

   private class CanvasThread extends Thread {

       

       private boolean running;

       

       public void setRunning(boolean running){

           this.running = running;

       }

       

       public void run() {

           

          while (running) {               

              Canvas c = null;

              try {

                  c = holder.lockCanvas(null);           

                  synchronized (holder) {

                      camera.captureAndDraw(c);

                  }

              }

              catch (Exception e) {

                  Log.e(getClass().getSimpleName(), "Error while drawing canvas", e);

              }

              finally {

                  if (c != null) {

                      holder.unlockCanvasAndPost(c);

                  }

              }

          }

       }

       

   }


}


HttpCamera

WebServer에 Connection하고 Image을 받아옵니다.

package com.javacodegeeks.android.camera;


import java.io.IOException;

import java.io.InputStream;

import java.net.HttpURLConnection;

import java.net.URL;


import android.graphics.Bitmap;

import android.graphics.BitmapFactory;

import android.graphics.Canvas;

import android.graphics.Paint;

import android.graphics.Rect;


public class HttpCamera {

   

   private static final int CONNECT_TIMEOUT = 1000;

   private static final int SOCKET_TIMEOUT = 1000;

   

   private final String url;

   private final Rect bounds;

   private final boolean preserveAspectRatio;

   private final Paint paint = new Paint();


   public HttpCamera(String url, int width, int height, boolean preserveAspectRatio) {

       this.url = url;

       bounds = new Rect(0, 0, width, height);

       this.preserveAspectRatio = preserveAspectRatio;

       

       paint.setFilterBitmap(true);

       paint.setAntiAlias(true);

   }


   private Bitmap retrieveBitmap() throws IOException {

       

       Bitmap bitmap = null;

       InputStream in = null;

       int response = -1;


       try {

           

           URL url = new URL(this.url);        

           HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();

           

           httpConn.setConnectTimeout(CONNECT_TIMEOUT);

           httpConn.setReadTimeout(SOCKET_TIMEOUT);

           httpConn.setRequestMethod("GET");

           

           httpConn.connect();

           response = httpConn.getResponseCode();

           

           if (response == HttpURLConnection.HTTP_OK) {

               in = httpConn.getInputStream();

               bitmap = BitmapFactory.decodeStream(in);

           }

           

           return bitmap;

           

       }

       catch (Exception e) {

           return null;

       }

       finally {

           if (in != null) try {

               in.close();

           } catch (IOException e) {

               /* ignore */

           }

       }

       

   }


   public boolean captureAndDraw(Canvas canvas) throws IOException {

       

       Bitmap bitmap = retrieveBitmap();

       

       if (bitmap == null) throw new IOException("Response Code: ");


       //render it to canvas, scaling if necessary

       if (bounds.right == bitmap.getWidth() && bounds.bottom == bitmap.getHeight()) {

           canvas.drawBitmap(bitmap, 0, 0, null);

       } else {

           Rect dest;

           if (preserveAspectRatio) {

               dest = new Rect(bounds);

               dest.bottom = bitmap.getHeight() * bounds.right / bitmap.getWidth();

               dest.offset(0, (bounds.bottom - dest.bottom)/2);

           }

           else {

               dest = bounds;

           }

           canvas.drawBitmap(bitmap, null, dest, paint);

       }

       

       return true;

       

   }


}


CameraPreview

WebCAM과 연결하지 않을 때 로컬 Mobile의 Camera 화면을 보여주는 View 입니다.

HttpCameraPreview와 같이 3개의 Callback Method을 구현해 줍니다.

package com.javacodegeeks.android.camera;


import android.content.Context;

import android.hardware.Camera;

import android.util.Log;

import android.view.SurfaceHolder;

import android.view.SurfaceView;


public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {


   private SurfaceHolder holder;

   private Camera camera;


   public CameraPreview(Context context) {

       super(context);

       holder = getHolder();

       holder.addCallback(this);

       holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

   }


   @Override

   public void surfaceChanged(SurfaceHolder holder2, int format, int w, int h) {

       Camera.Parameters parameters = camera.getParameters();

       parameters.setPreviewSize(w, h);

       camera.setParameters(parameters);

       camera.startPreview();

   }


   @Override

   public void surfaceCreated(SurfaceHolder holder1) {

       try {

           camera = Camera.open();

           camera.setPreviewDisplay(holder1);

       }

       catch (Exception e) {

           Log.i("Exception surfaceCreated()", "e=" + e);

           camera.release();

           camera = null;

       }


   }


   @Override

   public void surfaceDestroyed(SurfaceHolder arg0) {

       camera.stopPreview();

       camera.release();

       camera = null;

   }

   

}



본 예제를 실행하기 위해서는 Web Camera장비와 WebCam2000과 같은 Image publish Web Server가 필요합니다. 하지만 장비가 없다고 실망할 필요가 없습니다. 편법을 사용하시면 됩니다. Apache나 Tomcat 같은 Web Server을 설치하시고 아무 Image라도 Web에서 접근 가능하게 배포하십시오.  본인은 “hurukku.jsp” 이미지를 http://123.212.xxx.xxx:8080/bam/dashboard/hurukku.jpg 에 배포하였습니다. 그리고 HttpCameraPreview.java의 url을 위 주소로 바꿔주시면 됩니다.



728x90

'오래된글 > Articles' 카테고리의 다른 글

The Cost of an Exception  (0) 2018.04.19
Android XML Binding with Simple Framework Tutorial  (0) 2018.04.19
The impact of Garbage Collection on Java performance  (0) 2018.04.19
Stomp On Web Sockets  (0) 2018.04.19
HTML5  (0) 2018.04.19
Comments