fix: Asset Writer Video-Audio Sync (#1075)

* fix: Start asset writer session on first frame

* fix: Remove debug log

* fix: Reset dev team
This commit is contained in:
Thomas Coldwell 2022-06-11 11:15:24 +02:00 committed by GitHub
parent de41f8be83
commit fb2156ec39
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 15 additions and 18 deletions

View File

@ -324,7 +324,7 @@ PODS:
- React - React
- RNVectorIcons (8.1.0): - RNVectorIcons (8.1.0):
- React-Core - React-Core
- VisionCamera (2.13.0): - VisionCamera (2.13.3):
- React - React
- React-callinvoker - React-callinvoker
- React-Core - React-Core
@ -504,7 +504,7 @@ SPEC CHECKSUMS:
RNScreens: 40a2cb40a02a609938137a1e0acfbf8fc9eebf19 RNScreens: 40a2cb40a02a609938137a1e0acfbf8fc9eebf19
RNStaticSafeAreaInsets: 6103cf09647fa427186d30f67b0f5163c1ae8252 RNStaticSafeAreaInsets: 6103cf09647fa427186d30f67b0f5163c1ae8252
RNVectorIcons: 31cebfcf94e8cf8686eb5303ae0357da64d7a5a4 RNVectorIcons: 31cebfcf94e8cf8686eb5303ae0357da64d7a5a4
VisionCamera: 9959a41d3edc36b37e8361a2e6cbc05714f0689b VisionCamera: 7bcf3a81533a1c9ad13930804377ad13a03fcded
Yoga: e7dc4e71caba6472ff48ad7d234389b91dadc280 Yoga: e7dc4e71caba6472ff48ad7d234389b91dadc280
PODFILE CHECKSUM: 29b1752e05601e9867644e58ce0ed8b9106be6cb PODFILE CHECKSUM: 29b1752e05601e9867644e58ce0ed8b9106be6cb

View File

@ -456,7 +456,7 @@
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES; ENABLE_TESTABILITY = YES;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "arm64 "; "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "";
GCC_C_LANGUAGE_STANDARD = gnu99; GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO; GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES; GCC_NO_COMMON_BLOCKS = YES;
@ -517,7 +517,7 @@
COPY_PHASE_STRIP = YES; COPY_PHASE_STRIP = YES;
ENABLE_NS_ASSERTIONS = NO; ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_STRICT_OBJC_MSGSEND = YES;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "arm64 "; "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "";
GCC_C_LANGUAGE_STANDARD = gnu99; GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES; GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES;

View File

@ -140,9 +140,9 @@ extension CameraView: AVCaptureVideoDataOutputSampleBufferDelegate, AVCaptureAud
// start recording session with or without audio. // start recording session with or without audio.
do { do {
try recordingSession.start() try recordingSession.startAssetWriter()
} catch let error as NSError { } catch let error as NSError {
callback.reject(error: .capture(.createRecorderError(message: "RecordingSession failed to start writing.")), cause: error) callback.reject(error: .capture(.createRecorderError(message: "RecordingSession failed to start asset writer.")), cause: error)
return return
} }
self.isRecording = true self.isRecording = true

View File

@ -32,6 +32,7 @@ class RecordingSession {
private var initialTimestamp: CMTime? private var initialTimestamp: CMTime?
private var latestTimestamp: CMTime? private var latestTimestamp: CMTime?
private var hasStartedWritingSession = false
private var hasWrittenFirstVideoFrame = false private var hasWrittenFirstVideoFrame = false
private var isFinishing = false private var isFinishing = false
@ -111,7 +112,7 @@ class RecordingSession {
/** /**
Start the Asset Writer(s). If the AssetWriter failed to start, an error will be thrown. Start the Asset Writer(s). If the AssetWriter failed to start, an error will be thrown.
*/ */
func start() throws { func startAssetWriter() throws {
ReactLogger.log(level: .info, message: "Starting Asset Writer(s)...") ReactLogger.log(level: .info, message: "Starting Asset Writer(s)...")
let success = assetWriter.startWriting() let success = assetWriter.startWriting()
@ -119,10 +120,6 @@ class RecordingSession {
ReactLogger.log(level: .error, message: "Failed to start Asset Writer(s)!") ReactLogger.log(level: .error, message: "Failed to start Asset Writer(s)!")
throw RecordingSessionError.failedToStartSession throw RecordingSessionError.failedToStartSession
} }
initialTimestamp = CMTime(seconds: CACurrentMediaTime(), preferredTimescale: 1_000_000_000)
assetWriter.startSession(atSourceTime: initialTimestamp!)
ReactLogger.log(level: .info, message: "Started RecordingSession at \(initialTimestamp!.seconds) seconds.")
} }
/** /**
@ -138,11 +135,6 @@ class RecordingSession {
ReactLogger.log(level: .error, message: "Frame arrived, but sample buffer is not ready!") ReactLogger.log(level: .error, message: "Frame arrived, but sample buffer is not ready!")
return return
} }
guard let initialTimestamp = initialTimestamp else {
ReactLogger.log(level: .error,
message: "A frame arrived, but initialTimestamp was nil. Is this RecordingSession running?")
return
}
latestTimestamp = timestamp latestTimestamp = timestamp
@ -161,10 +153,15 @@ class RecordingSession {
ReactLogger.log(level: .error, message: "Failed to get the CVImageBuffer!") ReactLogger.log(level: .error, message: "Failed to get the CVImageBuffer!")
return return
} }
// Start the writing session before we write the first video frame
if !hasStartedWritingSession {
assetWriter.startSession(atSourceTime: timestamp)
ReactLogger.log(level: .info, message: "Started RecordingSession at \(timestamp.seconds) seconds.")
hasStartedWritingSession = true
}
bufferAdaptor.append(imageBuffer, withPresentationTime: timestamp) bufferAdaptor.append(imageBuffer, withPresentationTime: timestamp)
if !hasWrittenFirstVideoFrame { if !hasWrittenFirstVideoFrame {
hasWrittenFirstVideoFrame = true hasWrittenFirstVideoFrame = true
ReactLogger.log(level: .warning, message: "VideoWriter: First frame arrived \((initialTimestamp - timestamp).seconds) seconds late.")
} }
case .audio: case .audio:
guard let audioWriter = audioWriter else { guard let audioWriter = audioWriter else {
@ -174,7 +171,7 @@ class RecordingSession {
if !audioWriter.isReadyForMoreMediaData { if !audioWriter.isReadyForMoreMediaData {
return return
} }
if !hasWrittenFirstVideoFrame { if !hasWrittenFirstVideoFrame || !hasStartedWritingSession {
// first video frame has not been written yet, so skip this audio frame. // first video frame has not been written yet, so skip this audio frame.
return return
} }