解决腾讯pag不能播放线上资源

2023年 10月 8日 62.5k 0

前言

PAG 是腾讯多媒体技术委员会下 AVGenerator Oteam开源协同小组自主研发的一套完整的动效工作流解决方案,和业界常用的动效工作流解决方案相比,PAG支持的 AE 特性更多,覆盖的平台更广(Android、iOS、Web、macOS、Windows和Linux),性能方面也做了深层次的优化,支持文本和占位图编辑替换,可以与视频编辑场景紧密结合。

PAG的优势

这里简单总结一下PAG的优势

1. 相同动效相对Lottie体积更小

image.png

2. 支持文本和占位图的编辑和替换

目前,绝大部分的视频编辑App,在贴纸字幕这块的实现都分为两种类型,要么贴纸有丰富的动效,但不可编辑;要么可以编辑文本,但只有静态或者简单的动效,大大束缚了设计师,降低了视频的整体观感。而PAG方案让贴纸有精美动效的前提下,还可以保持强大的编辑性,让使用者的个性化元素得到更好的呈现。

3. 支持播放声音

4. 性能更好

基于 C++ 和 OpenGL 硬件加速渲染,除了能做到两端渲染完全一致外,应用了游戏渲染里的大量的优化经验,从中间渲染数据到局部位图的多级缓存架构,每帧渲染耗时平均可以做到Lottie的50%左右。

已应用的部分软件

image.png

问题和解决方案

目前官方的libpag库只支持播放本地PAG资源,不支持网络PAG资源,为此这里提供一个可播放网络PAG资源的方案LXYPAGPlayerSDK

核心代码

1. 使用

1.1 创建LXYPAGView

 lazy var pagView :LXYPAGView = {
        let pagView = LXYPAGView()
        return pagView
    }()

1.2 播放线上资源

 //MARK: - 播放线上资源
    private func playOnlineResource(){
        let config = LXYPAGConfig()
        config.resourceStr =  "http://xxx.pag"
        pagView.frame = CGRect(x: 0, y: 0, width: 300, height: 300)
        self.pagView.playAnim(config)
    }

2. LXPAGView内部实现

2.1 public func playAnim(_ config: LXYPAGConfig)方法中通过判断config.resourceStr是否以http开头判断是否是网络资源,如果是本地资源则调用 playLocalPathAnim(config)播放。,如果没有则进入网络下载环节

 if config.resourceStr.hasPrefix("http") == false {
           //本地数据
           playLocalPathAnim(config)
           return
       }

2.2 如果传入的config.resourceStr是网络地址,则通过缓存单例LXYPAGCacheManager查询本地是否已经有缓存数据

let cacheKey =  LXYPAGCacheManager.shareInstance.cacheKey(config.resourceStr)
      let cachePath = LXYPAGCacheManager.shareInstance.filepath(cacheKey)
      if cachePath.count > 0 && FileManager.default.fileExists(atPath: cachePath) {
          //本地有则拿本地数据进行播放
          config.resourceStr = cachePath
          playLocalPathAnim(config)
          return
      }

2.3 本地查询没有缓存怎进入下载环节

LXYPAGManager.shareInstance.downloader.loadData(config.resourceStr) { locationPath, err in
            if err != nil {
                self.delegate?.playErroronView(self, err)
                return
            }
            guard let locationPath = locationPath else{
                return
            }
            do{
                let targetPath = try LXYPAGCacheManager.shareInstance.moveTempData((locationPath as NSURL).path, cacheKey)
                if let targetPath = targetPath{
                    config.resourceStr = targetPath
                    self.playLocalPathAnim(config)
                }
            }catch let error{
                self.delegate?.playErroronView(self, error as NSError)
            }
        }
        
    }
    

2.4 playLocalPathAnim(_ config: LXYPAGConfig)实现

   //MARK: - 播放PAG
    private func playLocalPathAnim(_ config: LXYPAGConfig){
        if isPlaying() {
            stopPlay()
        }
        let path = config.resourceStr
        if path.count == 0 || FileManager.default.fileExists(atPath: path) == false {
            let error = NSError.localResourceNotExist(path)
            delegate?.playErroronView(self, error)
            return
        }
        pagFile = PAGFile.load(path)
        //动态替换资源,未实现
        pagView.setProgress(0)
        customizePlay()
        //播放音效,未实现
        pagView.play()
        //第一次播放时检查缓存大小,如果超出则删除
        if checkLocalCaches {
            LXYPAGCacheManager.shareInstance.removeFolderIfExceedsSize()
            checkLocalCaches = true
        }
    }
    

3. LXYDownloader里的下载逻辑

3.1 根据传入的url去队列中查询该下载路径下的下载任务是否已经存在队列中,如果存在再不重新发起网络请求,只是把这次请求的回调downloadCallback存放到队列queue中

    guard let url = URL(string: urlStr) else {
            let error = NSError.pathNotFound(urlStr)
            downloadCallback?(nil,error)
            return nil
        }
        let questTask = queue.queryTask(urlStr)
        if let questTask = questTask {
            //在下载队列中找到对应的下载请求
            if let downloadCallback = downloadCallback {
                queue.updateQueueItemCallback(urlStr, callback: downloadCallback)
            }
            return questTask
        }
    

3.2 下载完成后通过url去查询callbacks并让对应的quesTastTask出列

     let requestTask = self.session.downloadTask(with: url) {
            [weak self] (localPath, respon, error ) in
            guard let self = self else {
                return
            }
                var err: NSError?
                if let respon = respon as? HTTPURLResponse{
                    let statusCode = respon.statusCode
                    if statusCode  300 {
                        err = NSError.downloadStatueError(urlStr, statueCode: statusCode)
                        
                    }
                }
            let callbacks = queue.dequeueCallback(urlStr)
            guard let callbacks = callbacks else {
                return
            }
                for itemCallback in callbacks{

                    itemCallback(localPath,err)
                }
            
        }
    

常用使用场景介绍

创建LXYPAGView

 lazy var pagView :LXYPAGView = {
        let pagView = LXYPAGView()
        return pagView
    }()
  • 播放线上资源
  •  //MARK: - 播放线上资源
        private func playOnlineResource(){
            let config = LXYPAGConfig()
            config.resourceStr =  "http://xxx.pag"
            pagView.frame = CGRect(x: 0, y: 0, width: 300, height: 300)
            self.pagView.playAnim(config)
        }
    
  • 区间播放
  •     //MARK: - 区间播放
        private func playInFrame(){
            let config = LXYPAGConfig()
            if let path = Bundle.main.path(forResource: "like", ofType: ".pag") {
                config.resourceStr = path
                config.InFramePlayRange = NSRange(location: 30, length: 100)
            }
            pagView.frame = CGRect(x: 0, y: 0, width: 300, height: 300)
            self.pagView.playAnim(config)
        }
    
  • 循环+变速播放
  •     private func playInFrame(){
            let config = LXYPAGConfig()
            if let path = Bundle.main.path(forResource: "login_page_animation", ofType: ".pag") {
                config.resourceStr = path
                config.speed = 2
                config.loop = 0
            }
            pagView.frame = CGRect(x: 0, y: 0, width: 300, height: 300)
            self.pagView.playAnim(config)
        }
    

    主要流程

    whiteboard_exported_image.png

    githut地址

    github.com/liang152091…

    引用文章

    baijiahao.baidu.com/s?id=167924…
    baijiahao.baidu.com/s?id=167843…

    相关文章

    服务器端口转发,带你了解服务器端口转发
    服务器开放端口,服务器开放端口的步骤
    产品推荐:7月受欢迎AI容器镜像来了,有Qwen系列大模型镜像
    如何使用 WinGet 下载 Microsoft Store 应用
    百度搜索:蓝易云 – 熟悉ubuntu apt-get命令详解
    百度搜索:蓝易云 – 域名解析成功但ping不通解决方案

    发布评论