Skip to content

Commit 2eaada4

Browse files
committed
feat(core): startStream to take a snapshot if needed
1 parent 4a3c2a6 commit 2eaada4

File tree

6 files changed

+179
-125
lines changed

6 files changed

+179
-125
lines changed

core/src/main/java/io/github/thibaultbee/streampack/core/elements/processing/video/DefaultSurfaceProcessor.kt

Lines changed: 36 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import androidx.annotation.IntRange
2424
import androidx.concurrent.futures.CallbackToFutureAdapter
2525
import com.google.common.util.concurrent.ListenableFuture
2626
import io.github.thibaultbee.streampack.core.elements.processing.video.outputs.ISurfaceOutput
27+
import io.github.thibaultbee.streampack.core.elements.processing.video.outputs.SurfaceOutput
2728
import io.github.thibaultbee.streampack.core.elements.processing.video.utils.GLUtils
2829
import io.github.thibaultbee.streampack.core.elements.processing.video.utils.extensions.preRotate
2930
import io.github.thibaultbee.streampack.core.elements.processing.video.utils.extensions.preVerticalFlip
@@ -33,7 +34,6 @@ import io.github.thibaultbee.streampack.core.logger.Logger
3334
import io.github.thibaultbee.streampack.core.pipelines.DispatcherProvider.Companion.THREAD_NAME_GL
3435
import io.github.thibaultbee.streampack.core.pipelines.IVideoDispatcherProvider
3536
import io.github.thibaultbee.streampack.core.pipelines.utils.HandlerThreadExecutor
36-
import java.io.IOException
3737
import java.util.concurrent.atomic.AtomicBoolean
3838

3939

@@ -118,7 +118,7 @@ private class DefaultSurfaceProcessor(
118118

119119
executeSafely {
120120
if (!surfaceOutputs.contains(surfaceOutput)) {
121-
renderer.registerOutputSurface(surfaceOutput.descriptor.surface)
121+
renderer.registerOutputSurface(surfaceOutput.surface)
122122
surfaceOutputs.add(surfaceOutput)
123123
} else {
124124
Logger.w(TAG, "Surface already added")
@@ -128,7 +128,7 @@ private class DefaultSurfaceProcessor(
128128

129129
private fun removeOutputSurfaceInternal(surfaceOutput: ISurfaceOutput) {
130130
if (surfaceOutputs.contains(surfaceOutput)) {
131-
renderer.unregisterOutputSurface(surfaceOutput.descriptor.surface)
131+
renderer.unregisterOutputSurface(surfaceOutput.surface)
132132
surfaceOutputs.remove(surfaceOutput)
133133
} else {
134134
Logger.w(TAG, "Surface not found")
@@ -152,7 +152,7 @@ private class DefaultSurfaceProcessor(
152152

153153
executeSafely {
154154
val surfaceOutput =
155-
surfaceOutputs.firstOrNull { it.descriptor.surface == surface }
155+
surfaceOutputs.firstOrNull { it.surface == surface }
156156
if (surfaceOutput != null) {
157157
removeOutputSurfaceInternal(surfaceOutput)
158158
} else {
@@ -163,7 +163,7 @@ private class DefaultSurfaceProcessor(
163163

164164
private fun removeAllOutputSurfacesInternal() {
165165
surfaceOutputs.forEach { surfaceOutput ->
166-
renderer.unregisterOutputSurface(surfaceOutput.descriptor.surface)
166+
renderer.unregisterOutputSurface(surfaceOutput.surface)
167167
}
168168
surfaceOutputs.clear()
169169
}
@@ -225,15 +225,17 @@ private class DefaultSurfaceProcessor(
225225

226226
val timestamp =
227227
surfaceTexture.timestamp + (surfaceInputsTimestampInNsMap[surfaceTexture] ?: 0L)
228-
surfaceOutputs.filter { it.isStreaming() }.forEach {
228+
surfaceOutputs.filterIsInstance<SurfaceOutput>().forEach {
229229
try {
230230
it.updateTransformMatrix(surfaceOutputMatrix, textureMatrix)
231-
renderer.render(
232-
timestamp,
233-
surfaceOutputMatrix,
234-
it.descriptor.surface,
235-
it.viewportRect
236-
)
231+
if (it.isStreaming()) {
232+
renderer.render(
233+
timestamp,
234+
surfaceOutputMatrix,
235+
it.surface,
236+
it.viewportRect
237+
)
238+
}
237239
} catch (t: Throwable) {
238240
Logger.e(TAG, "Error while rendering frame", t)
239241
}
@@ -242,14 +244,14 @@ private class DefaultSurfaceProcessor(
242244
// Surface, size and transform matrix for JPEG Surface if exists
243245
if (pendingSnapshots.isNotEmpty()) {
244246
try {
245-
val first = surfaceOutputs.first()
246-
val snapshotOutput = Pair(
247-
first.descriptor.resolution,
248-
surfaceOutputMatrix.clone()
249-
)
247+
val bitmapSurface =
248+
surfaceOutputs.maxByOrNull { it.resolution.width * it.resolution.height }
249+
?: throw IllegalStateException(
250+
"No output surface available for snapshot"
251+
)
250252

251253
// Execute all pending snapshots.
252-
takeSnapshot(snapshotOutput)
254+
takeSnapshot(bitmapSurface.resolution, surfaceOutputMatrix.clone())
253255
} catch (e: RuntimeException) {
254256
// Propagates error back to the app if failed to take snapshot.
255257
failAllPendingSnapshots(e)
@@ -260,36 +262,39 @@ private class DefaultSurfaceProcessor(
260262
/**
261263
* Takes a snapshot of the current frame and draws it to given JPEG surface.
262264
*
263-
* @param snapshotOutput The <Surface size, transform matrix> pair for drawing.
265+
* @param snapshotSize The size of the snapshot.
266+
* @param snapshotTransform The GL transform matrix to apply to the snapshot.
264267
*/
265-
private fun takeSnapshot(snapshotOutput: Pair<Size, FloatArray>) {
268+
private fun takeSnapshot(snapshotSize: Size, snapshotTransform: FloatArray) {
266269
if (pendingSnapshots.isEmpty()) {
267270
// No pending snapshot requests, do nothing.
268271
return
269272
}
270273

271-
// Write to JPEG surface, once for each snapshot request.
274+
// Write to Bitmap, once for each snapshot request.
272275
try {
273276
for (pendingSnapshot in pendingSnapshots) {
274-
val (size, transform) = snapshotOutput
275-
276-
// Take a snapshot of the current frame.
277-
val bitmap = getBitmap(size, transform, pendingSnapshot.rotationDegrees)
278-
279-
// Complete the snapshot request.
280-
pendingSnapshot.completer.set(bitmap)
277+
try {
278+
// Take a snapshot of the current frame.
279+
val bitmap =
280+
getBitmap(snapshotSize, snapshotTransform, pendingSnapshot.rotationDegrees)
281+
282+
// Complete the snapshot request.
283+
pendingSnapshot.completer.set(bitmap)
284+
} catch (t: Throwable) {
285+
// Propagate error back to the app if failed to take snapshot.
286+
pendingSnapshot.completer.setException(t)
287+
}
281288
}
289+
} finally {
282290
pendingSnapshots.clear()
283-
} catch (e: IOException) {
284-
failAllPendingSnapshots(e)
285291
}
286292
}
287293

288294
private fun failAllPendingSnapshots(throwable: Throwable) {
289295
for (pendingSnapshot in pendingSnapshots) {
290296
pendingSnapshot.completer.setException(throwable)
291297
}
292-
pendingSnapshots.clear()
293298
}
294299

295300
private fun getBitmap(
Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
package io.github.thibaultbee.streampack.core.elements.processing.video.outputs
22

3-
import android.graphics.Rect
4-
import io.github.thibaultbee.streampack.core.pipelines.outputs.SurfaceDescriptor
3+
import android.util.Size
4+
import android.view.Surface
55

66
interface ISurfaceOutput {
7-
val descriptor: SurfaceDescriptor
8-
val isStreaming: () -> Boolean
9-
val viewportRect: Rect
7+
val surface: Surface
8+
val resolution: Size
9+
val type: OutputType
1010

1111
fun updateTransformMatrix(output: FloatArray, input: FloatArray)
12+
13+
enum class OutputType {
14+
INTERNAL,
15+
BITMAP
16+
}
1217
}

core/src/main/java/io/github/thibaultbee/streampack/core/elements/processing/video/outputs/IdentitySurfaceOutput.kt

Lines changed: 0 additions & 40 deletions
This file was deleted.

core/src/main/java/io/github/thibaultbee/streampack/core/elements/processing/video/outputs/SurfaceOutput.kt

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@ package io.github.thibaultbee.streampack.core.elements.processing.video.outputs
1818
import android.graphics.Rect
1919
import android.graphics.RectF
2020
import android.opengl.Matrix
21+
import android.util.Size
22+
import android.view.Surface
2123
import androidx.annotation.IntRange
24+
import io.github.thibaultbee.streampack.core.elements.processing.video.outputs.SurfaceOutput.TransformationInfo
2225
import io.github.thibaultbee.streampack.core.elements.processing.video.outputs.ViewPortUtils.calculateViewportRect
2326
import io.github.thibaultbee.streampack.core.elements.processing.video.source.ISourceInfoProvider
2427
import io.github.thibaultbee.streampack.core.elements.processing.video.utils.TransformUtils
@@ -29,14 +32,27 @@ import io.github.thibaultbee.streampack.core.elements.utils.RotationValue
2932
import io.github.thibaultbee.streampack.core.elements.utils.extensions.rotate
3033
import io.github.thibaultbee.streampack.core.pipelines.outputs.SurfaceDescriptor
3134

35+
fun SurfaceOutput(
36+
descriptor: SurfaceDescriptor,
37+
isStreaming: () -> Boolean,
38+
transformationInfo: TransformationInfo
39+
) =
40+
SurfaceOutput(
41+
descriptor.surface,
42+
descriptor.resolution,
43+
isStreaming,
44+
transformationInfo
45+
)
46+
3247
class SurfaceOutput(
33-
override val descriptor: SurfaceDescriptor,
34-
override val isStreaming: () -> Boolean,
48+
override val surface: Surface,
49+
override val resolution: Size,
50+
val isStreaming: () -> Boolean,
3551
private val transformationInfo: TransformationInfo
3652
) :
3753
ISurfaceOutput {
38-
private val resolution = descriptor.resolution
39-
54+
override val type = ISurfaceOutput.OutputType.INTERNAL
55+
4056
private val infoProvider: ISourceInfoProvider
4157
get() = transformationInfo.infoProvider
4258

@@ -52,7 +68,7 @@ class SurfaceOutput(
5268
private val additionalTransform = FloatArray(16)
5369
private val invertedTextureTransform = FloatArray(16)
5470

55-
override val viewportRect = calculateViewportRect(
71+
val viewportRect = calculateViewportRect(
5672
transformationInfo.aspectRatioMode,
5773
transformationInfo.infoProvider.getSurfaceSize(resolution),
5874
resolution

0 commit comments

Comments
 (0)