미리보기 구현

앱에 미리보기를 추가하려면 PreviewView를 사용합니다. 자르고, 크기를 조정하고, 회전하여 적절히 표시할 수 있는 View입니다.

카메라가 활성화되면 이미지 미리보기가 PreviewView 내부 영역으로 스트리밍됩니다.

PreviewView 사용

PreviewView를 사용하여 CameraX 미리보기를 구현하려면 다음 단계를 따르세요. 단계에 관한 설명은 다음 섹션에 있습니다.

  1. 선택사항으로 CameraXConfig.Provider를 구성합니다.
  2. PreviewView를 레이아웃에 추가합니다.
  3. ProcessCameraProvider를 요청합니다.
  4. View를 만들 때 ProcessCameraProvider를 확인합니다.
  5. 카메라를 선택하고 수명 주기 및 사용 사례를 결합합니다.

PreviewView를 사용하는 데는 몇 가지 제한사항이 있습니다. PreviewView를 사용하는 경우 다음 작업을 할 수 없습니다.

  • SurfaceTexture를 만들어서 TextureViewPreview.SurfaceProvider에서 설정
  • TextureView에서 SurfaceTexture를 검색하여 Preview.SurfaceProvider에서 설정
  • SurfaceView에서 Surface를 가져와서 Preview.SurfaceProvider에서 설정

이러한 작업을 할 경우 PreviewPreviewView로 프레임을 스트리밍하는 것을 중지합니다.

PreviewView를 레이아웃에 추가

다음 샘플은 레이아웃의 PreviewView를 보여줍니다.

<FrameLayout
    android:id="@+id/container">
        <androidx.camera.view.PreviewView
            android:id="@+id/previewView" />
</FrameLayout>

CameraProvider 요청

다음 코드는 CameraProvider를 요청하는 방법을 보여줍니다.

Kotlin

import androidx.camera.lifecycle.ProcessCameraProvider
import com.google.common.util.concurrent.ListenableFuture

class MainActivity : AppCompatActivity() {
    private lateinit var cameraProviderFuture : ListenableFuture<ProcessCameraProvider>
    override fun onCreate(savedInstanceState: Bundle?) {
        cameraProviderFuture = ProcessCameraProvider.getInstance(this)
    }
}

Java

import androidx.camera.lifecycle.ProcessCameraProvider
import com.google.common.util.concurrent.ListenableFuture

public class MainActivity extends AppCompatActivity {
    private ListenableFuture<ProcessCameraProvider> cameraProviderFuture;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        cameraProviderFuture = ProcessCameraProvider.getInstance(this);
    }
}

CameraProvider 사용 가능 여부 확인

CameraProvider를 요청한 후에는 뷰를 만들 때 초기화에 성공했는지 확인합니다. 다음 코드는 이 작업의 진행 방법을 보여줍니다.

Kotlin

cameraProviderFuture.addListener(Runnable {
    val cameraProvider = cameraProviderFuture.get()
    bindPreview(cameraProvider)
}, ContextCompat.getMainExecutor(this))

Java

cameraProviderFuture.addListener(() -> {
    try {
        ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
        bindPreview(cameraProvider);
    } catch (ExecutionException | InterruptedException e) {
        // No errors need to be handled for this Future.
        // This should never be reached.
    }
}, ContextCompat.getMainExecutor(this));

샘플에서 사용된 bindPreview 함수의 예는 다음 섹션에 제공된 코드를 참고하세요.

카메라 선택 및 수명 주기와 사용 사례 결합

CameraProvider를 만들고 확인한 후에는 다음 작업을 실행합니다.

  1. Preview를 만듭니다.
  2. 원하는 카메라 LensFacing 옵션을 지정합니다.
  3. 선택한 카메라와 사용 사례를 수명 주기에 결합합니다.
  4. PreviewPreviewView에 연결합니다.

다음 코드의 예제를 참조하세요.

Kotlin

fun bindPreview(cameraProvider : ProcessCameraProvider) {
    var preview : Preview = Preview.Builder()
            .build()

    var cameraSelector : CameraSelector = CameraSelector.Builder()
          .requireLensFacing(CameraSelector.LENS_FACING_BACK)
          .build()

    preview.setSurfaceProvider(previewView.getSurfaceProvider())

    var camera = cameraProvider.bindToLifecycle(this as LifecycleOwner, cameraSelector, preview)
}

Java

void bindPreview(@NonNull ProcessCameraProvider cameraProvider) {
    Preview preview = new Preview.Builder()
            .build();

    CameraSelector cameraSelector = new CameraSelector.Builder()
            .requireLensFacing(CameraSelector.LENS_FACING_BACK)
            .build();

    preview.setSurfaceProvider(previewView.getSurfaceProvider());

    Camera camera = cameraProvider.bindToLifecycle((LifecycleOwner)this, cameraSelector, preview);
}

bindToLifecycle()Camera 객체를 반환합니다. 확대/축소, 노출과 같은 카메라 출력을 제어하는 방법에 관한 자세한 내용은 카메라 출력을 참고하세요.

이제 카메라 미리보기를 구현했습니다. 앱을 빌드하고 미리보기가 예상대로 앱에 표시되고 작동하는지 확인합니다.

PreviewView의 추가 컨트롤

CameraX PreviewView는 다음과 같은 속성을 구성하기 위한 추가 API를 제공합니다.

구현 모드

PreviewView는 다음 모드 중 하나를 사용하여 타겟 View에 미리보기 스트림을 렌더링할 수 있습니다.

  • PERFORMANCE가 기본 모드입니다. PreviewViewSurfaceView를 사용하여 동영상 스트림을 표시하지만 특정 사례에서는 TextureView로 대체합니다. SurfaceView에는 전용 그리기 노출 영역이 있으며, 전용 그리기 노출 영역이 있으면 특히 미리보기 동영상 상단에 다른 UI 요소(예: 버튼)가 없는 경우 내부 하드웨어 컴포지터로 하드웨어 오버레이를 사용해 구현할 수 있는 가능성이 더 높습니다. 하드웨어 오버레이를 사용하여 렌더링하면 동영상 프레임이 GPU 경로를 사용하지 않으므로 플랫폼 전력 소비와 지연 시간을 줄일 수 있습니다.

  • COMPATIBLE 모드. 이 모드에서 PreviewViewSurfaceView와 달리 전용 그리기 노출 영역이 없는 TextureView를 사용합니다. 이에 따라 동영상이 표시될 수 있도록 블렌딩으로 렌더링됩니다. 이 추가 단계 중에 애플리케이션은 제한 없이 동영상 크기 조정 및 회전 등을 추가로 처리할 수 있습니다.

PreviewView.setImplementationMode()를 사용하여 애플리케이션에 적합한 구현 모드를 선택합니다. 기본 PERFORMANCE 모드가 애플리케이션에 적합하지 않은 경우 COMPATIBLE 모드를 설정하는 방법은 다음 코드 샘플에서 참고하세요.

Kotlin

// viewFinder is a PreviewView instance
viewFinder.implementationMode = PreviewView.ImplementationMode.COMPATIBLE

배율 유형

미리보기 동영상 해상도가 타겟 PreviewView의 크기와 다른 경우 자르기나 레터박스를 통해 동영상 콘텐츠를 뷰에 맞춰야 합니다(원본 가로세로 비율 유지). PreviewView는 이를 위해 다음과 같은 ScaleTypes를 제공합니다.

  • 레터박스용 FIT_CENTER, FIT_START, FIT_END: 전체 동영상 콘텐츠는 타겟 PreviewView에 표시할 수 있는 최대 크기로 조정됩니다(확대 또는 축소). 그러나 전체 동영상 프레임이 표시되지더라도 화면 일부가 비어 있을 수 있습니다. 선택한 3가지 배율 유형에 따라 동영상 프레임이 타겟 뷰의 가운데, 시작 또는 끝에 맞춰 정렬됩니다.

  • 자르기용 FILL_CENTER, FILL_START, FILL_END: 동영상이 PreviewView 가로세로 비율과 일치하지 않으면 콘텐츠의 일부만 표시되지만 동영상은 PreviewView 전체를 채웁니다.

CameraX에 사용되는 기본 배율 유형은 FILL_CENTER입니다. PreviewView.setScaleType()을 사용하여 애플리케이션에 가장 적합한 배율 유형을 설정합니다. 다음 코드 샘플은 FIT_CENTER 배율 유형을 설정합니다.

Kotlin

// viewFinder is a PreviewView instance
viewFinder.scaleType = PreviewView.ScaleType.FIT_CENTER

동영상을 표시하는 프로세스는 다음 단계로 구성됩니다.

  1. 동영상 크기 조정:
    • FIT_* 배율 유형의 경우 min(dst.width/src.width, dst.height/src.height)을 사용해 동영상 크기를 조정합니다.
    • FILL_* 배율 유형의 경우 max(dst.width/src.width, dst.height/src.height)를 사용해 동영상 크기를 조정합니다.
  2. 조정된 동영상을 대상 PreviewView에 맞춥니다.
    • FIT_CENTER/FILL_CENTER의 경우 조정된 동영상과 대상 PreviewView를 가운데에 맞춥니다.
    • FIT_START/FILL_START의 경우 조정된 동영상과 대상 PreviewView를 각 왼쪽 상단을 기준으로 맞춥니다.
    • FIT_END/FILL_END의 경우 조정된 동영상과 대상 PreviewView를 각 오른쪽 하단을 기준으로 맞춥니다.

예를 들어 640x480 원본 동영상 및 1920x1080 대상 PreviewView는 다음과 같습니다.

640x480 동영상과 1920x1080 미리보기를 비교하여 보여주는 이미지

다음 이미지는 FIT_START/FIT_CENTER/FIT_END 크기 조정 프로세스를 보여줍니다.

FIT_START, FIT_CENTER, FIT_END 크기 조정 프로세스를 보여주는 이미지

이 프로세스는 다음과 같이 작동합니다.

  1. min(1920/640, 1080/480) = 2.25를 사용해 동영상 프레임의 크기를 조정(원본 가로세로 비율 유지)하여 1440x1080의 중간 동영상 프레임을 생성합니다.
  2. 1440x1080 동영상 프레임을 1920x1080 PreviewView에 맞춥니다.
    • FIT_CENTER의 경우 동영상 프레임을 PreviewView 창의 가운데에 맞춥니다. PreviewView의 시작 및 끝 240픽셀 열은 비어 있습니다.
    • FIT_START의 경우 동영상 프레임을 PreviewView 창의 시작(왼쪽 상단)에 맞춥니다. PreviewView의 끝 480픽셀 열은 비어 있습니다.
    • FIT_END의 경우 동영상 프레임을 PreviewView 창의 (오른쪽 하단)에 맞춥니다. PreviewView의 시작 480픽셀 열은 비어 있습니다.

다음 이미지는 FILL_START/FILL_CENTER/FILL_END 크기 조정 프로세스를 보여줍니다.

FILL_START, FILL_CENTER, FILL_END 크기 조정 프로세스를 보여주는 이미지

이 프로세스는 다음과 같이 작동합니다.

  1. max(1920/640, 1080/480) = 3을 사용해 동영상 프레임의 크기를 조정하여 1920x1440(PreviewView 크기보다 큼)의 중간 동영상 프레임을 생성합니다.
  2. 1920x1080 PreviewView 창에 맞게 1920x1440 동영상 프레임을 자릅니다.
    • FILL_CENTER의 경우 조정된 1920x1440 동영상의 가운데에서 1920x1080을 자릅니다. 동영상의 상단 및 하단 180개 줄이 표시되지 않습니다.
    • FILL_START의 경우 조정된 1920x1440 동영상의 시작에서 1920x1080을 자릅니다. 동영상의 하단 360개 줄이 표시되지 않습니다.
    • FILL_END의 경우 조정된 1920x1440 동영상의 에서 1920x1080을 자릅니다. 동영상의 상단 360개 줄이 표시되지 않습니다.

추가 리소스

CameraX에 관해 자세히 알아보려면 다음 추가 리소스를 참조하세요.

Codelab

  • CameraX 시작하기
  • 코드 샘플

  • CameraX 샘플 앱