Skip to content

Commit bef8e17

Browse files
committed
refactor(*): introduce streamer pipeline to enable multiple output
1 parent e5e0c1d commit bef8e17

File tree

63 files changed

+4840
-1140
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+4840
-1140
lines changed
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/*
2+
* Copyright (C) 2025 Thibault B.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.github.thibaultbee.streampack.core.elements.endpoints
17+
18+
import android.util.Log
19+
import io.github.thibaultbee.streampack.core.configuration.mediadescriptor.MediaDescriptor
20+
import io.github.thibaultbee.streampack.core.elements.data.Frame
21+
import io.github.thibaultbee.streampack.core.elements.encoders.CodecConfig
22+
import kotlinx.coroutines.flow.MutableStateFlow
23+
import kotlinx.coroutines.flow.StateFlow
24+
import kotlinx.coroutines.runBlocking
25+
26+
class DummyEndpoint : IEndpointInternal {
27+
private val _isOpenFlow = MutableStateFlow(false)
28+
override val isOpenFlow: StateFlow<Boolean> = _isOpenFlow
29+
30+
private val _frameFlow = MutableStateFlow<Frame?>(null)
31+
val frameFlow: StateFlow<Frame?> = _frameFlow
32+
33+
var numOfAudioFramesWritten = 0
34+
private set
35+
var numOfVideoFramesWritten = 0
36+
private set
37+
val numOfFramesWritten: Int
38+
get() = numOfAudioFramesWritten + numOfVideoFramesWritten
39+
40+
private val _isStreamingFlow = MutableStateFlow(false)
41+
val isStreamingFlow: StateFlow<Boolean> = _isStreamingFlow
42+
43+
private val _configFlow = MutableStateFlow<CodecConfig?>(null)
44+
val configFlow: StateFlow<CodecConfig?> = _configFlow
45+
46+
override val info: IEndpoint.IEndpointInfo
47+
get() = TODO("Not yet implemented")
48+
49+
override fun getInfo(type: MediaDescriptor.Type): IEndpoint.IEndpointInfo {
50+
TODO("Not yet implemented")
51+
}
52+
53+
override val metrics: Any
54+
get() = TODO("Not yet implemented")
55+
56+
override suspend fun open(descriptor: MediaDescriptor) {
57+
_isOpenFlow.emit(true)
58+
}
59+
60+
override suspend fun close() {
61+
_isOpenFlow.emit(false)
62+
}
63+
64+
override suspend fun write(frame: Frame, streamPid: Int) {
65+
Log.i(TAG, "write: $frame")
66+
_frameFlow.emit(frame)
67+
when {
68+
frame.isAudio -> numOfAudioFramesWritten++
69+
frame.isVideo -> numOfVideoFramesWritten++
70+
}
71+
}
72+
73+
override fun addStreams(streamConfigs: List<CodecConfig>): Map<CodecConfig, Int> {
74+
runBlocking {
75+
streamConfigs.forEach { _configFlow.emit(it) }
76+
}
77+
return streamConfigs.associateWith { it.hashCode() }
78+
}
79+
80+
override fun addStream(streamConfig: CodecConfig): Int {
81+
runBlocking {
82+
_configFlow.emit(streamConfig)
83+
}
84+
return streamConfig.hashCode()
85+
}
86+
87+
override suspend fun startStream() {
88+
_isStreamingFlow.emit(true)
89+
}
90+
91+
override suspend fun stopStream() {
92+
_isStreamingFlow.emit(false)
93+
}
94+
95+
companion object {
96+
private const val TAG = "DummyEndpoint"
97+
}
98+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package io.github.thibaultbee.streampack.core.elements.sources
2+
3+
import android.media.MediaFormat
4+
import io.github.thibaultbee.streampack.core.elements.data.Frame
5+
import io.github.thibaultbee.streampack.core.elements.sources.audio.AudioSourceConfig
6+
import io.github.thibaultbee.streampack.core.elements.sources.audio.IAudioSourceInternal
7+
import kotlinx.coroutines.flow.MutableStateFlow
8+
import kotlinx.coroutines.flow.StateFlow
9+
import java.nio.ByteBuffer
10+
11+
class StubAudioSource : IAudioSourceInternal {
12+
override var isMuted: Boolean
13+
get() = TODO("Not yet implemented")
14+
set(value) {}
15+
16+
private val _isStreamingFlow = MutableStateFlow(false)
17+
val isStreamingFlow: StateFlow<Boolean> = _isStreamingFlow
18+
19+
private val _configurationFlow = MutableStateFlow<AudioSourceConfig?>(null)
20+
val configurationFlow: StateFlow<AudioSourceConfig?> = _configurationFlow
21+
22+
override fun getAudioFrame(inputBuffer: ByteBuffer?): Frame {
23+
return Frame(
24+
inputBuffer ?: ByteBuffer.allocate(8192),
25+
0,
26+
format = MediaFormat().apply {
27+
setString(
28+
MediaFormat.KEY_MIME,
29+
MediaFormat.MIMETYPE_AUDIO_RAW
30+
)
31+
})
32+
}
33+
34+
override fun startStream() {
35+
_isStreamingFlow.value = true
36+
}
37+
38+
override fun stopStream() {
39+
_isStreamingFlow.value = false
40+
}
41+
42+
override fun configure(config: AudioSourceConfig) {
43+
_configurationFlow.value = config
44+
}
45+
46+
47+
override fun release() {
48+
49+
}
50+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package io.github.thibaultbee.streampack.core.elements.sources
2+
3+
import android.media.MediaFormat
4+
import android.view.Surface
5+
import io.github.thibaultbee.streampack.core.elements.data.Frame
6+
import io.github.thibaultbee.streampack.core.elements.processing.video.source.DefaultSourceInfoProvider
7+
import io.github.thibaultbee.streampack.core.elements.processing.video.source.ISourceInfoProvider
8+
import io.github.thibaultbee.streampack.core.elements.sources.video.ISurfaceSource
9+
import io.github.thibaultbee.streampack.core.elements.sources.video.IVideoFrameSource
10+
import io.github.thibaultbee.streampack.core.elements.sources.video.IVideoSourceInternal
11+
import io.github.thibaultbee.streampack.core.elements.sources.video.VideoSourceConfig
12+
import kotlinx.coroutines.flow.MutableStateFlow
13+
import kotlinx.coroutines.flow.StateFlow
14+
import java.nio.ByteBuffer
15+
16+
class StubVideoSurfaceSource(override val timestampOffset: Long = 0) : StubVideoSource(),
17+
ISurfaceSource {
18+
override var outputSurface: Surface? = null
19+
}
20+
21+
class StubVideoFrameSource : StubVideoSource(), IVideoFrameSource {
22+
override fun getVideoFrame(buffer: ByteBuffer): Frame {
23+
return Frame(
24+
buffer,
25+
0L,
26+
format = MediaFormat().apply {
27+
setString(
28+
MediaFormat.KEY_MIME,
29+
MediaFormat.MIMETYPE_VIDEO_RAW
30+
)
31+
})
32+
}
33+
}
34+
35+
36+
abstract class StubVideoSource : IVideoSourceInternal {
37+
override val infoProviderFlow: StateFlow<ISourceInfoProvider> =
38+
MutableStateFlow(DefaultSourceInfoProvider())
39+
40+
private val _isStreamingFlow = MutableStateFlow(false)
41+
override val isStreamingFlow: StateFlow<Boolean> = _isStreamingFlow
42+
43+
private val _configurationFlow = MutableStateFlow<VideoSourceConfig?>(null)
44+
val configurationFlow: StateFlow<VideoSourceConfig?> = _configurationFlow
45+
46+
override suspend fun startStream() {
47+
_isStreamingFlow.emit(true)
48+
}
49+
50+
override suspend fun stopStream() {
51+
_isStreamingFlow.emit(false)
52+
}
53+
54+
override fun configure(config: VideoSourceConfig) {
55+
_configurationFlow.value = config
56+
}
57+
58+
override fun release() {
59+
60+
}
61+
}

0 commit comments

Comments
 (0)