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