使用HTTP Live Streaming方法播放实时流时,是否可以读取当前元数据(例如标题和艺术家)?这适用于iPhone收音机应用程序。
答案 0 :(得分:21)
不确定这个问题对于作者来说是否仍然存在,但可能对某些人有帮助。经过两天的痛苦,我调查了它很简单。以下是适用于我的代码:
AVPlayerItem* playerItem = [AVPlayerItem playerItemWithURL:[NSURL URLWithString:<here your http stream url>]];
[playerItem addObserver:self forKeyPath:@"timedMetadata" options:NSKeyValueObservingOptionNew context:nil];
AVPlayer* player = [[AVPlayer playerWithPlayerItem:playerItem] retain];
[player play];
然后:
- (void) observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object
change:(NSDictionary*)change context:(void*)context {
if ([keyPath isEqualToString:@"timedMetadata"])
{
AVPlayerItem* playerItem = object;
for (AVMetadataItem* metadata in playerItem.timedMetadata)
{
NSLog(@"\nkey: %@\nkeySpace: %@\ncommonKey: %@\nvalue: %@", [metadata.key description], metadata.keySpace, metadata.commonKey, metadata.stringValue);
}
}
}
就是这样。我不知道为什么Apple没有在AVPlayerItem的文档中提供这个样本来访问流的“标题”,这是现实世界流音频的关键特性。在“AV基础框架参考”中,他们告诉“timedMetadata”无处需要。 Matt的样本不适用于所有流(但AVPlayer会这样做)。
答案 1 :(得分:4)
在swift 2.0中获取元数据信息音乐流:
PlayerItem.addObserver(self, forKeyPath: "timedMetadata", options: NSKeyValueObservingOptions.New, context: nil)
添加此方法:
override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
//Atualiza Nome Musica
if keyPath == "timedMetadata" {
if let meta = PlayerItem.timedMetadata {
print("Novo Metadata \(meta)")
for metadata in meta {
if let nomemusica = metadata.valueForKey("value") as? String{
LB_NomeMusica.text = nomemusica
if NSClassFromString("MPNowPlayingInfoCenter") != nil {
let image:UIImage = UIImage(named: "logo.gif")!
let albumArt = MPMediaItemArtwork(image: image)
var songInfo: [String:AnyObject] = [
MPMediaItemPropertyTitle: nomemusica,
MPMediaItemPropertyArtist: "Ao Vivo",
MPMediaItemPropertyArtwork: albumArt
]
MPNowPlayingInfoCenter.defaultCenter().nowPlayingInfo = songInfo
}
}
}
}
}
}
答案 2 :(得分:1)
快速解决方案。这是简单的流音频播放器的示例。您可以使用委托AVPlayerItemMetadataOutputPushDelegate的方法读取元数据。
import UIKit
import AVFoundation
class PlayerViewController: UIViewController {
var player = AVPlayer()
override func viewDidLoad() {
super.viewDidLoad()
configurePlayer()
player.play()
}
private func configurePlayer() {
guard let url = URL(string: "Your stream URL") else { return }
let asset = AVAsset(url: url)
let playerItem = AVPlayerItem(asset: asset)
let metadataOutput = AVPlayerItemMetadataOutput(identifiers: nil)
metadataOutput.setDelegate(self, queue: DispatchQueue.main)
playerItem.add(metadataOutput)
player = AVPlayer(playerItem: playerItem)
}
}
extension PlayerViewController: AVPlayerItemMetadataOutputPushDelegate {
func metadataOutput(_ output: AVPlayerItemMetadataOutput, didOutputTimedMetadataGroups groups: [AVTimedMetadataGroup], from track: AVPlayerItemTrack?) {
let item = groups.first?.items.first
item?.value(forKeyPath: "value")
print(item!.value(forKeyPath: "value")!)
}
}
答案 3 :(得分:0)
确实如此,但这并不容易。 Matt Gallagher有关于流音频的nice post on his blog。引用他的话题:
最简单的元数据来源 来自HTTP标头。在 - 的里面 handleReadFromStream:事件类型: 方法,使用CFReadStreamCopyProperty 复制 kCFStreamPropertyHTTPResponseHeader 来自CFReadStreamRef的属性, 然后你可以使用 CFHTTPMessageCopyAllHeaderFields到 将标题字段复制出来 响应。对于许多流媒体音频 服务器,流名称是其中之一 这些领域。
相当难的来源 元数据是ID3标签。 ID3v1是 总是在文件的末尾(所以 流媒体时无用)。 ID3v2是 位于开头可能更多 访问。
我从来没有读过ID3标签,但是我 怀疑如果你缓存第一个 几百千字节的文件 在加载的某个地方,打开缓存 使用AudioFileOpenWithCallbacks和 然后读取kAudioFilePropertyID3Tag 您可以使用AudioFileGetProperty 能够读取ID3数据(如果它 存在)。就像我说的那样:我 从来没有真正这样做,所以我不这样做 确定它会起作用。