用JAVACV把圖片轉換成視訊在android上的實現
阿新 • • 發佈:2021-01-08
javacv下載連結
https://www.softpedia.com/get/Programming/Other-Programming-Files/JavaCV.shtml
javacpp下載連結
https://github.com/bytedeco/javacpp/releases
解壓後把以下jar包加入到專案
gradle
plugins { id 'com.android.application' id 'kotlin-android' } android { compileSdkVersion 30 buildToolsVersion "30.0.3" defaultConfig { applicationId "com.example.demo" minSdkVersion 18 targetSdkVersion 30 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" multiDexEnabled true ndk { // 設定支援的SO庫架構 abiFilters 'armeabi' , 'armeabi-v7a', 'arm64-v8a' // abiFilters 'armeabi-v7a' } } packagingOptions { exclude 'META-INF/native-image/android-arm/jnijavacpp/jni-config.json' exclude 'META-INF/native-image/android-arm/jnijavacpp/reflect-config.json' } repositories { flatDir { dirs 'libs' } } sourceSets{ main { //jni庫的呼叫會到資原始檔夾下libs裡面找so檔案 jniLibs.srcDirs = ['libs'] } } // packagingOptions { // exclude 'META-INF/native-image/ios-x86_64/jnijavacpp/' // } dataBinding { enabled = true } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } kotlinOptions { jvmTarget = '1.8' } } dependencies { implementation fileTree(dir: "libs", include: ["*.jar"]) implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" implementation 'androidx.core:core-ktx:1.2.0' implementation 'androidx.appcompat:appcompat:1.2.0' implementation 'com.google.android.material:material:1.2.1' implementation 'androidx.constraintlayout:constraintlayout:2.0.4' testImplementation 'junit:junit:4.+' androidTestImplementation 'androidx.test.ext:junit:1.1.2' androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' // implementation group: 'org.bytedeco', name: 'javacv-platform', version: '1.5.4' // implementation 'com.android.support:multidex:1.0.3' }
功能類:
import android.util.Log; import org.bytedeco.ffmpeg.global.avcodec; import org.bytedeco.ffmpeg.global.avutil; import org.bytedeco.javacv.FFmpegFrameRecorder; import org.bytedeco.javacv.Frame; import org.bytedeco.javacv.FrameRecorder; import org.bytedeco.javacv.Java2DFrameConverter; import java.io.File; import java.util.Map; import org.bytedeco.javacv.OpenCVFrameConverter; import org.bytedeco.opencv.opencv_core.IplImage; import static org.bytedeco.opencv.helper.opencv_imgcodecs.cvLoadImage; public class Utils { /** * 錄製成功監聽 */ public interface CompleteListener{ public void onComplete(String path); } public static void createMp4(String mp4SavePath, Map<Integer, File> imgMap, int width, int height,CompleteListener listener) throws FrameRecorder.Exception { //視訊寬高最好是按照常見的視訊的寬高 16:9 或者 9:16 FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(mp4SavePath, width, height); //設定視訊編碼層模式 recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264); //設定視訊為25幀每秒 recorder.setFrameRate(25); //設定視訊影象資料格式 recorder.setPixelFormat(avutil.AV_PIX_FMT_YUV420P); recorder.setFormat("mp4"); try { recorder.start(); Java2DFrameConverter converter = new Java2DFrameConverter(); Log.d("test","imgMap.size() = " + imgMap.size()); //錄製一個imgMap size秒數的的視訊,imgmap容量有多大就錄多少秒 for (int i = 0; i < imgMap.size(); i++) { if(imgMap.get(i) == null){ continue; } IplImage image = cvLoadImage(imgMap.get(i).getAbsolutePath());// OpenCVFrameConverter.ToMat converterToMat = new OpenCVFrameConverter.ToMat(); Frame frame = converterToMat.convert(image); //一秒是30幀 所以要記錄30次 for(int j = 0; j < 30; j++){ recorder.record(frame); } } } catch (Exception e) { e.printStackTrace(); } finally { //最後一定要結束並釋放資源 recorder.stop(); recorder.release(); if(listener != null){ listener.onComplete(mp4SavePath); } Log.d("test","工作已完成 "); } } }
activity呼叫:
class ImageToVideoActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_image_to_video) } fun start(v: View){ Log.d("ddebug", "---start---") // imageToMp4() object :Thread(){ override fun run() { super.run() //合成的MP4 //合成的MP4 val mp4SavePath = "/storage/emulated/0/ScreenRecord/${System.currentTimeMillis()}test_abc.mp4"//"D:\\javacv\\mp4\\img.mp4" //圖片地址 這裡面放了幾張圖片 val img = "/storage/emulated/0/ScreenRecord/temp" val width = 1600 val height = 900 //讀取所有圖片 val file = File(img) val files = file.listFiles() val imgMap: MutableMap<Int, File> = HashMap() var num = 0 for (imgFile in files) { imgMap[num] = imgFile num++ } Utils.createMp4(mp4SavePath, imgMap, width, height, object : Utils.CompleteListener{ override fun onComplete(path: String?) { runOnUiThread{ val tv:TextView = findViewById(R.id.tv) tv.setText("錄製已完成:$path") } } }); } }.start() } }