|
안드로이드 개발 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 |
