ビデオ編集シナリオにおけるテキスト テンプレートの技術的ソリューション

著者 | Lok'tar ogar

ガイド

この記事では、Duka Editing APP テキスト テンプレートの開発プラクティスに基づいて、ビデオ編集シナリオにおける静的テキスト テンプレート レンダリング機能の技術的ソリューションを共有します。リッチ テキスト レンダリング ソリューションのスーパーセットとして、この技術ソリューションは、複雑なリッチ テキスト レンダリングを必要とする他のシナリオに拡張できます。

全文は 6745 ワードで、予想読了時間は 17 分です。

スニークピーク

テキストテンプレート効果表示: △Duka編集でのテキストテンプレートの適用

01 背景

ビデオ作成ツールのコア競争力の 1 つは、さまざまなビデオ素材、オーディオ素材、ステッカー素材などを含む豊富な素材ライブラリです。テキスト テンプレートも不可欠な部分です。テキスト テンプレートはリッチ テキスト編集機能を提供し、ユーザーはより美しいスタイルのテキスト情報をビデオに追加できるため、ビデオ素材の多様性が高まります。さらに、プリセット スタイルを通じて、ユーザーは自分に合ったテキスト テンプレートをより便利に選択できるため、素材選択の時間が節約され、ユーザー エクスペリエンスが向上します。Duka の初期バージョンでは、マテリアル タイプのテキスト テンプレートを提供していませんでした。製品の競争力を高め、素材の普及率を高めるために、一定の研究開発を行い、ついにテキストテンプレート素材を発売しました。これらのテキスト テンプレート素材は、ユーザーのニーズを満たすだけでなく、ユーザーにより創造的なインスピレーションとアイデアを提供します。同時に、マテリアル ライブラリの更新と最適化を常に行っており、ユーザーが最新かつ最高品質のマテリアル リソースを入手できるようにしています。テキスト テンプレートが提示する必要があるグラフィックとテキスト スタイルは比較的複雑です. Duka テキスト テンプレートでサポートされている機能は以下のとおりです:

02 全体のデザイン

構築したマテリアル プラットフォームに基づいて、新しいタイプのテキスト テンプレートを追加し、マテリアル プラットフォーム上でマテリアルの編集、プレビュー、構成、およびオンライン機能を提供しました。素材制作とプレビューを組み合わせることで、調整したばかりの効果を同じインターフェイスでプレビューし、Duka のフォント ライブラリと直接照合し、画像リソースを直接変更できます。この素材制作方法は再利用性が高く、テキストテンプレートを使用して背景画像を変更し、ストロークを追加することで、別のテキストテンプレートを直接作成することができます。このテンプレートを公開してエフェクト ダイアグラムをエクスポートすると、レビュー待ちのキューに入り、レビュー後に構成して起動することができます。これまでに 361 セットのテキスト テンプレートを立ち上げ、[マテリアル プロダクション] - [マテリアル プラットフォーム プレビュー] - [マテリアル デリバリーとクライアント ロード] - [クライアント レンダリング] の完全なリンクを完了しました。

03 機能実現

3.1 材料生産

現在、ビデオ編集業界の主流の素材形式は、通常、リソース ファイルと構成ファイル (記述ファイル) を採用しています。その中で、リソース ファイルには画像リソースとフォント ファイルが含まれ、構成ファイルは主にテキスト テンプレートの組版属性とレンダリング パラメータを記述するために使用されます。この方法の利点は、制作側が特定のフィールドを通じて関連する特性を記述するだけでよく、それをレンダリング側で提示できることです。この方法は柔軟性が高く、特定のシナリオのニーズに応じて単純なものから複雑なものまで、関連する機能を繰り返すことができますが、実装コストは比較的低くなります。しかしデメリットとしては、素材制作の形態がカスタマイズされており、ある程度の設計・学習コストがかかることです。また、Photoshop(PS)を例にとると、プロ用デザインソフトの制作方法は他にもあります。PSには、さまざまなデータ構造を含む比較的成熟したファイル形式のドキュメントがあり、PSDファイルを直接使用して、レンダリング用のグラフィックおよびテキスト属性を分析できます。この方法の利点は、材料の作成方法がより一般的であり、設計に学習コストがほとんどかからないことです。ただし、欠点は、複数のテキスト ボックスを重ね合わせることによって得られる効果である多層シャドウ効果など、PSD だけでは必要な一部の機能を単純に満たすことができないことです。テキスト コンテンツを変更する場合、これらのテキスト ボックスを同時に変更する必要があるため、それらをグループとして扱う必要があり、ロジックはより複雑になります。設定ファイルで記述すれば、複雑なロジック処理なしで直接多層描画が可能です。ビジネス ROI と短期的なオンライン機能の実現可能性を考慮して、最初の方法を採用し、Butter Camera チームのマテリアル制作基準を利用して、組版属性とレンダリング パラメーターを記述するための JSON 構造を設計しました。

3.2 サイドレンダリング

ビデオ編集シナリオでは、テキスト処理には、テキスト レイアウトとテキスト描画の 2 つの部分が必要です。テキストの組版の場合、iOS プラットフォームは組版処理に CoreText の基盤となるフレームワークを使用しますが、Android は、FontMetrics などを介して基盤となる FreeType のフォント処理の結果を取得できます。テキストの一部が全体としてフォーマットされているか、各テキストの位置が個別に計算されているかに関係なく、処理全体のパフォーマンス消費は同じです。テキストの描画に関しては、パフォーマンスのオーバーヘッドと開発コストのバランスを取る必要があります。最終的に、iOS は QuartzCore フレームワークを採用し、Android はテキスト描画に Canvas を使用しました。このようにして、プレビュー時にテキストをビューに直接表示できるため、リアルタイムの編集とプレビューがサポートされます。ビデオをエクスポートする必要がある場合は、ステッカーとして処理し、ビデオに追加します。iOS を例にとると、Huazi コンポーネントのアーキテクチャは次のようになります。

3.3 記述ファイルの設計

前述のように、json ファイルを使用して、テキスト テンプレートの組版属性とレンダリング パラメータを記述します. リソースがクライアントに配信された後、クライアントは対応するパラメータを解析して、テキスト テンプレートの組版と最終的な効果のプレゼンテーションを実行します。 . 記述ファイルには、次の内容が含まれます。

(1) テキストレイアウト属性

  • ベースライン: 文字ベースライン、ベースラインは仮想線
  • ascent: グリフの最高点からベースラインまでの推奨距離
  • descent: グリフの最下点からベースラインまでの推奨距離
  • Leading: 行間隔、つまり、前の行の下降と次の行の上昇の間の距離
  • 前進幅: Origin から次のグリフ Origin までの距離
  • 左サイドベアリング: 原点からグリフの一番左までの距離
  • 右側のベアリング: グリフの右端から次のグリフの原点までの距離
  • 境界ボックス: グリフを含む最小の長方形
  • x-height: 一般に、小文字の x の最高点からベースラインまでの推奨距離を指します。
  • キャップの高さ: 一般に、H または I の最高点からベースラインまでの推奨距離を指します。

(2) テキストオブジェクトの組み合わせ 下図は、 2 つのテキスト描画領域を組み合わせた例です。

3.4 組版と描画プロセス

テキスト テンプレートでは、組版と描画は不可分であり、処理のためにコード ロジックに散在させる必要があります。私たちの描画ステップは、最下層から最上層までレイヤーごとに描画しますが、一部の描画プロセスには多くの時間がかかるため、メインスレッドのブロックを回避するために、非同期描画技術を使用します。非同期描画のプロセスでは、ユーザーの通常の使用に影響を与えないように、時間のかかる描画プロセスをバックグラウンド スレッドで処理します。同時に、非同期描画のプロセスでは、テキストのレイアウトも計算するため、後続の描画プロセスでテキストの関連情報をすばやく取得できるため、描画効率が向上します。一般に、非同期描画方式を採用することで、テキスト テンプレートの組版と描画プロセスが、ユーザーにあまり干渉することなくスムーズに進むようにすることができます。

04 困難と課題

1. 多端子効果の配置

私たちのプロジェクトは Web、iOS、Android のレンダリングをサポートしていますが、一般的なクロスエンド ソリューションでは最下層で OpenGL レンダリングを使用する必要があり、当時の人的リソースの制約により、短期間で実現することは困難でした。そのため、マルチターミナルの独立したレンダリング方法を採用し、各プラットフォームには独立したレンダリング ソリューションがあります。この方法にも問題があります。異なるプラットフォームのレンダリング効果は異なります。この問題を解決するには、多端子効果の一貫性を確保する必要があります。技術レベルの差を埋めるのは難しいため、ルールや基準を統一することで一貫性を保つことにしました。jsonファイルのフォーマットを設計する際に、テキスト装飾のテキストに対する相対的な初期位置を左上隅に揃えるか、中央揃えにするか、座標の原点を統一された。同時に、最終的なレンダリング効果の一貫性を最大限に確保するために、対応するパラメーターで使用される単位も統一しました。このようにして、レンダリングされるプラットフォームに関係なく、一貫した結果を得ることができ、ユーザー エクスペリエンスがより均一で優れたものになります。

2. テキストの事前組版

テキストテンプレートでは、フォントサイズを固定フォントサイズと非固定フォントサイズの 2 種類に分けています。固定フォント サイズの場合、テキスト レイアウトの計算と描画を直接実行できます。ただし、フォント サイズが固定されていないフォントの場合、現在のテキスト コンテンツに対応するフォント サイズを計算するために、組版前の計算を実行する必要があります。ここでのいくつかの解決策は二分法を使用し、最初に大きなフォント サイズの値を設定し、0 からフォント サイズの値の範囲内で徐々に正しい値に近づきますが、これは実際にはテキストの基本的なロジックと制限と相まって、不要な時間の損失を引き起こします。レイアウト 条件、O(1) に近い時間計算量を持つアルゴリズムを作成できます: 最大文字高さを計算します -> 最小文字高さを計算します -> 単語の最長行の文字高さを計算します -> に従って文字高さを計算します行数へ → 最終的な文字の高さを計算 → 文字の高さに応じてフォントサイズを計算 iOS で組版技術 CoreText を使用した場合、まれに塗りつぶしきれない文字が自動でカットされる場合があります. 計算されたフォントサイズをそのまま使用すると、文字の一部がカットされる場合があります. そのため, 上記の結果となるはずです.推定結果として使用され、パスを埋めることができるまで、サイズは 1 段階ずつ縮小されます。

        CGFloat ascent, descent;
        UIFont *font = [self.calFont fontWithSize:size];
        CTFontRef fontRefMeasure = (__bridge CTFontRef)font;
        [attrString addAttribute:(id)kCTFontAttributeName value:(__bridge id)fontRefMeasure range:NSMakeRange(0, attrString.length)];
        CTLineRef line = CTLineCreateWithAttributedString((__bridge CFAttributedStringRef)attrString);
        CTLineGetTypographicBounds(line, &ascent, &descent, NULL);
        
        //calculate max font size
        CGFloat calFontHeight = MIN(height, width);
        self.maxFontHeight = calFontHeight;
        
        //calculate min font size
        CGFloat maxLine = self.document.maxLine * BDTZBigFontDataOriginScale;
        if (maxLine <= 0) {
            maxLine = 1;
        }
        calFontHeight = [self itemWidth] / (maxLine + (maxLine - 1) * (self.leadingRatio * BDTZBigFontDataOriginScale - 1));
        self.minFontHeight = MIN(self.maxFontHeight, calFontHeight);
        
        // longest column
        int64_t n = 0;
        NSArray *strArray = [self.document.content componentsSeparatedByString:@"\n"];
        NSString *measureStr = self.document.content;
        // 这里是针对多行文本的处理,循环次数为行数,量级较小(一般为1-10行)
        for (NSString *str in strArray) {
            if (str.length > n) {
                n = str.length;
                measureStr = str;
            }
        }
        CGFloat fontWidthRatioOrigin = (self.document.fontWidthRatio * BDTZBigFontDataOriginScale);
        CGFloat trackingRatio = (self.document.trackingRatio * BDTZBigFontDataOriginScale) * (ascent + descent) / ascent;
        CGRect rect = [@"我" boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:self.calFont} context:nil];
        CGFloat fontWidthRatio = fontWidthRatioOrigin > 0 ? fontWidthRatioOrigin * (ascent + descent) / ascent : rect.size.width / rect.size.height;
        CGFloat fontHeight = width / (n * fontWidthRatio + n * trackingRatio);
        
        if (strArray.count > 1) {
            //calculate font size accoring column count
            calFontHeight = [self itemWidth] / (strArray.count + (strArray.count - 1) * (self.leadingRatio * BDTZBigFontDataOriginScale - 1));
            //take the min value of the above two font sizes
            fontHeight = MIN(fontHeight, calFontHeight);
        }
                
        if (fontHeight > self.maxFontHeight) {
            fontHeight = self.maxFontHeight;
        } else if (fontHeight < self.minFontHeight) {
            fontHeight = self.minFontHeight;
        }
        
        CGFloat calSize = fontHeight;
        calFontHeight = [self calculateFontHeightSize:calSize];
        calSize = floorf(calSize / (calFontHeight * (ascent + descent) / ascent) * calSize);
        
        //exact value, calculate repeatedly with frame until the path can be filled
        
        //根据估算结果,将size逐次减1,直至能填入path,此处代码省略
        
        if (calSize <= 0) {
            return calSize;
        }
        calFontHeight = [self calculateFontHeightSize:calSize];
        self.fontHeight = calFontHeight * (ascent + descent) / ascent;
        
        self.font = [self.calFont fontWithSize:calSize];

3.描画性能

テキスト テンプレートのリアルタイム プレビューを頻繁に描画する必要があるため、CPU に大きな負荷がかかり、遅延が発生します。この問題を解決するには、非同期描画を使用する必要があります。具体的には、各ユーザー操作のテキスト コンテンツ ステータスを格納する非同期シリアル キューを作成できます。ユーザーが変更を加えるたびに、現在の状態をキューに入れ、バックグラウンド スレッドが非同期で描画するのを待ちます。前の状態が描画された後、すべての状態が描画されるまで、次に描画される状態をキューから取り出します。このように非同期描画を実現し、メインスレッドのスタックを防ぎ、ユーザーによる各変更の結果が完全に表示されます。テキスト テンプレートのユーザー エクスペリエンスをさらに最適化するために、非同期描画に加えて、キャッシュ メカニズムを使用してレンダリング パフォーマンスを向上させることも検討できます。ユーザーがテキスト テンプレートを操作すると、テキスト ビューが再レイアウトおよび描画されます. テンプレート全体が毎回再描画されると、多くの CPU リソースを消費するだけでなく、ユーザー エクスペリエンスも低下します. したがって、キャッシュを使用して、描画されたテンプレート ビューを保存できます。ユーザーがテキスト コンテンツを変更した場合、ビュー全体ではなく、変更された部分のみを再描画する必要があります。このようにして、リソース消費を削減し、システムの応答性を向上させながら、レンダリング パフォーマンスを向上させることができます。

4. メモリの最適化

テキスト テンプレートは主にビデオ編集シナリオで使用され、ユーザーは特定の状況に応じてテキスト テンプレートをズームインまたはズームアウトする必要があります。純粋なベクター描画リフレッシュ方法を使用すると、ユーザーがテキスト テンプレートをある程度拡大すると、メモリ使用量が非常に高くなります。さらに、当社のユーザーは通常、エディターにステッカー、特殊効果、字幕などの多くの素材を追加しますが、これらの素材のそれぞれが多くのメモリを占有します.一定期間使用すると、メモリが増加する可能性があります. OOM のしきい値に達し、アプリケーションがクラッシュします。したがって、現在、1 つのテキスト テンプレートのメモリを 20M 未満に制御し、さまざまなビデオの幅と高さに応じて期待される明瞭さを達成するためにテキスト テンプレートに必要な幅と高さのしきい値を計算し、明快さのバランスをとります。各テキスト テンプレートには、異なるバランス パラメータがあります。これは単なるメモリ最適化の詳細ですが、マテリアルのメモリ使用量とオンライン OOM レートを制御する上で大きな役割を果たしています。

05 エピローグ

ビデオ編集の世界では、リッチ テキスト レンダリングはかなり複雑なプロセスです。最終的なレンダリングに関する限り、万能のソリューションはなく、特定のシーンに最適なソリューションのみです。テキスト テンプレート レンダリング ソリューションを設計および実装するプロセスでは、考慮すべき詳細事項が数多くあります。同時に、PS や Figma などの主流のデザイン ソフトウェアのファイル形式を深く理解することも必要です。私たちのチームは、より一般的なリッチ テキスト レンダリング シナリオを満たすことができる静的テキスト テンプレートに関連する技術的ソリューションを提供します。全体的な考え方は、テキストのレイアウトと描画についてはほぼ同じです。この記事では、読者が当社の技術ソリューションをよりよく理解できるように、基本的な概念とリッチ テキスト機能を紹介します。ただし、私たちが提供するソリューションを使用しても、その実装には多くの詳細を考慮する必要があります。レンダリングされたリッチ テキストが期待どおりの効果を発揮できるようにするには、フォント サイズ、色、配置、文字間隔、行間隔、およびその他の要因を考慮する必要があります。したがって、リッチ テキスト レンダリングの効果を最大限に引き出すには、設計と実装に多くの時間と労力を費やす必要があります。リッチテキストの特性と設計原理を深く理解することによってのみ、高品質のビデオ編集体験をユーザーに提供できます。

- 終わり -

推奨読書: イベント シナリオにおけるグラフ アルゴリズムのアンチチート アプリケーションについて話す

サーバーレス: パーソナライズされたサービス ポートレートに基づく柔軟なスケーリングの実践

画像アニメーション応用における動作分解法

パフォーマンス プラットフォーム データ アクセラレーション ロード

編集 AIGC 映像制作工程 アレンジ実習

バイドゥのエンジニアが動画の理解について語る

{{o.name}}
{{m.name}}

おすすめ

転載: my.oschina.net/u/4939618/blog/8590220