New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ffmpeg の -probesize オプションに相当するオプションを実装してほしい #335
Comments
要望とその背景を説明いただきありがとうございます。 ご指摘の通り、probesizeを指定できるようにすること自体は比較的難しくないので、--input-probesizeとしてオプションを追加したものを添付しました。(→ NVEncC64_5.31beta1.zip) また、このバージョンではわずかですがいくつか初期化処理の高速化を図りました。
ただ残念ながら"--input-format mpegts --input-analyze 0 --input-probesize 8192"での動作は難しいです。 avformat_find_stream_info は映像/音声のヘッダーを認識してその情報を取得するとともに、フレームレートを推定する重要な処理となっています。 しかし、ts ではデータの先頭がGOPの先頭とは限らないことから、analyzeduration や probesize が小さすぎるとGOPの先頭にあるヘッダーにたどり着けないことがあります。その結果、デコードに必要なヘッダー情報やエンコードに必要な映像の情報(解像度、フレームレート等)が取得できなくなってしまいます。 たとえば、ffmpegでも"-f mpegts -probesize 8192 -analyzeduration 0"とすると一部tsファイルでは下記にようにエラーメッセージがでてしまいます。 [mpegts @ 00000248751fe0c0] Stream #2: not enough frames to estimate rate; consider increasing probesize 太字部分が問題で、この状態では、エンコードに必要な映像の情報が取得できず、エンコードを開始することができません。(NVEncCではエラー終了するようになっています) ffmpegはこの状態でもなんとかしているのだとは思うのですが、いったいどうやっているのか、すみません、よくわかりません。ffmpegと同様の動作にはできていないのかと思います。 個人的に少し試した感じでは、現状のNVEncCの実装ですといまのところ下記オプションぐらいが限界のように感じていて、probesize等でそれ以上削るのは難しいかもしれません。 --input-format mpegts --input-analyze 0.66 ただ、初期化時の遅延についてもある程度は改善できているので、まずは添付した添付した5.31beta1(→ NVEncC64_5.31beta1.zip)をお試しいただき、ご意見いただければ幸いです。 よろしくお願いいたします。 |
早速の実装ありがとうございます!こちら側で試してみます。 |
色々試してはいるのですが、正直 ffmpeg ほどうまくいっていない感じです。 |
状況のご連絡ありがとうございます。 まだNVEncC側の改善が必要そうですね。 GWの時間を利用してffmpegの挙動と比較するなどして、もう少し改良できないか見てみたいと思います。 |
ありがとうございます。 こちらでも色々試してはいるのですが、どうも挙動がはっきりとわからなくて、なんとも言えないもどかしい状態です。 こちらの環境が悪いのかもしれませんが、番組やタイミングによってストリームの認識にかかる時間がかなり変わる?ようで、一定ではなく、早かったり遅かったりするみたいです。同時間に放送されているチャンネルでも、明らかにストリームの認識が早いチャンネルと遅いチャンネルが存在します。しかもチャンネルによって固定というわけでもないので、ますますよくわかりません。本当にひどいときだとUDP送信はとっくに始まっているのに、ストリームの認識に10秒以上待たされる事もありました。 ストリームの認識が早いチャンネル/番組、遅いチャンネル/番組はたしかにあるようなんですが、タイミングによっても?早い遅いは変化するようで、これも一定ではありません。それもあってよくわからないでいます。 これは今回の beta 版の更新による問題ではなく、以前からこのような状態だったようです。エンコーダーが違うからか完全に同じ認識秒数というわけでもないようですが、QSVEncC でも同様の傾向がありました。NVEncC で認識が遅いチャンネルは QSVEncC でも遅いし、その逆も然り。 そして、ffmpeg + というわけで、現時点では ffmpeg だとチャンネルによって認識時間が変わったりもせずほぼ一定で素早くストリームを認識してくれるけど、QSVEncC・NVEncC(環境がないのでわからないけど、おそらく VCEEncC も)ではどういうわけかチャンネルによって認識時間が変わったりがあるし、--input-probesize や --input-analyze を付与してもうまくいかない状態です。 |
1. NVEncCの改善 実際にTVRemotePlusを導入し、いろいろなチャンネルで動作確認を行いました。たしかに、エンコード開始に非常に時間のかかってしまうタイミングやチャンネルがありました。 私は従来 より詳細に調べると、ご指摘のように--input-analyzeはどのように指定しようが、ストリームの認識が遅い場合があり、これを防ぐには--input-probesizeを このとき、--input-probesize 8192のような設定では、0.5秒に1回程度やってくるGOPの先頭についている映像のヘッダを認識できずエラーとなってしまいます。これを防ぐため、--input-probesizeを適切に指定する必要があります。--log-level debugで詳細なログを見ると、
となるように設定する必要があります。 チャンネルごとにビットレート(スロット数)が違うので厄介ですが、BSの最大ビットレートを24Mbps(=3MB/s)とす仮定すると、probesize=900K程度がよさそうです。 まずは添付の実行ファイルNVEncC64_5.31beta2.zipをお使いいただき、 2. ffmpegの挙動の確認 次に、ffmpegの このとき、mpegtsの構造認識は終わっているものの、映像のヘッダ情報をとれていないという状態のまま、次に進んでいるようです。まあたしかに、これなら
ただその後、ヘッダーがない状態でデコーダを起動しているので、しばらくデコードエラーが出ていますが、
途中で(おそらくGOPが切り替わりヘッダを認識したところで)回復しています。
このように、ffmpegはとりあえずデコーダ・エンコーダを起動してしまい、デコードできるようになってから処理できるようになっているようです。 現状NVEncCはffmpegのようにデコーダのエラーを許容するようになっていないので、これとまったく同様の動作の再現は現状では難しいです。 まずは上記1.で示したような対応方法をお試しいただけないでしょうか。1.の方法でも遅いようですと、さらにNVEncCの実装見直しが必要になりそうです。 よろしくお願いいたします。 |
わざわざ導入までしていただいての素早いご対応に感謝します。ありがとうございます。 全体的にストリーム開始までの時間が(ffmpeg ほどとまではいきませんが)いくらか短縮され、またまちまちだったストリームの認識時間もあまり変わらなくなっていると思います。少なくとも、ストリームの認識に10秒以上かかることはなくなりました。
あとはごくまれに上記のようなエラーが出てエンコーダーが落ちてしまうことがあったくらいでしょうか。これに関してはちょっと probesize 諸々縮めすぎって事なんでしょうけど… |
早速お試しいただきありがとうございます。一定の効果が得られていてよかったです。
おっしゃる通りprobesize を縮めすぎということになるのですが、このエラーでエンコーダが落ちてしまうとストリームの立ち上がりがだいぶ遅くなってしまうので、こちらの問題への対策として、新たに
--log-level debugをつけるとファイル出力のタイミングがログに出ますが、わたしのほうではあまりラグがあるようには見受けられませんでした。なにか条件などがあるのかもしれませんが… |
返信ありがとうございます。 以前書いた tvk の放送休止の番組(カラーバーとビープ音が延々と流れるやつ)は、5.31beta3 でも残念ながらストリームの認識が遅いです。ffmpeg(字幕なし)では他の番組同様速いです。 少し話がそれてしまいますが、エンコーダーのストリーム認識時間の件と同時並行で、arib-subtitle-timedmetadater を TVRemotePlus に導入する準備をしています。develop ブランチにてテスト中です。 arib-subtitle-timedmetadater は monyone 氏が 元々 ARIB 字幕を再生するような仕様が HLS にある訳がありませんから、従来の手法の場合、HLS の再生には hls-b24.js のような TS から ARIB 字幕を取り出せるようにパッチを当てた hls.js(HLS 再生ライブラリ)を使う必要がありました。また、iOS Safari の制限で hls.js を使うことができない(内蔵 HLS プレイヤーを使うほかない)iOS では字幕を TS から取り出せないので、字幕を描画できないという問題がありました。 さらに、ffmpeg 4.2.0 以降は ARIB 字幕が arib_caption と字幕の一形式として認識されるようになりました。ffmpeg の HLS エンコーダーは字幕ストリームを強制的に webvtt に変換しようとしますが、arib_caption から webvtt に変換するエンコーダーはないためエラーで落ちてしまいます。monyone 氏開発の arib-subtitle-unrecognizer という arib_caption として認識させなくする 一方、ID3 メタデータが HLS の TS 内に入っている状態は HLS の仕様で規定されているようで、そのため TS セグメント内の ID3 メタデータであれば hls.js でも iOS Safari の内蔵 HLS プレイヤーでも標準で読み取る事が可能です。この新方式では従来の方法では不可能だった iOS Safari でも字幕を表示できるようになるので、今試しに実装してみています。 前置きが長くなりました。 さて、arib-subtitle-timedmetadater は TSTask から送信されてくるストリーム入力とエンコーダーとの間に入りそこで ARIB 字幕 → ID3 メタデータへ変換したTSを出力するため、必然的にエンコーダーではなく arib-subtitle-timedmetadater にて UDP 受信を行い、変換結果をパイプで NVEncC を含め各種エンコーダーに渡すような形態になります。 なのですが、先ほど実装いただいた
arib-subtitle-timedmetadater のエラー内容は上記の通りで、monyone 氏に問い合わせたところ「GitHub に上げられてないので差分が全く分からない…」「どのみち broken pipe になった時点でできる事ないし、入力を閉じないでくれというしかないですね」とのことでした。 次に、この手法の場合、あらかじめ arib-subtitle-timedmetadater によって挿入された timed_id3 ストリーム(注:ARIB 字幕のストリームを上書きするわけではなく、その隣のストリームとして挿入されるっぽい)をエンコーダーにコピーしてもらう必要があります。 そこで、timed_id3 ストリーム(もしくはデータストリーム全体)をコピーするオプションを実装していただけないでしょうか? 正直 arib-subtitle-timedmetadater を使った新方式は、ほかにも
などの面倒な課題を抱えていて一筋縄ではいきそうにないのですが、NVEncC (QSVEncC/VCEEncC) 側で対応していただければゴールが見えてきそうです。 …かなり長文になってしまいました。 |
現状と今後の開発予定について詳細にお知らせいただき、ありがとうございます。 1. input-retryについて なるほど、標準出力をNVEncCで受ける形を検討されているのですね。
エラーメッセージだけの問題ならエラーメッセージは標準出力でなくエラー出力に出せばよいだけですが、それだけでは解決しなそうですね。ファイルオープンしたままの再初期化は難しく、すみませんがいまのところこれ以上の改善案が浮かびません。現状のように、お手数ですがTVRemotePlus側でのプロセス再起動が妥当な対策と思います。 2. timed_id3 の転送 ご指摘のように 3. arib-subtitle-timedmetadater について developブランチを使用させていただき、 本日のNHKを処理したときのNVEncCの受け取ったパケットのタイムスタンプを出力しました。(NVEncC64_5.31beta4.zipで stream1.m3u8.packets.csv.txt の一部を抜粋します。一番右の列がタイムスタンプです。
このように、 4. 字幕mux時の8~10秒程度の遅延 これはffmpegに限らず、NVEncC等でも発生する遅延で、muxキューによる遅延と考えらます。 出力tsに映像と音声と字幕の各トラックをmuxして出力する際、各トラックの処理にかかる遅延はトラックごとに異なるので、データが常に同時にやってくるとは限りません。mux処理では、こうしたずれを調整し、各トラックのデータパケットの時刻(=タイムスタンプ)を同期して、同時刻のデータは近くに出力するよう調整する必要があります。 このとき、字幕データの扱いは難しく、継続的にデータが流れてくる映像や音声と異なり、字幕に関しては字幕のない時間というのが存在しますので、ある時刻に字幕データがあったりなかったりします。 mux処理では、字幕がない箇所では、字幕データがないことを確認するために、一定の時間(デフォルト=10秒分)映像や音声のデータをmuxキューにためて、その間字幕データがなければ字幕データがないと判断するようになっています。字幕を出力する際に10秒遅延が増加するのはこのためです。 今回のようなリアルタイムエンコードでは、10秒も待たなくてよいのではないかと思います。muxキューが待機する長さは下記オプションで調整可能です。下記では5秒にする例を示しました。 ffmpeg: なお、あまり短くしすぎると、字幕や音声のタイミングずれにつながりますのでご注意いただければと思います。 |
1. input-retryについてそうでしたか… わかりました。折角実装していただいたのに本当に申し訳ないです。 本来は些細な事で止まりがちなエンコーダーを監視するバックグラウンドプロセスを立ち上げて、その中でエンコーダーなどの出力を管理する(エンコーダープロセスの立ち上げ、ログの監視、エンコーダーが停止したら再起動、エンコード停止命令があればプロセスをKillする)のがベストだと思うのですが、元々軽い気持ちで試しに作ってみたツールに積み木のように後先考えず機能追加を繰り返していった結果コードが最悪な事になってしまっていて、そのような大幅な変更は現状難しいです。 ただ、いつになるかは分かりませんが TVRemotePlus の後継ソフト(機能的には似たようなソフトだが、Python(PHP では Windows 固有の問題に対処する事が難しいため)で一から作り直しもっと使いやすくする)を作る計画を練っていて、その時にはちゃんと実装するつもりでいます。 2. timed_id3 の転送最新の develop ブランチにおいて NVEncC で このあたりを調査している時に音声多重放送+字幕放送の場合に副音声で再生されてしまうケースがあったため、そのあたりのエンコードコマンドを調整しました(音声多重放送の番組を見ないので知らなかったけど、この件と関係なく前からだったかもしれない…)。 3. arib-subtitle-timedmetadater について前回のレスで報告した時に挙動確認を怠った私のミスなのですが、その時点での arib-subtitle-timedmetadater には不具合があり、ビット演算が JS だと丸められてしまう(?)とかで正しくない PTS が出力されてしまっていたみたいです。 実際、ffmpeg でも字幕の PTS タイムスタンプが不正なため、字幕が映像より10秒近く早く描画されてしまう(音声と字幕のタイミングが一致しない)事がありました。arib-subtitle-timedmetadater の更新後は ffmpeg であっても、NVEncC でもあっても字幕が音声と同じタイミングで表示されていました。ぜひご確認いただければと思います。 …ただ、なぜか「NVEncC でのみ」字幕のタイミングがずれる番組を一部で確認しました。同じ番組を ffmpeg でエンコードすると 100% 問題なく再生できているので、NVEncC 側の処理に何かしら問題があるとみています。 arib-subtitle-timedmetadater に関しては monyone 氏いわくまだ不具合があるかもとの事で、実際に一部の字幕がなぜか描画されない(これに関しては ffmpeg・NVEncC 共通)などの問題が残されています。もしかすると arib-subtitle-timedmetadater 側の問題なのかもしれませんが…。 4. 字幕mux時の8~10秒程度の遅延
てっきり ffmpeg のバグかと思っていましたが、そういうことだったんですね…!!確かに 10 秒ほど遅延するのも説明がつきます。納得です。
このオプションを ffmpeg と NVEncC それぞれに付与した所、字幕ありの場合でのエンコード開始までの時間が大幅に短縮されたように感じます。 字幕あり (ID3ストリームをコピーするオプションを付与) の場合、字幕なし (ID3ストリームをコピーしない) の場合で比較してみましたが、このオプションを付与するだけで再生が始まるまでの差がほとんどなくなったように感じます。番組にもよるかもしれませんが。
懸念していた音声のズレに関しては ffmpeg・NVEncC とも特になく普通に再生できたので、 ということで、現在の arib-subtitle-timedmetadater 対応の課題は下記のようになります。
せっかくのGWに色々対応していただいていて感謝です。 |
いろいろテスト、コメントいただきありがとうございます。muxキューによる遅延の件は、お役に立ててよかったです。 iOSはいろいろややこしそうですね…林檎がハード周りで独自仕様で面倒なのは知っていましたが、web周りでも独自仕様なのですね。 さて、こちらでも arib-subtitle-timedmetadater を更新させていただき、ご指摘いただいた NVEncC 使用時に字幕の描画タイミングがずれる問題について調査いたしました。原因は少し見えてきましたので、状況をご説明したのち1点質問させてください。 まず、原因としてはtimestampが認識できないtimed_id3のパケットが arib-subtitle-timedmetadater から送出されており、こうしたtimestampの設定されていないパケットを NVEncC が正常に処理できないためのようです。 本日テストしたときのパケット情報(stream1.m3u8.packets.csv.txt) から一部を抜粋します。
パケットのtimestampが認識できないのは、NVEncCだけの問題ということではなく、ffmpegでも同様でした。同じ番組に対して、ffmpegに
ffmpegはこうした状況でも(どうやってか)処理を継続できるようですが、NVEncCではこうしたtimestampを認識できないパケットのところでパケットの時刻が判断できないために以降のtimed_id3パケットの処理が停止してしまい、字幕表示の大幅な遅延につながるようです。 こうした状況が発生する条件はよくわからないのですが、番組によってはこうしたtimestampの認識できないパケットが多発しておりました。 ここで質問させていただきたいのですが、このような timed_id3 ストリームにtimestampが設定されないことがあるのはこういうもの(仕様)でしょうか、それとも「まだ不具合があるかも」のほうでしょうか? このあたりの字幕の仕様があまり理解できておらずすみません。 意図されていないものでしたら、可能であれば修正を monyone 氏にお願いいただけますと幸いです。 また、そうではなく仕様ということですと、NVEncCにパケットのtimestampが設定されていない場合の例外処理を加えないといけないかなと思っています。ただ、その場合は周囲のtimestampから適当に補完するぐらいしか思いつかないので、若干本来の時刻からずれてしまうかもしれません。 よろしくお願いいたします。 |
ありがとうございます。 私の方で調べたところ、NVEncC で字幕がずれるのはどうやら日テレ・テレ朝・TBS・フジテレビのみのようで、局によるようでした。 ということで、あとは arib-subtitle-timedmetadater でパケットロスが発生して画面にブロックノイズが入ってしまう問題が解決すれば、ついに正式対応できそうです。 |
字幕がずれる件、確認いただきありがとうございました。問題が解決したとのことで安心しました。 それでは今後、今回NVEncCに行った更新をQSVEncC/VCEEncCに展開して、それぞれで同様に使えるようにしていきたいと思います。 |
ありがとうございます!トラブル続きで諦めかけていましたが、なんとか使える状態に持って行けて私も一安心です。 |
@rigaya PTS の値がずれているというのは、JavaScript では基本的に double で数値を扱うのですが noPTS が混ざっていたのは、前者で PMT の再構成の際に ARIB字幕の PID+ 1 を timed-id3 に無確認で割り当てたためです。 表示されない場合があったのは、timed-id3 PES の private_data に TS パケットに合うようパディングを入れていたためです。 最後に、一応、なぜ、このようなものが必要になっているかについて、説明いたします。 arib-subtitle-timedmetadater とはこのツールは名前の通り、ARIB 字幕を timed-id3 に重畳しなおすツールです。 このツールの目的ARIB字幕と同じ PTS で TXXX フレームに ARIB 字幕のバイナリデータを base64 して mpegts に重畳することで このツールの利点このツールで timed-id3 に ARIB 字幕を変換する利点は以下の通りです。
このため、非MSE環境、様々な OS であっても、このツールで変換すれば原理的にはクライアントは受け取る事ができます。 このツールの動作以下の機能から構成されています。
つまるところ、PMT (Seciton) と 字幕 (PES) を置き換えて remux する、という動作をしています。 このツールの記述言語現時点では node.js 製の物をつくっております。node.js の Transform で変換処理を pipe として記述できます。 このツールの利用方法ffmpeg が現時点で arib subtitle の descriptor を落としてしまうため、ffmpeg より前段において動作する事を想定しています。
node.js 製なので、node.js であれば変換部分だけをプログラム内で利用可能です。 |
@tsukumijima 普段のNVEncCの実装では、処理遅延は許容してスループットを最大化する方向に振ることが多いのですが、今回は普段あまり意識しない処理遅延などについて注目したり、またはffmpegと挙動を比較したりしたことでいろいろ発見もあり、TVRemotePlusで使用する際のNVEncCの挙動改善につなげられたかと思います。 @monyone 今回PTSに関して発生していた現象についても理解できました。 |
@rigaya 関係者外から失礼いたします。要望だと思いますが、PTS 無しのパケットを支援することは可能でしょうか。 前述の通り、ARIB の文字スーパーは受信機が受信した後、すぐ表示するように想定されているため、mpegts のストリームで private_stream_2 を利用する、timestamp の無い Private PES で伝送されています。 背景としては、FFmpeg から出力された mpegts のストリームを mpegts.js + aribb24.js によって低遅延再生する際に、ARIB 字幕とARIB 文字スーパーを同時に表示できるようにしていました。https://twitter.com/magicxqq/status/1381786681926246402 EPGStation では既に mpegts.js が導入され、文字スーパーもまもなく対応するように進んでいます。@tsukumijima によると、TVRemotePlus も将来に mpegts.js を導入する予定があると聞いています。 FFmpeg の場合は、文字スーパーのパケットに対し warning が出ていますが、エラーになっていないので無事抽出できています。 もし NVEnc も PTS 無しのパケットを対応できるようになれば、文字スーパーの表示に大変助かると思います。 |
@xqq PTS 無しのパケットを処理できたほうが良いこと、承知しました。 次回の更新では、データストリームについてPTS 無しのパケットをそのまま転送できるよう、変更したいと思います。 |
NVEnc 5.31に更新し、要望いただいたデータストリームについてPTS 無しのパケットについて、そのまま転送できるよう変更しました。 文字スーパーも含めて転送する場合は、 |
ありがとうございます!!使わせていただきます。 |
(本来は QSVEncC の方に書くべきでしょうが、話題が同じなのでここで) 1秒だけですが字幕は表示できていたのでそのあたりは問題ありません。字幕あり/なしは関係ありませんでした。 以下に
デバッグ出力を切った場合は以下の通りになります。
個人的には
エラーからしてこちらではどうしようもできなさそうなので取り急ぎ報告まで。 |
QSVEncC 5.01 と、手元にあった QSVEncC 4.04 でスタンダードに ただし、HLS でないからか普通にエンコード自体は終わりました。途中でエンコードが終わっているといったこともありません。音声は両者とも問題ないように見えます。 Test_QSVEncC_4.04.mp4これが QSVEncC 4.04 でエンコードしたもの、 Test_QSVEncC_5.01.mp4こっちが QSVEncC 5.01 でエンコードしたものです。 Test_QSVEncC_5.01sw.mp4なんとなくデコードがうまく行っていないような気がしたので --avsw リーダーでソフトウェアデコーダーを使うようにしてみたら、上の通りあっさり正常にエンコードできました。おそらく問題はデコード側にあると思います。 |
QSVEnc 5.01でデコードがうまくいかないとのことですが、おそらく5.00で行った大規模更新に伴い、場合によってはSandyBridge環境に対応しなくなったものと思われます。 まずはじめに、ご留意いただきたい点として、QSVEnc(NVEncもVCEEncもそうですが)の想定動作環境は以下の通りとなっております。 Windows 10 (x86/x64) ハードウェアエンコード関連はデバイスによる差異が大きく、Windows10が標準でサポートしない過去の環境についてサポートを私個人で継続していくことは作業量の増大を招くため難しいので、大変勝手ながらこのようにさせていただいています。 さて、こちらでも確認のため適当なtsで
思いつく有効と思われる対応策・回避策として下記をお試しいただけますでしょうか?
お手数をおかけしますがよろしくお願いいたします。 なお、ご指摘いただいた下記エラーメッセージについてですが、
これはSandyBridgeがOpenCLをサポートしないため表示されますが、その後OpenCL抜きで動作するよう回復処理が行われるようになっており、特に問題はありません。 |
--input-probesizeの追加を上記QSVEnc 5.01に続き, VCEEnc 6.11でも行いましたので、ご連絡します。 よろしくお願いいたします。 |
うちはもう他のPCでモニタの接続が使われていて、録画マシンはあまりさわらないのでRDPでしか普段は操作していないです。ただ、そちらではRDP未使用でもブロックノイズが出るのですよね。となると条件が違うことになり、もっと広く発生する可能性があるのかもしれません。
そうですね、条件切り分けのため、開発版のstream.phpを改変して、TSTaskからのUDPやTCPを直接QSVEncCで受信してテストしています。このとき、やはり従来のUDP直接受信は問題ないです。TCPはarib-subtitle-timedmetadaterを介した場合でも介さず直接受信してもブロックノイズが出てしまいました。(TCPの送受信のトラブルと考えると、むしろarib-subtitle-timedmetadaterを介した場合でもだめというのは逆によくわからない…)
tsはたしかに中途半端なところからデータ開始となることが多いですが、それについては読み込み時に対策の実装を私のほうでしています。また、それ自体はファイル読みでもそうですし、NVEncCでもそうなので、原因ではないのかなあ、と思います。 調べれば調べるほど原因が思い当たらない状況ですが、他の不具合修正と並行してもう少し調べてみます。 |
ですよね… 確かに調べれば調べるほど原因がわからないって感じの… 一応お伝えしておくと、NVEncC でも 30 分に 1 ~ 2 回あるかないか程度の頻度で極稀に若干のパケットロスが発生することはあるようです。ただし、あったとしても微々たるもので、ごく一瞬だけ音声が繰り返しになったり映像の一部が乱れたりする程度なので許容範囲だとは思います(画面全体にはっきり出るほどではなく、ぼーっと見てれば気づかないくらい)。これに関しては arib-subtitle-timedmetadater 側で TCP の受信バッファを設定できれば解決しそうな気もしますが、node.js で TCP の受信バッファを設定する方法がわからない… TSTask に原因があるとすると ffmpeg や NVEncC でうまくいく説明がつかなくなるし、一旦 TCP で通信が行われる事による何かしらの変化とかがあるんでしょうかね…? |
そうなんですよね、私はこのあたりの知識はど素人ですが、TCPとUDPでいえばTCPのほうがドロップしなそうなイメージですが。また、TCP受信か標準入力か、どちらかはうまくいきそうなものです。
プロセスの優先度は、TSTaskを高優先度とかQSVEncCを高優先度とか、いろいろな組み合わせを試しましたが関係ないようです。 調べるとどんどん原因の候補がつぶれてはいくのですが、原因に辿りつけず、とにかくTCPを経由した状態でQSVEncCを使うとなにかが起こってしまうようで、全く原因がわからず手詰まりの状況です。 そこで異なるアプローチとして、 ただ、この方法だと字幕なし番組→字幕あり番組に切り替わった時に字幕が表示されないという問題が残ります。そのため、これでいいかというと微妙ですので、ひとつの案としてこういう方法もある、ぐらいで考えていただければと思います。 !! 最初に同梱したQSVEncCが古いものだったので再度更新しました(5/22 11:28) !! この変更を通じてTCP使用時のブロックノイズの原因のヒントがなにかわかるかな、という目論見もあったのですが、やはりUDPだとうまくいく、ぐらいしかわかりませんでした。うーん…。 |
まさかのアプローチで大変驚いています。たしかにこれならパケットロスなくエンコードできると思います。
これに関しては QSV/NV/VCEEncC 側の実装で改善することは可能でしょうか? もしこれが可能なのであれば、ご提案いただいた方法で正式に採用することも考えたいと思います(この方法なら --input-retry が使えますね)。 あと、実際の動作はおそらく問題ないとはいえ、受信方式を UDP と TCP 両方使うというのが実装的にかなりもにょります。本当はあまり複雑にしたくないしできる限り統一したいんですけどね… |
もう一つ TCP を使わない方法として、arib-subtitle-timedmetadater で UDP 受信してしまうとどうしてもパケットロスが出るので、パケットロスなく UDP 受信できるツールをどうにかして用意することができれば、arib-subtitle-timedmetadater に標準入力で受信データを流しパケットロス(ブロックノイズ)なくエンコードできるような気はします。 ただし「パケットロスなく UDP 受信できるツール」がいくら C++ で書いたとしても実現可能なのかは不明ですし、そこをクリアしないと難しいです。そして私は C++ が書けない… これはこちらでも検証してみようと思っていますが、あとは EpgDataCap_Bon の TCP 送信機能で受信した場合に挙動が変わるのかも気になります。 |
おっしゃる通りです。いとも簡単にブロックノイズが出ます。 ffmpeg/NVEncCでは問題ないが、QSVEncCで問題が出る以上、QSVEncCになにか原因がありそうとは思います。ですが逆に、libavformatでの受信方式を変える、たったそれだけでブロックノイズの有無が変わってしまうので、それはもはやQSVEncCでどうしようもないのでは、ということで堂々巡りです。
さすがにこれを機能として継続的にサポートするのは厳しいと考えています。
なるほど、私の理解不足で申し訳ありません。TCP/UDP併用は私の想像していた以上になかなかややこしいこと、説明いただいて理解できました。そう考えると、今回の方法は実装が複雑になりそうということで没にしたほうがよさそうですね。 |
そうですか… もしそれが実装できるのでしたらもうこれで暫定解決というのも考えはしたのですが。
せっかく色々実装していただいたのに申し訳ないです。
そういえばこの問題って HLS 出力でのみ発生するのでしょうか。単に TSTask なり arib-subtitle-timedmetadater なりから TCP 受信したものをファイルに書き出してみて、それでブロックノイズがないなら HLS 出力に関係するオプションや HLS 関連の実装に絞り込めそうです。 にしてもそちらがここまで調べてくださっているのに原因に全くたどり着けないとなると、色々どうしようもないですね…😥 |
TSTask の代わりに暫定的に EpgDataCap_Bon の TCP 送信機能を使う構成(TSTask を立ち上げるコードをコメントアウトし、代わりに EpgDataCap_Bon を 127.0.0.1:8201 に TCP 送信する状態で起動させっぱなしにしておく)で試した報告です。 ただし TSTask の場合と症状が異なっていて、EpgDataCap_Bon の場合は最初の大きいブロックノイズだけでなく、10秒に1~2回くらいのペースで頻繁にブロックノイズが入ります。 さらにこの症状は NVEncC や ffmpeg でも発生します。QSVEncC より若干頻度が少ない…かとも思いましたが、場合によりけりのようで顕著な差ではありませんでした。 これは以前 ffmpeg / ffplay で TSTask からの TCP 受信を試した時に頻繁にブロックノイズが入ってうまくいかなかった症状と概ね同じです。これに関しては TSTask 側で BonDriver_TCP 用のヘッダを送信しない設定にしたり、一度に送信するサイズを 256 から 188 に変更しているのが効いているのではないかと考えています。 …と、TSTask との挙動を比較する以前の問題のようで、残念ながらあまり比較になりませんでした。 |
EpgDataCap_Bon の TCP 送信機能 (SendTSTCP) 内で独自ヘッダを出している箇所はどこにあるんだろうと思い軽く探してみたら、https://github.com/xtne6f/EDCB/blob/work-plus-s/SendTSTCP/SendTSTCP/SendTSTCPMain.cpp が見つかりました。 コードを読む限り、どうやらポート 22000 ~ 22999 までの間なら BonDriver_TCP 用の独自ヘッダ( SendTSTCP プロトコル?)は送信されないようになっているようでした。なんでそうなっているのかはよく分かりませんがこの仕様を活用させてもらい、EpgDataCap_Bon → arib-subtitle-timedmetadater → QSVEncC の構成にて再度 TCP 受信の試験を行いました。 試験方法まず、TVRemotePlus の環境設定で、[UDP 送信時の開始ポート番号] を 8200 から 22000 に変更します。
最後に、modules/stream.php 内の TSTask 起動用コマンドを実行する箇所(ここ と ここ)をコメントアウトします。 この状態で Stream 1 で適当なチャンネルでストリームを起動すると、EpgDataCap_Bon(ポート:22001)からの TCP ストリームが受信に利用されます。 結果と考察驚くべき事に今まであれだけ不安定だった QSVEncC がいきなり安定し、ブロックノイズが一切なくなりました!! つまり、まず BonDriver_TCP 向けの独自ヘッダはエンコーダー(というより BonDriver 以外)で受信するときには完全に不要で、入れてしまうとどのエンコーダーでも正常に TS を処理しきれず、小さめのパケットロスが出てしまうようです。 EpgDataCap_Bon での受信において全エンコーダー共通の「連続的で小さめ」のブロックノイズを解消できたので、本題の QSVEncC のみで発生する「最初限りの大きな」ブロックノイズが発生するかどうかを検証しました。 かれこれ 20 回以上は QSVEncC の再起動やチャンネル変更、字幕あり番組なし番組など様々なパターンで試験したのですが、結局一度も「最初限りの大きな」ブロックノイズは発生しませんでした…!! TSTask と EpgDataCap_Bon 両方で BonDriver_TCP 向けの独自ヘッダは送信しないようにしてあります。その状態で TSTask での TCP 送信ではパケットロスが発生し、EpgDataCap_Bon ではパケットロスが全く発生しないという結果が得られました。 もちろんなぜ QSVEncC でのみうまくいかないのかは未だ謎ですが、少なくともなぜ TCP 受信でのみパケットロスが発生するのかの理由の説明にはなるはずです。 元の状態に戻した状態で QSVEncC を同じチャンネルで動かしてみた所、下記のような散々たる結果になりました…
また、これは確証はないのですが、前回の試験同様に独自ヘッダが付与される 8201 ポートで TCP 受信した場合でも、「連続的で小さめ」なブロックノイズは発生しますが、「最初だけの大きな」ブロックノイズは発生しないように見えました。 さらに、今まで私の環境のみ発生していた 1 セグメントのみでエンコーダーが落ちてしまう問題に関しても一切発生しなくなりました!なんとなく予想はしていましたが、やはりパケットロスに耐えられずに落ちてしまうのが原因だったようです。 今回「通常状態」でも試験を行ったところ、2 セグメントでエンコーダーが落ちてしまった例を観測しました。その例では 1 セグメント目ではほぼブロックノイズなく通常通りエンコードできていたものの、2セグメント目でブロックノイズがいきなり酷くなり終了してしまっていました。 まとめ私の手元では EpgDataCap_Bon(独自ヘッダが付与されないポート 22000 ~ 22999 の範囲)から TCP 受信することで、今まで長らく課題になっていた挙動が全て解決し、QSVEncC でも NVEncC 同等の安定性で継続してエンコードできるようになりました!! ffmpeg・NVEncC の挙動も問題なく、字幕に関してもずれはありません。かなり理想に近い状態でした。 そして、1 セグメントでエンコーダーが落ちる問題と、ストリーム再生当初にドカっとパケットロス(ブロックノイズ)が発生する問題に関しては、TSTask の TCP 送信機能が QSVEncC にのみ悪影響を与える何かしら(?)を含んだ TS を流しているからではないか(要するに TSTask が何かしら悪い)、という仮説ができました。 まずはそちら側で EpgDataCap_Bon (ポート 22000 ~ 22999) での TCP 受信でブロックノイズがなくなっているかを確認していただければと思います。
もし原因がわからなかったとしても、最悪 TSTask から EpgDataCap_Bon へ受信アプリを変更すればどうにかなりそうな事が分かったので、私としては一安心です。 |
EpgDataCap_Bon でのテスト、また結果をご連絡いただきありがとうございます。 これはもうTSTaskのTCP送信の問題で確定ですね、ということでTSTaskを実際にデバッグしてみました。 するとTCP送信のretryループがあるのですが、このbreak文で一度もretryせずすぐ抜けてしまうのでretryが機能しておらず思いっきりdropしてました(デバッグwriteさせて実際に確認しました)。ソケット通信のコードに詳しくないので、もしかすると間違っているかもしれませんが、どうも実質1秒のタイムアウトになっているように見えます。 ということでfixtcpdropブランチでretryが機能するよう修正を試みました。 だいぶ改善したと思いますが、お試しいただけますでしょうか。 なんでQSVEncCだけdropが発生したかについては、QSVは他と比べて内部バッファが多いため、エンジン起動が遅く、その間パケットを読み込まないため、1秒のタイムアウトではdropが不可避だったためと思われます。一度起動してしまえば、常時パケットを読み込むので、dropしないこととも整合します。(1秒未満で起動しろというのは、そりゃ無茶です…) |
デバッグありがとうございます。やっぱり TSTask が原因でしたか…(まさか TSTask 側の不具合を直して頂けるとは思いもせず、恐縮です)
あと、tsukumijima/TVRemotePlus#7 にて送信する TS パケット数の拡大が行われていますが、これはデフォルトの 256 の方が好ましいのでしょうか。 ひとまず PR に関してはマージし、こちらでも検証してみます。 |
改良版の TSTask の導入と PR して頂いた TSTask-tvrp.ini の設定変更を行った状態で QSVEncC にて検証したところ、以前 EpgDataCap_Bon (ポート 22000 ~ 22999) で検証した際の状態と同じく、非常に安定してエンコードできるようになりました…!!!! 今回も 10 回以上はチャンネルを変えながら検証したのですが、ブロックノイズが入ることは一度もありませんでした。1 セグメント目で落ちてしまう問題も今のところ起きていません。 まさか TSTask が原因だとは思いもよらず、検証やデバッグ等で多大な苦労をお掛けしてしまい、本当に申し訳ありませんでした。 あとは他の環境でどうなるかですね… 再度になりますが、本当にありがとうございました! |
よかったです!!安心しました。やっと「これだ!」という原因を見つけてすっきりできた気持ちです。さすがにちょっと疲れましたです、はい…。 お力になれましたらば幸いでした。
もうQSVEncC側ではどうしようもないので、TSTask側をさわるしかないかなと思いました。
そうですね、開始数秒後にわりと高い頻度(3,4回に1回程度)でかなり大きな帯状のブロックノイズが出る問題は完全に(30回ぐらいは試してゼロ)出なくなりました。
いえ、TSTask起動から1秒以内でエンコーダーが受信できる必要はないです。今回はそのあとの問題で、エンコーダーが受信できる状態になりTCP接続を確立してから送受信をしている途中で、送受信の間隔が1秒以上空いてしまうことがあると問題になるようです。 QSVEncCはエンコーダ等を初期化するにも入力ファイルの情報が必要なので、まず そういった動作はTSTaskでは想定していないのかもしれませんが、retry回数を指定できるのだからその分はちゃんとretryしてほしいなあということで今回の修正となりました。 実際にデバッグ文を入れて動作させてみて、修正前dropしていた箇所で修正後はdropしなくなったことを確認しました。
これは、drop被害にあうパケット数を減らすためにそちらのほうでデフォルトから縮小されたのかなと思い、ただ今回drop問題が解消したのでデフォルトに戻せばよいかなと思っただけで、あまり深い意味はありません。
VCEEncC + TVRemotePlusを初めて試してみました。まず、わたしのドキュメントの誤りで、 まずほとんどの場合、ffmpegやNV/QSVEncC同様に安定して切り替え、字幕表示でき、またブロックノイズも出ないことを確認しました。 一方、たまに(10回に1回ぐらい?)エンコード開始時にVCEEncCが固まってしまう問題が発生します。ただ、これはファイル読みでもちょっとdropがあるだけで発生しますので、今回のTVRemotePlusの変更によるものではありません。 VCEのハードウェアデコードはこれは以前からエラー耐性がQSVより低く、厄介なことにちょっとしたdropでもすぐ固まります(HWデコーダがなにもいわずにフレームを返さなくなる)。残念ながらアプリ側(VCEEncC側)ではどうしようもないので、現状ではデコーダを監視して固まったのを検知したらエラー終了するようにしています。このあたり、将来的にはVCEEncC側でどうにかしたいですが、すぐには改善できそうになく、またユーザー数がNVEncCやQSVEncCより少なそうなのもあって、現状手をつけられていません。 申し訳ありませんが、安定性重視ならVCEEncCだけは |
VCE の HW デコーダーはちょっとしたドロップでもフリーズするなどエラー耐性が低く TS を扱う用途では不安定なため、安定性を優先する reference: rigaya/NVEnc#335 (comment)
私も同感です…。 相当な試行錯誤の上とはいえ、何はともあれ万事解決できたのが幸いです。
私の環境でも「かなり大きな帯状のブロックノイズ」でした。横に長くて灰色っぽいやつ…
という事なのでしょうか。
私としては「もしかすると TS パケットのサイズである 188 に合わせたほうがドロップしないかもしれない」という意図で設定していました。深い意味はありませんので、256 のままにしておきます。
問題なさそうでしたのでマージしました。報告ありがとうございました。
それはよかったです。これでようやくリリースが出せそうです…。
そうなんですね…了解です。頻度は比較的低いとはいえ、ちょっとしたドロップでもすぐ固まるのはしんどいですね… tsukumijima/TVRemotePlus@12a6464 にて、VCEEncC のみ 重ね重ねになりますが、長きに渡り対応してくださり本当にありがとうございました! |
@tsukumijima @rigaya
原因は、エンコーダとの受け渡しに標準入出力を利用していたため、 以下の 2 つの仮定を置いていたため、気づくのに遅れてしまい、把握するまでに時間がかかってしまいました。
また、自分の環境でTVRemotePlus を導入した限りでは TCP での受信は、時たま出来る、程度の安定性になっています。 実質的に TCP 受信でのフロー制御が機能していない以上、接続が切れても関係ない UDP の方がメリットが大きいと思います。 @rigaya |
TCP 送信でもうまく行っていたが、なぜか一部の環境で TSTask との TCP 通信ができない場合があるようで、ひとまず UDP に変更してみる asyncbuf.exe を間に挟んだおかげで今までのドロップはなくなったはず reference: rigaya/NVEnc#335 (comment)
こちらではTSTaskの修正後はTCP受信でも非常に安定していましたが、ダメなケースもあるということなのですね。
送信側がstdoutに流す場合、受け取り側が受け取らなくてバッファを超えてしまうと、受け取り側が受信を再開するまで送信側も書き込みのところで処理が止まるという認識でしたが、stdoutへの書き込みが非同期処理になっているというようなイメージでしょうか。 ともかくUDPに再変更されたものでもQSVEncCを用いて試しましたが、asyncbufを挟んだおかげか、UDPでも問題なさそうなことを確認しました。 |
ご確認ありがとうございます。
これに関しては、同期処理で stdout に流した際に処理が止まってしまう、同期書き込みにしています。
この挙動で、stdout への書き込みが止まった際に、受信が止まると困った事態になってしまうのが、原因になります。 |
失礼します。
という処理がループするのですが、
とすることで失速を回避するものです。 そこで、 |
もともとそういう用途だったんですね。EMWUI の方には「再生のむらを吸収します」としか書かれておらず、EDCB でどういった使われ方をしているのかよく理解できていませんでした。
私の環境でも TCP でとても安定しているので、monyone 氏の環境でそうなるのがよく分からないな…という印象です。 TVTest (BonDriver_TCP) ならうまくいくそうなので何かしら TSTask に問題があるのだとは思いますが、おそらく環境依存な上に UDP なら全ての環境でうまく行っている以上、この問題にこれ以上リソースを割かなくても…という気持ちもあります。 |
@xtne6f この度は自作ツールの導入でご迷惑をおかけし申し訳ありません。
TCP では自分の環境固有に問題 (Bondriver_Mirakurun と TSTask の相性が悪い?) のかとも思っています。 この Issue が混沌としすぎていて、rigaya さんにも迷惑なのではと思っていますので (WinSock に詳しくないので、お役には立てないかと思いますが...) |
@monyone
そうですね、わたしがいうことではないかもしれませんが、個人的には UDP+asyncbuf の方法でより多くの環境で安定して動作し、必要な機能が実現できているのを確認できているので、特にほかに問題なければ UDP+asyncbuf を使用するのがよいのではないかなと思います。(わたしからTSTaskに手を出しといてなんですが、TSTaskのデバッグが目的ではないと思うので) |
@tsukumijima @monyone 返答ありがとうございます。
おおよそ6月3日の最新ってことで、TVRemotePlus/44468a9 あたりだと思いますが、このバージョンなら TSTask も更新されているようなので問題なさそうです。
とのことなので Mirakurun/BonDriver_Mirakurun を一通り弄ってみましたが、こちらの環境では問題ないです。 |
QSV/NV/VCEEncC を TVRemotePlus にて使わせていただいています。ありがとうございます。
さて、TVRemotePlus のライブ配信は TSTask から受け取った UDP の MPEG2-TS ストリーム(放送波)の映像を H.264 に再エンコードし、HLS (m3u8+TS) 形式に変換してそれをブラウザで再生する事で実現しています。
しかし、ffmpeg と、ffmpeg をベースに使用している QSV/NV/VCEEncC では受け取った TS ストリームを認識するまでに時間がかかり、その影響でブラウザ上で再生が開始されるまでに時間がかかってしまっています。
ストリームを開始してからブラウザ上で再生が開始されるまでにかかる時間は上記のように積み重なっていますが、このうち 3 番の「ffmpeg・QSV/NV/VCEEncC が UDP で受け取った TS ストリームを認識するまでの時間」にボトルネックがあることがわかりました。UDP が問題なのかとも思い TCP やパイプで渡してみたりもしたのですが、同様の状態でした。
ところが最近、ffmpeg にて試しに
-i
オプションの前に-f mpegts -probesize 8192 -analyzeduration 0
を指定してみたところ、 3 番にかかる時間が大幅に短縮され、結果的にブラウザ上で再生が開始されるまでの時間を2~3秒も短縮することができました。-probesize
と-analyzeduration
はいずれも入力ストリームの解析を行う上限のバイト数と時間(秒)を指定するもののようですが、これをあえて低い値にすることで入力の解析時間を短縮し、それが全体の時間短縮に繋がっているものと考えられます。入力がパイプで出力が MPEGTS (H.264) の場合は
-probesize
を最小の 32 にまで小さくすることもできるようですが、UDP で HLS 出力という関係か、8192 が実用上の限界でした。それでも 2 秒も短縮されるのは大きいです。しかし、QSV/NV/VCEEncC には ffmpeg の
-probesize
に相当するオプションがありません(少なくともオプションを確認した限りはそう見えます)。-f
に相当するオプションは--input-format
、-analyzeduration
に相当するオプションは--input-analyze
として存在するようですが、-probesize
に相当するオプションが今のところないため、QSV/NV/VCEEncC では再生開始までの時間を短縮できていません。そこで、QSV/NV/VCEEncC にも
-probesize
に相当するオプションを実装していただけないでしょうか?試しに QSVEncC・NVEncC で
--input-format mpegts --input-analyze 0
のように ffmpeg の-probesize
以外の相当するオプションを追加してやってみましたが、明らかな短縮効果は感じられませんでした。-probesize
と組み合わせて初めて短縮効果が出るみたいです。この手法を教えて頂いた方いわく、QSV/NV/VCEEncC の
-probesize
は 0.5GB で固定になっているとのことでした ( https://github.com/rigaya/QSVEnc/blob/8ca51bb13bd6052def2b9372fbba4d76098eaf93/QSVPipeline/rgy_input_avcodec.cpp#L1207-L1214 )。avformat_find_stream_info に probesize を指定する事は難しくないんじゃないかとも ( https://programmersought.com/article/430134736/ )。私は C++ も libav も分からないのでさっぱり理解できていませんが…私がメインで使わせて頂いているのが NVEncC なのでこちらのリポジトリに投稿させていただきましたが、もし可能であれば他の QSVEncC・VCEEncC にも実装していただけると大変助かります。
お忙しいとは思いますが、ぜひご検討をよろしくお願いします。
The text was updated successfully, but these errors were encountered: