2019/03/02

DGIndexでd2vを生成する処理ってなんか遅くないですか?

はたと、ファイルのインデックス処理をさせるだけなのに、100MB/s程度しか処理してくれないのはなんで?と疑問に思ったので調べてみました。

で、GOPの先頭のアドレスを記憶する(というかtelli64関数)のに尋常じゃなく時間を食っているということが分かったので、
とりあえずそこを必要な時にだけやるようにしたら、300MB/s程度までは出るようになりました。

が、ファイル構造を理解していないので、パケットが188じゃない時にどうするのかを悩み中・・・

と見ていたら、PS(DVDとか?)の時はGOPを開始するときしか処理してない。
TS(*.ts)対応を追加したときにさぼった?のか、なんか理由があるのか・・・まだちゃんと見切れていません。

と思ったらコメントが書いてあった
// We index the on-disk file position for accessing each I picture.
// We prefer to index a sequence header immediately accompanying
// the GOP, because it might carry new quant matrices that we would need
// to read if we randomly access the picture. If no sequence header is
// there, we index the I picture header start code. For ES, we index
// directly each indexed location. For PES, we index the position of
// the previous packet start code for each indexed location.
//
// There are two different indexing strategies, one for ES and one for PES.
// The ES scheme directly calculates the required file offset.
// The PES scheme uses CurrentPackHeaderPosition for the on-disk file
// offset of the last pack start code. This variable is irrelevant for ES!
// The pack header position is double-buffered through PackHeaderPosition
// and CurrentPackHeaderPosition to avoid a vulnerability in which
// PackHeaderPosition can become invalid due to a Fill_Next() call
// triggering a Next_Packet() call, which would rewrite PackHeaderPosition.
// So we record PackHeaderPosition to CurrentPackHeaderPosition as the
// first thing we do in Fill_Next().

・・・日本語でOK?
よくわかりませんが、そう書いてある以上は考慮したほうが良いのでしょうか。
CurrentPackHeaderPositionには上述のFill_Next関数の頭でしか値を入れておらず、
値を使っているのはさらにその上のMPEG2Decから直/もしくはGOPBackを介して呼ばれているGetHdr関数なので、ダブルバッファにする必要性はあるのかないのか。
プログラムの構造が良くわかっていないのでどうにもよくわかりません。

というわけでプログラム構造を確認していったところ、
1.入力ファイルチェック・種類判定
2.d2vのヘッダを書く
3.ファイル先頭からIピクチャを探す
4.最初のIピクチャから順次パケットを処理しつつd2vの残りを記述
というような感じになっているっぽい

インデックス処理は4.の中のGetHdr関数でしているのですが、その中でCurrentパケットの処理とNextパケットの処理があることを意識したら上述のコメントが理解できました。
これですっきり。

・・・ネットワーク(10G)越しには200MB/s程度しか出ないが何がボトルネックか・・・まぁいいや。

ソースはmakiさんのを使っているのですが、workaroundがあることに気が付いたのでそちらも追加。
GUI使わないからあまり関係ないですけどね。

たまに最終フレームを取りこぼすことがあるような。
ファイルによるのですが・・・イメージ的にはファイルを読んでいって最終バッファに入った区間にGOPの先頭が来る場合かな?
今回バッファサイズを2kB→128kBに拡張しているのですが、そこを元に戻したり、64kBに減らしたりすると一応治ります。
但し、65536はOKで65534はダメ、などで挙動がいまいちよくわかりません。

まぁ、最終フレームだけなのでいいかな?

190308追記
上記現象の解決方法が分かったので修正
これで今までと同じd2vファイルが作れるはず。
というわけでひとまずリリース。
DGIndexはバイナリ配布がいろいろ怪しいのでソースだけですが。
https://github.com/299792458m/DGIndex_mod/releases

AVX2とSSE2でなんか30%位速度が違う・・・と思ったらAVX2の時はBMI2対応コードを吐いていた。
最近のコンパイラはさすがですね。

と眺めていたらSSE2でも速度の出るコードが出来上がった。
・・・眺めていたのではなかったのか・・・

後は・・・ネットワーク越しだと遅いの何とかならんかね・・・
きっとシステムコール(低水準入出力)関数を使っているあたりが原因なんではないかと思っていますが
(CPUも遊んでる割に70~150MB/s位しか速度が出ない)

また、tellのもうちょっとスマートなやり方を思いついたので変更。
ファイル読んだときしかポインタは動かないよね・・・

0 件のコメント:

コメントを投稿