Skip to content

Commit 4ba1483

Browse files
committed
chore(*): upgrade view finder package to a stable version
1 parent 25d895d commit 4ba1483

File tree

9 files changed

+105
-74
lines changed

9 files changed

+105
-74
lines changed

core/src/main/java/io/github/thibaultbee/streampack/core/elements/sources/video/IPreviewableSource.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import android.view.Surface
2020
import android.view.SurfaceHolder
2121
import android.view.SurfaceView
2222
import android.view.TextureView
23+
import io.github.thibaultbee.streampack.core.elements.processing.video.source.ISourceInfoProvider
2324
import io.github.thibaultbee.streampack.core.interfaces.setPreview
2425
import io.github.thibaultbee.streampack.core.streamers.single.SingleStreamer
2526
import kotlinx.coroutines.flow.StateFlow
@@ -28,6 +29,12 @@ import kotlinx.coroutines.flow.StateFlow
2829
* Interface for video sources that can be previewed.
2930
*/
3031
interface IPreviewableSource {
32+
/**
33+
* Orientation provider of the capture source.
34+
* It is used to orientate the frame according to the source orientation.
35+
*/
36+
val infoProviderFlow: StateFlow<ISourceInfoProvider>
37+
3138
/**
3239
* Flow of the last previewing state.
3340
*/

core/src/main/java/io/github/thibaultbee/streampack/core/elements/sources/video/camera/CameraInfoProvider.kt

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
package io.github.thibaultbee.streampack.core.elements.sources.video.camera
1717

1818
import android.hardware.camera2.CameraCharacteristics
19-
import android.hardware.camera2.CameraManager
2019
import android.util.Size
2120
import androidx.annotation.IntRange
2221
import io.github.thibaultbee.streampack.core.elements.processing.video.source.ISourceInfoProvider
@@ -25,10 +24,8 @@ import io.github.thibaultbee.streampack.core.elements.utils.RotationValue
2524
import io.github.thibaultbee.streampack.core.elements.utils.extensions.rotationToDegrees
2625

2726
internal fun CameraInfoProvider(
28-
cameraManager: CameraManager,
29-
cameraId: String
27+
characteristics: CameraCharacteristics
3028
): CameraInfoProvider {
31-
val characteristics = cameraManager.getCameraCharacteristics(cameraId)
3229
val rotationDegrees = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION) ?: 0
3330
val facingDirection = characteristics.get(CameraCharacteristics.LENS_FACING)
3431
return CameraInfoProvider(rotationDegrees, facingDirection = facingDirection)

core/src/main/java/io/github/thibaultbee/streampack/core/elements/sources/video/camera/CameraSource.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ internal class CameraSource(
8787
}
8888

8989

90-
override val infoProviderFlow = MutableStateFlow(CameraInfoProvider(manager, cameraId))
90+
override val infoProviderFlow = MutableStateFlow(CameraInfoProvider(characteristics))
9191

9292
// States
9393
private val _isStreamingFlow = MutableStateFlow(false)

demos/camera/build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ android {
1010

1111
defaultConfig {
1212
applicationId = "io.github.thibaultbee.streampack.sample"
13+
14+
minSdk = 23
1315
}
1416
buildFeatures {
1517
viewBinding = true

gradle/libs.versions.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ guava = "33.5.0-android"
66
videoApiClient = "1.6.7"
77
androidxActivity = "1.10.1"
88
androidxAppcompat = "1.7.1"
9-
androidxCamera = "1.4.0-alpha13"
9+
androidxCamera = "1.5.2"
1010
androidxConstraintlayout = "2.2.1"
1111
androidxCore = "1.17.0"
1212
androidxDatabinding = "8.13.0"

ui/build.gradle.kts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import utils.AndroidVersions
2+
13
plugins {
24
id(libs.plugins.android.library.get().pluginId)
35
id(libs.plugins.kotlin.android.get().pluginId)
@@ -8,6 +10,10 @@ description = "UI components for StreamPack."
810

911
android {
1012
namespace = "io.github.thibaultbee.streampack.ui"
13+
14+
defaultConfig {
15+
minSdk = 23
16+
}
1117
}
1218

1319
dependencies {

ui/src/main/java/io/github/thibaultbee/streampack/ui/views/PreviewView.kt

Lines changed: 24 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,15 @@ import android.view.ViewConfiguration
3030
import android.view.ViewGroup
3131
import android.widget.FrameLayout
3232
import androidx.annotation.MainThread
33-
import androidx.camera.viewfinder.CameraViewfinder
34-
import androidx.camera.viewfinder.CameraViewfinderExt.requestSurface
3533
import androidx.camera.viewfinder.core.ScaleType
34+
import androidx.camera.viewfinder.core.TransformationInfo
3635
import androidx.camera.viewfinder.core.ViewfinderSurfaceRequest
37-
import androidx.camera.viewfinder.core.populateFromCharacteristics
36+
import androidx.camera.viewfinder.core.ViewfinderSurfaceSession
37+
import androidx.camera.viewfinder.view.ViewfinderView
38+
import androidx.camera.viewfinder.view.requestSurfaceSession
3839
import io.github.thibaultbee.streampack.core.elements.sources.video.IPreviewableSource
3940
import io.github.thibaultbee.streampack.core.elements.sources.video.camera.CameraSettings.FocusMetering.Companion.DEFAULT_AUTO_CANCEL_DURATION_MS
4041
import io.github.thibaultbee.streampack.core.elements.sources.video.camera.ICameraSource
41-
import io.github.thibaultbee.streampack.core.elements.sources.video.camera.extensions.getCameraCharacteristics
4242
import io.github.thibaultbee.streampack.core.elements.utils.ConflatedJob
4343
import io.github.thibaultbee.streampack.core.elements.utils.OrientationUtils
4444
import io.github.thibaultbee.streampack.core.elements.utils.extensions.runningHistoryNotNull
@@ -74,9 +74,9 @@ import kotlinx.coroutines.withContext
7474
class PreviewView @JvmOverloads constructor(
7575
context: Context, attrs: AttributeSet? = null, defStyle: Int = 0
7676
) : FrameLayout(context, attrs, defStyle) {
77-
private val viewfinder = CameraViewfinder(context, attrs, defStyle)
77+
private val viewfinder = ViewfinderView(context, attrs, defStyle)
7878

79-
private var viewfinderSurfaceRequest: ViewfinderSurfaceRequest? = null
79+
private var surfaceRequestSession: ViewfinderSurfaceSession? = null
8080

8181
/**
8282
* Enables zoom on pinch gesture.
@@ -170,7 +170,7 @@ class PreviewView @JvmOverloads constructor(
170170
previewableSource?.let {
171171
lifecycleScope?.launch {
172172
try {
173-
startPreviewIfNeeded(it, surface)
173+
startPreview(it, surface)
174174
} catch (t: Throwable) {
175175
Logger.e(TAG, "Failed to start preview: $t")
176176
}
@@ -181,11 +181,19 @@ class PreviewView @JvmOverloads constructor(
181181
}
182182

183183
@MainThread
184-
private suspend fun startPreviewIfNeeded(
184+
private suspend fun startPreview(
185185
videoSource: IPreviewableSource,
186186
surface: Surface
187187
) {
188188
try {
189+
Logger.d(TAG, "Settings transformation")
190+
viewfinder.transformationInfo = TransformationInfo(
191+
sourceRotation = videoSource.infoProviderFlow.value.getRelativeRotationDegrees(
192+
display.rotation,
193+
false
194+
)
195+
)
196+
189197
Logger.i(TAG, "Starting preview")
190198
videoSource.startPreview(surface)
191199
listener?.onPreviewStarted()
@@ -390,32 +398,21 @@ class PreviewView @JvmOverloads constructor(
390398
return
391399
}
392400
val previewSize = getPreviewSize(videoSource, size)
393-
val builder = ViewfinderSurfaceRequest.Builder(previewSize)
394-
if (videoSource is ICameraSource) {
395-
val cameraCharacteristics =
396-
context.getCameraCharacteristics(videoSource.cameraId)
397-
builder.populateFromCharacteristics(cameraCharacteristics)
398-
} else {
399-
400-
val rotationDegrees = OrientationUtils.getSurfaceRotationDegrees(display.rotation)
401-
builder.setSourceOrientation(rotationDegrees)
402-
}
403-
requestSurface(builder)
401+
val request = ViewfinderSurfaceRequest(previewSize.width, previewSize.height)
402+
requestSurface(request)
404403
}
405404

406405
/**
407406
* Use [requestSurface] instead.
408407
*/
409408
private fun requestSurface(
410-
viewfinderBuilder: ViewfinderSurfaceRequest.Builder
409+
viewfinderRequest: ViewfinderSurfaceRequest
411410
) {
412411
lifecycleScope?.launch {
413-
val viewfinderRequest = viewfinderBuilder.build().apply {
414-
viewfinderSurfaceRequest = this
412+
val requestSession = viewfinder.requestSurfaceSession(viewfinderRequest).apply {
413+
surfaceRequestSession = this
415414
}
416-
viewfinderRequest.getSurfaceAsync()
417-
val surface = viewfinder.requestSurface(viewfinderRequest)
418-
surfaceFlow.emit(surface)
415+
surfaceFlow.emit(requestSession.surface)
419416
} ?: Logger.w(TAG, "Lifecycle scope is not available")
420417
}
421418

@@ -428,8 +425,8 @@ class PreviewView @JvmOverloads constructor(
428425
source.resetPreview()
429426
}
430427
}
431-
viewfinderSurfaceRequest?.markSurfaceSafeToRelease()
432-
viewfinderSurfaceRequest = null
428+
surfaceRequestSession?.close()
429+
surfaceRequestSession = null
433430
}
434431

435432

ui/src/main/java/io/github/thibaultbee/streampack/ui/views/StreamerExtensions.kt

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,40 @@
11
package io.github.thibaultbee.streampack.ui.views
22

33
import android.util.Size
4-
import androidx.camera.viewfinder.CameraViewfinder
5-
import androidx.camera.viewfinder.core.ViewfinderSurfaceRequest
4+
import androidx.camera.viewfinder.core.ViewfinderSurfaceSession
5+
import androidx.camera.viewfinder.view.ViewfinderView
66
import io.github.thibaultbee.streampack.core.elements.sources.video.IPreviewableSource
77
import io.github.thibaultbee.streampack.core.interfaces.IWithVideoSource
88

99
/**
10-
* Set preview on a [CameraViewfinder]
10+
* Sets preview on a [ViewfinderView]
1111
*
12-
* @param viewfinder The [CameraViewfinder] to set as preview
12+
* @param viewfinder The [ViewfinderView] to set as preview
1313
* @param previewSize The size of the preview
14-
* @return The [ViewfinderSurfaceRequest] used to set the preview. Use it to call [ViewfinderSurfaceRequest.markSurfaceSafeToRelease].
14+
* @return The [ViewfinderSurfaceSession] used to set the preview. Use it to call [ViewfinderSurfaceSession.close].
1515
* @throws [IllegalStateException] if the video source is not previewable
1616
*/
1717
suspend fun IWithVideoSource.setPreview(
18-
viewfinder: CameraViewfinder,
18+
viewfinder: ViewfinderView,
1919
previewSize: Size
20-
): ViewfinderSurfaceRequest {
20+
): ViewfinderSurfaceSession {
2121
val videoSource = videoInput?.sourceFlow?.value as? IPreviewableSource
2222
?: throw IllegalStateException("Video source is not previewable")
2323
return videoSource.setPreview(viewfinder, previewSize)
2424
}
2525

2626
/**
27-
* Start preview on a [CameraViewfinder]
27+
* Starts preview on a [ViewfinderView]
2828
*
29-
* @param viewfinder The [CameraViewfinder] to set as preview
29+
* @param viewfinder The [ViewfinderView] to set as preview
3030
* @param previewSize The size of the preview
31-
* @return The [ViewfinderSurfaceRequest] used to set the preview. Use it to call [ViewfinderSurfaceRequest.markSurfaceSafeToRelease] after [IWithVideoSource.stopPreview].
31+
* @return The [ViewfinderSurfaceSession] used to set the preview. Use it to call [ViewfinderSurfaceSession.close].
3232
* @throws [IllegalStateException] if the video source is not previewable
3333
*/
3434
suspend fun IWithVideoSource.startPreview(
35-
viewfinder: CameraViewfinder,
35+
viewfinder: ViewfinderView,
3636
previewSize: Size
37-
): ViewfinderSurfaceRequest {
37+
): ViewfinderSurfaceSession {
3838
val videoSource = videoInput?.sourceFlow?.value as? IPreviewableSource
3939
?: throw IllegalStateException("Video source is not previewable")
4040
return videoSource.startPreview(viewfinder, previewSize)

ui/src/main/java/io/github/thibaultbee/streampack/ui/views/VideoSourceExtensions.kt

Lines changed: 51 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -16,48 +16,70 @@
1616
package io.github.thibaultbee.streampack.ui.views
1717

1818
import android.util.Size
19-
import androidx.camera.viewfinder.CameraViewfinder
20-
import androidx.camera.viewfinder.CameraViewfinderExt.requestSurface
2119
import androidx.camera.viewfinder.core.ViewfinderSurfaceRequest
22-
import androidx.camera.viewfinder.core.populateFromCharacteristics
20+
import androidx.camera.viewfinder.core.ViewfinderSurfaceSession
21+
import androidx.camera.viewfinder.view.ViewfinderView
22+
import androidx.camera.viewfinder.view.requestSurfaceSession
2323
import io.github.thibaultbee.streampack.core.elements.sources.video.IPreviewableSource
24-
import io.github.thibaultbee.streampack.core.elements.sources.video.camera.ICameraSource
25-
import io.github.thibaultbee.streampack.core.elements.sources.video.camera.extensions.getCameraCharacteristics
2624

2725
/**
28-
* Start preview on a [CameraViewfinder]
26+
* Sets preview on a [ViewfinderView]
2927
*
30-
* @param viewfinder The [CameraViewfinder] to set as preview
28+
* @param viewfinderView The [ViewfinderView] to set as preview
3129
* @param previewSize The size of the preview
32-
* @return The [ViewfinderSurfaceRequest] used to set the preview. Use it to call [ViewfinderSurfaceRequest.markSurfaceSafeToRelease] after [stopPreview].
30+
* @return The [ViewfinderSurfaceSession] used to set the preview. Use it to call [ViewfinderSurfaceSession.close].
3331
*/
34-
suspend fun IPreviewableSource.startPreview(
35-
viewfinder: CameraViewfinder,
32+
suspend fun IPreviewableSource.setPreview(
33+
viewfinderView: ViewfinderView,
3634
previewSize: Size
37-
): ViewfinderSurfaceRequest {
38-
val request = setPreview(viewfinder, previewSize)
39-
startPreview()
40-
return request
35+
) = setPreview(viewfinderView, ViewfinderSurfaceRequest(previewSize.width, previewSize.height))
36+
37+
/**
38+
* Sets preview on a [ViewfinderView]
39+
*
40+
* @param viewfinderView The [ViewfinderView] to set as preview
41+
* @param surfaceRequest The [ViewfinderSurfaceRequest] used to set the preview.
42+
* @return The [ViewfinderSurfaceSession] used to set the preview. Use it to call [ViewfinderSurfaceSession.close].
43+
*/
44+
suspend fun IPreviewableSource.setPreview(
45+
viewfinderView: ViewfinderView,
46+
surfaceRequest: ViewfinderSurfaceRequest
47+
): ViewfinderSurfaceSession {
48+
val surfaceSession = viewfinderView.requestSurfaceSession(
49+
surfaceRequest
50+
)
51+
setPreview(surfaceSession.surface)
52+
return surfaceSession
4153
}
4254

4355
/**
44-
* Set preview on a [CameraViewfinder]
56+
* Starts preview on a [ViewfinderView]
4557
*
46-
* @param viewfinder The [CameraViewfinder] to set as preview
58+
* @param viewfinderView The [ViewfinderView] to set as preview
4759
* @param previewSize The size of the preview
48-
* @return The [ViewfinderSurfaceRequest] used to set the preview. Use it to call [ViewfinderSurfaceRequest.markSurfaceSafeToRelease].
60+
* @return The [ViewfinderSurfaceSession] used to set the preview. Use it to call [ViewfinderSurfaceSession.close].
4961
*/
50-
suspend fun IPreviewableSource.setPreview(
51-
viewfinder: CameraViewfinder,
62+
suspend fun IPreviewableSource.startPreview(
63+
viewfinderView: ViewfinderView,
5264
previewSize: Size
53-
): ViewfinderSurfaceRequest {
54-
val builder = ViewfinderSurfaceRequest.Builder(previewSize)
55-
val request = if (this is ICameraSource) {
56-
val cameraCharacteristics = viewfinder.context.getCameraCharacteristics(cameraId)
57-
builder.populateFromCharacteristics(cameraCharacteristics).build()
58-
} else {
59-
builder.build()
60-
}
61-
setPreview(viewfinder.requestSurface(request))
62-
return request
65+
): ViewfinderSurfaceSession {
66+
val surfaceSession = setPreview(viewfinderView, previewSize)
67+
startPreview()
68+
return surfaceSession
69+
}
70+
71+
/**
72+
* Starts preview on a [ViewfinderView]
73+
*
74+
* @param viewfinderView The [ViewfinderView] to set as preview
75+
* @param surfaceRequest The [ViewfinderSurfaceRequest] used to set the preview.
76+
* @return The [ViewfinderSurfaceSession] used to set the preview. Use it to call [ViewfinderSurfaceSession.close].
77+
*/
78+
suspend fun IPreviewableSource.startPreview(
79+
viewfinderView: ViewfinderView,
80+
surfaceRequest: ViewfinderSurfaceRequest
81+
): ViewfinderSurfaceSession {
82+
val surfaceSession = setPreview(viewfinderView, surfaceRequest)
83+
startPreview()
84+
return surfaceSession
6385
}

0 commit comments

Comments
 (0)