这些PAG常用方法解读也能帮助大家使用起来更轻松:
(资料图)
PAG 运行时编辑
PAG 的运行时编辑主要分为两类:1)修改文本图层的文本信息、替换图片图层中的占位图、修改实色图层中的颜色
//C++std::shared_ptrReplaceImageOrText() {autopagFile=pag::PAGFile::Load("../../assets/test2.pag");if(pagFile==nullptr){returnnullptr;}for(inti=0;inumImages();i++){autopagImage=pag::PAGImage::FromPath("../../assets/scene.png");pagFile->replaceImage(i,pagImage);}for(inti=0;inumTexts();i++){autotextDocumentHandle=pagFile->getTextData(i);textDocumentHandle->text="hah哈哈哈哈哈";pagFile->replaceText(i,textDocumentHandle);}returnpagFile;}
2)渲染树编辑
渲染树编辑指的是通过使用 PAGComposition 的相关接口,完成多个图层、多个 pag 文件的自由组合。具体如何使用可以参考下面的代码:
//以OC版本为例-(PAGComposition*)makeComposition{PAGComposition*compostion=[PAGCompositionMake:self.view.bounds.size];floatitemWidth=self.view.bounds.size.width/5;floatitemHeight=100;for(inti=0;i<20;i++){PAGFile*pagFile=[selfgetPAGFile:i/5clume:i%5name:[NSStringstringWithFormat:@"%d",i]itemWidth:itemWidthitemHeight:itemHeight];[compostionaddLayer:pagFile];}returncompostion;}-(PAGFile*)getPAGFile:(int)rowclume:(int)columename:(NSString*)nameitemWidth:(float)itemWidthitemHeight:(float)itemHeight{PAGFile*pagFile=[PAGFileLoad:[[NSBundlemainBundle]pathForResource:nameofType:@"pag"]];if(pagFile){floatscaleX=itemWidth*1.0f/[pagFilewidth];CGAffineTransformtransform=CGAffineTransformMakeScale(scaleX,scaleX);CGAffineTransformtranflate=CGAffineTransformMakeTranslation(itemWidth*colume,row*itemHeight+150);transform=CGAffineTransformConcat(transform,tranflate);[pagFilesetMatrix:transform];[pagFilesetStartTime:0];[pagFilesetDuration:10000000];}returnpagFile;}
PAG UI场景及列表播放
当一个页面中含有多个pag 文件时,如果使用多个 PAGView,由于每一个 PAGView 都需要一个独立的渲染环境,内存和 CPU 占用相对较高,推荐的处理方法有两种:
1)通过使用 PAG 的组合模式用将多个 PAG 文件添加到同一个 PAGComposition 中,具体使用方法见运行时编辑,从而将多个渲染环境缩减到一个渲染环境,降低内存和 CPU 占用;
2)对于一些 UI 列表场景,需要有多个 View 的存在, pag 文件无法添加到一个 PAGComposition 中,此时可以使用 PAGImageView。
//以OC版本为例#import#defineWIDTH100@interfacePAGCell:UITableViewCell@property(nonatomic,strong)PAGImageView*pagImageView;@property(nonatomic,strong)NSString*filePath;@end@implementationPAGCell-(instancetype)initWithStyle:(UITableViewCellStyle)stylereuseIdentifier:(NSString*)reuseIdentifier{if(self=[superinitWithStyle:stylereuseIdentifier:reuseIdentifier]){self.pagImageView=[[PAGImageViewalloc]initWithFrame:CGRectMake(20,0,WIDTH,WIDTH)];[self.contentViewaddSubview:self.pagImageView];}returnself;}-(void)setFilePath:(NSString*)filePath{if([filePathlength]>0){[self.pagImageViewsetPath:filePath];[self.pagImageViewsetCurrentFrame:0];[self.pagImageViewsetRepeatCount:-1];[self.pagImageViewplay];}}
PAG 字体注册
PAG 除了支持修改文本图层的文本信息外,还支持修改字体。具体方法如下:
(1)通过 PAGFont 获取字体的相关信息,然后赋值给 PAGText,使用到的接口如下:
获取字体信息
//C++/***Registersafontrequiredbythetextlayersinpagfiles,sothattheycanberenderedas*designed.*/staticPAGFontRegisterFont(conststd::string&fontPath,intttcIndex,conststd::string&fontFamily="",conststd::string&fontStyle="");/***Registersafontrequiredbythetextlayersinpagfiles,sothattheycanberenderedas*designed.*/staticPAGFontRegisterFont(constvoid*data,size_tlength,intttcIndex,conststd::string&fontFamily="",conststd::string&fontStyle="");PAGFont(std::stringfontFamily,std::stringfontStyle):fontFamily(std::move(fontFamily)),fontStyle(std::move(fontStyle)){}/***Astringwiththenameofthefontfamily.**/conststd::stringfontFamily;/***Astringwiththestyleinformation—e.g.,“bold”,“italic”.**/conststd::stringfontStyle;
(2)fontFamlily 和 fontStyle 赋值给 PAGText,PAGText 再填充到 PAGTextLayer 中。
//C++for(inti=0;inumTexts();i++){autotextDocumentHandle=pagFile->getTextData(i);textDocumentHandle->text="hah哈哈哈哈哈";//UsespecialfontautopagFont=pag::PAGFont::RegisterFont("../../resources/font/NotoSansSC-Regular.otf",0);textDocumentHandle->fontFamily=pagFont.fontFamily;textDocumentHandle->fontStyle=pagFont.fontStyle;pagFile->replaceText(i,textDocumentHandle);}
如果使用了特定字体而又没有注册或字体文件中没有包含该字符,PAG 内部(Android、iOS、macOS、Windows 平台)有一个默认字体列表(同时支持外部设置字体回退列表,外部设置时会覆盖默认设置),会回退到 PAG 的默认字体列表中,此时使用那种字体对于业务方而言是不确定的。
//C++/***Resetsthefallbackfontnames.Itshouldbecalledonlyoncewhentheapplicationisbeing*initialized.*/staticvoidSetFallbackFontNames(conststd::vector&fontNames);/***Resetsthefallbackfontpaths.Itshouldbecalledonlyoncewhentheapplicationisbeing*initialized.*/staticvoidSetFallbackFontPaths(conststd::vector&fontPaths,conststd::vector&ttcIndices);
PAG 视频编辑场景
在视频编辑场景,使用的不是 PAGView,而是 PAGPlayer、PAGSurface 和 PAGComposition。
PAGSurface 可以通过 CVPixelBufferRef 或纹理创建,方便快捷的与视频后编辑中的 CVPixelBuffer 或 纹理进行整合。同时 PAGImage 也支持通过 CVPixelBufferRef 或 纹理创建,通过 PAGPlayer 控制播放进度,将视频内容填充进图片图层的占位图。
//OC/***CreatesaPAGImageobjectfromthespecifiedCVPixelBuffer,returnnulliftheCVPixelBufferis*invalid.*/+(PAGImage*)FromPixelBuffer:(CVPixelBufferRef)pixelBuffer;//javapublicstaticPAGImageFromTexture(inttextureID,inttextureTarget,intwidth,intheight);publicstaticPAGImageFromTexture(inttextureID,inttextureTarget,intwidth,intheight,booleanflipY);
PAG 软解注入
为什么会有软解注入?PAG 的导出方式中支持 BMP 预合成导出,在 pag 文件中,如果含有 BMP 预合成,一个 BMP 预合成相当于一个视频,视频则需要解码。在 PAG SDK 中默认使用硬件解码,但硬件解码存在两个问题:
1)移动端硬件解码器的瞬时存在数目是有限制的,不能无限的创建,如果创建硬件解码器的数目超过限制,就会出现解码器创建失败的情况,在视频编辑场景中需要关注;
2)Android 平台由于机型兼容性、碎片化验证,不能保证所有的机型都能硬件解码成功,因此 Android 平台软解是必须的。
于是,在提供的制品库中, iOS 平台由于没有兼容性的问题,默认是不带软解的,Android 提供了两个包,普通的包默认是内置软解的,noffavc 的包是没有内置软解的。
具体怎么注入软解呢:Android 平台可以选择完整制品库,iOS 平台可以引入 ffavc。
pod"ffavc"
通过如下方法完成软件解码器的注册:
//OC-(void)registerSoftwareDecoder{//注册软件解码器工厂指针autofactory=ffavc::DecoderFactory::GetHandle();[PAGVideoDecoderRegisterSoftwareDecoderFactory:(void*)factory];}
如果接入方自己的 APP 中已经内置了软解库,可以通过外部注入的方式注入软解。
PAG 官网提供了下面这个软解注入接口,需要业务方基于自己的解码器实现,PAG BMP 预合成中的视频编码格式为 h264。
https://github.com/libpag/ffavc/blob/main/vendor/libpag/include/pag/decoder.h
具体的实现方式可以参考:
ffavc/FFAVCDecoder.cpp at main · libpag/ffavc · GitHub
然后自己通过上面提到的方式注入软解。
PAG 服务端渲染
和 Lottie、SVGA 不同的是,PAG 支持服务端渲染,尽管 PAG 的渲染依赖 OpenGL 环境,但 服务端却可以继续使用 CPU 服务器。具体实现层面,PAG 通过 swiftshader 在 CPU 服务器上构建出了 OpenGL 环境,使得 pag 文件可以在 CPU 环境中正常渲染。
在服务端的具体使用如下,获取到的是 BGRA 的数据,该数据可以用于视频编码。
//C++autopagFile=pag::PAGFile::Load("../../assets/test2.pag");autopagSurface=pag::PAGSurface::MakeOffscreen(pagFile->width(),pagFile->height());if(pagSurface==nullptr){printf("---pagSurfaceisnullptr!!!\n");return-1;}autopagPlayer=newpag::PAGPlayer();pagPlayer->setSurface(pagSurface);pagPlayer->setComposition(pagFile);autototalFrames=TimeToFrame(pagFile->duration(),pagFile->frameRate());autocurrentFrame=0;intbytesLength=pagFile->width()*pagFile->height()*4;while(currentFrame<=totalFrames){pagPlayer->setProgress(currentFrame*1.0/totalFrames);autostatus=pagPlayer->flush();//PAG渲染数据读取autodata=newuint8_t[bytesLength];pagSurface->readPixels(pag::ColorType::BGRA_8888,pag::AlphaType::Premultiplied,data,pagFile->width()*4);delete[]data;currentFrame++;}deletepagPlayer;
开始使用 :如何接入
接入使用分为开发部分和设计部分,这里分别为大家介绍下:
(1) 开发者——接入SDK
在PAG的Github Wiki中有非常详细的接入指引(包括Android、iOS、Web等平台的接入方法和范例工程),大家自行学习就好:https://github.com/Tencent/libpag/wiki
(2)设计师——下载导出插件和预览工具
设计师想要使用PAG,只需在官网下载预览工具 PAGViewer和 AE 导出插件即可:https://pag.art/docs/install.html
整体看来,PAG的核心价值如下:
据官网显示已经有很多头部应用接入使用(如微信、王者荣耀、小红书、知乎等),稳定性应该很有保证,如果有动效上线相关业务的朋友非常值得试试。
最后顺便附上 PAG 相关的资源,大家感兴趣可以进一步了解:
官网: https:/pag.art/
Github:https://github.com/Tencent/libpag
QQ 群:893379574