【问题标题】:AVPlayer stuck video, but audio worksAVPlayer 卡住视频,但音频有效
【发布时间】:2016-04-12 10:56:47
【问题描述】:

我去创建AVPlayerItemAVURLAsset,我的代码:

let asset = AVURLAsset(URL: safeURL, options: [AVURLAssetPreferPreciseDurationAndTimingKey: true])
    asset.loadValuesAsynchronouslyForKeys([assetKeyPlayable, self.assetKeyTracks, self.assetKeyHasProtectedContent]) {
        () -> Void in
        dispatch_async(dispatch_get_main_queue(), {
            () -> Void in
            // Use the AVAsset playable property to detect whether the asset can be played
            if !asset.playable {
                let localizedDescription = "Item cannot be played,Item cannot be played description"
                let localizedFailureReason = "The assets tracks were loaded, but could not be made playable,Item cannot be played failure reason"
                let userInfo = [NSLocalizedDescriptionKey: localizedDescription, NSLocalizedFailureReasonErrorKey: localizedFailureReason]
                let error = NSError(domain: "domain", code: 0, userInfo: userInfo)
                self.videoPlayerDelegate?.videoPlayer?(self, playerItemStatusDidFail: error)
                self.cleanPlayer()
                return
            }
            // At this point we're ready to set up for playback of the asset. Stop observing
            if let _ = self.player?.currentItem {
                self.cleanPlayer()
            }
            if asset.URL.absoluteString != safeURL.absoluteString {
                return
            }
            var error: NSError?
            let status = asset.statusOfValueForKey(self.assetKeyTracks, error: &error)
            var playerItem = AVPlayerItem(URL: safeURL)
            if status == .Loaded {
                playerItem = AVPlayerItem(asset: asset)
            } else {
                // You should deal with the error appropriately.If Loaded fails, create an AVPlayerItem directly from the URL
                playerItem = AVPlayerItem(URL: safeURL)
            }
            self.player = self.playerWithPlayerItem(playerItem)
            self.registerMonitoring()
            self.registerNotification()
            self.addTimeObserver()
            completionBlock?(loadURLString: playerURL.absoluteString)
        })
    }

在我的视图中添加AVPlayerLayer显示视频,我的代码:

// MARK: - 属性

var player: AVPlayer? {
    get {
        return playerLayer.player
    }

    set {
        playerLayer.player = newValue
    }
}

var playerLayer: AVPlayerLayer {
    return layer as! AVPlayerLayer
}

加载完成后显示视频时

self.videoPlayer?.loadPlayer({
        [weak self](loadURLString) in
        if let strongSelf = self {
            strongSelf.player = strongSelf.videoPlayer?.player
            strongSelf.startPlay()
        }
    })

调用seekToTime方法指定播放:

self.player?.currentItem?.seekToTime(CMTimeMakeWithSeconds(time, Int32(NSEC_PER_SEC)), toleranceBefore: kCMTimeZero, toleranceAfter: kCMTimeZero) {
        [weak self] finished in
        if let weakSelf = self {
            if weakSelf.isPlaying {
               weakSelf.videoPlayerDelegate?.videoPlayerDidplayerItemSeekToTime?(weakSelf)
            }
        }
    }

卡住界面的部分图片:

第一张图有声音,但是界面卡住了。

在第二张图片中,视频可以播放,但我没有声音。

我的问题:

完成后调用seekToTime方法时,有时视频有声音,但界面卡住,偶尔视频能正常播放。我尝试调用CALayersetNeedsDisplay 方法来更新AVPlayerLayer 图片,但这并没有帮助。我不知道该怎么办了,我会很感激每一个帮助。

【问题讨论】:

  • 香农;我不确定,但也许你的 AVURLAsset 超出了这里的范围; AVPlayer 是一段非常有弹性的代码;有时会让你悬而未决而不是在黑暗中。
  • 你应该做的是创建一个非常简单的演示项目,添加一些平淡无奇的资产,并在那里复制问题。您可以在 Dropbox 等上发布该项目,然后寻求帮助进行调试。

标签: ios objective-c swift video avfoundation


【解决方案1】:

尝试这种方法,因为我遇到了同样的问题并通过这种方法解决它。

player.pause()
player.currentItem?.seek(to: CMTime(), completionHandler: { (_) in
    player.play()
})

【讨论】:

    【解决方案2】:

    由于我们中的许多人以不同的方式发生这种情况并且没有得到回答,所以我在这里回答它,对我来说,当我尝试使用 AVPlayer 和 AVPlayerLayer 在 UIView 中播放视频时发生这种情况,但是当我使用相同的 AVPlayer 在 AVPlayerViewController 中加载视频,视频卡住了,音频继续播放。

    诀窍是在其他地方使用相同的 AVPlayer 之前销毁 AVPlayerLayer,不敢相信我在这里找到了这个启示。

    https://twitter.com/skumancer/status/294605708073263104

    我是如何实现的?

    我在主故事板上创建了 2 个视图控制器。

    1) 视图控制器场景 i)这有一个 UIView 引用 IBOutlet 'videoView' ii) 一个带有 segue 导航的按钮,用于“显示”AV 播放器视图控制器场景,引用 IBOutlet“全屏” 2) AV Player View Controller Scene

    // Code in your controller class.
    
    
    // Make sure to reference your IBOutlet in your StoryBoard.
    @IBOutlet weak var videoView : UIView!
    @IBOutlet weak var fullscreen : UIButton!
    
    var player:AVPlayer? = nil;
    var playerLayer:AVPlayerLayer? = nil;
    
    override func viewDidLoad() {
        super.viewDidLoad()
    
        // Your Url to play, could be hls type video
        let url = URL(string: "https://your_url.m3u8");
    
        let asset = AVAsset(url : url!)
    
        let playerItem = AVPlayerItem(asset: asset)
    
        player = AVPlayer(playerItem: playerItem)
    }
    
    
    override func viewDidAppear(_ animated: Bool) {
        playInUIView()
        pauseVideo()
    }
    
    // Creates An AVPlayerLayer and adds it as a sublayer in UIView.
    func playInUIView(){
        // Creating player layer to render video.
        playerLayer = AVPlayerLayer(player: player)
    
        playerLayer?.frame = self.videoView.bounds
    
        playerLayer?.videoGravity = .resizeAspect
    
        // Adding a sub layer to display it in UIView
        self.videoView.layer.addSublayer(playerLayer!)
    }
    
    // Destroyes an AVPlayerLayer and Sublayer of your UIView
    func destroyPlayInView(){
        self.videoView.layer.sublayers=nil
        playerLayer = nil
    }
        
    // On button click open AVPlayerViewController.
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        let destination = segue.destination as! AVPlayerViewController
    
        // Destroy AVPlayerLayer before rendering video in AVPlayerViewController.
        destroyPlayInView()
    
        // Set same AVPlayer in AVPlayerViewController.
        destination.player = self.player
    
        self.present(destination, animated: true) {
            destination.player!.play()
        }
    }

    PS - 我还没有实施任何控制,因为几天前我刚刚开始 swift 和 IOS 开发,所以可能存在编码不当,所以请让我知道我哪里错了。

    【讨论】:

    • 哇。我到处寻找解决方案。简单地将 avPlayerLayer 设置为 nil 对我有用。干得好,非常感谢你的分享。我将 avPlayerLayer 嵌入到 avPlayerViewConroller 到 UICollectionViewCell 中。我不敢相信这行得通。请注意,我在主线程等上运行所有东西,就像你应该做的那样。
    【解决方案3】:

    用户 nferocious76 的相同代码,但在 Objective C 中

    [self.player pause];
    AVPlayerItem *playerItem = [self.player currentItem];
    __weak typeof(self) weakSelf = self;
    [playerItem seekToTime:playerItem.currentTime completionHandler:^(BOOL finished){
        if (finished){   
            [weakSelf.player play];
        }
     }];
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多