node-av 6.0.0-beta.3 → 6.0.0-beta.4
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/api/bitstream-filter.d.ts +101 -83
- package/dist/api/bitstream-filter.js +157 -100
- package/dist/api/bitstream-filter.js.map +1 -1
- package/dist/api/demuxer.d.ts +12 -12
- package/dist/api/demuxer.js.map +1 -1
- package/dist/api/muxer.d.ts +11 -8
- package/dist/api/muxer.js +27 -0
- package/dist/api/muxer.js.map +1 -1
- package/dist/api/pipeline.js +6 -6
- package/dist/api/pipeline.js.map +1 -1
- package/dist/constants/bsf-options.d.ts +7 -0
- package/dist/constants/format-options.d.ts +511 -10
- package/dist/constants/formats.d.ts +18 -0
- package/dist/constants/formats.js +7 -0
- package/dist/constants/formats.js.map +1 -0
- package/dist/constants/index.d.ts +3 -2
- package/package.json +11 -10
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { Packet } from '../lib/packet.js';
|
|
2
|
+
import { Stream } from '../lib/stream.js';
|
|
3
|
+
import { Encoder } from './encoder.js';
|
|
2
4
|
import { Muxer } from './muxer.js';
|
|
3
5
|
import { Scheduler, SchedulerControl } from './utilities/scheduler.js';
|
|
4
|
-
import type { BsfOptionsFor } from '../constants/index.js';
|
|
5
|
-
import type { Stream } from '../lib/stream.js';
|
|
6
|
+
import type { BsfName, BsfOptionsFor } from '../constants/index.js';
|
|
6
7
|
/**
|
|
7
8
|
* Options for bitstream filter creation.
|
|
8
9
|
*
|
|
@@ -68,7 +69,8 @@ export interface BitstreamFilterOptions<N extends string = string> {
|
|
|
68
69
|
export declare class BitStreamFilterAPI implements Disposable {
|
|
69
70
|
private ctx;
|
|
70
71
|
private bsf;
|
|
71
|
-
private
|
|
72
|
+
private source;
|
|
73
|
+
private initialized;
|
|
72
74
|
private packet;
|
|
73
75
|
private isClosed;
|
|
74
76
|
private inputQueue;
|
|
@@ -82,63 +84,55 @@ export declare class BitStreamFilterAPI implements Disposable {
|
|
|
82
84
|
*
|
|
83
85
|
* @param ctx - Filter context
|
|
84
86
|
*
|
|
85
|
-
* @param
|
|
87
|
+
* @param source - Input source for lazy parameter resolution
|
|
86
88
|
*
|
|
87
89
|
* @internal
|
|
88
90
|
*/
|
|
89
91
|
private constructor();
|
|
90
92
|
/**
|
|
91
|
-
* Create a bitstream filter
|
|
93
|
+
* Create a bitstream filter.
|
|
92
94
|
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
+
* The input source provides the codec parameters the filter is configured with.
|
|
96
|
+
* Pass a {@link Stream} to filter its packets directly (stream copy), or an
|
|
97
|
+
* {@link Encoder} to filter that encoder's output (transcode) - parameters are
|
|
98
|
+
* derived from the encoder once it is open. Another {@link BitStreamFilterAPI}
|
|
99
|
+
* may be passed to chain filters.
|
|
100
|
+
*
|
|
101
|
+
* Initialization is lazy: filter options are validated immediately, but the
|
|
102
|
+
* input parameters are bound and the filter is initialized on the first packet,
|
|
103
|
+
* so an `Encoder` source (opened lazily on its first frame) is ready in time.
|
|
95
104
|
*
|
|
96
105
|
* Direct mapping to av_bsf_get_by_name() and av_bsf_alloc().
|
|
97
106
|
*
|
|
98
107
|
* @param filterName - Name of the bitstream filter
|
|
99
108
|
*
|
|
100
|
-
* @param
|
|
109
|
+
* @param source - Input source: a `Stream` (copy), `Encoder` (transcode), or upstream filter (chain)
|
|
101
110
|
*
|
|
102
111
|
* @param filterOptions - Optional filter-specific options
|
|
103
112
|
*
|
|
104
113
|
* @returns Configured bitstream filter
|
|
105
114
|
*
|
|
106
|
-
* @throws {
|
|
107
|
-
*
|
|
108
|
-
* @throws {FFmpegError} If allocation or initialization fails
|
|
115
|
+
* @throws {FFmpegError} If the filter is not found, allocation fails, or an option is invalid
|
|
109
116
|
*
|
|
110
117
|
* @example
|
|
111
118
|
* ```typescript
|
|
112
|
-
* // H.264 MP4 to Annex B conversion
|
|
119
|
+
* // Stream copy: H.264 MP4 to Annex B conversion
|
|
113
120
|
* const filter = BitStreamFilterAPI.create('h264_mp4toannexb', videoStream);
|
|
114
121
|
* ```
|
|
115
122
|
*
|
|
116
123
|
* @example
|
|
117
124
|
* ```typescript
|
|
118
|
-
* //
|
|
119
|
-
* const filter = BitStreamFilterAPI.create('
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
* @example
|
|
123
|
-
* ```typescript
|
|
124
|
-
* // Remove AUDs from H.264 stream
|
|
125
|
-
* const filter = BitStreamFilterAPI.create('h264_metadata', stream, {
|
|
126
|
-
* options: { aud: 'remove' }
|
|
127
|
-
* });
|
|
128
|
-
* ```
|
|
129
|
-
*
|
|
130
|
-
* @example
|
|
131
|
-
* ```typescript
|
|
132
|
-
* // Set H.264 level
|
|
133
|
-
* const filter = BitStreamFilterAPI.create('h264_metadata', stream, {
|
|
134
|
-
* options: { level: 51 }
|
|
125
|
+
* // Transcode: derive parameters from the encoder's output
|
|
126
|
+
* const filter = BitStreamFilterAPI.create('h264_metadata', encoder, {
|
|
127
|
+
* options: { aud: 'remove', level: '4.1' },
|
|
135
128
|
* });
|
|
129
|
+
* pipeline(input, decoder, encoder, filter, output);
|
|
136
130
|
* ```
|
|
137
131
|
*
|
|
138
132
|
* @see {@link BitStreamFilter.getByName} For filter discovery
|
|
139
133
|
* @see {@link BitstreamFilterOptions} For available options
|
|
140
134
|
*/
|
|
141
|
-
static create<const N extends string = string>(filterName: N,
|
|
135
|
+
static create<const N extends BsfName | (string & {}) = BsfName | (string & {})>(filterName: N, source: Stream | Encoder | BitStreamFilterAPI, filterOptions?: BitstreamFilterOptions<N>): BitStreamFilterAPI;
|
|
142
136
|
/**
|
|
143
137
|
* Get filter name.
|
|
144
138
|
*
|
|
@@ -184,6 +178,38 @@ export declare class BitStreamFilterAPI implements Disposable {
|
|
|
184
178
|
* ```
|
|
185
179
|
*/
|
|
186
180
|
get isBitstreamFilterOpen(): boolean;
|
|
181
|
+
/**
|
|
182
|
+
* Check if the filter has been initialized.
|
|
183
|
+
*
|
|
184
|
+
* Initialization is lazy and happens on the first processed packet, after
|
|
185
|
+
* which {@link outputCodecParameters} reflect the filter's output.
|
|
186
|
+
*
|
|
187
|
+
* @example
|
|
188
|
+
* ```typescript
|
|
189
|
+
* if (filter.isInitialized) {
|
|
190
|
+
* const params = filter.outputCodecParameters;
|
|
191
|
+
* }
|
|
192
|
+
* ```
|
|
193
|
+
*/
|
|
194
|
+
get isInitialized(): boolean;
|
|
195
|
+
/**
|
|
196
|
+
* Get associated stream.
|
|
197
|
+
*
|
|
198
|
+
* Returns the stream this filter was created for. Only available when the
|
|
199
|
+
* filter was created from a {@link Stream}; filters created from an `Encoder`
|
|
200
|
+
* derive their parameters from the encoder's output instead.
|
|
201
|
+
*
|
|
202
|
+
* @returns Associated stream
|
|
203
|
+
*
|
|
204
|
+
* @throws {Error} If the filter was not created from a stream
|
|
205
|
+
*
|
|
206
|
+
* @example
|
|
207
|
+
* ```typescript
|
|
208
|
+
* const stream = filter.getStream();
|
|
209
|
+
* console.log(`Filtering stream ${stream.index}`);
|
|
210
|
+
* ```
|
|
211
|
+
*/
|
|
212
|
+
getStream(): Stream;
|
|
187
213
|
/**
|
|
188
214
|
* Send a packet to the filter.
|
|
189
215
|
*
|
|
@@ -642,6 +668,43 @@ export declare class BitStreamFilterAPI implements Disposable {
|
|
|
642
668
|
* @see {@link receive} For async version
|
|
643
669
|
*/
|
|
644
670
|
receiveSync(): Packet | null;
|
|
671
|
+
/**
|
|
672
|
+
* Pipe output to another bitstream filter.
|
|
673
|
+
*
|
|
674
|
+
* Starts background worker for packet processing.
|
|
675
|
+
* Packets flow through: input → this filter → target filter.
|
|
676
|
+
*
|
|
677
|
+
* @param target - Target bitstream filter
|
|
678
|
+
*
|
|
679
|
+
* @returns Scheduler for continued chaining
|
|
680
|
+
*
|
|
681
|
+
* @example
|
|
682
|
+
* ```typescript
|
|
683
|
+
* const filter1 = BitStreamFilterAPI.create('h264_mp4toannexb', stream);
|
|
684
|
+
* const filter2 = BitStreamFilterAPI.create('dump_extra', stream);
|
|
685
|
+
* filter1.pipeTo(filter2).pipeTo(output, 0);
|
|
686
|
+
* ```
|
|
687
|
+
*/
|
|
688
|
+
pipeTo(target: BitStreamFilterAPI): Scheduler<Packet>;
|
|
689
|
+
/**
|
|
690
|
+
* Pipe output to muxer.
|
|
691
|
+
*
|
|
692
|
+
* Terminal stage - writes filtered packets to output file.
|
|
693
|
+
*
|
|
694
|
+
* @param output - Muxer to write to
|
|
695
|
+
*
|
|
696
|
+
* @param streamIndex - Stream index in output
|
|
697
|
+
*
|
|
698
|
+
* @returns Control interface for pipeline
|
|
699
|
+
*
|
|
700
|
+
* @example
|
|
701
|
+
* ```typescript
|
|
702
|
+
* const filter = BitStreamFilterAPI.create('h264_mp4toannexb', stream);
|
|
703
|
+
* const control = filter.pipeTo(output, 0);
|
|
704
|
+
* await control.send(packet);
|
|
705
|
+
* ```
|
|
706
|
+
*/
|
|
707
|
+
pipeTo(output: Muxer, streamIndex: number): SchedulerControl<Packet>;
|
|
645
708
|
/**
|
|
646
709
|
* Flush all buffered packets as async generator.
|
|
647
710
|
*
|
|
@@ -691,20 +754,6 @@ export declare class BitStreamFilterAPI implements Disposable {
|
|
|
691
754
|
* @see {@link flushPackets} For async version
|
|
692
755
|
*/
|
|
693
756
|
flushPacketsSync(): Generator<Packet>;
|
|
694
|
-
/**
|
|
695
|
-
* Get associated stream.
|
|
696
|
-
*
|
|
697
|
-
* Returns the stream this filter was created for.
|
|
698
|
-
*
|
|
699
|
-
* @returns Associated stream
|
|
700
|
-
*
|
|
701
|
-
* @example
|
|
702
|
-
* ```typescript
|
|
703
|
-
* const stream = filter.getStream();
|
|
704
|
-
* console.log(`Filtering stream ${stream.index}`);
|
|
705
|
-
* ```
|
|
706
|
-
*/
|
|
707
|
-
getStream(): Stream;
|
|
708
757
|
/**
|
|
709
758
|
* Reset filter state.
|
|
710
759
|
*
|
|
@@ -753,6 +802,12 @@ export declare class BitStreamFilterAPI implements Disposable {
|
|
|
753
802
|
* @see {@link close} For manual cleanup
|
|
754
803
|
*/
|
|
755
804
|
[Symbol.dispose](): void;
|
|
805
|
+
/**
|
|
806
|
+
* Bind input parameters from the source and initialize the filter.
|
|
807
|
+
*
|
|
808
|
+
* @internal
|
|
809
|
+
*/
|
|
810
|
+
private ensureInitialized;
|
|
756
811
|
/**
|
|
757
812
|
* Send packet to input queue or flush the pipeline.
|
|
758
813
|
*
|
|
@@ -770,7 +825,7 @@ export declare class BitStreamFilterAPI implements Disposable {
|
|
|
770
825
|
*
|
|
771
826
|
* @internal
|
|
772
827
|
*/
|
|
773
|
-
sendToQueue
|
|
828
|
+
private sendToQueue;
|
|
774
829
|
/**
|
|
775
830
|
* Receive packet from output queue.
|
|
776
831
|
*
|
|
@@ -778,48 +833,11 @@ export declare class BitStreamFilterAPI implements Disposable {
|
|
|
778
833
|
*
|
|
779
834
|
* @internal
|
|
780
835
|
*/
|
|
781
|
-
receiveFromQueue
|
|
836
|
+
private receiveFromQueue;
|
|
782
837
|
/**
|
|
783
838
|
* Worker loop for push-based processing.
|
|
784
839
|
*
|
|
785
840
|
* @internal
|
|
786
841
|
*/
|
|
787
842
|
private runWorker;
|
|
788
|
-
/**
|
|
789
|
-
* Pipe output to another bitstream filter.
|
|
790
|
-
*
|
|
791
|
-
* Starts background worker for packet processing.
|
|
792
|
-
* Packets flow through: input → this filter → target filter.
|
|
793
|
-
*
|
|
794
|
-
* @param target - Target bitstream filter
|
|
795
|
-
*
|
|
796
|
-
* @returns Scheduler for continued chaining
|
|
797
|
-
*
|
|
798
|
-
* @example
|
|
799
|
-
* ```typescript
|
|
800
|
-
* const filter1 = BitStreamFilterAPI.create('h264_mp4toannexb', stream);
|
|
801
|
-
* const filter2 = BitStreamFilterAPI.create('dump_extra', stream);
|
|
802
|
-
* filter1.pipeTo(filter2).pipeTo(output, 0);
|
|
803
|
-
* ```
|
|
804
|
-
*/
|
|
805
|
-
pipeTo(target: BitStreamFilterAPI): Scheduler<Packet>;
|
|
806
|
-
/**
|
|
807
|
-
* Pipe output to muxer.
|
|
808
|
-
*
|
|
809
|
-
* Terminal stage - writes filtered packets to output file.
|
|
810
|
-
*
|
|
811
|
-
* @param output - Muxer to write to
|
|
812
|
-
*
|
|
813
|
-
* @param streamIndex - Stream index in output
|
|
814
|
-
*
|
|
815
|
-
* @returns Control interface for pipeline
|
|
816
|
-
*
|
|
817
|
-
* @example
|
|
818
|
-
* ```typescript
|
|
819
|
-
* const filter = BitStreamFilterAPI.create('h264_mp4toannexb', stream);
|
|
820
|
-
* const control = filter.pipeTo(output, 0);
|
|
821
|
-
* await control.send(packet);
|
|
822
|
-
* ```
|
|
823
|
-
*/
|
|
824
|
-
pipeTo(output: Muxer, streamIndex: number): SchedulerControl<Packet>;
|
|
825
843
|
}
|
|
@@ -55,7 +55,9 @@ import { BitStreamFilterContext } from '../lib/bitstream-filter-context.js';
|
|
|
55
55
|
import { BitStreamFilter } from '../lib/bitstream-filter.js';
|
|
56
56
|
import { FFmpegError } from '../lib/error.js';
|
|
57
57
|
import { Packet } from '../lib/packet.js';
|
|
58
|
+
import { Stream } from '../lib/stream.js';
|
|
58
59
|
import { PACKET_THREAD_QUEUE_SIZE } from './constants.js';
|
|
60
|
+
import { Encoder } from './encoder.js';
|
|
59
61
|
import { Muxer } from './muxer.js';
|
|
60
62
|
import { AsyncQueue } from './utilities/async-queue.js';
|
|
61
63
|
import { Scheduler, SchedulerControl } from './utilities/scheduler.js';
|
|
@@ -101,7 +103,8 @@ import { Scheduler, SchedulerControl } from './utilities/scheduler.js';
|
|
|
101
103
|
export class BitStreamFilterAPI {
|
|
102
104
|
ctx;
|
|
103
105
|
bsf;
|
|
104
|
-
|
|
106
|
+
source;
|
|
107
|
+
initialized = false;
|
|
105
108
|
packet;
|
|
106
109
|
isClosed = false;
|
|
107
110
|
// Worker pattern for push-based processing
|
|
@@ -116,73 +119,66 @@ export class BitStreamFilterAPI {
|
|
|
116
119
|
*
|
|
117
120
|
* @param ctx - Filter context
|
|
118
121
|
*
|
|
119
|
-
* @param
|
|
122
|
+
* @param source - Input source for lazy parameter resolution
|
|
120
123
|
*
|
|
121
124
|
* @internal
|
|
122
125
|
*/
|
|
123
|
-
constructor(bsf, ctx,
|
|
126
|
+
constructor(bsf, ctx, source) {
|
|
124
127
|
this.bsf = bsf;
|
|
125
128
|
this.ctx = ctx;
|
|
126
|
-
this.
|
|
129
|
+
this.source = source;
|
|
127
130
|
this.packet = new Packet();
|
|
128
131
|
this.packet.alloc();
|
|
129
132
|
this.inputQueue = new AsyncQueue(PACKET_THREAD_QUEUE_SIZE);
|
|
130
133
|
this.outputQueue = new AsyncQueue(PACKET_THREAD_QUEUE_SIZE);
|
|
131
134
|
}
|
|
132
135
|
/**
|
|
133
|
-
* Create a bitstream filter
|
|
136
|
+
* Create a bitstream filter.
|
|
134
137
|
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
138
|
+
* The input source provides the codec parameters the filter is configured with.
|
|
139
|
+
* Pass a {@link Stream} to filter its packets directly (stream copy), or an
|
|
140
|
+
* {@link Encoder} to filter that encoder's output (transcode) - parameters are
|
|
141
|
+
* derived from the encoder once it is open. Another {@link BitStreamFilterAPI}
|
|
142
|
+
* may be passed to chain filters.
|
|
143
|
+
*
|
|
144
|
+
* Initialization is lazy: filter options are validated immediately, but the
|
|
145
|
+
* input parameters are bound and the filter is initialized on the first packet,
|
|
146
|
+
* so an `Encoder` source (opened lazily on its first frame) is ready in time.
|
|
137
147
|
*
|
|
138
148
|
* Direct mapping to av_bsf_get_by_name() and av_bsf_alloc().
|
|
139
149
|
*
|
|
140
150
|
* @param filterName - Name of the bitstream filter
|
|
141
151
|
*
|
|
142
|
-
* @param
|
|
152
|
+
* @param source - Input source: a `Stream` (copy), `Encoder` (transcode), or upstream filter (chain)
|
|
143
153
|
*
|
|
144
154
|
* @param filterOptions - Optional filter-specific options
|
|
145
155
|
*
|
|
146
156
|
* @returns Configured bitstream filter
|
|
147
157
|
*
|
|
148
|
-
* @throws {
|
|
149
|
-
*
|
|
150
|
-
* @throws {FFmpegError} If allocation or initialization fails
|
|
158
|
+
* @throws {FFmpegError} If the filter is not found, allocation fails, or an option is invalid
|
|
151
159
|
*
|
|
152
160
|
* @example
|
|
153
161
|
* ```typescript
|
|
154
|
-
* // H.264 MP4 to Annex B conversion
|
|
162
|
+
* // Stream copy: H.264 MP4 to Annex B conversion
|
|
155
163
|
* const filter = BitStreamFilterAPI.create('h264_mp4toannexb', videoStream);
|
|
156
164
|
* ```
|
|
157
165
|
*
|
|
158
166
|
* @example
|
|
159
167
|
* ```typescript
|
|
160
|
-
* //
|
|
161
|
-
* const filter = BitStreamFilterAPI.create('
|
|
162
|
-
*
|
|
163
|
-
*
|
|
164
|
-
* @example
|
|
165
|
-
* ```typescript
|
|
166
|
-
* // Remove AUDs from H.264 stream
|
|
167
|
-
* const filter = BitStreamFilterAPI.create('h264_metadata', stream, {
|
|
168
|
-
* options: { aud: 'remove' }
|
|
169
|
-
* });
|
|
170
|
-
* ```
|
|
171
|
-
*
|
|
172
|
-
* @example
|
|
173
|
-
* ```typescript
|
|
174
|
-
* // Set H.264 level
|
|
175
|
-
* const filter = BitStreamFilterAPI.create('h264_metadata', stream, {
|
|
176
|
-
* options: { level: 51 }
|
|
168
|
+
* // Transcode: derive parameters from the encoder's output
|
|
169
|
+
* const filter = BitStreamFilterAPI.create('h264_metadata', encoder, {
|
|
170
|
+
* options: { aud: 'remove', level: '4.1' },
|
|
177
171
|
* });
|
|
172
|
+
* pipeline(input, decoder, encoder, filter, output);
|
|
178
173
|
* ```
|
|
179
174
|
*
|
|
180
175
|
* @see {@link BitStreamFilter.getByName} For filter discovery
|
|
181
176
|
* @see {@link BitstreamFilterOptions} For available options
|
|
182
177
|
*/
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
178
|
+
// eslint-disable-next-line space-before-function-paren
|
|
179
|
+
static create(filterName, source, filterOptions) {
|
|
180
|
+
if (!source) {
|
|
181
|
+
throw new Error('A source (Stream, Encoder, or BitStreamFilterAPI) is required');
|
|
186
182
|
}
|
|
187
183
|
// Find the bitstream filter
|
|
188
184
|
const filter = BitStreamFilter.getByName(filterName);
|
|
@@ -194,24 +190,15 @@ export class BitStreamFilterAPI {
|
|
|
194
190
|
const allocRet = ctx.alloc(filter);
|
|
195
191
|
FFmpegError.throwIfError(allocRet, 'Failed to allocate bitstream filter context');
|
|
196
192
|
try {
|
|
197
|
-
//
|
|
198
|
-
|
|
199
|
-
throw new Error('Failed to get input codec parameters from filter context');
|
|
200
|
-
}
|
|
201
|
-
stream.codecpar.copy(ctx.inputCodecParameters);
|
|
202
|
-
// Set time base
|
|
203
|
-
ctx.inputTimeBase = stream.timeBase;
|
|
204
|
-
// Apply filter-specific options before init
|
|
193
|
+
// Apply (and validate) filter-specific options now; input parameters and
|
|
194
|
+
// init() are deferred to ensureInitialized() on the first packet.
|
|
205
195
|
if (filterOptions?.options) {
|
|
206
196
|
for (const [key, value] of Object.entries(filterOptions.options)) {
|
|
207
197
|
const ret = ctx.setOption(key, value);
|
|
208
198
|
FFmpegError.throwIfError(ret, `Failed to set bitstream filter option '${key}'`);
|
|
209
199
|
}
|
|
210
200
|
}
|
|
211
|
-
|
|
212
|
-
const initRet = ctx.init();
|
|
213
|
-
FFmpegError.throwIfError(initRet, 'Failed to initialize bitstream filter');
|
|
214
|
-
const bsfApi = new BitStreamFilterAPI(filter, ctx, stream);
|
|
201
|
+
const bsfApi = new BitStreamFilterAPI(filter, ctx, source);
|
|
215
202
|
if (filterOptions?.signal) {
|
|
216
203
|
filterOptions.signal.throwIfAborted();
|
|
217
204
|
bsfApi.signal = filterOptions.signal;
|
|
@@ -277,6 +264,45 @@ export class BitStreamFilterAPI {
|
|
|
277
264
|
get isBitstreamFilterOpen() {
|
|
278
265
|
return !this.isClosed;
|
|
279
266
|
}
|
|
267
|
+
/**
|
|
268
|
+
* Check if the filter has been initialized.
|
|
269
|
+
*
|
|
270
|
+
* Initialization is lazy and happens on the first processed packet, after
|
|
271
|
+
* which {@link outputCodecParameters} reflect the filter's output.
|
|
272
|
+
*
|
|
273
|
+
* @example
|
|
274
|
+
* ```typescript
|
|
275
|
+
* if (filter.isInitialized) {
|
|
276
|
+
* const params = filter.outputCodecParameters;
|
|
277
|
+
* }
|
|
278
|
+
* ```
|
|
279
|
+
*/
|
|
280
|
+
get isInitialized() {
|
|
281
|
+
return this.initialized;
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Get associated stream.
|
|
285
|
+
*
|
|
286
|
+
* Returns the stream this filter was created for. Only available when the
|
|
287
|
+
* filter was created from a {@link Stream}; filters created from an `Encoder`
|
|
288
|
+
* derive their parameters from the encoder's output instead.
|
|
289
|
+
*
|
|
290
|
+
* @returns Associated stream
|
|
291
|
+
*
|
|
292
|
+
* @throws {Error} If the filter was not created from a stream
|
|
293
|
+
*
|
|
294
|
+
* @example
|
|
295
|
+
* ```typescript
|
|
296
|
+
* const stream = filter.getStream();
|
|
297
|
+
* console.log(`Filtering stream ${stream.index}`);
|
|
298
|
+
* ```
|
|
299
|
+
*/
|
|
300
|
+
getStream() {
|
|
301
|
+
if (!(this.source instanceof Stream)) {
|
|
302
|
+
throw new Error('No associated stream: this bitstream filter derives its parameters from an upstream component');
|
|
303
|
+
}
|
|
304
|
+
return this.source;
|
|
305
|
+
}
|
|
280
306
|
/**
|
|
281
307
|
* Send a packet to the filter.
|
|
282
308
|
*
|
|
@@ -334,6 +360,7 @@ export class BitStreamFilterAPI {
|
|
|
334
360
|
if (this.isClosed) {
|
|
335
361
|
return;
|
|
336
362
|
}
|
|
363
|
+
this.ensureInitialized();
|
|
337
364
|
// Send packet to filter (null signals EOF/flush)
|
|
338
365
|
const sendRet = await this.ctx.sendPacket(packet);
|
|
339
366
|
if (sendRet < 0 && sendRet !== AVERROR_EOF && sendRet !== AVERROR_EAGAIN) {
|
|
@@ -397,6 +424,7 @@ export class BitStreamFilterAPI {
|
|
|
397
424
|
if (this.isClosed) {
|
|
398
425
|
return;
|
|
399
426
|
}
|
|
427
|
+
this.ensureInitialized();
|
|
400
428
|
// Send packet to filter (null signals EOF/flush)
|
|
401
429
|
const sendRet = this.ctx.sendPacketSync(packet);
|
|
402
430
|
if (sendRet < 0 && sendRet !== AVERROR_EOF && sendRet !== AVERROR_EAGAIN) {
|
|
@@ -748,7 +776,7 @@ export class BitStreamFilterAPI {
|
|
|
748
776
|
*/
|
|
749
777
|
async flush() {
|
|
750
778
|
this.signal?.throwIfAborted();
|
|
751
|
-
if (this.isClosed) {
|
|
779
|
+
if (this.isClosed || !this.initialized) {
|
|
752
780
|
return;
|
|
753
781
|
}
|
|
754
782
|
// Send EOF
|
|
@@ -791,7 +819,7 @@ export class BitStreamFilterAPI {
|
|
|
791
819
|
* @see {@link flush} For async version
|
|
792
820
|
*/
|
|
793
821
|
flushSync() {
|
|
794
|
-
if (this.isClosed) {
|
|
822
|
+
if (this.isClosed || !this.initialized) {
|
|
795
823
|
return;
|
|
796
824
|
}
|
|
797
825
|
// Send EOF
|
|
@@ -844,7 +872,7 @@ export class BitStreamFilterAPI {
|
|
|
844
872
|
* @see {@link receiveSync} For synchronous version
|
|
845
873
|
*/
|
|
846
874
|
async receive() {
|
|
847
|
-
if (this.isClosed) {
|
|
875
|
+
if (this.isClosed || !this.initialized) {
|
|
848
876
|
return null;
|
|
849
877
|
}
|
|
850
878
|
// Clear previous packet data
|
|
@@ -911,7 +939,7 @@ export class BitStreamFilterAPI {
|
|
|
911
939
|
* @see {@link receive} For async version
|
|
912
940
|
*/
|
|
913
941
|
receiveSync() {
|
|
914
|
-
if (this.isClosed) {
|
|
942
|
+
if (this.isClosed || !this.initialized) {
|
|
915
943
|
return null;
|
|
916
944
|
}
|
|
917
945
|
// Clear previous packet data
|
|
@@ -935,6 +963,42 @@ export class BitStreamFilterAPI {
|
|
|
935
963
|
return null;
|
|
936
964
|
}
|
|
937
965
|
}
|
|
966
|
+
pipeTo(target, streamIndex) {
|
|
967
|
+
if (target instanceof Muxer) {
|
|
968
|
+
// Start worker if not already running
|
|
969
|
+
this.workerPromise ??= this.runWorker();
|
|
970
|
+
// Start pipe task: filter.outputQueue -> output
|
|
971
|
+
this.pipeToPromise = (async () => {
|
|
972
|
+
while (true) {
|
|
973
|
+
const packet = await this.receiveFromQueue();
|
|
974
|
+
if (!packet)
|
|
975
|
+
break;
|
|
976
|
+
await target.writePacket(packet, streamIndex);
|
|
977
|
+
}
|
|
978
|
+
})();
|
|
979
|
+
// Return control without pipeTo (terminal stage)
|
|
980
|
+
return new SchedulerControl(this);
|
|
981
|
+
}
|
|
982
|
+
else {
|
|
983
|
+
// BitStreamFilterAPI
|
|
984
|
+
const t = target;
|
|
985
|
+
// Store reference to next component for flush propagation
|
|
986
|
+
this.nextComponent = t;
|
|
987
|
+
// Start worker if not already running
|
|
988
|
+
this.workerPromise ??= this.runWorker();
|
|
989
|
+
// Start pipe task: filter.outputQueue -> target.inputQueue (via target.send)
|
|
990
|
+
this.pipeToPromise = (async () => {
|
|
991
|
+
while (true) {
|
|
992
|
+
const packet = await this.receiveFromQueue();
|
|
993
|
+
if (!packet)
|
|
994
|
+
break;
|
|
995
|
+
await t.sendToQueue(packet);
|
|
996
|
+
}
|
|
997
|
+
})();
|
|
998
|
+
// Return scheduler for chaining (target is now the last component)
|
|
999
|
+
return new Scheduler(this, t);
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
938
1002
|
/**
|
|
939
1003
|
* Flush all buffered packets as async generator.
|
|
940
1004
|
*
|
|
@@ -998,22 +1062,6 @@ export class BitStreamFilterAPI {
|
|
|
998
1062
|
yield packet;
|
|
999
1063
|
}
|
|
1000
1064
|
}
|
|
1001
|
-
/**
|
|
1002
|
-
* Get associated stream.
|
|
1003
|
-
*
|
|
1004
|
-
* Returns the stream this filter was created for.
|
|
1005
|
-
*
|
|
1006
|
-
* @returns Associated stream
|
|
1007
|
-
*
|
|
1008
|
-
* @example
|
|
1009
|
-
* ```typescript
|
|
1010
|
-
* const stream = filter.getStream();
|
|
1011
|
-
* console.log(`Filtering stream ${stream.index}`);
|
|
1012
|
-
* ```
|
|
1013
|
-
*/
|
|
1014
|
-
getStream() {
|
|
1015
|
-
return this.stream;
|
|
1016
|
-
}
|
|
1017
1065
|
/**
|
|
1018
1066
|
* Reset filter state.
|
|
1019
1067
|
*
|
|
@@ -1079,6 +1127,50 @@ export class BitStreamFilterAPI {
|
|
|
1079
1127
|
[Symbol.dispose]() {
|
|
1080
1128
|
this.close();
|
|
1081
1129
|
}
|
|
1130
|
+
/**
|
|
1131
|
+
* Bind input parameters from the source and initialize the filter.
|
|
1132
|
+
*
|
|
1133
|
+
* @internal
|
|
1134
|
+
*/
|
|
1135
|
+
ensureInitialized() {
|
|
1136
|
+
if (this.initialized) {
|
|
1137
|
+
return;
|
|
1138
|
+
}
|
|
1139
|
+
const params = this.ctx.inputCodecParameters;
|
|
1140
|
+
if (!params) {
|
|
1141
|
+
throw new Error('Failed to get input codec parameters from filter context');
|
|
1142
|
+
}
|
|
1143
|
+
const source = this.source;
|
|
1144
|
+
if (source instanceof Stream) {
|
|
1145
|
+
source.codecpar.copy(params);
|
|
1146
|
+
this.ctx.inputTimeBase = source.timeBase;
|
|
1147
|
+
}
|
|
1148
|
+
else if (source instanceof Encoder) {
|
|
1149
|
+
const codecContext = source.getCodecContext();
|
|
1150
|
+
if (!codecContext) {
|
|
1151
|
+
throw new Error('Encoder is not initialized yet; cannot derive bitstream filter parameters.');
|
|
1152
|
+
}
|
|
1153
|
+
const ret = params.fromContext(codecContext);
|
|
1154
|
+
FFmpegError.throwIfError(ret, 'Failed to derive bitstream filter parameters from encoder');
|
|
1155
|
+
this.ctx.inputTimeBase = codecContext.timeBase;
|
|
1156
|
+
}
|
|
1157
|
+
else {
|
|
1158
|
+
// Upstream is another bitstream filter: chain from its output.
|
|
1159
|
+
source.ensureInitialized();
|
|
1160
|
+
const upstream = source.outputCodecParameters;
|
|
1161
|
+
if (!upstream) {
|
|
1162
|
+
throw new Error('Upstream bitstream filter has no output parameters.');
|
|
1163
|
+
}
|
|
1164
|
+
upstream.copy(params);
|
|
1165
|
+
const tb = source.outputTimeBase;
|
|
1166
|
+
if (tb) {
|
|
1167
|
+
this.ctx.inputTimeBase = tb;
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
const initRet = this.ctx.init();
|
|
1171
|
+
FFmpegError.throwIfError(initRet, 'Failed to initialize bitstream filter');
|
|
1172
|
+
this.initialized = true;
|
|
1173
|
+
}
|
|
1082
1174
|
/**
|
|
1083
1175
|
* Send packet to input queue or flush the pipeline.
|
|
1084
1176
|
*
|
|
@@ -1146,6 +1238,7 @@ export class BitStreamFilterAPI {
|
|
|
1146
1238
|
if (this.isClosed) {
|
|
1147
1239
|
break;
|
|
1148
1240
|
}
|
|
1241
|
+
this.ensureInitialized();
|
|
1149
1242
|
// Send packet to filter
|
|
1150
1243
|
const sendRet = await this.ctx.sendPacket(packet);
|
|
1151
1244
|
// Handle EAGAIN
|
|
@@ -1202,41 +1295,5 @@ export class BitStreamFilterAPI {
|
|
|
1202
1295
|
this.outputQueue?.close();
|
|
1203
1296
|
}
|
|
1204
1297
|
}
|
|
1205
|
-
pipeTo(target, streamIndex) {
|
|
1206
|
-
if (target instanceof Muxer) {
|
|
1207
|
-
// Start worker if not already running
|
|
1208
|
-
this.workerPromise ??= this.runWorker();
|
|
1209
|
-
// Start pipe task: filter.outputQueue -> output
|
|
1210
|
-
this.pipeToPromise = (async () => {
|
|
1211
|
-
while (true) {
|
|
1212
|
-
const packet = await this.receiveFromQueue();
|
|
1213
|
-
if (!packet)
|
|
1214
|
-
break;
|
|
1215
|
-
await target.writePacket(packet, streamIndex);
|
|
1216
|
-
}
|
|
1217
|
-
})();
|
|
1218
|
-
// Return control without pipeTo (terminal stage)
|
|
1219
|
-
return new SchedulerControl(this);
|
|
1220
|
-
}
|
|
1221
|
-
else {
|
|
1222
|
-
// BitStreamFilterAPI
|
|
1223
|
-
const t = target;
|
|
1224
|
-
// Store reference to next component for flush propagation
|
|
1225
|
-
this.nextComponent = t;
|
|
1226
|
-
// Start worker if not already running
|
|
1227
|
-
this.workerPromise ??= this.runWorker();
|
|
1228
|
-
// Start pipe task: filter.outputQueue -> target.inputQueue (via target.send)
|
|
1229
|
-
this.pipeToPromise = (async () => {
|
|
1230
|
-
while (true) {
|
|
1231
|
-
const packet = await this.receiveFromQueue();
|
|
1232
|
-
if (!packet)
|
|
1233
|
-
break;
|
|
1234
|
-
await t.sendToQueue(packet);
|
|
1235
|
-
}
|
|
1236
|
-
})();
|
|
1237
|
-
// Return scheduler for chaining (target is now the last component)
|
|
1238
|
-
return new Scheduler(this, t);
|
|
1239
|
-
}
|
|
1240
|
-
}
|
|
1241
1298
|
}
|
|
1242
1299
|
//# sourceMappingURL=bitstream-filter.js.map
|