diff --git a/Examples/Sources/SCRecorderViewController.m b/Examples/Sources/SCRecorderViewController.m index fd936523..613716b7 100644 --- a/Examples/Sources/SCRecorderViewController.m +++ b/Examples/Sources/SCRecorderViewController.m @@ -69,6 +69,8 @@ - (void)viewDidLoad { _recorder = [SCRecorder recorder]; _recorder.sessionPreset = AVCaptureSessionPreset1280x720; _recorder.maxRecordDuration = CMTimeMake(5, 1); + _recorder.videoConfiguration.maxFrameRate = 10; + _recorder.videoConfiguration.timeScale = 0.333; _recorder.delegate = self; _recorder.autoSetVideoOrientation = YES; diff --git a/Library/Sources/SCRecordSession.m b/Library/Sources/SCRecordSession.m index 25e33e87..be6603ca 100644 --- a/Library/Sources/SCRecordSession.m +++ b/Library/Sources/SCRecordSession.m @@ -92,8 +92,10 @@ - (id)init { _currentSegmentCount = 0; _timeOffset = kCMTimeZero; _lastTimeAudio = kCMTimeZero; + _lastAppendedVideo = kCMTimeZero; _currentSegmentDuration = kCMTimeZero; _segmentsDuration = kCMTimeZero; + _sessionBegan = kCMTimeZero; _date = [NSDate date]; _recordSegmentsDirectory = SCRecordSessionTemporaryDirectory; _identifier = [NSString stringWithFormat:@"%ld", (long)[_date timeIntervalSince1970]]; @@ -599,6 +601,10 @@ - (BOOL)appendAudioSampleBuffer:(CMSampleBufferRef)audioSampleBuffer { if ([_audioInput isReadyForMoreMediaData]) { CMTime actualBufferTime = CMSampleBufferGetPresentationTimeStamp(audioSampleBuffer); + if (CMTIME_IS_INVALID(_sessionBegan)) { + _sessionBegan = actualBufferTime; + } + if (CMTIME_IS_INVALID(_timeOffset)) { _timeOffset = CMTimeSubtract(actualBufferTime, _currentSegmentDuration); } @@ -631,6 +637,23 @@ - (BOOL)appendVideoSampleBuffer:(CMSampleBufferRef)videoSampleBuffer duration:(C if ([_videoInput isReadyForMoreMediaData]) { CMTime actualBufferTime = CMSampleBufferGetPresentationTimeStamp(videoSampleBuffer); + if (CMTIME_IS_INVALID(_sessionBegan)) { + _sessionBegan = actualBufferTime; + } + + if (_videoConfiguration.maxFrameRate > 0) { + CMTime interval = CMTimeMake(1, _videoConfiguration.maxFrameRate); + + CMTime offset = CMTimeSubtract(actualBufferTime, _lastAppendedVideo); + if (CMTIME_COMPARE_INLINE(_lastAppendedVideo, ==, kCMTimeZero)) { + offset = CMTimeSubtract(actualBufferTime, _sessionBegan); + } + + if (CMTIME_COMPARE_INLINE(offset, <, interval)) { + return NO; + } + } + if (CMTIME_IS_INVALID(_timeOffset)) { _timeOffset = CMTimeSubtract(actualBufferTime, _currentSegmentDuration); // NSLog(@"Recomputed time offset to: %fs", CMTimeGetSeconds(_timeOffset)); @@ -644,7 +667,6 @@ - (BOOL)appendVideoSampleBuffer:(CMSampleBufferRef)videoSampleBuffer duration:(C } CMTime bufferTimestamp = CMTimeSubtract(actualBufferTime, _timeOffset); - if (_videoPixelBufferAdaptor != nil) { CIImage *image = [CIImage imageWithCVPixelBuffer:CMSampleBufferGetImageBuffer(videoSampleBuffer)]; @@ -674,6 +696,7 @@ - (BOOL)appendVideoSampleBuffer:(CMSampleBufferRef)videoSampleBuffer duration:(C CFRelease(adjustedBuffer); } + _lastAppendedVideo = actualBufferTime; _currentSegmentDuration = CMTimeAdd(bufferTimestamp, duration); _currentSegmentHasVideo = YES; diff --git a/Library/Sources/SCRecordSession_Internal.h b/Library/Sources/SCRecordSession_Internal.h index a5b33dc6..c7e347f2 100644 --- a/Library/Sources/SCRecordSession_Internal.h +++ b/Library/Sources/SCRecordSession_Internal.h @@ -22,6 +22,8 @@ int _currentSegmentCount; CMTime _timeOffset; CMTime _lastTimeAudio; + CMTime _lastAppendedVideo; + CMTime _sessionBegan; SCVideoConfiguration *_videoConfiguration; SCAudioConfiguration *_audioConfiguration; diff --git a/Library/Sources/SCRecorder.m b/Library/Sources/SCRecorder.m index e79a8e58..c0eee0e3 100644 --- a/Library/Sources/SCRecorder.m +++ b/Library/Sources/SCRecorder.m @@ -155,7 +155,7 @@ - (void)commitSessionConfiguration { if (_captureSession != nil) { _beginSessionConfigurationCount--; if (_beginSessionConfigurationCount == 0) { - [_captureSession commitConfiguration]; + [self.captureSession commitConfiguration]; } } } @@ -967,7 +967,31 @@ - (void)setPhotoOutputSettings:(NSDictionary *)photoOutputSettings { - (void)setDevice:(AVCaptureDevicePosition)device { _device = device; if (_captureSession != nil) { - [self reconfigureVideoInput:self.videoConfiguration.enabled audioInput:NO]; + + [self beginSessionConfiguration]; + NSError *error = nil; + AVCaptureDeviceInput *currentInput = [self currentDeviceInputForMediaType:AVMediaTypeVideo]; + AVCaptureDeviceInput *newInput = [[AVCaptureDeviceInput alloc] initWithDevice:[self videoDevice] error:&error]; + + if (error == nil) { + [_captureSession removeInput:currentInput]; + if ([_captureSession canAddInput:newInput]) { + [_captureSession addInput:newInput]; + } else { + [_captureSession addInput:currentInput]; + error = [SCRecorder createError:@"Failed to add input to capture session"]; + } + } + + dispatch_sync(_recordSessionQueue, ^{ + [self updateVideoOrientation]; + }); + [self commitSessionConfiguration]; + + id delegate = self.delegate; + if ([delegate respondsToSelector:@selector(recorder:didReconfigureVideoInput:)]) { + [delegate recorder:self didReconfigureVideoInput:error]; + } } } diff --git a/Library/Sources/SCVideoConfiguration.h b/Library/Sources/SCVideoConfiguration.h index 49f97971..730ff82d 100644 --- a/Library/Sources/SCVideoConfiguration.h +++ b/Library/Sources/SCVideoConfiguration.h @@ -50,7 +50,7 @@ typedef enum : NSUInteger { @property (copy, nonatomic) NSString *scalingMode; /** - The maximum framerate that this SCRecordSession should handle + The maximum input framerate that this SCRecordSession should handle If the camera appends too much frames, they will be dropped. If this property's value is 0, it will use the current video framerate from the camera.