Compare commits
1 Commits
main
...
loewy/andr
| Author | SHA1 | Date | |
|---|---|---|---|
| a1f23e0183 |
@@ -110,6 +110,8 @@ class UnknownCaptureError(wasImageCaptured: Boolean) :
|
||||
CameraError("capture", "unknown", "An unknown error occurred while trying to capture an Image! Was Image captured: $wasImageCaptured")
|
||||
class RecorderError(name: String, extra: Int) :
|
||||
CameraError("capture", "recorder-error", "An error occured while recording a video! $name $extra")
|
||||
class FragmentedRecorderError(message: String, cause: Throwable? = null) :
|
||||
CameraError("capture", "fragmented-recorder-error", message, cause)
|
||||
class NoRecordingInProgressError :
|
||||
CameraError("capture", "no-recording-in-progress", "There was no active video recording in progress! Did you call stopRecording() twice?")
|
||||
class InsufficientStorageError : CameraError("capture", "insufficient-storage", "There is not enough storage space available.")
|
||||
|
||||
@@ -20,7 +20,8 @@ import java.io.File
|
||||
*/
|
||||
class FragmentedRecordingManager(
|
||||
private val encoder: MediaCodec,
|
||||
private val muxer: HlsMuxer
|
||||
private val muxer: HlsMuxer,
|
||||
private val onError: (CameraError) -> Unit
|
||||
) : MediaCodec.Callback(), ChunkedRecorderInterface {
|
||||
|
||||
companion object {
|
||||
@@ -36,6 +37,7 @@ class FragmentedRecordingManager(
|
||||
bitRate: Int,
|
||||
options: RecordVideoOptions,
|
||||
outputDirectory: File,
|
||||
onError: (CameraError) -> Unit,
|
||||
segmentDurationSeconds: Int = DEFAULT_SEGMENT_DURATION_SECONDS
|
||||
): FragmentedRecordingManager {
|
||||
val mimeType = options.videoCodec.toMimeType()
|
||||
@@ -81,11 +83,12 @@ class FragmentedRecordingManager(
|
||||
)
|
||||
muxer.setSegmentDuration(segmentDurationSeconds * 1_000_000L)
|
||||
|
||||
return FragmentedRecordingManager(codec, muxer)
|
||||
return FragmentedRecordingManager(codec, muxer, onError)
|
||||
}
|
||||
}
|
||||
|
||||
private var recording = false
|
||||
private var failed = false
|
||||
private var muxerStarted = false
|
||||
private var trackIndex = -1
|
||||
|
||||
@@ -100,6 +103,17 @@ class FragmentedRecordingManager(
|
||||
recording = true
|
||||
}
|
||||
|
||||
private fun failRecording(message: String, cause: Throwable) {
|
||||
if (failed) {
|
||||
return
|
||||
}
|
||||
|
||||
failed = true
|
||||
recording = false
|
||||
Log.e(TAG, message, cause)
|
||||
onError(FragmentedRecorderError(message, cause))
|
||||
}
|
||||
|
||||
override fun finish() {
|
||||
synchronized(this) {
|
||||
recording = false
|
||||
@@ -138,7 +152,10 @@ class FragmentedRecordingManager(
|
||||
|
||||
val buffer = encoder.getOutputBuffer(index)
|
||||
if (buffer == null) {
|
||||
Log.e(TAG, "getOutputBuffer returned null")
|
||||
failRecording(
|
||||
"Failed to write fragmented MP4 sample: output buffer was null",
|
||||
RuntimeException("getOutputBuffer returned null")
|
||||
)
|
||||
encoder.releaseOutputBuffer(index, false)
|
||||
return
|
||||
}
|
||||
@@ -146,7 +163,7 @@ class FragmentedRecordingManager(
|
||||
try {
|
||||
muxer.writeSampleData(trackIndex, buffer, bufferInfo)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Error writing sample", e)
|
||||
failRecording("Failed to write fragmented MP4 sample", e)
|
||||
}
|
||||
|
||||
encoder.releaseOutputBuffer(index, false)
|
||||
@@ -154,16 +171,22 @@ class FragmentedRecordingManager(
|
||||
}
|
||||
|
||||
override fun onError(codec: MediaCodec, e: MediaCodec.CodecException) {
|
||||
Log.e(TAG, "Codec error: ${e.message}")
|
||||
synchronized(this) {
|
||||
failRecording("Fragmented MP4 encoder error", e)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onOutputFormatChanged(codec: MediaCodec, format: MediaFormat) {
|
||||
synchronized(this) {
|
||||
Log.i(TAG, "Output format changed: $format")
|
||||
|
||||
try {
|
||||
trackIndex = muxer.addTrack(format)
|
||||
muxer.start()
|
||||
muxerStarted = true
|
||||
} catch (e: Exception) {
|
||||
failRecording("Failed to start fragmented MP4 muxer", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -273,7 +273,10 @@ class HlsMuxer(
|
||||
// Write init segment
|
||||
val initBytes = buildInitSegment(format)
|
||||
val initFile = File(outputDirectory, "init.mp4")
|
||||
FileOutputStream(initFile).use { it.write(initBytes) }
|
||||
FileOutputStream(initFile).use { output ->
|
||||
output.write(initBytes)
|
||||
output.fd.sync()
|
||||
}
|
||||
|
||||
// Log frame rate metadata for debugging
|
||||
val defaultSampleDuration = timescale / fps
|
||||
|
||||
@@ -72,6 +72,7 @@ class RecordingSession(
|
||||
bitRate,
|
||||
options,
|
||||
outputPath,
|
||||
onError,
|
||||
SEGMENT_DURATION_SECONDS
|
||||
)
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user