@danything/arib 2.1.0 → 2.3.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.
@@ -0,0 +1,170 @@
1
+ /**
2
+ * 4K の放送 (MMT/TLV) の映像・音声・字幕を取り出す (ISO/IEC 23008-1、ARIB STD-B60)。TS の `pes.ts` に当たる。
3
+ *
4
+ * MMT では、映像・音声・字幕は MPU (頭出しできる所から次の頭出しできる所まで) に分けて送られる。
5
+ * MPU の中身はアクセスユニット (映像の 1 コマ、音声の 1 フレーム) の並びで、データユニットを
6
+ * MMTP のパケットに分割したり、小さいものを 1 つに集約したりして運ぶ (`mmtp.ts` の `parseMpu`)。
7
+ *
8
+ * **時刻はパケットには無く、MPT の記述子にある。** MPU タイムスタンプ記述子が MPU の最初の提示時刻を、
9
+ * MPU 拡張タイムスタンプ記述子がアクセスユニットごとのずれを、これから来る MPU のぶんまで並べる
10
+ * (実機のケーブルの BS4K で確かめた。映像は 1 MPU に 32 コマ、音声は 4 フレーム)。
11
+ * 時刻は NTP の 64 ビットで来るので、ここで **90 kHz** に直す (TS の PTS と同じ物差し。一周はしない)。
12
+ *
13
+ * 中身の形式は次のとおり。実機の録りは映像・音声がスクランブルされていて中身を読めないので、どれも推定。
14
+ *
15
+ * - 映像 (`hev1`): データユニット 1 つが、長さ (4 バイト) を前に付けた NAL ユニット。MPU は ISO BMFF の形式なので、
16
+ * サンプルの中身も MP4 と同じ形と見ている。同じ sample_number のデータユニットが 1 つのコマ
17
+ * - 音声 (`mp4a`): データユニット 1 つが LATM の AudioMuxElement (LOAS の同期のヘッダーは付かない)。
18
+ * MPT の音声コンポーネント記述子の stream_type は 0x11 (LATM/LOAS) だった (確かめた)
19
+ * - 字幕 (`stpp`): MPU 1 つが TTML の文書 1 つ (`ttml.ts` で読む)。文書の中の画像 (PNG) は扱わない
20
+ *
21
+ * スクランブルされたパケットは数えて捨てる (`scrambled`)。復号はエージェントの仕事
22
+ */
23
+ import { CLOCK } from "./pes.js";
24
+ /** 放送の時刻の物差し (TS の PTS と同じ。`pes.ts` の `CLOCK`) */
25
+ export { CLOCK };
26
+ /** NTP の 64 ビットの時刻 (上位 32 ビットが秒、下位 32 ビットが端数) を 90 kHz に */
27
+ export declare function ntpToClock(data: Uint8Array, at: number): number;
28
+ /** MPU タイムスタンプ記述子を読む。`[mpu_sequence_number, 最初の提示時刻 (90 kHz)]` の並び */
29
+ export declare function parseMpuTimestamps(body: Uint8Array): [number, number][];
30
+ /** MPU 拡張タイムスタンプ記述子の、MPU 1 つぶん。時間は `timescale` の単位 */
31
+ export interface MpuExtendedTimestamp {
32
+ mpuSequenceNumber: number;
33
+ timescale: number;
34
+ /** mpu_decoding_time_offset。最初のアクセスユニットの DTS が、最初の提示時刻より前にずれる長さ */
35
+ decodingOffset: number;
36
+ /** アクセスユニットごとの、DTS から PTS までのずれ (デコードの順) */
37
+ dtsPtsOffsets: number[];
38
+ /** アクセスユニットごとの、次のアクセスユニットの DTS までの長さ (pts_offset) */
39
+ durations: number[];
40
+ }
41
+ /**
42
+ * MPU 拡張タイムスタンプ記述子を読む。次のものは DTS を進められないので、空を返す (その MPU は時刻が分からないものとして捨てる)
43
+ *
44
+ * - timescale を持たないもの (MPU のメタデータの mdhd を見る、の意味)。放送ではメタデータを送らない
45
+ * - pts_offset を持たないもの (pts_offset_type 0)。コマの長さが分からない
46
+ */
47
+ export declare function parseMpuExtendedTimestamps(body: Uint8Array): MpuExtendedTimestamp[];
48
+ /** アクセスユニットの時刻 (90 kHz) */
49
+ export interface UnitTime {
50
+ pts: number;
51
+ dts: number;
52
+ /** 次のアクセスユニットの DTS まで */
53
+ duration: number;
54
+ }
55
+ /**
56
+ * MPU の `index` 番目 (デコードの順、0 から) のアクセスユニットの時刻。
57
+ * DTS は最初の提示時刻から decodingOffset だけ戻った所に始まり、durations を足して進む。
58
+ * PTS は DTS に dtsPtsOffsets を足したもの。記述子に無い番目なら null
59
+ */
60
+ export declare function unitTime(presentation: number, extended: MpuExtendedTimestamp, index: number): UnitTime | null;
61
+ /** AAC の設定 (LATM の StreamMuxConfig にある AudioSpecificConfig) */
62
+ export interface AacConfig {
63
+ /** AudioSpecificConfig のバイト列 (MP4 の esds にそのまま入れる) */
64
+ audioSpecificConfig: Uint8Array;
65
+ /** audioObjectType (2 は AAC LC) */
66
+ objectType: number;
67
+ sampleRate: number;
68
+ /** チャンネルの数 (channelConfiguration 7 は 8) */
69
+ channels: number;
70
+ }
71
+ /**
72
+ * LATM の AudioMuxElement (muxConfigPresent = 1) から、AAC のフレームを取り出す。
73
+ * **設定 (StreamMuxConfig) は来たときだけ書いてあり、あいだは「前と同じ」になる** ので、前の設定を覚えておく。
74
+ *
75
+ * 読むのは放送で使う形 (番組 1・層 1・サブフレーム 1・frameLengthType 0) だけ。ほかの形は null を返す
76
+ */
77
+ export declare class LatmReader {
78
+ private config;
79
+ read(element: Uint8Array): {
80
+ config: AacConfig;
81
+ frame: Uint8Array;
82
+ } | null;
83
+ private readStreamMuxConfig;
84
+ }
85
+ export type MediaKind = "video" | "audio" | "caption";
86
+ /** 取り出すアセット (MPT のアセットのうち、映像・音声・字幕のそれぞれ最初のもの) */
87
+ export interface MediaAsset {
88
+ kind: MediaKind;
89
+ /** asset_type (`hev1`・`mp4a`・`stpp`) */
90
+ type: string;
91
+ packetId: number;
92
+ /** MH-ストリーム識別記述子の component_tag。無ければ null */
93
+ componentTag: number | null;
94
+ }
95
+ interface UnitBase extends UnitTime {
96
+ asset: MediaAsset;
97
+ mpuSequenceNumber: number;
98
+ }
99
+ /** 映像の 1 コマ */
100
+ export interface VideoUnit extends UnitBase {
101
+ kind: "video";
102
+ /** NAL ユニットの並び (長さの前置きを外したもの) */
103
+ nals: Uint8Array[];
104
+ /** IRAP (IDR・CRA・BLA) のピクチャを含む */
105
+ keyframe: boolean;
106
+ }
107
+ /** 音声の 1 フレーム */
108
+ export interface AudioUnit extends UnitBase {
109
+ kind: "audio";
110
+ /** AAC のフレーム (LATM を外したもの。ADTS のヘッダーも無い) */
111
+ frame: Uint8Array;
112
+ config: AacConfig;
113
+ }
114
+ /** 字幕の文書 1 つ。時刻は MPU の最初の提示時刻 */
115
+ export interface CaptionUnit extends UnitBase {
116
+ kind: "caption";
117
+ /** TTML の文書 (UTF-8 を読んだもの) */
118
+ document: string;
119
+ }
120
+ export type MediaUnit = VideoUnit | AudioUnit | CaptionUnit;
121
+ /**
122
+ * `MmtMediaReader.feed` が返すもの。選んだアセットが変わったら (番組が替わったときなど)、
123
+ * 先に `assets` が来る。受け側は組み立て中のもの (fMP4 の初期化セグメント) を作り直す
124
+ */
125
+ export type MediaEvent = {
126
+ kind: "assets";
127
+ assets: MediaAsset[];
128
+ } | MediaUnit;
129
+ /**
130
+ * 1 局に絞った TLV のバイト列 (`mmt-service-filter.ts`) から、映像・音声・字幕のアクセスユニットを時刻つきで取り出す。
131
+ *
132
+ * - 局 (`serviceId` = MMT_package_id) の MPT を読んで、映像・音声・字幕のそれぞれ最初のアセットを選ぶ。
133
+ * アセットは MPT と同じ IP の並びのもの (在りかの種類 0) だけを読む
134
+ * - 時刻は MPT の記述子から引く。時刻がまだ分からない MPU (最初の MPT より先に来たもの) は数えて捨てる (`untimed`)
135
+ * - パケットが欠けた (packet_sequence_number が続かない) アクセスユニットは捨てる (`dropped`)
136
+ * - アクセスユニットは、次のアクセスユニット (か次の MPU) の始まりが来たときに返す。最後のものは `end` で返す
137
+ */
138
+ export declare class MmtMediaReader {
139
+ private readonly serviceId;
140
+ private readonly tlv;
141
+ private readonly ip;
142
+ private readonly signaling;
143
+ /** `並び/packet_id` → 組み立て */
144
+ private tracks;
145
+ /** 選んだアセットの並び (変わったかを見る) */
146
+ private selection;
147
+ /** 選んだアセットの MMTP のパケット (MPU) の数。スクランブルされていたもの (`scrambled`) も数える */
148
+ media: number;
149
+ /** スクランブルされていて読めなかった MMTP のパケットの数 */
150
+ scrambled: number;
151
+ /** 時刻が分からずに捨てたアクセスユニットの数 */
152
+ untimed: number;
153
+ /** パケットが欠けたか、中身を読めずに捨てたアクセスユニットの数 */
154
+ dropped: number;
155
+ constructor(serviceId: number);
156
+ /** 選んでいるアセット */
157
+ get assets(): MediaAsset[];
158
+ feed(chunk: Uint8Array): Generator<MediaEvent>;
159
+ /** 終わりまで読んだとき、組み立て中のアクセスユニットを閉じて返す (録画のファイルの最後など) */
160
+ end(): Generator<MediaUnit>;
161
+ /** MPT から、アセットを選び直して時刻を覚える */
162
+ private readMpt;
163
+ /** MPU のパケットの中身を 1 つ読む */
164
+ private readMpu;
165
+ /** データユニット (分割したものはその断片) を 1 つ受ける。ヘッダーは断片ごとに付いている */
166
+ private dataUnit;
167
+ private keep;
168
+ /** 組み立て中のアクセスユニットを閉じて返す */
169
+ private finish;
170
+ }