原因
If the AVPlayer's current item is displaying video on the device's display, playback of the AVPlayer is automatically paused when the app is sent to the background.
参考:Playing media while in the background using AV Foundation on iOS
一般情况下不会有有黑屏,但是因为这个原因导致可能会发生。我们的App里有openGL的使用,导致性能消耗过大,当退回到后台后系统会释放AVPlayer的资源,所以再次返回的时候会出现短暂的黑屏。
我们的App有一个更加严重的问题,当一个视频播放完之后会停留在当前页面,退回后台再返回会明显黑屏。(如果是视频播放中的话系统会重新加载资源,黑屏时间是短暂发生,但是视频播放完会长期黑屏)
一般解决方式
目前暂时没有好的办法,苹果有两个推荐方案,但是不太试用于我们项目。如下:
- Disable the video tracks in the player item (file-based content only).
- Remove the
AVPlayerLayer
from its associated AVPlayer (set the AVPlayerLayer player property to nil).
Disabling the video tracks in the player item
import AVFoundation
let playerItem = <#Your player item#>
let tracks = playerItem.tracks
for playerItemTrack in tracks {
// Find the video tracks.
if playerItemTrack.assetTrack.hasMediaCharacteristic(AVMediaCharacteristicVisual) {
// Disable the track.
playerItemTrack.isEnabled = false
}
}
Remove/Restore the AVPlayerLayer and its associated AVPlayer
import UIKit
import AVFoundation
...
// A `UIView` subclass that is backed by an `AVPlayerLayer` layer.
class PlayerView: UIView {
var player: AVPlayer? {
get {
return playerLayer.player
}
set {
playerLayer.player = newValue
}
}
var playerLayer: AVPlayerLayer {
return layer as! AVPlayerLayer
}
override class var layerClass: AnyClass {
return AVPlayerLayer.self
}
}
...
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
@IBOutlet weak var playerView: PlayerView!
/*
Remove the AVPlayerLayer from its associated AVPlayer
once the app is in the background.
*/
func applicationDidEnterBackground(_ application: UIApplication) {
// Remove the player.
playerView.player = nil
}
// Restore the AVPlayer when the app is active again.
func applicationDidBecomeActive(_ application: UIApplication) {
// Restore the player.
playerView.player = <#Your player#>
}
}
方法一比较通用。方法二只能作用于本地视频。
最终解决方式
我们采用了截屏的方式,截取最后一帧放到PlayerView上,遮挡黑屏
附上截屏方法:
extension AVPlayer {
func getPlayerScreenShot(screenSize: CGSize, callback: @escaping (UIImage?) ->Void) {
//1. 获取当前时间
let currentTime = self.currentTime().value / 1000
if currentTime < 1 {
callback(nil)
return
}
guard let urlAsset = currentItem?.asset else {
callback(nil)
return
}
//2. 截图配置
let generator = AVAssetImageGenerator(asset: urlAsset)
generator.appliesPreferredTrackTransform = true
generator.maximumSize = screenSize
generator.requestedTimeToleranceBefore = .zero
generator.requestedTimeToleranceAfter = .zero
//3. 分段截图时间数组
var times: [NSValue] = []
let timeM = CMTimeMake(value: currentTime, timescale: self.currentTime().timescale)
let timeV = NSValue(time: timeM)
times.append(timeV)
//4. 开始截图
generator.generateCGImagesAsynchronously(forTimes: times) {
(requestedTime, cgimage, actualTime, result, error) in
switch result {
case .cancelled, .failed: callback(nil)
case .succeeded:
guard let image = cgimage else {
callback(nil)
return
}
let displayImage = UIImage(cgImage: image)
callback(displayImage)
}
}
}
}
网友评论