要从多张图片创建视频,你可以使用Android提供的MediaCodec和MediaMuxer类来实现。下面是一个使用Kotlin编写的示例代码,演示了如何从多张图片创建视频:
import android.media.MediaCodec
import android.media.MediaCodecInfo
import android.media.MediaFormat
import android.media.MediaMuxer
import android.os.Environment
import android.util.Log
import java.io.File
import java.io.IOException
import java.nio.ByteBuffer
class ImageToVideoConverter {
private val TAG = "ImageToVideoConverter"
private val MIME_TYPE = "video/avc"
private val FRAME_RATE = 10
private val IFRAME_INTERVAL = 1
private val TIMEOUT_US = 10000L
private var mediaCodec: MediaCodec? = null
private var mediaMuxer: MediaMuxer? = null
private var bufferInfo: MediaCodec.BufferInfo? = null
private var outputFile: File? = null
private var input: ArrayList? = null
fun convertImagesToVideo(imagePaths: ArrayList, outputFilePath: String) {
input = imagePaths
outputFile = File(outputFilePath)
try {
mediaCodec = MediaCodec.createEncoderByType(MIME_TYPE)
val format = MediaFormat.createVideoFormat(MIME_TYPE, 720, 1280)
format.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface)
format.setInteger(MediaFormat.KEY_BIT_RATE, 2000000)
format.setInteger(MediaFormat.KEY_FRAME_RATE, FRAME_RATE)
format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, IFRAME_INTERVAL)
mediaCodec?.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE)
mediaCodec?.start()
bufferInfo = MediaCodec.BufferInfo()
mediaMuxer = MediaMuxer(outputFile?.absolutePath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4)
val inputSurface = mediaCodec?.createInputSurface()
val videoEncoderThread = VideoEncoderThread(inputSurface)
videoEncoderThread.start()
mediaMuxer?.start()
val presentationTimeUs = 0L
for (i in input!!.indices) {
val imagePath = input!![i]
val bitmap = BitmapFactory.decodeFile(imagePath)
val frame = Bitmap.createBitmap(bitmap.width, bitmap.height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(frame)
canvas.drawBitmap(bitmap, 0f, 0f, null)
val byteBuffer = ByteBuffer.allocate(frame.byteCount)
frame.copyPixelsToBuffer(byteBuffer)
byteBuffer.rewind()
val buffer = byteBuffer.array()
val inputBufferIndex = mediaCodec?.dequeueInputBuffer(TIMEOUT_US)
if (inputBufferIndex!! >= 0) {
val inputBuffer = mediaCodec?.getInputBuffer(inputBufferIndex)
inputBuffer?.clear()
inputBuffer?.put(buffer)
mediaCodec?.queueInputBuffer(inputBufferIndex, 0, buffer.size, presentationTimeUs, 0)
}
mediaCodec?.dequeueOutputBuffer(bufferInfo!!, TIMEOUT_US)
while (bufferInfo?.flags!! and MediaCodec.BUFFER_FLAG_CODEC_CONFIG != 0) {
mediaCodec?.releaseOutputBuffer(inputBufferIndex!!, false)
inputBufferIndex = mediaCodec?.dequeueOutputBuffer(bufferInfo!!, TIMEOUT_US)
}
mediaCodec?.stop()
mediaCodec?.release()
mediaCodec = null
mediaCodec = MediaCodec.createEncoderByType(MIME_TYPE)
mediaCodec?.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE)
mediaCodec?.start()
}
videoEncoderThread.quit()
mediaMuxer?.stop()
mediaMuxer?.release()
} catch (e: IOException) {
Log.e(TAG, "Failed to create video from images: ${e.message}")
}
}
private inner class VideoEncoderThread(private val inputSurface: Surface?) : Thread() {
private var isRunning = true
override fun run() {
val bufferInfo = MediaCodec.BufferInfo()
while (isRunning) {
val outputBufferIndex = mediaCodec?.dequeueOutputBuffer(bufferInfo, TIMEOUT_US)
if (outputBufferIndex!! >= 0) {
val outputBuffer = mediaCodec?.getOutputBuffer(outputBufferIndex)
mediaMuxer?.writeSampleData(0, outputBuffer!!, bufferInfo)
mediaCodec?.releaseOutputBuffer(outputBufferIndex, false)
if (bufferInfo.flags and MediaCodec.BUFFER_FLAG_END_OF_STREAM != 0) {
break
}
}
}