I'm trying to duplicate this https://jmacmullin.wordpress.com/2010/11/03/adding-meta-data-to-video-in-ios/ in swift.
Here is a video of Jake's code in action...
Objective C Timed Metadat in HLS stream
Here is an additional link to something similar...
http://cloudfields.net/blog/metadata-audiostream-mpmovieplayercontroller/
When my video is playing timed metadata should update a button to redirect to a specific youtube url in a webview when clicked. My video is roughly 15 min long and has 6 timed metadata urls.
I can't find any code or documentation anywhere on how to achieve this in Swift. I've managed to convert Jake's Objective C code for his Notification call.
// Register for meta-data notifications
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:self
selector:@selector(metadataUpdate:)
name:MPMoviePlayerTimedMetadataUpdatedNotification
object:nil];
to Swift Code
NSNotificationCenter.defaultCenter().addObserver(
self,
selector: "metadataUpdated",
name: MPMoviePlayerTimedMetadataUpdatedNotification,
object: nil)
Jake's Function
Actor *actor = [[Actor alloc] init];
if ([player timedMetadata]!=nil && [[player timedMetadata] count] > 0) {
for (MPTimedMetadata *metadata in [player timedMetadata]) {
if ([[metadata.allMetadata valueForKey:@"key"] isEqualToString:@"TPE1"]) {
[actor setName:[metadata.allMetadata objectForKey:@"value"]];
}
if ([[metadata.allMetadata valueForKey:@"key"] isEqualToString:@"WXXX"]) {
NSURL *url = [NSURL URLWithString:[metadata.allMetadata objectForKey:@"value"]];
[actor setProfileURL:url];
}
}
}
// display some UI element for the user to interact with
to Swift
func metadataUpdated (notification: NSNotification!) {
if moviePlayer?.timedMetadata != nil && moviePlayer?.timedMetadata.count > 0 {
for MPTimedMetadata in [moviePlayer?.timedMetadata] {
if MPTimedMetadata?.description == ("TPE1") {
let name = ("value")
}
if MPTimedMetadata?.description == ("WXXX") {
var url = NSURL.observeValueForKeyPath("value")
}
}
}
println("Things are kind of working")
}
}
For the life of me though I cant figure out how to turn the metadata into any actionable code. I really need to create a button that redirects to the URL carried in the metadata, but can't convert it to a String. Any help is greatly appreciated. Here is what i have so far.
import UIKit
import MediaPlayer
class ViewController: UIViewController {
var moviePlayer: MPMoviePlayerController?
var youtube = ""
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let url = NSURL(string: "http://path/to/video.m3u8")
moviePlayer = MPMoviePlayerController(contentURL: url)
if let player = moviePlayer {
player.view.frame = CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: self.view.frame.size.height)
player.view.sizeToFit()
player.scalingMode = MPMovieScalingMode.None
player.movieSourceType = MPMovieSourceType.Streaming
//player.repeatMode = MPMovieRepeatMode.One
player.play()
self.view.addSubview(player.view)
NSNotificationCenter.defaultCenter().addObserver(
self,
selector: "metadataUpdated:",
name: MPMoviePlayerTimedMetadataUpdatedNotification,
object: nil)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func metadataUpdated (notification: NSNotification!) {
if moviePlayer?.timedMetadata != nil && moviePlayer?.timedMetadata.count > 0 {
for MPTimedMetadata in [moviePlayer?.timedMetadata] {
if MPTimedMetadata?.description == ("TPE1") {
let name = ("value")
}
if MPTimedMetadata?.description == ("WXXX") {
var url = NSURL.observeValueForKeyPath("value")
}
}
}
println("Things are kind of working")
}
}
So I got this to work, but ended up ditch MPMovieController opting for AVPlayer. Here is my code, and the link to another post that helped me get it functional.
Timed Metadata with AVPlayer
import UIKit
import MediaPlayer
import AVFoundation
var youtubeRequest: NSURLRequest! = nil
var player : AVPlayer? = nil
var url:NSString!
class ViewController: UIViewController {
var moviePlayer: MPMoviePlayerController?
var movieItem: AVPlayerItem!
var Player: AVPlayer!
var playerLayer : AVPlayerLayer? = nil
var asset : AVAsset? = nil
var playerItem: AVPlayerItem!
var youtubeRequest: NSURLRequest! = nil
@IBOutlet var playButtonOutlet: UIBarButtonItem!
@IBAction func playButtonAction(sender: AnyObject) {player?.play()
playButtonOutlet.enabled = false
}
@IBOutlet var videoView: UIView!
@IBAction func loadURL(sender: AnyObject) {player?.pause()
playButtonOutlet.enabled = true
}
@IBOutlet var urlButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
urlButton.enabled = false
let videoURL = NSURL(string: "http://path/to/video.m3u8")
playButtonOutlet.enabled = false
movieItem = AVPlayerItem(URL: NSURL(string: "http://path/to/video.m3u8"))
movieItem.addObserver(self, forKeyPath: "timedMetadata", options: nil, context: nil)
Player = AVPlayer(playerItem: movieItem)
var metaArray: Array<Any> = [moviePlayer?.timedMetadata]
asset = AVAsset.assetWithURL(videoURL) as? AVAsset
playerItem = AVPlayerItem(asset: asset)
playerItem = AVPlayerItem(URL: NSURL(string: "http://path/to/video.m3u8"))
playerItem.addObserver(self, forKeyPath: "timedMetadata", options: nil, context: nil)
playerItem.addObserver(self, forKeyPath: "presentationSize", options: nil, context: nil)
player = AVPlayer(playerItem: playerItem)
playerLayer = AVPlayerLayer(player: player)
playerLayer!.frame = videoView.bounds
videoView.layer.addSublayer(self.playerLayer)
player!.play()
NSNotificationCenter.defaultCenter().addObserver(
self,
selector: "rotated",
name: UIDeviceOrientationDidChangeNotification,
object: nil)
}
override func observeValueForKeyPath(keyPath: String, ofObject object: AnyObject, change: [NSObject : AnyObject], context: UnsafeMutablePointer<Void>) -> Void {
if keyPath != "timedMetadata" { return }
var data: AVPlayerItem = object as AVPlayerItem
var urlError = false
for item in data.timedMetadata as [AVMetadataItem] {
println(item.stringValue)
var metaArray: Array<Any> = [playerItem?.timedMetadata]
println("Total objects in array \(metaArray[0])")
var data = item.stringValue
url = NSString(string: data) as NSString!
if url != nil {
urlButton.enabled = true
println("The url is \(url)")
} else {
urlError = true
}
var urlRedirect = NSURL(fileURLWithPath: "\(url)")
println("The url is \(urlRedirect)")
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func rotated()
{
if(UIDeviceOrientationIsLandscape(UIDevice.currentDevice().orientation))
{
self.navigationController?.navigationBarHidden = true
playerLayer?.frame = CGRectMake(0,0,self.view.frame.size.width,self.view.frame.size.height)
playerLayer?.frame = CGRectMake(0,0,self.view.frame.size.width,self.view.frame.size.height)
println("landscape")
}
if(UIDeviceOrientationIsPortrait(UIDevice.currentDevice().orientation))
{
self.navigationController?.navigationBarHidden = false
playerLayer!.frame = videoView.bounds
println("portraight")
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With