fixed ios camera timing (patch by Eduard Feicho)
This commit is contained in:
parent
da5aaab277
commit
e95bc7d502
@ -80,7 +80,6 @@
|
|||||||
|
|
||||||
@property (nonatomic, retain) UIView* parentView;
|
@property (nonatomic, retain) UIView* parentView;
|
||||||
|
|
||||||
- (void)pause;
|
|
||||||
- (void)start;
|
- (void)start;
|
||||||
- (void)stop;
|
- (void)stop;
|
||||||
- (void)switchCameras;
|
- (void)switchCameras;
|
||||||
@ -121,6 +120,8 @@
|
|||||||
AVAssetWriterInputPixelBufferAdaptor* recordPixelBufferAdaptor;
|
AVAssetWriterInputPixelBufferAdaptor* recordPixelBufferAdaptor;
|
||||||
AVAssetWriter* recordAssetWriter;
|
AVAssetWriter* recordAssetWriter;
|
||||||
|
|
||||||
|
CMTime lastSampleTime;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@property (nonatomic, assign) id<CvVideoCameraDelegate> delegate;
|
@property (nonatomic, assign) id<CvVideoCameraDelegate> delegate;
|
||||||
@ -134,6 +135,8 @@
|
|||||||
- (void)adjustLayoutToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation;
|
- (void)adjustLayoutToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation;
|
||||||
- (void)layoutPreviewLayer;
|
- (void)layoutPreviewLayer;
|
||||||
- (void)saveVideo;
|
- (void)saveVideo;
|
||||||
|
- (NSURL *)videoFileURL;
|
||||||
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@ -99,89 +99,28 @@ static CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;};
|
|||||||
[super start];
|
[super start];
|
||||||
|
|
||||||
if (self.recordVideo == YES) {
|
if (self.recordVideo == YES) {
|
||||||
// [self.videoFileOutput startRecordingToOutputFileURL:[self tempFileURL] recordingDelegate:self];
|
|
||||||
|
|
||||||
NSError* error;
|
NSError* error;
|
||||||
if ([[NSFileManager defaultManager] fileExistsAtPath:[self tempFileString]]) [[NSFileManager defaultManager] removeItemAtPath:[self tempFileString] error:&error];
|
if ([[NSFileManager defaultManager] fileExistsAtPath:[self videoFileString]]) {
|
||||||
|
[[NSFileManager defaultManager] removeItemAtPath:[self videoFileString] error:&error];
|
||||||
|
}
|
||||||
if (error == nil) {
|
if (error == nil) {
|
||||||
NSLog(@"[Camera] Delete file %@", [self tempFileString]);
|
NSLog(@"[Camera] Delete file %@", [self videoFileString]);
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
BOOL started = [self.recordAssetWriter startWriting];
|
|
||||||
[self.recordAssetWriter startSessionAtSourceTime:kCMTimeZero];
|
|
||||||
|
|
||||||
NSLog(@"[Camera] Session started? %d", started);
|
|
||||||
|
|
||||||
if (self.recordAssetWriter.status == AVAssetWriterStatusUnknown) {
|
|
||||||
NSLog(@"AVAssetWriter status: unknown");
|
|
||||||
} else if (self.recordAssetWriter.status == AVAssetWriterStatusWriting) {
|
|
||||||
NSLog(@"AVAssetWriter status: writing");
|
|
||||||
} else if (self.recordAssetWriter.status == AVAssetWriterStatusCompleted) {
|
|
||||||
NSLog(@"AVAssetWriter status: completed");
|
|
||||||
} else if (self.recordAssetWriter.status == AVAssetWriterStatusFailed) {
|
|
||||||
NSLog(@"AVAssetWriter status: failed");
|
|
||||||
} else if (self.recordAssetWriter.status == AVAssetWriterStatusCancelled) {
|
|
||||||
NSLog(@"AVAssetWriter status: cancelled");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self.recordAssetWriter.status != AVAssetWriterStatusWriting) {
|
|
||||||
NSLog(@"[Camera] Recording Error: asset writer status is not writing: %@", self.recordAssetWriter.error);
|
|
||||||
} else {
|
|
||||||
NSLog(@"[Camera] Recording started");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
- (void)pause;
|
|
||||||
{
|
|
||||||
[super pause];
|
|
||||||
if (self.recordVideo == YES) {
|
|
||||||
// [self.videoFileOutput stopRecording];
|
|
||||||
|
|
||||||
|
|
||||||
if (self.recordAssetWriter.status == AVAssetWriterStatusUnknown) {
|
|
||||||
NSLog(@"AVAssetWriter status: unknown");
|
|
||||||
} else if (self.recordAssetWriter.status == AVAssetWriterStatusWriting) {
|
|
||||||
NSLog(@"AVAssetWriter status: writing");
|
|
||||||
} else if (self.recordAssetWriter.status == AVAssetWriterStatusCompleted) {
|
|
||||||
NSLog(@"AVAssetWriter status: completed");
|
|
||||||
} else if (self.recordAssetWriter.status == AVAssetWriterStatusFailed) {
|
|
||||||
NSLog(@"AVAssetWriter status: failed");
|
|
||||||
} else if (self.recordAssetWriter.status == AVAssetWriterStatusCancelled) {
|
|
||||||
NSLog(@"AVAssetWriter status: cancelled");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self.recordAssetWriter.status == AVAssetWriterStatusWriting) {
|
|
||||||
[self.recordAssetWriter finishWriting];
|
|
||||||
NSLog(@"[Camera] recording stopped");
|
|
||||||
} else {
|
|
||||||
NSLog(@"[Camera] Recording Error: asset writer status is not writing");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
- (void)stop;
|
- (void)stop;
|
||||||
{
|
{
|
||||||
[super stop];
|
[super stop];
|
||||||
|
|
||||||
if (self.recordVideo == YES) {
|
self.videoDataOutput = nil;
|
||||||
NSLog(@"recording stop");
|
if (videoDataOutputQueue) {
|
||||||
if (self.recordAssetWriter.status == AVAssetWriterStatusUnknown) {
|
dispatch_release(videoDataOutputQueue);
|
||||||
NSLog(@"AVAssetWriter status: unknown");
|
|
||||||
} else if (self.recordAssetWriter.status == AVAssetWriterStatusWriting) {
|
|
||||||
NSLog(@"AVAssetWriter status: writing");
|
|
||||||
} else if (self.recordAssetWriter.status == AVAssetWriterStatusCompleted) {
|
|
||||||
NSLog(@"AVAssetWriter status: completed");
|
|
||||||
} else if (self.recordAssetWriter.status == AVAssetWriterStatusFailed) {
|
|
||||||
NSLog(@"AVAssetWriter status: failed");
|
|
||||||
} else if (self.recordAssetWriter.status == AVAssetWriterStatusCancelled) {
|
|
||||||
NSLog(@"AVAssetWriter status: cancelled");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (self.recordVideo == YES) {
|
||||||
|
|
||||||
if (self.recordAssetWriter.status == AVAssetWriterStatusWriting) {
|
if (self.recordAssetWriter.status == AVAssetWriterStatusWriting) {
|
||||||
[self.recordAssetWriter finishWriting];
|
[self.recordAssetWriter finishWriting];
|
||||||
@ -195,11 +134,6 @@ static CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;};
|
|||||||
self.recordPixelBufferAdaptor = nil;
|
self.recordPixelBufferAdaptor = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.videoDataOutput = nil;
|
|
||||||
if (videoDataOutputQueue) {
|
|
||||||
dispatch_release(videoDataOutputQueue);
|
|
||||||
}
|
|
||||||
|
|
||||||
[self.customPreviewLayer removeFromSuperlayer];
|
[self.customPreviewLayer removeFromSuperlayer];
|
||||||
self.customPreviewLayer = nil;
|
self.customPreviewLayer = nil;
|
||||||
}
|
}
|
||||||
@ -405,15 +339,6 @@ static CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;};
|
|||||||
|
|
||||||
- (void)createVideoFileOutput;
|
- (void)createVideoFileOutput;
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
if (self.recordVideo == YES) {
|
|
||||||
self.videoFileOutput = [[AVCaptureMovieFileOutput alloc] init];
|
|
||||||
if ( [self.captureSession canAddOutput:self.videoFileOutput] ) {
|
|
||||||
[self.captureSession addOutput:self.videoFileOutput];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Video File Output in H.264, via AVAsserWriter */
|
/* Video File Output in H.264, via AVAsserWriter */
|
||||||
NSLog(@"Create Video with dimensions %dx%d", self.imageWidth, self.imageHeight);
|
NSLog(@"Create Video with dimensions %dx%d", self.imageWidth, self.imageHeight);
|
||||||
|
|
||||||
@ -428,19 +353,16 @@ static CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;};
|
|||||||
self.recordAssetWriterInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:outputSettings];
|
self.recordAssetWriterInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:outputSettings];
|
||||||
|
|
||||||
|
|
||||||
/* I'm going to push pixel buffers to it, so will need a
|
|
||||||
AVAssetWriterPixelBufferAdaptor, to expect the same 32BGRA input as I've
|
|
||||||
asked the AVCaptureVideDataOutput to supply */
|
|
||||||
int pixelBufferFormat = (self.grayscaleMode == YES) ? kCVPixelFormatType_420YpCbCr8BiPlanarFullRange : kCVPixelFormatType_32BGRA;
|
int pixelBufferFormat = (self.grayscaleMode == YES) ? kCVPixelFormatType_420YpCbCr8BiPlanarFullRange : kCVPixelFormatType_32BGRA;
|
||||||
|
|
||||||
self.recordPixelBufferAdaptor =
|
self.recordPixelBufferAdaptor =
|
||||||
[[AVAssetWriterInputPixelBufferAdaptor alloc]
|
[[AVAssetWriterInputPixelBufferAdaptor alloc]
|
||||||
initWithAssetWriterInput:self.recordAssetWriterInput
|
initWithAssetWriterInput:self.recordAssetWriterInput
|
||||||
sourcePixelBufferAttributes:[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:pixelBufferFormat], kCVPixelBufferPixelFormatTypeKey,nil]];
|
sourcePixelBufferAttributes:[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:pixelBufferFormat], kCVPixelBufferPixelFormatTypeKey, nil]];
|
||||||
|
|
||||||
NSError* error = nil;
|
NSError* error = nil;
|
||||||
NSLog(@"Create AVAssetWriter with url: %@", [self tempFileURL]);
|
NSLog(@"Create AVAssetWriter with url: %@", [self videoFileURL]);
|
||||||
self.recordAssetWriter = [AVAssetWriter assetWriterWithURL:[self tempFileURL]
|
self.recordAssetWriter = [AVAssetWriter assetWriterWithURL:[self videoFileURL]
|
||||||
fileType:AVFileTypeMPEG4
|
fileType:AVFileTypeMPEG4
|
||||||
error:&error];
|
error:&error];
|
||||||
if (error != nil) {
|
if (error != nil) {
|
||||||
@ -448,10 +370,9 @@ static CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;};
|
|||||||
}
|
}
|
||||||
|
|
||||||
[self.recordAssetWriter addInput:self.recordAssetWriterInput];
|
[self.recordAssetWriter addInput:self.recordAssetWriterInput];
|
||||||
self.recordAssetWriterInput.expectsMediaDataInRealTime = NO;
|
self.recordAssetWriterInput.expectsMediaDataInRealTime = YES;
|
||||||
|
|
||||||
NSLog(@"[Camera] created AVAssetWriter");
|
NSLog(@"[Camera] created AVAssetWriter");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -580,8 +501,6 @@ static CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;};
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// render buffer
|
// render buffer
|
||||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||||
self.customPreviewLayer.contents = (__bridge id)dstImage;
|
self.customPreviewLayer.contents = (__bridge id)dstImage;
|
||||||
@ -589,16 +508,26 @@ static CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;};
|
|||||||
|
|
||||||
|
|
||||||
if (self.recordVideo == YES) {
|
if (self.recordVideo == YES) {
|
||||||
// a very dense way to keep track of the time at which this frame
|
lastSampleTime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
|
||||||
// occurs relative to the output stream, but it's just an example!
|
// CMTimeShow(lastSampleTime);
|
||||||
|
if (self.recordAssetWriter.status != AVAssetWriterStatusWriting) {
|
||||||
// TODO reset frame number
|
[self.recordAssetWriter startWriting];
|
||||||
static int64_t frameNumber = 0;
|
[self.recordAssetWriter startSessionAtSourceTime:lastSampleTime];
|
||||||
if (self.recordAssetWriterInput.readyForMoreMediaData) {
|
if (self.recordAssetWriter.status != AVAssetWriterStatusWriting) {
|
||||||
[self.recordPixelBufferAdaptor appendPixelBuffer:imageBuffer
|
NSLog(@"[Camera] Recording Error: asset writer status is not writing: %@", self.recordAssetWriter.error);
|
||||||
withPresentationTime:CMTimeMake(frameNumber, self.defaultFPS)];
|
return;
|
||||||
|
} else {
|
||||||
|
NSLog(@"[Camera] Video recording started");
|
||||||
}
|
}
|
||||||
frameNumber++;
|
}
|
||||||
|
|
||||||
|
if (self.recordAssetWriterInput.readyForMoreMediaData) {
|
||||||
|
if (! [self.recordPixelBufferAdaptor appendPixelBuffer:imageBuffer
|
||||||
|
withPresentationTime:lastSampleTime] ) {
|
||||||
|
NSLog(@"Video Writing Error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -627,14 +556,14 @@ static CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;};
|
|||||||
}
|
}
|
||||||
|
|
||||||
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
|
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
|
||||||
if ([library videoAtPathIsCompatibleWithSavedPhotosAlbum:[self tempFileURL]]) {
|
if ([library videoAtPathIsCompatibleWithSavedPhotosAlbum:[self videoFileURL]]) {
|
||||||
[library writeVideoAtPathToSavedPhotosAlbum:[self tempFileURL]
|
[library writeVideoAtPathToSavedPhotosAlbum:[self videoFileURL]
|
||||||
completionBlock:^(NSURL *assetURL, NSError *error){}];
|
completionBlock:^(NSURL *assetURL, NSError *error){}];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (NSURL *)tempFileURL;
|
- (NSURL *)videoFileURL;
|
||||||
{
|
{
|
||||||
NSString *outputPath = [[NSString alloc] initWithFormat:@"%@%@", NSTemporaryDirectory(), @"output.mov"];
|
NSString *outputPath = [[NSString alloc] initWithFormat:@"%@%@", NSTemporaryDirectory(), @"output.mov"];
|
||||||
NSURL *outputURL = [NSURL fileURLWithPath:outputPath];
|
NSURL *outputURL = [NSURL fileURLWithPath:outputPath];
|
||||||
@ -647,7 +576,7 @@ static CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;};
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
- (NSString *)tempFileString;
|
- (NSString *)videoFileString;
|
||||||
{
|
{
|
||||||
NSString *outputPath = [[NSString alloc] initWithFormat:@"%@%@", NSTemporaryDirectory(), @"output.mov"];
|
NSString *outputPath = [[NSString alloc] initWithFormat:@"%@%@", NSTemporaryDirectory(), @"output.mov"];
|
||||||
return outputPath;
|
return outputPath;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user