iOS内嵌播放视图到View实现单帧控制(Swift)

3 篇文章 0 订阅

把播放视图内嵌到View,官方文档上已经有了比较好的说明,继承UIView 设置Layer层,然后把AVPlayer设置到AVPlayerLayer即可:

import UIKit
import AVFoundation

public class DOVPlayerView: UIView {

    /*
    // Only override draw() if you perform custom drawing.
    // An empty implementation adversely affects performance during animation.
    override func draw(_ rect: CGRect) {
        // Drawing code
    }
    */

    public var player:AVPlayer?{
        get{
            return playerLayer.player
        }
        set{
            playerLayer.player = newValue
        }
    }

    public var playerLayer:AVPlayerLayer {
        return layer as! AVPlayerLayer
    }

    override public class var layerClass: AnyClass {
        return AVPlayerLayer.self
    }
}

在storyboard中绘制视图的时候,直接拖入一个UIView,然后修改为继承的playerView即可,如下图所示:
PlayerView

要实现单帧控制也很简单,AVPlayerItem中有一个step(stepCount: Int)的函数,stepCount为前进或者后退的帧数,设置为正整数则前进,负整数则后退:

    //前后移动一帧
    public func reverseOneFrame() -> CMTime{

        self.getPlayerItem()?.step(byCount: 1)
        return self.getCurrentTime()
    }

    public func forwardOneFrame() -> CMTime{

        self.getPlayerItem()?.step(byCount: -1)
        return self.getCurrentTime()
    }

然后当直接调用AVPlayer的seek(to:CMTime)操作的时候,会发现无法seek到设置的位置上,可改为如下操作,即可正确的seek到设定的位置:

    //seek
    public func seekToTime(time:CMTime){
        self.seek(to: time, toleranceBefore: kCMTimeZero, toleranceAfter: kCMTimeZero)
    }

当素材在播放的时候,我想要实时的获取到播放的当前位置,并做对应的同步处理,这里可以设置一个定时器来实时的触发消息通知,将获取到的当前素材播放位置通知出去,操作如下:

fileprivate var timer: Timer?

extension AVPlayer : DOVPlayerProtocol{

    //发送通知
    public func postCurrentTime(){
        let currentTime = CMTimeGetSeconds(self.currentTime())
        NotificationCenter.default.post(name: PlaybackCurrentTimeChangeNotifaction, object: self, userInfo: ["currentTime": currentTime])
    }

    //播放控制
    public func startPlay(){
        if self.status == AVPlayerStatus.readyToPlay && (self.currentItem?.status)! == AVPlayerItemStatus.readyToPlay{
            self.play()
            //设置定时器:50ms
            timer = Timer.scheduledTimer(timeInterval: 0.05, target: self, selector: #selector(self.postCurrentTime), userInfo: nil, repeats: true)
        }
    }

因为扩展了AVPlayer类来继承相应的协议,在扩展中不能定义存储属性,所以定义在了类外,加上fileprivate表示只能在该文件类访问。
接收通知的代码可以做如下操作:

class ViewController: UIViewController {

    @IBOutlet weak var playerView: DOVPlayerView!

    @IBOutlet weak var playOrPauseButton: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        let url = Bundle.main.url(forResource:"Movie", withExtension: "m4v")
        let video = AVURLAsset(url: url!)

        let playerItem = AVPlayerItem(asset: video)


        let player = DOVPlayer(playerItem: playerItem)

        playerView.player = player

        NotificationCenter.default.addObserver(self, selector: #selector(self.printNotification(notification:)), name: PlaybackCurrentTimeChangeNotifaction, object: nil)
    }

    func printNotification(notification:Notification){
        let userInfo = notification.userInfo as! [String : AnyObject]
        let time = userInfo["currentTime"] as! Double
        print(time)
    }

当素材播放的时候就会每隔50ms通知一次当前位置,其他对象可以接收该通知,并做相应的处理。
运行界面如下:
运行界面

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值