PAG動效框架源碼筆記 (二)層級視圖

轉(zhuǎn)載請注明出處:http://www.olinone.com/

如上章所言说订,特效播放主要包括應用邏輯處理和圖形渲染兩個階段吨铸,其中宴霸,邏輯處理又可以看做模型對象的定義與流轉(zhuǎn)

模型分層

PAG框架模型大致可以分為三部分:

1译断、組件(PAGCompositon)

PAG框架支持多文件多圖層渲染萧恕,PAGCompositon組件可以同時容納多個PAGFile文件漾狼,每個PAGFile文件又可以包含多個Layer組件

PAGFile解析自File源文件鸠蚪,其中Layer組件可以支持元素替換今阳,比如可以替換PAGImageLayer中PAGImage資源對象,從而實現(xiàn)自定義融合元素

2茅信、圖層(PAGStage)

PAGStage承載了完整的組件圖層盾舌,記錄了每個組件及其資源對象的映射關(guān)系,比如PAGImage及其關(guān)聯(lián)的PAGImageLayer對象蘸鲸,實現(xiàn)通過資源對象查找對應Layer對象的能力

此外妖谴,PAGStage通過SequenceCache還緩存了資源對象與Graphic視圖對象的映射關(guān)系,類似于渲染緩存的職責

3酌摇、圖形(LayerGraphic)

組件模塊加上時間戳膝舅,就生成對應時刻的圖形對象Graphic,比如紋理圖形Picture妙痹,或者文本圖形Text

LayerGraphic作為圖形模型的容器铸史,繼承自ComposeGraphic對象,包含當前播放時刻所有的圖像對象怯伊,每一個圖形對象可以通過裝飾器添加裁切或者蒙版等多種處理效果

源碼淺析

1琳轿、File文件解析

// 文件二進制解析

std::shared_ptr<File> File::Load(const void* bytes, size_t length, const std::string& filePath, const std::string&) {

file = Codec::Decode(bytes, static_cast<uint32_t>(length), filePath);

...

return file;

}

// File對象初始化

File::File(std::vector<Composition*> compositionList, std::vector<pag::ImageBytes*> imageList) : images(std::move(imageList)), compositions(std::move(compositionList)) {

// 每一個File文件都有對應的mainComposition對象,組件元信息其實都存在compositon里面

mainComposition = compositions.back();

rootLayer = PreComposeLayer::Wrap(mainComposition).release();

...

}

2耿芹、PAGFile構(gòu)造

// 通過File構(gòu)造PAGFile

std::shared_ptr<PAGFile> PAGFile::MakeFrom(std::shared_ptr<File> file) {

? // 解析File構(gòu)造組件模型

? auto pagLayer = BuildPAGLayer(file, file->getRootLayer());

? pagLayer->gotoTime(0);

? auto pagFile = std::static_pointer_cast<PAGFile>(pagLayer);

? ...

? return pagFile;

}

// 每一個組件對象其實都持有原始File對象

std::shared_ptr<PAGLayer> PAGFile::BuildPAGLayer(std::shared_ptr<File> file, Layer* layer) {

? PAGLayer* pagLayer;

? switch (layer->type()) {

? ? case LayerType::Text: {

? ? ? pagLayer = new PAGTextLayer(file, static_cast<TextLayer*>(layer));

? ? } break;

? ? case LayerType::Image: {

? ? ? pagLayer = new PAGImageLayer(file, static_cast<ImageLayer*>(layer));

? ? } break;

? ? case LayerType::PreCompose: {

? ? ? ...

? ? ? if (composition->type() == CompositionType::Vector) {

? ? ? ? auto& layers = static_cast<VectorComposition*>(composition)->layers;

? ? ? ? // 遍歷組件列表

? ? ? ? for (int i = static_cast<int>(layers.size()) - 1; i >= 0; i--) {

? ? ? ? ? auto childLayer = layers[i];

? ? ? ? ? auto childPAGLayer = BuildPAGLayer(file, childLayer);

...

? ? ? ? }

? ? ? }

? ? } break;

? }

}

3崭篡、PAGStage圖層填充

// PAGComposition可以容納多個PAGFile

- (PAGComposition *)makeComposition {

? ? PAGComposition* compostion = [PAGComposition Make:self.view.bounds.size];

? ? PAGFile* file = [PAGFile Load:[[NSBundle mainBundle] pathForResource:@"data-TimeStretch" ofType:@"pag"]];

? ? // 可以替換PAGImage資源對象,底層其實是操作PAGImageLayer

? ? [file replaceImage:0 data:[PAGImage FromPath:[[NSBundle mainBundle] pathForResource:@"test" ofType:@"png"]]];

? ? [compostion addLayer:file];


? ? file = [PAGFile Load:[[NSBundle mainBundle] pathForResource:@"data_video" ofType:@"pag"]];

? ? [compostion addLayer:file atIndex:0];

? ? return compostion;

}

void PAGPlayer::setComposition(std::shared_ptr<PAGComposition> newComposition) {

? ...

? pagComposition = newComposition;

? if (pagComposition) {

? ? // 填充容器

? ? stage->doAddLayer(pagComposition, 0);

? }

}

// 建立索引緩存

void PAGStage::addReference(PAGLayer* pagLayer) {

? addToReferenceMap(pagLayer->uniqueID(), pagLayer);

? addToReferenceMap(pagLayer->layer->uniqueID, pagLayer);

? if (pagLayer->layerType() == LayerType::PreCompose) {

? ? auto composition = static_cast<PreComposeLayer*>(pagLayer->layer)->composition;

? ? addToReferenceMap(composition->uniqueID, pagLayer);

? } else if (pagLayer->layerType() == LayerType::Image) {

? ? auto imageBytes = static_cast<ImageLayer*>(pagLayer->layer)->imageBytes;

? ? addToReferenceMap(imageBytes->uniqueID, pagLayer);

? ? auto pagImage = static_cast<PAGImageLayer*>(pagLayer)->getPAGImage();

? ? if (pagImage != nullptr) {

? ? ? addReference(pagImage.get(), pagLayer);

? ? }

? }

...

}

// 可以通過資源ID查找渲染緩存

std::shared_ptr<Graphic> PAGStage::getSequenceGraphic(Composition* composition,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Frame compositionFrame) {

...

? SequenceCache cache = {};

? cache.graphic = RenderSequenceComposition(composition, compositionFrame);

? cache.compositionFrame = compositionFrame;

? sequenceCache[composition->uniqueID] = cache;

? return cache.graphic;

}

4吧秕、Graphic圖形生成

// 播放進度

void PAGPlayer::setProgress(double percent) {

? auto pagComposition = stage->getRootComposition();

? ...

? pagComposition->setProgressInternal(realProgress);

}

// 生成圖形

void PAGPlayer::prepareInternal() {

? renderCache->beginFrame();

? auto result = updateStageSize();

? if (result && contentVersion != stage->getContentVersion()) {

? ? contentVersion = stage->getContentVersion();

? ? Recorder recorder = {};

? ? // 通過recorder記錄每個可繪制組件Layer

? ? stage->draw(&recorder);

? ? // 導出所有圖形對象

? ? lastGraphic = recorder.makeGraphic();

? }

}

// recorder類似于二叉樹琉闪,記錄了每個Layer組件當前時刻對應的Graphic

void PAGComposition::draw(Recorder* recorder) {

? ...

? auto composition = preComposeLayer->composition;

? if (composition->type() == CompositionType::Bitmap ||

? ? ? composition->type() == CompositionType::Video) {

? ? auto layerFrame = layer->startTime + contentFrame;

? ? auto compositionFrame = preComposeLayer->getCompositionFrame(layerFrame);

? ? auto graphic = stage->getSequenceGraphic(composition, compositionFrame);

? ? recorder->drawGraphic(graphic);

? }

...

? if (hasClip()) {

? ? // 裁切裝飾器

? ? recorder->saveClip(0, 0, static_cast<float>(_width), static_cast<float>(_height));

? }

? // 堆棧模式處理每個視圖及其子視圖,保證每個視圖及其子視圖渲染環(huán)境一致性砸彬,比如matrix變化等

? for (int i = 0; i < count; i++) {

? ? DrawChildLayer(recorder, childLayer.get());

? }

? if (hasClip()) {

? ? recorder->restore();

? }

}

總結(jié)

為了支持多文件多圖層渲染颠毙,PAG框架設計了一套完整的框架模型,其復雜的對象繼承關(guān)系砂碉,加深了代碼閱讀理解難度蛀蜜,在理解其設計思路后,才能知其然知其所以然

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末增蹭,一起剝皮案震驚了整個濱河市滴某,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖霎奢,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件户誓,死亡現(xiàn)場離奇詭異,居然都是意外死亡幕侠,警方通過查閱死者的電腦和手機帝美,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來橙依,“玉大人证舟,你說我怎么就攤上這事〈捌铮” “怎么了女责?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長创译。 經(jīng)常有香客問我抵知,道長,這世上最難降的妖魔是什么软族? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任刷喜,我火速辦了婚禮,結(jié)果婚禮上立砸,老公的妹妹穿的比我還像新娘掖疮。我一直安慰自己,他們只是感情好颗祝,可當我...
    茶點故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布浊闪。 她就那樣靜靜地躺著,像睡著了一般螺戳。 火紅的嫁衣襯著肌膚如雪搁宾。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天倔幼,我揣著相機與錄音盖腿,去河邊找鬼。 笑死损同,一個胖子當著我的面吹牛翩腐,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播膏燃,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼栗菜,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了蹄梢?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎禁炒,沒想到半個月后而咆,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡幕袱,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年暴备,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片们豌。...
    茶點故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡涯捻,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出望迎,到底是詐尸還是另有隱情障癌,我是刑警寧澤,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布辩尊,位于F島的核電站涛浙,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏摄欲。R本人自食惡果不足惜轿亮,卻給世界環(huán)境...
    茶點故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望胸墙。 院中可真熱鬧我注,春花似錦、人聲如沸迟隅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽玻淑。三九已至嗽冒,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間补履,已是汗流浹背添坊。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留箫锤,地道東北人贬蛙。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像谚攒,于是被迫代替她去往敵國和親阳准。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,781評論 2 354

推薦閱讀更多精彩內(nèi)容