@mediaway/ffi 0.1.8 → 0.2.2
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/container-replay.d.ts +125 -0
- package/dist/container-replay.js +102 -0
- package/dist/index.d.ts +57 -6
- package/dist/index.js +31 -11
- package/dist/pipeline-v7.d.ts +48 -0
- package/dist/pipeline-v7.js +54 -0
- package/dist/rational.d.ts +8 -0
- package/dist/rational.js +12 -0
- package/native/darwin-arm64/libmediaway_ffi.dylib +0 -0
- package/native/darwin-x64/libmediaway_ffi.dylib +0 -0
- package/native/linux-x64/libmediaway_ffi.so +0 -0
- package/native/win32-x64/mediaway_ffi.dll +0 -0
- package/package.json +1 -1
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Replay ring + MP4 payload placements (adr/container/0009-replay-ring-c-abi.md).
|
|
3
|
+
*
|
|
4
|
+
* Split out of index.ts, which sits under the workspace's 1000-line source cap. This module
|
|
5
|
+
* imports only leaf modules (koffi, loader), never index.ts, so there is no import cycle:
|
|
6
|
+
* index.ts calls {@link createReplayBindings} once, after it has defined `MwRational` and
|
|
7
|
+
* `MwPacketView`, whose koffi names the signatures below refer to.
|
|
8
|
+
*/
|
|
9
|
+
import { type TypeObject } from "koffi";
|
|
10
|
+
/** `mediaway_replay_payload_kind_t`. */
|
|
11
|
+
export declare const REPLAY_PAYLOAD_BYTES = 0;
|
|
12
|
+
export declare const REPLAY_PAYLOAD_STORED = 1;
|
|
13
|
+
/** `mediaway_replay_ring_config_t`. */
|
|
14
|
+
export interface RawReplayRingConfig {
|
|
15
|
+
anchor_stream_id: number;
|
|
16
|
+
anchor_time_base: {
|
|
17
|
+
num: bigint | number;
|
|
18
|
+
den: number;
|
|
19
|
+
};
|
|
20
|
+
window_ms: bigint | number;
|
|
21
|
+
max_bytes: bigint | number;
|
|
22
|
+
payload_kind: number;
|
|
23
|
+
}
|
|
24
|
+
/** `mediaway_packet_meta_t`. */
|
|
25
|
+
export interface RawPacketMeta {
|
|
26
|
+
stream_id: number;
|
|
27
|
+
pts: bigint | number;
|
|
28
|
+
dts: bigint | number;
|
|
29
|
+
duration: bigint | number;
|
|
30
|
+
is_keyframe: boolean;
|
|
31
|
+
is_discard: boolean;
|
|
32
|
+
}
|
|
33
|
+
/** `mediaway_stored_payload_t`. */
|
|
34
|
+
export interface RawStoredPayload {
|
|
35
|
+
file: number;
|
|
36
|
+
offset: bigint | number;
|
|
37
|
+
len: number;
|
|
38
|
+
}
|
|
39
|
+
/** `mediaway_replay_clip_entry_t`. `payload` is BORROWED from the clip. */
|
|
40
|
+
export interface RawReplayClipEntry {
|
|
41
|
+
stream_id: number;
|
|
42
|
+
pts: bigint;
|
|
43
|
+
dts: bigint;
|
|
44
|
+
duration: bigint;
|
|
45
|
+
is_keyframe: boolean;
|
|
46
|
+
is_discard: boolean;
|
|
47
|
+
payload_kind: number;
|
|
48
|
+
payload: unknown;
|
|
49
|
+
payload_len: number;
|
|
50
|
+
stored_file: number;
|
|
51
|
+
stored_offset: bigint;
|
|
52
|
+
stored_len: number;
|
|
53
|
+
}
|
|
54
|
+
/** `mediaway_placement_t`. */
|
|
55
|
+
export interface RawPlacement {
|
|
56
|
+
track_id: number;
|
|
57
|
+
dts: bigint;
|
|
58
|
+
offset: bigint;
|
|
59
|
+
len: number;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Declare the replay structs and bind the functions.
|
|
63
|
+
*
|
|
64
|
+
* `rational` is index.ts's `MwRational` (the struct is registered there once; koffi rejects a
|
|
65
|
+
* second definition under the same name).
|
|
66
|
+
*/
|
|
67
|
+
export declare function createReplayBindings(rational: TypeObject): {
|
|
68
|
+
structs: {
|
|
69
|
+
MwReplayRingConfig: TypeObject;
|
|
70
|
+
MwPacketMeta: TypeObject;
|
|
71
|
+
MwStoredPayload: TypeObject;
|
|
72
|
+
MwReplayClipEntry: TypeObject;
|
|
73
|
+
MwPlacement: TypeObject;
|
|
74
|
+
};
|
|
75
|
+
ringCreate: import("koffi").Callable;
|
|
76
|
+
ringAddStream: import("koffi").Callable;
|
|
77
|
+
ringPush: import("koffi").Callable;
|
|
78
|
+
ringPushStored: import("koffi").Callable;
|
|
79
|
+
ringSpanMs: import("koffi").Callable;
|
|
80
|
+
ringClipLast: import("koffi").Callable;
|
|
81
|
+
ringClose: import("koffi").Callable;
|
|
82
|
+
clipPacketCount: import("koffi").Callable;
|
|
83
|
+
clipDurationMs: import("koffi").Callable;
|
|
84
|
+
clipPacketAt: import("koffi").Callable;
|
|
85
|
+
clipFree: import("koffi").Callable;
|
|
86
|
+
muxerCreateWithPlacements: import("koffi").Callable;
|
|
87
|
+
muxerPollPlacements: import("koffi").Callable;
|
|
88
|
+
placementsFree: import("koffi").Callable;
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* `sizeof` and member offsets of the replay structs as koffi lays them out, for the test that
|
|
92
|
+
* pins them against a gcc probe of the real header.
|
|
93
|
+
*/
|
|
94
|
+
export declare function replayLayout(structs: ReturnType<typeof createReplayBindings>["structs"]): {
|
|
95
|
+
replayRingConfig: {
|
|
96
|
+
size: number;
|
|
97
|
+
offsets: {
|
|
98
|
+
[k: string]: number;
|
|
99
|
+
};
|
|
100
|
+
};
|
|
101
|
+
packetMeta: {
|
|
102
|
+
size: number;
|
|
103
|
+
offsets: {
|
|
104
|
+
[k: string]: number;
|
|
105
|
+
};
|
|
106
|
+
};
|
|
107
|
+
storedPayload: {
|
|
108
|
+
size: number;
|
|
109
|
+
offsets: {
|
|
110
|
+
[k: string]: number;
|
|
111
|
+
};
|
|
112
|
+
};
|
|
113
|
+
replayClipEntry: {
|
|
114
|
+
size: number;
|
|
115
|
+
offsets: {
|
|
116
|
+
[k: string]: number;
|
|
117
|
+
};
|
|
118
|
+
};
|
|
119
|
+
placement: {
|
|
120
|
+
size: number;
|
|
121
|
+
offsets: {
|
|
122
|
+
[k: string]: number;
|
|
123
|
+
};
|
|
124
|
+
};
|
|
125
|
+
};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Replay ring + MP4 payload placements (adr/container/0009-replay-ring-c-abi.md).
|
|
3
|
+
*
|
|
4
|
+
* Split out of index.ts, which sits under the workspace's 1000-line source cap. This module
|
|
5
|
+
* imports only leaf modules (koffi, loader), never index.ts, so there is no import cycle:
|
|
6
|
+
* index.ts calls {@link createReplayBindings} once, after it has defined `MwRational` and
|
|
7
|
+
* `MwPacketView`, whose koffi names the signatures below refer to.
|
|
8
|
+
*/
|
|
9
|
+
import koffi, {} from "koffi";
|
|
10
|
+
import { containerLib } from "./loader.js";
|
|
11
|
+
/** `mediaway_replay_payload_kind_t`. */
|
|
12
|
+
export const REPLAY_PAYLOAD_BYTES = 0;
|
|
13
|
+
export const REPLAY_PAYLOAD_STORED = 1;
|
|
14
|
+
/**
|
|
15
|
+
* Declare the replay structs and bind the functions.
|
|
16
|
+
*
|
|
17
|
+
* `rational` is index.ts's `MwRational` (the struct is registered there once; koffi rejects a
|
|
18
|
+
* second definition under the same name).
|
|
19
|
+
*/
|
|
20
|
+
export function createReplayBindings(rational) {
|
|
21
|
+
const MwReplayRingConfig = koffi.struct("MwReplayRingConfig", {
|
|
22
|
+
anchor_stream_id: "uint32",
|
|
23
|
+
anchor_time_base: rational,
|
|
24
|
+
window_ms: "uint64",
|
|
25
|
+
max_bytes: "uint64",
|
|
26
|
+
payload_kind: "int32",
|
|
27
|
+
});
|
|
28
|
+
const MwPacketMeta = koffi.struct("MwPacketMeta", {
|
|
29
|
+
stream_id: "uint32",
|
|
30
|
+
pts: "int64",
|
|
31
|
+
dts: "int64",
|
|
32
|
+
duration: "uint64",
|
|
33
|
+
is_keyframe: "bool",
|
|
34
|
+
is_discard: "bool",
|
|
35
|
+
});
|
|
36
|
+
const MwStoredPayload = koffi.struct("MwStoredPayload", {
|
|
37
|
+
file: "uint32",
|
|
38
|
+
offset: "uint64",
|
|
39
|
+
len: "uint32",
|
|
40
|
+
});
|
|
41
|
+
const MwReplayClipEntry = koffi.struct("MwReplayClipEntry", {
|
|
42
|
+
stream_id: "uint32",
|
|
43
|
+
pts: "int64",
|
|
44
|
+
dts: "int64",
|
|
45
|
+
duration: "uint64",
|
|
46
|
+
is_keyframe: "bool",
|
|
47
|
+
is_discard: "bool",
|
|
48
|
+
payload_kind: "int32",
|
|
49
|
+
payload: "uint8_t *",
|
|
50
|
+
payload_len: "size_t",
|
|
51
|
+
stored_file: "uint32",
|
|
52
|
+
stored_offset: "uint64",
|
|
53
|
+
stored_len: "uint32",
|
|
54
|
+
});
|
|
55
|
+
const MwPlacement = koffi.struct("MwPlacement", {
|
|
56
|
+
track_id: "uint32",
|
|
57
|
+
dts: "int64",
|
|
58
|
+
offset: "uint64",
|
|
59
|
+
len: "uint32",
|
|
60
|
+
});
|
|
61
|
+
return {
|
|
62
|
+
structs: { MwReplayRingConfig, MwPacketMeta, MwStoredPayload, MwReplayClipEntry, MwPlacement },
|
|
63
|
+
ringCreate: containerLib.func("int mediaway_replay_ring_create(MwReplayRingConfig *config, _Out_ void **out_ring)"),
|
|
64
|
+
ringAddStream: containerLib.func("int mediaway_replay_ring_add_stream(void *ring, uint32_t stream_id, MwRational time_base)"),
|
|
65
|
+
ringPush: containerLib.func("int mediaway_replay_ring_push(void *ring, MwPacketView *packet)"),
|
|
66
|
+
ringPushStored: containerLib.func("int mediaway_replay_ring_push_stored(void *ring, MwPacketMeta *meta, MwStoredPayload *stored)"),
|
|
67
|
+
ringSpanMs: containerLib.func("int mediaway_replay_ring_span_ms(void *ring, _Out_ uint64_t *out_span_ms)"),
|
|
68
|
+
ringClipLast: containerLib.func("int mediaway_replay_ring_clip_last(void *ring, uint64_t span_ms, _Out_ void **out_clip, _Out_ bool *out_has)"),
|
|
69
|
+
ringClose: containerLib.func("void mediaway_replay_ring_close(void *ring)"),
|
|
70
|
+
clipPacketCount: containerLib.func("size_t mediaway_replay_clip_packet_count(void *clip)"),
|
|
71
|
+
clipDurationMs: containerLib.func("int mediaway_replay_clip_duration_ms(void *clip, _Out_ uint64_t *out_ms)"),
|
|
72
|
+
clipPacketAt: containerLib.func("int mediaway_replay_clip_packet_at(void *clip, size_t index, _Out_ MwReplayClipEntry *out_entry)"),
|
|
73
|
+
clipFree: containerLib.func("void mediaway_replay_clip_free(void *clip)"),
|
|
74
|
+
muxerCreateWithPlacements: containerLib.func("void *mediaway_muxer_create_with_placements()"),
|
|
75
|
+
muxerPollPlacements: containerLib.func("int mediaway_muxer_poll_placements(void *muxer, _Out_ MwPlacement **out_rows, _Out_ size_t *out_count)"),
|
|
76
|
+
placementsFree: containerLib.func("void mediaway_placements_free(MwPlacement *rows, size_t count)"),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* `sizeof` and member offsets of the replay structs as koffi lays them out, for the test that
|
|
81
|
+
* pins them against a gcc probe of the real header.
|
|
82
|
+
*/
|
|
83
|
+
export function replayLayout(structs) {
|
|
84
|
+
const describe = (type, members) => ({
|
|
85
|
+
size: koffi.sizeof(type),
|
|
86
|
+
offsets: Object.fromEntries(members.map((m) => [m, koffi.offsetof(type, m)])),
|
|
87
|
+
});
|
|
88
|
+
return {
|
|
89
|
+
replayRingConfig: describe(structs.MwReplayRingConfig, [
|
|
90
|
+
"anchor_stream_id", "anchor_time_base", "window_ms", "max_bytes", "payload_kind",
|
|
91
|
+
]),
|
|
92
|
+
packetMeta: describe(structs.MwPacketMeta, [
|
|
93
|
+
"stream_id", "pts", "dts", "duration", "is_keyframe", "is_discard",
|
|
94
|
+
]),
|
|
95
|
+
storedPayload: describe(structs.MwStoredPayload, ["file", "offset", "len"]),
|
|
96
|
+
replayClipEntry: describe(structs.MwReplayClipEntry, [
|
|
97
|
+
"stream_id", "pts", "dts", "duration", "is_keyframe", "is_discard", "payload_kind",
|
|
98
|
+
"payload", "payload_len", "stored_file", "stored_offset", "stored_len",
|
|
99
|
+
]),
|
|
100
|
+
placement: describe(structs.MwPlacement, ["track_id", "dts", "offset", "len"]),
|
|
101
|
+
};
|
|
102
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -15,8 +15,11 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import { type TypeObject } from "koffi";
|
|
17
17
|
import { findLibrary, containerLib, pipelineLib, deviceLib } from "./loader.js";
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
import { MwRational } from "./rational.js";
|
|
19
|
+
import { replayLayout } from "./container-replay.js";
|
|
20
|
+
export * from "./container-replay.js";
|
|
21
|
+
export { findLibrary, containerLib, pipelineLib, deviceLib, MwRational };
|
|
22
|
+
export * from "./pipeline-v7.js";
|
|
20
23
|
export declare const MwVideoTrackInfo: TypeObject;
|
|
21
24
|
export declare const MwAudioTrackInfo: TypeObject;
|
|
22
25
|
export declare const MwPacketView: TypeObject;
|
|
@@ -45,7 +48,6 @@ export declare const MwAudioStreamInfo: TypeObject;
|
|
|
45
48
|
export declare const MwDecodePacketView: TypeObject;
|
|
46
49
|
export declare const MwAutoVideoDecodeConfig: TypeObject;
|
|
47
50
|
export declare const MwDecodedVideoFrame: TypeObject;
|
|
48
|
-
export declare const MwAudioDecodeConfig: TypeObject;
|
|
49
51
|
export declare const MwDecodedAudioFrame: TypeObject;
|
|
50
52
|
export declare const container: {
|
|
51
53
|
abiVersion: import("koffi").Callable;
|
|
@@ -134,6 +136,13 @@ export declare const container: {
|
|
|
134
136
|
wavParse: import("koffi").Callable;
|
|
135
137
|
};
|
|
136
138
|
export declare const pipeline: {
|
|
139
|
+
sessionWriteFrameFromCameraCapture: import("koffi").Callable;
|
|
140
|
+
sessionWriteFrameFromDesktopCapture: import("koffi").Callable;
|
|
141
|
+
audioDecodeConfigAac: import("koffi").Callable;
|
|
142
|
+
sessionPollBytes: import("koffi").Callable;
|
|
143
|
+
encoderSupportAt: import("koffi").Callable;
|
|
144
|
+
encoderSupportFree: import("koffi").Callable;
|
|
145
|
+
decoderSupport: import("koffi").Callable;
|
|
137
146
|
abiVersion: import("koffi").Callable;
|
|
138
147
|
encConfigNew: import("koffi").Callable;
|
|
139
148
|
encConfigH264: import("koffi").Callable;
|
|
@@ -167,8 +176,6 @@ export declare const pipeline: {
|
|
|
167
176
|
audioDecodeSessionFlush: import("koffi").Callable;
|
|
168
177
|
audioDecodeSessionClose: import("koffi").Callable;
|
|
169
178
|
decodedAudioFrameFree: import("koffi").Callable;
|
|
170
|
-
sessionWriteFrameFromCameraCapture: import("koffi").Callable;
|
|
171
|
-
sessionWriteFrameFromDesktopCapture: import("koffi").Callable;
|
|
172
179
|
};
|
|
173
180
|
export declare const device: {
|
|
174
181
|
abiVersion: import("koffi").Callable;
|
|
@@ -181,6 +188,8 @@ export declare const device: {
|
|
|
181
188
|
cameraClose: import("koffi").Callable;
|
|
182
189
|
cameraFrameFree: import("koffi").Callable;
|
|
183
190
|
desktopConfigScreen: import("koffi").Callable;
|
|
191
|
+
desktopConfigWindow: import("koffi").Callable;
|
|
192
|
+
desktopBorderHidden: import("koffi").Callable;
|
|
184
193
|
desktopOpen: import("koffi").Callable;
|
|
185
194
|
desktopGeometry: import("koffi").Callable;
|
|
186
195
|
desktopPollFrame: import("koffi").Callable;
|
|
@@ -199,6 +208,31 @@ export declare const device: {
|
|
|
199
208
|
gpuDeviceHandle: import("koffi").Callable;
|
|
200
209
|
gpuDeviceClose: import("koffi").Callable;
|
|
201
210
|
};
|
|
211
|
+
export declare const replay: {
|
|
212
|
+
structs: {
|
|
213
|
+
MwReplayRingConfig: TypeObject;
|
|
214
|
+
MwPacketMeta: TypeObject;
|
|
215
|
+
MwStoredPayload: TypeObject;
|
|
216
|
+
MwReplayClipEntry: TypeObject;
|
|
217
|
+
MwPlacement: TypeObject;
|
|
218
|
+
};
|
|
219
|
+
ringCreate: import("koffi").Callable;
|
|
220
|
+
ringAddStream: import("koffi").Callable;
|
|
221
|
+
ringPush: import("koffi").Callable;
|
|
222
|
+
ringPushStored: import("koffi").Callable;
|
|
223
|
+
ringSpanMs: import("koffi").Callable;
|
|
224
|
+
ringClipLast: import("koffi").Callable;
|
|
225
|
+
ringClose: import("koffi").Callable;
|
|
226
|
+
clipPacketCount: import("koffi").Callable;
|
|
227
|
+
clipDurationMs: import("koffi").Callable;
|
|
228
|
+
clipPacketAt: import("koffi").Callable;
|
|
229
|
+
clipFree: import("koffi").Callable;
|
|
230
|
+
muxerCreateWithPlacements: import("koffi").Callable;
|
|
231
|
+
muxerPollPlacements: import("koffi").Callable;
|
|
232
|
+
placementsFree: import("koffi").Callable;
|
|
233
|
+
};
|
|
234
|
+
/** koffi's sizeof/offsetof for the replay structs — pinned by test/replay-ring.test.ts. */
|
|
235
|
+
export declare const replayStructLayout: () => ReturnType<typeof replayLayout>;
|
|
202
236
|
/** Copy `len` bytes out of a koffi pointer/opaque handle. */
|
|
203
237
|
export declare function copyBytes(ptr: unknown, len: number): Buffer;
|
|
204
238
|
/**
|
|
@@ -335,6 +369,21 @@ export interface RawPipelineFrame {
|
|
|
335
369
|
}
|
|
336
370
|
/** `mediaway_gpu_device_handle_t` (Screen capture / GPU-input encode input,
|
|
337
371
|
* mediaway_gpu_device_handle()'s output). */
|
|
372
|
+
export interface RawDesktopConfig {
|
|
373
|
+
source_kind: number;
|
|
374
|
+
source_index: number;
|
|
375
|
+
time_base: RawRational;
|
|
376
|
+
gpu_device: RawGpuDeviceHandle;
|
|
377
|
+
window_handle: bigint | number;
|
|
378
|
+
cursor: number;
|
|
379
|
+
border: number;
|
|
380
|
+
dimensions: number;
|
|
381
|
+
region_x: number;
|
|
382
|
+
region_y: number;
|
|
383
|
+
region_width: number;
|
|
384
|
+
region_height: number;
|
|
385
|
+
region_enabled: boolean;
|
|
386
|
+
}
|
|
338
387
|
export interface RawGpuDeviceHandle {
|
|
339
388
|
kind: number;
|
|
340
389
|
native: number | bigint;
|
|
@@ -415,12 +464,14 @@ export interface RawDecodedVideoFrame {
|
|
|
415
464
|
data: unknown;
|
|
416
465
|
data_len: number;
|
|
417
466
|
}
|
|
418
|
-
/** `mediaway_audio_decode_config_t` (Opus
|
|
467
|
+
/** `mediaway_audio_decode_config_t` (Opus or AAC; AAC needs `extra_data`, the ASC). */
|
|
419
468
|
export interface RawAudioDecodeConfig {
|
|
420
469
|
codec: number;
|
|
421
470
|
sample_rate: number;
|
|
422
471
|
channels: number;
|
|
423
472
|
time_base: RawRational;
|
|
473
|
+
extra_data: unknown;
|
|
474
|
+
extra_data_len: number;
|
|
424
475
|
}
|
|
425
476
|
/** `mediaway_decoded_audio_frame_t` (audio decode session output; always F32). */
|
|
426
477
|
export interface RawDecodedAudioFrame {
|
package/dist/index.js
CHANGED
|
@@ -15,12 +15,16 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import koffi, {} from "koffi";
|
|
17
17
|
import { findLibrary, containerLib, pipelineLib, deviceLib } from "./loader.js";
|
|
18
|
-
|
|
18
|
+
import { MwRational } from "./rational.js";
|
|
19
|
+
// Pipeline ABI v7 (streaming bytes, AAC decode, capability probes) lives in its own module for
|
|
20
|
+
// the 1000-line source cap. Importing it first also registers `MwAudioDecodeConfig`, which the
|
|
21
|
+
// `pipeline` object's prototype strings below name.
|
|
22
|
+
import { pipelineV7 } from "./pipeline-v7.js";
|
|
23
|
+
import { createReplayBindings, replayLayout } from "./container-replay.js";
|
|
24
|
+
export * from "./container-replay.js";
|
|
25
|
+
export { findLibrary, containerLib, pipelineLib, deviceLib, MwRational };
|
|
26
|
+
export * from "./pipeline-v7.js";
|
|
19
27
|
// ── Structs (layouts mirror the headers exactly) ───────────────────────────────
|
|
20
|
-
export const MwRational = koffi.struct("MwRational", {
|
|
21
|
-
num: "uint64",
|
|
22
|
-
den: "uint32",
|
|
23
|
-
});
|
|
24
28
|
export const MwVideoTrackInfo = koffi.struct("MwVideoTrackInfo", {
|
|
25
29
|
id: "uint32",
|
|
26
30
|
codec: "int32",
|
|
@@ -132,11 +136,22 @@ export const MwCameraFrame = koffi.struct("MwCameraFrame", {
|
|
|
132
136
|
data: "uint8_t *",
|
|
133
137
|
data_len: "size_t",
|
|
134
138
|
});
|
|
139
|
+
// Field order and widths mirror `mediaway_desktop_capture_config_t` in device.h
|
|
140
|
+
// exactly (ADR-0005). Every field after `gpu_device` is zero-means-previous-behaviour.
|
|
135
141
|
export const MwDesktopConfig = koffi.struct("MwDesktopConfig", {
|
|
136
142
|
source_kind: "int32",
|
|
137
143
|
source_index: "uint32",
|
|
138
144
|
time_base: MwRational,
|
|
139
145
|
gpu_device: MwGpuDeviceHandle,
|
|
146
|
+
window_handle: "uint64",
|
|
147
|
+
cursor: "int32", // 0 = excluded, 1 = included
|
|
148
|
+
border: "int32", // 0 = shown, 1 = hidden (Window only)
|
|
149
|
+
dimensions: "int32", // 0 = native, 1 = even-cropped (Window only)
|
|
150
|
+
region_x: "uint32",
|
|
151
|
+
region_y: "uint32",
|
|
152
|
+
region_width: "uint32",
|
|
153
|
+
region_height: "uint32",
|
|
154
|
+
region_enabled: "bool",
|
|
140
155
|
});
|
|
141
156
|
export const MwDesktopFrame = koffi.struct("MwDesktopFrame", {
|
|
142
157
|
pts: "int64",
|
|
@@ -245,12 +260,7 @@ export const MwDecodedVideoFrame = koffi.struct("MwDecodedVideoFrame", {
|
|
|
245
260
|
data: "uint8_t *", // owned
|
|
246
261
|
data_len: "size_t",
|
|
247
262
|
});
|
|
248
|
-
|
|
249
|
-
codec: "int32", // Opus only today
|
|
250
|
-
sample_rate: "uint32",
|
|
251
|
-
channels: "uint16",
|
|
252
|
-
time_base: MwRational,
|
|
253
|
-
});
|
|
263
|
+
// `MwAudioDecodeConfig` (Opus + AAC) is defined in pipeline-v7.ts.
|
|
254
264
|
export const MwDecodedAudioFrame = koffi.struct("MwDecodedAudioFrame", {
|
|
255
265
|
pts: "int64",
|
|
256
266
|
duration: "uint64",
|
|
@@ -389,6 +399,8 @@ export const pipeline = {
|
|
|
389
399
|
audioDecodeSessionFlush: pipelineLib.func("int mediaway_audio_decode_session_flush(void *session)"),
|
|
390
400
|
audioDecodeSessionClose: pipelineLib.func("void mediaway_audio_decode_session_close(void *session)"),
|
|
391
401
|
decodedAudioFrameFree: pipelineLib.func("void mediaway_decoded_audio_frame_free(MwDecodedAudioFrame *frame)"),
|
|
402
|
+
// ── ABI v7: streaming bytes, AAC decode config, capability probes (pipeline-v7.ts) ──
|
|
403
|
+
...pipelineV7,
|
|
392
404
|
// ── Capture-to-encode bridge (adr/pipeline/0005-capture-encode-bridge-c-abi.md) ──
|
|
393
405
|
// Pushes one polled frame from a device.h capture handle straight into a
|
|
394
406
|
// session — no intermediate MwCameraFrame/MwDesktopFrame, no extra copy.
|
|
@@ -407,6 +419,8 @@ export const device = {
|
|
|
407
419
|
cameraClose: deviceLib.func("int mediaway_camera_capture_close(void *capture)"),
|
|
408
420
|
cameraFrameFree: deviceLib.func("void mediaway_camera_frame_free(MwCameraFrame *frame)"),
|
|
409
421
|
desktopConfigScreen: deviceLib.func("MwDesktopConfig mediaway_desktop_capture_config_screen(uint32_t output_index, MwRational time_base, MwGpuDeviceHandle gpu_device)"),
|
|
422
|
+
desktopConfigWindow: deviceLib.func("MwDesktopConfig mediaway_desktop_capture_config_window(uint64_t hwnd, MwRational time_base, MwGpuDeviceHandle gpu_device)"),
|
|
423
|
+
desktopBorderHidden: deviceLib.func("int mediaway_desktop_capture_border_hidden(void *capture, _Out_ bool *out_hidden)"),
|
|
410
424
|
desktopOpen: deviceLib.func("int mediaway_desktop_capture_open(MwDesktopConfig *config, _Out_ void **out_capture)"),
|
|
411
425
|
desktopGeometry: deviceLib.func("int mediaway_desktop_capture_geometry(void *capture, _Out_ uint32_t *out_width, _Out_ uint32_t *out_height)"),
|
|
412
426
|
desktopPollFrame: deviceLib.func("int mediaway_desktop_capture_poll_frame(void *capture, _Out_ MwDesktopFrame *out_frame, _Out_ bool *out_has)"),
|
|
@@ -426,6 +440,12 @@ export const device = {
|
|
|
426
440
|
gpuDeviceHandle: deviceLib.func("int mediaway_gpu_device_handle(void *device, _Out_ MwGpuDeviceHandle *out_handle)"),
|
|
427
441
|
gpuDeviceClose: deviceLib.func("void mediaway_gpu_device_close(void *device)"),
|
|
428
442
|
};
|
|
443
|
+
// ── Replay ring + payload placements (adr/container/0009) ────────────────────
|
|
444
|
+
// Declared in container-replay.ts (this file is near the 1000-line cap). Called here, after
|
|
445
|
+
// `MwRational` and `MwPacketView` exist, because the signatures name them.
|
|
446
|
+
export const replay = createReplayBindings(MwRational);
|
|
447
|
+
/** koffi's sizeof/offsetof for the replay structs — pinned by test/replay-ring.test.ts. */
|
|
448
|
+
export const replayStructLayout = () => replayLayout(replay.structs);
|
|
429
449
|
// ── Copy helpers ───────────────────────────────────────────────────────────────
|
|
430
450
|
/** Copy `len` bytes out of a koffi pointer/opaque handle. */
|
|
431
451
|
export function copyBytes(ptr, len) {
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pipeline ABI v7 additions — `crates/mediaway-ffi/adr/pipeline/0007-stream-bytes-aac-decode-
|
|
3
|
+
* support-probe.md`: streaming fMP4 bytes, AAC decode, and the capability probes.
|
|
4
|
+
*
|
|
5
|
+
* Split out of index.ts for the workspace's 1000-line source cap. It imports only leaf modules
|
|
6
|
+
* (`rational.ts`, `loader.ts`), never `index.ts`, so `index.ts` can re-export it without a cycle.
|
|
7
|
+
*
|
|
8
|
+
* Ownership (from `pipeline.h`):
|
|
9
|
+
* - `mediaway_encode_session_poll_bytes` returns an OWNED buffer (release it with
|
|
10
|
+
* `pipeline.bufferFree`); nothing ready is `NULL` / `0` and needs no free.
|
|
11
|
+
* - `mediaway_encoder_support_at` returns an OWNED array; release it with
|
|
12
|
+
* `mediaway_encoder_support_free`, passing back the same pointer and count.
|
|
13
|
+
* - `mediaway_audio_decode_config_t.extra_data` is BORROWED, valid for `open()` only.
|
|
14
|
+
*/
|
|
15
|
+
/** `mediaway_audio_decode_config_t` — Opus passes `extra_data = NULL`, AAC the raw ASC. */
|
|
16
|
+
export declare const MwAudioDecodeConfig: import("koffi").TypeObject;
|
|
17
|
+
/** `mediaway_encoder_capability_t` — one backend row of `mediaway_encoder_support_at`. */
|
|
18
|
+
export declare const MwEncoderCapability: import("koffi").TypeObject;
|
|
19
|
+
/** `mediaway_encoder_capability_t` as decoded by koffi. */
|
|
20
|
+
export interface RawEncoderCapability {
|
|
21
|
+
backend: number;
|
|
22
|
+
state: number;
|
|
23
|
+
path_class: number;
|
|
24
|
+
}
|
|
25
|
+
/** Codec numbers the probes and AAC decode accept (`mediaway_pipeline_codec_kind_t`). */
|
|
26
|
+
export declare const PIPELINE_CODEC: {
|
|
27
|
+
readonly h264: 0;
|
|
28
|
+
readonly hevc: 1;
|
|
29
|
+
readonly av1: 2;
|
|
30
|
+
readonly vp9: 3;
|
|
31
|
+
readonly aac: 4;
|
|
32
|
+
readonly opus: 5;
|
|
33
|
+
};
|
|
34
|
+
export declare const pipelineV7: {
|
|
35
|
+
audioDecodeConfigAac: import("koffi").Callable;
|
|
36
|
+
sessionPollBytes: import("koffi").Callable;
|
|
37
|
+
encoderSupportAt: import("koffi").Callable;
|
|
38
|
+
encoderSupportFree: import("koffi").Callable;
|
|
39
|
+
decoderSupport: import("koffi").Callable;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Size and field offsets of a registered struct, for pinning a mirror against the C header's
|
|
43
|
+
* layout in a test. `fields` are read in the order given.
|
|
44
|
+
*/
|
|
45
|
+
export declare function structLayout(type: unknown, fields: readonly string[]): {
|
|
46
|
+
size: number;
|
|
47
|
+
offsets: Record<string, number>;
|
|
48
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pipeline ABI v7 additions — `crates/mediaway-ffi/adr/pipeline/0007-stream-bytes-aac-decode-
|
|
3
|
+
* support-probe.md`: streaming fMP4 bytes, AAC decode, and the capability probes.
|
|
4
|
+
*
|
|
5
|
+
* Split out of index.ts for the workspace's 1000-line source cap. It imports only leaf modules
|
|
6
|
+
* (`rational.ts`, `loader.ts`), never `index.ts`, so `index.ts` can re-export it without a cycle.
|
|
7
|
+
*
|
|
8
|
+
* Ownership (from `pipeline.h`):
|
|
9
|
+
* - `mediaway_encode_session_poll_bytes` returns an OWNED buffer (release it with
|
|
10
|
+
* `pipeline.bufferFree`); nothing ready is `NULL` / `0` and needs no free.
|
|
11
|
+
* - `mediaway_encoder_support_at` returns an OWNED array; release it with
|
|
12
|
+
* `mediaway_encoder_support_free`, passing back the same pointer and count.
|
|
13
|
+
* - `mediaway_audio_decode_config_t.extra_data` is BORROWED, valid for `open()` only.
|
|
14
|
+
*/
|
|
15
|
+
import koffi from "koffi";
|
|
16
|
+
import { pipelineLib } from "./loader.js";
|
|
17
|
+
import { MwRational } from "./rational.js";
|
|
18
|
+
/** `mediaway_audio_decode_config_t` — Opus passes `extra_data = NULL`, AAC the raw ASC. */
|
|
19
|
+
export const MwAudioDecodeConfig = koffi.struct("MwAudioDecodeConfig", {
|
|
20
|
+
codec: "int32", // Opus (5) or AAC (4)
|
|
21
|
+
sample_rate: "uint32",
|
|
22
|
+
channels: "uint16",
|
|
23
|
+
time_base: MwRational,
|
|
24
|
+
extra_data: "uint8_t *", // borrowed, open-call only; AAC's AudioSpecificConfig
|
|
25
|
+
extra_data_len: "size_t",
|
|
26
|
+
});
|
|
27
|
+
/** `mediaway_encoder_capability_t` — one backend row of `mediaway_encoder_support_at`. */
|
|
28
|
+
export const MwEncoderCapability = koffi.struct("MwEncoderCapability", {
|
|
29
|
+
backend: "int32",
|
|
30
|
+
state: "int32",
|
|
31
|
+
path_class: "int32", // meaningful only when state == SUPPORTED
|
|
32
|
+
});
|
|
33
|
+
/** Codec numbers the probes and AAC decode accept (`mediaway_pipeline_codec_kind_t`). */
|
|
34
|
+
export const PIPELINE_CODEC = { h264: 0, hevc: 1, av1: 2, vp9: 3, aac: 4, opus: 5 };
|
|
35
|
+
export const pipelineV7 = {
|
|
36
|
+
audioDecodeConfigAac: pipelineLib.func("MwAudioDecodeConfig mediaway_audio_decode_config_aac(uint32_t sample_rate, uint16_t channels, MwRational time_base, uint8_t *extra_data, size_t extra_data_len)"),
|
|
37
|
+
sessionPollBytes: pipelineLib.func("int mediaway_encode_session_poll_bytes(void *session, _Out_ uint8_t **out_data, _Out_ size_t *out_len)"),
|
|
38
|
+
encoderSupportAt: pipelineLib.func("int mediaway_encoder_support_at(int codec, uint32_t width, uint32_t height, _Out_ void **out_rows, _Out_ size_t *out_count)"),
|
|
39
|
+
encoderSupportFree: pipelineLib.func("void mediaway_encoder_support_free(void *rows, size_t count)"),
|
|
40
|
+
decoderSupport: pipelineLib.func("int mediaway_decoder_support(int codec, _Out_ int *out_state)"),
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Size and field offsets of a registered struct, for pinning a mirror against the C header's
|
|
44
|
+
* layout in a test. `fields` are read in the order given.
|
|
45
|
+
*/
|
|
46
|
+
export function structLayout(type, fields) {
|
|
47
|
+
// `type` stays `unknown` so callers can pass whatever `koffi.struct` returned; `koffi.d.ts`
|
|
48
|
+
// types the pair strictly (`TypeObject`), so narrow it once here.
|
|
49
|
+
const registered = type;
|
|
50
|
+
const offsets = {};
|
|
51
|
+
for (const field of fields)
|
|
52
|
+
offsets[field] = koffi.offsetof(registered, field);
|
|
53
|
+
return { size: koffi.sizeof(registered), offsets };
|
|
54
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `mediaway_rational_t`, in a leaf module.
|
|
3
|
+
*
|
|
4
|
+
* Split out of index.ts so `pipeline-v7.ts` (which needs it to define struct layouts that
|
|
5
|
+
* embed a timebase) can import it without a cycle: index.ts imports pipeline-v7.ts, so
|
|
6
|
+
* pipeline-v7.ts must not import index.ts.
|
|
7
|
+
*/
|
|
8
|
+
export declare const MwRational: import("koffi").TypeObject;
|
package/dist/rational.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `mediaway_rational_t`, in a leaf module.
|
|
3
|
+
*
|
|
4
|
+
* Split out of index.ts so `pipeline-v7.ts` (which needs it to define struct layouts that
|
|
5
|
+
* embed a timebase) can import it without a cycle: index.ts imports pipeline-v7.ts, so
|
|
6
|
+
* pipeline-v7.ts must not import index.ts.
|
|
7
|
+
*/
|
|
8
|
+
import koffi from "koffi";
|
|
9
|
+
export const MwRational = koffi.struct("MwRational", {
|
|
10
|
+
num: "uint64",
|
|
11
|
+
den: "uint32",
|
|
12
|
+
});
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED