diff --git a/app/build.gradle b/app/build.gradle index 796cfcc..166d246 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -13,6 +13,10 @@ targetSdkVersion 33 versionCode 1000 versionName "1.0.0.0" + + ndk { + abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64" + } } buildTypes { @@ -98,4 +102,6 @@ implementation 'org.greenrobot:greendao:3.3.0' //数据库升级 implementation 'io.github.yuweiguocn:GreenDaoUpgradeHelper:v2.2.1' + //ffmpeg + implementation 'com.github.microshow:RxFFmpeg:4.9.0' } \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 796cfcc..166d246 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -13,6 +13,10 @@ targetSdkVersion 33 versionCode 1000 versionName "1.0.0.0" + + ndk { + abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64" + } } buildTypes { @@ -98,4 +102,6 @@ implementation 'org.greenrobot:greendao:3.3.0' //数据库升级 implementation 'io.github.yuweiguocn:GreenDaoUpgradeHelper:v2.2.1' + //ffmpeg + implementation 'com.github.microshow:RxFFmpeg:4.9.0' } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b4fb060..6dc1bff 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -38,5 +38,9 @@ android:name=".view.BigImageActivity" android:screenOrientation="landscape" android:theme="@style/Theme.BigImageActivity" /> + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 796cfcc..166d246 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -13,6 +13,10 @@ targetSdkVersion 33 versionCode 1000 versionName "1.0.0.0" + + ndk { + abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64" + } } buildTypes { @@ -98,4 +102,6 @@ implementation 'org.greenrobot:greendao:3.3.0' //数据库升级 implementation 'io.github.yuweiguocn:GreenDaoUpgradeHelper:v2.2.1' + //ffmpeg + implementation 'com.github.microshow:RxFFmpeg:4.9.0' } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b4fb060..6dc1bff 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -38,5 +38,9 @@ android:name=".view.BigImageActivity" android:screenOrientation="landscape" android:theme="@style/Theme.BigImageActivity" /> + + \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt b/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt index 9643a69..6f48798 100644 --- a/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt +++ b/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt @@ -35,7 +35,9 @@ //根据不同的日期显示不同的改日期下的九宫格形式子文件 val videoDir = File(context.getExternalFilesDir(Environment.DIRECTORY_MOVIES), date) videoDir.listFiles()?.forEach { - fileBeans.add(it) + if (it.name.startsWith("t")) { + fileBeans.add(it) + } } val imageDir = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), date) diff --git a/app/build.gradle b/app/build.gradle index 796cfcc..166d246 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -13,6 +13,10 @@ targetSdkVersion 33 versionCode 1000 versionName "1.0.0.0" + + ndk { + abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64" + } } buildTypes { @@ -98,4 +102,6 @@ implementation 'org.greenrobot:greendao:3.3.0' //数据库升级 implementation 'io.github.yuweiguocn:GreenDaoUpgradeHelper:v2.2.1' + //ffmpeg + implementation 'com.github.microshow:RxFFmpeg:4.9.0' } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b4fb060..6dc1bff 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -38,5 +38,9 @@ android:name=".view.BigImageActivity" android:screenOrientation="landscape" android:theme="@style/Theme.BigImageActivity" /> + + \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt b/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt index 9643a69..6f48798 100644 --- a/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt +++ b/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt @@ -35,7 +35,9 @@ //根据不同的日期显示不同的改日期下的九宫格形式子文件 val videoDir = File(context.getExternalFilesDir(Environment.DIRECTORY_MOVIES), date) videoDir.listFiles()?.forEach { - fileBeans.add(it) + if (it.name.startsWith("t")) { + fileBeans.add(it) + } } val imageDir = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), date) diff --git a/app/src/main/java/com/casic/endoscope/base/BaseApplication.kt b/app/src/main/java/com/casic/endoscope/base/BaseApplication.kt index 6439217..21cc4f5 100644 --- a/app/src/main/java/com/casic/endoscope/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/endoscope/base/BaseApplication.kt @@ -5,6 +5,7 @@ import com.casic.endoscope.greendao.DaoSession import com.casic.endoscope.utils.EndoscopeDevOpenHelper import com.pengxh.kt.lite.utils.SaveKeyValues +import io.microshow.rxffmpeg.RxFFmpegInvoke import kotlin.properties.Delegates class BaseApplication : Application() { @@ -24,6 +25,7 @@ application = this SaveKeyValues.initSharedPreferences(this) initDataBase() + RxFFmpegInvoke.getInstance().setDebug(false) } private fun initDataBase() { diff --git a/app/build.gradle b/app/build.gradle index 796cfcc..166d246 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -13,6 +13,10 @@ targetSdkVersion 33 versionCode 1000 versionName "1.0.0.0" + + ndk { + abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64" + } } buildTypes { @@ -98,4 +102,6 @@ implementation 'org.greenrobot:greendao:3.3.0' //数据库升级 implementation 'io.github.yuweiguocn:GreenDaoUpgradeHelper:v2.2.1' + //ffmpeg + implementation 'com.github.microshow:RxFFmpeg:4.9.0' } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b4fb060..6dc1bff 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -38,5 +38,9 @@ android:name=".view.BigImageActivity" android:screenOrientation="landscape" android:theme="@style/Theme.BigImageActivity" /> + + \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt b/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt index 9643a69..6f48798 100644 --- a/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt +++ b/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt @@ -35,7 +35,9 @@ //根据不同的日期显示不同的改日期下的九宫格形式子文件 val videoDir = File(context.getExternalFilesDir(Environment.DIRECTORY_MOVIES), date) videoDir.listFiles()?.forEach { - fileBeans.add(it) + if (it.name.startsWith("t")) { + fileBeans.add(it) + } } val imageDir = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), date) diff --git a/app/src/main/java/com/casic/endoscope/base/BaseApplication.kt b/app/src/main/java/com/casic/endoscope/base/BaseApplication.kt index 6439217..21cc4f5 100644 --- a/app/src/main/java/com/casic/endoscope/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/endoscope/base/BaseApplication.kt @@ -5,6 +5,7 @@ import com.casic.endoscope.greendao.DaoSession import com.casic.endoscope.utils.EndoscopeDevOpenHelper import com.pengxh.kt.lite.utils.SaveKeyValues +import io.microshow.rxffmpeg.RxFFmpegInvoke import kotlin.properties.Delegates class BaseApplication : Application() { @@ -24,6 +25,7 @@ application = this SaveKeyValues.initSharedPreferences(this) initDataBase() + RxFFmpegInvoke.getInstance().setDebug(false) } private fun initDataBase() { diff --git a/app/src/main/java/com/casic/endoscope/service/VideoTranscodeService.kt b/app/src/main/java/com/casic/endoscope/service/VideoTranscodeService.kt new file mode 100644 index 0000000..ff353d3 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/service/VideoTranscodeService.kt @@ -0,0 +1,82 @@ +package com.casic.endoscope.service + +import android.app.Service +import android.content.Intent +import android.os.IBinder +import android.util.Log +import com.casic.endoscope.utils.FFmpegCommandHub +import com.casic.endoscope.utils.ProjectConstant +import com.pengxh.kt.lite.extensions.createLogFile +import com.pengxh.kt.lite.extensions.writeToFile +import io.microshow.rxffmpeg.RxFFmpegInvoke +import io.microshow.rxffmpeg.RxFFmpegSubscriber +import java.util.Timer +import java.util.TimerTask + +class VideoTranscodeService : Service() { + + private val kTag = "VideoTranscodeService" + + override fun onBind(intent: Intent?): IBinder? { + return null + } + + override fun onCreate() { + super.onCreate() + Log.d(kTag, "onCreate => ") + } + + + /** + * 执行该方法后,Service 会启动并在后台无限期执行 + * 需要调用 stopSelf() 或 stopService() 来结束Service + * */ + override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + //定时遍历缓存,看是否有新的视频被录制 + Timer().schedule(object : TimerTask() { + override fun run() { + if (ProjectConstant.VIDEO_PATH_STACK.isNotEmpty()) { + transcodeVideo(ProjectConstant.VIDEO_PATH_STACK.pop()) + } + } + }, 0, 1000) + return START_NOT_STICKY + } + + //开始后台转码 + private fun transcodeVideo(inputPath: String) { + /** + * //storage/emulated/0/Android/data/com.casic.endoscope/files/Movies/2024-02-21/20240221161555.mp4 + * */ + val lastIndex = inputPath.lastIndexOf("/") + val fileName = inputPath.drop(lastIndex + 1) + //文件名前面+t + val newFileName = fileName.reversed().plus("t").reversed() + val outputPath = inputPath.replace(fileName, newFileName) + + RxFFmpegInvoke.getInstance() + .runCommandRxJava(FFmpegCommandHub.createVideoTranscodeCommand(inputPath, outputPath)) + .subscribe(object : RxFFmpegSubscriber() { + override fun onError(message: String?) { + message?.writeToFile(createLogFile()) + } + + override fun onFinish() { + Log.d(kTag, "onFinish => $outputPath 转码完成") + } + + override fun onProgress(progress: Int, progressTime: Long) { + Log.d(kTag, "onProgress => $progress") + } + + override fun onCancel() { + + } + }) + } + + override fun onDestroy() { + super.onDestroy() + Log.d(kTag, "onDestroy => ") + } +} \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 796cfcc..166d246 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -13,6 +13,10 @@ targetSdkVersion 33 versionCode 1000 versionName "1.0.0.0" + + ndk { + abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64" + } } buildTypes { @@ -98,4 +102,6 @@ implementation 'org.greenrobot:greendao:3.3.0' //数据库升级 implementation 'io.github.yuweiguocn:GreenDaoUpgradeHelper:v2.2.1' + //ffmpeg + implementation 'com.github.microshow:RxFFmpeg:4.9.0' } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b4fb060..6dc1bff 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -38,5 +38,9 @@ android:name=".view.BigImageActivity" android:screenOrientation="landscape" android:theme="@style/Theme.BigImageActivity" /> + + \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt b/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt index 9643a69..6f48798 100644 --- a/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt +++ b/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt @@ -35,7 +35,9 @@ //根据不同的日期显示不同的改日期下的九宫格形式子文件 val videoDir = File(context.getExternalFilesDir(Environment.DIRECTORY_MOVIES), date) videoDir.listFiles()?.forEach { - fileBeans.add(it) + if (it.name.startsWith("t")) { + fileBeans.add(it) + } } val imageDir = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), date) diff --git a/app/src/main/java/com/casic/endoscope/base/BaseApplication.kt b/app/src/main/java/com/casic/endoscope/base/BaseApplication.kt index 6439217..21cc4f5 100644 --- a/app/src/main/java/com/casic/endoscope/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/endoscope/base/BaseApplication.kt @@ -5,6 +5,7 @@ import com.casic.endoscope.greendao.DaoSession import com.casic.endoscope.utils.EndoscopeDevOpenHelper import com.pengxh.kt.lite.utils.SaveKeyValues +import io.microshow.rxffmpeg.RxFFmpegInvoke import kotlin.properties.Delegates class BaseApplication : Application() { @@ -24,6 +25,7 @@ application = this SaveKeyValues.initSharedPreferences(this) initDataBase() + RxFFmpegInvoke.getInstance().setDebug(false) } private fun initDataBase() { diff --git a/app/src/main/java/com/casic/endoscope/service/VideoTranscodeService.kt b/app/src/main/java/com/casic/endoscope/service/VideoTranscodeService.kt new file mode 100644 index 0000000..ff353d3 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/service/VideoTranscodeService.kt @@ -0,0 +1,82 @@ +package com.casic.endoscope.service + +import android.app.Service +import android.content.Intent +import android.os.IBinder +import android.util.Log +import com.casic.endoscope.utils.FFmpegCommandHub +import com.casic.endoscope.utils.ProjectConstant +import com.pengxh.kt.lite.extensions.createLogFile +import com.pengxh.kt.lite.extensions.writeToFile +import io.microshow.rxffmpeg.RxFFmpegInvoke +import io.microshow.rxffmpeg.RxFFmpegSubscriber +import java.util.Timer +import java.util.TimerTask + +class VideoTranscodeService : Service() { + + private val kTag = "VideoTranscodeService" + + override fun onBind(intent: Intent?): IBinder? { + return null + } + + override fun onCreate() { + super.onCreate() + Log.d(kTag, "onCreate => ") + } + + + /** + * 执行该方法后,Service 会启动并在后台无限期执行 + * 需要调用 stopSelf() 或 stopService() 来结束Service + * */ + override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + //定时遍历缓存,看是否有新的视频被录制 + Timer().schedule(object : TimerTask() { + override fun run() { + if (ProjectConstant.VIDEO_PATH_STACK.isNotEmpty()) { + transcodeVideo(ProjectConstant.VIDEO_PATH_STACK.pop()) + } + } + }, 0, 1000) + return START_NOT_STICKY + } + + //开始后台转码 + private fun transcodeVideo(inputPath: String) { + /** + * //storage/emulated/0/Android/data/com.casic.endoscope/files/Movies/2024-02-21/20240221161555.mp4 + * */ + val lastIndex = inputPath.lastIndexOf("/") + val fileName = inputPath.drop(lastIndex + 1) + //文件名前面+t + val newFileName = fileName.reversed().plus("t").reversed() + val outputPath = inputPath.replace(fileName, newFileName) + + RxFFmpegInvoke.getInstance() + .runCommandRxJava(FFmpegCommandHub.createVideoTranscodeCommand(inputPath, outputPath)) + .subscribe(object : RxFFmpegSubscriber() { + override fun onError(message: String?) { + message?.writeToFile(createLogFile()) + } + + override fun onFinish() { + Log.d(kTag, "onFinish => $outputPath 转码完成") + } + + override fun onProgress(progress: Int, progressTime: Long) { + Log.d(kTag, "onProgress => $progress") + } + + override fun onCancel() { + + } + }) + } + + override fun onDestroy() { + super.onDestroy() + Log.d(kTag, "onDestroy => ") + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/utils/FFmpegCommandHub.kt b/app/src/main/java/com/casic/endoscope/utils/FFmpegCommandHub.kt new file mode 100644 index 0000000..128fbd8 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/utils/FFmpegCommandHub.kt @@ -0,0 +1,19 @@ +package com.casic.endoscope.utils + +import io.microshow.rxffmpeg.RxFFmpegCommandList + +object FFmpegCommandHub { + + /** + * 海康视频转码指令 + * */ + fun createVideoTranscodeCommand(inputFilePath: String, outputFilePath: String): Array { + val commandParams = RxFFmpegCommandList() + commandParams.append("-i") + commandParams.append(inputFilePath) + commandParams.append("-c:v") + commandParams.append("libx264") + commandParams.append(outputFilePath) + return commandParams.build() + } +} \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 796cfcc..166d246 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -13,6 +13,10 @@ targetSdkVersion 33 versionCode 1000 versionName "1.0.0.0" + + ndk { + abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64" + } } buildTypes { @@ -98,4 +102,6 @@ implementation 'org.greenrobot:greendao:3.3.0' //数据库升级 implementation 'io.github.yuweiguocn:GreenDaoUpgradeHelper:v2.2.1' + //ffmpeg + implementation 'com.github.microshow:RxFFmpeg:4.9.0' } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b4fb060..6dc1bff 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -38,5 +38,9 @@ android:name=".view.BigImageActivity" android:screenOrientation="landscape" android:theme="@style/Theme.BigImageActivity" /> + + \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt b/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt index 9643a69..6f48798 100644 --- a/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt +++ b/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt @@ -35,7 +35,9 @@ //根据不同的日期显示不同的改日期下的九宫格形式子文件 val videoDir = File(context.getExternalFilesDir(Environment.DIRECTORY_MOVIES), date) videoDir.listFiles()?.forEach { - fileBeans.add(it) + if (it.name.startsWith("t")) { + fileBeans.add(it) + } } val imageDir = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), date) diff --git a/app/src/main/java/com/casic/endoscope/base/BaseApplication.kt b/app/src/main/java/com/casic/endoscope/base/BaseApplication.kt index 6439217..21cc4f5 100644 --- a/app/src/main/java/com/casic/endoscope/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/endoscope/base/BaseApplication.kt @@ -5,6 +5,7 @@ import com.casic.endoscope.greendao.DaoSession import com.casic.endoscope.utils.EndoscopeDevOpenHelper import com.pengxh.kt.lite.utils.SaveKeyValues +import io.microshow.rxffmpeg.RxFFmpegInvoke import kotlin.properties.Delegates class BaseApplication : Application() { @@ -24,6 +25,7 @@ application = this SaveKeyValues.initSharedPreferences(this) initDataBase() + RxFFmpegInvoke.getInstance().setDebug(false) } private fun initDataBase() { diff --git a/app/src/main/java/com/casic/endoscope/service/VideoTranscodeService.kt b/app/src/main/java/com/casic/endoscope/service/VideoTranscodeService.kt new file mode 100644 index 0000000..ff353d3 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/service/VideoTranscodeService.kt @@ -0,0 +1,82 @@ +package com.casic.endoscope.service + +import android.app.Service +import android.content.Intent +import android.os.IBinder +import android.util.Log +import com.casic.endoscope.utils.FFmpegCommandHub +import com.casic.endoscope.utils.ProjectConstant +import com.pengxh.kt.lite.extensions.createLogFile +import com.pengxh.kt.lite.extensions.writeToFile +import io.microshow.rxffmpeg.RxFFmpegInvoke +import io.microshow.rxffmpeg.RxFFmpegSubscriber +import java.util.Timer +import java.util.TimerTask + +class VideoTranscodeService : Service() { + + private val kTag = "VideoTranscodeService" + + override fun onBind(intent: Intent?): IBinder? { + return null + } + + override fun onCreate() { + super.onCreate() + Log.d(kTag, "onCreate => ") + } + + + /** + * 执行该方法后,Service 会启动并在后台无限期执行 + * 需要调用 stopSelf() 或 stopService() 来结束Service + * */ + override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + //定时遍历缓存,看是否有新的视频被录制 + Timer().schedule(object : TimerTask() { + override fun run() { + if (ProjectConstant.VIDEO_PATH_STACK.isNotEmpty()) { + transcodeVideo(ProjectConstant.VIDEO_PATH_STACK.pop()) + } + } + }, 0, 1000) + return START_NOT_STICKY + } + + //开始后台转码 + private fun transcodeVideo(inputPath: String) { + /** + * //storage/emulated/0/Android/data/com.casic.endoscope/files/Movies/2024-02-21/20240221161555.mp4 + * */ + val lastIndex = inputPath.lastIndexOf("/") + val fileName = inputPath.drop(lastIndex + 1) + //文件名前面+t + val newFileName = fileName.reversed().plus("t").reversed() + val outputPath = inputPath.replace(fileName, newFileName) + + RxFFmpegInvoke.getInstance() + .runCommandRxJava(FFmpegCommandHub.createVideoTranscodeCommand(inputPath, outputPath)) + .subscribe(object : RxFFmpegSubscriber() { + override fun onError(message: String?) { + message?.writeToFile(createLogFile()) + } + + override fun onFinish() { + Log.d(kTag, "onFinish => $outputPath 转码完成") + } + + override fun onProgress(progress: Int, progressTime: Long) { + Log.d(kTag, "onProgress => $progress") + } + + override fun onCancel() { + + } + }) + } + + override fun onDestroy() { + super.onDestroy() + Log.d(kTag, "onDestroy => ") + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/utils/FFmpegCommandHub.kt b/app/src/main/java/com/casic/endoscope/utils/FFmpegCommandHub.kt new file mode 100644 index 0000000..128fbd8 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/utils/FFmpegCommandHub.kt @@ -0,0 +1,19 @@ +package com.casic.endoscope.utils + +import io.microshow.rxffmpeg.RxFFmpegCommandList + +object FFmpegCommandHub { + + /** + * 海康视频转码指令 + * */ + fun createVideoTranscodeCommand(inputFilePath: String, outputFilePath: String): Array { + val commandParams = RxFFmpegCommandList() + commandParams.append("-i") + commandParams.append(inputFilePath) + commandParams.append("-c:v") + commandParams.append("libx264") + commandParams.append(outputFilePath) + return commandParams.build() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/utils/ProjectConstant.kt b/app/src/main/java/com/casic/endoscope/utils/ProjectConstant.kt index 1db0579..6c561a8 100644 --- a/app/src/main/java/com/casic/endoscope/utils/ProjectConstant.kt +++ b/app/src/main/java/com/casic/endoscope/utils/ProjectConstant.kt @@ -1,9 +1,14 @@ package com.casic.endoscope.utils +import java.util.Stack + object ProjectConstant { //海康摄像头参数 const val HK_NET_IP = "192.168.43.121" const val HK_NET_PORT = "8000" const val HK_NET_USERNAME = "admin" const val HK_NET_PASSWORD = "casic203" + + //待转码视频路径 + val VIDEO_PATH_STACK = Stack() } \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 796cfcc..166d246 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -13,6 +13,10 @@ targetSdkVersion 33 versionCode 1000 versionName "1.0.0.0" + + ndk { + abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64" + } } buildTypes { @@ -98,4 +102,6 @@ implementation 'org.greenrobot:greendao:3.3.0' //数据库升级 implementation 'io.github.yuweiguocn:GreenDaoUpgradeHelper:v2.2.1' + //ffmpeg + implementation 'com.github.microshow:RxFFmpeg:4.9.0' } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b4fb060..6dc1bff 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -38,5 +38,9 @@ android:name=".view.BigImageActivity" android:screenOrientation="landscape" android:theme="@style/Theme.BigImageActivity" /> + + \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt b/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt index 9643a69..6f48798 100644 --- a/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt +++ b/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt @@ -35,7 +35,9 @@ //根据不同的日期显示不同的改日期下的九宫格形式子文件 val videoDir = File(context.getExternalFilesDir(Environment.DIRECTORY_MOVIES), date) videoDir.listFiles()?.forEach { - fileBeans.add(it) + if (it.name.startsWith("t")) { + fileBeans.add(it) + } } val imageDir = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), date) diff --git a/app/src/main/java/com/casic/endoscope/base/BaseApplication.kt b/app/src/main/java/com/casic/endoscope/base/BaseApplication.kt index 6439217..21cc4f5 100644 --- a/app/src/main/java/com/casic/endoscope/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/endoscope/base/BaseApplication.kt @@ -5,6 +5,7 @@ import com.casic.endoscope.greendao.DaoSession import com.casic.endoscope.utils.EndoscopeDevOpenHelper import com.pengxh.kt.lite.utils.SaveKeyValues +import io.microshow.rxffmpeg.RxFFmpegInvoke import kotlin.properties.Delegates class BaseApplication : Application() { @@ -24,6 +25,7 @@ application = this SaveKeyValues.initSharedPreferences(this) initDataBase() + RxFFmpegInvoke.getInstance().setDebug(false) } private fun initDataBase() { diff --git a/app/src/main/java/com/casic/endoscope/service/VideoTranscodeService.kt b/app/src/main/java/com/casic/endoscope/service/VideoTranscodeService.kt new file mode 100644 index 0000000..ff353d3 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/service/VideoTranscodeService.kt @@ -0,0 +1,82 @@ +package com.casic.endoscope.service + +import android.app.Service +import android.content.Intent +import android.os.IBinder +import android.util.Log +import com.casic.endoscope.utils.FFmpegCommandHub +import com.casic.endoscope.utils.ProjectConstant +import com.pengxh.kt.lite.extensions.createLogFile +import com.pengxh.kt.lite.extensions.writeToFile +import io.microshow.rxffmpeg.RxFFmpegInvoke +import io.microshow.rxffmpeg.RxFFmpegSubscriber +import java.util.Timer +import java.util.TimerTask + +class VideoTranscodeService : Service() { + + private val kTag = "VideoTranscodeService" + + override fun onBind(intent: Intent?): IBinder? { + return null + } + + override fun onCreate() { + super.onCreate() + Log.d(kTag, "onCreate => ") + } + + + /** + * 执行该方法后,Service 会启动并在后台无限期执行 + * 需要调用 stopSelf() 或 stopService() 来结束Service + * */ + override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + //定时遍历缓存,看是否有新的视频被录制 + Timer().schedule(object : TimerTask() { + override fun run() { + if (ProjectConstant.VIDEO_PATH_STACK.isNotEmpty()) { + transcodeVideo(ProjectConstant.VIDEO_PATH_STACK.pop()) + } + } + }, 0, 1000) + return START_NOT_STICKY + } + + //开始后台转码 + private fun transcodeVideo(inputPath: String) { + /** + * //storage/emulated/0/Android/data/com.casic.endoscope/files/Movies/2024-02-21/20240221161555.mp4 + * */ + val lastIndex = inputPath.lastIndexOf("/") + val fileName = inputPath.drop(lastIndex + 1) + //文件名前面+t + val newFileName = fileName.reversed().plus("t").reversed() + val outputPath = inputPath.replace(fileName, newFileName) + + RxFFmpegInvoke.getInstance() + .runCommandRxJava(FFmpegCommandHub.createVideoTranscodeCommand(inputPath, outputPath)) + .subscribe(object : RxFFmpegSubscriber() { + override fun onError(message: String?) { + message?.writeToFile(createLogFile()) + } + + override fun onFinish() { + Log.d(kTag, "onFinish => $outputPath 转码完成") + } + + override fun onProgress(progress: Int, progressTime: Long) { + Log.d(kTag, "onProgress => $progress") + } + + override fun onCancel() { + + } + }) + } + + override fun onDestroy() { + super.onDestroy() + Log.d(kTag, "onDestroy => ") + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/utils/FFmpegCommandHub.kt b/app/src/main/java/com/casic/endoscope/utils/FFmpegCommandHub.kt new file mode 100644 index 0000000..128fbd8 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/utils/FFmpegCommandHub.kt @@ -0,0 +1,19 @@ +package com.casic.endoscope.utils + +import io.microshow.rxffmpeg.RxFFmpegCommandList + +object FFmpegCommandHub { + + /** + * 海康视频转码指令 + * */ + fun createVideoTranscodeCommand(inputFilePath: String, outputFilePath: String): Array { + val commandParams = RxFFmpegCommandList() + commandParams.append("-i") + commandParams.append(inputFilePath) + commandParams.append("-c:v") + commandParams.append("libx264") + commandParams.append(outputFilePath) + return commandParams.build() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/utils/ProjectConstant.kt b/app/src/main/java/com/casic/endoscope/utils/ProjectConstant.kt index 1db0579..6c561a8 100644 --- a/app/src/main/java/com/casic/endoscope/utils/ProjectConstant.kt +++ b/app/src/main/java/com/casic/endoscope/utils/ProjectConstant.kt @@ -1,9 +1,14 @@ package com.casic.endoscope.utils +import java.util.Stack + object ProjectConstant { //海康摄像头参数 const val HK_NET_IP = "192.168.43.121" const val HK_NET_PORT = "8000" const val HK_NET_USERNAME = "admin" const val HK_NET_PASSWORD = "casic203" + + //待转码视频路径 + val VIDEO_PATH_STACK = Stack() } \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/view/MainActivity.kt b/app/src/main/java/com/casic/endoscope/view/MainActivity.kt index 37ce0b4..0a65486 100644 --- a/app/src/main/java/com/casic/endoscope/view/MainActivity.kt +++ b/app/src/main/java/com/casic/endoscope/view/MainActivity.kt @@ -1,6 +1,7 @@ package com.casic.endoscope.view import android.annotation.SuppressLint +import android.content.Intent import android.graphics.PixelFormat import android.os.Bundle import android.os.Handler @@ -20,6 +21,7 @@ import com.casic.endoscope.extensions.createVideoFileDir import com.casic.endoscope.extensions.getChannel import com.casic.endoscope.extensions.toTime +import com.casic.endoscope.service.VideoTranscodeService import com.casic.endoscope.utils.DataBaseManager import com.casic.endoscope.utils.ProjectConstant import com.casic.endoscope.utils.hk.MessageCodeHub @@ -46,6 +48,7 @@ import java.util.Timer import java.util.TimerTask + @SuppressLint("all") class MainActivity : KotlinBaseActivity(), SurfaceHolder.Callback, Handler.Callback { @@ -80,8 +83,10 @@ private var seconds = 0L private var dataBeans: MutableList = ArrayList() private var selectedItems: MutableList = ArrayList() + private var inputVideoPath = "" private lateinit var weakReferenceHandler: WeakReferenceHandler private lateinit var dataAdapter: CameraPointAdapter + private lateinit var serviceIntent: Intent override fun initViewBinding(): ActivityMainBinding { return ActivityMainBinding.inflate(layoutInflater) @@ -94,6 +99,16 @@ //显示数据 weakReferenceHandler.sendEmptyMessage(messageCode) + +// ProjectConstant.VIDEO_PATH_STACK.push("/storage/self/primary/Android/data/com.casic.endoscope/files/Movies/2024-02-20/20240220113648.mp4") + + serviceIntent = Intent(this, VideoTranscodeService::class.java) + } + + override fun onResume() { + super.onResume() + //启动视频转码服务 + startService(serviceIntent) } override fun handleMessage(msg: Message): Boolean { @@ -145,8 +160,8 @@ //视频录制 binding.videoButton.setOnClickListener { if (isPreviewSuccess) { - val videoPath = "/${createVideoFileDir()}/${timeFormat.format(Date())}.mp4" - hkSDK.NET_DVR_SaveRealData(returnUserId, videoPath) + inputVideoPath = "/${createVideoFileDir()}/${timeFormat.format(Date())}.mp4" + hkSDK.NET_DVR_SaveRealData(returnUserId, inputVideoPath) binding.videoStateView.visibility = View.VISIBLE } else { "摄像头预览未打开,无法录制视频".show(this) @@ -157,6 +172,7 @@ //停止视频抓取 hkSDK.NET_DVR_StopSaveRealData(returnUserId) binding.videoStateView.visibility = View.INVISIBLE + ProjectConstant.VIDEO_PATH_STACK.push(inputVideoPath) "视频录制成功".show(this) true } @@ -528,6 +544,7 @@ override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean { if (keyCode == KeyEvent.KEYCODE_BACK) { if (System.currentTimeMillis() - clickTime > 2000) { + stopService(serviceIntent) "再按一次退出应用".show(this) clickTime = System.currentTimeMillis() return true