@danything/arib 0.1.0 → 1.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/LICENSE +39 -0
- package/README.md +12 -8
- package/dist/ait.d.ts +1 -1
- package/dist/ait.js +4 -1
- package/dist/aribtext.d.ts +8 -5
- package/dist/aribtext.js +60 -26
- package/dist/b24-tables.d.ts +22 -4
- package/dist/b24-tables.js +97 -6
- package/dist/b24caption.d.ts +5 -1
- package/dist/b24caption.js +42 -13
- package/dist/bml-protocol.d.ts +3 -2
- package/dist/bml-protocol.js +2 -1
- package/dist/bml.d.ts +4 -4
- package/dist/bml.js +30 -9
- package/dist/caption-text.d.ts +8 -3
- package/dist/caption-text.js +2 -2
- package/dist/drcs-smooth.d.ts +1 -1
- package/dist/drcs-smooth.js +2 -1
- package/dist/dsmcc.d.ts +23 -5
- package/dist/dsmcc.js +50 -10
- package/dist/eit.d.ts +42 -9
- package/dist/eit.js +44 -14
- package/dist/multipart.d.ts +1 -1
- package/dist/multipart.js +1 -1
- package/dist/pes.d.ts +3 -3
- package/dist/pes.js +24 -11
- package/dist/psi.d.ts +4 -4
- package/dist/psi.js +5 -5
- package/dist/service-filter.d.ts +16 -5
- package/dist/service-filter.js +38 -6
- package/dist/synth-av.d.ts +3 -3
- package/dist/synth-av.js +3 -3
- package/dist/synth-caption.d.ts +1 -1
- package/dist/synth-caption.js +1 -1
- package/dist/synth.d.ts +21 -3
- package/dist/synth.js +39 -6
- package/package.json +1 -1
package/dist/eit.d.ts
CHANGED
|
@@ -29,6 +29,32 @@ interface EventAudio {
|
|
|
29
29
|
/** 主音声か (`main_component_flag`)。**解説放送はこちらが立っていないほう** */
|
|
30
30
|
main?: boolean;
|
|
31
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* シリーズ (series_descriptor。ARIB STD-B10 第2部)。**載せる局と載せない局がある。**
|
|
34
|
+
*
|
|
35
|
+
* `seriesId` で決まるのは**その局の中だけ**。番号は局ごとに振るので、別の局の同じ番号は
|
|
36
|
+
* 別のシリーズ。比べるときは局 (original_network_id + service_id) と組にする
|
|
37
|
+
*/
|
|
38
|
+
export interface EitSeries {
|
|
39
|
+
seriesId: number;
|
|
40
|
+
/**
|
|
41
|
+
* 再放送の印 (repeat_label)。**0 はオリジナル**、それ以外は、オリジナルの放送期間と
|
|
42
|
+
* 重なって流れる再放送のシリーズを別のものとして見分けるための番号。
|
|
43
|
+
* 重ならない再放送は 0 のまま来ることがあるので、**0 でも初回とは言えない**
|
|
44
|
+
*/
|
|
45
|
+
repeatLabel: number;
|
|
46
|
+
/**
|
|
47
|
+
* 編成の型 (program_pattern)。0=不定期 1=帯 (毎日・平日のみなど) 2=週1回 3=月1回
|
|
48
|
+
* 4=同じ日に何話か 5=長い番組を分けたもの。6・7 はここでは意味を読まない
|
|
49
|
+
*/
|
|
50
|
+
programPattern: number;
|
|
51
|
+
/** 何話目か (episode_number)。0 (話数が決まっていない) は null */
|
|
52
|
+
episode: number | null;
|
|
53
|
+
/** 全何話か (last_episode_number)。0 (分からない) は null */
|
|
54
|
+
lastEpisode: number | null;
|
|
55
|
+
/** シリーズ名。載っていなければ空文字 */
|
|
56
|
+
name: string;
|
|
57
|
+
}
|
|
32
58
|
/** ジャンル。大分類 (`lv1`) と中分類 (`lv2`) の番号 */
|
|
33
59
|
export interface Genre {
|
|
34
60
|
lv1: number;
|
|
@@ -58,13 +84,20 @@ export interface EitEvent {
|
|
|
58
84
|
resolution: string | null;
|
|
59
85
|
} | null;
|
|
60
86
|
/**
|
|
61
|
-
* **コピー禁止か** (デジタルコピー制御記述子)。禁止の番組は録らない (docs/data.md)。
|
|
87
|
+
* **コピー禁止か** (デジタルコピー制御記述子)。禁止の番組は録らない (denpa の docs/data.md)。
|
|
62
88
|
*
|
|
63
89
|
* `null` は「この表は言っていない」。記述子は基本の表 (と p/f) に載り、詳細の表
|
|
64
90
|
* (0x58〜) には載らないので、詳細だけ届いた回で「禁止ではない」と上書きしないため
|
|
65
91
|
* (`EpgReader.merge`)
|
|
66
92
|
*/
|
|
67
93
|
copyNever: boolean | null;
|
|
94
|
+
/**
|
|
95
|
+
* シリーズ (series_descriptor)。載っていなければ null。
|
|
96
|
+
*
|
|
97
|
+
* **この項目が無い**のは「この表は言っていない」。`copyNever` と同じく基本の表 (と p/f) に載り、
|
|
98
|
+
* 詳細の表 (0x58〜) には載らない。詳細だけ届いた回で消さないため (`EpgReader.merge`)
|
|
99
|
+
*/
|
|
100
|
+
series?: EitSeries | null;
|
|
68
101
|
}
|
|
69
102
|
export interface EitSection {
|
|
70
103
|
tableId: number;
|
|
@@ -134,13 +167,13 @@ export declare class ScheduleProgress {
|
|
|
134
167
|
private readonly lastSection;
|
|
135
168
|
private lastTableId;
|
|
136
169
|
/**
|
|
137
|
-
* `table_id` →
|
|
170
|
+
* `table_id` → バージョン。変わったらその表だけ数え直す。
|
|
138
171
|
*
|
|
139
|
-
*
|
|
172
|
+
* **バージョンは `table_id` ごとに別々に振られる。** 番組表の1つの表 (sub_table) は
|
|
140
173
|
* `table_id` + 局 + TS で決まり、`version_number` はその単位で動く。
|
|
141
174
|
* 局に1つだけ持っていた頃は、**基本 (0x50〜) と詳細 (0x58〜) を行き来する
|
|
142
|
-
*
|
|
143
|
-
* 二度と無いので、どのチャンネルも上限の10分 (`epgChannelTimeout`) まで開きっぱなしになる。
|
|
175
|
+
* たびにバージョンが違って数えたものを全部捨てて**いた。揃ったと分かることが
|
|
176
|
+
* 二度と無いので、どのチャンネルも上限の10分 (denpa の `epgChannelTimeout`) まで開きっぱなしになる。
|
|
144
177
|
*/
|
|
145
178
|
private readonly version;
|
|
146
179
|
/**
|
|
@@ -158,7 +191,7 @@ export declare class ScheduleProgress {
|
|
|
158
191
|
* **`0x52`〜`0x57` は永久に来ません**。
|
|
159
192
|
*
|
|
160
193
|
* `0x50` から `last_table_id` まで全部を待っていた頃は、詳細を積んでいる局が
|
|
161
|
-
* **一度も「揃った」にならず**、どのチャンネルも上限の10分 (`epgChannelTimeout`) まで開きっぱなしに
|
|
194
|
+
* **一度も「揃った」にならず**、どのチャンネルも上限の10分 (denpa の `epgChannelTimeout`) まで開きっぱなしに
|
|
162
195
|
* なっていました (実機で、詳細の無い BS11 だけが早く閉じていた)。
|
|
163
196
|
*
|
|
164
197
|
* 見かけた表と、`last_table_id` が指す表だけを見ます。
|
|
@@ -208,7 +241,7 @@ export declare class EpgReader {
|
|
|
208
241
|
/**
|
|
209
242
|
* @param now いまの時刻。局ごとの `ScheduleProgress` にそのまま渡す
|
|
210
243
|
* @param options.other ほかの TS の局の番組表も読む。ネットワーク全局ぶんを
|
|
211
|
-
* 1つの中継から先に入れるときに使う (`epg-collect.ts` の初回)
|
|
244
|
+
* 1つの中継から先に入れるときに使う (denpa の `epg-collect.ts` の初回)
|
|
212
245
|
* @param options.settle `other` のとき、新しい局が出てこなくなってから閉じるまで (ms)
|
|
213
246
|
* @param options.expect `other` のとき、来るはずの局 (service_id)。全部見えて揃えば
|
|
214
247
|
* `settle` を待たずに閉じる。受信できない局が混ざっていれば `settle` で閉じる
|
|
@@ -244,7 +277,7 @@ export declare class EpgReader {
|
|
|
244
277
|
* **`running_status` を当てにしきれない。** 4 (放送中) を入れてくる局も
|
|
245
278
|
* あれば、**0 (未定義) しか入れてこない局もある** — 実機の NHK は 74 節
|
|
246
279
|
* ぜんぶ 0 だった。4 だけを見ていると、そういう局では延長追従が丸ごと
|
|
247
|
-
* 効かなくなる (docs/
|
|
280
|
+
* 効かなくなる (denpa の docs/data.md)。
|
|
248
281
|
*
|
|
249
282
|
* そこで 0 のときは**節の番号で決める**。p/f は仕様で
|
|
250
283
|
* **section 0 が現在・section 1 が次**と決まっていて、こちらは局の都合で
|
|
@@ -253,7 +286,7 @@ export declare class EpgReader {
|
|
|
253
286
|
private onAir;
|
|
254
287
|
/**
|
|
255
288
|
* 前に呼んでから増えた・変わった番組。**読みながら少しずつ保存する**ため
|
|
256
|
-
* (`epg-collect.ts`)。揃うまで待ってからまとめて書くと、全局読みの数分のあいだ
|
|
289
|
+
* (denpa の `epg-collect.ts`)。揃うまで待ってからまとめて書くと、全局読みの数分のあいだ
|
|
257
290
|
* 画面に何も出ない
|
|
258
291
|
*/
|
|
259
292
|
takeChanged(): EitEvent[];
|
package/dist/eit.js
CHANGED
|
@@ -31,7 +31,8 @@ const DESC_EXTENDED_EVENT = 0x4e;
|
|
|
31
31
|
const DESC_COMPONENT = 0x50;
|
|
32
32
|
const DESC_CONTENT = 0x54;
|
|
33
33
|
const DESC_AUDIO_COMPONENT = 0xc4;
|
|
34
|
-
|
|
34
|
+
const DESC_SERIES = 0xd5;
|
|
35
|
+
/** 自局の表か (p/f 0x4E と schedule 0x50〜0x5F)。ほかの TS の schedule (0x60〜0x6F) は下、他局の p/f (0x4F) は読まない */
|
|
35
36
|
function isEitActual(tableId) {
|
|
36
37
|
return (tableId === TABLE_PF_ACTUAL ||
|
|
37
38
|
(tableId >= SCHEDULE_ACTUAL_MIN && tableId <= SCHEDULE_ACTUAL_MAX));
|
|
@@ -41,7 +42,7 @@ function isEitActual(tableId) {
|
|
|
41
42
|
* 並びは自局のもの (0x50〜0x5F) と同じで、`OTHER_SHIFT` だけずれている。
|
|
42
43
|
*
|
|
43
44
|
* BS・CS はどの中継にもネットワーク全局ぶんが流れているが、**詳細はほぼ付かない**
|
|
44
|
-
* (実測で BS 45 局のうち2局ぶん。docs/data.md)。いま/次 (0x4F) は読まない
|
|
45
|
+
* (実測で BS 45 局のうち2局ぶん。denpa の docs/data.md)。いま/次 (0x4F) は読まない
|
|
45
46
|
*/
|
|
46
47
|
const SCHEDULE_OTHER_MIN = 0x60;
|
|
47
48
|
const SCHEDULE_OTHER_MAX = 0x6f;
|
|
@@ -131,7 +132,7 @@ const lang = (data, at) => ascii(data, at, 3).toLowerCase();
|
|
|
131
132
|
* 見出しごとに繋ぎ直さないと、長い説明が途中で切れる。見出しが空の項目は
|
|
132
133
|
* 「直前の項目の続き」という意味なので、そこにも繋ぐ。
|
|
133
134
|
*
|
|
134
|
-
*
|
|
135
|
+
* **繋ぐのはデコードする前、バイトのうちに。** 部分ごとにデコードして文字列を繋いで
|
|
135
136
|
* いた頃は、続きが**別の文字で出て**いました (実機の「音楽制作ずはのづ ねふびどっ」。
|
|
136
137
|
* 正しくは「音楽制作:ONE MUSIC」)。分割点は
|
|
137
138
|
*
|
|
@@ -139,10 +140,10 @@ const lang = (data, at) => ascii(data, at, 3).toLowerCase();
|
|
|
139
140
|
* - **文字集合の状態を持ち越す** — G0〜G3 の指示も GL/GR の呼び出しも、
|
|
140
141
|
* 続きの側には書き直されない。前の状態のまま読む前提で送られてくる
|
|
141
142
|
*
|
|
142
|
-
*
|
|
143
|
+
* ので、部分だけを単独でデコードすると、そこから先が崩れます。
|
|
143
144
|
*/
|
|
144
145
|
function readDescriptors(event, body) {
|
|
145
|
-
/**
|
|
146
|
+
/** 見出しごとの生バイト。**全部揃ってからデコードする** (Map なので見出しの出てきた順に並ぶ) */
|
|
146
147
|
const pending = new Map();
|
|
147
148
|
let lastHeading = "";
|
|
148
149
|
for (const [tag, data] of descriptors(body)) {
|
|
@@ -228,11 +229,35 @@ function readDescriptors(event, body) {
|
|
|
228
229
|
event.copyNever = isCopyNever(data);
|
|
229
230
|
break;
|
|
230
231
|
}
|
|
232
|
+
/*
|
|
233
|
+
* series_descriptor (ARIB STD-B10 第2部)。
|
|
234
|
+
*
|
|
235
|
+
* [0..1] series_id
|
|
236
|
+
* [2] repeat_label(4) program_pattern(3) expire_date_valid_flag(1)
|
|
237
|
+
* [3..4] expire_date (MJD) … 使わない
|
|
238
|
+
* [5..7] episode_number(12) last_episode_number(12)
|
|
239
|
+
* [残り] series_name_char
|
|
240
|
+
*/
|
|
241
|
+
case DESC_SERIES: {
|
|
242
|
+
if (data.length < 8)
|
|
243
|
+
break;
|
|
244
|
+
const episode = (data[5] << 4) | (data[6] >> 4);
|
|
245
|
+
const lastEpisode = ((data[6] & 0x0f) << 8) | data[7];
|
|
246
|
+
event.series = {
|
|
247
|
+
seriesId: u16(data, 0),
|
|
248
|
+
repeatLabel: data[2] >> 4,
|
|
249
|
+
programPattern: (data[2] >> 1) & 0x07,
|
|
250
|
+
episode: episode === 0 ? null : episode,
|
|
251
|
+
lastEpisode: lastEpisode === 0 ? null : lastEpisode,
|
|
252
|
+
name: decodeAribText(data.subarray(8)).trim(),
|
|
253
|
+
};
|
|
254
|
+
break;
|
|
255
|
+
}
|
|
231
256
|
default:
|
|
232
257
|
break;
|
|
233
258
|
}
|
|
234
259
|
}
|
|
235
|
-
//
|
|
260
|
+
// 全部揃ってからデコードする (分割点が二バイト文字や文字集合の途中に来るため)
|
|
236
261
|
for (const [heading, parts] of pending)
|
|
237
262
|
event.extended[heading] = decodeAribText(joinBytes(parts));
|
|
238
263
|
}
|
|
@@ -292,6 +317,8 @@ export function parseEit(section, options = {}) {
|
|
|
292
317
|
video: null,
|
|
293
318
|
// 記述子が無ければ「禁止ではない」。詳細の表はもとから載せないので「言っていない」
|
|
294
319
|
copyNever: tableId >= SCHEDULE_ACTUAL_EXTENDED ? null : false,
|
|
320
|
+
// シリーズも同じ。載っていなければ「シリーズではない」、詳細の表なら「言っていない」
|
|
321
|
+
...(tableId >= SCHEDULE_ACTUAL_EXTENDED ? {} : { series: null }),
|
|
295
322
|
};
|
|
296
323
|
at += 12 + descriptorsLength;
|
|
297
324
|
if (body.length < descriptorsLength)
|
|
@@ -326,13 +353,13 @@ export class ScheduleProgress {
|
|
|
326
353
|
lastSection = new Map();
|
|
327
354
|
lastTableId = SCHEDULE_ACTUAL_MIN;
|
|
328
355
|
/**
|
|
329
|
-
* `table_id` →
|
|
356
|
+
* `table_id` → バージョン。変わったらその表だけ数え直す。
|
|
330
357
|
*
|
|
331
|
-
*
|
|
358
|
+
* **バージョンは `table_id` ごとに別々に振られる。** 番組表の1つの表 (sub_table) は
|
|
332
359
|
* `table_id` + 局 + TS で決まり、`version_number` はその単位で動く。
|
|
333
360
|
* 局に1つだけ持っていた頃は、**基本 (0x50〜) と詳細 (0x58〜) を行き来する
|
|
334
|
-
*
|
|
335
|
-
* 二度と無いので、どのチャンネルも上限の10分 (`epgChannelTimeout`) まで開きっぱなしになる。
|
|
361
|
+
* たびにバージョンが違って数えたものを全部捨てて**いた。揃ったと分かることが
|
|
362
|
+
* 二度と無いので、どのチャンネルも上限の10分 (denpa の `epgChannelTimeout`) まで開きっぱなしになる。
|
|
336
363
|
*/
|
|
337
364
|
version = new Map();
|
|
338
365
|
/**
|
|
@@ -371,7 +398,7 @@ export class ScheduleProgress {
|
|
|
371
398
|
* **`0x52`〜`0x57` は永久に来ません**。
|
|
372
399
|
*
|
|
373
400
|
* `0x50` から `last_table_id` まで全部を待っていた頃は、詳細を積んでいる局が
|
|
374
|
-
* **一度も「揃った」にならず**、どのチャンネルも上限の10分 (`epgChannelTimeout`) まで開きっぱなしに
|
|
401
|
+
* **一度も「揃った」にならず**、どのチャンネルも上限の10分 (denpa の `epgChannelTimeout`) まで開きっぱなしに
|
|
375
402
|
* なっていました (実機で、詳細の無い BS11 だけが早く閉じていた)。
|
|
376
403
|
*
|
|
377
404
|
* 見かけた表と、`last_table_id` が指す表だけを見ます。
|
|
@@ -478,7 +505,7 @@ export class EpgReader {
|
|
|
478
505
|
/**
|
|
479
506
|
* @param now いまの時刻。局ごとの `ScheduleProgress` にそのまま渡す
|
|
480
507
|
* @param options.other ほかの TS の局の番組表も読む。ネットワーク全局ぶんを
|
|
481
|
-
* 1つの中継から先に入れるときに使う (`epg-collect.ts` の初回)
|
|
508
|
+
* 1つの中継から先に入れるときに使う (denpa の `epg-collect.ts` の初回)
|
|
482
509
|
* @param options.settle `other` のとき、新しい局が出てこなくなってから閉じるまで (ms)
|
|
483
510
|
* @param options.expect `other` のとき、来るはずの局 (service_id)。全部見えて揃えば
|
|
484
511
|
* `settle` を待たずに閉じる。受信できない局が混ざっていれば `settle` で閉じる
|
|
@@ -553,6 +580,9 @@ export class EpgReader {
|
|
|
553
580
|
audios: event.audios.length === 0 ? old.audios : event.audios,
|
|
554
581
|
video: event.video ?? old.video,
|
|
555
582
|
copyNever: event.copyNever ?? old.copyNever,
|
|
583
|
+
...(event.series === undefined && old.series !== undefined
|
|
584
|
+
? { series: old.series }
|
|
585
|
+
: {}),
|
|
556
586
|
});
|
|
557
587
|
}
|
|
558
588
|
/**
|
|
@@ -561,7 +591,7 @@ export class EpgReader {
|
|
|
561
591
|
* **`running_status` を当てにしきれない。** 4 (放送中) を入れてくる局も
|
|
562
592
|
* あれば、**0 (未定義) しか入れてこない局もある** — 実機の NHK は 74 節
|
|
563
593
|
* ぜんぶ 0 だった。4 だけを見ていると、そういう局では延長追従が丸ごと
|
|
564
|
-
* 効かなくなる (docs/
|
|
594
|
+
* 効かなくなる (denpa の docs/data.md)。
|
|
565
595
|
*
|
|
566
596
|
* そこで 0 のときは**節の番号で決める**。p/f は仕様で
|
|
567
597
|
* **section 0 が現在・section 1 が次**と決まっていて、こちらは局の都合で
|
|
@@ -574,7 +604,7 @@ export class EpgReader {
|
|
|
574
604
|
}
|
|
575
605
|
/**
|
|
576
606
|
* 前に呼んでから増えた・変わった番組。**読みながら少しずつ保存する**ため
|
|
577
|
-
* (`epg-collect.ts`)。揃うまで待ってからまとめて書くと、全局読みの数分のあいだ
|
|
607
|
+
* (denpa の `epg-collect.ts`)。揃うまで待ってからまとめて書くと、全局読みの数分のあいだ
|
|
578
608
|
* 画面に何も出ない
|
|
579
609
|
*/
|
|
580
610
|
takeChanged() {
|
package/dist/multipart.d.ts
CHANGED
|
@@ -36,7 +36,7 @@ export interface Entity {
|
|
|
36
36
|
export declare function parseMediaType(text: string): MediaType | null;
|
|
37
37
|
/**
|
|
38
38
|
* 中身を1つ読む。**ヘッダの終わり (空行) が無いものは null** — どこからが本体か
|
|
39
|
-
* 分からない。`multipart/mixed` なら中までデコードする (
|
|
39
|
+
* 分からない。`multipart/mixed` なら中までデコードする (入れ子も同じ形式)。
|
|
40
40
|
*
|
|
41
41
|
* @param part multipart の中の部品か。部品はヘッダの行でちょうど終わってよい (下の説明)
|
|
42
42
|
*/
|
package/dist/multipart.js
CHANGED
|
@@ -113,7 +113,7 @@ function find(haystack, needle, from) {
|
|
|
113
113
|
}
|
|
114
114
|
/**
|
|
115
115
|
* 中身を1つ読む。**ヘッダの終わり (空行) が無いものは null** — どこからが本体か
|
|
116
|
-
* 分からない。`multipart/mixed` なら中までデコードする (
|
|
116
|
+
* 分からない。`multipart/mixed` なら中までデコードする (入れ子も同じ形式)。
|
|
117
117
|
*
|
|
118
118
|
* @param part multipart の中の部品か。部品はヘッダの行でちょうど終わってよい (下の説明)
|
|
119
119
|
*/
|
package/dist/pes.d.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* **1局に絞った TS から、映像と音声の PES を取り出す** (
|
|
2
|
+
* **1局に絞った TS から、映像と音声の PES を取り出す** (denpa のライブを変換せずに送る経路。docs/stream.md#放送そのままmpeg-2を送る)。
|
|
3
3
|
*
|
|
4
4
|
* エンコードする経路ではここを ffmpeg がやっていた。変換せずに送ると TS がそのままブラウザへ来るので、
|
|
5
|
-
* 映像も音声も WASM のデコーダ (`wasm/decoder.c`) に渡す前に、
|
|
5
|
+
* 映像も音声も WASM のデコーダ (denpa の `wasm/decoder.c`) に渡す前に、
|
|
6
6
|
* こちらで PES に戻す。サーバが1局に絞ってある (`ServiceFilter`) ので、PAT に
|
|
7
7
|
* 載っている局は1つだけ — その PMT を読んで、映像1本と音声 (並んだ順) を取り出す。
|
|
8
8
|
*
|
|
9
9
|
* DOM も WASM も触らないので、ここだけ単体で確かめられる (`pes.test.ts`)。
|
|
10
10
|
*/
|
|
11
|
-
/** PTS・PCR の刻み (90kHz)
|
|
11
|
+
/** PTS・PCR の刻み (90kHz)。denpa の取り決めの時刻もこの刻み (docs/stream.md#websocket-プロトコル) */
|
|
12
12
|
export declare const CLOCK = 90000;
|
|
13
13
|
/** PTS の一周 (33ビット)。26.5 時間 */
|
|
14
14
|
export declare const WRAP: number;
|
package/dist/pes.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* **1局に絞った TS から、映像と音声の PES を取り出す** (
|
|
2
|
+
* **1局に絞った TS から、映像と音声の PES を取り出す** (denpa のライブを変換せずに送る経路。docs/stream.md#放送そのままmpeg-2を送る)。
|
|
3
3
|
*
|
|
4
4
|
* エンコードする経路ではここを ffmpeg がやっていた。変換せずに送ると TS がそのままブラウザへ来るので、
|
|
5
|
-
* 映像も音声も WASM のデコーダ (`wasm/decoder.c`) に渡す前に、
|
|
5
|
+
* 映像も音声も WASM のデコーダ (denpa の `wasm/decoder.c`) に渡す前に、
|
|
6
6
|
* こちらで PES に戻す。サーバが1局に絞ってある (`ServiceFilter`) ので、PAT に
|
|
7
7
|
* 載っている局は1つだけ — その PMT を読んで、映像1本と音声 (並んだ順) を取り出す。
|
|
8
8
|
*
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import { concatBytes, u16 } from "./bytes.js";
|
|
12
12
|
import { PACKET, packetPid, PacketStream, PID_PAT, pmtStreams, PmtTracker, } from "./psi.js";
|
|
13
|
-
/** PTS・PCR の刻み (90kHz)
|
|
13
|
+
/** PTS・PCR の刻み (90kHz)。denpa の取り決めの時刻もこの刻み (docs/stream.md#websocket-プロトコル) */
|
|
14
14
|
export const CLOCK = 90_000;
|
|
15
15
|
/** PTS の一周 (33ビット)。26.5 時間 */
|
|
16
16
|
export const WRAP = 2 ** 33;
|
|
@@ -41,6 +41,8 @@ export function parsePes(data) {
|
|
|
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 (映像) の入れ物の最初の大きさ。1 コマの多くはこれに収まる */
|
|
45
|
+
const PES_START = 64 * 1024;
|
|
44
46
|
/**
|
|
45
47
|
* TS を食わせて PES を吐く。**選局し直したら作り直す** (前の局の切れ端を持ち越さない)。
|
|
46
48
|
*
|
|
@@ -120,19 +122,25 @@ export class PesDemuxer {
|
|
|
120
122
|
this.finish(pid, kind, out);
|
|
121
123
|
const expected = payload.length >= 6 ? 6 + u16(payload, 4) : 0;
|
|
122
124
|
// 溜めるものは写す。パケットは届いた塊の上の窓で、塊は使い回される (psi.ts の PacketStream)
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
});
|
|
125
|
+
const known = expected === 6 ? 0 : expected;
|
|
126
|
+
// 長さが書いてあればちょうどの大きさ (音声はほぼこれ)、無ければ映像向けに大きめ
|
|
127
|
+
const buffer = new Uint8Array(Math.max(known > 0 ? known : PES_START, payload.length));
|
|
128
|
+
buffer.set(payload);
|
|
129
|
+
this.partial.set(pid, { buffer, size: payload.length, expected: known });
|
|
128
130
|
}
|
|
129
131
|
else {
|
|
130
132
|
const partial = this.partial.get(pid);
|
|
131
133
|
// 頭を見ていない続きは捨てる (途中から受け取った)
|
|
132
134
|
if (partial === undefined)
|
|
133
135
|
return;
|
|
134
|
-
partial.
|
|
135
|
-
|
|
136
|
+
const end = partial.size + payload.length;
|
|
137
|
+
if (end > partial.buffer.length) {
|
|
138
|
+
const wider = new Uint8Array(Math.max(end, partial.buffer.length * 2));
|
|
139
|
+
wider.set(partial.buffer.subarray(0, partial.size));
|
|
140
|
+
partial.buffer = wider;
|
|
141
|
+
}
|
|
142
|
+
partial.buffer.set(payload, partial.size);
|
|
143
|
+
partial.size = end;
|
|
136
144
|
}
|
|
137
145
|
const partial = this.partial.get(pid);
|
|
138
146
|
if (partial !== undefined &&
|
|
@@ -146,7 +154,12 @@ export class PesDemuxer {
|
|
|
146
154
|
if (partial === undefined)
|
|
147
155
|
return;
|
|
148
156
|
this.partial.delete(pid);
|
|
149
|
-
|
|
157
|
+
// 余りが大きければ詰めて返す。返したものはキューに積まれたり worker へ送られたりするので、
|
|
158
|
+
// 広げた入れ物の余り (最大で倍近く) まで抱えさせない
|
|
159
|
+
const { buffer, size } = partial;
|
|
160
|
+
const parsed = parsePes(size * 1.25 < buffer.length
|
|
161
|
+
? buffer.slice(0, size)
|
|
162
|
+
: buffer.subarray(0, size));
|
|
150
163
|
if (parsed === null || parsed.data.length === 0)
|
|
151
164
|
return;
|
|
152
165
|
out.push({ pid, kind, ...parsed });
|
package/dist/psi.d.ts
CHANGED
|
@@ -73,7 +73,7 @@ export declare class SectionAssembler {
|
|
|
73
73
|
private append;
|
|
74
74
|
private flush;
|
|
75
75
|
}
|
|
76
|
-
/** `from` 以降 `until` の手前までで、188 間隔に 0x47 が続くところを探す。無ければ -1 (`seek.ts` も使う) */
|
|
76
|
+
/** `from` 以降 `until` の手前までで、188 間隔に 0x47 が続くところを探す。無ければ -1 (denpa の `seek.ts` も使う) */
|
|
77
77
|
export declare function findSync(data: Uint8Array, from?: number, until?: number): number;
|
|
78
78
|
/**
|
|
79
79
|
* 任意の長さで届くバイト列を 188 バイトのパケットに切り分ける。
|
|
@@ -84,7 +84,7 @@ export declare function findSync(data: Uint8Array, from?: number, until?: number
|
|
|
84
84
|
*
|
|
85
85
|
* **出すパケットは渡された塊の上の窓** (写しではない。写すと録画の処理の 1/3 を食う)。
|
|
86
86
|
* 塊の入れ物を使い回す呼び出し側がある
|
|
87
|
-
* (`server/recorded-bml.ts`) ので、**次の `feed` より後まで持つなら写すこと**。
|
|
87
|
+
* (denpa の `server/recorded-bml.ts`) ので、**次の `feed` より後まで持つなら写すこと**。
|
|
88
88
|
* いまのパーサ (`SectionAssembler`・`PesDemuxer`) は溜めるときに写している
|
|
89
89
|
*/
|
|
90
90
|
export declare class PacketStream {
|
|
@@ -114,7 +114,7 @@ export declare const DESC_DIGITAL_COPY_CONTROL = 193;
|
|
|
114
114
|
*
|
|
115
115
|
* 先頭2ビットの digital_recording_control_data が 11 なら禁止
|
|
116
116
|
* (00 コピー可、01 事業者定義、10 1世代のみ)。禁止の番組は録らない
|
|
117
|
-
* ([data.md](https://github.com/danything/denpa/blob/main/docs/data.md)
|
|
117
|
+
* ([data.md](https://github.com/danything/denpa/blob/main/docs/data.md)「コピー禁止の番組は録らない」)
|
|
118
118
|
*/
|
|
119
119
|
export declare function isCopyNever(data: Uint8Array): boolean;
|
|
120
120
|
/**
|
|
@@ -135,7 +135,7 @@ export declare function parsePat(section: Uint8Array): Map<number, number>;
|
|
|
135
135
|
/**
|
|
136
136
|
* SDT のサービスの並びを (service_id, 記述子の並び) に切り分ける。
|
|
137
137
|
*
|
|
138
|
-
* **読む側が2つある。** 局名 (`parseSdt`) とロゴの対応 (`ts/logo.ts`) で、
|
|
138
|
+
* **読む側が2つある。** 局名 (`parseSdt`) とロゴの対応 (denpa の `ts/logo.ts`) で、
|
|
139
139
|
* 欲しい記述子が違うだけで歩き方は同じ。並びの読み方をここ1箇所に置く。
|
|
140
140
|
*/
|
|
141
141
|
export declare function sdtServices(section: Uint8Array): Generator<[number, Uint8Array]>;
|
package/dist/psi.js
CHANGED
|
@@ -31,7 +31,7 @@ const DESC_TS_INFORMATION = 0xcd;
|
|
|
31
31
|
/**
|
|
32
32
|
* スキャンで残すサービス種別。Mirakurun のスキャンが通しているものと同じで、
|
|
33
33
|
* ラジオ (0x02) とデータ (0xc0) も入る。映像の無いものを番組表に並べないのは
|
|
34
|
-
* 取り込むほう (epg.ts の DIGITAL_TV)
|
|
34
|
+
* 取り込むほう (denpa の epg.ts の DIGITAL_TV)
|
|
35
35
|
*/
|
|
36
36
|
const SERVICE_TYPES = new Set([0x01, 0x02, 0xa1, 0xa4, 0xa5, 0xad, 0xc0]);
|
|
37
37
|
const CRC32_TABLE = (() => {
|
|
@@ -168,7 +168,7 @@ export class SectionAssembler {
|
|
|
168
168
|
* 1つだけでは中身のたまたまの 0x47 を頭と誤認する
|
|
169
169
|
*/
|
|
170
170
|
const CONFIRM = 3;
|
|
171
|
-
/** `from` 以降 `until` の手前までで、188 間隔に 0x47 が続くところを探す。無ければ -1 (`seek.ts` も使う) */
|
|
171
|
+
/** `from` 以降 `until` の手前までで、188 間隔に 0x47 が続くところを探す。無ければ -1 (denpa の `seek.ts` も使う) */
|
|
172
172
|
export function findSync(data, from = 0, until = data.length) {
|
|
173
173
|
for (let at = from; at < until && at + PACKET * (CONFIRM - 1) < data.length; at++) {
|
|
174
174
|
let i = 0;
|
|
@@ -188,7 +188,7 @@ export function findSync(data, from = 0, until = data.length) {
|
|
|
188
188
|
*
|
|
189
189
|
* **出すパケットは渡された塊の上の窓** (写しではない。写すと録画の処理の 1/3 を食う)。
|
|
190
190
|
* 塊の入れ物を使い回す呼び出し側がある
|
|
191
|
-
* (`server/recorded-bml.ts`) ので、**次の `feed` より後まで持つなら写すこと**。
|
|
191
|
+
* (denpa の `server/recorded-bml.ts`) ので、**次の `feed` より後まで持つなら写すこと**。
|
|
192
192
|
* いまのパーサ (`SectionAssembler`・`PesDemuxer`) は溜めるときに写している
|
|
193
193
|
*/
|
|
194
194
|
export class PacketStream {
|
|
@@ -308,7 +308,7 @@ export const DESC_DIGITAL_COPY_CONTROL = 0xc1;
|
|
|
308
308
|
*
|
|
309
309
|
* 先頭2ビットの digital_recording_control_data が 11 なら禁止
|
|
310
310
|
* (00 コピー可、01 事業者定義、10 1世代のみ)。禁止の番組は録らない
|
|
311
|
-
* ([data.md](https://github.com/danything/denpa/blob/main/docs/data.md)
|
|
311
|
+
* ([data.md](https://github.com/danything/denpa/blob/main/docs/data.md)「コピー禁止の番組は録らない」)
|
|
312
312
|
*/
|
|
313
313
|
export function isCopyNever(data) {
|
|
314
314
|
return data.length >= 1 && data[0] >> 6 === 0b11;
|
|
@@ -360,7 +360,7 @@ export function parsePat(section) {
|
|
|
360
360
|
/**
|
|
361
361
|
* SDT のサービスの並びを (service_id, 記述子の並び) に切り分ける。
|
|
362
362
|
*
|
|
363
|
-
* **読む側が2つある。** 局名 (`parseSdt`) とロゴの対応 (`ts/logo.ts`) で、
|
|
363
|
+
* **読む側が2つある。** 局名 (`parseSdt`) とロゴの対応 (denpa の `ts/logo.ts`) で、
|
|
364
364
|
* 欲しい記述子が違うだけで歩き方は同じ。並びの読み方をここ1箇所に置く。
|
|
365
365
|
*/
|
|
366
366
|
export function* sdtServices(section) {
|
package/dist/service-filter.d.ts
CHANGED
|
@@ -22,8 +22,9 @@
|
|
|
22
22
|
/**
|
|
23
23
|
* 局1つぶんに絞る。
|
|
24
24
|
*
|
|
25
|
-
* PAT
|
|
26
|
-
*
|
|
25
|
+
* PAT と PMT を読むまでは**何も出さない**。どの PID がその局のものか決まらないためで、
|
|
26
|
+
* どちらも 100ms ごとに流れてくるので待つのは一瞬。**待つ間に届いたものは取っておき**、PMT を読んだら
|
|
27
|
+
* その局のぶんを PMT の後ろに出す (`HOLD_MOST`)。
|
|
27
28
|
*/
|
|
28
29
|
export declare class ServiceFilter {
|
|
29
30
|
private readonly serviceId;
|
|
@@ -40,15 +41,17 @@ export declare class ServiceFilter {
|
|
|
40
41
|
private tsid;
|
|
41
42
|
private copyNeverNow;
|
|
42
43
|
private streamsNow;
|
|
44
|
+
/** PMT を読む前に届いた、局の分からないパケット (写したもの)。届いた順 */
|
|
45
|
+
private held;
|
|
43
46
|
constructor(serviceId: number);
|
|
44
|
-
/** その局の PMT を読めたか。読めるまで映像は1バイトも出ない */
|
|
47
|
+
/** その局の PMT を読めたか。読めるまで映像は1バイトも出ない (届いたものは取っておく) */
|
|
45
48
|
get ready(): boolean;
|
|
46
49
|
/**
|
|
47
50
|
* **いま流れているものがコピー禁止か** (最後に読んだ PMT のデジタルコピー制御記述子)。
|
|
48
51
|
* 番組全体 (1つめのループ) と ES ごと (2つめのループ) のどちらかが禁止なら禁止。
|
|
49
52
|
* PMT を読むまでは false。
|
|
50
53
|
*
|
|
51
|
-
* 録画はこれを見て、禁止のあいだは保存しない (`recorder.ts`)。番組表が古い・無いときの備え。
|
|
54
|
+
* 録画はこれを見て、禁止のあいだは保存しない (denpa の `recorder.ts`)。番組表が古い・無いときの備え。
|
|
52
55
|
* 絞り方には効かせない — ライブは保存しないので、禁止の番組もそのまま観られる
|
|
53
56
|
*/
|
|
54
57
|
get copyNever(): boolean;
|
|
@@ -75,8 +78,16 @@ export declare class ServiceFilter {
|
|
|
75
78
|
*
|
|
76
79
|
* 落とした PID の連続性カウンタは飛ぶが、**残す PID は元のまま**なので
|
|
77
80
|
* 読む側から見て抜けは無い。自分で作るのは PAT だけで、そこは自前で数える。
|
|
81
|
+
*
|
|
82
|
+
* **PMT を読む前に届いたものも捨てない。** 選局したてで捨てると、PMT の前に始まった I フレームを失って
|
|
83
|
+
* 次の GOP (0.5 秒) まで映像が出ず、音も PMT のあとから貯め始めることになる。取っておいて、読めたら
|
|
84
|
+
* その局のぶんだけを PMT の後ろに足す (並びは届いた順のまま。読む側は PAT・PMT を先に知る)
|
|
78
85
|
*/
|
|
79
86
|
filter(chunk: Uint8Array): Uint8Array;
|
|
87
|
+
/** PMT を読む前のパケットを取っておく。**写す** (パケットは届いた塊の上の窓。`PacketStream`) */
|
|
88
|
+
private hold;
|
|
89
|
+
/** 取っておいたもののうち、その局のぶんを出す */
|
|
90
|
+
private release;
|
|
80
91
|
private readPat;
|
|
81
92
|
private readPmt;
|
|
82
93
|
}
|
|
@@ -85,7 +96,7 @@ export declare class ServiceFilter {
|
|
|
85
96
|
* 1回だけ true を返して新しい並びを覚え直す。
|
|
86
97
|
*
|
|
87
98
|
* 並びを決め打ちで起こした ffmpeg (`-map`) は、番組が替わって音声の本数や字幕の PID が変わっても追従しない。
|
|
88
|
-
* 変わったら起こし直す — ライブと追っかけのエンコード (`server/live.ts` の `Session.pump`)、MPEG-2 をそのまま
|
|
99
|
+
* 変わったら起こし直す — ライブと追っかけのエンコード (denpa の `server/live.ts` の `Session.pump`)、MPEG-2 をそのまま
|
|
89
100
|
* 流す経路の字幕 (`Session.runRaw`・`recordingCaptions`)
|
|
90
101
|
*/
|
|
91
102
|
export declare class StreamsWatch {
|
package/dist/service-filter.js
CHANGED
|
@@ -26,7 +26,7 @@ const PID_NULL = 0x1fff;
|
|
|
26
26
|
* 局に関係なく残す PID。**どれも数十バイト/秒**で、落として得るものが無い。
|
|
27
27
|
*
|
|
28
28
|
* CDT (ロゴ) はここに入れない。録画に要らないうえ、衛星では数百KBのカルーセルが
|
|
29
|
-
* 流れてくる。ロゴを取得するのは録画の外でやる (logo.ts)
|
|
29
|
+
* 流れてくる。ロゴを取得するのは録画の外でやる (denpa の logo.ts)
|
|
30
30
|
*/
|
|
31
31
|
const KEEP = new Set([
|
|
32
32
|
0x0001, // CAT
|
|
@@ -36,6 +36,13 @@ const KEEP = new Set([
|
|
|
36
36
|
0x0014, // TDT / TOT
|
|
37
37
|
]);
|
|
38
38
|
const DESC_CA = 0x09;
|
|
39
|
+
/**
|
|
40
|
+
* PMT を読むまで取っておくパケットの数の上限。**選局したての頭を捨てない** (`ServiceFilter.filter`)。
|
|
41
|
+
*
|
|
42
|
+
* PAT と PMT はそれぞれ 100ms ごとに来るので、待つのはふつう 0.2 秒まで。地上波 (17Mbit/s) なら 2,300 個、
|
|
43
|
+
* BS の中継丸ごと (52Mbit/s) でも 7,000 個ほど。来ない (局を読み違えた) ときに抱え込み続けないよう、超えたら古いほうから捨てる
|
|
44
|
+
*/
|
|
45
|
+
const HOLD_MOST = 8192;
|
|
39
46
|
/** 1つの局に絞った PAT を組み立てる */
|
|
40
47
|
function buildPat(transportStreamId, version, serviceId, pmtPid) {
|
|
41
48
|
const body = [
|
|
@@ -78,8 +85,9 @@ const MEDIA_STREAMS = new Set([0x02, 0x1b, 0x24, 0x03, 0x04, 0x0f, 0x11, 0x06]);
|
|
|
78
85
|
/**
|
|
79
86
|
* 局1つぶんに絞る。
|
|
80
87
|
*
|
|
81
|
-
* PAT
|
|
82
|
-
*
|
|
88
|
+
* PAT と PMT を読むまでは**何も出さない**。どの PID がその局のものか決まらないためで、
|
|
89
|
+
* どちらも 100ms ごとに流れてくるので待つのは一瞬。**待つ間に届いたものは取っておき**、PMT を読んだら
|
|
90
|
+
* その局のぶんを PMT の後ろに出す (`HOLD_MOST`)。
|
|
83
91
|
*/
|
|
84
92
|
export class ServiceFilter {
|
|
85
93
|
serviceId;
|
|
@@ -96,10 +104,12 @@ export class ServiceFilter {
|
|
|
96
104
|
tsid = null;
|
|
97
105
|
copyNeverNow = false;
|
|
98
106
|
streamsNow = null;
|
|
107
|
+
/** PMT を読む前に届いた、局の分からないパケット (写したもの)。届いた順 */
|
|
108
|
+
held = [];
|
|
99
109
|
constructor(serviceId) {
|
|
100
110
|
this.serviceId = serviceId;
|
|
101
111
|
}
|
|
102
|
-
/** その局の PMT を読めたか。読めるまで映像は1バイトも出ない */
|
|
112
|
+
/** その局の PMT を読めたか。読めるまで映像は1バイトも出ない (届いたものは取っておく) */
|
|
103
113
|
get ready() {
|
|
104
114
|
return this.own.size > 0;
|
|
105
115
|
}
|
|
@@ -108,7 +118,7 @@ export class ServiceFilter {
|
|
|
108
118
|
* 番組全体 (1つめのループ) と ES ごと (2つめのループ) のどちらかが禁止なら禁止。
|
|
109
119
|
* PMT を読むまでは false。
|
|
110
120
|
*
|
|
111
|
-
* 録画はこれを見て、禁止のあいだは保存しない (`recorder.ts`)。番組表が古い・無いときの備え。
|
|
121
|
+
* 録画はこれを見て、禁止のあいだは保存しない (denpa の `recorder.ts`)。番組表が古い・無いときの備え。
|
|
112
122
|
* 絞り方には効かせない — ライブは保存しないので、禁止の番組もそのまま観られる
|
|
113
123
|
*/
|
|
114
124
|
get copyNever() {
|
|
@@ -141,6 +151,10 @@ export class ServiceFilter {
|
|
|
141
151
|
*
|
|
142
152
|
* 落とした PID の連続性カウンタは飛ぶが、**残す PID は元のまま**なので
|
|
143
153
|
* 読む側から見て抜けは無い。自分で作るのは PAT だけで、そこは自前で数える。
|
|
154
|
+
*
|
|
155
|
+
* **PMT を読む前に届いたものも捨てない。** 選局したてで捨てると、PMT の前に始まった I フレームを失って
|
|
156
|
+
* 次の GOP (0.5 秒) まで映像が出ず、音も PMT のあとから貯め始めることになる。取っておいて、読めたら
|
|
157
|
+
* その局のぶんだけを PMT の後ろに足す (並びは届いた順のまま。読む側は PAT・PMT を先に知る)
|
|
144
158
|
*/
|
|
145
159
|
filter(chunk) {
|
|
146
160
|
const out = [];
|
|
@@ -158,12 +172,30 @@ export class ServiceFilter {
|
|
|
158
172
|
if (pid === this.pmtPid) {
|
|
159
173
|
this.readPmt(ts);
|
|
160
174
|
out.push(ts);
|
|
175
|
+
if (this.own.size > 0)
|
|
176
|
+
this.release(out);
|
|
161
177
|
}
|
|
162
178
|
else if (KEEP.has(pid) || this.own.has(pid))
|
|
163
179
|
out.push(ts);
|
|
180
|
+
else if (this.own.size === 0)
|
|
181
|
+
this.hold(ts);
|
|
164
182
|
}
|
|
165
183
|
return concatBytes(out);
|
|
166
184
|
}
|
|
185
|
+
/** PMT を読む前のパケットを取っておく。**写す** (パケットは届いた塊の上の窓。`PacketStream`) */
|
|
186
|
+
hold(ts) {
|
|
187
|
+
this.held.push(ts.slice());
|
|
188
|
+
// 溢れたら古い半分を捨てる (1つずつ捨てると、来ないあいだずっと詰め直すことになる)
|
|
189
|
+
if (this.held.length > HOLD_MOST)
|
|
190
|
+
this.held = this.held.slice(this.held.length - HOLD_MOST / 2);
|
|
191
|
+
}
|
|
192
|
+
/** 取っておいたもののうち、その局のぶんを出す */
|
|
193
|
+
release(out) {
|
|
194
|
+
for (const ts of this.held)
|
|
195
|
+
if (this.own.has(packetPid(ts)))
|
|
196
|
+
out.push(ts);
|
|
197
|
+
this.held = [];
|
|
198
|
+
}
|
|
167
199
|
readPat(ts) {
|
|
168
200
|
for (const section of this.pat.feed(ts)) {
|
|
169
201
|
if (section[0] !== TABLE_PAT)
|
|
@@ -217,7 +249,7 @@ export class ServiceFilter {
|
|
|
217
249
|
* 1回だけ true を返して新しい並びを覚え直す。
|
|
218
250
|
*
|
|
219
251
|
* 並びを決め打ちで起こした ffmpeg (`-map`) は、番組が替わって音声の本数や字幕の PID が変わっても追従しない。
|
|
220
|
-
* 変わったら起こし直す — ライブと追っかけのエンコード (`server/live.ts` の `Session.pump`)、MPEG-2 をそのまま
|
|
252
|
+
* 変わったら起こし直す — ライブと追っかけのエンコード (denpa の `server/live.ts` の `Session.pump`)、MPEG-2 をそのまま
|
|
221
253
|
* 流す経路の字幕 (`Session.runRaw`・`recordingCaptions`)
|
|
222
254
|
*/
|
|
223
255
|
export class StreamsWatch {
|
package/dist/synth-av.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* **本物の MPEG-2 映像と AAC 音声を、ffmpeg 無しで組み立てる** (試験用)。
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* denpa のライブを変換せずに送る経路 (docs/stream.md#放送そのままmpeg-2を送る) は、ブラウザが MPEG-2 をデコードして映像を出す
|
|
5
5
|
* ところまでが仕事で、そこを試すには**本当にデコードできる放送**が要る。偽エージェントの
|
|
6
6
|
* 放送は中身を 0xFF で埋めていて、デコードするものが無い。E2E のイメージには本物の ffmpeg も
|
|
7
7
|
* 入っていない (数十分かかる組み立てを避けている) ので、ここで小さく作る。
|
|
@@ -23,7 +23,7 @@ export declare const AUDIO_TICKS = 1920;
|
|
|
23
23
|
* (放送は GOP ごとに書く。試験ではその手間を省く)。
|
|
24
24
|
*
|
|
25
25
|
* @param n 何枚目か。色と time_code に使う
|
|
26
|
-
* @param color マクロブロック (16x16) ごとの色。既定は流れる縞 (
|
|
26
|
+
* @param color マクロブロック (16x16) ごとの色。既定は流れる縞 (スクリーンショットを撮るときはカラーバー。denpa の `tests/fake/docs.ts`)
|
|
27
27
|
*/
|
|
28
28
|
export declare function mpeg2Frame(n: number, color?: (col: number, row: number, n: number, field: 0 | 1) => [number, number, number]): Uint8Array;
|
|
29
29
|
/**
|
|
@@ -36,7 +36,7 @@ export declare function silentAac(): Uint8Array;
|
|
|
36
36
|
/**
|
|
37
37
|
* PES にする。映像は長さ 0 (「次の頭まで」。放送もそう書く)、音声は長さを書く
|
|
38
38
|
*
|
|
39
|
-
* @param streamId 0xE0 (映像) / 0xC0 (音声)
|
|
39
|
+
* @param streamId 0xE0 (映像) / 0xC0 (音声) / 0xBD (字幕。`synth-caption.ts`)
|
|
40
40
|
*/
|
|
41
41
|
export declare function pes(streamId: number, pts: number, data: Uint8Array): Uint8Array;
|
|
42
42
|
/**
|