DroidFS/app/src/main/java/sushi/hardcore/droidfs/video_recording/FFmpegMuxer.kt

91 lines
2.9 KiB
Kotlin
Raw Normal View History

2021-10-03 14:36:06 +02:00
package sushi.hardcore.droidfs.video_recording
import android.media.MediaCodec
import android.media.MediaFormat
2023-04-17 15:52:20 +02:00
import androidx.camera.video.MediaMuxer
2021-10-03 14:36:06 +02:00
import java.nio.ByteBuffer
2023-04-17 15:52:20 +02:00
class FFmpegMuxer(val writer: SeekableWriter): MediaMuxer {
2021-10-03 14:36:06 +02:00
external fun allocContext(): Long
external fun addVideoTrack(formatContext: Long, bitrate: Int, frameRate: Int, width: Int, height: Int, orientationHint: Int): Int
2021-10-03 14:36:06 +02:00
external fun addAudioTrack(formatContext: Long, bitrate: Int, sampleRate: Int, channelCount: Int): Int
external fun writeHeaders(formatContext: Long): Int
external fun writePacket(formatContext: Long, buffer: ByteArray, pts: Long, streamIndex: Int, isKeyFrame: Boolean)
external fun writeTrailer(formatContext: Long)
external fun release(formatContext: Long)
var formatContext: Long?
2023-04-17 15:52:20 +02:00
var orientation = 0
private var videoTrackIndex: Int? = null
private var audioTrackIndex: Int? = null
private var firstPts: Long? = null
2021-10-03 14:36:06 +02:00
init {
System.loadLibrary("mux")
formatContext = allocContext()
}
2023-04-17 15:52:20 +02:00
override fun writeSampleData(trackIndex: Int, buffer: ByteBuffer, bufferInfo: MediaCodec.BufferInfo) {
2021-10-03 14:36:06 +02:00
val byteArray = ByteArray(bufferInfo.size)
buffer.get(byteArray)
if (firstPts == null) {
firstPts = bufferInfo.presentationTimeUs
}
2023-04-17 15:52:20 +02:00
writePacket(
formatContext!!, byteArray, bufferInfo.presentationTimeUs - firstPts!!, trackIndex,
bufferInfo.flags and MediaCodec.BUFFER_FLAG_KEY_FRAME != 0
)
2021-10-03 14:36:06 +02:00
}
2023-04-17 15:52:20 +02:00
override fun addTrack(mediaFormat: MediaFormat): Int {
val mime = mediaFormat.getString("mime")!!.split('/')
val bitrate = mediaFormat.getInteger("bitrate")
2021-10-03 14:36:06 +02:00
return if (mime[0] == "audio") {
2023-04-17 15:52:20 +02:00
addAudioTrack(
2021-10-03 14:36:06 +02:00
formatContext!!,
bitrate,
2023-04-17 15:52:20 +02:00
mediaFormat.getInteger("sample-rate"),
mediaFormat.getInteger("channel-count")
).also {
audioTrackIndex = it
}
2021-10-03 14:36:06 +02:00
} else {
2023-04-17 15:52:20 +02:00
addVideoTrack(
2021-10-03 14:36:06 +02:00
formatContext!!,
bitrate,
mediaFormat.getInteger("frame-rate"),
2023-04-17 15:52:20 +02:00
mediaFormat.getInteger("width"),
mediaFormat.getInteger("height"),
orientation
).also {
videoTrackIndex = it
}
2021-10-03 14:36:06 +02:00
}
}
2023-04-17 15:52:20 +02:00
override fun start() {
2021-10-03 14:36:06 +02:00
writeHeaders(formatContext!!)
}
2023-04-17 15:52:20 +02:00
override fun stop() {
2021-10-03 14:36:06 +02:00
writeTrailer(formatContext!!)
}
2023-04-17 15:52:20 +02:00
override fun setOrientationHint(degree: Int) {
orientation = degree
}
override fun release() {
2021-10-03 14:36:06 +02:00
writer.close()
release(formatContext!!)
firstPts = null
formatContext = null
}
fun writePacket(buff: ByteArray) {
writer.write(buff, buff.size)
2021-10-03 14:36:06 +02:00
}
fun seek(offset: Long) {
writer.seek(offset)
}
}