Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/camera/camera_android_camerax/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.7.6+1

* Fixes video recording duration discrepancy by waiting for the first recorded frame before completing `startVideoCapturing`, and validates errors on `stopVideoRecording`.

## 0.7.6

* Adds support for zero-shutter-lag still image capture via
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -425,13 +425,17 @@ abstract class CameraXLibraryPigeonProxyApiRegistrar(val binaryMessenger: Binary
*/
abstract fun getPigeonApiCameraIntegerRange(): PigeonApiCameraIntegerRange

/**
* An implementation of [PigeonApiRecordingStats] used to add a new Dart instance of
* `RecordingStats` to the Dart `InstanceManager`.
*/
abstract fun getPigeonApiRecordingStats(): PigeonApiRecordingStats

/**
* An implementation of [PigeonApiVideoRecordEvent] used to add a new Dart instance of
* `VideoRecordEvent` to the Dart `InstanceManager`.
*/
open fun getPigeonApiVideoRecordEvent(): PigeonApiVideoRecordEvent {
return PigeonApiVideoRecordEvent(this)
}
abstract fun getPigeonApiVideoRecordEvent(): PigeonApiVideoRecordEvent

/**
* An implementation of [PigeonApiVideoRecordEventStart] used to add a new Dart instance of
Expand All @@ -441,13 +445,19 @@ abstract class CameraXLibraryPigeonProxyApiRegistrar(val binaryMessenger: Binary
return PigeonApiVideoRecordEventStart(this)
}

/**
* An implementation of [PigeonApiVideoRecordEventStatus] used to add a new Dart instance of
* `VideoRecordEventStatus` to the Dart `InstanceManager`.
*/
open fun getPigeonApiVideoRecordEventStatus(): PigeonApiVideoRecordEventStatus {
return PigeonApiVideoRecordEventStatus(this)
}

/**
* An implementation of [PigeonApiVideoRecordEventFinalize] used to add a new Dart instance of
* `VideoRecordEventFinalize` to the Dart `InstanceManager`.
*/
open fun getPigeonApiVideoRecordEventFinalize(): PigeonApiVideoRecordEventFinalize {
return PigeonApiVideoRecordEventFinalize(this)
}
abstract fun getPigeonApiVideoRecordEventFinalize(): PigeonApiVideoRecordEventFinalize

/**
* An implementation of [PigeonApiMeteringPoint] used to add a new Dart instance of
Expand Down Expand Up @@ -745,6 +755,7 @@ abstract class CameraXLibraryPigeonProxyApiRegistrar(val binaryMessenger: Binary
PigeonApiCameraSize.setUpMessageHandlers(binaryMessenger, getPigeonApiCameraSize())
PigeonApiCameraIntegerRange.setUpMessageHandlers(
binaryMessenger, getPigeonApiCameraIntegerRange())
PigeonApiVideoRecordEvent.setUpMessageHandlers(binaryMessenger, getPigeonApiVideoRecordEvent())
PigeonApiMeteringPoint.setUpMessageHandlers(binaryMessenger, getPigeonApiMeteringPoint())
PigeonApiObserver.setUpMessageHandlers(binaryMessenger, getPigeonApiObserver())
PigeonApiCameraInfo.setUpMessageHandlers(binaryMessenger, getPigeonApiCameraInfo())
Expand Down Expand Up @@ -800,6 +811,7 @@ abstract class CameraXLibraryPigeonProxyApiRegistrar(val binaryMessenger: Binary
CameraXLibraryPigeonInstanceManagerApi.setUpMessageHandlers(binaryMessenger, null)
PigeonApiCameraSize.setUpMessageHandlers(binaryMessenger, null)
PigeonApiCameraIntegerRange.setUpMessageHandlers(binaryMessenger, null)
PigeonApiVideoRecordEvent.setUpMessageHandlers(binaryMessenger, null)
PigeonApiMeteringPoint.setUpMessageHandlers(binaryMessenger, null)
PigeonApiObserver.setUpMessageHandlers(binaryMessenger, null)
PigeonApiCameraInfo.setUpMessageHandlers(binaryMessenger, null)
Expand Down Expand Up @@ -908,12 +920,24 @@ private class CameraXLibraryPigeonProxyApiBaseCodec(
logNewInstanceFailure("CameraIntegerRange", value, it.exceptionOrNull())
}
}
} else if (value is androidx.camera.video.RecordingStats) {
registrar.getPigeonApiRecordingStats().pigeon_newInstance(value) {
if (it.isFailure) {
logNewInstanceFailure("RecordingStats", value, it.exceptionOrNull())
}
}
} else if (value is androidx.camera.video.VideoRecordEvent.Start) {
registrar.getPigeonApiVideoRecordEventStart().pigeon_newInstance(value) {
if (it.isFailure) {
logNewInstanceFailure("VideoRecordEventStart", value, it.exceptionOrNull())
}
}
} else if (value is androidx.camera.video.VideoRecordEvent.Status) {
registrar.getPigeonApiVideoRecordEventStatus().pigeon_newInstance(value) {
if (it.isFailure) {
logNewInstanceFailure("VideoRecordEventStatus", value, it.exceptionOrNull())
}
}
} else if (value is androidx.camera.video.VideoRecordEvent.Finalize) {
registrar.getPigeonApiVideoRecordEventFinalize().pigeon_newInstance(value) {
if (it.isFailure) {
Expand Down Expand Up @@ -1840,15 +1864,101 @@ abstract class PigeonApiCameraIntegerRange(
}
}
}
/**
* RecordingStats provides recording statistics such as duration and bytes recorded.
*
* See https://developer.android.com/reference/androidx/camera/video/RecordingStats.
*/
@Suppress("UNCHECKED_CAST")
abstract class PigeonApiRecordingStats(
open val pigeonRegistrar: CameraXLibraryPigeonProxyApiRegistrar
) {
/** The recorded duration in nanoseconds. */
abstract fun recordedDurationNanos(pigeon_instance: androidx.camera.video.RecordingStats): Long

/** The number of bytes recorded. */
abstract fun numBytesRecorded(pigeon_instance: androidx.camera.video.RecordingStats): Long

@Suppress("LocalVariableName", "FunctionName")
/** Creates a Dart instance of RecordingStats and attaches it to [pigeon_instanceArg]. */
fun pigeon_newInstance(
pigeon_instanceArg: androidx.camera.video.RecordingStats,
callback: (Result<Unit>) -> Unit
) {
if (pigeonRegistrar.ignoreCallsToDart) {
callback(
Result.failure(
CameraXError("ignore-calls-error", "Calls to Dart are being ignored.", "")))
} else if (pigeonRegistrar.instanceManager.containsInstance(pigeon_instanceArg)) {
callback(Result.success(Unit))
} else {
val pigeon_identifierArg =
pigeonRegistrar.instanceManager.addHostCreatedInstance(pigeon_instanceArg)
val recordedDurationNanosArg = recordedDurationNanos(pigeon_instanceArg)
val numBytesRecordedArg = numBytesRecorded(pigeon_instanceArg)
val binaryMessenger = pigeonRegistrar.binaryMessenger
val codec = pigeonRegistrar.codec
val channelName =
"dev.flutter.pigeon.camera_android_camerax.RecordingStats.pigeon_newInstance"
val channel = BasicMessageChannel<Any?>(binaryMessenger, channelName, codec)
channel.send(listOf(pigeon_identifierArg, recordedDurationNanosArg, numBytesRecordedArg)) {
if (it is List<*>) {
if (it.size > 1) {
callback(
Result.failure(CameraXError(it[0] as String, it[1] as String, it[2] as String?)))
} else {
callback(Result.success(Unit))
}
} else {
callback(Result.failure(CameraXLibraryPigeonUtils.createConnectionError(channelName)))
}
}
}
}
}
/**
* VideoRecordEvent is used to report video recording events and status.
*
* See https://developer.android.com/reference/androidx/camera/video/VideoRecordEvent.
*/
@Suppress("UNCHECKED_CAST")
open class PigeonApiVideoRecordEvent(
abstract class PigeonApiVideoRecordEvent(
open val pigeonRegistrar: CameraXLibraryPigeonProxyApiRegistrar
) {
/** The recording statistics for this event. */
abstract fun getRecordingStats(
pigeon_instance: androidx.camera.video.VideoRecordEvent
): androidx.camera.video.RecordingStats

companion object {
@Suppress("LocalVariableName")
fun setUpMessageHandlers(binaryMessenger: BinaryMessenger, api: PigeonApiVideoRecordEvent?) {
val codec = api?.pigeonRegistrar?.codec ?: CameraXLibraryPigeonCodec()
run {
val channel =
BasicMessageChannel<Any?>(
binaryMessenger,
"dev.flutter.pigeon.camera_android_camerax.VideoRecordEvent.getRecordingStats",
codec)
if (api != null) {
channel.setMessageHandler { message, reply ->
val args = message as List<Any?>
val pigeon_instanceArg = args[0] as androidx.camera.video.VideoRecordEvent
val wrapped: List<Any?> =
try {
listOf(api.getRecordingStats(pigeon_instanceArg))
} catch (exception: Throwable) {
CameraXLibraryPigeonUtils.wrapError(exception)
}
reply.reply(wrapped)
}
} else {
channel.setMessageHandler(null)
}
}
}
}

@Suppress("LocalVariableName", "FunctionName")
/** Creates a Dart instance of VideoRecordEvent and attaches it to [pigeon_instanceArg]. */
fun pigeon_newInstance(
Expand Down Expand Up @@ -1934,15 +2044,81 @@ open class PigeonApiVideoRecordEventStart(
return pigeonRegistrar.getPigeonApiVideoRecordEvent()
}
}
/**
* Indicates recording status updates.
*
* See https://developer.android.com/reference/androidx/camera/video/VideoRecordEvent.Status.
*/
@Suppress("UNCHECKED_CAST")
open class PigeonApiVideoRecordEventStatus(
open val pigeonRegistrar: CameraXLibraryPigeonProxyApiRegistrar
) {
@Suppress("LocalVariableName", "FunctionName")
/** Creates a Dart instance of VideoRecordEventStatus and attaches it to [pigeon_instanceArg]. */
fun pigeon_newInstance(
pigeon_instanceArg: androidx.camera.video.VideoRecordEvent.Status,
callback: (Result<Unit>) -> Unit
) {
if (pigeonRegistrar.ignoreCallsToDart) {
callback(
Result.failure(
CameraXError("ignore-calls-error", "Calls to Dart are being ignored.", "")))
} else if (pigeonRegistrar.instanceManager.containsInstance(pigeon_instanceArg)) {
callback(Result.success(Unit))
} else {
val pigeon_identifierArg =
pigeonRegistrar.instanceManager.addHostCreatedInstance(pigeon_instanceArg)
val binaryMessenger = pigeonRegistrar.binaryMessenger
val codec = pigeonRegistrar.codec
val channelName =
"dev.flutter.pigeon.camera_android_camerax.VideoRecordEventStatus.pigeon_newInstance"
val channel = BasicMessageChannel<Any?>(binaryMessenger, channelName, codec)
channel.send(listOf(pigeon_identifierArg)) {
if (it is List<*>) {
if (it.size > 1) {
callback(
Result.failure(CameraXError(it[0] as String, it[1] as String, it[2] as String?)))
} else {
callback(Result.success(Unit))
}
} else {
callback(Result.failure(CameraXLibraryPigeonUtils.createConnectionError(channelName)))
}
}
}
}

@Suppress("FunctionName")
/** An implementation of [PigeonApiVideoRecordEvent] used to access callback methods */
fun pigeon_getPigeonApiVideoRecordEvent(): PigeonApiVideoRecordEvent {
return pigeonRegistrar.getPigeonApiVideoRecordEvent()
}
}
/**
* Indicates the finalization of recording.
*
* See https://developer.android.com/reference/androidx/camera/video/VideoRecordEvent.Finalize.
*/
@Suppress("UNCHECKED_CAST")
open class PigeonApiVideoRecordEventFinalize(
abstract class PigeonApiVideoRecordEventFinalize(
open val pigeonRegistrar: CameraXLibraryPigeonProxyApiRegistrar
) {
/**
* The error code of the finalization.
*
* See
* https://developer.android.com/reference/androidx/camera/video/VideoRecordEvent.Finalize#getError().
*/
abstract fun error(pigeon_instance: androidx.camera.video.VideoRecordEvent.Finalize): Long

/**
* Whether the recording finalized with an error.
*
* See
* https://developer.android.com/reference/androidx/camera/video/VideoRecordEvent.Finalize#hasError().
*/
abstract fun hasError(pigeon_instance: androidx.camera.video.VideoRecordEvent.Finalize): Boolean

@Suppress("LocalVariableName", "FunctionName")
/**
* Creates a Dart instance of VideoRecordEventFinalize and attaches it to [pigeon_instanceArg].
Expand All @@ -1960,12 +2136,14 @@ open class PigeonApiVideoRecordEventFinalize(
} else {
val pigeon_identifierArg =
pigeonRegistrar.instanceManager.addHostCreatedInstance(pigeon_instanceArg)
val errorArg = error(pigeon_instanceArg)
val hasErrorArg = hasError(pigeon_instanceArg)
val binaryMessenger = pigeonRegistrar.binaryMessenger
val codec = pigeonRegistrar.codec
val channelName =
"dev.flutter.pigeon.camera_android_camerax.VideoRecordEventFinalize.pigeon_newInstance"
val channel = BasicMessageChannel<Any?>(binaryMessenger, channelName, codec)
channel.send(listOf(pigeon_identifierArg)) {
channel.send(listOf(pigeon_identifierArg, errorArg, hasErrorArg)) {
if (it is List<*>) {
if (it.size > 1) {
callback(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,24 @@ public PigeonApiVideoRecordEventListener getPigeonApiVideoRecordEventListener()
return new VideoRecordEventListenerProxyApi(this);
}

@NonNull
@Override
public PigeonApiRecordingStats getPigeonApiRecordingStats() {
return new RecordingStatsProxyApi(this);
}

@NonNull
@Override
public PigeonApiVideoRecordEvent getPigeonApiVideoRecordEvent() {
return new VideoRecordEventProxyApi(this);
}

@NonNull
@Override
public PigeonApiVideoRecordEventFinalize getPigeonApiVideoRecordEventFinalize() {
return new VideoRecordEventFinalizeProxyApi(this);
}

@NonNull
@Override
public PigeonApiPendingRecording getPigeonApiPendingRecording() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright 2013 The Flutter Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package io.flutter.plugins.camerax;

import androidx.annotation.NonNull;
import androidx.camera.video.RecordingStats;

/** ProxyApi implementation for {@link RecordingStats}. */
class RecordingStatsProxyApi extends PigeonApiRecordingStats {
RecordingStatsProxyApi(@NonNull ProxyApiRegistrar pigeonRegistrar) {
super(pigeonRegistrar);
}

@Override
public long recordedDurationNanos(@NonNull RecordingStats pigeonInstance) {
return pigeonInstance.getRecordedDurationNanos();
}

@Override
public long numBytesRecorded(@NonNull RecordingStats pigeonInstance) {
return pigeonInstance.getNumBytesRecorded();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright 2013 The Flutter Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package io.flutter.plugins.camerax;

import androidx.annotation.NonNull;
import androidx.camera.video.VideoRecordEvent;

/** ProxyApi implementation for {@link VideoRecordEvent.Finalize}. */
class VideoRecordEventFinalizeProxyApi extends PigeonApiVideoRecordEventFinalize {
VideoRecordEventFinalizeProxyApi(@NonNull ProxyApiRegistrar pigeonRegistrar) {
super(pigeonRegistrar);
}

@Override
public long error(@NonNull VideoRecordEvent.Finalize pigeonInstance) {
return (long) pigeonInstance.getError();
}

@Override
public boolean hasError(@NonNull VideoRecordEvent.Finalize pigeonInstance) {
return pigeonInstance.hasError();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright 2013 The Flutter Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package io.flutter.plugins.camerax;

import androidx.annotation.NonNull;
import androidx.camera.video.RecordingStats;
import androidx.camera.video.VideoRecordEvent;

/** ProxyApi implementation for {@link VideoRecordEvent}. */
class VideoRecordEventProxyApi extends PigeonApiVideoRecordEvent {
VideoRecordEventProxyApi(@NonNull ProxyApiRegistrar pigeonRegistrar) {
super(pigeonRegistrar);
}

@NonNull
@Override
public RecordingStats getRecordingStats(@NonNull VideoRecordEvent pigeonInstance) {
return pigeonInstance.getRecordingStats();
}
}
Loading
Loading