Commit e95bc7d5 authored by Vadim Pisarevsky's avatar Vadim Pisarevsky

fixed ios camera timing (patch by Eduard Feicho)

parent da5aaab2
...@@ -80,7 +80,6 @@ ...@@ -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;
...@@ -120,6 +119,8 @@ ...@@ -120,6 +119,8 @@
AVAssetWriterInput* recordAssetWriterInput; AVAssetWriterInput* recordAssetWriterInput;
AVAssetWriterInputPixelBufferAdaptor* recordPixelBufferAdaptor; AVAssetWriterInputPixelBufferAdaptor* recordPixelBufferAdaptor;
AVAssetWriter* recordAssetWriter; AVAssetWriter* recordAssetWriter;
CMTime lastSampleTime;
} }
...@@ -134,6 +135,8 @@ ...@@ -134,6 +135,8 @@
- (void)adjustLayoutToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation; - (void)adjustLayoutToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation;
- (void)layoutPreviewLayer; - (void)layoutPreviewLayer;
- (void)saveVideo; - (void)saveVideo;
- (NSURL *)videoFileURL;
@end @end
......
...@@ -98,90 +98,29 @@ static CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;}; ...@@ -98,90 +98,29 @@ 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"); if (self.recordVideo == YES) {
} 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) { if (self.recordAssetWriter.status == AVAssetWriterStatusWriting) {
[self.recordAssetWriter finishWriting]; [self.recordAssetWriter finishWriting];
...@@ -194,11 +133,6 @@ static CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;}; ...@@ -194,11 +133,6 @@ static CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;};
self.recordAssetWriterInput = nil; self.recordAssetWriterInput = nil;
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;}; ...@@ -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);
...@@ -426,21 +351,18 @@ static CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;}; ...@@ -426,21 +351,18 @@ 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;}; ...@@ -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;}; ...@@ -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;}; ...@@ -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) {
[self.recordAssetWriter startWriting];
[self.recordAssetWriter startSessionAtSourceTime:lastSampleTime];
if (self.recordAssetWriter.status != AVAssetWriterStatusWriting) {
NSLog(@"[Camera] Recording Error: asset writer status is not writing: %@", self.recordAssetWriter.error);
return;
} else {
NSLog(@"[Camera] Video recording started");
}
}
// TODO reset frame number
static int64_t frameNumber = 0;
if (self.recordAssetWriterInput.readyForMoreMediaData) { if (self.recordAssetWriterInput.readyForMoreMediaData) {
[self.recordPixelBufferAdaptor appendPixelBuffer:imageBuffer if (! [self.recordPixelBufferAdaptor appendPixelBuffer:imageBuffer
withPresentationTime:CMTimeMake(frameNumber, self.defaultFPS)]; withPresentationTime:lastSampleTime] ) {
NSLog(@"Video Writing Error");
}
} }
frameNumber++;
} }
...@@ -627,14 +556,14 @@ static CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;}; ...@@ -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;}; ...@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment