Compare commits
1 Commits
main
...
ivan/try-t
Author | SHA1 | Date | |
---|---|---|---|
1ac1b045fe |
@ -12,26 +12,31 @@ import com.mrousavy.camera.types.Orientation
|
|||||||
import com.mrousavy.camera.types.RecordVideoOptions
|
import com.mrousavy.camera.types.RecordVideoOptions
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
|
import kotlin.math.ceil
|
||||||
|
|
||||||
class ChunkedRecordingManager(private val encoder: MediaCodec, private val outputDirectory: File, private val orientationHint: Int, private val iFrameInterval: Int, private val callbacks: CameraSession.Callback) :
|
class ChunkedRecordingManager(private val encoder: MediaCodec, private val outputDirectory: File, private val orientationHint: Int, private val iFrameInterval: Float, private val callbacks: CameraSession.Callback) :
|
||||||
MediaCodec.Callback() {
|
MediaCodec.Callback() {
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "ChunkedRecorder"
|
private const val TAG = "ChunkedRecorder"
|
||||||
|
|
||||||
|
private fun roundIntervalLengthUp(fps: Float, interval: Float): Float {
|
||||||
|
return ceil(fps * interval) / fps
|
||||||
|
}
|
||||||
|
|
||||||
fun fromParams(
|
fun fromParams(
|
||||||
callbacks: CameraSession.Callback,
|
callbacks: CameraSession.Callback,
|
||||||
size: Size,
|
size: Size,
|
||||||
enableAudio: Boolean,
|
enableAudio: Boolean,
|
||||||
fps: Int? = null,
|
fps: Float = 30.0f,
|
||||||
cameraOrientation: Orientation,
|
cameraOrientation: Orientation,
|
||||||
bitRate: Int,
|
bitRate: Int,
|
||||||
options: RecordVideoOptions,
|
options: RecordVideoOptions,
|
||||||
outputDirectory: File,
|
outputDirectory: File,
|
||||||
iFrameInterval: Int = 5
|
iFrameInterval: Float = 5.0f
|
||||||
): ChunkedRecordingManager {
|
): ChunkedRecordingManager {
|
||||||
val mimeType = options.videoCodec.toMimeType()
|
val mimeType = options.videoCodec.toMimeType()
|
||||||
val cameraOrientationDegrees = cameraOrientation.toDegrees()
|
val cameraOrientationDegrees = cameraOrientation.toDegrees()
|
||||||
val recordingOrientationDegrees = (options.orientation ?: Orientation.PORTRAIT).toDegrees();
|
val recordingOrientationDegrees = (options.orientation ?: Orientation.PORTRAIT).toDegrees()
|
||||||
val (width, height) = if (cameraOrientation.isLandscape()) {
|
val (width, height) = if (cameraOrientation.isLandscape()) {
|
||||||
size.height to size.width
|
size.height to size.width
|
||||||
} else {
|
} else {
|
||||||
@ -42,25 +47,25 @@ class ChunkedRecordingManager(private val encoder: MediaCodec, private val outpu
|
|||||||
|
|
||||||
val codec = MediaCodec.createEncoderByType(mimeType)
|
val codec = MediaCodec.createEncoderByType(mimeType)
|
||||||
|
|
||||||
|
val roundedInterval = roundIntervalLengthUp(fps, iFrameInterval)
|
||||||
|
|
||||||
// Set some properties. Failing to specify some of these can cause the MediaCodec
|
// Set some properties. Failing to specify some of these can cause the MediaCodec
|
||||||
// configure() call to throw an unhelpful exception.
|
// configure() call to throw an unhelpful exception.
|
||||||
format.setInteger(
|
format.setInteger(
|
||||||
MediaFormat.KEY_COLOR_FORMAT,
|
MediaFormat.KEY_COLOR_FORMAT,
|
||||||
MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface
|
MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface
|
||||||
)
|
)
|
||||||
fps?.apply {
|
format.setFloat(MediaFormat.KEY_FRAME_RATE, fps)
|
||||||
format.setInteger(MediaFormat.KEY_FRAME_RATE, this)
|
|
||||||
}
|
|
||||||
// TODO: Pull this out into configuration
|
// TODO: Pull this out into configuration
|
||||||
format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, iFrameInterval)
|
format.setFloat(MediaFormat.KEY_I_FRAME_INTERVAL, roundedInterval)
|
||||||
format.setInteger(MediaFormat.KEY_BIT_RATE, bitRate)
|
format.setInteger(MediaFormat.KEY_BIT_RATE, bitRate)
|
||||||
|
|
||||||
Log.d(TAG, "Video Format: $format, camera orientation $cameraOrientationDegrees, recordingOrientation: $recordingOrientationDegrees")
|
Log.d(TAG, "Video Format: $format, camera orientation $cameraOrientationDegrees, recordingOrientation: $recordingOrientationDegrees, Set fps: $fps")
|
||||||
// Create a MediaCodec encoder, and configure it with our format. Get a Surface
|
// Create a MediaCodec encoder, and configure it with our format. Get a Surface
|
||||||
// we can use for input and wrap it with a class that handles the EGL work.
|
// we can use for input and wrap it with a class that handles the EGL work.
|
||||||
codec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE)
|
codec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE)
|
||||||
return ChunkedRecordingManager(
|
return ChunkedRecordingManager(
|
||||||
codec, outputDirectory, recordingOrientationDegrees, iFrameInterval, callbacks
|
codec, outputDirectory, recordingOrientationDegrees, roundedInterval, callbacks
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -69,7 +74,7 @@ class ChunkedRecordingManager(private val encoder: MediaCodec, private val outpu
|
|||||||
private var currentFrameNumber: Int = 0
|
private var currentFrameNumber: Int = 0
|
||||||
private var chunkIndex = -1
|
private var chunkIndex = -1
|
||||||
private var encodedFormat: MediaFormat? = null
|
private var encodedFormat: MediaFormat? = null
|
||||||
private var recording = false;
|
private var recording = false
|
||||||
|
|
||||||
private val targetDurationUs = iFrameInterval * 1000000
|
private val targetDurationUs = iFrameInterval * 1000000
|
||||||
|
|
||||||
@ -83,15 +88,15 @@ class ChunkedRecordingManager(private val encoder: MediaCodec, private val outpu
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Muxer specific
|
// Muxer specific
|
||||||
private class MuxerContext(val muxer: MediaMuxer, val filepath: File, val chunkIndex: Int, startTimeUs: Long, encodedFormat: MediaFormat) {
|
private class MuxerContext(
|
||||||
|
val muxer: MediaMuxer, val filepath: File, val chunkIndex: Int,
|
||||||
|
val startTimeUs: Long, encodedFormat: MediaFormat
|
||||||
|
) {
|
||||||
val videoTrack: Int = muxer.addTrack(encodedFormat)
|
val videoTrack: Int = muxer.addTrack(encodedFormat)
|
||||||
val startTimeUs: Long = startTimeUs
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
muxer.start()
|
muxer.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun finish() {
|
fun finish() {
|
||||||
muxer.stop()
|
muxer.stop()
|
||||||
muxer.release()
|
muxer.release()
|
||||||
@ -146,7 +151,7 @@ class ChunkedRecordingManager(private val encoder: MediaCodec, private val outpu
|
|||||||
override fun onInputBufferAvailable(codec: MediaCodec, index: Int) {
|
override fun onInputBufferAvailable(codec: MediaCodec, index: Int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOutputBufferAvailable(codec: MediaCodec, index: Int, bufferInfo: MediaCodec.BufferInfo) {
|
override fun onOutputBufferAvailable(codec: MediaCodec, index: Int, bufferInfo: BufferInfo) {
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
if (!recording) {
|
if (!recording) {
|
||||||
return
|
return
|
||||||
|
@ -45,7 +45,7 @@ class RecordingSession(
|
|||||||
allCallbacks,
|
allCallbacks,
|
||||||
size,
|
size,
|
||||||
enableAudio,
|
enableAudio,
|
||||||
fps,
|
(fps ?: 30).toFloat(),
|
||||||
cameraOrientation,
|
cameraOrientation,
|
||||||
bitRate,
|
bitRate,
|
||||||
options,
|
options,
|
||||||
|
Loading…
Reference in New Issue
Block a user