I'm having trouble with what I think should be an easy task.
I'm trying to record video from any attached webcam to a file for a specific duration. But the duration that actually gets recorded is always about 3/4 of a second off. E.g. 5 secs gets recorded as 4.28
Following some advice from Googling and stackoverflow-ing, i've seen that a simple way to do this is to use setMaximumRecordedDuration
on the movie output file, and then stop capturing in the delegate captureOutput method.
For instance for capturing 5 secs of video, I'm using the following code right now;
// set maximum duration (e.g. 5 secs at 30000 timescale) ??
[mCaptureMovieFileOutput recordToOutputFileURL:[NSURL fileURLWithPath:path]];
[mCaptureMovieFileOutput setMaximumRecordedDuration: QTMakeTime(5*30000, 30000)];
[mCaptureSession startRunning];
// start a run loop (for how long?)
verbose("(recording for %.2lf seconds)\n", [recordSeconds doubleValue]);
NSDate *now = [[NSDate alloc] init];
[[NSRunLoop currentRunLoop] runUntilDate:[now dateByAddingTimeInterval: [recordSeconds doubleValue]]];
verbose("(recording period ended)\n");
Then in my captureOutput delegate method I have;
- (BOOL)captureOutput:(QTCaptureFileOutput *)captureOutput shouldChangeOutputFileAtURL:(NSURL *)outputFileURL forConnections:(NSArray *)connections dueToError:(NSError *)error {
QTTime durationRecorded = [mCaptureMovieFileOutput recordedDuration];
NSString *outputDuration = QTStringFromTime(durationRecorded);
verbose("(capture output reached %s !)\n", [outputDuration UTF8String]);
[mCaptureMovieFileOutput recordToOutputFileURL:nil];
return YES;
}
The full code for this is here; https://github.com/matthutchinson/videosnap/blob/master/videosnap/videosnap.m
This code is part of a new open source command line app i'm working on VideoSnap. You can see the full source code, download and open it in xCode from GitHub
3 questions;
setMaximumRecordedDuration
to make this work for 5 secondsBelow is the pasted output from the above code;
(no filename specified, using default)
(no device specified, using default)
(options before recording)
delay: 0.00s
record: 10.00s
filename: movie.mov
device: Built-in iSight
(no delay)
(starting device...)
(recording for 10.00 seconds)
(recorded (null) - frameCount 0!)
(recorded (null) - frameCount 1!)
(recorded (null) - frameCount 2!)
(recorded (null) - frameCount 3!)
(recorded (null) - frameCount 4!)
(recorded (null) - frameCount 5!)
(recorded (null) - frameCount 6!)
(recorded (null) - frameCount 7!)
(recorded (null) - frameCount 8!)
(recorded (null) - frameCount 9!)
(recorded (null) - frameCount 10!)
(recorded (null) - frameCount 11!)
(recorded (null) - frameCount 12!)
(recorded (null) - frameCount 13!)
(recorded (null) - frameCount 14!)
(recorded (null) - frameCount 15!)
(recorded (null) - frameCount 16!)
(recorded (null) - frameCount 17!)
(recorded (null) - frameCount 18!)
(recorded (null) - frameCount 19!)
(recorded (null) - frameCount 20!)
(recorded (null) - frameCount 21!)
(recorded (null) - frameCount 22!)
(recorded (null) - frameCount 23!)
(recorded 0:00:00:00.00/1 - frameCount 24!)
(recorded 0:00:00:00.00/1 - frameCount 25!)
(recorded 0:00:00:00.00/1 - frameCount 26!)
(recorded 0:00:00:00.18000/30000 - frameCount 27!)
(recorded 0:00:00:00.18000/30000 - frameCount 28!)
(recorded 0:00:00:00.18000/30000 - frameCount 29!)
(recorded 0:00:00:00.20000/30000 - frameCount 30!)
(recorded 0:00:00:00.20000/30000 - frameCount 31!)
(recorded 0:00:00:00.20000/30000 - frameCount 32!)
(recorded 0:00:00:00.20000/30000 - frameCount 33!)
(recorded 0:00:00:00.22000/30000 - frameCount 34!)
(recorded 0:00:00:00.22000/30000 - frameCount 35!)
(recorded 0:00:00:00.22000/30000 - frameCount 36!)
(recorded 0:00:00:00.22000/30000 - frameCount 37!)
(recorded 0:00:00:00.24000/30000 - frameCount 38!)
(recorded 0:00:00:00.24000/30000 - frameCount 39!)
(recorded 0:00:00:00.24000/30000 - frameCount 40!)
(recorded 0:00:00:00.24000/30000 - frameCount 41!)
(recorded 0:00:00:00.26000/30000 - frameCount 42!)
(recorded 0:00:00:00.26000/30000 - frameCount 43!)
(recorded 0:00:00:00.26000/30000 - frameCount 44!)
(recorded 0:00:00:00.26000/30000 - frameCount 45!)
(recorded 0:00:00:00.28000/30000 - frameCount 46!)
(recorded 0:00:00:00.28000/30000 - frameCount 47!)
(recorded 0:00:00:00.28000/30000 - frameCount 48!)
(recorded 0:00:00:00.28000/30000 - frameCount 49!)
(recorded 0:00:00:01.00/30000 - frameCount 50!)
(recorded 0:00:00:01.00/30000 - frameCount 51!)
(recorded 0:00:00:01.00/30000 - frameCount 52!)
(recorded 0:00:00:01.00/30000 - frameCount 53!)
(recorded 0:00:00:01.00/30000 - frameCount 54!)
(recorded 0:00:00:01.00/30000 - frameCount 55!)
(recorded 0:00:00:01.00/30000 - frameCount 56!)
(recorded 0:00:00:01.4000/30000 - frameCount 57!)
(recorded 0:00:00:01.4000/30000 - frameCount 58!)
(recorded 0:00:00:01.4000/30000 - frameCount 59!)
(recorded 0:00:00:01.4000/30000 - frameCount 60!)
(recorded 0:00:00:01.6000/30000 - frameCount 61!)
(recorded 0:00:00:01.6000/30000 - frameCount 62!)
(recorded 0:00:00:01.6000/30000 - frameCount 63!)
(recorded 0:00:00:01.6000/30000 - frameCount 64!)
(recorded 0:00:00:01.8000/30000 - frameCount 65!)
(recorded 0:00:00:01.8000/30000 - frameCount 66!)
(recorded 0:00:00:01.8000/30000 - frameCount 67!)
(recorded 0:00:00:01.8000/30000 - frameCount 68!)
(recorded 0:00:00:01.10000/30000 - frameCount 69!)
(recorded 0:00:00:01.10000/30000 - frameCount 70!)
(recorded 0:00:00:01.10000/30000 - frameCount 71!)
(recorded 0:00:00:01.10000/30000 - frameCount 72!)
(recorded 0:00:00:01.12000/30000 - frameCount 73!)
(recorded 0:00:00:01.12000/30000 - frameCount 74!)
(recorded 0:00:00:01.12000/30000 - frameCount 75!)
(recorded 0:00:00:01.12000/30000 - frameCount 76!)
(recorded 0:00:00:01.14000/30000 - frameCount 77!)
(recorded 0:00:00:01.14000/30000 - frameCount 78!)
(recorded 0:00:00:01.14000/30000 - frameCount 79!)
(recorded 0:00:00:01.14000/30000 - frameCount 80!)
(recorded 0:00:00:01.16000/30000 - frameCount 81!)
(recorded 0:00:00:01.16000/30000 - frameCount 82!)
(recorded 0:00:00:01.16000/30000 - frameCount 83!)
(recorded 0:00:00:01.16000/30000 - frameCount 84!)
(recorded 0:00:00:01.16000/30000 - frameCount 85!)
(recorded 0:00:00:01.16000/30000 - frameCount 86!)
(recorded 0:00:00:01.16000/30000 - frameCount 87!)
(recorded 0:00:00:01.20000/30000 - frameCount 88!)
(recorded 0:00:00:01.20000/30000 - frameCount 89!)
(recorded 0:00:00:01.20000/30000 - frameCount 90!)
(recorded 0:00:00:01.20000/30000 - frameCount 91!)
(recorded 0:00:00:01.22000/30000 - frameCount 92!)
(recorded 0:00:00:01.22000/30000 - frameCount 93!)
(recorded 0:00:00:01.22000/30000 - frameCount 94!)
(recorded 0:00:00:01.22000/30000 - frameCount 95!)
(recorded 0:00:00:01.24000/30000 - frameCount 96!)
(recorded 0:00:00:01.24000/30000 - frameCount 97!)
(recorded 0:00:00:01.24000/30000 - frameCount 98!)
(recorded 0:00:00:01.24000/30000 - frameCount 99!)
(recorded 0:00:00:01.26000/30000 - frameCount 100!)
(recorded 0:00:00:01.26000/30000 - frameCount 101!)
(recorded 0:00:00:01.26000/30000 - frameCount 102!)
(recorded 0:00:00:01.26000/30000 - frameCount 103!)
(recorded 0:00:00:01.28000/30000 - frameCount 104!)
(recorded 0:00:00:01.28000/30000 - frameCount 105!)
(recorded 0:00:00:01.28000/30000 - frameCount 106!)
(recorded 0:00:00:01.28000/30000 - frameCount 107!)
(recorded 0:00:00:02.00/30000 - frameCount 108!)
(recorded 0:00:00:02.00/30000 - frameCount 109!)
(recorded 0:00:00:02.00/30000 - frameCount 110!)
(recorded 0:00:00:02.00/30000 - frameCount 111!)
(recorded 0:00:00:02.2000/30000 - frameCount 112!)
(recorded 0:00:00:02.2000/30000 - frameCount 113!)
(recorded 0:00:00:02.2000/30000 - frameCount 114!)
(recorded 0:00:00:02.2000/30000 - frameCount 115!)
(recorded 0:00:00:02.2000/30000 - frameCount 116!)
(recorded 0:00:00:02.2000/30000 - frameCount 117!)
(recorded 0:00:00:02.2000/30000 - frameCount 118!)
(recorded 0:00:00:02.6000/30000 - frameCount 119!)
(recorded 0:00:00:02.6000/30000 - frameCount 120!)
(recorded 0:00:00:02.6000/30000 - frameCount 121!)
(recorded 0:00:00:02.6000/30000 - frameCount 122!)
(recorded 0:00:00:02.8000/30000 - frameCount 123!)
(recorded 0:00:00:02.8000/30000 - frameCount 124!)
(recorded 0:00:00:02.8000/30000 - frameCount 125!)
(recorded 0:00:00:02.8000/30000 - frameCount 126!)
(recorded 0:00:00:02.10000/30000 - frameCount 127!)
(recorded 0:00:00:02.10000/30000 - frameCount 128!)
(recorded 0:00:00:02.10000/30000 - frameCount 129!)
(recorded 0:00:00:02.10000/30000 - frameCount 130!)
(recorded 0:00:00:02.12000/30000 - frameCount 131!)
(recorded 0:00:00:02.12000/30000 - frameCount 132!)
(recorded 0:00:00:02.12000/30000 - frameCount 133!)
(recorded 0:00:00:02.12000/30000 - frameCount 134!)
(recorded 0:00:00:02.14000/30000 - frameCount 135!)
(recorded 0:00:00:02.14000/30000 - frameCount 136!)
(recorded 0:00:00:02.14000/30000 - frameCount 137!)
(recorded 0:00:00:02.14000/30000 - frameCount 138!)
(recorded 0:00:00:02.16000/30000 - frameCount 139!)
(recorded 0:00:00:02.16000/30000 - frameCount 140!)
(recorded 0:00:00:02.16000/30000 - frameCount 141!)
(recorded 0:00:00:02.16000/30000 - frameCount 142!)
(recorded 0:00:00:02.18000/30000 - frameCount 143!)
(recorded 0:00:00:02.18000/30000 - frameCount 144!)
(recorded 0:00:00:02.18000/30000 - frameCount 145!)
(recorded 0:00:00:02.18000/30000 - frameCount 146!)
(recorded 0:00:00:02.18000/30000 - frameCount 147!)
(recorded 0:00:00:02.18000/30000 - frameCount 148!)
(recorded 0:00:00:02.18000/30000 - frameCount 149!)
(recorded 0:00:00:02.22000/30000 - frameCount 150!)
(recorded 0:00:00:02.22000/30000 - frameCount 151!)
(recorded 0:00:00:02.22000/30000 - frameCount 152!)
(recorded 0:00:00:02.22000/30000 - frameCount 153!)
(recorded 0:00:00:02.24000/30000 - frameCount 154!)
(recorded 0:00:00:02.24000/30000 - frameCount 155!)
(recorded 0:00:00:02.24000/30000 - frameCount 156!)
(recorded 0:00:00:02.24000/30000 - frameCount 157!)
(recorded 0:00:00:02.26000/30000 - frameCount 158!)
(recorded 0:00:00:02.26000/30000 - frameCount 159!)
(recorded 0:00:00:02.26000/30000 - frameCount 160!)
(recorded 0:00:00:02.26000/30000 - frameCount 161!)
(recorded 0:00:00:02.28000/30000 - frameCount 162!)
(recorded 0:00:00:02.28000/30000 - frameCount 163!)
(recorded 0:00:00:02.28000/30000 - frameCount 164!)
(recorded 0:00:00:02.28000/30000 - frameCount 165!)
(recorded 0:00:00:03.00/30000 - frameCount 166!)
(recorded 0:00:00:03.00/30000 - frameCount 167!)
(recorded 0:00:00:03.00/30000 - frameCount 168!)
(recorded 0:00:00:03.00/30000 - frameCount 169!)
(recorded 0:00:00:03.2000/30000 - frameCount 170!)
(recorded 0:00:00:03.2000/30000 - frameCount 171!)
(recorded 0:00:00:03.2000/30000 - frameCount 172!)
(recorded 0:00:00:03.2000/30000 - frameCount 173!)
(recorded 0:00:00:03.4000/30000 - frameCount 174!)
(recorded 0:00:00:03.4000/30000 - frameCount 175!)
(recorded 0:00:00:03.4000/30000 - frameCount 176!)
(recorded 0:00:00:03.4000/30000 - frameCount 177!)
(recorded 0:00:00:03.4000/30000 - frameCount 178!)
(recorded 0:00:00:03.4000/30000 - frameCount 179!)
(recorded 0:00:00:03.4000/30000 - frameCount 180!)
(recorded 0:00:00:03.8000/30000 - frameCount 181!)
(recorded 0:00:00:03.8000/30000 - frameCount 182!)
(recorded 0:00:00:03.8000/30000 - frameCount 183!)
(recorded 0:00:00:03.8000/30000 - frameCount 184!)
(recorded 0:00:00:03.10000/30000 - frameCount 185!)
(recorded 0:00:00:03.10000/30000 - frameCount 186!)
(recorded 0:00:00:03.10000/30000 - frameCount 187!)
(recorded 0:00:00:03.10000/30000 - frameCount 188!)
(recorded 0:00:00:03.12000/30000 - frameCount 189!)
(recorded 0:00:00:03.12000/30000 - frameCount 190!)
(recorded 0:00:00:03.12000/30000 - frameCount 191!)
(recorded 0:00:00:03.12000/30000 - frameCount 192!)
(recorded 0:00:00:03.14000/30000 - frameCount 193!)
(recorded 0:00:00:03.14000/30000 - frameCount 194!)
(recorded 0:00:00:03.14000/30000 - frameCount 195!)
(recorded 0:00:00:03.14000/30000 - frameCount 196!)
(recorded 0:00:00:03.16000/30000 - frameCount 197!)
(recorded 0:00:00:03.16000/30000 - frameCount 198!)
(recorded 0:00:00:03.16000/30000 - frameCount 199!)
(recorded 0:00:00:03.16000/30000 - frameCount 200!)
(recorded 0:00:00:03.18000/30000 - frameCount 201!)
(recorded 0:00:00:03.18000/30000 - frameCount 202!)
(recorded 0:00:00:03.18000/30000 - frameCount 203!)
(recorded 0:00:00:03.18000/30000 - frameCount 204!)
(recorded 0:00:00:03.20000/30000 - frameCount 205!)
(recorded 0:00:00:03.20000/30000 - frameCount 206!)
(recorded 0:00:00:03.20000/30000 - frameCount 207!)
(recorded 0:00:00:03.20000/30000 - frameCount 208!)
(recorded 0:00:00:03.20000/30000 - frameCount 209!)
(recorded 0:00:00:03.20000/30000 - frameCount 210!)
(recorded 0:00:00:03.20000/30000 - frameCount 211!)
(recorded 0:00:00:03.24000/30000 - frameCount 212!)
(recorded 0:00:00:03.24000/30000 - frameCount 213!)
(recorded 0:00:00:03.24000/30000 - frameCount 214!)
(recorded 0:00:00:03.24000/30000 - frameCount 215!)
(recorded 0:00:00:03.26000/30000 - frameCount 216!)
(recorded 0:00:00:03.26000/30000 - frameCount 217!)
(recorded 0:00:00:03.26000/30000 - frameCount 218!)
(recorded 0:00:00:03.26000/30000 - frameCount 219!)
(recorded 0:00:00:03.28000/30000 - frameCount 220!)
(recorded 0:00:00:03.28000/30000 - frameCount 221!)
(recorded 0:00:00:03.28000/30000 - frameCount 222!)
(recorded 0:00:00:03.28000/30000 - frameCount 223!)
(recorded 0:00:00:04.00/30000 - frameCount 224!)
(recorded 0:00:00:04.00/30000 - frameCount 225!)
(recorded 0:00:00:04.00/30000 - frameCount 226!)
(recorded 0:00:00:04.00/30000 - frameCount 227!)
(recorded 0:00:00:04.2000/30000 - frameCount 228!)
(recorded 0:00:00:04.2000/30000 - frameCount 229!)
(recorded 0:00:00:04.2000/30000 - frameCount 230!)
(recorded 0:00:00:04.2000/30000 - frameCount 231!)
(recorded 0:00:00:04.4000/30000 - frameCount 232!)
(recorded 0:00:00:04.4000/30000 - frameCount 233!)
(recorded 0:00:00:04.4000/30000 - frameCount 234!)
(recorded 0:00:00:04.4000/30000 - frameCount 235!)
(recorded 0:00:00:04.6000/30000 - frameCount 236!)
(recorded 0:00:00:04.6000/30000 - frameCount 237!)
(recorded 0:00:00:04.6000/30000 - frameCount 238!)
(recorded 0:00:00:04.6000/30000 - frameCount 239!)
(recorded 0:00:00:04.6000/30000 - frameCount 240!)
(recorded 0:00:00:04.6000/30000 - frameCount 241!)
(recorded 0:00:00:04.6000/30000 - frameCount 242!)
(recorded 0:00:00:04.10000/30000 - frameCount 243!)
(recorded 0:00:00:04.10000/30000 - frameCount 244!)
(recorded 0:00:00:04.10000/30000 - frameCount 245!)
(recorded 0:00:00:04.10000/30000 - frameCount 246!)
(recorded 0:00:00:04.12000/30000 - frameCount 247!)
(recorded 0:00:00:04.12000/30000 - frameCount 248!)
(recorded 0:00:00:04.12000/30000 - frameCount 249!)
(recorded 0:00:00:04.12000/30000 - frameCount 250!)
(recorded 0:00:00:04.14000/30000 - frameCount 251!)
(recorded 0:00:00:04.14000/30000 - frameCount 252!)
(recorded 0:00:00:04.14000/30000 - frameCount 253!)
(recorded 0:00:00:04.14000/30000 - frameCount 254!)
(recorded 0:00:00:04.16000/30000 - frameCount 255!)
(recorded 0:00:00:04.16000/30000 - frameCount 256!)
(recorded 0:00:00:04.16000/30000 - frameCount 257!)
(recorded 0:00:00:04.16000/30000 - frameCount 258!)
(recorded 0:00:00:04.18000/30000 - frameCount 259!)
(recorded 0:00:00:04.18000/30000 - frameCount 260!)
(recorded 0:00:00:04.18000/30000 - frameCount 261!)
(recorded 0:00:00:04.18000/30000 - frameCount 262!)
(recorded 0:00:00:04.20000/30000 - frameCount 263!)
(recorded 0:00:00:04.20000/30000 - frameCount 264!)
(recorded 0:00:00:04.20000/30000 - frameCount 265!)
(recorded 0:00:00:04.20000/30000 - frameCount 266!)
(recorded 0:00:00:04.22000/30000 - frameCount 267!)
(recorded 0:00:00:04.22000/30000 - frameCount 268!)
(recorded 0:00:00:04.22000/30000 - frameCount 269!)
(recorded 0:00:00:04.22000/30000 - frameCount 270!)
(recorded 0:00:00:04.22000/30000 - frameCount 271!)
(recorded 0:00:00:04.22000/30000 - frameCount 272!)
(recorded 0:00:00:04.22000/30000 - frameCount 273!)
(recorded 0:00:00:04.26000/30000 - frameCount 274!)
(recorded 0:00:00:04.26000/30000 - frameCount 275!)
(recorded 0:00:00:04.26000/30000 - frameCount 276!)
(recorded 0:00:00:04.26000/30000 - frameCount 277!)
(recorded 0:00:00:04.28000/30000 - frameCount 278!)
(recorded 0:00:00:04.28000/30000 - frameCount 279!)
(recorded 0:00:00:04.28000/30000 - frameCount 280!)
(recorded 0:00:00:04.28000/30000 - frameCount 281!)
(capture output reached 0:00:00:04.28000/30000 !)
(recorded 0:00:00:05.00/30000 - frameCount 282!)
(recorded 0:00:00:05.00/30000 - frameCount 283!)
(recorded 0:00:00:05.00/30000 - frameCount 284!)
(recorded 0:00:00:05.00/30000 - frameCount 285!)
(finished writing to movie file duration was 0:00:00:05.00/30000 !)
(stopping session)
(recording period ended)
DONE! movie.mov
So I basically figured it out (with some help from a another iOS/Obj-C developer);
There were 2 problems with my code;
I needed a proper run loop (outside the main thread) to be running so that I can start my capture session with the camera and not exit right away (or use a while loop). To do this I added the following at the end of my processArgs()
method
[[NSRunLoop currentRunLoop] run];
I discovered using QTTime objects to measure the amount of time I had recorded was more trouble than I needed to deal with, so instead I opted for a simple NSDate
object (called mRecordingStartedOnDate
). Also looking at my output it was clear that the session/camera take some time to warm up before capturing begins and the output is written to the file. So I check the recordedFileSize
on the file first, and start counting time from then. All this happens in my captureOutput delegate method like so;
- (void)captureOutput:(QTCaptureFileOutput *)captureOutput didOutputSampleBuffer:(QTSampleBuffer *)sampleBuffer fromConnection:(QTCaptureConnection *)connection {
// check we have started to record some bytes (this allows us to wait for camera to warm up and start capturing)
long recordedBytes = [mCaptureMovieFileOutput recordedFileSize];
if(mRecordingStartedOnDate != nil) {
// check if we have recorded enough video yet
float recordedSeconds = [[NSDate date] timeIntervalSinceDate:mRecordingStartedOnDate];
verbose("(recorded %f seconds)\n", recordedSeconds);
if(recordedSeconds >= 5.0) {
// stop recording to the file
[mCaptureMovieFileOutput recordToOutputFileURL:nil];
}
} else if(recordedBytes > 0) {
// set the start date when recording initiated
mRecordingStartedOnDate = [NSDate date];
}
}
I may refactor things, but the code for the current state of this project is here.
-- Thanks to Paul Tsochantaris for the help!