homebridge-plugin-utils 1.35.0 → 2.1.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.
Files changed (204) hide show
  1. package/README.md +130 -2
  2. package/build/eslint-plugin/README.md +164 -0
  3. package/build/eslint-plugin/config.mjs +308 -0
  4. package/build/eslint-plugin/index.mjs +7 -0
  5. package/build/eslint-plugin/plugin.mjs +46 -0
  6. package/build/eslint-plugin/rules/blank-line-after-open-brace.mjs +137 -0
  7. package/build/eslint-plugin/rules/blank-line-after-open-brace.test.mjs +112 -0
  8. package/build/eslint-plugin/rules/comment-style.mjs +190 -0
  9. package/build/eslint-plugin/rules/comment-style.test.mjs +190 -0
  10. package/build/eslint-plugin/rules/enforce-node-protocol.mjs +114 -0
  11. package/build/eslint-plugin/rules/enforce-node-protocol.test.mjs +116 -0
  12. package/build/eslint-plugin/rules/paren-comparisons-in-logical.mjs +94 -0
  13. package/build/eslint-plugin/rules/paren-comparisons-in-logical.test.mjs +107 -0
  14. package/build/eslint-plugin/rules/split-type-imports.mjs +354 -0
  15. package/build/eslint-plugin/rules/split-type-imports.test.mjs +268 -0
  16. package/build/eslint-plugin/test-setup.mjs +21 -0
  17. package/build/fs-ops.mjs +184 -0
  18. package/build/tsconfig.json +18 -3
  19. package/dist/backpressure.d.ts +94 -45
  20. package/dist/backpressure.js +229 -93
  21. package/dist/backpressure.js.map +1 -1
  22. package/dist/cli/index.d.ts +166 -0
  23. package/dist/cli/index.js +551 -0
  24. package/dist/cli/index.js.map +1 -0
  25. package/dist/clock-double.d.ts +93 -0
  26. package/dist/clock-double.js +141 -0
  27. package/dist/clock-double.js.map +1 -0
  28. package/dist/clock.d.ts +39 -0
  29. package/dist/clock.js +34 -0
  30. package/dist/clock.js.map +1 -0
  31. package/dist/disposable-stack.d.ts +59 -0
  32. package/dist/disposable-stack.js +155 -0
  33. package/dist/disposable-stack.js.map +1 -0
  34. package/dist/docChrome.d.ts +260 -0
  35. package/dist/docChrome.js +361 -0
  36. package/dist/docChrome.js.map +1 -0
  37. package/dist/eslint-plugin/config.d.mts +193 -0
  38. package/dist/eslint-plugin/index.d.mts +2 -0
  39. package/dist/eslint-plugin/plugin.d.mts +87 -0
  40. package/dist/eslint-plugin/rules/blank-line-after-open-brace.d.mts +19 -0
  41. package/dist/eslint-plugin/rules/comment-style.d.mts +15 -0
  42. package/dist/eslint-plugin/rules/enforce-node-protocol.d.mts +18 -0
  43. package/dist/eslint-plugin/rules/paren-comparisons-in-logical.d.mts +15 -0
  44. package/dist/eslint-plugin/rules/split-type-imports.d.mts +16 -0
  45. package/dist/featureOptions-docs.d.ts +96 -0
  46. package/dist/featureOptions-docs.js +193 -0
  47. package/dist/featureOptions-docs.js.map +1 -0
  48. package/dist/featureOptions.d.ts +674 -0
  49. package/dist/featureOptions.js +870 -0
  50. package/dist/featureOptions.js.map +1 -0
  51. package/dist/ffmpeg/codecs.d.ts +256 -72
  52. package/dist/ffmpeg/codecs.js +477 -262
  53. package/dist/ffmpeg/codecs.js.map +1 -1
  54. package/dist/ffmpeg/dgram-util.d.ts +46 -0
  55. package/dist/ffmpeg/dgram-util.js +38 -0
  56. package/dist/ffmpeg/dgram-util.js.map +1 -0
  57. package/dist/ffmpeg/exec.d.ts +83 -64
  58. package/dist/ffmpeg/exec.js +77 -86
  59. package/dist/ffmpeg/exec.js.map +1 -1
  60. package/dist/ffmpeg/fmp4.d.ts +49 -2
  61. package/dist/ffmpeg/fmp4.js +47 -11
  62. package/dist/ffmpeg/fmp4.js.map +1 -1
  63. package/dist/ffmpeg/hap-enums.d.ts +214 -0
  64. package/dist/ffmpeg/hap-enums.js +92 -0
  65. package/dist/ffmpeg/hap-enums.js.map +1 -0
  66. package/dist/ffmpeg/index.d.ts +16 -9
  67. package/dist/ffmpeg/index.js +6 -0
  68. package/dist/ffmpeg/index.js.map +1 -1
  69. package/dist/ffmpeg/mp4-assembler.d.ts +161 -0
  70. package/dist/ffmpeg/mp4-assembler.js +424 -0
  71. package/dist/ffmpeg/mp4-assembler.js.map +1 -0
  72. package/dist/ffmpeg/mp4-parser.d.ts +94 -0
  73. package/dist/ffmpeg/mp4-parser.js +130 -0
  74. package/dist/ffmpeg/mp4-parser.js.map +1 -0
  75. package/dist/ffmpeg/options.d.ts +62 -149
  76. package/dist/ffmpeg/options.js +608 -499
  77. package/dist/ffmpeg/options.js.map +1 -1
  78. package/dist/ffmpeg/process.d.ts +142 -96
  79. package/dist/ffmpeg/process.js +406 -278
  80. package/dist/ffmpeg/process.js.map +1 -1
  81. package/dist/ffmpeg/record.d.ts +325 -186
  82. package/dist/ffmpeg/record.js +418 -565
  83. package/dist/ffmpeg/record.js.map +1 -1
  84. package/dist/ffmpeg/recording-process-double.d.ts +157 -0
  85. package/dist/ffmpeg/recording-process-double.js +190 -0
  86. package/dist/ffmpeg/recording-process-double.js.map +1 -0
  87. package/dist/ffmpeg/rtp-parser.d.ts +70 -0
  88. package/dist/ffmpeg/rtp-parser.js +77 -0
  89. package/dist/ffmpeg/rtp-parser.js.map +1 -0
  90. package/dist/ffmpeg/rtp.d.ts +198 -141
  91. package/dist/ffmpeg/rtp.js +474 -251
  92. package/dist/ffmpeg/rtp.js.map +1 -1
  93. package/dist/ffmpeg/settings.d.ts +5 -2
  94. package/dist/ffmpeg/settings.js +20 -5
  95. package/dist/ffmpeg/settings.js.map +1 -1
  96. package/dist/ffmpeg/stream.d.ts +57 -107
  97. package/dist/ffmpeg/stream.js +121 -150
  98. package/dist/ffmpeg/stream.js.map +1 -1
  99. package/dist/formatters.d.ts +106 -0
  100. package/dist/formatters.js +174 -0
  101. package/dist/formatters.js.map +1 -0
  102. package/dist/homebridge-enums.d.ts +30 -0
  103. package/dist/homebridge-enums.js +17 -0
  104. package/dist/homebridge-enums.js.map +1 -0
  105. package/dist/index.d.ts +13 -6
  106. package/dist/index.js +8 -2
  107. package/dist/index.js.map +1 -1
  108. package/dist/logclient/auth.d.ts +114 -0
  109. package/dist/logclient/auth.js +199 -0
  110. package/dist/logclient/auth.js.map +1 -0
  111. package/dist/logclient/cli-run.d.ts +76 -0
  112. package/dist/logclient/cli-run.js +639 -0
  113. package/dist/logclient/cli-run.js.map +1 -0
  114. package/dist/logclient/cli.d.ts +3 -0
  115. package/dist/logclient/cli.js +97 -0
  116. package/dist/logclient/cli.js.map +1 -0
  117. package/dist/logclient/client.d.ts +145 -0
  118. package/dist/logclient/client.js +600 -0
  119. package/dist/logclient/client.js.map +1 -0
  120. package/dist/logclient/config.d.ts +173 -0
  121. package/dist/logclient/config.js +199 -0
  122. package/dist/logclient/config.js.map +1 -0
  123. package/dist/logclient/endpoints.d.ts +54 -0
  124. package/dist/logclient/endpoints.js +73 -0
  125. package/dist/logclient/endpoints.js.map +1 -0
  126. package/dist/logclient/filter.d.ts +45 -0
  127. package/dist/logclient/filter.js +51 -0
  128. package/dist/logclient/filter.js.map +1 -0
  129. package/dist/logclient/frame.d.ts +93 -0
  130. package/dist/logclient/frame.js +203 -0
  131. package/dist/logclient/frame.js.map +1 -0
  132. package/dist/logclient/index.d.ts +31 -0
  133. package/dist/logclient/index.js +12 -0
  134. package/dist/logclient/index.js.map +1 -0
  135. package/dist/logclient/parser.d.ts +211 -0
  136. package/dist/logclient/parser.js +393 -0
  137. package/dist/logclient/parser.js.map +1 -0
  138. package/dist/logclient/rest.d.ts +41 -0
  139. package/dist/logclient/rest.js +111 -0
  140. package/dist/logclient/rest.js.map +1 -0
  141. package/dist/logclient/settings.d.ts +15 -0
  142. package/dist/logclient/settings.js +64 -0
  143. package/dist/logclient/settings.js.map +1 -0
  144. package/dist/logclient/socket-double.d.ts +201 -0
  145. package/dist/logclient/socket-double.js +384 -0
  146. package/dist/logclient/socket-double.js.map +1 -0
  147. package/dist/logclient/socket.d.ts +257 -0
  148. package/dist/logclient/socket.js +620 -0
  149. package/dist/logclient/socket.js.map +1 -0
  150. package/dist/logclient/stitch.d.ts +83 -0
  151. package/dist/logclient/stitch.js +146 -0
  152. package/dist/logclient/stitch.js.map +1 -0
  153. package/dist/logclient/time-expression.d.ts +42 -0
  154. package/dist/logclient/time-expression.js +181 -0
  155. package/dist/logclient/time-expression.js.map +1 -0
  156. package/dist/logclient/time-window.d.ts +38 -0
  157. package/dist/logclient/time-window.js +53 -0
  158. package/dist/logclient/time-window.js.map +1 -0
  159. package/dist/logclient/types.d.ts +107 -0
  160. package/dist/logclient/types.js +6 -0
  161. package/dist/logclient/types.js.map +1 -0
  162. package/dist/mqttClient.d.ts +287 -0
  163. package/dist/mqttClient.js +433 -0
  164. package/dist/mqttClient.js.map +1 -0
  165. package/dist/service.d.ts +64 -15
  166. package/dist/service.js +93 -66
  167. package/dist/service.js.map +1 -1
  168. package/dist/ui/featureOptions.js +870 -0
  169. package/dist/ui/featureOptions.js.map +1 -0
  170. package/dist/ui/formatters.js +174 -0
  171. package/dist/ui/formatters.js.map +1 -0
  172. package/dist/ui/pluginConfigSession.mjs +141 -0
  173. package/dist/ui/webUi-featureOptions/categoryState.mjs +135 -0
  174. package/dist/ui/webUi-featureOptions/effects/keyboard.mjs +61 -0
  175. package/dist/ui/webUi-featureOptions/effects/persist.mjs +226 -0
  176. package/dist/ui/webUi-featureOptions/effects/theme.mjs +398 -0
  177. package/dist/ui/webUi-featureOptions/effects/tokens.mjs +152 -0
  178. package/dist/ui/webUi-featureOptions/rendering.mjs +431 -0
  179. package/dist/ui/webUi-featureOptions/selectors.mjs +360 -0
  180. package/dist/ui/webUi-featureOptions/state.mjs +319 -0
  181. package/dist/ui/webUi-featureOptions/store.mjs +181 -0
  182. package/dist/ui/webUi-featureOptions/utils.mjs +213 -0
  183. package/dist/ui/webUi-featureOptions/views/connectionError.mjs +152 -0
  184. package/dist/ui/webUi-featureOptions/views/deviceInfo.mjs +80 -0
  185. package/dist/ui/webUi-featureOptions/views/header.mjs +77 -0
  186. package/dist/ui/webUi-featureOptions/views/nav.mjs +341 -0
  187. package/dist/ui/webUi-featureOptions/views/options.mjs +521 -0
  188. package/dist/ui/webUi-featureOptions/views/search.mjs +395 -0
  189. package/dist/ui/webUi-featureOptions.mjs +702 -0
  190. package/dist/ui/webUi.mjs +225 -88
  191. package/dist/util.d.ts +679 -45
  192. package/dist/util.js +830 -77
  193. package/dist/util.js.map +1 -1
  194. package/package.json +33 -15
  195. package/build/eslint-rules.mjs +0 -511
  196. package/dist/featureoptions.d.ts +0 -264
  197. package/dist/featureoptions.js +0 -480
  198. package/dist/featureoptions.js.map +0 -1
  199. package/dist/mqttclient.d.ts +0 -178
  200. package/dist/mqttclient.js +0 -310
  201. package/dist/mqttclient.js.map +0 -1
  202. package/dist/ui/featureoptions.js +0 -480
  203. package/dist/ui/featureoptions.js.map +0 -1
  204. package/dist/ui/webUi-featureoptions.mjs +0 -3765
@@ -0,0 +1,94 @@
1
+ /**
2
+ * ISO BMFF box type code for the `ftyp` (file type) box, encoded as a 32-bit big-endian integer. Useful for branching on {@link Mp4Box.type} without re-encoding
3
+ * the 4-character ASCII tag on every comparison.
4
+ *
5
+ * @category FFmpeg
6
+ */
7
+ export declare const BOX_TYPE_FTYP = 1718909296;
8
+ /**
9
+ * ISO BMFF box type code for the `mdat` (media data) box. The mdat box carries the sample payload for the preceding `moof` in an fMP4 fragment and is the end-of-segment
10
+ * marker that {@link ffmpeg/mp4-assembler!Mp4SegmentAssembler | Mp4SegmentAssembler} watches for.
11
+ *
12
+ * @category FFmpeg
13
+ */
14
+ export declare const BOX_TYPE_MDAT = 1835295092;
15
+ /**
16
+ * ISO BMFF box type code for the `moof` (movie fragment) box. Marks the start of a new fMP4 media fragment; the first `moof` in a stream also marks the end of the
17
+ * initialization segment.
18
+ *
19
+ * @category FFmpeg
20
+ */
21
+ export declare const BOX_TYPE_MOOF = 1836019558;
22
+ /**
23
+ * ISO BMFF box type code for the `moov` (movie) box. Part of the initialization segment that precedes the first `moof` in an fMP4 stream.
24
+ *
25
+ * @category FFmpeg
26
+ */
27
+ export declare const BOX_TYPE_MOOV = 1836019574;
28
+ /**
29
+ * A complete parsed ISO BMFF box emitted by {@link Mp4BoxParser}.
30
+ *
31
+ * @property bytes - The complete box bytes, including the 8-byte header. The buffer is typically a zero-copy subarray view over the feed chunk; consumers that need
32
+ * to hold it past the iteration loop should copy with `Buffer.from()` if the upstream chunk lifetime is suspect.
33
+ * @property type - The box type encoded as a 32-bit big-endian integer. Compare against the `BOX_TYPE_*` constants exported from this module; numeric comparison
34
+ * avoids the per-box string allocation that an ASCII tag comparison would incur.
35
+ *
36
+ * @category FFmpeg
37
+ */
38
+ export interface Mp4Box {
39
+ bytes: Buffer;
40
+ type: number;
41
+ }
42
+ /**
43
+ * Pure stateful parser that converts a stream of ISO BMFF byte chunks into discrete {@link Mp4Box} records.
44
+ *
45
+ * Feed each chunk from the byte source through {@link Mp4BoxParser.consume} and iterate the returned values for every complete box now available. The parser carries
46
+ * only the bytes of an incomplete trailing box across calls; chunk boundaries in the middle of a box are handled transparently. A single chunk may produce zero, one, or
47
+ * many boxes depending on how the stream falls on chunk boundaries.
48
+ *
49
+ * The class is intentionally signal-free and event-free. It performs one job, synchronously, and leaves resource lifecycle and async consumption to the composing
50
+ * caller - typically {@link ffmpeg/mp4-assembler!Mp4SegmentAssembler | Mp4SegmentAssembler} for fMP4 streams driven by an FFmpeg process.
51
+ *
52
+ * @remarks **Trust boundary.** The parser does not bound the size field it reads from the wire. A source that claims a multi-gigabyte box size would cause the parser
53
+ * to accumulate incoming chunks into its internal pending buffer until the declared box completes. This is safe for trusted sources like FFmpeg stdout, where the
54
+ * size field reflects the actual payload. Callers feeding untrusted byte streams (e.g., user-uploaded media, network input from arbitrary peers) should impose their
55
+ * own bound - either by truncating chunks that would exceed a budget, or by wrapping the parser in a guard that rejects implausibly large declared sizes before
56
+ * feeding the chunk.
57
+ *
58
+ * @example
59
+ *
60
+ * ```ts
61
+ * import { BOX_TYPE_MDAT, Mp4BoxParser } from "homebridge-plugin-utils";
62
+ *
63
+ * const parser = new Mp4BoxParser();
64
+ *
65
+ * for(const box of parser.consume(chunk)) {
66
+ *
67
+ * if(box.type === BOX_TYPE_MDAT) {
68
+ *
69
+ * // We have just received a complete mdat box.
70
+ * }
71
+ * }
72
+ * ```
73
+ *
74
+ * @see Mp4SegmentAssembler
75
+ *
76
+ * @category FFmpeg
77
+ */
78
+ export declare class Mp4BoxParser {
79
+ #private;
80
+ /**
81
+ * Feed the parser a new byte chunk and yield every complete box now available.
82
+ *
83
+ * The iterable is single-pass: consume it with a `for...of` loop (or spread into an array) before the next call to `consume`. Emitted `bytes` are typically
84
+ * zero-copy subarray views over the input chunk; copy with `Buffer.from()` if you intend to hold a box past the upstream chunk's lifetime.
85
+ *
86
+ * Chunk boundaries in the middle of a box are handled internally: the incomplete trailing bytes are stashed and prepended to the next call's input.
87
+ *
88
+ * @param chunk - A contiguous slice of box-stream bytes from the source.
89
+ *
90
+ * @returns An iterable of every box contained in (or completed by) this chunk, in stream order.
91
+ */
92
+ consume(chunk: Buffer): Iterable<Mp4Box>;
93
+ }
94
+ //# sourceMappingURL=mp4-parser.d.ts.map
@@ -0,0 +1,130 @@
1
+ /* Copyright(C) 2017-2026, HJD (https://github.com/hjdhjd). All rights reserved.
2
+ *
3
+ * ffmpeg/mp4-parser.ts: Pure byte-to-record parser for ISO BMFF (fMP4) box streams.
4
+ */
5
+ /**
6
+ * Pure stateful byte-to-record parser for ISO BMFF (fMP4) box streams.
7
+ *
8
+ * This module ships the streaming counterpart to the static predicates in {@link ffmpeg/fmp4! | fmp4}. The predicates (`findBox`, `isKeyframe`, `hasAudioTrack`,
9
+ * `splitMoofMdat`) answer one-shot questions about a complete Buffer. {@link Mp4BoxParser} solves a different problem: incrementally consuming an unbounded byte stream
10
+ * (typically FFmpeg stdout producing fMP4 fragments) and emitting each complete box as it becomes available.
11
+ *
12
+ * The parser is intentionally signal-free, event-free, and allocation-light. It carries only the bytes of an incomplete trailing box across calls and hands out
13
+ * zero-copy `subarray` views whenever possible. Resource lifetime, async consumption, and cancellation are not this class's job - those belong to the composing
14
+ * caller (see {@link ffmpeg/mp4-assembler!Mp4SegmentAssembler | Mp4SegmentAssembler}).
15
+ *
16
+ * @module
17
+ */
18
+ import { BOX_HEADER_SIZE } from "./fmp4.js";
19
+ /**
20
+ * ISO BMFF box type code for the `ftyp` (file type) box, encoded as a 32-bit big-endian integer. Useful for branching on {@link Mp4Box.type} without re-encoding
21
+ * the 4-character ASCII tag on every comparison.
22
+ *
23
+ * @category FFmpeg
24
+ */
25
+ export const BOX_TYPE_FTYP = 0x66747970;
26
+ /**
27
+ * ISO BMFF box type code for the `mdat` (media data) box. The mdat box carries the sample payload for the preceding `moof` in an fMP4 fragment and is the end-of-segment
28
+ * marker that {@link ffmpeg/mp4-assembler!Mp4SegmentAssembler | Mp4SegmentAssembler} watches for.
29
+ *
30
+ * @category FFmpeg
31
+ */
32
+ export const BOX_TYPE_MDAT = 0x6D646174;
33
+ /**
34
+ * ISO BMFF box type code for the `moof` (movie fragment) box. Marks the start of a new fMP4 media fragment; the first `moof` in a stream also marks the end of the
35
+ * initialization segment.
36
+ *
37
+ * @category FFmpeg
38
+ */
39
+ export const BOX_TYPE_MOOF = 0x6D6F6F66;
40
+ /**
41
+ * ISO BMFF box type code for the `moov` (movie) box. Part of the initialization segment that precedes the first `moof` in an fMP4 stream.
42
+ *
43
+ * @category FFmpeg
44
+ */
45
+ export const BOX_TYPE_MOOV = 0x6D6F6F76;
46
+ // Reusable empty buffer sentinel for the parser's pending-bytes state. Avoids repeated zero-byte allocations at the start of every parse cycle where no residual bytes
47
+ // carried over from the previous chunk.
48
+ const EMPTY_BUFFER = Buffer.alloc(0);
49
+ /**
50
+ * Pure stateful parser that converts a stream of ISO BMFF byte chunks into discrete {@link Mp4Box} records.
51
+ *
52
+ * Feed each chunk from the byte source through {@link Mp4BoxParser.consume} and iterate the returned values for every complete box now available. The parser carries
53
+ * only the bytes of an incomplete trailing box across calls; chunk boundaries in the middle of a box are handled transparently. A single chunk may produce zero, one, or
54
+ * many boxes depending on how the stream falls on chunk boundaries.
55
+ *
56
+ * The class is intentionally signal-free and event-free. It performs one job, synchronously, and leaves resource lifecycle and async consumption to the composing
57
+ * caller - typically {@link ffmpeg/mp4-assembler!Mp4SegmentAssembler | Mp4SegmentAssembler} for fMP4 streams driven by an FFmpeg process.
58
+ *
59
+ * @remarks **Trust boundary.** The parser does not bound the size field it reads from the wire. A source that claims a multi-gigabyte box size would cause the parser
60
+ * to accumulate incoming chunks into its internal pending buffer until the declared box completes. This is safe for trusted sources like FFmpeg stdout, where the
61
+ * size field reflects the actual payload. Callers feeding untrusted byte streams (e.g., user-uploaded media, network input from arbitrary peers) should impose their
62
+ * own bound - either by truncating chunks that would exceed a budget, or by wrapping the parser in a guard that rejects implausibly large declared sizes before
63
+ * feeding the chunk.
64
+ *
65
+ * @example
66
+ *
67
+ * ```ts
68
+ * import { BOX_TYPE_MDAT, Mp4BoxParser } from "homebridge-plugin-utils";
69
+ *
70
+ * const parser = new Mp4BoxParser();
71
+ *
72
+ * for(const box of parser.consume(chunk)) {
73
+ *
74
+ * if(box.type === BOX_TYPE_MDAT) {
75
+ *
76
+ * // We have just received a complete mdat box.
77
+ * }
78
+ * }
79
+ * ```
80
+ *
81
+ * @see Mp4SegmentAssembler
82
+ *
83
+ * @category FFmpeg
84
+ */
85
+ export class Mp4BoxParser {
86
+ // Residual bytes from the previous call that did not complete a box. Prepended to the next chunk so a box split across two chunks is reassembled transparently. A
87
+ // zero-length sentinel is used when nothing is pending to avoid per-call allocation.
88
+ #pending = EMPTY_BUFFER;
89
+ /**
90
+ * Feed the parser a new byte chunk and yield every complete box now available.
91
+ *
92
+ * The iterable is single-pass: consume it with a `for...of` loop (or spread into an array) before the next call to `consume`. Emitted `bytes` are typically
93
+ * zero-copy subarray views over the input chunk; copy with `Buffer.from()` if you intend to hold a box past the upstream chunk's lifetime.
94
+ *
95
+ * Chunk boundaries in the middle of a box are handled internally: the incomplete trailing bytes are stashed and prepended to the next call's input.
96
+ *
97
+ * @param chunk - A contiguous slice of box-stream bytes from the source.
98
+ *
99
+ * @returns An iterable of every box contained in (or completed by) this chunk, in stream order.
100
+ */
101
+ *consume(chunk) {
102
+ // Prepend any pending partial box from the previous call. Buffer.concat is only paid when there is actually residual state; the common "chunk carries whole boxes
103
+ // and nothing is pending" path stays zero-allocation.
104
+ const buffer = (this.#pending.length > 0) ? Buffer.concat([this.#pending, chunk]) : chunk;
105
+ let offset = 0;
106
+ // Walk boxes by reading each header: 4 bytes size (big-endian) + 4 bytes type. The 32-bit type code is surfaced directly so consumers can compare against the
107
+ // exported BOX_TYPE_* constants without re-encoding a 4-character ASCII tag on every box.
108
+ while ((offset + BOX_HEADER_SIZE) <= buffer.length) {
109
+ const size = buffer.readUInt32BE(offset);
110
+ // Size must be at least the header size. Smaller values indicate corruption, a misaligned feed, or an unsupported extended-size box (size === 1 signals a 64-bit
111
+ // size field that we do not handle). Either way, the parser cannot make further progress - reset pending state so we do not busy-loop on the same bad byte on
112
+ // every subsequent chunk.
113
+ if (size < BOX_HEADER_SIZE) {
114
+ this.#pending = EMPTY_BUFFER;
115
+ return;
116
+ }
117
+ // Not enough bytes for a complete box yet. Stash the remainder - including the header - for the next call.
118
+ if ((offset + size) > buffer.length) {
119
+ break;
120
+ }
121
+ const type = buffer.readUInt32BE(offset + 4);
122
+ const bytes = buffer.subarray(offset, offset + size);
123
+ offset += size;
124
+ yield { bytes, type };
125
+ }
126
+ // Carry the trailing incomplete box (header + partial payload, or just the unconsumed tail) into the next call.
127
+ this.#pending = (offset === buffer.length) ? EMPTY_BUFFER : buffer.subarray(offset);
128
+ }
129
+ }
130
+ //# sourceMappingURL=mp4-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mp4-parser.js","sourceRoot":"","sources":["../../src/ffmpeg/mp4-parser.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAE5C;;;;;GAKG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,UAAU,CAAC;AAExC;;;;;GAKG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,UAAU,CAAC;AAExC;;;;;GAKG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,UAAU,CAAC;AAExC;;;;GAIG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,UAAU,CAAC;AAExC,uKAAuK;AACvK,wCAAwC;AACxC,MAAM,YAAY,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAkBrC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,MAAM,OAAO,YAAY;IAEvB,kKAAkK;IAClK,qFAAqF;IACrF,QAAQ,GAAW,YAAY,CAAC;IAEhC;;;;;;;;;;;OAWG;IACI,CAAC,OAAO,CAAC,KAAa;QAE3B,kKAAkK;QAClK,sDAAsD;QACtD,MAAM,MAAM,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAE,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;QAC5F,IAAI,MAAM,GAAG,CAAC,CAAC;QAEf,8JAA8J;QAC9J,0FAA0F;QAC1F,OAAM,CAAC,MAAM,GAAG,eAAe,CAAC,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YAElD,MAAM,IAAI,GAAG,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;YAEzC,iKAAiK;YACjK,8JAA8J;YAC9J,0BAA0B;YAC1B,IAAG,IAAI,GAAG,eAAe,EAAE,CAAC;gBAE1B,IAAI,CAAC,QAAQ,GAAG,YAAY,CAAC;gBAE7B,OAAO;YACT,CAAC;YAED,2GAA2G;YAC3G,IAAG,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC;gBAEnC,MAAM;YACR,CAAC;YAED,MAAM,IAAI,GAAG,MAAM,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YAC7C,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;YAErD,MAAM,IAAI,IAAI,CAAC;YAEf,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QACxB,CAAC;QAED,gHAAgH;QAChH,IAAI,CAAC,QAAQ,GAAG,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACtF,CAAC;CACF"}
@@ -17,9 +17,22 @@
17
17
  *
18
18
  * @module
19
19
  */
20
- import { AudioRecordingCodecType, H264Level, H264Profile, type Logging } from "homebridge";
21
- import type { FfmpegCodecs } from "./codecs.js";
22
- import type { HomebridgePluginLogging } from "../util.js";
20
+ import type { H264Level as H264LevelEnum, H264Profile as H264ProfileEnum } from "homebridge";
21
+ import { AudioRecordingCodecType } from "./hap-enums.ts";
22
+ import type { FfmpegCodecs } from "./codecs.ts";
23
+ import type { Logger } from "../util.ts";
24
+ declare const H264Level: {
25
+ readonly LEVEL3_1: H264LevelEnum.LEVEL3_1;
26
+ readonly LEVEL3_2: H264LevelEnum.LEVEL3_2;
27
+ readonly LEVEL4_0: H264LevelEnum.LEVEL4_0;
28
+ };
29
+ declare const H264Profile: {
30
+ readonly BASELINE: H264ProfileEnum.BASELINE;
31
+ readonly HIGH: H264ProfileEnum.HIGH;
32
+ readonly MAIN: H264ProfileEnum.MAIN;
33
+ };
34
+ type H264Level = H264LevelEnum;
35
+ type H264Profile = H264ProfileEnum;
23
36
  /**
24
37
  * Configuration options for `FfmpegOptions`, defining transcoding, decoding, logging, and hardware acceleration settings.
25
38
  *
@@ -66,15 +79,17 @@ export interface FfmpegOptionsConfig {
66
79
  debug?: boolean;
67
80
  hardwareDecoding: boolean;
68
81
  hardwareTranscoding: boolean;
69
- log: HomebridgePluginLogging | Logging;
82
+ log: Logger;
70
83
  name: () => string;
71
84
  }
72
85
  /**
73
- * Options used for configuring video encoding in FFmpeg operations.
86
+ * Options used for configuring audio encoding in FFmpeg operations.
74
87
  *
75
- * These options control output bitrate, framerate, resolution, H.264 profile and level, input framerate, and smart quality optimizations.
88
+ * The single field selects the AAC profile that drives encoder-specific arg emission in {@link FfmpegOptions.audioEncoder} - AAC-ELD (the HomeKit Secure Video event-
89
+ * recording default, lower bitrate, low-latency) versus AAC-LC (higher-quality livestream variant). The chosen profile maps to `aac_at` mode switches on macOS and to
90
+ * `libfdk_aac` flags elsewhere.
76
91
  *
77
- * @property codec - Optional. Audio codec to encode (`AudioRecordingCodecType.AAC_ELD` or `AudioRecordingCodecType.AAC_LC`). Defaults to
92
+ * @property codec - Optional. AAC profile to encode (`AudioRecordingCodecType.AAC_ELD` or `AudioRecordingCodecType.AAC_LC`). Defaults to
78
93
  * `AudioRecordingCodecType.AAC_ELD`.
79
94
  *
80
95
  * @example
@@ -104,14 +119,21 @@ export interface AudioEncoderOptions {
104
119
  *
105
120
  * @property bitrate - Target video bitrate, in kilobits per second.
106
121
  * @property fps - Target output frames per second.
107
- * @property hardwareDecoding - Optional. If `true`, encoder options will account for hardware decoding (primarily for Intel QSV scenarios). Defaults to `true`.
122
+ * @property hardwareDecoding - Optional. If `true`, the emitted encoder args assume the input stream has already been hardware-decoded (the GPU holds the frames).
123
+ * Used by the transfer-filter logic to decide between `hwupload`, `hwdownload`, or neither. Defaults to the resolved
124
+ * `FfmpegOptionsConfig.hardwareDecoding` value on the owning `FfmpegOptions` instance.
125
+ * @property hardwareTranscoding - Optional. If `true`, the emitted args select a hardware-accelerated encoder (`h264_videotoolbox` / `h264_qsv` / `h264_v4l2m2m`) and
126
+ * the matching filter pipeline. If `false`, the args fall back to the libx264 software encoder. Defaults to the resolved
127
+ * `FfmpegOptionsConfig.hardwareTranscoding` value on the owning `FfmpegOptions` instance.
108
128
  * @property height - Output video height, in pixels.
109
129
  * @property idrInterval - Interval (in seconds) between keyframes (IDR frames).
110
130
  * @property inputFps - Input (source) frames per second.
111
131
  * @property level - H.264 profile level for output.
112
132
  * @property profile - H.264 profile for output.
113
- * @property smartQuality - Optional and applicable only when not using hardware acceleration. If `true`, enables smart quality and variable bitrate optimizations.
114
- * Defaults to `true`.
133
+ * @property smartQuality - Optional. Enables variable-bitrate quality-constrained encoding on encoders that support it - libx264 (`-crf 20`), Apple Silicon
134
+ * VideoToolbox (`-q:v 90`), and Intel QSV (`-global_quality 20`). Intel VideoToolbox and v4l2m2m have no quality-constraint mode and
135
+ * always emit a fixed `-b:v` regardless. In all cases, `smartQuality` also adds `HOMEKIT_STREAMING_HEADROOM` to `-maxrate`, giving the
136
+ * encoder a narrow band of variation above the target bitrate. Defaults to `true`.
115
137
  * @property width - Output video width, in pixels.
116
138
  *
117
139
  * @example
@@ -155,6 +177,15 @@ export interface VideoEncoderOptions {
155
177
  smartQuality?: boolean;
156
178
  width: number;
157
179
  }
180
+ /**
181
+ * Every hardware-transcode context this module distinguishes, each with a source-pixel ceiling that can differ on a given host. Live streaming and HKSV recording
182
+ * both transcode, but a host may admit one context to its hardware encoder and not the other (today: Raspberry Pi runs live transcoding on h264_v4l2m2m but falls
183
+ * HKSV recording back to libx264). Consumed by `maxSourcePixels` and the `recordEncoder` software-fallback so both derive the same per-context hardware-capability
184
+ * answer from one predicate.
185
+ *
186
+ * @category FFmpeg
187
+ */
188
+ export type EncoderContext = "record" | "stream";
158
189
  /**
159
190
  * Provides Homebridge FFmpeg transcoding, decoding, and encoding options, selecting codecs, pixel formats, and hardware acceleration for the host system.
160
191
  *
@@ -194,27 +225,13 @@ export interface VideoEncoderOptions {
194
225
  * @category FFmpeg
195
226
  */
196
227
  export declare class FfmpegOptions {
228
+ #private;
197
229
  /**
198
- * FFmpeg codec and hardware capabilities for the current host.
199
- *
200
- */
201
- readonly codecSupport: FfmpegCodecs;
202
- /**
203
- * The configuration options used to initialize this instance.
230
+ * The configuration options used to initialize this instance. This is the single stored state on `FfmpegOptions`: every other public field on this class is either
231
+ * a getter that forwards to `this.config`, or a fixed constant independent of it (`audioDecoder`), so external callers have exactly one canonical path to each
232
+ * config-backed value and internal code never has to keep a parallel field in sync with `config` at construction time.
204
233
  */
205
234
  readonly config: FfmpegOptionsConfig;
206
- /**
207
- * Indicates if debug logging is enabled.
208
- */
209
- readonly debug: boolean;
210
- /**
211
- * Logging interface for output and errors.
212
- */
213
- readonly log: HomebridgePluginLogging | Logging;
214
- /**
215
- * Function returning the name for this options instance to be used for logging.
216
- */
217
- readonly name: () => string;
218
235
  /**
219
236
  * Creates an instance of Homebridge FFmpeg encoding and decoding options.
220
237
  *
@@ -228,50 +245,18 @@ export declare class FfmpegOptions {
228
245
  */
229
246
  constructor(options: FfmpegOptionsConfig);
230
247
  /**
231
- * Determines and configures hardware-accelerated video decoding and transcoding for the host system.
232
- *
233
- * This internal method checks for the availability of hardware codecs and accelerators based on the host platform and updates
234
- * FFmpeg options to use the best available hardware or falls back to software processing when necessary.
235
- * It logs warnings or errors if required codecs or hardware acceleration are unavailable.
236
- *
237
- * This method is called automatically by the `FfmpegOptions` constructor and is not intended to be called directly.
238
- *
239
- * @returns `true` if hardware-accelerated transcoding is enabled after configuration, otherwise `false`.
240
- *
241
- * @example
242
- *
243
- * ```ts
244
- * // This method is invoked by the FfmpegOptions constructor:
245
- * const ffmpegOpts = new FfmpegOptions(optionsConfig);
246
- *
247
- * // Hardware acceleration configuration occurs automatically.
248
- * // Developers typically do not need to call configureHwAccel() directly.
249
- * ```
250
- *
251
- * @see FfmpegCodecs
252
- * @see FfmpegOptions
248
+ * Indicates if debug logging is enabled. Normalizes `undefined` to `false` so callers always see a definite boolean regardless of whether the config object set
249
+ * the field explicitly.
253
250
  */
254
- private configureHwAccel;
251
+ get debug(): boolean;
255
252
  /**
256
- * Determines the required hardware transfer filters based on the decoding and encoding configuration.
257
- *
258
- * This method manages the transition between software and hardware processing contexts. When video data needs to move between the CPU and GPU for processing, we
259
- * provide the appropriate FFmpeg filters to handle that transfer efficiently.
260
- *
261
- * @param options - Video encoder options including hardware decoding and transcoding state.
262
- * @returns Array of filter strings for hardware upload or download operations.
253
+ * Logging interface for output and errors.
263
254
  */
264
- private getHardwareTransferFilters;
255
+ get log(): Logger;
265
256
  /**
266
- * Gets hardware device initialization options for encoders that need them.
267
- *
268
- * When we're using hardware encoding without hardware decoding, we need to initialize the hardware device context explicitly. This method provides the
269
- * platform-specific initialization arguments required by FFmpeg.
270
- *
271
- * @param options - Video encoder options.
272
- * @returns Array of FFmpeg arguments for hardware device initialization.
257
+ * Function returning the name for this options instance to be used for logging.
273
258
  */
274
- private getHardwareDeviceInit;
259
+ get name(): () => string;
275
260
  /**
276
261
  * Returns the audio encoder arguments to use when transcoding.
277
262
  *
@@ -294,7 +279,8 @@ export declare class FfmpegOptions {
294
279
  /**
295
280
  * Returns the video decoder arguments to use for decoding video.
296
281
  *
297
- * @param codec - Optional. Codec to decode (`"av1"`, `"h264"` (default), or `"hevc"`).
282
+ * @param codec - Optional. Codec to decode (`"av1"`, `"h264"` (default), or `"hevc"`; `"h265"` is accepted as an
283
+ * alias for `"hevc"`, and codec matching is case-insensitive).
298
284
  * @returns Array of FFmpeg command-line arguments for video decoding or an empty array if the codec isn't supported.
299
285
  *
300
286
  * @example
@@ -318,43 +304,6 @@ export declare class FfmpegOptions {
318
304
  * @returns The crop filter string for FFmpeg.
319
305
  */
320
306
  get cropFilter(): string;
321
- /**
322
- * Generate the appropriate scale filter for the current platform. This method returns platform-specific scale filters to leverage hardware acceleration capabilities
323
- * where available.
324
- */
325
- private getScaleFilter;
326
- /**
327
- * Generates the default set of FFmpeg video encoder arguments for software transcoding using libx264.
328
- *
329
- * This method builds command-line options for the FFmpeg libx264 encoder based on the provided encoder options, including bitrate, H.264 profile and level, pixel
330
- * format, frame rate, buffer size, and optional smart quality settings. It is used internally when hardware-accelerated transcoding is not enabled or supported.
331
- *
332
- * @param options - The encoder options to use for generating FFmpeg arguments.
333
- *
334
- * @returns An array of FFmpeg command-line arguments for software video encoding.
335
- *
336
- * @example
337
- *
338
- * ```ts
339
- * const encoderOptions: VideoEncoderOptions = {
340
- *
341
- * bitrate: 2000,
342
- * fps: 30,
343
- * height: 720,
344
- * idrInterval: 2,
345
- * inputFps: 30,
346
- * level: H264Level.LEVEL3_1,
347
- * profile: H264Profile.MAIN,
348
- * smartQuality: true,
349
- * width: 1280
350
- * };
351
- *
352
- * const args = ffmpegOpts['defaultVideoEncoderOptions'](encoderOptions);
353
- * ```
354
- *
355
- * @see VideoEncoderOptions
356
- */
357
- private defaultVideoEncoderOptions;
358
307
  /**
359
308
  * Returns the video encoder options to use for HomeKit Secure Video (HKSV) event recording.
360
309
  *
@@ -376,51 +325,15 @@ export declare class FfmpegOptions {
376
325
  */
377
326
  streamEncoder(options: VideoEncoderOptions): string[];
378
327
  /**
379
- * Returns the maximum pixel count supported by a specific hardware encoder on the host system, or `Infinity` if not limited.
380
- *
381
- * @returns Maximum supported pixel count.
382
- */
383
- get hostSystemMaxPixels(): number;
384
- /**
385
- * Converts a HomeKit H.264 level enum value to the corresponding FFmpeg string or numeric representation.
386
- *
387
- * This helper is used to translate between HomeKit's `H264Level` enum and the string or numeric format expected by FFmpeg's `-level:v` argument.
388
- *
389
- * @param level - The H.264 level to translate.
390
- * @param numeric - Optional. If `true`, returns the numeric representation (e.g., "31"). If `false` or omitted, returns the standard string format (e.g., "3.1").
391
- *
392
- * @returns The FFmpeg-compatible H.264 level string or numeric value.
393
- *
394
- * @example
395
- *
396
- * ```ts
397
- * ffmpegOpts['getH264Level'](H264Level.LEVEL3_1); // "3.1"
398
- *
399
- * ffmpegOpts['getH264Level'](H264Level.LEVEL4_0, true); // "40"
400
- * ```
401
- *
402
- * @see H264Level
403
- */
404
- private getH264Level;
405
- /**
406
- * Converts a HomeKit H.264 profile enum value to the corresponding FFmpeg string or numeric representation.
407
- *
408
- * This helper is used to translate between HomeKit's `H264Profile` enum and the string or numeric format expected by FFmpeg's `-profile:v` argument.
409
- *
410
- * @param profile - The H.264 profile to translate.
411
- * @param numeric - Optional. If `true`, returns the numeric representation (e.g., "100"). If `false` or omitted, returns the standard string format (e.g., "high").
328
+ * Returns the maximum source pixel count the host's hardware transcode pipeline can ingest for the given encoding context, or `Infinity` when unconstrained.
412
329
  *
413
- * @returns The FFmpeg-compatible H.264 profile string or numeric value.
414
- *
415
- * @example
416
- *
417
- * ```ts
418
- * ffmpegOpts['getH264Profile'](H264Profile.HIGH); // "high"
419
- *
420
- * ffmpegOpts['getH264Profile'](H264Profile.BASELINE, true); // "66"
421
- * ```
330
+ * Only Raspberry Pi's GPU imposes a real limit; every other host is unconstrained. A context is capped only when it actually runs on that hardware path - so today live
331
+ * streaming on a Pi returns the RPi ceiling while recording on a Pi returns `Infinity` (it software-encodes). Consumers apply this value blindly; the "why" lives here.
422
332
  *
423
- * @see H264Profile
333
+ * @param context - The encoding context whose ceiling is requested.
334
+ * @returns Maximum supported source pixel count for `context`.
424
335
  */
425
- private getH264Profile;
336
+ maxSourcePixels(context: EncoderContext): number;
426
337
  }
338
+ export {};
339
+ //# sourceMappingURL=options.d.ts.map