Как использовать Google Low Light Boost с CameraX, поскольку для создания LlbSession требуется Surface?Android

Форум для тех, кто программирует под Android
Ответить
Anonymous
 Как использовать Google Low Light Boost с CameraX, поскольку для создания LlbSession требуется Surface?

Сообщение Anonymous »

У меня есть этот код

Код: Выделить всё

import android.os.Bundle
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import android.Manifest
import android.content.ContentValues
import android.content.pm.PackageManager
import android.hardware.camera2.CameraCaptureSession
import android.hardware.camera2.CaptureRequest
import android.hardware.camera2.TotalCaptureResult
import android.os.Build
import android.provider.MediaStore
import androidx.camera.video.Recorder
import androidx.camera.video.Recording
import androidx.camera.video.VideoCapture
import androidx.core.content.ContextCompat
import java.util.concurrent.ExecutorService
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.core.Preview
import androidx.camera.core.CameraSelector
import android.util.Log
import android.view.Surface
import android.widget.Button
import androidx.annotation.OptIn
import androidx.camera.camera2.interop.Camera2Interop
import androidx.camera.camera2.interop.ExperimentalCamera2Interop
import androidx.camera.core.SurfaceRequest
import androidx.camera.core.UseCaseGroup
import androidx.camera.video.MediaStoreOutputOptions
import androidx.camera.video.Quality
import androidx.camera.video.QualitySelector
import androidx.camera.video.VideoRecordEvent
import androidx.camera.view.PreviewView
import androidx.core.content.PermissionChecker
import androidx.lifecycle.lifecycleScope
import com.google.android.gms.cameralowlight.LowLightBoost
import com.google.android.gms.cameralowlight.LowLightBoostCallback
import com.google.android.gms.cameralowlight.LowLightBoostClient
import com.google.android.gms.cameralowlight.LowLightBoostOptions
import com.google.android.gms.cameralowlight.LowLightBoostSession
import com.google.android.gms.cameralowlight.SceneDetectorCallback
import com.google.android.gms.common.api.Status
import kotlinx.coroutines.launch
import kotlinx.coroutines.tasks.await
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.concurrent.Executor

class MainActivity : AppCompatActivity() {

private var videoCapture: VideoCapture? = null
private var recording: Recording? = null

private var llbSession: LowLightBoostSession? = null

private lateinit var cameraExecutor: ExecutorService

private lateinit var viewFinder: PreviewView
private lateinit var button: Button

private val activityResultLauncher =
registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
)
{ permissions ->
// Handle Permission granted/rejected
var permissionGranted = true
permissions.entries.forEach {
if (it.key in REQUIRED_PERMISSIONS &&  !it.value)
permissionGranted = false
}
if (!permissionGranted) {
Toast.makeText(
baseContext,
"Permission request denied",
Toast.LENGTH_SHORT
).show()
} else {
startCamera()
}
}

val cameraId = "12"
var isInstalled = false
private lateinit var llbClient: LowLightBoostClient
private lateinit var executor: Executor

val callback = object : LowLightBoostClient.InstallStatusCallback {
override fun onError(description: String) {
}

override fun onCancelled() {
}

override fun onDownloadProgressUpdate(progress: Int) {
}

override fun onDownloadPending() {
}

override fun onDownloadStart() {
}

override fun onDownloadPaused() {
}

override fun onDownloadComplete() {
}

override fun onInstalled() {
isInstalled = true

}
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(R.layout.activity_main)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}

viewFinder = findViewById(R.id.viewFinder)
button = findViewById(R.id.video_capture_button)
executor = ContextCompat.getMainExecutor(this)

lifecycleScope.launch {
llbClient = LowLightBoost.getClient(this@MainActivity)
val isSupported = llbClient.isCameraSupported(cameraId).await()
if (isSupported && !isInstalled) {
// Trigger installation
llbClient.installModule(callback).await()
requestCameraPermission()
}
}

button.setOnClickListener {
captureVideo()
}
}

suspend fun createLlbSession(surfaceRequest: SurfaceRequest, outputSurfaceForLlb: Surface) {
// 1. Create the LLB Session configuration
val options = LowLightBoostOptions(
outputSurfaceForLlb,
cameraId,
surfaceRequest.resolution.width,
surfaceRequest.resolution.height,
true // Start enabled
)

// 2. Create the session.
llbSession = llbClient.createSession(options, object : LowLightBoostCallback {
override fun onSessionDisconnected(status: Status) {
}

override fun onSessionDestroyed() {
}
}).await()

// 3. Get the surface to use.
val llbInputSurface = llbSession?.getCameraSurface()

if (llbInputSurface != null) {
// 4. Provide the surface to the CameraX Preview UseCase.
surfaceRequest.provideSurface(llbInputSurface, executor, resultListener)

// 5.  Set the scene detector callback to monitor how much boost is being applied.
val onSceneBrightnessChanged = object : SceneDetectorCallback {
override fun onSceneBrightnessChanged(
session: LowLightBoostSession,
boostStrength: Float
) {
// Monitor the boostStrength from 0 (no boosting) to 1 (maximum boosting)
}
}
llbSession?.setSceneDetectorCallback(onSceneBrightnessChanged, null)
}

}

val resultListener: (SurfaceRequest.Result) -> Unit = { result ->
when (result.resultCode) {
SurfaceRequest.Result.RESULT_SURFACE_USED_SUCCESSFULLY -> {
// Surface accepted
}

SurfaceRequest.Result.RESULT_REQUEST_CANCELLED -> {
// Camera closed
}

SurfaceRequest.Result.RESULT_WILL_NOT_PROVIDE_SURFACE -> {
// UseCase stopped
}

SurfaceRequest.Result.RESULT_INVALID_SURFACE -> {
// Invalid surface
}

SurfaceRequest.Result.RESULT_SURFACE_ALREADY_PROVIDED -> {
// Surface already provided
}
}
}

private fun requestCameraPermission() {
if (allPermissionsGranted()) {
startCamera()
} else {
requestPermissions()
}
}

private fun captureVideo() {
val videoCapture = this.videoCapture ?: return

button.isEnabled = false

val curRecording = recording
if (curRecording != null) {
// Stop the current recording session.
curRecording.stop()
recording = null
return
}

// create and start a new recording session
val name = SimpleDateFormat(FILENAME_FORMAT, Locale.US)
.format(System.currentTimeMillis())
val contentValues = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, name)
put(MediaStore.MediaColumns.MIME_TYPE, "video/mp4")
put(MediaStore.Video.Media.RELATIVE_PATH, "Movies/CameraX-Video")
}

val mediaStoreOutputOptions = MediaStoreOutputOptions
.Builder(contentResolver, MediaStore.Video.Media.EXTERNAL_CONTENT_URI)
.setContentValues(contentValues)
.build()
recording = videoCapture.output
.prepareRecording(this, mediaStoreOutputOptions)
.apply {
if (PermissionChecker.checkSelfPermission(
this@MainActivity,
Manifest.permission.RECORD_AUDIO
) ==
PermissionChecker.PERMISSION_GRANTED
) {
withAudioEnabled()
}
}
.start(executor) { recordEvent ->
when (recordEvent) {
is VideoRecordEvent.Start -> {
button.apply {
text = "Stop"
isEnabled = true
}
}

is VideoRecordEvent.Finalize -> {
if (!recordEvent.hasError()) {
val msg = "Video capture succeeded: " +
"${recordEvent.outputResults.outputUri}"
Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT)
.show()
Log.d(TAG, msg)
} else {
recording?.close()
recording = null
Log.e(
TAG, "Video capture ends with error: "  +
"${recordEvent.error}"
)
}
button.apply {
text = "Start"
isEnabled = true
}
}
}
}
}

@OptIn(ExperimentalCamera2Interop::class)
private fun startCamera() {
val cameraProviderFuture = ProcessCameraProvider.getInstance(this)

cameraProviderFuture.addListener({
// Used to bind the lifecycle of cameras to the lifecycle owner
val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()

// Preview
val previewBuilder = Preview.Builder()

val extender = Camera2Interop.Extender(previewBuilder)
extender.setSessionCaptureCallback(
object : CameraCaptureSession.CaptureCallback() {
override fun onCaptureCompleted(
session: CameraCaptureSession,
request: CaptureRequest,
result: TotalCaptureResult
) {
super.onCaptureCompleted(session, request, result)
llbSession?.processCaptureResult(result)
}
}
)

val preview = previewBuilder.build()
.also {
it.surfaceProvider = viewFinder.surfaceProvider
}
preview.setSurfaceProvider { surfaceRequest ->
lifecycleScope.launch {
if (::llbClient.isInitialized && isInstalled) {
createLlbSession(surfaceRequest, someSurface)
}
}

}

val recorder = Recorder.Builder()
.setQualitySelector(QualitySelector.from(Quality.HIGHEST))
.build()
videoCapture = VideoCapture.withOutput(recorder)

// Select back camera as a default
val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA

val cameraInfo = cameraProvider.getCameraInfo(cameraSelector)

val useCaseGroupBuilder = UseCaseGroup.Builder()
.addUseCase(preview)
.addUseCase(videoCapture!!)

try {
// Unbind use cases before rebinding
cameraProvider.unbindAll()

val camera = cameraProvider.bindToLifecycle(
this, cameraSelector, useCaseGroupBuilder.build()
)

} catch (exc: Exception) {
Log.e(TAG, "Use case binding failed", exc)
}

}, ContextCompat.getMainExecutor(this))
}

private fun requestPermissions() {
activityResultLauncher.launch(REQUIRED_PERMISSIONS)
}

private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all {
ContextCompat.checkSelfPermission(
baseContext, it
) == PackageManager.PERMISSION_GRANTED
}

override fun onDestroy() {
super.onDestroy()
cameraExecutor.shutdown()
}

companion object {
private const val TAG = "CameraXApp"
private const val FILENAME_FORMAT = "yyyy-MM-dd-HH-mm-ss-SSS"
private val REQUIRED_PERMISSIONS =
mutableListOf(
Manifest.permission.CAMERA,
Manifest.permission.RECORD_AUDIO
).apply {
}.toTypedArray()
}

}
Теперь я следую этому документу и использую Google Low Light Boost
, который говорит о создании createLlbSession, но я не уверен, как передать выходную поверхностьForLlb, как показано в документе, а также я не уверен, что вызываю его в нужный момент, поскольку единственный пример кода относится к Camera2, а не к CameraX.
Вот пример кодовой базы.>

Подробнее здесь: https://stackoverflow.com/questions/798 ... n-requires
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Android»