将CMTime转换为人类可读的时间(在Objective-C中)

26

我有一个视频的CMTime。如何将它转换为像“照片”应用程序中视频时间持续标签中那样的漂亮字符串?是否有一些方便的方法可以处理这个问题?谢谢。

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

41
你也可以使用这个方法将视频时长以文本格式获取,如果你不需要日期格式。
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];

1
dTotalSeconds % 3600 % 60 还等同于 dTotalSeconds % 60 :) - Ja͢ck

18

总有办法解决的 ;)

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)
        }
    }
}

使用

videoPlayer?.addPeriodicTimeObserverForInterval(CMTime(seconds: 1, preferredTimescale: 1), queue: dispatch_get_main_queue()) { time in
    print(time.durationText)
}

13

您可以使用CMTimeCopyDescription,它的效果非常好。

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

编辑:好的,我太快阅读了问题,这不是你想要的,但是对于调试可能仍然有帮助。

编辑:如@bcattle评论所述,我建议的实现在ARC下存在内存泄漏。这里是已更正的版本:

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

1
太好了!非常适合简单的调试,还有CMTimeRangeCopyDescription,谢谢! - Firula
3
太好了!有一个小更新,需要进行桥接广播:(NSString*)CFBridgingRelease(CMTimeCopyDescription(NULL, self.player.currentTime)) - bcattle

12

基于上面的问题和评论,这是简明扼要的:

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];

2
我已经进行了一些性能测试,使用NSDateFormatter比使用NSString stringWithFormat慢120倍(来自ceekay的答案)。 - Animal Mother
3
因为您不应该反复创建格式化程序,它们的创建成本很高。只需创建一次并保留即可。 - uchuugaka

7

基于Swift 3.0和iOS 10的答案,参考codingrhythm的回答...

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)
    }
  }
}

7

我使用的简单扩展可以显示视频文件的时长。

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)
        }
    }
}

5

Swift 4.2 扩展

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)
    }
}

4
例如,您可以使用NSDate及其描述方法。您可以指定任何输出格式。
> ` 
// 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];`

2
首先,使用NSDate* d = [[NSDate alloc] initWithTimeIntervalSinceNow:seconds];创建NSDate对象; 然后指定输出格式 NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; [dateFormatter setDateFormat:@"HH:mm:ss"]; 最后用NSString* result = [dateFormatter stringWithDate:d];获取输出结果。 - Andreyz4k
谢谢。它有效了,我在最后一个方法中使用了stringFromDate,但问题是时间持续了4.168334,但输出是0:36:15... 我错过了什么吗? - randomor
因此,我最终使用NSDate* d = [NSDate dateWithTimeIntervalSince1970:audioDurationSeconds]; //Then specify output format NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; [dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:@"UTC"]]; [dateFormatter setDateFormat:@"HH:mm:ss"]; 设置时区和更改到1973的引用似乎可以工作。但是如果我不想在小时数前有多余的零呢? - randomor
你应该从日期格式设置中仅移除“HH”,因为它是指小时数字。 - Andreyz4k
应该使用stringFromDate。stringWithDate不存在 :) - Predrag Manojlovic

1

这里是从CMTime获取秒数的代码

NSLog(@"seconds = %f", CMTimeGetSeconds(cmTime));

0

Swift 3:

let time = kCMTimeZero
let timeString = time.toString() 

1
你能详细解释一下吗? - Adrian
1
请使用[编辑]链接来解释这段代码的工作原理,而不仅仅是提供代码,因为解释更有可能帮助未来的读者。另请参见[答案]。来源 - Jed Fox

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接