Skip to content

Commit 16a5a7a

Browse files
committed
Implement tanersener/mobile-ffmpeg integration for devices that can support it
1 parent 7eb7958 commit 16a5a7a

File tree

17 files changed

+305
-43
lines changed

17 files changed

+305
-43
lines changed

app/src/main/java/tv/remo/android/controller/activities/MainActivity.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import tv.remo.android.controller.sdk.RemoSettingsUtil
1818
import tv.remo.android.controller.sdk.components.RemoSocketComponent
1919
import tv.remo.android.controller.sdk.components.StatusBroadcasterComponent
2020
import tv.remo.android.controller.sdk.components.audio.RemoAudioProcessor
21-
import tv.remo.android.controller.sdk.components.video.RemoVideoProcessor
21+
import tv.remo.android.controller.sdk.components.video.RemoVideoProcessorLegacy
2222

2323
class MainActivity : AppCompatActivity(), View.OnClickListener {
2424
private lateinit var handler : Handler
@@ -97,7 +97,7 @@ class MainActivity : AppCompatActivity(), View.OnClickListener {
9797
websiteConnectionStatusView.registerStatusEvents(RemoSocketComponent::class.java)
9898
hardwareConnectionStatusView.registerStatusEvents(CommunicationDriverComponent::class.java)
9999
audioConnectionStatusView.registerStatusEvents(RemoAudioProcessor::class.java)
100-
videoConnectionStatusView.registerStatusEvents(RemoVideoProcessor::class.java)
100+
videoConnectionStatusView.registerStatusEvents(RemoVideoProcessorLegacy::class.java)
101101
ttsConnectionStatusView.registerStatusEvents(SystemDefaultTTSComponent::class.java)
102102
StatusBroadcasterComponent.sendUpdateBroadcast(applicationContext)
103103
}

mobile-ffmpeg-full-4.4/build.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
configurations.maybeCreate("default")
2+
artifacts.add("default", file('mobile-ffmpeg-full-4.4.aar'))
Binary file not shown.

sdk/src/main/java/tv/remo/android/controller/sdk/components/video/RemoVideoProcessor.kt

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
package tv.remo.android.controller.sdk.components.video
22

3+
import androidx.annotation.RequiresApi
34
import org.btelman.android.shellutil.Executor
45
import org.btelman.controlsdk.streaming.models.StreamInfo
5-
import org.btelman.controlsdk.streaming.video.processors.FFmpegVideoProcessor
6+
import org.btelman.controlsdk.streaming.video.processors.FFmpegVideoProcessorAPI27
67
import tv.remo.android.controller.sdk.RemoSettingsUtil
78
import tv.remo.android.controller.sdk.models.StringPref
89

910
/**
1011
* More customized video processor that ties into the remo app better
1112
*/
12-
class RemoVideoProcessor : FFmpegVideoProcessor() {
13-
13+
@RequiresApi(27)
14+
class RemoVideoProcessor : FFmpegVideoProcessorAPI27() {
1415
override fun getFilterOptions(props: StreamInfo): String {
1516
var filter = ""
1617
context?.let {
@@ -22,11 +23,11 @@ class RemoVideoProcessor : FFmpegVideoProcessor() {
2223
return filter
2324
}
2425

25-
override fun getVideoInputOptions(props: StreamInfo): ArrayList<String> {
26-
return RemoSettingsUtil.with(context!!){
27-
return@with getAndProcessPreference(it.ffmpegInputOptions, props)
28-
}
29-
}
26+
// override fun getVideoInputOptions(props: StreamInfo): ArrayList<String> {
27+
// return RemoSettingsUtil.with(context!!){
28+
// return@with getAndProcessPreference(it.ffmpegInputOptions, props)
29+
// }
30+
// }
3031

3132
override fun getVideoOutputOptions(props: StreamInfo): ArrayList<String> {
3233
return RemoSettingsUtil.with(context!!){
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package tv.remo.android.controller.sdk.components.video
2+
3+
import org.btelman.android.shellutil.Executor
4+
import org.btelman.controlsdk.streaming.models.StreamInfo
5+
import org.btelman.controlsdk.streaming.video.processors.LegacyFFmpegVideoProcessor
6+
import tv.remo.android.controller.sdk.RemoSettingsUtil
7+
import tv.remo.android.controller.sdk.models.StringPref
8+
9+
/**
10+
* More customized video processor that ties into the remo app better
11+
*/
12+
class RemoVideoProcessorLegacy : LegacyFFmpegVideoProcessor() {
13+
14+
override fun getFilterOptions(props: StreamInfo): String {
15+
var filter = ""
16+
context?.let {
17+
RemoSettingsUtil.with(it){ settings ->
18+
filter = settings.cameraFFmpegFilterOptions.getPref()
19+
}
20+
}
21+
filter = filter.replace("\${internal}", super.getFilterOptions(props))
22+
return filter
23+
}
24+
25+
override fun getVideoInputOptions(props: StreamInfo): ArrayList<String> {
26+
return RemoSettingsUtil.with(context!!){
27+
return@with getAndProcessPreference(it.ffmpegInputOptions, props)
28+
}
29+
}
30+
31+
override fun getVideoOutputOptions(props: StreamInfo): ArrayList<String> {
32+
return RemoSettingsUtil.with(context!!){
33+
return@with getAndProcessPreference(it.ffmpegOutputOptions, props)
34+
}
35+
}
36+
37+
private fun getAndProcessPreference(options: StringPref, props: StreamInfo) : ArrayList<String>{
38+
options.getPref().let { inputCommand ->
39+
return processCommand(inputCommand, props)
40+
//was not right, so lets just process the default
41+
?: processCommand(options.defaultValue, props)
42+
//default is also broken. Should never happen outside of development
43+
?: throw IllegalArgumentException("Invalid options!")
44+
}
45+
}
46+
47+
fun getHeaders() : String{
48+
val apiKey = RemoSettingsUtil.with(context!!).apiKey.getPref()
49+
return "-headers Authorization:Bearer${Executor.CHARACTER_SPACE}${apiKey}"
50+
}
51+
52+
/**
53+
* process command to replace with camera props
54+
*/
55+
private fun processCommand(command: String?, props: StreamInfo): ArrayList<String>? {
56+
if(command.isNullOrEmpty()) return null //nothing here, cannot use this command
57+
var processedCommand : String = command
58+
59+
//replace any defined variables that were wrapped in ${}
60+
props.apply {
61+
processedCommand = processedCommand.replace("\$width", "$width")
62+
.replace("\${height}", "$height")
63+
.replace("\${resolution}", "${width}x$height")
64+
.replace("\${framerate}", "$framerate")
65+
.replace("\${bitrate}", "$bitrate")
66+
.replace("\${inputStream}", "-")
67+
.replace("\${endpoint}", endpoint)
68+
.replace("\${headers}", getHeaders())
69+
.replace("\${bitrateflags}",
70+
"-b:v ${bitrate}k -minrate ${bitrate}k -maxrate ${bitrate}k -bufsize ${bitrate/1.5}k")
71+
}
72+
73+
return ArrayList<String>().also { list ->
74+
list.add(processedCommand)
75+
}
76+
}
77+
}

sdk/src/main/java/tv/remo/android/controller/sdk/utils/ComponentBuilderUtil.kt

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package tv.remo.android.controller.sdk.utils
22

3+
import android.content.Context
34
import android.os.Bundle
45
import org.btelman.controlsdk.hardware.components.HardwareComponent
56
import org.btelman.controlsdk.hardware.interfaces.HardwareDriver
@@ -10,6 +11,8 @@ import org.btelman.controlsdk.streaming.factories.VideoProcessorFactory
1011
import org.btelman.controlsdk.streaming.factories.VideoRetrieverFactory
1112
import org.btelman.controlsdk.streaming.models.CameraDeviceInfo
1213
import org.btelman.controlsdk.streaming.models.StreamInfo
14+
import org.btelman.controlsdk.streaming.utils.CameraUtil
15+
import org.btelman.controlsdk.streaming.video.retrievers.DummyRetriever
1316
import org.btelman.controlsdk.tts.SystemDefaultTTSComponent
1417
import tv.remo.android.controller.sdk.RemoSettingsUtil
1518
import tv.remo.android.controller.sdk.components.RemoCommandHandler
@@ -20,6 +23,7 @@ import tv.remo.android.controller.sdk.components.hardware.HardwareWatchdogCompon
2023
import tv.remo.android.controller.sdk.components.video.CameraCompatOverride
2124
import tv.remo.android.controller.sdk.components.video.RemoVideoComponent
2225
import tv.remo.android.controller.sdk.components.video.RemoVideoProcessor
26+
import tv.remo.android.controller.sdk.components.video.RemoVideoProcessorLegacy
2327

2428
/**
2529
* Helper class for assembling our list of components that we will use when using the robot
@@ -49,9 +53,9 @@ object ComponentBuilderUtil {
4953
return ttsList
5054
}
5155

52-
fun createStreamingComponents(settings: RemoSettingsUtil): Collection<ComponentHolder<*>> {
56+
fun createStreamingComponents(context: Context, settings: RemoSettingsUtil): Collection<ComponentHolder<*>> {
5357
val streamList = ArrayList<ComponentHolder<*>>()
54-
buildStreamingBundle(settings).apply {
58+
buildStreamingBundle(context, settings).apply {
5559
if(settings.cameraEnabled.getPref()){
5660
val videoComponent = ComponentHolder(RemoVideoComponent::class.java, this)
5761
streamList.add(videoComponent)
@@ -72,7 +76,7 @@ object ComponentBuilderUtil {
7276
RemoSocketComponent.createBundle(settings.apiKey.getPref(), settings.channelId.getPref()))
7377
}
7478

75-
private fun buildStreamingBundle(settings: RemoSettingsUtil): Bundle {
79+
private fun buildStreamingBundle(context: Context, settings: RemoSettingsUtil): Bundle {
7680
return Bundle().apply {
7781
val resolution = settings.cameraResolution.getPref().split("x")
7882
val streamInfo = StreamInfo(
@@ -85,8 +89,14 @@ object ComponentBuilderUtil {
8589
height = resolution[1].toInt()
8690
)
8791
//use our customized remo classes
88-
VideoRetrieverFactory.putClassInBundle(CameraCompatOverride::class.java, this)
89-
VideoProcessorFactory.putClassInBundle(RemoVideoProcessor::class.java, this)
92+
if(CameraUtil.supportsNDKCamera(context, settings.cameraDeviceId.getPref())){
93+
VideoRetrieverFactory.putClassInBundle(DummyRetriever::class.java, this)
94+
VideoProcessorFactory.putClassInBundle(RemoVideoProcessor::class.java, this)
95+
}
96+
else{
97+
VideoRetrieverFactory.putClassInBundle(CameraCompatOverride::class.java, this)
98+
VideoProcessorFactory.putClassInBundle(RemoVideoProcessorLegacy::class.java, this)
99+
}
90100
AudioProcessorFactory.putClassInBundle(RemoAudioProcessor::class.java, this)
91101
streamInfo.addToExistingBundle(this)
92102
}

settings.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1+
include ':mobile-ffmpeg-full-4.4'
12
include ':app', ':sdk', ':settingsutil', ':licensehelper', ':streaming'

streaming/build.gradle

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,15 @@ android {
2828
minifyEnabled false
2929
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
3030
}
31+
releaseDemo {
32+
minifyEnabled false
33+
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
34+
}
3135
}
32-
3336
}
3437

3538
dependencies {
39+
api project(path: ':mobile-ffmpeg-full-4.4')
3640
implementation fileTree(dir: 'libs', include: ['*.jar'])
3741
api "org.btelman.ffmpeg:core:1.0.2"
3842
api 'org.btelman.android:shellutil:1.4'

streaming/src/androidTest/java/org/btelman/controlsdk/streaming/VideoProcessorFactoryAndroidTest.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import org.btelman.controlsdk.streaming.factories.VideoProcessorFactory
55
import org.btelman.controlsdk.streaming.models.ImageDataPacket
66
import org.btelman.controlsdk.streaming.models.StreamInfo
77
import org.btelman.controlsdk.streaming.video.processors.BaseVideoProcessor
8-
import org.btelman.controlsdk.streaming.video.processors.FFmpegVideoProcessor
8+
import org.btelman.controlsdk.streaming.video.processors.LegacyFFmpegVideoProcessor
99
import org.junit.Assert
1010
import org.junit.Test
1111
import org.junit.runner.RunWith
@@ -19,7 +19,7 @@ import org.junit.runner.RunWith
1919
class VideoProcessorFactoryAndroidTest {
2020
@Test
2121
fun findProcessorTest() {
22-
Assert.assertTrue(VideoProcessorFactory.findProcessor(Bundle()) is FFmpegVideoProcessor)
22+
Assert.assertTrue(VideoProcessorFactory.findProcessor(Bundle()) is LegacyFFmpegVideoProcessor)
2323

2424
val streamInfo = StreamInfo("http://example.com:3000") //testing default parameters. Should use either Camera1SurfaceTextureComponent or Camera2SurfaceTextureComponent
2525
//test custom class
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
2-
package="org.btelman.controlsdk.streaming">
2+
xmlns:tools="http://schemas.android.com/tools"
3+
package="org.btelman.controlsdk.streaming">
34
<uses-permission android:name="android.permission.CAMERA"/>
45
<uses-feature android:name="android.hardware.camera"/>
56
<uses-feature android:name="android.hardware.camera.autofocus"/>
7+
<uses-sdk tools:overrideLibrary="com.arthenica.mobileffmpeg"/>
68
</manifest>

0 commit comments

Comments
 (0)