diff --git a/AndroidMedia/src/main/java/com/frank/androidmedia/controller/AudioTrackController.kt b/AndroidMedia/src/main/java/com/frank/androidmedia/controller/AudioTrackController.kt index 5d19198..80dcadc 100644 --- a/AndroidMedia/src/main/java/com/frank/androidmedia/controller/AudioTrackController.kt +++ b/AndroidMedia/src/main/java/com/frank/androidmedia/controller/AudioTrackController.kt @@ -49,7 +49,7 @@ open class AudioTrackController { private fun initMediaCodec(mediaFormat: MediaFormat): Boolean { val mimeType = mediaFormat.getString(MediaFormat.KEY_MIME) - mediaCodec = MediaCodec.createDecoderByType(mimeType) + mediaCodec = MediaCodec.createDecoderByType(mimeType.toString()) return try { mediaCodec!!.configure(mediaFormat, null, null, 0) mediaCodec!!.start() diff --git a/AndroidMedia/src/main/java/com/frank/androidmedia/controller/MediaMetadataController.kt b/AndroidMedia/src/main/java/com/frank/androidmedia/controller/MediaMetadataController.kt index 6a0dc6a..9843c44 100644 --- a/AndroidMedia/src/main/java/com/frank/androidmedia/controller/MediaMetadataController.kt +++ b/AndroidMedia/src/main/java/com/frank/androidmedia/controller/MediaMetadataController.kt @@ -57,7 +57,9 @@ open class MediaMetadataController { try { if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) { val frameRateStr = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_CAPTURE_FRAMERATE) - frameRate = frameRateStr.toFloat() + if (frameRateStr != null) { + frameRate = frameRateStr.toFloat() + } Log.i(TAG, "frameRate=$frameRate") } } catch (e: Exception) { @@ -69,7 +71,9 @@ open class MediaMetadataController { thumbnail = retriever.getFrameAtTime(0) } else if (hasAudioStr != null && "yes" == hasAudioStr) { val byteArray = retriever.embeddedPicture - thumbnail = BitmapFactory.decodeByteArray(byteArray, 0, byteArray.size, null) + if (byteArray != null) { + thumbnail = BitmapFactory.decodeByteArray(byteArray, 0, byteArray.size, null) + } } if (thumbnail != null) { Log.i(TAG, "thumbnail width=${thumbnail?.width}, height=${thumbnail?.height}") diff --git a/AndroidMedia/src/main/java/com/frank/androidmedia/util/WavUtil.kt b/AndroidMedia/src/main/java/com/frank/androidmedia/util/WavUtil.kt index 58de8db..d4d1d42 100644 --- a/AndroidMedia/src/main/java/com/frank/androidmedia/util/WavUtil.kt +++ b/AndroidMedia/src/main/java/com/frank/androidmedia/util/WavUtil.kt @@ -31,7 +31,7 @@ object WavUtil { val h: ByteArray = try { header.header } catch (e1: IOException) { - Log.e("WavUtil", e1.message) + Log.e("WavUtil", e1.message.toString()) return false } if (h.size != 44) return false @@ -52,7 +52,7 @@ object WavUtil { inStream.close() ouStream.close() } catch (e: IOException) { - Log.e("WavUtil", e.message) + Log.e("WavUtil", e.message.toString()) return false } if (deletePcmFile) { diff --git a/app/build.gradle b/app/build.gradle index 51cd81d..19ecd52 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -20,6 +20,9 @@ android { ndk { abiFilters "armeabi-v7a", "arm64-v8a" } + vectorDrawables { + useSupportLibrary true + } } buildTypes { release { @@ -51,6 +54,21 @@ android { pickFirst 'lib/arm64-v8a/libmp3lame.so' pickFirst 'lib/armeabi-v7a/libffmpeg.so' pickFirst 'lib/arm64-v8a/libffmpeg.so' + resources { + excludes += '/META-INF/{AL2.0,LGPL2.1}' + } + } + kotlinOptions { + jvmTarget = '1.8' + } + buildFeatures { + compose true + } + buildFeatures { + compose true + } + composeOptions { + kotlinCompilerExtensionVersion compose_version } } @@ -65,4 +83,30 @@ dependencies { implementation project(':AndroidMedia') //implementation "libmp3" if you need mp3-lite module // implementation project(':libmp3') + + + // compose start + implementation 'androidx.compose.ui:ui:1.1.1' + // Tooling support (Previews, etc.) + implementation 'androidx.compose.ui:ui-tooling:1.1.1' + // Foundation (Border, Background, Box, Image, Scroll, shapes, animations, etc.) + implementation 'androidx.compose.foundation:foundation:1.1.1' + // Material Design + implementation 'androidx.compose.material:material:1.1.1' + // Material design icons + implementation 'androidx.compose.material:material-icons-core:1.1.1' + implementation 'androidx.compose.material:material-icons-extended:1.1.1' + // Integration with activities + implementation 'androidx.activity:activity-compose:1.4.0' + // Integration with ViewModels + implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.4.1' + // Integration with observables + implementation 'androidx.compose.runtime:runtime-livedata:1.1.1' + implementation 'androidx.compose.runtime:runtime-rxjava2:1.1.1' + implementation "androidx.compose.ui:ui-tooling-preview:$compose_version" + implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1' + + // UI Tests + androidTestImplementation 'androidx.compose.ui:ui-test-junit4:1.1.1' + // compose end } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index eb4b9e4..cc94e53 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -3,17 +3,6 @@ xmlns:tools="http://schemas.android.com/tools" package="com.frank.ffmpeg"> - - - - - - - - - - - - - + + @@ -47,5 +40,16 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/frank/ffmpeg/activity/AudioPlayActivity.kt b/app/src/main/java/com/frank/ffmpeg/activity/AudioPlayActivity.kt index 2943b73..f2d8fe8 100644 --- a/app/src/main/java/com/frank/ffmpeg/activity/AudioPlayActivity.kt +++ b/app/src/main/java/com/frank/ffmpeg/activity/AudioPlayActivity.kt @@ -48,7 +48,7 @@ class AudioPlayActivity : AppCompatActivity() { private val mHandler: Handler = @SuppressLint("HandlerLeak") object : Handler() { - override fun handleMessage(msg: Message?) { + override fun handleMessage(msg: Message) { super.handleMessage(msg) when (msg?.what) { MSG_TIME -> { diff --git a/app/src/main/java/com/frank/ffmpeg/activity/ComposeActivity.kt b/app/src/main/java/com/frank/ffmpeg/activity/ComposeActivity.kt new file mode 100644 index 0000000..1277842 --- /dev/null +++ b/app/src/main/java/com/frank/ffmpeg/activity/ComposeActivity.kt @@ -0,0 +1,43 @@ +package com.frank.ffmpeg.activity + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Surface +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import com.frank.ffmpeg.activity.ui.theme.FFmpegAndroidTheme + +class ComposeActivity : ComponentActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContent { + FFmpegAndroidTheme { + // A surface container using the 'background' color from the theme + Surface( + modifier = Modifier.fillMaxSize(), + color = MaterialTheme.colors.background + ) { + Greeting("Android") + } + } + } + } +} + +@Composable +fun Greeting(name: String) { + Text(text = "Hello $name!") +} + +@Preview(showBackground = true) +@Composable +fun DefaultPreview() { + FFmpegAndroidTheme { + Greeting("Android") + } +} \ No newline at end of file diff --git a/app/src/main/java/com/frank/ffmpeg/activity/FilterActivity.kt b/app/src/main/java/com/frank/ffmpeg/activity/FilterActivity.kt index 8feae3c..cb527de 100644 --- a/app/src/main/java/com/frank/ffmpeg/activity/FilterActivity.kt +++ b/app/src/main/java/com/frank/ffmpeg/activity/FilterActivity.kt @@ -87,7 +87,7 @@ class FilterActivity : BaseActivity(), SurfaceHolder.Callback { registerLister() hideRunnable = HideRunnable() - mHandler.postDelayed(hideRunnable, DELAY_TIME.toLong()) + mHandler.postDelayed(hideRunnable!!, DELAY_TIME.toLong()) } private fun initView() { @@ -126,7 +126,7 @@ class FilterActivity : BaseActivity(), SurfaceHolder.Callback { btnSelect!!.visibility = View.VISIBLE btnSound!!.visibility = View.VISIBLE recyclerView!!.visibility = View.VISIBLE - mHandler.postDelayed(hideRunnable, DELAY_TIME.toLong()) + hideRunnable?.let { it1 -> mHandler.postDelayed(it1, DELAY_TIME.toLong()) } } btnSound!!.setOnCheckedChangeListener { buttonView, isChecked -> setPlayAudio() } diff --git a/app/src/main/java/com/frank/ffmpeg/activity/LiveActivity.kt b/app/src/main/java/com/frank/ffmpeg/activity/LiveActivity.kt index 91f4e73..71377f9 100644 --- a/app/src/main/java/com/frank/ffmpeg/activity/LiveActivity.kt +++ b/app/src/main/java/com/frank/ffmpeg/activity/LiveActivity.kt @@ -16,6 +16,7 @@ import android.view.View import android.widget.CompoundButton import android.widget.Toast import android.widget.ToggleButton +import androidx.compose.runtime.Composable import com.frank.ffmpeg.R import com.frank.ffmpeg.handler.ConnectionReceiver diff --git a/app/src/main/java/com/frank/ffmpeg/activity/MainActivity.kt b/app/src/main/java/com/frank/ffmpeg/activity/MainActivity.kt index b1555e9..b93e076 100644 --- a/app/src/main/java/com/frank/ffmpeg/activity/MainActivity.kt +++ b/app/src/main/java/com/frank/ffmpeg/activity/MainActivity.kt @@ -27,15 +27,17 @@ class MainActivity : BaseActivity() { private fun initView() { val list = listOf( - getString(R.string.audio_handle), - getString(R.string.video_handle), - getString(R.string.media_handle), - getString(R.string.video_push), - getString(R.string.video_live), - getString(R.string.video_filter), - getString(R.string.video_preview), - getString(R.string.media_probe), - getString(R.string.audio_effect)) + getString(R.string.audio_handle), + getString(R.string.video_handle), + getString(R.string.media_handle), + getString(R.string.video_push), + getString(R.string.video_live), + getString(R.string.video_filter), + getString(R.string.video_preview), + getString(R.string.media_probe), + getString(R.string.audio_effect), + getString(R.string.compose) + ) val viewWaterfall: RecyclerView = findViewById(R.id.list_main_item) val layoutManager = StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL) @@ -71,6 +73,8 @@ class MainActivity : BaseActivity() { -> intent.setClass(this@MainActivity, ProbeFormatActivity::class.java) 8 //audio effect -> intent.setClass(this@MainActivity, AudioEffectActivity::class.java) + 9 + -> intent.setClass(this@MainActivity, ComposeActivity::class.java) else -> { } } diff --git a/app/src/main/java/com/frank/ffmpeg/activity/ui/theme/Color.kt b/app/src/main/java/com/frank/ffmpeg/activity/ui/theme/Color.kt new file mode 100644 index 0000000..6ce7984 --- /dev/null +++ b/app/src/main/java/com/frank/ffmpeg/activity/ui/theme/Color.kt @@ -0,0 +1,8 @@ +package com.frank.ffmpeg.activity.ui.theme + +import androidx.compose.ui.graphics.Color + +val Purple200 = Color(0xFFBB86FC) +val Purple500 = Color(0xFF6200EE) +val Purple700 = Color(0xFF3700B3) +val Teal200 = Color(0xFF03DAC5) \ No newline at end of file diff --git a/app/src/main/java/com/frank/ffmpeg/activity/ui/theme/Shape.kt b/app/src/main/java/com/frank/ffmpeg/activity/ui/theme/Shape.kt new file mode 100644 index 0000000..8db6171 --- /dev/null +++ b/app/src/main/java/com/frank/ffmpeg/activity/ui/theme/Shape.kt @@ -0,0 +1,11 @@ +package com.frank.ffmpeg.activity.ui.theme + +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Shapes +import androidx.compose.ui.unit.dp + +val Shapes = Shapes( + small = RoundedCornerShape(4.dp), + medium = RoundedCornerShape(4.dp), + large = RoundedCornerShape(0.dp) +) \ No newline at end of file diff --git a/app/src/main/java/com/frank/ffmpeg/activity/ui/theme/Theme.kt b/app/src/main/java/com/frank/ffmpeg/activity/ui/theme/Theme.kt new file mode 100644 index 0000000..08c845d --- /dev/null +++ b/app/src/main/java/com/frank/ffmpeg/activity/ui/theme/Theme.kt @@ -0,0 +1,47 @@ +package com.frank.ffmpeg.activity.ui.theme + +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material.MaterialTheme +import androidx.compose.material.darkColors +import androidx.compose.material.lightColors +import androidx.compose.runtime.Composable + +private val DarkColorPalette = darkColors( + primary = Purple200, + primaryVariant = Purple700, + secondary = Teal200 +) + +private val LightColorPalette = lightColors( + primary = Purple500, + primaryVariant = Purple700, + secondary = Teal200 + + /* Other default colors to override + background = Color.White, + surface = Color.White, + onPrimary = Color.White, + onSecondary = Color.Black, + onBackground = Color.Black, + onSurface = Color.Black, + */ +) + +@Composable +fun FFmpegAndroidTheme( + darkTheme: Boolean = isSystemInDarkTheme(), + content: @Composable () -> Unit +) { + val colors = if (darkTheme) { + DarkColorPalette + } else { + LightColorPalette + } + + MaterialTheme( + colors = colors, + typography = Typography, + shapes = Shapes, + content = content + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/frank/ffmpeg/activity/ui/theme/Type.kt b/app/src/main/java/com/frank/ffmpeg/activity/ui/theme/Type.kt new file mode 100644 index 0000000..ed31e5a --- /dev/null +++ b/app/src/main/java/com/frank/ffmpeg/activity/ui/theme/Type.kt @@ -0,0 +1,28 @@ +package com.frank.ffmpeg.activity.ui.theme + +import androidx.compose.material.Typography +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.sp + +// Set of Material typography styles to start with +val Typography = Typography( + body1 = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 16.sp + ) + /* Other default text styles to override + button = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.W500, + fontSize = 14.sp + ), + caption = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 12.sp + ) + */ +) \ No newline at end of file diff --git a/app/src/main/res/values-en/strings.xml b/app/src/main/res/values-en/strings.xml index be4a3d7..3bb7965 100644 --- a/app/src/main/res/values-en/strings.xml +++ b/app/src/main/res/values-en/strings.xml @@ -1,5 +1,6 @@ FFmpegAndroid + compose Audio transform Audio cut Audio concat diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9b49510..18deaa0 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,5 +1,6 @@ FFmpegAndroid + compose 音频转码 音频剪切 音频拼接 diff --git a/build.gradle b/build.gradle index dcf1b31..c080a5f 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,9 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { + ext { + compose_version = '1.0.1' + } ext.kotlin_version = '1.3.50' repositories { google() @@ -8,7 +11,7 @@ buildscript { } dependencies { classpath 'com.android.tools.build:gradle:7.1.3' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.21" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } @@ -26,10 +29,10 @@ task clean(type: Delete) { } ext { - compileSdkVersion = 28 - buildToolsVersion = '28.0.2' + compileSdkVersion = 31 + buildToolsVersion = '31.0.2' minSdkVersion = 21 - targetSdkVersion = 28 + targetSdkVersion = 31 versionCode = 103000 versionName = "1.3.0" } \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 6c948f6..ce55f21 100644 --- a/gradle.properties +++ b/gradle.properties @@ -15,7 +15,7 @@ # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true -org.gradle.jvmargs=-Xmx512m +org.gradle.jvmargs=-Xmx4096m android.enableJetifier=true android.useAndroidX=true diff --git a/libmp3/src/main/java/com/frank/mp3/Mp3Converter.kt b/libmp3/src/main/java/com/frank/mp3/Mp3Converter.kt index 8666b78..317c4a9 100644 --- a/libmp3/src/main/java/com/frank/mp3/Mp3Converter.kt +++ b/libmp3/src/main/java/com/frank/mp3/Mp3Converter.kt @@ -227,13 +227,15 @@ open class Mp3Converter { Log.i(TAG, "prepareDecode get mMediaFormat=$mMediaFormat") val mime = mMediaFormat.getString(MediaFormat.KEY_MIME) - if (mime.startsWith("audio")) { - mMediaCodec = MediaCodec.createDecoderByType(mime) - mMediaCodec!!.configure(mMediaFormat, null, null, 0) - mediaExtractor!!.selectTrack(i) - inSampleRate = mMediaFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE) - channels = mMediaFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT) - break + if (mime != null) { + if (mime.startsWith("audio")) { + mMediaCodec = MediaCodec.createDecoderByType(mime) + mMediaCodec!!.configure(mMediaFormat, null, null, 0) + mediaExtractor!!.selectTrack(i) + inSampleRate = mMediaFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE) + channels = mMediaFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT) + break + } } } mMediaCodec!!.start()