toruのブログ

月1くらいで記事書きたい。

DaVinci Color Transform Language (DCTL) を試してみた

0. 更新履歴

日付 Revision 内容
2023/05/20 rev.1 新規作成
2023/05/24 rev.2 DCTL の Syntax Error の確認方法を追記
2023/06/02 rev.3 DCTL の printf デバッグ方法を追記

1. 背景

諸事情により DaVinci CTL (DCTL) を使って動画コンテンツの解析をしたくなった。 しかし、筆者は DCTL を全く触ったことが無かったため、まずは簡単な DCTL のコードを書いてみることにした。

2. 目的

  • DCTL をとりあえず試してみる
  • 実装で苦労した点をまとめておく

3. 結論

簡単な DCTL のコードを書き DaVinci 用のエフェクトを作成することに成功した。成果物の紹介と苦労した点を以下に示す。

3.1. 成果物の紹介

2020年に作成した HDRコンテンツ解析用 Luminance Map の生成コードを DCTL で書き、 DaVinci Resolve のエフェクトとして利用可能にした。

ソースコードは以下で公開している。動作の様子を動画1 に示す。

github.com

動画1. 作成したエフェクトが動作する様子

3.2. 実装で苦労した点

  • ①エラーログが無く Syntax Error が出ないのでコードの文法誤りの検出が困難
    • 筆者は VS Code上でソースコード 1行ずつコメントアウト して問題のあるコードを検出していた
    • 2023/05/24 追記
      • ブログ公開後、複数の方にエラーログの確認方法を教えて頂いた🙏
      • 以下のフォルダにある davinci_resolve.log を見ると Syntax Error の内容が確認できる
        • Windows: C:\Users\<user_name>\AppData\Roaming\Blackmagic Design\DaVinci Resolve\Support\logs
        • macOS: /Users/<user_name>/Library/Application Support/Blackmagic Design/DaVinci Resolve/logs
      • エラーログの例は以下
C:\ProgramData\Blackmagic Design\DaVinci Resolve\Support\LUT\TY_DCTL\show_internal_value.dctl(3106): warning: parameter "rgb" was set but never used
C:\ProgramData\Blackmagic Design\DaVinci Resolve\Support\LUT\TY_DCTL\show_internal_value.dctl(3148): error: identifier "rgb" is undefined
2 errors detected in the compilation of "C:\ProgramData\Blackmagic Design\DaVinci Resolve\Support\LUT\TY_DCTL\show_internal_value.dctl".


  • ②動作確認時のデバッグが困難
    • コンソール出力が無いので printf デバッグすらできない
    • 仕方ないので閾値で出力を2値化するデバッグ用の DCTL を用意して内部値の推測を行った (図1~図3)
図1. DCTL Off 時の様子 図2. 閾値を 1.0 に設定した場合の様子 図3. 閾値を 10.0 に設定した場合の様子

2023/06/02 追記

ややトリッキーではありますが、DCTL で printf デバッグすることに成功しました。詳細は以下の記事を参照下さい。 trev16.hatenablog.com

4. DCTL について筆者が理解した点

以下で筆者が理解した点を参考情報として残しておく。 なお、今回作成した DCTL のプラグインは EDIT ページで実行する想定で作成した。 Colorページでの運用は今のところ考えていない(Colorページでも使えるとは思うが)。

4.1. DCTL のマニュアルは README.txt のみ

DaVinci Resolve の公式マニュアルには詳細の記述がない。

詳細マニュアルは DaVinci 起動時にメニューバーから Help --> Documentation --> Developer を選択した際に 開くウィンドウの先にある DaVinciCTL/README.txt のみである。

4.2. 生成した DCTLファイルは LUT と同じフォルダに配置する

作成した DCTL のコードは .dctl の拡張子で保存して、以下のフォルダに配置する。

  • Mac OS X: Library/Application Support/Blackmagic Design/DaVinci Resolve/LUT
  • Windows: C:\ProgramData\Blackmagic Design\DaVinci Resolve\Support\LUT
  • Linux: /home/resolve/LUT

意外なことに DCTL 用のフォルダではなく、LUT用のフォルダに配置 する仕様であった。 DaVinci 的には DCTL も LUT も内部的には似たような取り扱いなのかもしれない。

4.3. DCTL の処理は Timeline color space で行われる

非常に恥ずかしい話なのだが、筆者はこれまで DaVinci の EDITページで色処理を行う経験が殆どなく、 Timeline color space が何のために存在しているのか分かっていなかった(勝手に内部処理は Linear空間で行われると考えていた)。

今回 DCTL のコードを書くことで初めて Timeline color space の意味が理解できた。 筆者の理解は次の通りである。Timeline color space は Color Grading における ACEScct のように、信号処理の内容に応じて適切な色空間を選択するために存在している。

さて、そうなると Timeline color space の値域を正しく理解しておく必要がある。 なぜならば値域を理解しないことには DCTL のコードを書けないからである(HDR の場合は 1.0 を超える値を取り扱うので)。

筆者が調査したところ、0.0 ~ 1.0 に正規化された入力データを使用した場合の Timeline color space の値域は以下の表1となることが分かった。

表1. 入力の Gamma 設定と Timeline color space の Gamma 設定の組み合わせにおける値域の例
入力の Gamma Timeline の Gamma
Linear
Timeline の Gamma
PQ
Timeline の Gamma
2.4
2.4 0.0 ~ 1.0 0.0 ~ 0.508 0.0 ~ 1.0
PQ 0.0 ~ 100.0 0.0 ~ 1.0 0.0 ~ 6.81

設定によって値域が大きく異なるため、Timeline color space で処理を行う DCTL コードを書く際は、この点に注意する必要がある。

4.4. DCTL では CTL のコードをそのまま流用できない

筆者は当初、CTL のコードも include して使い回せると考えていたのだが、そんなことは無かった。

以下は SMPTE ST 2084 の EOTF を CTL から DCTL に書き換えた際の diff である。 見て分かるように様々な変更が入るため CTL をそのまま流用するのは不可能であった。

--- st2084.ctl  2023-05-14 11:48:03.867909400 +0900
+++ st2084.dctl 2023-05-14 11:50:22.216460100 +0900
@@ -6,23 +6,23 @@
 
 const float pq_C = 10000.0;
 
-float ST2084_2_Y( float N )
+__DEVICE__ float ST2084_2_Y( float N )
 {
-  float Np = pow( N, 1.0 / pq_m2 );
+  float Np = _powf( N, 1.0 / pq_m2 );
   float L = Np - pq_c1;
   if ( L < 0.0 )
     L = 0.0;
   L = L / ( pq_c2 - pq_c3 * Np );
-  L = pow( L, 1.0 / pq_m1 );
+  L = _powf( L, 1.0 / pq_m1 );
   return L * pq_C; // returns cd/m^2
 }
 
-float[3] ST2084_2_Y_f3( float in[3])
+__DEVICE__ float3 ST2084_2_Y_f3( float3 in )
 {
-  float out[3];
-  out[0] = ST2084_2_Y( in[0]);
-  out[1] = ST2084_2_Y( in[1]);
-  out[2] = ST2084_2_Y( in[2]);
+  float3 out;
+  out.x = ST2084_2_Y( in.x );
+  out.y = ST2084_2_Y( in.y );
+  out.z = ST2084_2_Y( in.z );
 
   return out;
 }

主な変更箇所は以下の通りである。

  • 関数定義の冒頭に __DEVICE__ の接頭語がつく
  • pow_powf に変更
  • float in[3]float3 に変わる
    • それにともないメンバのアクセスに .x, .y, .z の記述が必要

5. 感想

思っていたより難易度が高かったが DCTL の基本的な書き方を理解できた。ここまで来れば応用は割と簡単なので、 今後は本来やりたかった処理を数週間かけて実装していきたい。