feat: initial packet-stats implementation - #185
Conversation
`SendStopMessage()` emits `"type": "stop"`, but the help text documented the message as `end`.
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #185 +/- ##
==========================================
+ Coverage 75.39% 76.74% +1.34%
==========================================
Files 38 40 +2
Lines 4755 5142 +387
Branches 477 512 +35
==========================================
+ Hits 3585 3946 +361
- Misses 876 879 +3
- Partials 294 317 +23 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
LGTM. copyrightがmasnagamになっていますが,あとで |
| } else if (stream.isSubtitles() || IsAribSubtitle(stream) || | ||
| IsAribSuperimposedText(stream)) { | ||
| SetCategory(pid, PacketCategory::kSubtitle); | ||
| } |
There was a problem hiding this comment.
@masnagam
自分で見ていて気づきましたが、
isSubtitlesはARIBのMPEG2-TSでは絶対にtrueにはならないかと思うので、削除しようと思います。
tsduck-aribのisSubtitles()は、ARIBでは使用しないDVBのDescriptorの内容を見ています。mirakc-aribの既存コードにも使用箇所はありますが、同じ理由でtrueにはならないのではと思いました。
あとカテゴリ名がsubtitleなのにsuperimposed textも含めてしまっていますが、
名称に偽りのある状態なので
これは対象外としても良いかと思いました。
なら別途superimposed textのカテゴリを作るか?と言う論点も出てくると思いますが
一旦カウントしない方針にしようかと思っています。
めったにsuperimposed textは実TSに入らないとは言え視聴に影響あるとは思いますが、
(めったに実TSに入らないので)確認が難しいためです。
概要
#77 の、
mirakc-arib record-serviceにおけるpacket statsを再実装しました。旧実装では全PIDのcontinuity counter(CC)を単一のカウンターで集計していましたが、映像・音声・字幕などのカテゴリ別にドロップ数を集計するように変更しました。
#77 のレビューコメントでmasnagamさんが指摘したとおり、
PSI/SIは再送される一方でPESのドロップは映像・音声の乱れに直結するなど、パケットの種類によってドロップの影響が異なるのが理由です。
ドロップ数は以下のカテゴリ別で集計します。
ドロップ数だけでなく、
ServiceFilter通過後の全TSパケットについてTEI(
transport_error_indicator)付きのパケット数とスクランブル化されたままのパケット数も集計します。stopメッセージのヘルプ文言も修正実際には
record-serviceでの録画終了時はstopメッセージが送られるのに、ヘルプ文言では
endと表記されているのも同時に修正しています。実装詳細
record-serviceに新オプション--packet-statsを追加しました。指定時は、次の形式の
packet-statsメッセージを送信します。{ "type": "packet-stats", "data": { "errorPackets": 0, "scrambledPackets": 0, "droppedPackets": { "video": 0, "audio": 0, "subtitle": 0, "pmt": 0 } } }errorPackets: TEI付きのパケット数scrambledPackets: TSCが0以外のパケット数(NULL PIDとTEI付きパケットは除外)droppedPackets: 不連続のCCから推定したカテゴリ別のドロップ数packet-statsメッセージは、各chunk、event-end、stopメッセージの直前に送信します。ただし録画開始直後に送信される最初の
chunkメッセージの直前でpacket-statsメッセージの送信を行う事はしません。集計は録画開始後に記録されたパケットのみが対象で、録画開始直後はまだ1パケットも集計されていないからです。
各カウンターは0から開始し、
packet-statsメッセージの送信ごとにリセットされます。各メッセージの値は、前回の
packet-stats(初回は録画開始)からの区間の集計値です。集計上の制約
ServiceFilterで除外されるパケット
ServiceFilterの後段に来るServiceRecorderで集計を行うため、ServiceFilterで除外されたパケットはerrorPacketsとscrambledPacketsに含まれません。稀なケースかも知れませんが、現在
ServiceFilterはTEI付きパケットを特別扱いしていないので、エラーにより
ServiceFilterの段階でPIDが既に化けていた場合は過剰(または過小)にerrorPacketsが計上される可能性もあります。16パケット以上の連続ドロップ
CCは4bitのため、ドロップ数は
(CC - 期待値) & 0x0Fで推定しており、正しく数えられるのは15パケットまでです。16パケット以上が連続してドロップした場合は16で割った余りが計上され、ちょうど16の倍数であればドロップなしと見なされます。
重複パケット
#77 の旧実装は前パケットとの比較で重複を検出していましたが、今回はそれをやめました。
MPEG-2 TSは同一パケットの2回送出を規格上は許していますが、日本のデジタル放送で重複パケットが送られたという報告は見つからず、対応する価値が低いと判断したためです。
前パケットを保持していないため、重複とドロップが区別できず、仮にペイロードを持つ重複パケットが送られた場合は15パケットのドロップとして計上されます。
PAT PID
ServiceFilterはPATを書き換えてからServiceRecorderに渡します。この際CCは必ず連続している状態になるため、入力TSにおけるPATのドロップは追跡できません。
PCR PID
映像PIDなどと共有されないPCR専用PIDは、ペイロードがなくCCが増加しないため、CCからドロップ数を推定できません。
映像PIDなどとPCR PIDが共有される場合は、そのカテゴリとしての追跡はされますが、
私の手持ちのARIB MPEG2-TSはPCR専用PIDしか使用していませんでした。
「映像PIDなどとPCR PIDが共有されていた」というネット上での報告も私が探した限りは無かったです。
テスト
実ストリームでの確認方法
指定したカテゴリのパケットを実際にドロップさせて、対応するカウンターが増えることを確認できます。
ちょうど良いツールが見当たらなかったため、標準入力のTSの一部パケットをドロップしたり、TEIやスクランブルを付けたりするts-corruptをAIで作成しました。
ts-pids.pyがtsresyncとtstablesを使うため、TSDuckが必要です。ts-pids.pyはPMTを読んでカテゴリに対応するPIDを--pid引数の形で出力し、ts-corrupt.pyがそのPIDのパケットの一部をドロップします。実行コマンドの例を以下で示します。
mirakc-aribは
~/Git/mirakc-arib/でビルドしていて、ts-corruptは~/Git/ts-corruptにあり、mirakcはhttp://ts262:40772で動作している前提です。ts-pids.pyの-cに渡すカテゴリを変えると、増加するdroppedPacketsのカウンターも変わります。video・audio・subtitle・pmtはdroppedPacketsの同名フィールドに対応します。otherはPMTに列挙された残りのPID(PCR専用PIDなど)で、カテゴリの分類対象外のためdroppedPacketsのどのカウンターも増えません。分類対象外のPIDでのドロップが、誤って他のカテゴリに計上されていないかの確認に使えます。
ts-corrupt.pyに--teiを付けると、パケットをドロップする代わりにTEIを立てるためerrorPacketsが増えます。--scrambleを付けた場合はTSCにeven key(10)を設定するためscrambledPacketsが増えます。テスト一覧
AIを使用し、テスト一覧と、テストの意図を示す日本語での簡潔な説明文を生成しました。
(テスト名だけですぐ意図分かりそうな簡単な内容のテストもありますが、全部に対し説明文を生成しました)
PacketStatsCollectorのテスト一覧TEI
TeiPacketIsCountedAsErrorAndExcludedFromContinuityTeiWithDiscontinuityIndicatorIsStillCountedAsErrorTeiPacketIsCountedEvenWhenPidIsIgnoredスクランブル
ScrambledPacketIsCountedScrambledPacketIsCountedEvenWhenPidIsUnclassifiedScrambledNullPacketIsNotCountedPIDの分類
PmtPidIsClassifiedAsPmtpmtに分類UnclassifiedPidIsIgnoredPmtClassifiesStreamsByCategoryPmtPidCategoryIsNotUpdatedByInvalidPmtPmtUpdateClassifiesPreviouslyIgnoredPidPmtUpdateResetsCategoryOfPidNoLongerReferencedPMT PIDの変更
SetPmtPidResetsCategoryOfPreviousPmtPidChangingPmtPidKeepsStreamClassificationUntilNewPmtPCR PIDとNULL PID
PcrPidIsIgnoredPcrPidSharedWithVideoStreamIsClassifiedAsVideoNullPidInPmtIsIgnoredCCとドロップ数
RegularPacketsProduceZeroErrorStatisticsSameCcRecordsDroppedPacketsMultipleMissingPacketsIncreasesDroppedWrapAroundMissingPacketsIncreasesDroppedNoPayloadSameCcDoesNotIncreaseDroppedNoPayloadCcChangedIncreasesDroppedDiscontinuityIndicatorDoesNotIncreaseDroppedPMT更新時のCC状態
RecategorizedPidDropsItsCcStateRepeatedPmtKeepsCcStateリセット
ResetPacketStatsClearsAllCountersServiceRecorderのテストEventProgress:--packet-statsの有無によるchunk/stop前のpacket-statsメッセージ送信と、最初のchunkの前では送信しないことを確認EventEnd:event-end/stop前のpacket-statsメッセージ送信を確認EventEndDoesNotIncludeItsTriggeringPacketInPacketStats:event-endを発生させた未書き込みパケットが直前のpacket-statsの集計に含まれないことを確認CLIのテスト
cli_tests.sh:record-serviceが--packet-statsを受け付け、空の標準入力に対して終了コード0で終了することを確認