Skip to content

Commit

Permalink
Merge pull request #1439 from pedroSG94/refactor/create-source
Browse files Browse the repository at this point in the history
refactor create video and audio sources
  • Loading branch information
pedroSG94 committed Mar 19, 2024
2 parents 7b48d58 + a7e9664 commit 1ff34d3
Show file tree
Hide file tree
Showing 16 changed files with 53 additions and 60 deletions.
Expand Up @@ -52,7 +52,7 @@ class CameraXSource(
private var preview = Preview.Builder().build()
private var facing = CameraSelector.LENS_FACING_BACK

override fun create(width: Int, height: Int, fps: Int): Boolean {
override fun create(width: Int, height: Int, fps: Int, rotation: Int): Boolean {
preview = Preview.Builder()
.setTargetFrameRate(Range(fps, fps))
.setResolutionSelector(
Expand All @@ -65,7 +65,6 @@ class CameraXSource(
).build()
).build()
lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE)
created = true
return true
}

Expand Down
4 changes: 2 additions & 2 deletions build.gradle.kts
Expand Up @@ -7,13 +7,13 @@ val junitVersion by rootProject.extra { "4.13.2" }
val mockitoVersion by rootProject.extra { "5.2.1" }

plugins {
id("com.android.application") version "8.2.2" apply false
id("com.android.application") version "8.3.0" apply false
id("org.jetbrains.kotlin.android") version "1.9.23" apply false
id("org.jetbrains.dokka") version "1.9.20" apply true
}

tasks.register("clean") {
delete(rootProject.buildDir)
delete(layout.buildDirectory)
}

tasks.dokkaHtmlMultiModule.configure {
Expand Down
Expand Up @@ -118,7 +118,7 @@ public boolean prepareVideoEncoder(int width, int height, int fps, int bitRate,
return false;
}
MediaFormat videoFormat;
//if you dont use mediacodec rotation you need swap width and height in rotation 90 or 270
//if you don't use mediacodec rotation you need swap width and height in rotation 90 or 270
// for correct encoding resolution
String resolution;
if ((rotation == 90 || rotation == 270)) {
Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
#Sun Aug 06 22:37:42 CEST 2023
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
8 changes: 4 additions & 4 deletions library/src/main/java/com/pedro/library/base/StreamBase.kt
Expand Up @@ -105,7 +105,7 @@ abstract class StreamBase(
if (isStreaming || isRecording || isOnPreview) {
throw IllegalStateException("Stream, record and preview must be stopped before prepareVideo")
}
val videoResult = videoSource.create(width, height, fps)
val videoResult = videoSource.init(width, height, fps, rotation)
if (videoResult) {
if (rotation == 90 || rotation == 270) glInterface.setEncoderSize(height, width)
else glInterface.setEncoderSize(width, height) //0, 180
Expand All @@ -129,7 +129,7 @@ abstract class StreamBase(
if (isStreaming || isRecording) {
throw IllegalStateException("Stream and record must be stopped before prepareAudio")
}
val audioResult = audioSource.create(sampleRate, isStereo, echoCanceler, noiseSuppressor)
val audioResult = audioSource.init(sampleRate, isStereo, echoCanceler, noiseSuppressor)
if (audioResult) {
audioInfo(sampleRate, isStereo)
return audioEncoder.prepareAudioEncoder(bitrate, sampleRate, isStereo, audioSource.getMaxInputSize())
Expand Down Expand Up @@ -292,7 +292,7 @@ abstract class StreamBase(
fun changeVideoSource(source: VideoSource) {
val wasRunning = videoSource.isRunning()
val wasCreated = videoSource.created
if (wasCreated) source.create(videoEncoder.width, videoEncoder.height, videoEncoder.fps)
if (wasCreated) source.init(videoEncoder.width, videoEncoder.height, videoEncoder.fps, videoEncoder.rotation)
videoSource.stop()
videoSource.release()
if (wasRunning) source.start(glInterface.surfaceTexture)
Expand All @@ -309,7 +309,7 @@ abstract class StreamBase(
fun changeAudioSource(source: AudioSource) {
val wasRunning = audioSource.isRunning()
val wasCreated = audioSource.created
if (wasCreated) source.create(audioSource.sampleRate, audioSource.isStereo, audioSource.echoCanceler, audioSource.noiseSuppressor)
if (wasCreated) source.init(audioSource.sampleRate, audioSource.isStereo, audioSource.echoCanceler, audioSource.noiseSuppressor)
audioSource.stop()
audioSource.release()
if (wasRunning) source.start(getMicrophoneData)
Expand Down
Expand Up @@ -39,11 +39,7 @@ class AudioFileSource(
}).apply { isLoopMode = true }

override fun create(sampleRate: Int, isStereo: Boolean, echoCanceler: Boolean, noiseSuppressor: Boolean): Boolean {
this.sampleRate = sampleRate
this.isStereo = isStereo
this.echoCanceler = echoCanceler
this.noiseSuppressor = noiseSuppressor
//create microphone to confirm valid parameters
//create extractor to confirm valid parameters
val result = audioDecoder.initExtractor(context, path, null)
if (!result) {
throw IllegalArgumentException("Audio file track not found")
Expand All @@ -54,7 +50,6 @@ class AudioFileSource(
if (audioDecoder.isStereo != isStereo) {
throw IllegalArgumentException("Audio file isStereo (${audioDecoder.isStereo}) is different than the configured: $isStereo")
}
created = true
return true
}

Expand Down
Expand Up @@ -30,7 +30,16 @@ abstract class AudioSource {
var echoCanceler = false
var noiseSuppressor = false

abstract fun create(sampleRate: Int, isStereo: Boolean, echoCanceler: Boolean, noiseSuppressor: Boolean): Boolean
fun init(sampleRate: Int, isStereo: Boolean, echoCanceler: Boolean, noiseSuppressor: Boolean): Boolean {
this.sampleRate = sampleRate
this.isStereo = isStereo
this.echoCanceler = echoCanceler
this.noiseSuppressor = noiseSuppressor
created = create(sampleRate, isStereo, echoCanceler, noiseSuppressor)
return created
}

protected abstract fun create(sampleRate: Int, isStereo: Boolean, echoCanceler: Boolean, noiseSuppressor: Boolean): Boolean
abstract fun start(getMicrophoneData: GetMicrophoneData)
abstract fun stop()
abstract fun isRunning(): Boolean
Expand Down
Expand Up @@ -37,16 +37,11 @@ class InternalSource(private val mediaProjection: MediaProjection): AudioSource(
private val handlerThread = HandlerThread("InternalSource")

override fun create(sampleRate: Int, isStereo: Boolean, echoCanceler: Boolean, noiseSuppressor: Boolean): Boolean {
this.sampleRate = sampleRate
this.isStereo = isStereo
this.echoCanceler = echoCanceler
this.noiseSuppressor = noiseSuppressor
//create microphone to confirm valid parameters
val result = microphone.createMicrophone(sampleRate, isStereo, echoCanceler, noiseSuppressor)
if (!result) {
throw IllegalArgumentException("Some parameters specified are not valid");
}
created = true
return true
}

Expand Down
Expand Up @@ -28,16 +28,11 @@ class MicrophoneSource: AudioSource(), GetMicrophoneData {
private val microphone = MicrophoneManager(this)

override fun create(sampleRate: Int, isStereo: Boolean, echoCanceler: Boolean, noiseSuppressor: Boolean): Boolean {
this.sampleRate = sampleRate
this.isStereo = isStereo
this.echoCanceler = echoCanceler
this.noiseSuppressor = noiseSuppressor
//create microphone to confirm valid parameters
val result = microphone.createMicrophone(sampleRate, isStereo, echoCanceler, noiseSuppressor)
if (!result) {
throw IllegalArgumentException("Some parameters specified are not valid");
}
created = true
return true
}

Expand Down
Expand Up @@ -29,7 +29,6 @@ class NoAudioSource: AudioSource() {
private var running = false

override fun create(sampleRate: Int, isStereo: Boolean, echoCanceler: Boolean, noiseSuppressor: Boolean): Boolean {
created = true
return true
}

Expand Down
Expand Up @@ -38,15 +38,11 @@ class Camera1Source(context: Context): VideoSource() {
private val camera = Camera1ApiManager(null, context)
private var facing = CameraHelper.Facing.BACK

override fun create(width: Int, height: Int, fps: Int): Boolean {
this.width = width
this.height = height
this.fps = fps
override fun create(width: Int, height: Int, fps: Int, rotation: Int): Boolean {
val result = checkResolutionSupported(width, height)
if (!result) {
throw IllegalArgumentException("Unsupported resolution: ${width}x$height")
}
created = true
return true
}

Expand Down
Expand Up @@ -37,15 +37,11 @@ class Camera2Source(context: Context): VideoSource() {
private val camera = Camera2ApiManager(context)
private var facing = CameraHelper.Facing.BACK

override fun create(width: Int, height: Int, fps: Int): Boolean {
this.width = width
this.height = height
this.fps = fps
override fun create(width: Int, height: Int, fps: Int, rotation: Int): Boolean {
val result = checkResolutionSupported(width, height)
if (!result) {
throw IllegalArgumentException("Unsupported resolution: ${width}x$height")
}
created = true
return true
}

Expand Down
Expand Up @@ -28,8 +28,7 @@ class NoVideoSource: VideoSource() {

private var running = false

override fun create(width: Int, height: Int, fps: Int): Boolean {
created = true
override fun create(width: Int, height: Int, fps: Int, rotation: Int): Boolean {
return true
}

Expand Down
Expand Up @@ -31,40 +31,39 @@ import androidx.annotation.RequiresApi
* Created by pedro on 11/1/24.
*/
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
class ScreenSource(private val context: Context, private val mediaProjection: MediaProjection): VideoSource() {
class ScreenSource @JvmOverloads constructor(
context: Context,
private val mediaProjection: MediaProjection,
mediaProjectionCallback: MediaProjection.Callback? = null,
virtualDisplayCallback: VirtualDisplay.Callback? = null
): VideoSource() {

private var virtualDisplay: VirtualDisplay? = null
private val handlerThread = HandlerThread("ScreenSource")
private val mediaProjectionCallback = mediaProjectionCallback ?: object : MediaProjection.Callback() {}
private val virtualDisplayCallback = virtualDisplayCallback ?: object : VirtualDisplay.Callback() {}
private val dpi = context.resources.displayMetrics.densityDpi

override fun create(width: Int, height: Int, fps: Int): Boolean {
this.width = width
this.height = height
this.fps = fps
val result = checkResolutionSupported(width, height)
if (result) created = true
return result
override fun create(width: Int, height: Int, fps: Int, rotation: Int): Boolean {
return checkResolutionSupported(width, height)
}

override fun start(surfaceTexture: SurfaceTexture) {
this.surfaceTexture = surfaceTexture
if (!isRunning()) {
val dpi = context.resources.displayMetrics.densityDpi
val flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR
//Adapt MediaProjection render to stream resolution
val shouldRotate = width > height
val shouldRotate = rotation == 90 || rotation == 270
val displayWidth = if (shouldRotate) height else width
val displayHeight = if (shouldRotate) width else height
if (shouldRotate) {
surfaceTexture.setDefaultBufferSize(height, width)
}
handlerThread.start()
val mediaProjectionCallback = object : MediaProjection.Callback() {}
mediaProjection.registerCallback(mediaProjectionCallback, Handler(handlerThread.looper))

val callback = object : VirtualDisplay.Callback() {}
virtualDisplay = mediaProjection.createVirtualDisplay("ScreenSource",
displayWidth, displayHeight, dpi, flags,
Surface(surfaceTexture), callback, Handler(handlerThread.looper)
Surface(surfaceTexture), virtualDisplayCallback, Handler(handlerThread.looper)
)
}
}
Expand All @@ -78,6 +77,7 @@ class ScreenSource(private val context: Context, private val mediaProjection: Me
}

override fun release() {
mediaProjection.unregisterCallback(mediaProjectionCallback)
mediaProjection.stop()
}

Expand All @@ -89,4 +89,8 @@ class ScreenSource(private val context: Context, private val mediaProjection: Me
}
return true
}

fun resize(width: Int, height: Int) {
virtualDisplay?.resize(width, height, dpi)
}
}
Expand Up @@ -38,15 +38,11 @@ class VideoFileSource(
}
}).apply { isLoopMode = true }

override fun create(width: Int, height: Int, fps: Int): Boolean {
this.width = width
this.height = height
this.fps = fps
override fun create(width: Int, height: Int, fps: Int, rotation: Int): Boolean {
val result = videoDecoder.initExtractor(context, path, null)
if (!result) {
throw IllegalArgumentException("Video file track not found")
}
created = true
return true
}

Expand Down
Expand Up @@ -28,8 +28,18 @@ abstract class VideoSource {
var width = 0
var height = 0
var fps = 0
var rotation = 0

abstract fun create(width: Int, height: Int, fps: Int): Boolean
fun init(width: Int, height: Int, fps: Int, rotation: Int): Boolean {
this.width = width
this.height = height
this.fps = fps
this.rotation = rotation
created = create(width, height, fps, rotation)
return created
}

protected abstract fun create(width: Int, height: Int, fps: Int, rotation: Int): Boolean
abstract fun start(surfaceTexture: SurfaceTexture)
abstract fun stop()
abstract fun release()
Expand Down

0 comments on commit 1ff34d3

Please sign in to comment.