'Efficiently converting an array of bitmaps to video

Using the Jcodec library, I had success producing and storing a video file on the Android file system from an array of Bitmap objects.

However, the encoding time takes way too long. I thought about scaling down each of the bitmaps to speed this up but this did not seem to work. Despite researching extensively, I struggled to find a helpful answer.

The below code is currently how I'm creating a bitmap, Where canvasView.getWidth() and canvasView.getHeight() correspond to 1920 x 1280 respectively.

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;
}

I noticed when you change these two parameters to something smaller, IE:

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

The encoding speeds up dramatically.

The size of the entire view is 1920 x 1280, so the createBitmap method shown above would only capture a small portion of the window (256 x 256), which is not what I require.

I need help finding a way to more efficiently encode an array of bitmaps to video or use the same method I am using but scaling down each bitmap while maintaining the entire image's visibility and speeding up the encoding process.



Solution 1:[1]

I just put up this project that does this without external libs.

https://github.com/dburckh/bitmap2video

Solution 2:[2]

for implementation use these

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
}

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

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Dustin
Solution 2