728x90
안녕하세요 오늘은 Camera2 Api 를 사용해 동영상 찍기 예제를 만들어 보겠습니다.
이전 사진 찍기 예제를 보고 와주세요
https://stickode.tistory.com/1090
package com.example.myapplication;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.ImageFormat;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.*;
import android.media.Image;
import android.media.ImageReader;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.util.Size;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.text.SimpleDateFormat;
import java.util.*;
public class MainActivity extends AppCompatActivity {
// 카메라 미리보기를 위한 TextureView
private TextureView textureView;
// 카메라 디바이스를 참조하기 위한 객체
private CameraDevice cameraDevice;
// 캡처 요청을 만들기 위한 Builder
private CaptureRequest.Builder captureRequestBuilder;
// 카메라 캡처 세션
private CameraCaptureSession cameraCaptureSessions;
String fileName = "IMG_" + new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()) + ".jpg";
// 카메라 사용 권한 요청 코드
private static final int REQUEST_CAMERA_PERMISSION = 200;
private Size imageDimension;
private MediaRecorder mediaRecorder;
private boolean isRecording = false;
// TextureView의 상태를 감지하는 리스너
private final TextureView.SurfaceTextureListener textureListener = new TextureView.SurfaceTextureListener() {
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
// 텍스쳐뷰가 사용 가능할 때 카메라를 여는 함수 호출
openCamera();
}
// 텍스처 크기가 변경될 때 호출
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
}
// 텍스쳐가 파괴될 때 호출
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
return false;
}
// 텍스쳐가 업데이트될 때 호출
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
}
};
// 카메라 상태 콜백
private final CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {
@Override
public void onOpened(CameraDevice camera) {
// 카메라가 성공적으로 열리면 CameraDevice 인스턴스를 할당하고 미리보기 시작
cameraDevice = camera;
createCameraPreview();
}
@Override
public void onDisconnected(CameraDevice camera) {
// 카메라 연결이 끊기면 닫음
cameraDevice.close();
}
@Override
public void onError(CameraDevice camera, int error) {
// 에러 발생시 카메라 닫고 null 할당
cameraDevice.close();
cameraDevice = null;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textureView = findViewById(R.id.textureView);
// TextureView에 리스너 설정
textureView.setSurfaceTextureListener(textureListener);
Button takePictureButton = findViewById(R.id.btn_takepicture);
takePictureButton.setText("Record");
takePictureButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d("test",""+isRecording);
if (isRecording) {
stopRecording();
takePictureButton.setText("Record");
isRecording = false;
} else {
isRecording = true;
try {
startRecording();
} catch (IOException e) {
throw new RuntimeException(e);
}
takePictureButton.setText("Stop");
}
Log.d("test",""+isRecording);
}
// public void onClick(View v) {
// // 사진 촬영 버튼 클릭 이벤트
//// takePicture(); // 사진 촬영 메소드 호출
// startRecordingVideo();
// }
});
}
// 카메라 미리보기를 생성하는 메소드
private void createCameraPreview() {
try {
SurfaceTexture texture = textureView.getSurfaceTexture();
assert texture != null;
// 텍스처의 크기를 카메라 미리보기 크기로 설정
texture.setDefaultBufferSize(1920, 1080);
Surface surface = new Surface(texture);
// 미리보기를 위한 CaptureRequest.Builder 설정
captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
captureRequestBuilder.addTarget(surface);
// 카메라 캡처 세션 생성
cameraDevice.createCaptureSession(Collections.singletonList(surface), new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(CameraCaptureSession session) {
// 카메라가 이미 닫혔다면 아무 작업도 수행하지 않음
if (cameraDevice == null) {
return;
}
// 캡처 세션 시작
cameraCaptureSessions = session;
updatePreview();
}
@Override
public void onConfigureFailed(CameraCaptureSession session) {
// 구성 실패시 Toast 메시지 출력
Toast.makeText(MainActivity.this, "Configuration change", Toast.LENGTH_SHORT).show();
}
}, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
// 카메라를 여는 메소드
private void openCamera() {
CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try {
String cameraId = manager.getCameraIdList()[0];
// 카메라 권한 체크
if (ActivityCompat.checkSelfPermission(this, "android.permission.CAMERA") != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{"android.permission.CAMERA","android.permission.RECORD_AUDIO"}, REQUEST_CAMERA_PERMISSION);
return;
}
// 카메라 오픈, 상태 콜백과 핸들러 설정
manager.openCamera(cameraId, stateCallback, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
// 카메라 미리보기를 업데이트하는 메소드
private void updatePreview() {
if (cameraDevice == null) {
Toast.makeText(this, "Error", Toast.LENGTH_SHORT).show();
return;
}
// 자동 모드로 미리보기 설정
captureRequestBuilder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO);
try {
// 미리보기 요청을 반복하여 캡처 세션에 제출
cameraCaptureSessions.setRepeatingRequest(captureRequestBuilder.build(), null, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
@Override
protected void onPause() {
// 액티비티가 일시정지되면 카메라를 닫음
super.onPause();
if (cameraDevice != null) {
cameraDevice.close();
cameraDevice = null;
}
}
private void takePicture() {
if (cameraDevice == null) return;
CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try {
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraDevice.getId());
Size[] jpegSizes = null;
if (characteristics != null) {
jpegSizes = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP).getOutputSizes(ImageFormat.JPEG);
}
// 이미지 사이즈 설정
int width = 480;
int height = 640;
if (jpegSizes != null && jpegSizes.length > 0) {
width = jpegSizes[0].getWidth();
height = jpegSizes[0].getHeight();
}
// 이미지 저장을 위한 ImageReader 설정
ImageReader reader = ImageReader.newInstance(width, height, ImageFormat.JPEG, 1);
List<Surface> outputSurfaces = new ArrayList<>(2);
outputSurfaces.add(reader.getSurface());
outputSurfaces.add(new Surface(textureView.getSurfaceTexture()));
// 캡처 요청 생성
final CaptureRequest.Builder captureBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureBuilder.addTarget(reader.getSurface());
captureBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
String path = getCacheDir() + "/" + fileName;
// 파일 생성
File file = new File(path);
// 이미지 저장 리스너
ImageReader.OnImageAvailableListener readerListener = new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader reader) {
Image image = null;
try {
image = reader.acquireLatestImage();
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
byte[] bytes = new byte[buffer.capacity()];
buffer.get(bytes);
save(bytes);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (image != null) {
image.close();
}
}
}
private void save(byte[] bytes) throws IOException {
OutputStream output = null;
try {
output = new FileOutputStream(file);
output.write(bytes);
} finally {
if (null != output) {
output.close();
}
}
}
};
reader.setOnImageAvailableListener(readerListener, null);
// 캡처 세션 종료 후 이미지 저장
final CameraCaptureSession.CaptureCallback captureListener = new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
super.onCaptureCompleted(session, request, result);
Toast.makeText(MainActivity.this, "Saved:" + file, Toast.LENGTH_SHORT).show();
createCameraPreview();
// 여기에서 다른 화면으로 전환
Intent intent = new Intent(MainActivity.this, MainActivity2.class);
intent.putExtra("img",path);
startActivity(intent);
}
};
// 캡처 세션 시작
cameraDevice.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(CameraCaptureSession session) {
try {
session.capture(captureBuilder.build(), captureListener, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
@Override
public void onConfigureFailed(CameraCaptureSession session) {
}
}, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private void closePreviewSession() {
if (cameraCaptureSessions != null) {
cameraCaptureSessions.close();
cameraCaptureSessions = null;
}
}
private void setUpMediaRecorder() throws IOException {
Log.d("Test","setUpMediaRecorder()");
mediaRecorder = new MediaRecorder();
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
// 저장될 파일 설정
String outputFilePath = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DOWNLOADS ) + "/my_video.mp4";
File mediaFile = new File(outputFilePath);
mediaRecorder.setOutputFile(mediaFile.getAbsolutePath());
mediaRecorder.setVideoEncodingBitRate(10000000);
mediaRecorder.setVideoFrameRate(30);
mediaRecorder.setVideoSize(1920, 1080);
mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
mediaRecorder.prepare();
}
public void startRecording() throws IOException {
setUpMediaRecorder();
startRecordingVideo(); // 이전에 설명한 녹화 시작 로직
}
public void stopRecording() {
Log.d("StopStop","stop");
mediaRecorder.stop();
mediaRecorder.reset();
// startPreview(); // 녹화 후에 카메라 미리보기를 다시 시작
}
private void startRecordingVideo() {
try {
closePreviewSession();
SurfaceTexture texture = textureView.getSurfaceTexture();
assert texture != null;
texture.setDefaultBufferSize(1920, 1080);
List<Surface> surfaces = new ArrayList<>();
// Surface for the camera preview
Surface previewSurface = new Surface(texture);
surfaces.add(previewSurface);
captureRequestBuilder.addTarget(previewSurface);
// Surface for the MediaRecorder
Surface recorderSurface = mediaRecorder.getSurface();
surfaces.add(recorderSurface);
captureRequestBuilder.addTarget(recorderSurface);
// Start a capture session
cameraDevice.createCaptureSession(surfaces, new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
cameraCaptureSessions = cameraCaptureSession;
updatePreview();
runOnUiThread(new Runnable() {
@Override
public void run() {
// UI
isRecording = true;
// Start recording
mediaRecorder.start();
}
});
}
@Override
public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {
Toast.makeText(MainActivity.this, "Configuration change", Toast.LENGTH_SHORT).show();
}
}, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
}
결과 입니다.
'안드로이드 자바' 카테고리의 다른 글
[Android][Java] 로고 애니메이션 넣어주기 (0) | 2024.02.02 |
---|---|
[Android][Java] 그림 그리기 (2) | 2024.01.30 |
[Android][Java] 카메라X 프리뷰 보여주기 (0) | 2024.01.21 |
[Android][Java] Camera2 API를 사용하여 사진찍기 (0) | 2024.01.19 |
[Android][Java] Intent 사용해서 유튜브 앱 열기 (0) | 2024.01.15 |