I am working on a little app to navigate and play videos which includes framerate and initial timecode information (eg: "TimeCode" : "09:25:15:08"
). I am using the AVKit Player View Controller
to display my video, and I would like to add a UILabel displaying the current timecode.
I'm all set about the way to add up custom UI elements, but I'm lost about how to calculate the timecode
and make it update itself every frame the video plays.
I have read about the AVFoundation - Timecode Support with AVAssetWriter and AVAssetReader, but I'm not sure if I have understood it.
Any explanations, guidance, or content to look at would be really appreciated.
UPDATE:
After thinking for a while, I though that I could use the frame count to build up my own timecode references.
note item is the AVPlayer
using var totalTime = CMTimeGetSeconds(item.currentItem.asset.duration)
I can get the total length in seconds of the video track, and currentTime = CMTimeGetSeconds(item.currentItem.currentTime())
to get its current time position.
Then I can do var fps = item.currentItem.asset.tracks[0].nominalFrameRate
to get the framerate and use this variable to divide totalTime
and currentTime
to get the total frame count as well as the current frame.
With this im considering the idea of building up a pre normalized array of time in second for each frame from the total frame count. this way I could know what exact frame is related to a time stamp.
I never had to work with timecode or dates so if someone has an idea about the way to do this I would appreciate the help.
basically, a timecode looks like this: HH:MM:SS:FF
(FF being the current frame).
If the fps = 24, then every 24 frames a second is added to the SS and so on.
TEST CASE:
import UIKit
import AVKit
import AVFoundation
class ViewController: UIViewController {
var player = AVPlayer()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
var url=NSURL(string: "http://km.support.apple.com/library/APPLE/APPLECARE_ALLGEOS/HT1211/sample_iTunes.mov")
player = AVPlayer(URL: url)
let playerController = AVPlayerViewController()
playerController.player = player
self.addChildViewController(playerController)
self.view.addSubview(playerController.view)
playerController.view.frame = self.view.frame
//Debug btn
var btn = UIButton()
btn.frame = CGRect(x:10, y:50, width:100, height:30)
btn.setTitle("FPS", forState: .Normal)
btn.addTarget(self, action: "buttonTapAction:", forControlEvents: UIControlEvents.TouchUpInside)
playerController.view.addSubview(btn)
player.play()
// getFps(player)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func getFps(item:AVPlayer) {
var fps = item.currentItem.asset.tracks[0].nominalFrameRate
println("FPS: \(fps)")
var timeRange_src = CMTimeGetSeconds(item.currentItem.asset.duration)
var timeRange = Float(timeRange_src)
println("time Range: \(timeRange)")
var frameCount = timeRange * fps
println("total frames: \(frameCount)")
var timeIs = Float(CMTimeGetSeconds(item.currentItem.currentTime()))
var frameIs = timeIs * fps
println("current time: \(timeIs)")
println("current frame: \(frameIs)")
}
func buttonTapAction(sender:UIButton!)
{
getFps(player)
}
}
ok so here is how I solved my problem and built the timecode based on the variables I had:
func pad(fps:Float, currentFrame:Float) -> (String){
var fps = fps
var frame = currentFrame + f
var ff = frame % fps
var seconds = s + ((currentFrame) / fps)
var ss = seconds % 60
var minutes = m + ((seconds - ss) / 60)
var mm = minutes % 60
var hh = h + ((minutes - mm) / 60)
return "\(showTwoDigits(hh)):\(showTwoDigits(mm)):\(showTwoDigits(ss)):\(showTwoDigits(ff))"
}
func showTwoDigits(number:Float) -> (String){
var string = ("00" + String(format:"%.f", number))
var range = Range(start: (advance(string.endIndex, -2)), end: string.endIndex)
var cutStr = string.substringWithRange(range)
return cutStr
}