LSW FFmpeg 5.0 or later対応
修正するために調べたメモです。
原因
原因は以下のURLらへんでindex_entriesがinternalにされたせいです。
internalにされて秘匿されたおかげでindex_entriesを気軽に弄れなくなりました。
index_entriesとは
AVIndexEntryは
table:AVIndexEntry
メンバ名 内容
pos ファイルでのポジション
timestamp AVStream.time_base単位でのタイムスタンプ
flags フラグ
size サイズ
min_distance 前のキーフレームとの最小長さ
を持った構造体です
index_entriesはAVIndexEntryの配列です。つまり、キーフレームを保存しておくことでシーク時のアクセス速度を上げることができます。
なぜindex_entriesを弄る必要があるのか
Q. FFmpeg側が用意している構造体なのに、いじる必要があるの?
A. あります。コンテナによってはFFmpeg側で正しいindex_entriesを生成してくれないことがあります。(例: WMVで使われているASF)
実際にWMVを読み込む際にnb_index_entriesを見てみたら0だったり、正確でなかったり...
つまり、WMVなどのindex_entriesが生成されないものなどに対して、LSW側でindex_entriesを挿げ替えることでシーク時のアクセス速度を上げたり、正確なindex_entriesを突っ込んでやろうということだと思っています。
解決法
1.
AkarinVS氏が ffmpeg-4.5 branch で対応をされています。
実は当時から気が付いてはいました。
問題
ですが、これだけ見るとまだ問題が残っているように見えます。
今まではindex_entriesをL-SMASH Works側で勝手に作成して挿げ替えていたわけですが、FFmpeg側で用意されてるAPIについて
AVIndexEntryの数を取得
n個目のAVIndexEntryの取得
タイムスタンプからのAVIndexEntryの取得
AVIndexEntryの追加
のみしか確認できませんでした。
よって、消すことができないので追加することしかできません。
AkarinVS氏のブランチではTODOのまま放置されています。
追加することしかできないということは、index_entriesがダブる場合は内部でソートされる場合検索効率も落ちますし、不必要なメモリを使用することとなる可能性があります。
ということで、FFmpegでindex_entriesを追加する際の中身を見てみます。(FFmpeg 6.1時点)
1. index_entriesの数が大きすぎることがないように判定
2. timestampが無効な値ではないか判定
3. sizeが無効な値ではないか判定
4. timestampが相対的だったら、ベースで引く
5. realloc
6. realloc失敗判定
7. timestampから検索
8. 検索結果が負の数だった場合(なかった場合)
1. 一番最後のポインタを選択
9. 検索結果が正の数だった場合
1. 検索結果のポインタを選択
2. 検索結果のタイムスタンプが同一の場合
1. min_distanceの更新
3. 検索結果のタイムスタンプが追加するタイムスタンプより前の場合
1. エラーを返す
4. memmoveで後ろに詰める
10. 選択したポインタのデータ更新
ダブってる場合は追加されないが、無限に同一のnb_index_entriesでreallocとそれぞれのAVIndexEntryの更新がされますね
結論
同一のAVIndexEntryをaddしても問題はないので、削除するコードを追加する必要はない。
(1個分無駄にindex_entriesの領域が確保されますが)
よって、AkarinVS氏のコードを参考に変更を加えても全く問題がない。
2.
第二の解決策を考えてみる
index_entriesを更新するのは
ASFのnb_index_entriesが0の時
のみなため、ASFの時のみindex_entriesを記載するよう、lwiの構造を変えてみる?
そうすれば、無駄な更新をすることがなくなります。
だが、ASF以外でindex_entriesの更新をする必要があることが判明した際、lwiを読み込む際には判定をしないため、
1. 旧VerでStreamIndexEntriesが記載されてないlwiファイルを出力
2. 新Verに変更
3. 新Verで読み込む際にもlwiファイルにStreamIndexEntriesの記載がされていないため、更新がされずにシークが遅くなる?
のデメリットがありますね...
3
lwiの構造を変更せずに
nb_index_entries == 0
なら読み込むといった方法をとる
これならデータが競合する心配もない
が、FFmpegが誤ったindex_entriesを出力しており、その情報を更新したい際にはそこが実行されなくなる。
結局のとこ1がいいか。
何か不都合があれば後で修正すればいいので、とりあえず1を実装しますかね。
2024/06/16 追記
AkarinVS氏のffmpeg-4.5 branchをcherry-pickして、対応
FFmpeg 4.4でビルドした最終版
L-SMASH-Works-Auto-BuildsでMr-Ojii版L-SMASH-WorksをFFmpeg 4.4でビルドした最終版をおいておきます。
5.0以降のものを使って不具合が出た場合に使ってください。