26

So I have a CMTime from a video. How do I convert it into a nice string like in the video time duration label in the Photo App. Is there some convenience methods that handle this? Thanks.

AVURLAsset* videoAsset = [AVURLAsset URLAssetWithURL:url options:nil];
CMTime videoDuration = videoAsset.duration;
float videoDurationSeconds = CMTimeGetSeconds(videoDuration);
randomor
  • 5,329
  • 4
  • 46
  • 68

11 Answers11

41

You can use this as well to get a video duration in a text format if you dont require a date format

AVURLAsset *videoAVURLAsset = [AVURLAsset assetWithURL:url];
CMTime durationV = videoAVURLAsset.duration;

NSUInteger dTotalSeconds = CMTimeGetSeconds(durationV);

NSUInteger dHours = floor(dTotalSeconds / 3600);
NSUInteger dMinutes = floor(dTotalSeconds % 3600 / 60);
NSUInteger dSeconds = floor(dTotalSeconds % 3600 % 60);

NSString *videoDurationText = [NSString stringWithFormat:@"%i:%02i:%02i",dHours, dMinutes, dSeconds];
ceekay
  • 1,167
  • 1
  • 10
  • 14
18

There is always an extension ;)

import CoreMedia

extension CMTime {
    var durationText:String {
        let totalSeconds = Int(CMTimeGetSeconds(self))
        let hours:Int = Int(totalSeconds / 3600)
        let minutes:Int = Int(totalSeconds % 3600 / 60)
        let seconds:Int = Int((totalSeconds % 3600) % 60)

        if hours > 0 {
            return String(format: "%i:%02i:%02i", hours, minutes, seconds)
        } else {
            return String(format: "%02i:%02i", minutes, seconds)
        }
    }
}

to use

videoPlayer?.addPeriodicTimeObserverForInterval(CMTime(seconds: 1, preferredTimescale: 1), queue: dispatch_get_main_queue()) { time in
    print(time.durationText)
}
andesta.erfan
  • 972
  • 2
  • 12
  • 30
codingrhythm
  • 1,456
  • 14
  • 26
13

You can use CMTimeCopyDescription, it work really well.

NSString *timeDesc = (NSString *)CMTimeCopyDescription(NULL, self.player.currentTime);
NSLog(@"Description of currentTime: %@", timeDesc);

edit: okay, i read the question too fast, this is not what your wanted but could be helpful anyway for debuging.

edit: as @bcattle commented, the implementation i suggested contain a memory leak with ARC. Here the corrected version :

NSString *timeDesc = (NSString *)CFBridgingRelease(CMTimeCopyDescription(NULL, self.player.currentTime));
NSLog(@"Description of currentTime: %@", timeDesc);
Lifely
  • 1,035
  • 12
  • 22
  • 1
    Yes! perfect for simple debbugging, and CMTimeRangeCopyDescription too, thanks! – Firula Oct 22 '12 at 20:40
  • 3
    This is great! Minor update, need to do a bridged cast: `(NSString*)CFBridgingRelease(CMTimeCopyDescription(NULL, self.player.currentTime))` – bcattle May 20 '14 at 23:05
12

Based on combination of the question and comments above, this is concise:

AVURLAsset* videoAsset = [AVURLAsset URLAssetWithURL:url options:nil];
CMTime videoDuration = videoAsset.duration;
float videoDurationSeconds = CMTimeGetSeconds(videoDuration);

NSDate* date = [NSDate dateWithTimeIntervalSince1970:videoDurationSeconds];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:@"UTC"]];
[dateFormatter setDateFormat:@"HH:mm:ss"];  //you can vary the date string. Ex: "mm:ss"
NSString* result = [dateFormatter stringFromDate:date];
Brody Robertson
  • 8,506
  • 2
  • 47
  • 42
  • 2
    I've done some performance testing and using the NSDateFormatter is 120 times slower than using NSString stringWithFormat (ceekay's answer). – Animal Mother Nov 19 '14 at 19:22
  • 3
    Because you should not repeatedly create formatters. They're expensive to create. Create it once and keep it around. – uchuugaka Sep 23 '16 at 23:38
7

Swift 3.0 ios 10 answer based codingrhythm answer...

extension CMTime {
var durationText:String {
    let totalSeconds = CMTimeGetSeconds(self)
    let hours:Int = Int(totalSeconds / 3600)
    let minutes:Int = Int(totalSeconds.truncatingRemainder(dividingBy: 3600) / 60)
    let seconds:Int = Int(totalSeconds.truncatingRemainder(dividingBy: 60))

    if hours > 0 {
        return String(format: "%i:%02i:%02i", hours, minutes, seconds)
    } else {
        return String(format: "%02i:%02i", minutes, seconds)
    }
  }
}
Community
  • 1
  • 1
user3069232
  • 8,587
  • 7
  • 46
  • 87
7

Simple extension I use for displaying video file duration.

import CoreMedia

extension CMTime {
    var stringValue: String {
        let totalSeconds = Int(self.seconds)
        let hours = totalSeconds / 3600
        let minutes = totalSeconds % 3600 / 60
        let seconds = totalSeconds % 3600 % 60
        if hours > 0 {
            return String(format: "%i:%02i:%02i", hours, minutes, seconds)
        } else {
            return String(format: "%02i:%02i", minutes, seconds)
        }
    }
}
Timur Bernikovich
  • 5,660
  • 4
  • 45
  • 58
5

Swift 4.2 extension

extension CMTime {
    var timeString: String {
        let sInt = Int(seconds)
        let s: Int = sInt % 60
        let m: Int = (sInt / 60) % 60
        let h: Int = sInt / 3600
        return String(format: "%02d:%02d:%02d", h, m, s)
    }
    
    var timeFromNowString: String {
        let d = Date(timeIntervalSinceNow: seconds)
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "mm:ss"
        return dateFormatter.string(from: d)
    }
}
Community
  • 1
  • 1
Nike Kov
  • 12,630
  • 8
  • 75
  • 122
4

For example you can use NSDate and it's description method. You can specify any output format you want.

> ` 
// First, create NSDate object using 
NSDate* d = [[NSDate alloc] initWithTimeIntervalSinceNow:seconds]; 
// Then specify output format 
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; [dateFormatter setDateFormat:@"HH:mm:ss"]; 
// And get output with 
NSString* result = [dateFormatter stringWithDate:d];`
Mohd Sadham
  • 435
  • 3
  • 19
Andreyz4k
  • 116
  • 4
  • 2
    First, create NSDate object using `NSDate* d = [[NSDate alloc] initWithTimeIntervalSinceNow:seconds];` Then specify output format `NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; [dateFormatter setDateFormat:@"HH:mm:ss"];` And get output with `NSString* result = [dateFormatter stringWithDate:d];` – Andreyz4k May 18 '12 at 15:08
  • Thanks. it works, I used stringFromDate for the last method, but the problem is the time duration was 4.168334, yet the output is 0:36:15... Did I miss something? – randomor May 18 '12 at 15:38
  • So I eventually use `NSDate* d = [NSDate dateWithTimeIntervalSince1970:audioDurationSeconds]; //Then specify output format NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; [dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:@"UTC"]]; [dateFormatter setDateFormat:@"HH:mm:ss"];` Setting the timeZone and changing the reference to 1973 seems to work. But what if I don't want the redundant zeros for the hours? – randomor May 18 '12 at 18:49
  • You should just remove HH from setting date format, they go for the hour numbers. – Andreyz4k May 19 '12 at 08:32
  • stringFromDate should be used. stringWithDate doesn't exists :) – Predrag Manojlovic May 22 '16 at 21:58
1

here is the code for getting seconds from cmtime

NSLog(@"seconds = %f", CMTimeGetSeconds(cmTime));
Asad Amodi
  • 136
  • 4
  • 13
0

Swift 3:

let time = kCMTimeZero
let timeString = time.toString() 
  • 1
    Can you expound a little bit? – Adrian May 23 '17 at 19:43
  • 1
    Please use the [edit] link to explain how this code works and don't just give the code, as an explanation is more likely to help future readers. See also [answer]. [source](http://stackoverflow.com/users/5244995) – Jed Fox May 23 '17 at 21:14
0

A simplest way (without using NSDate and NSDateFormatter) to do this:-

Using Swift:-

        func updateRecordingTimeLabel()
        {

    // Result Output = MM:SS(01:23) 
    let cmTime = videoFileOutput.recordedDuration
                    var durationInSeconds = Int(CMTimeGetSeconds(cmTime))
                    let durationInMinutes = Int(CMTimeGetSeconds(cmTime)/60)
                    var strDuMin = String(durationInMinutes)

                    durationInSeconds = durationInSeconds-(60*durationInMinutes)
                    var strDuSec = String(durationInSeconds)

                    if durationInSeconds < 10
                    {
                        strDuSec = "0"+strDuSec
                    }
                    if durationInMinutes < 10
                    {
                        strDuMin = "0"+strDuMin
                    }
    // Output string
     let str_output = strDuMin+":"+strDuSec
print("Result Output : [\(str_output)]")

}
Ravi Sharma
  • 975
  • 11
  • 29