有效地将位图数组转换为视频

Efficiently converting an array of bitmaps to video

使用 Jcodec 库,我成功地从位图对象数组生成视频文件并将其存储在 Android 文件系统上。

但是,编码时间太长了。我考虑过缩小每个位图以加快速度,但这似乎不起作用。尽管进行了广泛的研究,我还是很难找到有用的答案。

下面的代码是我当前创建位图的方式,其中 canvasView.getWidth()canvasView.getHeight() 分别对应 1920 x 1280

public Bitmap loadBitmapFromView(View v) {
    Bitmap b = Bitmap.createBitmap(canvasView.getWidth(), canvasView.getHeight(), Bitmap.Config.RGB_565);
    Log.i("Downloading", "OWidth: " + b.getWidth() + " --- " + "OHeight: " +  b.getHeight());

    Canvas c = new Canvas(b);
    c.drawColor(Color.WHITE);   // Essential

    v.draw(c);
    v.invalidate();
    v.requestLayout();

    return b;
}

我注意到当您将这两个参数更改为更小的值时,IE:

Bitmap.createBitmap(256, 256, Bitmap.Config.RGB_565);

编码速度显着加快。

整个视图的大小是1920 x 1280,所以上面显示的createBitmap方法只会捕获一小部分window( 256 x 256),这不是我所需要的。

我需要帮助找到一种更有效地将位图数组编码为视频的方法,或者使用我正在使用的相同方法,但缩小每个位图,同时保持整个图像的可见性并加快编码过程。

您可以使用 FFmpeg 加快从图像或位图制作视频的过程

ffmpeg 命令:-

        File dir = your directory where image stores;
        String filePrefix = "picture"; //imagename prefix
        String fileExtn = ".jpg";//image extention
        filePath = dir.getAbsolutePath();
        File src = new File(dir, filePrefix + "%03d" + fileExtn);// image name should ne picture001, picture002,picture003 soon  ffmpeg takes as input valid



complexCommand = new String[]{"-i", src + "", "-c:v", "libx264", "-c:a", "aac", "-vf", "setpts=2*PTS", "-pix_fmt", "yuv420p", "-crf", "10", "-r", "15", "-shortest", "-y", "/storage/emulated/0/" + app_name + "/Video/" + app_name + "_Video" + number + ".mp4"};

此处 src = 包含多张图片的目录路径

您可以使用 writingminds 库来轻松地将 ffmpeg 集成到您的项目中

https://github.com/WritingMinds/ffmpeg-android-java

但是 ffmpeg 增加了 apk 大小大约 18-20 mb

我刚刚提出了这个没有外部库的项目。

https://github.com/dburckh/bitmap2video

实施使用这些

implementation 'org.jcodec:jcodec:0.2.5'
implementation 'org.jcodec:jcodec-android:0.2.5'
implementation 'org.jcodec:jcodec-javase:0.2.5'
implementation 'com.writingminds:FFmpegAndroid:0.3.2'

fun creteRootPath(): File? {
    var file: File? = null
    try {
          if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            file =  File(getApplicationContext()
     .getExternalFilesDir("")
      .toString() + File.separator + "UsamaSd.mp4")
        } else {
            file = File(Environment
      .getExternalStorageDirectory()
      .absolutePath.toString() 
       + File.separator + "UsamaSd.mp4")
        }
        if (file?.exists() == true) {
            file?.mkdirs()
        }
    } catch (e: Exception) {
        e.printStackTrace()
        file // it will return null
    }
    return file
}
fun convertImagesToVideo() {
    try {//Rational(1, 1). SequenceEncoder
        val output = creteRootPath()
        val enc =
            
AWTSequenceEncoder.createWithFps(NIOUtils.writableChannel(output), 
Rational.R(2, 1))
        for (bitmap in arrayOfImagesFinalImages) {
            enc.encodeNativeFrame(fromBitmaps(bitmap))
        }
        enc.finish()
    } finally {
        NIOUtils.closeQuietly(out);
    }
}

fun fromBitmaps(src: Bitmap): Picture {
    val dst: Picture = Picture.create(src.width, src.height, RGB)
    AndroidUtil.fromBitmap(src, dst)
    return dst
}

AndroidUtil class https://github.com/jcodec/jcodec/blob/master/android/src/main/org/jcodec/common/AndroidUtil.java