Skip to content

Instantly share code, notes, and snippets.

@tobins
Created March 31, 2016 01:47
Show Gist options
  • Save tobins/ca1bcde437870ef9662447e8e47c9de9 to your computer and use it in GitHub Desktop.
Save tobins/ca1bcde437870ef9662447e8e47c9de9 to your computer and use it in GitHub Desktop.
MP4 loading & playing
//
// MP4View.swift
//
// Created by Tobin Schwaiger-Hastanan on 3/25/16.
// Copyright © 2016 Tobin Schwaiger-Hastanan. All rights reserved.
//
import UIKit
import AVFoundation
class MP4View: UIView {
var repeatObserver:NSObjectProtocol? = nil
var operation:MP4ViewOperation? = nil
static var operationQueue:NSOperationQueue = {
let queue = NSOperationQueue()
queue.maxConcurrentOperationCount = 1
return queue
}()
lazy var player: AVPlayer = {
let player = AVPlayer()
player.muted = true
player.actionAtItemEnd = AVPlayerActionAtItemEnd.None
player.addObserver(self, forKeyPath: "currentItem", options: [.New, .Initial], context: nil)
return player
}()
lazy var playerLayer: AVPlayerLayer = {
let playerLayer = AVPlayerLayer(player:self.player)
playerLayer.videoGravity = AVLayerVideoGravityResizeAspect
return playerLayer
}()
init(asset:AVAsset) {
super.init(frame: CGRectZero)
initialize()
play(asset)
}
override init(frame: CGRect) {
super.init(frame: frame)
initialize()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
initialize()
}
deinit {
if let observer = self.repeatObserver {
NSNotificationCenter.defaultCenter().removeObserver(observer)
}
self.player.removeObserver(self, forKeyPath: "currentItem")
}
func initialize() {
self.repeatObserver = NSNotificationCenter.defaultCenter().addObserverForName(AVPlayerItemDidPlayToEndTimeNotification, object: self.player.currentItem, queue: nil, usingBlock: { (notification) in
if let playerItem = notification.object as? AVPlayerItem {
playerItem.seekToTime(kCMTimeZero)
}
})
self.layer.addSublayer(self.playerLayer)
}
func play(asset:AVAsset) {
let queue = MP4View.operationQueue
self.clear()
self.operation = MP4ViewOperation(asset:asset, player: self.player, queue:queue)
queue.addOperation(self.operation!)
}
func cancel() {
if let operation = self.operation {
self.operation = nil
operation.cancel()
}
}
func clear() {
self.player.replaceCurrentItemWithPlayerItem(nil)
}
override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
if object!.isKindOfClass(AVPlayer.self) {
if let player:AVPlayer = object as? AVPlayer {
if player.status == AVPlayerStatus.ReadyToPlay {
dispatch_async( dispatch_get_main_queue(), {
player.play()
let animation = CABasicAnimation(keyPath: "opacity")
animation.fromValue = 0
animation.toValue = 1.0
animation.repeatCount = 0
animation.duration = 0.15
self.playerLayer.addAnimation(animation, forKey: "playerOpacity")
})
}
}
}
}
override func layoutSubviews() {
super.layoutSubviews()
self.playerLayer.frame = CGRectMake(0, 0, CGRectGetWidth(self.frame), CGRectGetHeight(self.frame))
}
}
//
// MP4ViewOperation.swift
//
// Created by Tobin Schwaiger-Hastanan on 3/30/16.
// Copyright © 2016 Tobin Schwaiger-Hastanan. All rights reserved.
//
import UIKit
import AVFoundation
class MP4ViewOperation: NSOperation {
// initialized properties
let asset:AVAsset
let player:AVPlayer
let queue:NSOperationQueue
init(asset:AVAsset, player:AVPlayer, queue:NSOperationQueue) {
self.asset = asset
self.player = player
self.queue = queue
}
override func main() {
if self.cancelled {
return
}
self.queue.suspended = true
self.loadValuesAsynchronously(asset, keys: ["duration", "tracks", "playable"])
}
func loadValuesAsynchronously(asset:AVAsset, keys:[String]) {
asset.loadValuesAsynchronouslyForKeys(keys, completionHandler: {
var loaded = true
for key in keys {
var error: NSError?
let status = asset.statusOfValueForKey(key, error:&error)
if status == .Failed || status == .Cancelled {
loaded = false
} else if status == .Loading {
loaded = false
self.loadValuesAsynchronously(asset, keys: keys)
}
}
if loaded {
if self.cancelled {
self.queue.suspended = false
return
}
let playerItem = AVPlayerItem(asset: asset)
dispatch_async( dispatch_get_main_queue(), {
self.player.replaceCurrentItemWithPlayerItem(playerItem)
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(0.15 * Double(NSEC_PER_SEC))), dispatch_get_main_queue(), {
self.queue.suspended = false
})
})
}
})
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment