【问题标题】:Why AVPlayer downloading first instead live streaming?为什么AVPlayer先下载而不是直播?
【发布时间】:2017-05-23 09:48:17
【问题描述】:

我第一次使用 AVPlayer,我想使用带有实时流的 HTTP 请求播放 mp3 文件。我使用AVPlayer 可以正常播放mp3 文件,但问题是AVPlayer 需要先下载mp3 然后播放。我不知道为什么AVPlayer 下载文件然后播放而不是现场播放。我的 Xcode 8.2.1 和我正在使用 Swift 3。

这是我的代码 sn-p。

var audioPlayer = AVPlayer()
var avplayerItem : AVPlayerItem?

override func viewDidLoad() {
    super.viewDidLoad()

    let fileurl:URL = URL(string : "http://www.noiseaddicts.com/samples_1w72b820/2514.mp3")!
    avplayerItem = AVPlayerItem(url : fileurl)
    audioPlayer = AVPlayer(playerItem : avplayerItem)
    audioPlayer.rate = 1.0
    audioPlayer.play()
}

如果AVPlayer需要在播放前下载整个文件,音频直播应该怎么做?

谢谢。

【问题讨论】:

  • 直播需要服务器支持 - 至少能够进行部分下载。其他播放器是否允许使用该 URL 进行直播?
  • 你怎么知道AVPlayer正在下载整个文件?
  • 首先它花费了太多时间来播放,在此期间播放器当前项目当前时间为0。当它开始播放时,如果我关闭互联网连接它仍然播放到结束。跨度>
  • 这里有同样的问题,有更新吗?

标签: swift avplayer live-streaming http-live-streaming


【解决方案1】:

另外编辑:Luaan 也是对的。 “直播需要服务器支持 - 至少能够进行部分下载。其他播放器是否允许使用该 URL 进行直播?”您还应该尝试使用未定义持续时间的声音 url。

您是否尝试过将其视为未定义持续时间的音频流?

  avplayerItem = CachingPlayerItem(url: url, recordingName: recordingName ?? "default.mp3")

CachingPlayerItem 将从 url 准备一个 AVURLAsset。

 init(url: URL, customFileExtension: String?, recordingName: String) {
    guard let components = URLComponents(url: url, resolvingAgainstBaseURL: false),
    let scheme = components.scheme,
    var urlWithCustomScheme = url.withScheme(cachingPlayerItemScheme) else {
    fatalError("Urls without a scheme are not supported")
    }
    self.recordingName = recordingName
    self.url = url
    self.initialScheme = scheme
    if let ext = customFileExtension {
    urlWithCustomScheme.deletePathExtension()
    urlWithCustomScheme.appendPathExtension(ext)
    self.customFileExtension = ext
    }
    let asset = AVURLAsset(url: urlWithCustomScheme)
    asset.resourceLoader.setDelegate(resourceLoaderDelegate, queue: DispatchQueue.main)
    super.init(asset: asset, automaticallyLoadedAssetKeys: nil)
    resourceLoaderDelegate.owner = self
    addObserver(self, forKeyPath: "status", options: NSKeyValueObservingOptions.new, context: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(playbackStalledHandler), name:NSNotification.Name.AVPlayerItemPlaybackStalled, object: self)
    }

在 AVPlayerItem 初始化后,从它创建一个 AVPlayer 对象,以便它可以启动从给定 url 加载音频流的过程:

player = AVPlayer(playerItem: playerItem)
player.automaticallyWaitsToMinimizeStalling = false

func resourceLoader(_ resourceLoader: AVAssetResourceLoader, shouldWaitForLoadingOfRequestedResource loadingRequest: AVAssetResourceLoadingRequest) -> Bool {
if playingFromData {
// Nothing to load.
} else if session == nil {
// If we're playing from a url, we need to download the file.
// We start loading the file on first request only.
guard let initialUrl = owner?.url else {
fatalError("internal inconsistency")
}
startDataRequest(with: initialUrl)
}
pendingRequests.insert(loadingRequest)
processPendingRequests()
return true
}

安装资源后:

func startDataRequest(with url: URL) {
var recordingName = "default.mp3"
if let recording = owner?.recordingName{
recordingName = recording
}
fileURL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
.appendingPathComponent(recordingName)
let configuration = URLSessionConfiguration.default
configuration.requestCachePolicy = .reloadIgnoringLocalAndRemoteCacheData
session = URLSession(configuration: configuration, delegate: self, delegateQueue: nil)
session?.dataTask(with: url).resume()
outputStream = OutputStream(url: fileURL, append: true)
outputStream?.schedule(in: RunLoop.current, forMode: RunLoopMode.defaultRunLoopMode)
outputStream?.open()
}

然后,开始将数据字节接收到委托函数中:

func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data)

现在您已经开始接收实时音频流了。

func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
let bytesWritten = data.withUnsafeBytes{outputStream?.write($0, maxLength: data.count)}
print("bytes written :\(bytesWritten!) to \(fileURL)")
}

现在创建一个 OutputStream 对象,打开它,然后在上面的委托函数中附加我们接收到的字节,就是这样,我们保存了实时音频流的所需部分。

取自:Medium Article, Mohan Pandey

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-03-04
    • 2012-11-10
    • 1970-01-01
    • 1970-01-01
    • 2018-11-17
    • 2021-05-03
    • 1970-01-01
    相关资源
    最近更新 更多