Created
March 31, 2016 01:47
-
-
Save tobins/ca1bcde437870ef9662447e8e47c9de9 to your computer and use it in GitHub Desktop.
MP4 loading & playing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// 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)) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// 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