@danything/arib 1.3.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ait.d.ts +4 -4
- package/dist/ait.js +5 -5
- package/dist/aribtext-gaiji.d.ts +1 -1
- package/dist/aribtext-gaiji.js +1 -1
- package/dist/aribtext.js +3 -3
- package/dist/b24-tables.d.ts +5 -5
- package/dist/b24-tables.js +42 -42
- package/dist/b24caption.js +3 -3
- package/dist/bml-protocol.d.ts +2 -2
- package/dist/bml-protocol.js +1 -1
- package/dist/bml.d.ts +4 -4
- package/dist/bml.js +17 -12
- package/dist/bytes.d.ts +3 -3
- package/dist/bytes.js +3 -3
- package/dist/caption-text.d.ts +1 -1
- package/dist/drcs-smooth.d.ts +1 -1
- package/dist/drcs-smooth.js +1 -1
- package/dist/dsmcc.d.ts +5 -5
- package/dist/dsmcc.js +4 -4
- package/dist/eit.d.ts +11 -11
- package/dist/eit.js +17 -17
- package/dist/multipart.js +1 -1
- package/dist/pes.d.ts +4 -4
- package/dist/pes.js +10 -10
- package/dist/psi.d.ts +11 -44
- package/dist/psi.js +26 -35
- package/dist/service-filter.d.ts +9 -9
- package/dist/service-filter.js +10 -10
- package/dist/synth-av.d.ts +5 -5
- package/dist/synth-av.js +8 -8
- package/dist/synth-caption.d.ts +1 -1
- package/dist/synth-caption.js +1 -1
- package/dist/synth.d.ts +10 -10
- package/dist/synth.js +11 -11
- package/package.json +1 -1
package/dist/eit.d.ts
CHANGED
|
@@ -99,7 +99,7 @@ export interface EitEvent {
|
|
|
99
99
|
*/
|
|
100
100
|
series?: EitSeries | null;
|
|
101
101
|
/**
|
|
102
|
-
* CA契約情報記述子 (0xCB) の contract_verification_info。
|
|
102
|
+
* CA 契約情報記述子 (0xCB) の contract_verification_info。
|
|
103
103
|
* 有料放送の契約確認・復号判定に使う (B-CAS の 0x90 0x3C コマンド)。
|
|
104
104
|
* 載っていなければ null。詳細の表では言っていないので undefined。
|
|
105
105
|
*/
|
|
@@ -124,10 +124,10 @@ export declare const PID_TIME = 20;
|
|
|
124
124
|
/**
|
|
125
125
|
* TDT / TOT のセクションから**放送の実時刻**を読む。別のテーブルなら null。
|
|
126
126
|
*
|
|
127
|
-
*
|
|
127
|
+
* 先頭 3 バイトのあとに MJD + BCD が 5 バイト。**TOT も同じ並び**で、後ろに
|
|
128
128
|
* 時差の記述子が付くだけなので同じに読める。
|
|
129
129
|
*
|
|
130
|
-
* データ放送 (`bml.ts` の `onTime`)
|
|
130
|
+
* データ放送 (`bml.ts` の `onTime`) が読んで、BML の時計にする
|
|
131
131
|
*/
|
|
132
132
|
export declare function parseTimeTable(section: Uint8Array): number | null;
|
|
133
133
|
/**
|
|
@@ -194,24 +194,24 @@ export declare class ScheduleProgress {
|
|
|
194
194
|
* **番号が飛ぶ。** 1 つの `table_id` が受け持つのは 4 日ぶんで、基本は
|
|
195
195
|
* `0x50` から、詳細は `0x58` から始まる。日本の放送は 8 日ぶんなので、
|
|
196
196
|
* 実際に流れてくるのは `0x50` `0x51` と `0x58` `0x59` あたりだけで、
|
|
197
|
-
* **`0x52`〜`0x57`
|
|
197
|
+
* **`0x52`〜`0x57` は永久に来ない**。
|
|
198
198
|
*
|
|
199
199
|
* `0x50` から `last_table_id` まで全部を待っていた頃は、詳細を積んでいる局が
|
|
200
200
|
* **一度も「揃った」にならず**、どのチャンネルも上限の 10 分 (denpa の `epgChannelTimeout`) まで開きっぱなしに
|
|
201
|
-
*
|
|
201
|
+
* なっていた (実機で、詳細の無い BS11 だけが早く閉じていた)。
|
|
202
202
|
*
|
|
203
|
-
* 見かけた表と、`last_table_id`
|
|
203
|
+
* 見かけた表と、`last_table_id` が指す表だけを見る。
|
|
204
204
|
*/
|
|
205
205
|
get complete(): boolean;
|
|
206
|
-
/**
|
|
206
|
+
/** その表でまだ来ていないセクション。セグメントの先頭すら来ていなければ、先頭の番号を数える */
|
|
207
207
|
private holes;
|
|
208
208
|
/**
|
|
209
209
|
* そのセグメントの時間帯がもう過ぎているか。**過ぎたものは待たない。**
|
|
210
210
|
*
|
|
211
|
-
* セグメントは 0:00 から 3 時間ずつの枠で、`table_id`
|
|
211
|
+
* セグメントは 0:00 から 3 時間ずつの枠で、`table_id` とセクション番号から
|
|
212
212
|
* それがいつの枠なのかが決まる。基本は `0x50` が当日 0:00 から 4 日ぶん、
|
|
213
213
|
* `0x51` がその次の 4 日ぶん。詳細 (`0x58`〜) も同じ並びをもう一度たどる。
|
|
214
|
-
*
|
|
214
|
+
* 終わった枠は放送されない (クラスの説明)。そのぶんの番組は、そこが未来だった数日前に取り込んである。
|
|
215
215
|
*/
|
|
216
216
|
private stale;
|
|
217
217
|
/**
|
|
@@ -281,11 +281,11 @@ export declare class EpgReader {
|
|
|
281
281
|
* p/f で「いま流れている」と言えるか。
|
|
282
282
|
*
|
|
283
283
|
* **`running_status` を当てにしきれない。** 4 (放送中) を入れてくる局も
|
|
284
|
-
* あれば、**0 (未定義) しか入れてこない局もある。** 実機の NHK は 74
|
|
284
|
+
* あれば、**0 (未定義) しか入れてこない局もある。** 実機の NHK は 74 セクション
|
|
285
285
|
* ぜんぶ 0 だった。4 だけを見ていると、そういう局では延長追従が丸ごと
|
|
286
286
|
* 効かなくなる (denpa の docs/data.md)。
|
|
287
287
|
*
|
|
288
|
-
* そこで 0
|
|
288
|
+
* そこで 0 のときは**セクションの番号で決める**。p/f は仕様で
|
|
289
289
|
* **section 0 が現在・section 1 が次**と決まっていて、こちらは局の都合で
|
|
290
290
|
* 変わらない。1 (まもなく) や 2 (停止中) は今までどおり入れない。
|
|
291
291
|
*/
|
package/dist/eit.js
CHANGED
|
@@ -60,10 +60,10 @@ const TABLE_TOT = 0x73;
|
|
|
60
60
|
/**
|
|
61
61
|
* TDT / TOT のセクションから**放送の実時刻**を読む。別のテーブルなら null。
|
|
62
62
|
*
|
|
63
|
-
*
|
|
63
|
+
* 先頭 3 バイトのあとに MJD + BCD が 5 バイト。**TOT も同じ並び**で、後ろに
|
|
64
64
|
* 時差の記述子が付くだけなので同じに読める。
|
|
65
65
|
*
|
|
66
|
-
* データ放送 (`bml.ts` の `onTime`)
|
|
66
|
+
* データ放送 (`bml.ts` の `onTime`) が読んで、BML の時計にする
|
|
67
67
|
*/
|
|
68
68
|
export function parseTimeTable(section) {
|
|
69
69
|
if (section[0] !== TABLE_TDT && section[0] !== TABLE_TOT)
|
|
@@ -134,14 +134,14 @@ const lang = (data, at) => ascii(data, at, 3).toLowerCase();
|
|
|
134
134
|
* 「直前の項目の続き」という意味なので、そこにも繋ぐ。
|
|
135
135
|
*
|
|
136
136
|
* **繋ぐのはデコードする前、バイトのうちに。** 部分ごとにデコードして文字列を繋いで
|
|
137
|
-
*
|
|
137
|
+
* いた頃は、続きが**別の文字で出て**いた (実機の「音楽制作ずはのづ ねふびどっ」。
|
|
138
138
|
* 正しくは「音楽制作:ONE MUSIC」)。分割点は
|
|
139
139
|
*
|
|
140
140
|
* - **二バイト文字の途中**に来ることがある (片割れだけでは字にならない)
|
|
141
141
|
* - **文字集合の状態を持ち越す。** G0〜G3 の指示も GL/GR の呼び出しも、
|
|
142
142
|
* 続きの側には書き直されない。前の状態のまま読む前提で送られてくる
|
|
143
143
|
*
|
|
144
|
-
*
|
|
144
|
+
* ので、部分だけを単独でデコードすると、そこから先が崩れる。
|
|
145
145
|
*
|
|
146
146
|
* **ただし見出しのある項目は、同じ見出しでも別の項目として最初の状態から読む。** 見出しが同じ
|
|
147
147
|
* 項目が 2 つ続けて来る局があり (BS日テレの「番組内容」)、2 つ目は最初の状態 (漢字) から読む前提で
|
|
@@ -254,7 +254,7 @@ function readDescriptors(event, body) {
|
|
|
254
254
|
at++;
|
|
255
255
|
if (at + cviLength <= data.length && cviLength > 0) {
|
|
256
256
|
const cvi = data.subarray(at, at + cviLength);
|
|
257
|
-
// B-CAS (0x0005)
|
|
257
|
+
// B-CAS (0x0005) を優先。まだ無ければこれを使う
|
|
258
258
|
if (caSystemId === 0x0005 ||
|
|
259
259
|
event.contractVerification === undefined ||
|
|
260
260
|
event.contractVerification === null) {
|
|
@@ -434,13 +434,13 @@ export class ScheduleProgress {
|
|
|
434
434
|
* **番号が飛ぶ。** 1 つの `table_id` が受け持つのは 4 日ぶんで、基本は
|
|
435
435
|
* `0x50` から、詳細は `0x58` から始まる。日本の放送は 8 日ぶんなので、
|
|
436
436
|
* 実際に流れてくるのは `0x50` `0x51` と `0x58` `0x59` あたりだけで、
|
|
437
|
-
* **`0x52`〜`0x57`
|
|
437
|
+
* **`0x52`〜`0x57` は永久に来ない**。
|
|
438
438
|
*
|
|
439
439
|
* `0x50` から `last_table_id` まで全部を待っていた頃は、詳細を積んでいる局が
|
|
440
440
|
* **一度も「揃った」にならず**、どのチャンネルも上限の 10 分 (denpa の `epgChannelTimeout`) まで開きっぱなしに
|
|
441
|
-
*
|
|
441
|
+
* なっていた (実機で、詳細の無い BS11 だけが早く閉じていた)。
|
|
442
442
|
*
|
|
443
|
-
* 見かけた表と、`last_table_id`
|
|
443
|
+
* 見かけた表と、`last_table_id` が指す表だけを見る。
|
|
444
444
|
*/
|
|
445
445
|
get complete() {
|
|
446
446
|
if (this.seen.size === 0)
|
|
@@ -454,7 +454,7 @@ export class ScheduleProgress {
|
|
|
454
454
|
}
|
|
455
455
|
return true;
|
|
456
456
|
}
|
|
457
|
-
/**
|
|
457
|
+
/** その表でまだ来ていないセクション。セグメントの先頭すら来ていなければ、先頭の番号を数える */
|
|
458
458
|
holes(tableId) {
|
|
459
459
|
const numbers = this.seen.get(tableId) ?? new Set();
|
|
460
460
|
const last = this.lastSection.get(tableId) ?? 0;
|
|
@@ -477,10 +477,10 @@ export class ScheduleProgress {
|
|
|
477
477
|
/**
|
|
478
478
|
* そのセグメントの時間帯がもう過ぎているか。**過ぎたものは待たない。**
|
|
479
479
|
*
|
|
480
|
-
* セグメントは 0:00 から 3 時間ずつの枠で、`table_id`
|
|
480
|
+
* セグメントは 0:00 から 3 時間ずつの枠で、`table_id` とセクション番号から
|
|
481
481
|
* それがいつの枠なのかが決まる。基本は `0x50` が当日 0:00 から 4 日ぶん、
|
|
482
482
|
* `0x51` がその次の 4 日ぶん。詳細 (`0x58`〜) も同じ並びをもう一度たどる。
|
|
483
|
-
*
|
|
483
|
+
* 終わった枠は放送されない (クラスの説明)。そのぶんの番組は、そこが未来だった数日前に取り込んである。
|
|
484
484
|
*/
|
|
485
485
|
stale(tableId, start) {
|
|
486
486
|
const base = tableId < SCHEDULE_ACTUAL_EXTENDED
|
|
@@ -501,7 +501,7 @@ export class ScheduleProgress {
|
|
|
501
501
|
*/
|
|
502
502
|
report() {
|
|
503
503
|
if (this.seen.size === 0)
|
|
504
|
-
return "EIT[schedule] が1つも来ていない";
|
|
504
|
+
return "EIT[schedule] が 1 つも来ていない";
|
|
505
505
|
if (!this.seen.has(this.lastTableId)) {
|
|
506
506
|
const seen = [...this.seen.keys()].map(hex).join(",");
|
|
507
507
|
return `最後の表 ${hex(this.lastTableId)} が一度も来ない (来たのは ${seen})`;
|
|
@@ -511,12 +511,12 @@ export class ScheduleProgress {
|
|
|
511
511
|
const holes = this.holes(tableId);
|
|
512
512
|
if (holes.length > 0) {
|
|
513
513
|
const head = holes.slice(0, 8).join(",");
|
|
514
|
-
missing.push(`${hex(tableId)} の ${head}${holes.length > 8 ? `
|
|
514
|
+
missing.push(`${hex(tableId)} の ${head}${holes.length > 8 ? ` ほか ${holes.length - 8}` : ""}`);
|
|
515
515
|
}
|
|
516
516
|
}
|
|
517
517
|
return missing.length === 0
|
|
518
518
|
? "揃っている"
|
|
519
|
-
:
|
|
519
|
+
: `来ていないセクション: ${missing.join(" / ")}`;
|
|
520
520
|
}
|
|
521
521
|
}
|
|
522
522
|
const hex = (value) => `0x${value.toString(16)}`;
|
|
@@ -632,11 +632,11 @@ export class EpgReader {
|
|
|
632
632
|
* p/f で「いま流れている」と言えるか。
|
|
633
633
|
*
|
|
634
634
|
* **`running_status` を当てにしきれない。** 4 (放送中) を入れてくる局も
|
|
635
|
-
* あれば、**0 (未定義) しか入れてこない局もある。** 実機の NHK は 74
|
|
635
|
+
* あれば、**0 (未定義) しか入れてこない局もある。** 実機の NHK は 74 セクション
|
|
636
636
|
* ぜんぶ 0 だった。4 だけを見ていると、そういう局では延長追従が丸ごと
|
|
637
637
|
* 効かなくなる (denpa の docs/data.md)。
|
|
638
638
|
*
|
|
639
|
-
* そこで 0
|
|
639
|
+
* そこで 0 のときは**セクションの番号で決める**。p/f は仕様で
|
|
640
640
|
* **section 0 が現在・section 1 が次**と決まっていて、こちらは局の都合で
|
|
641
641
|
* 変わらない。1 (まもなく) や 2 (停止中) は今までどおり入れない。
|
|
642
642
|
*/
|
|
@@ -775,7 +775,7 @@ export class PresentFollowing {
|
|
|
775
775
|
return changed;
|
|
776
776
|
}
|
|
777
777
|
}
|
|
778
|
-
/** 変わったかどうかを見る中身。**番号・時刻・尺・タイトルだけ** (
|
|
778
|
+
/** 変わったかどうかを見る中身。**番号・時刻・尺・タイトルだけ** (番組表に入れて画面に出るもの) */
|
|
779
779
|
function markOf(event) {
|
|
780
780
|
return `${event.eventId}:${event.startAt}:${event.duration}:${event.name}`;
|
|
781
781
|
}
|
package/dist/multipart.js
CHANGED
|
@@ -121,7 +121,7 @@ export function readEntity(data, part = false) {
|
|
|
121
121
|
const headers = [];
|
|
122
122
|
let at = 0;
|
|
123
123
|
for (;;) {
|
|
124
|
-
// 中身が空の部品は、ヘッダの空行の CRLF
|
|
124
|
+
// 中身が空の部品は、ヘッダの空行の CRLF が次の区切りの先頭として読まれ、ヘッダの行で
|
|
125
125
|
// ちょうど終わる (`--X\r\nContent-Type: a\r\n\r\n--X--`)。空の本体として受ける
|
|
126
126
|
// (web-bml の entity-parser はここで null を返し、モジュールごと捨てていた)
|
|
127
127
|
if (part && at === data.length && headers.length > 0)
|
package/dist/pes.d.ts
CHANGED
|
@@ -29,7 +29,7 @@ export interface Streams {
|
|
|
29
29
|
}
|
|
30
30
|
/** 5 バイトの PTS / DTS を読む (ISO/IEC 13818-1 2.4.3.7) */
|
|
31
31
|
export declare function readStamp(data: Uint8Array, at: number): number;
|
|
32
|
-
/** PES
|
|
32
|
+
/** PES のヘッダを読んで中身を切り出す。**壊れていれば null** (先頭の 00 00 01 が無いなど) */
|
|
33
33
|
export declare function parsePes(data: Uint8Array): {
|
|
34
34
|
pts: number | null;
|
|
35
35
|
dts: number | null;
|
|
@@ -38,7 +38,7 @@ export declare function parsePes(data: Uint8Array): {
|
|
|
38
38
|
/**
|
|
39
39
|
* TS を渡すと PES を返す。**選局し直したら作り直す** (前の局の切れ端を持ち越さない)。
|
|
40
40
|
*
|
|
41
|
-
* 映像は長さ 0 (
|
|
41
|
+
* 映像は長さ 0 (次の PES の先頭で終わりが分かる) なので 1 フレームぶん遅れて出るが、受け側が貯めるぶんに収まる。
|
|
42
42
|
* 音声は長さが書いてあるので揃った時点で出す
|
|
43
43
|
*/
|
|
44
44
|
export declare class PesDemuxer {
|
|
@@ -65,7 +65,7 @@ export declare class PesDemuxer {
|
|
|
65
65
|
/** ADTS の標本化周波数の表 (ISO/IEC 14496-3 表 1.18) */
|
|
66
66
|
export declare const ADTS_RATES: number[];
|
|
67
67
|
export interface AdtsFrame {
|
|
68
|
-
/**
|
|
68
|
+
/** ヘッダ (7 か 9 バイト) ごと。WASM の AAC デコーダは ADTS のまま受け取る */
|
|
69
69
|
data: Uint8Array;
|
|
70
70
|
/** 90kHz */
|
|
71
71
|
pts: number;
|
|
@@ -77,7 +77,7 @@ export interface AdtsFrame {
|
|
|
77
77
|
/**
|
|
78
78
|
* PES の中身を ADTS のコマに割る。**コマは PES をまたぐことがある**ので、余りは持ち越す。
|
|
79
79
|
*
|
|
80
|
-
* 時刻は PES の PTS
|
|
80
|
+
* 時刻は PES の PTS を先頭のコマに付け、続くコマには 1 コマぶんずつ足す。持ち越した
|
|
81
81
|
* 余りから始まるコマは、前の続きの時刻になる
|
|
82
82
|
*/
|
|
83
83
|
export declare class AdtsSplitter {
|
package/dist/pes.js
CHANGED
|
@@ -25,7 +25,7 @@ export function readStamp(data, at) {
|
|
|
25
25
|
(data[at + 3] << 7) +
|
|
26
26
|
(data[at + 4] >> 1));
|
|
27
27
|
}
|
|
28
|
-
/** PES
|
|
28
|
+
/** PES のヘッダを読んで中身を切り出す。**壊れていれば null** (先頭の 00 00 01 が無いなど) */
|
|
29
29
|
export function parsePes(data) {
|
|
30
30
|
if (data.length < 9 || data[0] !== 0 || data[1] !== 0 || data[2] !== 1)
|
|
31
31
|
return null;
|
|
@@ -35,18 +35,18 @@ export function parsePes(data) {
|
|
|
35
35
|
if (start > data.length)
|
|
36
36
|
return null;
|
|
37
37
|
const length = u16(data, 4);
|
|
38
|
-
// 長さが書いてあればそこまで (後ろに詰め物が付くことがある)。0
|
|
38
|
+
// 長さが書いてあればそこまで (後ろに詰め物が付くことがある)。0 は「次の PES の先頭まで」
|
|
39
39
|
const end = length === 0 ? data.length : Math.min(data.length, 6 + length);
|
|
40
40
|
const pts = flags & 0x02 && data.length >= 14 ? readStamp(data, 9) : null;
|
|
41
41
|
const dts = flags === 0x03 && data.length >= 19 ? readStamp(data, 14) : pts;
|
|
42
42
|
return { pts, dts, data: data.subarray(start, end) };
|
|
43
43
|
}
|
|
44
|
-
/** 長さの分からない PES (映像)
|
|
44
|
+
/** 長さの分からない PES (映像) のバッファの最初の大きさ。1 コマの多くはこれに収まる */
|
|
45
45
|
const PES_START = 64 * 1024;
|
|
46
46
|
/**
|
|
47
47
|
* TS を渡すと PES を返す。**選局し直したら作り直す** (前の局の切れ端を持ち越さない)。
|
|
48
48
|
*
|
|
49
|
-
* 映像は長さ 0 (
|
|
49
|
+
* 映像は長さ 0 (次の PES の先頭で終わりが分かる) なので 1 フレームぶん遅れて出るが、受け側が貯めるぶんに収まる。
|
|
50
50
|
* 音声は長さが書いてあるので揃った時点で出す
|
|
51
51
|
*/
|
|
52
52
|
export class PesDemuxer {
|
|
@@ -118,19 +118,19 @@ export class PesDemuxer {
|
|
|
118
118
|
return;
|
|
119
119
|
const payload = packet.subarray(offset);
|
|
120
120
|
if (packet[1] & 0x40) {
|
|
121
|
-
//
|
|
121
|
+
// 次の PES の先頭が来た。**長さ 0 の PES (映像) はここで終わりが分かる**
|
|
122
122
|
this.finish(pid, kind, out);
|
|
123
123
|
const expected = payload.length >= 6 ? 6 + u16(payload, 4) : 0;
|
|
124
|
-
// 溜めるものは写す。パケットは届いた塊の上の窓で、塊は使い回される (psi.ts の PacketStream)
|
|
125
124
|
const known = expected === 6 ? 0 : expected;
|
|
126
125
|
// 長さが書いてあればちょうどの大きさ (音声はほぼこれ)、無ければ映像向けに大きめ
|
|
127
126
|
const buffer = new Uint8Array(Math.max(known > 0 ? known : PES_START, payload.length));
|
|
127
|
+
// 溜めるものはコピーする。パケットは届いたチャンクの一部を指し、チャンクのバッファは使い回される (psi.ts の PacketStream)
|
|
128
128
|
buffer.set(payload);
|
|
129
129
|
this.partial.set(pid, { buffer, size: payload.length, expected: known });
|
|
130
130
|
}
|
|
131
131
|
else {
|
|
132
132
|
const partial = this.partial.get(pid);
|
|
133
|
-
//
|
|
133
|
+
// 先頭を見ていない続きは捨てる (途中から受け取った)
|
|
134
134
|
if (partial === undefined)
|
|
135
135
|
return;
|
|
136
136
|
const end = partial.size + payload.length;
|
|
@@ -155,7 +155,7 @@ export class PesDemuxer {
|
|
|
155
155
|
return;
|
|
156
156
|
this.partial.delete(pid);
|
|
157
157
|
// 余りが大きければ詰めて返す。返したものはキューに積まれたり worker へ送られたりするので、
|
|
158
|
-
//
|
|
158
|
+
// 広げたバッファの余り (最大で倍近く) まで抱えさせない
|
|
159
159
|
const { buffer, size } = partial;
|
|
160
160
|
const parsed = parsePes(size * 1.25 < buffer.length
|
|
161
161
|
? buffer.slice(0, size)
|
|
@@ -173,14 +173,14 @@ export const ADTS_RATES = [
|
|
|
173
173
|
/**
|
|
174
174
|
* PES の中身を ADTS のコマに割る。**コマは PES をまたぐことがある**ので、余りは持ち越す。
|
|
175
175
|
*
|
|
176
|
-
* 時刻は PES の PTS
|
|
176
|
+
* 時刻は PES の PTS を先頭のコマに付け、続くコマには 1 コマぶんずつ足す。持ち越した
|
|
177
177
|
* 余りから始まるコマは、前の続きの時刻になる
|
|
178
178
|
*/
|
|
179
179
|
export class AdtsSplitter {
|
|
180
180
|
rest = new Uint8Array(0);
|
|
181
181
|
next = null;
|
|
182
182
|
feed(data, pts) {
|
|
183
|
-
// 余りが無いときだけ PES の時刻に合わせ直す (
|
|
183
|
+
// 余りが無いときだけ PES の時刻に合わせ直す (余りがあれば先頭のコマはその続き)
|
|
184
184
|
if (pts !== null && this.rest.length === 0)
|
|
185
185
|
this.next = pts;
|
|
186
186
|
const buffer = this.rest.length === 0 ? data : concatBytes([this.rest, data]);
|
package/dist/psi.d.ts
CHANGED
|
@@ -17,14 +17,10 @@ export declare const SYNC = 71;
|
|
|
17
17
|
export declare function packetPid(packet: Uint8Array): number;
|
|
18
18
|
/** PAT。どの PID に PMT があるかを持つ。**入口はいつもここ** */
|
|
19
19
|
export declare const PID_PAT = 0;
|
|
20
|
-
export declare const PID_NIT = 16;
|
|
21
20
|
export declare const PID_SDT = 17;
|
|
22
21
|
export declare const TABLE_PAT = 0;
|
|
23
22
|
export declare const TABLE_PMT = 2;
|
|
24
|
-
export declare const TABLE_NIT_ACTUAL = 64;
|
|
25
|
-
export declare const TABLE_NIT_OTHER = 65;
|
|
26
23
|
export declare const TABLE_SDT_ACTUAL = 66;
|
|
27
|
-
export declare const TABLE_SDT_OTHER = 70;
|
|
28
24
|
/**
|
|
29
25
|
* スキャンで残すサービス種別。Mirakurun のスキャンが通しているものと同じで、
|
|
30
26
|
* ラジオ (0x02) とデータ (0xc0) も入る。映像の無いものを番組表に並べないのは
|
|
@@ -60,7 +56,7 @@ export interface NetworkInfo {
|
|
|
60
56
|
*
|
|
61
57
|
* セクションは TS パケットをまたいで運ばれ、パケットの切れ目とは無関係な
|
|
62
58
|
* 位置で終わる。payload_unit_start_indicator と pointer_field を見て
|
|
63
|
-
*
|
|
59
|
+
* 先頭を合わせ、section_length ぶん溜まったら 1 本として返す。
|
|
64
60
|
*/
|
|
65
61
|
export declare class SectionAssembler {
|
|
66
62
|
private readonly pid;
|
|
@@ -90,14 +86,14 @@ export declare function findSync(data: Uint8Array, from?: number, until?: number
|
|
|
90
86
|
/**
|
|
91
87
|
* 任意の長さで届くバイト列を 188 バイトのパケットに切り分ける。
|
|
92
88
|
*
|
|
93
|
-
*
|
|
94
|
-
* ずれたままだと**以降ずっと 1
|
|
89
|
+
* 渡されたバイト列の先頭がパケットの先頭とは限らず、電波が弱いと途中で数バイト落ちる。
|
|
90
|
+
* ずれたままだと**以降ずっと 1 パケットも読めなくなる**ので、先頭が 0x47 でなければ
|
|
95
91
|
* 取り直す。普段は先頭が 0x47 なので、探しに行くのはずれたときだけ。
|
|
96
92
|
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
* (denpa の `server/recorded-bml.ts`) ので、**次の `feed`
|
|
100
|
-
* いまのパーサ (`SectionAssembler`・`PesDemuxer`)
|
|
93
|
+
* **出すパケットは渡されたチャンクの一部を指す** (コピーではない。コピーすると録画の処理時間の 1/3 を使う)。
|
|
94
|
+
* チャンクのバッファを使い回す呼び出し側がある
|
|
95
|
+
* (denpa の `server/recorded-bml.ts`) ので、**次の `feed` より後まで持つならコピーすること**。
|
|
96
|
+
* いまのパーサ (`SectionAssembler`・`PesDemuxer`) は溜めるときにコピーしている
|
|
101
97
|
*/
|
|
102
98
|
export declare class PacketStream {
|
|
103
99
|
private rest;
|
|
@@ -136,10 +132,10 @@ export declare function pmtProgramInfo(section: Uint8Array): Uint8Array;
|
|
|
136
132
|
/**
|
|
137
133
|
* PMT の ES の並びを `[stream_type, PID, 記述子]` で返す。
|
|
138
134
|
*
|
|
139
|
-
* **`stream_type`
|
|
135
|
+
* **`stream_type` では中身を見分けられない。** データ放送も AIT もロゴも同じ
|
|
140
136
|
* DSM-CC セクション (0x0D) を名乗るので、見分けるのは記述子のほう
|
|
141
|
-
* (component_tag や application_signalling)
|
|
142
|
-
*
|
|
137
|
+
* (component_tag や application_signalling)。だからここは**素通しで並べる
|
|
138
|
+
* だけ**にして、選り分けは呼ぶ側に置いてある。
|
|
143
139
|
*/
|
|
144
140
|
export declare function pmtStreams(section: Uint8Array): Generator<[number, number, Uint8Array]>;
|
|
145
141
|
/** PAT から `サービスID → PMT の PID`。サービス 0 は NIT なので飛ばす */
|
|
@@ -147,19 +143,10 @@ export declare function parsePat(section: Uint8Array): Map<number, number>;
|
|
|
147
143
|
/**
|
|
148
144
|
* SDT のサービスの並びを (service_id, 記述子の並び) に切り分ける。
|
|
149
145
|
*
|
|
150
|
-
* **読む側が 2 つある。** 局名 (`
|
|
146
|
+
* **読む側が 2 つある。** 局名 (`sdtTransport`) とロゴの対応 (denpa の `ts/logo.ts`) で、
|
|
151
147
|
* 欲しい記述子が違うだけで歩き方は同じ。並びの読み方をここ 1 箇所に置く。
|
|
152
148
|
*/
|
|
153
149
|
export declare function sdtServices(section: Uint8Array): Generator<[number, Uint8Array]>;
|
|
154
|
-
/** SDT からサービスの一覧を読む。自分の TS のものだけ */
|
|
155
|
-
export declare function parseSdt(section: Uint8Array): TransportInfo | null;
|
|
156
|
-
/**
|
|
157
|
-
* SDT[other] からサービスの一覧を読む。**ほかの TS のもの。**
|
|
158
|
-
*
|
|
159
|
-
* 衛星は、どの TS にもネットワークのほかの TS の局名を流している (番組表の EIT[other] と同じ考え)。
|
|
160
|
-
* 開いていない TS の局名をこれで知る。TS ごとに別のセクションで来るので、集めるのは `SdtReader`
|
|
161
|
-
*/
|
|
162
|
-
export declare function parseSdtOther(section: Uint8Array): TransportInfo | null;
|
|
163
150
|
/** 衛星の分配の記述子 (0x43)。どの周波数で流れているか */
|
|
164
151
|
export interface SatelliteDelivery {
|
|
165
152
|
kind: "satellite";
|
|
@@ -196,26 +183,6 @@ export type Delivery = SatelliteDelivery | TerrestrialDelivery;
|
|
|
196
183
|
export interface NetworkTransport extends TransportInfo {
|
|
197
184
|
delivery: Delivery | null;
|
|
198
185
|
}
|
|
199
|
-
/** NIT のセクション 1 つ。表は何本かのセクションに分かれて来るので、そろえるのは `NitReader` */
|
|
200
|
-
export interface NitSection {
|
|
201
|
-
/** NIT[other] (ほかのネットワークのもの) なら true */
|
|
202
|
-
other: boolean;
|
|
203
|
-
networkId: number;
|
|
204
|
-
version: number;
|
|
205
|
-
/** current_next_indicator。0 (これから使う表) のものは `NitReader` が読まない */
|
|
206
|
-
current: boolean;
|
|
207
|
-
sectionNumber: number;
|
|
208
|
-
lastSectionNumber: number;
|
|
209
|
-
remoteControlKeyId: number | null;
|
|
210
|
-
transportStreams: NetworkTransport[];
|
|
211
|
-
}
|
|
212
|
-
/** NIT のセクションを 1 つ読む。actual (0x40) と other (0x41) のどちらも */
|
|
213
|
-
export declare function parseNitSection(section: Uint8Array): NitSection | null;
|
|
214
|
-
/**
|
|
215
|
-
* NIT からネットワーク ID とリモコン番号、他の TS の顔ぶれを読む。**セクション 1 つぶん。**
|
|
216
|
-
* スキャンで「どのネットワークか」を知るにはこれで足りる。ネットワークの全部の TS が要るなら `NitReader`
|
|
217
|
-
*/
|
|
218
|
-
export declare function parseNit(section: Uint8Array): NetworkInfo | null;
|
|
219
186
|
/** そろった NIT。セクションをつないだもの */
|
|
220
187
|
export interface Network {
|
|
221
188
|
/** NIT[other] なら true */
|
package/dist/psi.js
CHANGED
|
@@ -21,14 +21,14 @@ export function packetPid(packet) {
|
|
|
21
21
|
}
|
|
22
22
|
/** PAT。どの PID に PMT があるかを持つ。**入口はいつもここ** */
|
|
23
23
|
export const PID_PAT = 0x0000;
|
|
24
|
-
|
|
24
|
+
const PID_NIT = 0x0010;
|
|
25
25
|
export const PID_SDT = 0x0011;
|
|
26
26
|
export const TABLE_PAT = 0x00;
|
|
27
27
|
export const TABLE_PMT = 0x02;
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
const TABLE_NIT_ACTUAL = 0x40;
|
|
29
|
+
const TABLE_NIT_OTHER = 0x41;
|
|
30
30
|
export const TABLE_SDT_ACTUAL = 0x42;
|
|
31
|
-
|
|
31
|
+
const TABLE_SDT_OTHER = 0x46;
|
|
32
32
|
const DESC_SERVICE_LIST = 0x41;
|
|
33
33
|
const DESC_SATELLITE_DELIVERY = 0x43;
|
|
34
34
|
const DESC_TERRESTRIAL_DELIVERY = 0xfa;
|
|
@@ -80,14 +80,14 @@ export function withCrc(body) {
|
|
|
80
80
|
new DataView(out.buffer).setUint32(section.length, crc32(section));
|
|
81
81
|
return out;
|
|
82
82
|
}
|
|
83
|
-
/**
|
|
83
|
+
/** 何も組み上がらなかったときの返り。使い回すので `Object.freeze` してある */
|
|
84
84
|
const NONE = Object.freeze([]);
|
|
85
85
|
/**
|
|
86
86
|
* PSI セクションを組み立てる。
|
|
87
87
|
*
|
|
88
88
|
* セクションは TS パケットをまたいで運ばれ、パケットの切れ目とは無関係な
|
|
89
89
|
* 位置で終わる。payload_unit_start_indicator と pointer_field を見て
|
|
90
|
-
*
|
|
90
|
+
* 先頭を合わせ、section_length ぶん溜まったら 1 本として返す。
|
|
91
91
|
*/
|
|
92
92
|
export class SectionAssembler {
|
|
93
93
|
pid;
|
|
@@ -133,7 +133,7 @@ export class SectionAssembler {
|
|
|
133
133
|
// pointer_field の手前は前のセクションの続き
|
|
134
134
|
this.append(payload.subarray(1, 1 + pointer));
|
|
135
135
|
const done = this.flush();
|
|
136
|
-
//
|
|
136
|
+
// コピーする。パケットは届いたチャンクの一部を指し、チャンクのバッファは使い回される (PacketStream)
|
|
137
137
|
this.buffer = payload.slice(1 + pointer);
|
|
138
138
|
const next = this.flush();
|
|
139
139
|
if (done.length === 0)
|
|
@@ -173,7 +173,7 @@ export class SectionAssembler {
|
|
|
173
173
|
}
|
|
174
174
|
/**
|
|
175
175
|
* 同期が取れているとみなすのに必要な連続パケット数。
|
|
176
|
-
* 1
|
|
176
|
+
* 1 つだけでは中身にたまたまある 0x47 をパケットの先頭と誤認する
|
|
177
177
|
*/
|
|
178
178
|
const CONFIRM = 3;
|
|
179
179
|
/** `from` 以降 `until` の手前までで、188 間隔に 0x47 が続くところを探す。無ければ -1 (denpa の `seek.ts` も使う) */
|
|
@@ -190,21 +190,21 @@ export function findSync(data, from = 0, until = data.length) {
|
|
|
190
190
|
/**
|
|
191
191
|
* 任意の長さで届くバイト列を 188 バイトのパケットに切り分ける。
|
|
192
192
|
*
|
|
193
|
-
*
|
|
194
|
-
* ずれたままだと**以降ずっと 1
|
|
193
|
+
* 渡されたバイト列の先頭がパケットの先頭とは限らず、電波が弱いと途中で数バイト落ちる。
|
|
194
|
+
* ずれたままだと**以降ずっと 1 パケットも読めなくなる**ので、先頭が 0x47 でなければ
|
|
195
195
|
* 取り直す。普段は先頭が 0x47 なので、探しに行くのはずれたときだけ。
|
|
196
196
|
*
|
|
197
|
-
*
|
|
198
|
-
*
|
|
199
|
-
* (denpa の `server/recorded-bml.ts`) ので、**次の `feed`
|
|
200
|
-
* いまのパーサ (`SectionAssembler`・`PesDemuxer`)
|
|
197
|
+
* **出すパケットは渡されたチャンクの一部を指す** (コピーではない。コピーすると録画の処理時間の 1/3 を使う)。
|
|
198
|
+
* チャンクのバッファを使い回す呼び出し側がある
|
|
199
|
+
* (denpa の `server/recorded-bml.ts`) ので、**次の `feed` より後まで持つならコピーすること**。
|
|
200
|
+
* いまのパーサ (`SectionAssembler`・`PesDemuxer`) は溜めるときにコピーしている
|
|
201
201
|
*/
|
|
202
202
|
export class PacketStream {
|
|
203
203
|
rest = new Uint8Array(0);
|
|
204
204
|
*feed(chunk) {
|
|
205
205
|
/*
|
|
206
|
-
* 前の残り (`rest`)
|
|
207
|
-
*
|
|
206
|
+
* 前の残り (`rest`) とチャンクを繋いだ並びを順に読む。位置 `at` はその並びでの位置。
|
|
207
|
+
* 繋ぐのは**残りに先頭があるパケットを読むのに要るぶんだけ** (先頭を探すのに
|
|
208
208
|
* 3 パケットぶん先まで見る)
|
|
209
209
|
*/
|
|
210
210
|
const split = this.rest.length;
|
|
@@ -218,7 +218,7 @@ export class PacketStream {
|
|
|
218
218
|
while (at < split && at + PACKET <= total) {
|
|
219
219
|
if (head[at] !== SYNC) {
|
|
220
220
|
const found = findSync(head, at, split);
|
|
221
|
-
//
|
|
221
|
+
// 残りの中には無い。チャンクのほうを探す
|
|
222
222
|
if (found < 0) {
|
|
223
223
|
lost = true;
|
|
224
224
|
break;
|
|
@@ -252,13 +252,13 @@ export class PacketStream {
|
|
|
252
252
|
}
|
|
253
253
|
at = split + offset;
|
|
254
254
|
}
|
|
255
|
-
//
|
|
255
|
+
// 同期が取れないまま溜め込まないよう、先頭を探せるぶんだけ残す
|
|
256
256
|
const from = Math.max(at, total - PACKET * CONFIRM);
|
|
257
257
|
if (from >= split) {
|
|
258
258
|
this.rest = chunk.slice(from - split);
|
|
259
259
|
}
|
|
260
260
|
else {
|
|
261
|
-
//
|
|
261
|
+
// チャンクが短くて、前の残りの途中から残す
|
|
262
262
|
const rest = new Uint8Array(total - from);
|
|
263
263
|
rest.set(this.rest.subarray(from));
|
|
264
264
|
rest.set(chunk, split - from);
|
|
@@ -333,10 +333,10 @@ export function pmtProgramInfo(section) {
|
|
|
333
333
|
/**
|
|
334
334
|
* PMT の ES の並びを `[stream_type, PID, 記述子]` で返す。
|
|
335
335
|
*
|
|
336
|
-
* **`stream_type`
|
|
336
|
+
* **`stream_type` では中身を見分けられない。** データ放送も AIT もロゴも同じ
|
|
337
337
|
* DSM-CC セクション (0x0D) を名乗るので、見分けるのは記述子のほう
|
|
338
|
-
* (component_tag や application_signalling)
|
|
339
|
-
*
|
|
338
|
+
* (component_tag や application_signalling)。だからここは**素通しで並べる
|
|
339
|
+
* だけ**にして、選り分けは呼ぶ側に置いてある。
|
|
340
340
|
*/
|
|
341
341
|
export function* pmtStreams(section) {
|
|
342
342
|
if (section[0] !== TABLE_PMT || section.length < 16)
|
|
@@ -368,7 +368,7 @@ export function parsePat(section) {
|
|
|
368
368
|
/**
|
|
369
369
|
* SDT のサービスの並びを (service_id, 記述子の並び) に切り分ける。
|
|
370
370
|
*
|
|
371
|
-
* **読む側が 2 つある。** 局名 (`
|
|
371
|
+
* **読む側が 2 つある。** 局名 (`sdtTransport`) とロゴの対応 (denpa の `ts/logo.ts`) で、
|
|
372
372
|
* 欲しい記述子が違うだけで歩き方は同じ。並びの読み方をここ 1 箇所に置く。
|
|
373
373
|
*/
|
|
374
374
|
export function* sdtServices(section) {
|
|
@@ -411,18 +411,9 @@ function sdtTransport(section) {
|
|
|
411
411
|
};
|
|
412
412
|
}
|
|
413
413
|
/** SDT からサービスの一覧を読む。自分の TS のものだけ */
|
|
414
|
-
|
|
414
|
+
function parseSdt(section) {
|
|
415
415
|
return section[0] === TABLE_SDT_ACTUAL ? sdtTransport(section) : null;
|
|
416
416
|
}
|
|
417
|
-
/**
|
|
418
|
-
* SDT[other] からサービスの一覧を読む。**ほかの TS のもの。**
|
|
419
|
-
*
|
|
420
|
-
* 衛星は、どの TS にもネットワークのほかの TS の局名を流している (番組表の EIT[other] と同じ考え)。
|
|
421
|
-
* 開いていない TS の局名をこれで知る。TS ごとに別のセクションで来るので、集めるのは `SdtReader`
|
|
422
|
-
*/
|
|
423
|
-
export function parseSdtOther(section) {
|
|
424
|
-
return section[0] === TABLE_SDT_OTHER ? sdtTransport(section) : null;
|
|
425
|
-
}
|
|
426
417
|
/** BCD の桁を左から `digits` 桁ぶん読んで、10 進の整数にする */
|
|
427
418
|
function bcdDigits(data, at, digits) {
|
|
428
419
|
let value = 0;
|
|
@@ -468,7 +459,7 @@ function terrestrialDelivery(descriptor) {
|
|
|
468
459
|
};
|
|
469
460
|
}
|
|
470
461
|
/** NIT のセクションを 1 つ読む。actual (0x40) と other (0x41) のどちらも */
|
|
471
|
-
|
|
462
|
+
function parseNitSection(section) {
|
|
472
463
|
const tableId = section[0];
|
|
473
464
|
if (tableId !== TABLE_NIT_ACTUAL && tableId !== TABLE_NIT_OTHER)
|
|
474
465
|
return null;
|
|
@@ -534,7 +525,7 @@ export function parseNitSection(section) {
|
|
|
534
525
|
* NIT からネットワーク ID とリモコン番号、他の TS の顔ぶれを読む。**セクション 1 つぶん。**
|
|
535
526
|
* スキャンで「どのネットワークか」を知るにはこれで足りる。ネットワークの全部の TS が要るなら `NitReader`
|
|
536
527
|
*/
|
|
537
|
-
|
|
528
|
+
function parseNit(section) {
|
|
538
529
|
if (section[0] !== TABLE_NIT_ACTUAL)
|
|
539
530
|
return null;
|
|
540
531
|
const parsed = parseNitSection(section);
|
package/dist/service-filter.d.ts
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* ([agent.md](https://github.com/danything/denpa/blob/main/docs/agent.md))、選り分けるのは denpa の仕事。
|
|
6
6
|
*
|
|
7
7
|
* **これをやらないと 1 つの録画に複数の番組が入る。** 実機の TOKYO MX は
|
|
8
|
-
* 1 本の TS に MX1 と MX2
|
|
9
|
-
*
|
|
8
|
+
* 1 本の TS に MX1 と MX2 が入っていて、丸ごと保存すると ffprobe が 2 つの
|
|
9
|
+
* プログラムを返す。
|
|
10
10
|
*
|
|
11
11
|
* 残すものは次のとおり。
|
|
12
12
|
*
|
|
@@ -41,7 +41,7 @@ export declare class ServiceFilter {
|
|
|
41
41
|
private tsid;
|
|
42
42
|
private copyNeverNow;
|
|
43
43
|
private streamsNow;
|
|
44
|
-
/** PMT を読む前に届いた、局の分からないパケット (
|
|
44
|
+
/** PMT を読む前に届いた、局の分からないパケット (コピーしたもの)。届いた順 */
|
|
45
45
|
private held;
|
|
46
46
|
constructor(serviceId: number);
|
|
47
47
|
/** その局の PMT を読めたか。読めるまで映像は 1 バイトも出ない (届いたものは取っておく) */
|
|
@@ -66,10 +66,10 @@ export declare class ServiceFilter {
|
|
|
66
66
|
/**
|
|
67
67
|
* **中継の番号 (transport_stream_id)。** PAT を読むまでは null。
|
|
68
68
|
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
* これを取り、TVer のサーバへそのまま送る。`null`
|
|
72
|
-
* "null"
|
|
69
|
+
* 絞るのに要るわけではない。**データ放送が受信機に訊いてくる**ので
|
|
70
|
+
* 覚えておく。テレ朝の TVer リンクは `browser.getProgramID(4)` で
|
|
71
|
+
* これを取り、TVer のサーバへそのまま送る。`null` のまま渡すと文字列の
|
|
72
|
+
* "null" が送られて、あちらが断り、画面には `DT-RE` とだけ出る
|
|
73
73
|
* ([server/live.ts](https://github.com/danything/denpa/blob/main/src/lib/server/live.ts) の `programInfo`)
|
|
74
74
|
*/
|
|
75
75
|
get transportStreamId(): number | null;
|
|
@@ -84,7 +84,7 @@ export declare class ServiceFilter {
|
|
|
84
84
|
* その局のぶんだけを PMT の後ろに足す (並びは届いた順のまま。読む側は PAT・PMT を先に知る)
|
|
85
85
|
*/
|
|
86
86
|
filter(chunk: Uint8Array): Uint8Array;
|
|
87
|
-
/** PMT
|
|
87
|
+
/** PMT を読む前のパケットを取っておく。**コピーする** (パケットは届いたチャンクの一部を指す。`PacketStream`) */
|
|
88
88
|
private hold;
|
|
89
89
|
/** 取っておいたもののうち、その局のぶんを出す */
|
|
90
90
|
private release;
|
|
@@ -101,6 +101,6 @@ export declare class ServiceFilter {
|
|
|
101
101
|
*/
|
|
102
102
|
export declare class StreamsWatch {
|
|
103
103
|
private seen;
|
|
104
|
-
/** `filter`
|
|
104
|
+
/** `filter` にチャンクを通したあとに呼ぶ */
|
|
105
105
|
changed(filter: ServiceFilter): boolean;
|
|
106
106
|
}
|