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

94 lines
2.9 KiB
Kotlin

package sushi.hardcore.droidfs.video_recording
import android.media.MediaCodec
import android.media.MediaFormat
import java.nio.ByteBuffer
class MediaMuxer(val writer: SeekableWriter) {
external fun allocContext(): Long
external fun addVideoTrack(formatContext: Long, bitrate: Int, width: Int, height: Int, orientationHint: Int): Int
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)
companion object {
const val VIDEO_TRACK_INDEX = 0
const val AUDIO_TRACK_INDEX = 1
}
var formatContext: Long?
var orientationHint = 0
var realVideoTrackIndex: Int? = null
var audioFrameSize: Int? = null
var firstPts: Long? = null
private var audioPts = 0L
init {
System.loadLibrary("mux")
formatContext = allocContext()
}
fun writeSampleData(trackIndex: Int, buffer: ByteBuffer, bufferInfo: MediaCodec.BufferInfo) {
val byteArray = ByteArray(bufferInfo.size)
buffer.get(byteArray)
if (firstPts == null) {
firstPts = bufferInfo.presentationTimeUs
}
if (trackIndex == AUDIO_TRACK_INDEX) {
writePacket(formatContext!!, byteArray, audioPts, -1, false)
audioPts += audioFrameSize!!
} else {
writePacket(
formatContext!!, byteArray, bufferInfo.presentationTimeUs - firstPts!!, realVideoTrackIndex!!,
bufferInfo.flags and MediaCodec.BUFFER_FLAG_KEY_FRAME != 0
)
}
}
fun addTrack(format: MediaFormat): Int {
val mime = format.getString("mime")!!.split('/')
val bitrate = format.getInteger("bitrate")
return if (mime[0] == "audio") {
audioFrameSize = addAudioTrack(
formatContext!!,
bitrate,
format.getInteger("sample-rate"),
format.getInteger("channel-count")
)
AUDIO_TRACK_INDEX
} else {
realVideoTrackIndex = addVideoTrack(
formatContext!!,
bitrate,
format.getInteger("width"),
format.getInteger("height"),
orientationHint
)
VIDEO_TRACK_INDEX
}
}
fun start() {
writeHeaders(formatContext!!)
}
fun stop() {
writeTrailer(formatContext!!)
}
fun release() {
writer.close()
release(formatContext!!)
firstPts = null
audioPts = 0
formatContext = null
}
fun writePacket(buff: ByteArray) {
writer.write(buff)
}
fun seek(offset: Long) {
writer.seek(offset)
}
}