### Start Preview with HDR Extension Source: https://context7.com/android/camera-samples/llms.txt Initiates a camera preview using a specified extension mode, such as HDR. This example assumes the CameraX ExtensionsManager has been initialized and the desired extension is available. ```kotlin viewModel.startPreviewWithExtension( lifecycleOwner = this, previewView = binding.previewView, extensionMode = ExtensionMode.HDR // Or BOKEH, NIGHT, etc. ) ``` -------------------------------- ### Initialize Camera and Start Preview with Camera2 API Source: https://context7.com/android/camera-samples/llms.txt Initializes the camera, sets up an ImageReader for JPEG capture, and creates a capture session. It then starts a repeating preview request. ```kotlin private fun initializeCamera() = lifecycleScope.launch(Dispatchers.Main) { val cameraId = cameraManager.cameraIdList[0] val characteristics = cameraManager.getCameraCharacteristics(cameraId) // Open camera camera = openCamera(cameraId) // Create ImageReader for still capture val size = characteristics.get( CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP )!!.getOutputSizes(ImageFormat.JPEG).maxByOrNull { it.width * it.height }!! imageReader = ImageReader.newInstance( size.width, size.height, ImageFormat.JPEG, 3 // Buffer size ) // Create capture session with preview and capture surfaces val targets = listOf(viewFinder.holder.surface, imageReader.surface) session = createCaptureSession(camera, targets) // Start preview val previewRequest = camera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW) .apply { addTarget(viewFinder.holder.surface) } session.setRepeatingRequest(previewRequest.build(), null, cameraHandler) } ``` -------------------------------- ### Start Video Capture with MediaStore Source: https://github.com/android/camera-samples/blob/main/CameraXVideo/README.md Initiates video recording using MediaStore for output. Requires a configured Recorder and OutputOptions. The capture process is asynchronous and returns an ActiveRecording object. ```kotlin private fun startVideoCapture() { val recording = this.recording if (recording != null) { // stop the currently ongoing recording recording.stop()) this.recording = null return } val name = "${System.currentTimeMillis()}.mp4" val outputOptions = MediaStoreOutputOptions.Builder( context.contentResolver, MediaStore.Video.Media.EXTERNAL_CONTENT_URI ) .setDisplayName(name) .build() recording = videoCapture.output .prepareRecording(this, outputOptions) .apply { if (audioEnabled.isChecked) { withAudioEnabled() } } .start(ContextCompat.getMainExecutor(context)) { recordEvent -> when(recordEvent) { is VideoRecordEvent.Finalize -> { val ہمارا影片已儲存至: ${recordEvent.output.targetUri} } } } } ``` -------------------------------- ### Custom Image Analysis with LuminosityAnalyzer Source: https://context7.com/android/camera-samples/llms.txt Implement ImageAnalysis.Analyzer for real-time frame processing. Analyze frames at most once per second and always close the image when done. This example calculates average luminance. ```kotlin import androidx.camera.core.ImageAnalysis import androidx.camera.core.ImageProxy import java.nio.ByteBuffer typealias LumaListener = (luma: Double) -> Unit class LuminosityAnalyzer(private val listener: LumaListener) : ImageAnalysis.Analyzer { private var lastAnalyzedTimestamp = 0L private fun ByteBuffer.toByteArray(): ByteArray { rewind() val data = ByteArray(remaining()) get(data) return data } override fun analyze(image: ImageProxy) { val currentTimestamp = System.currentTimeMillis() // Analyze at most every second if (currentTimestamp - lastAnalyzedTimestamp >= 1000L) { // YUV format: planes[0] is luminance (Y plane) val buffer = image.planes[0].buffer val data = buffer.toByteArray() // Convert bytes to pixel values (0-255) val pixels = data.map { it.toInt() and 0xFF } // Compute average luminance val luma = pixels.average() listener(luma) lastAnalyzedTimestamp = currentTimestamp } // IMPORTANT: Always close the image when done image.close() } } // Usage with ImageAnalysis val imageAnalysis = ImageAnalysis.Builder() .setTargetResolution(Size(1280, 720)) .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST) .build() imageAnalysis.setAnalyzer(cameraExecutor, LuminosityAnalyzer { luma -> Log.d(TAG, "Average luminosity: $luma") // Trigger actions based on luminosity (e.g., flash warning) }) ``` -------------------------------- ### Get Available Camera Extensions Source: https://context7.com/android/camera-samples/llms.txt Retrieves a list of supported camera extensions for a given camera ID. Ensure the camera ID is valid and accessible. ```kotlin import android.hardware.camera2.* import android.content.Context import androidx.fragment.app.Fragment import android.util.Log import kotlinx.coroutines.suspendCancellableCoroutine import kotlin.coroutines.resume import kotlin.coroutines.resumeWithException import android.view.Surface import androidx.core.content.ContextCompat import androidx.lifecycle.lifecycleScope import kotlinx.coroutines.launch class Camera2ExtensionsFragment : Fragment() { private val cameraManager: CameraManager by lazy { requireContext().getSystemService(Context.CAMERA_SERVICE) as CameraManager } private fun getAvailableExtensions(cameraId: String): List { val extensionChars = cameraManager.getCameraExtensionCharacteristics(cameraId) return extensionChars.supportedExtensions } @SuppressLint("MissingPermission") private suspend fun createExtensionSession( device: CameraDevice, extensionType: Int, // e.g., CameraExtensionCharacteristics.EXTENSION_HDR targets: List ): CameraExtensionSession = suspendCancellableCoroutine { cont -> val outputConfigs = targets.map { OutputConfiguration(it) } val extensionConfig = ExtensionSessionConfiguration( extensionType, outputConfigs, ContextCompat.getMainExecutor(requireContext()), object : CameraExtensionSession.StateCallback() { override fun onConfigured(session: CameraExtensionSession) { cont.resume(session) } override fun onConfigureFailed(session: CameraExtensionSession) { cont.resumeWithException(RuntimeException("Extension session failed")) } } ) device.createExtensionSession(extensionConfig) } private fun initializeWithExtension() = lifecycleScope.launch { val cameraId = cameraManager.cameraIdList[0] // Check available extensions val availableExtensions = getAvailableExtensions(cameraId) Log.d(TAG, "Available extensions: $availableExtensions") // Extension type constants // CameraExtensionCharacteristics.EXTENSION_AUTOMATIC // CameraExtensionCharacteristics.EXTENSION_BOKEH // CameraExtensionCharacteristics.EXTENSION_HDR // CameraExtensionCharacteristics.EXTENSION_NIGHT // CameraExtensionCharacteristics.EXTENSION_FACE_RETOUCH if (availableExtensions.contains(CameraExtensionCharacteristics.EXTENSION_HDR)) { val camera = openCamera(cameraId) val targets = listOf(viewFinder.holder.surface, imageReader.surface) val extensionSession = createExtensionSession( camera, CameraExtensionCharacteristics.EXTENSION_HDR, targets ) // Start preview with extension val previewRequest = camera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW) .apply { addTarget(viewFinder.holder.surface) } extensionSession.setRepeatingRequest( previewRequest.build(), ContextCompat.getMainExecutor(requireContext()), null ) } } } ``` -------------------------------- ### Capture JPEG, RAW, and DEPTH Images with Camera2 Source: https://context7.com/android/camera-samples/llms.txt This Kotlin code snippet demonstrates how to capture images in JPEG, RAW, and DEPTH formats using the Camera2 API. It includes setup for image readers, capture requests, and handling capture results. ```kotlin import android.hardware.camera2.* import android.media.Image import android.media.ImageReader import java.io.File import java.io.FileOutputStream data class CombinedCaptureResult( val image: Image, val metadata: CaptureResult, val orientation: Int, val format: Int ) : Closeable { override fun close() = image.close() } private suspend fun takePhoto(): CombinedCaptureResult = suspendCancellableCoroutine { // Flush any pending images while (imageReader.acquireNextImage() != null) { } // Queue for captured images val imageQueue = ArrayBlockingQueue(3) imageReader.setOnImageAvailableListener({ val image = reader.acquireNextImage() imageQueue.add(image) }, imageReaderHandler) // Create still capture request val captureRequest = session.device.createCaptureRequest( CameraDevice.TEMPLATE_STILL_CAPTURE ).apply { addTarget(imageReader.surface) } session.capture(captureRequest.build(), object : CameraCaptureSession.CaptureCallback() { override fun onCaptureCompleted( session: CameraCaptureSession, request: CaptureRequest, result: TotalCaptureResult ) { super.onCaptureCompleted(session, request, result) lifecycleScope.launch { val image = imageQueue.take() val orientation = computeExifOrientation(relativeOrientation.value ?: 0) cont.resume(CombinedCaptureResult( image = image, metadata = result, orientation = orientation, format = imageReader.imageFormat )) } } }, cameraHandler) } ``` ```kotlin private fun saveResult(result: CombinedCaptureResult): File { return when (result.format) { // Save JPEG directly ImageFormat.JPEG, ImageFormat.DEPTH_JPEG -> { val buffer = result.image.planes[0].buffer val bytes = ByteArray(buffer.remaining()).apply { buffer.get(this) } val output = File(context.filesDir, "IMG_${timestamp()}.jpg") FileOutputStream(output).use { it.write(bytes) } output } // Save RAW as DNG ImageFormat.RAW_SENSOR -> { val dngCreator = DngCreator(characteristics, result.metadata) val output = File(context.filesDir, "IMG_${timestamp()}.dng") FileOutputStream(output).use { dngCreator.writeImage(it, result.image) } output } else -> throw RuntimeException("Unknown format: ${result.format}") } } ``` -------------------------------- ### Initialize Camera and Preview with CameraX Source: https://context7.com/android/camera-samples/llms.txt Use this snippet to set up the camera provider, select a camera lens, and bind preview, image capture, and image analysis use cases to the lifecycle. Ensure CameraX dependencies are added to your project. ```kotlin import androidx.camera.core.* import androidx.camera.lifecycle.ProcessCameraProvider import androidx.concurrent.futures.await class CameraFragment : Fragment() { private var preview: Preview? = null private var imageCapture: ImageCapture? = null private var imageAnalyzer: ImageAnalysis? = null private var camera: Camera? = null private var cameraProvider: ProcessCameraProvider? = null private suspend fun setUpCamera() { // Get camera provider instance cameraProvider = ProcessCameraProvider.getInstance(requireContext()).await() // Select back camera as default val lensFacing = when { cameraProvider?.hasCamera(CameraSelector.DEFAULT_BACK_CAMERA) == true -> CameraSelector.LENS_FACING_BACK cameraProvider?.hasCamera(CameraSelector.DEFAULT_FRONT_CAMERA) == true -> CameraSelector.LENS_FACING_FRONT else -> throw IllegalStateException("No camera available") } bindCameraUseCases(lensFacing) } private fun bindCameraUseCases(lensFacing: Int) { val cameraProvider = cameraProvider ?: throw IllegalStateException("Camera init failed") // Build camera selector val cameraSelector = CameraSelector.Builder() .requireLensFacing(lensFacing) .build() // Build Preview use case preview = Preview.Builder() .setTargetAspectRatio(AspectRatio.RATIO_16_9) .setTargetRotation(viewFinder.display.rotation) .build() // Build ImageCapture use case imageCapture = ImageCapture.Builder() .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY) .setTargetAspectRatio(AspectRatio.RATIO_16_9) .setTargetRotation(viewFinder.display.rotation) .build() // Build ImageAnalysis use case imageAnalyzer = ImageAnalysis.Builder() .setTargetAspectRatio(AspectRatio.RATIO_16_9) .setTargetRotation(viewFinder.display.rotation) .build() .also { it.setAnalyzer(cameraExecutor, LuminosityAnalyzer { luma -> Log.d(TAG, "Average luminosity: $luma") }) } // Unbind all use cases before rebinding cameraProvider.unbindAll() // Bind use cases to camera camera = cameraProvider.bindToLifecycle( this, // LifecycleOwner cameraSelector, // Camera selector preview, // Preview use case imageCapture, // ImageCapture use case imageAnalyzer // ImageAnalysis use case ) // Connect preview to the view finder preview?.setSurfaceProvider(viewFinder.surfaceProvider) } } ``` -------------------------------- ### Initialize CameraX Extensions Manager Source: https://context7.com/android/camera-samples/llms.txt Initializes the CameraProvider and ExtensionsManager, then checks for available camera extensions. Ensure you have the necessary CameraX dependencies. ```kotlin import androidx.camera.extensions.ExtensionMode import androidx.camera.extensions.ExtensionsManager import androidx.camera.lifecycle.ProcessCameraProvider import kotlinx.coroutines.guava.await class CameraExtensionsViewModel(application: Application) : ViewModel() { private lateinit var cameraProvider: ProcessCameraProvider private lateinit var extensionsManager: ExtensionsManager suspend fun initializeCamera() { cameraProvider = ProcessCameraProvider.getInstance(application).await() extensionsManager = ExtensionsManager.getInstanceAsync( application, cameraProvider ).await() val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA // Check available extensions val availableExtensions = listOf( ExtensionMode.AUTO, ExtensionMode.BOKEH, ExtensionMode.HDR, ExtensionMode.NIGHT, ExtensionMode.FACE_RETOUCH ).filter { extensionsManager.isExtensionAvailable(cameraSelector, it) } Log.d(TAG, "Available extensions: $availableExtensions") } fun startPreviewWithExtension( lifecycleOwner: LifecycleOwner, previewView: PreviewView, @ExtensionMode.Mode extensionMode: Int ) { val baseCameraSelector = CameraSelector.DEFAULT_BACK_CAMERA // Get extension-enabled camera selector val cameraSelector = if (extensionMode == ExtensionMode.NONE) { baseCameraSelector } else { extensionsManager.getExtensionEnabledCameraSelector( baseCameraSelector, extensionMode ) } // Build use cases val preview = Preview.Builder() .setTargetAspectRatio(AspectRatio.RATIO_16_9) .build() val imageCapture = ImageCapture.Builder() .setTargetAspectRatio(AspectRatio.RATIO_16_9) .build() val useCaseGroup = UseCaseGroup.Builder() .setViewPort(previewView.viewPort!!) .addUseCase(imageCapture) .addUseCase(preview) .build() // Bind with extension-enabled selector cameraProvider.unbindAll() cameraProvider.bindToLifecycle( lifecycleOwner, cameraSelector, useCaseGroup ) preview.surfaceProvider = previewView.surfaceProvider } } ``` -------------------------------- ### Build CameraXbasic App Source: https://github.com/android/camera-samples/blob/main/CameraXBasic/README.md Use this command to build the debug version of the CameraXbasic app from the command line. ```sh ./gradlew assembleDebug ``` -------------------------------- ### Initialize High-Speed Capture Session Source: https://context7.com/android/camera-samples/llms.txt Sets up a high-speed capture session for slow-motion video. Requires a CameraDevice and a list of target Surfaces. Ensure the camera supports the desired frame rate. ```kotlin import android.hardware.camera2.* import android.media.MediaRecorder import android.util.Range class SlowMotionFragment : Fragment() { private lateinit var session: CameraConstrainedHighSpeedCaptureSession private lateinit var camera: CameraDevice private lateinit var recorder: MediaRecorder private val targetFps = 240 // High-speed frame rate private fun createRecorder(surface: Surface) = MediaRecorder().apply { setAudioSource(MediaRecorder.AudioSource.MIC) setVideoSource(MediaRecorder.VideoSource.SURFACE) setOutputFormat(MediaRecorder.OutputFormat.MPEG_4) setOutputFile(outputFile.absolutePath) setVideoEncodingBitRate(10_000_000) setVideoFrameRate(targetFps) setVideoSize(1920, 1080) setVideoEncoder(MediaRecorder.VideoEncoder.H264) setAudioEncoder(MediaRecorder.AudioEncoder.AAC) setInputSurface(surface) } private suspend fun createHighSpeedSession( device: CameraDevice, targets: List ): CameraConstrainedHighSpeedCaptureSession = suspendCancellableCoroutine { device.createConstrainedHighSpeedCaptureSession( targets, object : CameraCaptureSession.StateCallback() { override fun onConfigured(session: CameraCaptureSession) { cont.resume(session as CameraConstrainedHighSpeedCaptureSession) } override fun onConfigureFailed(session: CameraCaptureSession) { cont.resumeWithException(RuntimeException("High-speed session failed")) } }, cameraHandler ) } private fun initializeCamera() = lifecycleScope.launch(Dispatchers.Main) { camera = openCamera(cameraId) val targets = listOf(viewFinder.holder.surface, recorderSurface) session = createHighSpeedSession(camera, targets) // Create preview request with high-speed FPS range val previewRequest = session.device.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW) .apply { addTarget(viewFinder.holder.surface) set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, Range(30, targetFps)) } // Must use createHighSpeedRequestList for high-speed sessions val previewRequestList = session.createHighSpeedRequestList(previewRequest.build()) // Use setRepeatingBurst for high-speed capture session.setRepeatingBurst(previewRequestList, null, cameraHandler) } private fun startRecording() = lifecycleScope.launch(Dispatchers.IO) { // Stop preview and switch to recording request session.stopRepeating() val recordRequest = session.device.createCaptureRequest(CameraDevice.TEMPLATE_RECORD) .apply { addTarget(viewFinder.holder.surface) addTarget(recorderSurface) set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, Range(targetFps, targetFps)) } val recordRequestList = session.createHighSpeedRequestList(recordRequest.build()) session.setRepeatingBurst(recordRequestList, null, cameraHandler) // Start MediaRecorder recorder.apply { setOrientationHint(relativeOrientation.value ?: 0) prepare() start() } } private fun stopRecording() { recorder.stop() // Resume preview after recording } } ``` -------------------------------- ### Create Camera Capture Session with Camera2 API Source: https://context7.com/android/camera-samples/llms.txt Creates a capture session for the camera device. This session is used to process capture requests. Configuration failures are handled by throwing a runtime exception. ```kotlin private suspend fun createCaptureSession( device: CameraDevice, targets: List ): CameraCaptureSession = suspendCancellableCoroutine { device.createCaptureSession(targets, object : CameraCaptureSession.StateCallback() { override fun onConfigured(session: CameraCaptureSession) { cont.resume(session) } override fun onConfigureFailed(session: CameraCaptureSession) { val exc = RuntimeException("Session configuration failed") cont.resumeWithException(exc) } }, cameraHandler) } ``` -------------------------------- ### QR Code Scanner Implementation with MlKitAnalyzer Source: https://context7.com/android/camera-samples/llms.txt Sets up CameraX to scan QR codes using MLKit. Configure the barcode scanner for QR codes and use `MlKitAnalyzer` with a view-referenced coordinate system. Handles detected QR code content, including URLs, contact info, and Wi-Fi details, and logs them. ```kotlin import androidx.camera.mlkit.vision.MlKitAnalyzer import androidx.camera.view.CameraController.COORDINATE_SYSTEM_VIEW_REFERENCED import androidx.camera.view.LifecycleCameraController import androidx.camera.view.PreviewView import com.google.mlkit.vision.barcode.BarcodeScanner import com.google.mlkit.vision.barcode.BarcodeScannerOptions import com.google.mlkit.vision.barcode.BarcodeScanning import com.google.mlkit.vision.barcode.common.Barcode class QRScannerActivity : AppCompatActivity() { private lateinit var cameraController: LifecycleCameraController private lateinit var barcodeScanner: BarcodeScanner private fun startCamera() { cameraController = LifecycleCameraController(baseContext) val previewView: PreviewView = findViewById(R.id.preview_view) // Configure barcode scanner for QR codes val options = BarcodeScannerOptions.Builder() .setBarcodeFormats(Barcode.FORMAT_QR_CODE) .build() barcodeScanner = BarcodeScanning.getClient(options) // Set up MlKitAnalyzer with coordinate system cameraController.setImageAnalysisAnalyzer( ContextCompat.getMainExecutor(this), MlKitAnalyzer( listOf(barcodeScanner), COORDINATE_SYSTEM_VIEW_REFERENCED, // Coordinates relative to PreviewView ContextCompat.getMainExecutor(this) ) { result: MlKitAnalyzer.Result? -> val barcodeResults = result?.getValue(barcodeScanner) if (barcodeResults.isNullOrEmpty()) { previewView.overlay.clear() previewView.setOnTouchListener { _, _ -> false } return@MlKitAnalyzer } // Process detected QR code val barcode = barcodeResults.first() val qrContent = barcode.rawValue ?: return@MlKitAnalyzer // Handle different barcode value types when (barcode.valueType) { Barcode.TYPE_URL -> { val url = barcode.url?.url Log.d(TAG, "URL detected: $url") // Open URL in browser } Barcode.TYPE_CONTACT_INFO -> { val contact = barcode.contactInfo Log.d(TAG, "Contact: ${contact?.name?.formattedName}") } Barcode.TYPE_WIFI -> { val wifi = barcode.wifi Log.d(TAG, "WiFi SSID: ${wifi?.ssid}") } else -> { Log.d(TAG, "QR Content: $qrContent") } } // Draw bounding box overlay on detected QR code val boundingBox = barcode.boundingBox // Add custom drawable overlay to previewView.overlay } ) // Bind camera controller to lifecycle cameraController.bindToLifecycle(this) previewView.controller = cameraController } override fun onDestroy() { super.onDestroy() barcodeScanner.close() } } ``` -------------------------------- ### Capture Still Image to MediaStore Source: https://context7.com/android/camera-samples/llms.txt Use ImageCapture to take photos and save them to MediaStore. The callback provides success/error handling with the saved URI. Ensure necessary permissions and context are provided. ```kotlin import android.content.ContentValues import android.provider.MediaStore import androidx.camera.core.ImageCapture import androidx.camera.core.ImageCaptureException import java.text.SimpleDateFormat import java.util.Locale fun capturePhoto(imageCapture: ImageCapture, context: Context, executor: Executor) { // Create timestamped filename val name = SimpleDateFormat("yyyy-MM-dd-HH-mm-ss-SSS", Locale.US) .format(System.currentTimeMillis()) // Create MediaStore content values val contentValues = ContentValues().apply { put(MediaStore.MediaColumns.DISPLAY_NAME, name) put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg") if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) { put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/CameraXApp") } } // Create output options with MediaStore destination val outputOptions = ImageCapture.OutputFileOptions.Builder( context.contentResolver, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues ).build() // Take picture with callback imageCapture.takePicture( outputOptions, executor, object : ImageCapture.OnImageSavedCallback { override fun onError(exception: ImageCaptureException) { Log.e(TAG, "Photo capture failed: ${exception.message}", exception) } override fun onImageSaved(output: ImageCapture.OutputFileResults) { val savedUri = output.savedUri Log.d(TAG, "Photo capture succeeded: $savedUri") // Update UI, show thumbnail, etc. } } ) } ``` -------------------------------- ### Configure CameraX Gradle Dependencies Source: https://context7.com/android/camera-samples/llms.txt Include these dependencies in your app's build.gradle file for CameraX core, Camera2, lifecycle, view, video, extensions, and MLKit integration. Ensure you are using compatible versions for Kotlin coroutines and AndroidX libraries. ```groovy // build.gradle (app module) plugins { id 'com.android.application' id 'org.jetbrains.kotlin.android' } android { compileSdk 34 defaultConfig { applicationId "com.example.camerasample" minSdk 21 targetSdk 34 } buildFeatures { viewBinding true } } dependencies { // CameraX core def camerax_version = "1.3.1" implementation "androidx.camera:camera-core:$camerax_version" implementation "androidx.camera:camera-camera2:$camerax_version" implementation "androidx.camera:camera-lifecycle:$camerax_version" implementation "androidx.camera:camera-view:$camerax_version" // CameraX Video implementation "androidx.camera:camera-video:$camerax_version" // CameraX Extensions (HDR, Night, Bokeh, etc.) implementation "androidx.camera:camera-extensions:$camerax_version" // CameraX MLKit integration implementation "androidx.camera:camera-mlkit-vision:$camerax_version" // MLKit Barcode scanning implementation 'com.google.mlkit:barcode-scanning:17.2.0' // Kotlin coroutines implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3' implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-guava:1.7.3' // AndroidX implementation 'androidx.core:core-ktx:1.12.0' implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'androidx.fragment:fragment-ktx:1.6.2' implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.2' implementation 'androidx.concurrent:concurrent-futures-ktx:1.1.0' // ExifInterface for image metadata implementation 'androidx.exifinterface:exifinterface:1.3.7' } ``` -------------------------------- ### Bind VideoCapture Use Case Source: https://context7.com/android/camera-samples/llms.txt Binds the VideoCapture use case with a Recorder and configures video quality. Ensure CameraX core and video libraries are added to your project. ```kotlin import androidx.camera.video.* import android.content.ContentValues import android.provider.MediaStore import java.text.SimpleDateFormat import java.util.Locale class VideoCaptureFragment : Fragment() { private lateinit var videoCapture: VideoCapture private var currentRecording: Recording? = null private suspend fun bindVideoCapture() { val cameraProvider = ProcessCameraProvider.getInstance(requireContext()).await() val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA // Create QualitySelector for video resolution val qualitySelector = QualitySelector.from(Quality.FHD) // Build Preview val preview = Preview.Builder() .setTargetAspectRatio(AspectRatio.RATIO_16_9) .build() .apply { setSurfaceProvider(previewView.surfaceProvider) } // Build Recorder and VideoCapture val recorder = Recorder.Builder() .setQualitySelector(qualitySelector) .build() videoCapture = VideoCapture.withOutput(recorder) // Bind use cases cameraProvider.unbindAll() cameraProvider.bindToLifecycle( viewLifecycleOwner, cameraSelector, videoCapture, preview ) } @SuppressLint("MissingPermission") private fun startRecording() { // Create MediaStore output options val name = "CameraX-recording-" + SimpleDateFormat("yyyy-MM-dd-HH-mm-ss-SSS", Locale.US) .format(System.currentTimeMillis()) + ".mp4" val contentValues = ContentValues().apply { put(MediaStore.Video.Media.DISPLAY_NAME, name) } val mediaStoreOutput = MediaStoreOutputOptions.Builder( requireActivity().contentResolver, MediaStore.Video.Media.EXTERNAL_CONTENT_URI ).setContentValues(contentValues).build() // Start recording currentRecording = videoCapture.output .prepareRecording(requireActivity(), mediaStoreOutput) .withAudioEnabled() // Enable audio recording .start(ContextCompat.getMainExecutor(requireContext())) { event -> when (event) { is VideoRecordEvent.Start -> { Log.d(TAG, "Recording started") // Update UI to show recording state } is VideoRecordEvent.Pause -> { Log.d(TAG, "Recording paused") } is VideoRecordEvent.Resume -> { Log.d(TAG, "Recording resumed") } is VideoRecordEvent.Finalize -> { if (!event.hasError()) { val uri = event.outputResults.outputUri Log.d(TAG, "Video saved to: $uri") } else { Log.e(TAG, "Recording error: ${event.error}") } } } // Update recording stats val stats = event.recordingStats val sizeMB = stats.numBytesRecorded / 1_000_000.0 val durationSec = stats.recordedDurationNanos / 1_000_000_000 Log.d(TAG, "Recording: ${sizeMB}MB, ${durationSec}s") } } private fun stopRecording() { currentRecording?.stop() currentRecording = null } private fun pauseRecording() { currentRecording?.pause() } private fun resumeRecording() { currentRecording?.resume() } } ``` -------------------------------- ### Open Camera Device with Camera2 API Source: https://context7.com/android/camera-samples/llms.txt Opens a camera device using its ID. Handles connection, disconnection, and errors. Requires a `Handler` for asynchronous operations. ```kotlin import android.hardware.camera2.* import android.view.Surface import kotlinx.coroutines.suspendCancellableCoroutine import kotlin.coroutines.resume import kotlin.coroutines.resumeWithException class Camera2Fragment : Fragment() { private val cameraManager: CameraManager by lazy { requireContext().getSystemService(Context.CAMERA_SERVICE) as CameraManager } private lateinit var camera: CameraDevice private lateinit var session: CameraCaptureSession private lateinit var imageReader: ImageReader private val cameraThread = HandlerThread("CameraThread").apply { start() } private val cameraHandler = Handler(cameraThread.looper) @SuppressLint("MissingPermission") private suspend fun openCamera(cameraId: String): CameraDevice = suspendCancellableCoroutine { cameraManager.openCamera(cameraId, object : CameraDevice.StateCallback() { override fun onOpened(device: CameraDevice) { cont.resume(device) } override fun onDisconnected(device: CameraDevice) { Log.w(TAG, "Camera $cameraId disconnected") device.close() } override fun onError(device: CameraDevice, error: Int) { val msg = when (error) { ERROR_CAMERA_DEVICE -> "Fatal (device)" ERROR_CAMERA_DISABLED -> "Device policy" ERROR_CAMERA_IN_USE -> "Camera in use" ERROR_CAMERA_SERVICE -> "Fatal (service)" ERROR_MAX_CAMERAS_IN_USE -> "Maximum cameras in use" else -> "Unknown" } val exc = RuntimeException("Camera $cameraId error: ($error) $msg") if (cont.isActive) cont.resumeWithException(exc) } }, cameraHandler) } ``` -------------------------------- ### Run Unit Tests with Robolectric Source: https://github.com/android/camera-samples/blob/main/CameraXBasic/README.md Execute unit tests using Robolectric without requiring an Android device. This is useful for fast, local testing. ```sh ./gradlew test ``` -------------------------------- ### Implement AutoFitSurfaceView for Camera Preview Source: https://context7.com/android/camera-samples/llms.txt Use this custom SurfaceView to automatically adjust its dimensions to match the camera preview's aspect ratio, preventing distortion. Call setAspectRatio with the desired preview dimensions. ```kotlin import android.content.Context import android.util.AttributeSet import android.view.SurfaceView import kotlin.math.roundToInt class AutoFitSurfaceView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyle: Int = 0 ) : SurfaceView(context, attrs, defStyle) { private var aspectRatio = 0f /** * Sets the aspect ratio for this view. The size will be measured based on * the ratio calculated from the parameters. * * @param width Camera resolution horizontal size * @param height Camera resolution vertical size */ fun setAspectRatio(width: Int, height: Int) { require(width > 0 && height > 0) { "Size cannot be negative" } aspectRatio = width.toFloat() / height.toFloat() holder.setFixedSize(width, height) requestLayout() } override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { super.onMeasure(widthMeasureSpec, heightMeasureSpec) val width = MeasureSpec.getSize(widthMeasureSpec) val height = MeasureSpec.getSize(heightMeasureSpec) if (aspectRatio == 0f) { setMeasuredDimension(width, height) } else { // Maintain aspect ratio val newWidth: Int val newHeight: Int val actualRatio = if (width > height) aspectRatio else 1f / aspectRatio if (width < height * actualRatio) { newHeight = height newWidth = (height * actualRatio).roundToInt() } else { newWidth = width newHeight = (width / actualRatio).roundToInt() } setMeasuredDimension(newWidth, newHeight) } } } // Usage val previewSize = getPreviewOutputSize(display, characteristics, SurfaceHolder::class.java) autoFitSurfaceView.setAspectRatio(previewSize.width, previewSize.height) ``` -------------------------------- ### Run Instrumented Tests on Device Source: https://github.com/android/camera-samples/blob/main/CameraXBasic/README.md Execute instrumented tests on an Android device connected via ADB. This ensures tests run in a more realistic environment. ```sh ./gradlew connectedAndroidTest ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.