5

I had implemented the concept of AVCaptureSession for recording video.

-(void)startRecordingWithOrientation:(AVCaptureVideoOrientation)videoOrientation 
{

    AVCaptureConnection *videoConnection = [AVCamUtilities   
                                           connectionWithMediaType:AVMediaTypeVideo  
                                           fromConnections:[[self movieFileOutput] connections]];
    if ([videoConnection isVideoOrientationSupported])
        [videoConnection setVideoOrientation:videoOrientation];

    [[self movieFileOutput] startRecordingToOutputFileURL:[self outputFileURL]  
    recordingDelegate:self];
 } 

It is recording the video properly but the recording timer in not there on the screen. Anyone has an idea that how to show timer while making video.

Thanks in advance.

Kumar KL
  • 15,315
  • 9
  • 38
  • 60
Sudha Tiwari
  • 2,499
  • 26
  • 50

4 Answers4

8

I use add a UILabel to the view where is presented the video while is recording and I use this code to show the record time

@property (weak, nonatomic) IBOutlet UILabel *labelTime;

@property(nonatomic, strong) NSTimer *timer;
@property(nonatomic) int timeSec;
@property(nonatomic) int timeMin;

//Method to start recording

- (void)startRecord {
    self.timeMin = 0;
    self.timeSec = 0;

    //String format 00:00
    NSString* timeNow = [NSString stringWithFormat:@"%02d:%02d", self.timeMin, self.timeSec];
    //Display on your label
    //[timeLabel setStringValue:timeNow];
    self.labelTime.text= timeNow;

    self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerTick:) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode];

    //Start recording
    [movieFileOutput startRecordingToOutputFileURL:outputURL recordingDelegate:self];

}


//Event called every time the NSTimer ticks.
- (void)timerTick:(NSTimer *)timer {
    self.timeSec++;
    if (self.timeSec == 60)
    {
        self.timeSec = 0;
        self.timeMin++;
    }
    //String format 00:00
    NSString* timeNow = [NSString stringWithFormat:@"%02d:%02d", self.timeMin, self.timeSec];
    //Display on your label
    self.labelTime.text= timeNow;
}
Fran Martin
  • 2,369
  • 22
  • 19
  • 1
    as an FYI, keep in mind that `scheduledTimerWithTimeInterval` call will add `NSTimer` to a current runloop, so no need to manually add it later. – ymotov Aug 16 '16 at 17:45
  • @Fran Martin since I was using this in Swift I was using the wrong Timer method. I was using Timer(timeInterval:...) instead of Timer.scheduledTimer(). I eventually figured it out. Your answer works great!!! Thanks :) – Lance Samaria Mar 16 '18 at 14:50
8

The accepted answer from @Fran Martin works great!

Since i was using it in Swift it took me about an hour to figure out the correct Timer() function. To help the next person who isn't fluent in Objective C here's the Swift version of the accepted answer with some extra functions to invalidate the timer, to reset the timer back to 00:00, when to use it in viewWillAppear, and when to invalidate it

ALWAYS invalidate the timer in viewWillDisappear or viewDidDisappear otherwise if it is a repeat timer and it’s running you can get a memory leak

I had an unforeseen problem where the timer kept running even though I would stop it and I found this SO Answer that said you have to stop it before starting it again and when you declare the timer use weak

@IBOutlet weak fileprivate var yourLabel: UILabel!

var timeMin = 0
var timeSec = 0
weak var timer: Timer?

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    // if your presenting this vc yourLabel.txt will show 00:00
    yourLabel.txt = String(format: "%02d:%02d", timeMin, timeSec)
}

override func viewDidDisappear(_ animated: Bool) {
    super.viewDidDisappear(animated)

    resetTimerToZero()
}

// MARK:- recordButton
@IBAction fileprivate func recordButtonTapped(_ sender: UIButton) {

    startTimer()
    
    movieFileOutput.startRecording(to: videoUrl, recordingDelegate: self)
}

// MARK:- Timer Functions
fileprivate func startTimer(){
    
    // if you want the timer to reset to 0 every time the user presses record you can uncomment out either of these 2 lines

    // timeSec = 0
    // timeMin = 0

    // If you don't use the 2 lines above then the timer will continue from whatever time it was stopped at
    let timeNow = String(format: "%02d:%02d", timeMin, timeSec)
    yourLabel.txt = timeNow

    stopTimer() // stop it at it's current time before starting it again
    timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in
                self?.timerTick()
            }
}
    
@objc fileprivate func timerTick(){
     timeSec += 1
        
     if timeSec == 60{
         timeSec = 0
         timeMin += 1
     }
        
     let timeNow = String(format: "%02d:%02d", timeMin, timeSec)
        
     yourLabel.txt = timeNow
}

// resets both vars back to 0 and when the timer starts again it will start at 0
@objc fileprivate func resetTimerToZero(){
     timeSec = 0
     timeMin = 0
     stopTimer()
}

// if you need to reset the timer to 0 and yourLabel.txt back to 00:00
@objc fileprivate resetTimerAndLabel(){

     resetTimerToZero()
     yourLabel.txt = String(format: "%02d:%02d", timeMin, timeSec)
}

// stops the timer at it's current time
@objc fileprivate stopTimer(){

     timer?.invalidate()
     timer = nil
}
Lance Samaria
  • 17,576
  • 18
  • 108
  • 256
  • Hello @lance Samaria ,I have tried the same above method but in this , recording gets started first and after recording gets stopped timer gets started. Parallel both are to working together.Can you please help me out for this.Thanks in advance – puja Oct 23 '21 at 07:24
  • @puja It sounds like you’re starting the timer when the recording stops when instead you should be starting the timer when the recording starts and stop the timer when the the recording stops. It sounds likes you just have the code in the wrong place. You should slowly look through your code line by line. This is a simple a error. What you should do is c+p the above code exactly as it. Add a class `var isRecording = false`, when the button is tapped set it to true then start the timer, when you press it again set it to false and stop the timer. If it works then compare it to your other code – Lance Samaria Oct 23 '21 at 09:30
  • In the button simply check `if !isRecording { isRecording = true; startTimer() } else { isRecording = false ; stopTimer() }` – Lance Samaria Oct 23 '21 at 09:34
  • 1
    It's important that you set `timer = nil` in `stopTimer` after calling `invalidate`. This avoids the chance that `invalidate` could be called more than once on a timer. – HangarRash Jul 03 '23 at 21:07
  • @HangarRash You're correct, I forgot to add it. I've updated my answer, thanks :) – Lance Samaria Jul 04 '23 at 14:21
1

I am using Timer with swift5 and Xcode14.3.1

declare a var Timer and a count

var timer : Timer?
var count : Int = 0

call the following method when need to start the timer...

 func startTimer(){
        timer?.invalidate() 
        timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] timer in
            //do something with your timer
            print("Timer fired! \(self?.runCount)")
            self?.runCount += 1            
        }
    }

Note: always invalidate old timers before initializing the new timer ...if you initialize a new timer before deinitializing the old one you gonna lost the reference of old timer and that's gonna be a huge problem so be careful

call the following line whenever you want to stop the timer

timer?.invalidate()

you can also add logic to stop it after particular seconds or do something like the following...

 func startTimer(){
        timer?.invalidate()
        timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] timer in
            print("Timer fired! \(self?.runCount)")
            
            self?.runCount += 1
            if self?.runCount == 15 {
                timer.invalidate()
                timer = nil
                //do something 
            }
        }
Wahab Khan Jadon
  • 875
  • 13
  • 21
  • 1
    You need to set `timer = nil` after calling `invalidate` at the end of your second example. Otherwise if `startTimer` is called again, you end up trying to invalidate a timer that has already been invalidated and that can be a problem. – HangarRash Jul 03 '23 at 21:10
  • @HangarRash answer updated... – Wahab Khan Jadon Jul 04 '23 at 06:01
0

Remember the time (NSTimeInterval) when you started recording, save it in an instance variable, then calculate the difference to the current time (NSDate timeIntervalSinceReferenceDate) in a timer that fires twice per second or so, and display the resulting time in a UITextView?

To avoid drift, set the "fire time" on the Timer after every display and set it to how long until the next full second (or half second or however often) is away. That way, if e.g. displaying the time takes 0.1 seconds, the next fire time is more likely to be on a full second or so.

uliwitness
  • 8,532
  • 36
  • 58
  • I can do this but what about the default timer of camera? – Sudha Tiwari Mar 06 '14 at 10:42
  • You mean your camera shows the time as an on-screen display on its little monitor? That's a thing the camera does. It doesn't feed that out to you generally. You'll have to look in the camera's manual. – uliwitness Mar 06 '14 at 10:45
  • I don't think the callback that gives you a CVPixelBuffer includes the MPEG timestamp, in case that was what you're looking for. – uliwitness Mar 06 '14 at 10:52
  • I am not getting you. Do I have to make my custom timer. Can't we use camera default timer? – Sudha Tiwari Mar 06 '14 at 11:05