안드로이드 개발 SurfaceView에 카메라 영상 띄우는 방법 |
환경: Android Studio |
SurfaceView 는 TextView, ImageView 와 같이 화면에 뭔가를 표현할 때 사용하는 안드로이드 위젯입니다. 모두 View 를 상속받아서 구현된 것은 맞지만 차이점이 있습니다. SurfaceView 는 컨텐츠를 표현할 때 View 내에 하나의 쓰레드에서 처리되지 않습니다. 고화질의 카메라 영상이나 애니메이션 화면을 구현해서 보여 줘야 하기 때문에 화면 업데이트를 백그라운드 스레드에서 처리한 후 전달 받은 데이터를 보여 주는 역할을 합니다. 그러니까 SurfaceView 는 단순히 영상을 보는 액자 역할만 하고 SurfaceHolder 클래스가 백그라운드에서 처리된 결과를 중간에서 주고 받아 관리합니다.
▼ 오늘은 SurfaceView 와 SurfaceHolder 를 이용해서 스마트폰 카메라에서 받은 영상을 표현해 보겠습니다. 위에서 이야기 했듯이 SurfaceView 에 영상을 표현하기 위해서는 SurfaceHolder 가 필요합니다. 카메라 영상을 표현하기 위해서 SurfaceHolder.Callback 을 implements 하고 필수 구현 함수 안에 SurfaceView 로 영상을 넘기기 위한 작업을 해야 합니다. 구현해야 되는 함수는 총 3가지 입니다.
@Override public void surfaceCreated(SurfaceHolder holder) { } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceDestroyed(SurfaceHolder holder) { }
▼ surfaceCreated() 는 SurfaceView 가 생성될 때 발생하는 함수로 카메라와 SurfaceHolder 와 연결하고 카메라 Preview를 시작합니다. surfaceChanged() 는 상태가 변경될 때 마다 발생하는 함수로 SurfaceView 에 맞게 카메라 Preview 도 재설정한 후 다시 시작하게 합니다. surfaceDestoryed() 는 SurfaceView 객체가 사라지게 되면 발생하는 함수로 카메라 리소스를 반환합니다.
@Override public void surfaceCreated(SurfaceHolder holder) { try { if (mCamera == null) { mCamera.setPreviewDisplay(holder); mCamera.startPreview(); } } catch (IOException e) { } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { // View 가 존재하지 않을 때 if (mCameraHolder.getSurface() == null) { return; } // 작업을 위해 잠시 멈춘다 try { mCamera.stopPreview(); } catch (Exception e) { // 에러가 나더라도 무시한다. } // 카메라 설정을 다시 한다. Camera.Parameters parameters = mCamera.getParameters(); List<String> focusModes = parameters.getSupportedFocusModes(); if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) { parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); } mCamera.setParameters(parameters); // View 를 재생성한다. try { mCamera.setPreviewDisplay(mCameraHolder); mCamera.startPreview(); } catch (Exception e) { } } @Override public void surfaceDestroyed(SurfaceHolder holder) { if (mCamera != null) { mCamera.stopPreview(); mCamera.release(); mCamera = null; } }
▼ 다음은 카메라 리소스를 받고 SurfaceHolder 와 SurfaceView 를 연결하는 부분입니다. 여기에서 mCamera.setDisplayOrientation(90) 을 한 것은 카메라를 가로에서 세로로 돌리기 위함입니다.
private void init(){ mCamera = Camera.open(); mCamera.setDisplayOrientation(90); // surfaceview setting mCameraHolder = mCameraView.getHolder(); mCameraHolder.addCallback(this); mCameraHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); }
▼ 메인 Activity를 구현한 xml 은 다음과 같습니다.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical"> <SurfaceView android:id="@+id/cameraView" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1"/> </LinearLayout>
메인 Activity 전체 소스는 다음과 같습니다.
import android.app.Activity; import android.hardware.Camera; import android.hardware.camera2.CameraDevice; import android.media.MediaRecorder; import android.os.Bundle; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.widget.Button; import java.io.IOException; import java.util.List; public class CameraActivity extends Activity implements SurfaceHolder.Callback { private CameraDevice camera; private SurfaceView mCameraView; private SurfaceHolder mCameraHolder; private Camera mCamera; private Button mStart; private boolean recording = false; private MediaRecorder mediaRecorder; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_camera); mCameraView = (SurfaceView)findViewById(R.id.cameraView); init(); } private void init(){ mCamera = Camera.open(); mCamera.setDisplayOrientation(90); // surfaceview setting mCameraHolder = mCameraView.getHolder(); mCameraHolder.addCallback(this); mCameraHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); } // surfaceholder 와 관련된 구현 내용 @Override public void surfaceCreated(SurfaceHolder holder) { try { if (mCamera == null) { mCamera.setPreviewDisplay(holder); mCamera.startPreview(); } } catch (IOException e) { } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { // View 가 존재하지 않을 때 if (mCameraHolder.getSurface() == null) { return; } // 작업을 위해 잠시 멈춘다 try { mCamera.stopPreview(); } catch (Exception e) { // 에러가 나더라도 무시한다. } // 카메라 설정을 다시 한다. Camera.Parameters parameters = mCamera.getParameters(); List<String> focusModes = parameters.getSupportedFocusModes(); if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) { parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); } mCamera.setParameters(parameters); // View 를 재생성한다. try { mCamera.setPreviewDisplay(mCameraHolder); mCamera.startPreview(); } catch (Exception e) { } } @Override public void surfaceDestroyed(SurfaceHolder holder) { if (mCamera != null) { mCamera.stopPreview(); mCamera.release(); mCamera = null; } } }
'안드로이드 개발' 카테고리의 다른 글
안드로이드(Android) 사용자정의 다이얼로그(Custom Dialog) 만드는 방법 (0) | 2019.10.25 |
---|---|
안드로이드(Android) 기본 알림창 AlertDialog 띄우는 방법 (0) | 2019.10.24 |
안드로이드 개발 Fragment 화면 구성하는 방법 - FragmentActivity 로 화면 구성 (0) | 2019.10.10 |
로컬 레파지토리 sonatype nexus 설정해서 안드로이드 스튜디오 환경 구성하는 방법 (0) | 2019.10.09 |
안드로이드 개발 앱에서 만든 DB 소스로 추출하는 방법 (0) | 2019.09.16 |
Wowza GoCoder 안드로이드, 아이폰 클라이언트 개발을 위한 라이선스 키 받는 방법 (1) | 2019.09.15 |
안드로이드 개발 화면 전환 할 때 Activity 삭제와 생성 방지 orientation, screenSize 속성 사용하기 (0) | 2019.09.15 |
안드로이드 버전코드(versionCode), 버전이름(versionName) 차이와 조회하는 방법 (0) | 2019.09.14 |