node-av 1.0.3 → 1.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.
- package/README.md +5 -3
- package/dist/api/bitstream-filter.js +2 -1
- package/dist/api/bitstream-filter.js.map +1 -1
- package/dist/api/decoder.d.ts +10 -1
- package/dist/api/decoder.js +44 -25
- package/dist/api/decoder.js.map +1 -1
- package/dist/api/encoder.d.ts +19 -7
- package/dist/api/encoder.js +94 -130
- package/dist/api/encoder.js.map +1 -1
- package/dist/api/filter-presets.d.ts +316 -0
- package/dist/api/filter-presets.js +823 -0
- package/dist/api/filter-presets.js.map +1 -0
- package/dist/api/filter.d.ts +133 -173
- package/dist/api/filter.js +309 -393
- package/dist/api/filter.js.map +1 -1
- package/dist/api/hardware.d.ts +33 -73
- package/dist/api/hardware.js +86 -134
- package/dist/api/hardware.js.map +1 -1
- package/dist/api/index.d.ts +2 -1
- package/dist/api/index.js +1 -0
- package/dist/api/index.js.map +1 -1
- package/dist/api/io-stream.js +2 -1
- package/dist/api/io-stream.js.map +1 -1
- package/dist/api/media-input.d.ts +2 -1
- package/dist/api/media-input.js +2 -1
- package/dist/api/media-input.js.map +1 -1
- package/dist/api/media-output.js +2 -1
- package/dist/api/media-output.js.map +1 -1
- package/dist/api/types.d.ts +7 -1
- package/dist/api/utilities/audio-sample.d.ts +1 -1
- package/dist/api/utilities/image.d.ts +1 -1
- package/dist/api/utilities/media-type.d.ts +1 -1
- package/dist/api/utilities/pixel-format.d.ts +1 -1
- package/dist/api/utilities/sample-format.d.ts +1 -1
- package/dist/api/utilities/timestamp.d.ts +1 -1
- package/dist/{lib → constants}/channel-layouts.d.ts +1 -1
- package/dist/constants/channel-layouts.js.map +1 -0
- package/dist/{lib → constants}/constants.d.ts +19 -4
- package/dist/{lib → constants}/constants.js +15 -1
- package/dist/constants/constants.js.map +1 -0
- package/dist/constants/decoders.d.ts +609 -0
- package/dist/constants/decoders.js +617 -0
- package/dist/constants/decoders.js.map +1 -0
- package/dist/constants/encoders.d.ts +285 -0
- package/dist/constants/encoders.js +298 -0
- package/dist/constants/encoders.js.map +1 -0
- package/dist/constants/index.d.ts +4 -0
- package/dist/constants/index.js +5 -0
- package/dist/constants/index.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/audio-fifo.d.ts +1 -1
- package/dist/lib/binding.d.ts +7 -5
- package/dist/lib/binding.js.map +1 -1
- package/dist/lib/bitstream-filter.d.ts +1 -1
- package/dist/lib/codec-context.d.ts +1 -1
- package/dist/lib/codec-parameters.d.ts +1 -1
- package/dist/lib/codec-parser.d.ts +1 -1
- package/dist/lib/codec.d.ts +131 -3
- package/dist/lib/codec.js +191 -0
- package/dist/lib/codec.js.map +1 -1
- package/dist/lib/dictionary.d.ts +1 -1
- package/dist/lib/dictionary.js +1 -1
- package/dist/lib/dictionary.js.map +1 -1
- package/dist/lib/error.d.ts +1 -1
- package/dist/lib/error.js.map +1 -1
- package/dist/lib/filter-context.d.ts +58 -1
- package/dist/lib/filter-context.js +72 -0
- package/dist/lib/filter-context.js.map +1 -1
- package/dist/lib/filter-graph.d.ts +1 -1
- package/dist/lib/filter.js +1 -1
- package/dist/lib/filter.js.map +1 -1
- package/dist/lib/format-context.d.ts +1 -1
- package/dist/lib/format-context.js +1 -1
- package/dist/lib/format-context.js.map +1 -1
- package/dist/lib/frame.d.ts +1 -1
- package/dist/lib/hardware-device-context.d.ts +1 -1
- package/dist/lib/hardware-frames-context.d.ts +1 -1
- package/dist/lib/index.d.ts +0 -2
- package/dist/lib/index.js +0 -3
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/input-format.d.ts +1 -1
- package/dist/lib/io-context.d.ts +1 -1
- package/dist/lib/io-context.js +1 -1
- package/dist/lib/io-context.js.map +1 -1
- package/dist/lib/log.d.ts +1 -1
- package/dist/lib/native-types.d.ts +10 -6
- package/dist/lib/native-types.js +16 -0
- package/dist/lib/native-types.js.map +1 -1
- package/dist/lib/option.d.ts +1 -1
- package/dist/lib/option.js +1 -1
- package/dist/lib/option.js.map +1 -1
- package/dist/lib/output-format.d.ts +1 -1
- package/dist/lib/packet.d.ts +1 -1
- package/dist/lib/software-resample-context.d.ts +1 -1
- package/dist/lib/software-scale-context.d.ts +1 -1
- package/dist/lib/software-scale-context.js +1 -1
- package/dist/lib/software-scale-context.js.map +1 -1
- package/dist/lib/stream.d.ts +1 -1
- package/dist/lib/types.d.ts +1 -1
- package/dist/lib/utilities.d.ts +1 -1
- package/package.json +18 -19
- package/release_notes.md +59 -13
- package/dist/lib/channel-layouts.js.map +0 -1
- package/dist/lib/constants.js.map +0 -1
- /package/dist/{lib → constants}/channel-layouts.js +0 -0
package/README.md
CHANGED
|
@@ -14,6 +14,7 @@ npm install node-av
|
|
|
14
14
|
|
|
15
15
|
```typescript
|
|
16
16
|
import { Decoder, Encoder, MediaInput, MediaOutput } from 'node-av/api';
|
|
17
|
+
import { FF_ENCODER_LIBX264 } from 'node-av/constants';
|
|
17
18
|
|
|
18
19
|
// Open media
|
|
19
20
|
await using input = await MediaInput.open('input.mp4');
|
|
@@ -24,7 +25,7 @@ const videoStream = input.video();
|
|
|
24
25
|
|
|
25
26
|
// Create decoder/encoder
|
|
26
27
|
using decoder = await Decoder.create(videoStream!);
|
|
27
|
-
using encoder = await Encoder.create(
|
|
28
|
+
using encoder = await Encoder.create(FF_ENCODER_LIBX264, decoder.getOutputStreamInfo(), {
|
|
28
29
|
bitrate: '2M',
|
|
29
30
|
gopSize: 60,
|
|
30
31
|
});
|
|
@@ -71,7 +72,7 @@ import { pipeline, MediaInput, MediaOutput, Decoder, Encoder } from 'node-av/api
|
|
|
71
72
|
const input = await MediaInput.open('input.mp4');
|
|
72
73
|
const output = await MediaOutput.open('output.mp4');
|
|
73
74
|
const decoder = await Decoder.create(input.video());
|
|
74
|
-
const encoder = await Encoder.create(
|
|
75
|
+
const encoder = await Encoder.create(FF_ENCODER_LIBX264, decoder.getOutputStreamInfo(), {
|
|
75
76
|
bitrate: '2M',
|
|
76
77
|
gopSize: 60
|
|
77
78
|
});
|
|
@@ -109,6 +110,7 @@ The library supports all hardware acceleration methods available in FFmpeg. The
|
|
|
109
110
|
|
|
110
111
|
```typescript
|
|
111
112
|
import { HardwareContext } from 'node-av/api';
|
|
113
|
+
import { FF_ENCODER_H264_VIDEOTOOLBOX } from 'node-av/constants';
|
|
112
114
|
|
|
113
115
|
// Automatically detect best available hardware
|
|
114
116
|
const hw = await HardwareContext.auto();
|
|
@@ -121,7 +123,7 @@ if (hw) {
|
|
|
121
123
|
});
|
|
122
124
|
|
|
123
125
|
// Use with encoder (use hardware-specific codec)
|
|
124
|
-
const encoder = await Encoder.create(
|
|
126
|
+
const encoder = await Encoder.create(FF_ENCODER_H264_VIDEOTOOLBOX, decoder.getOutputStreamInfo(), {
|
|
125
127
|
hardware: hw
|
|
126
128
|
});
|
|
127
129
|
}
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
*
|
|
10
10
|
* @module api/bitstream-filter
|
|
11
11
|
*/
|
|
12
|
-
import {
|
|
12
|
+
import { AVERROR_EOF } from '../constants/constants.js';
|
|
13
|
+
import { AVERROR_EAGAIN, BitStreamFilter, BitStreamFilterContext, FFmpegError, Packet } from '../lib/index.js';
|
|
13
14
|
/**
|
|
14
15
|
* High-level bitstream filter for packet processing.
|
|
15
16
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bitstream-filter.js","sourceRoot":"","sources":["../../src/api/bitstream-filter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"bitstream-filter.js","sourceRoot":"","sources":["../../src/api/bitstream-filter.ts"],"names":[],"mappings":"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"}
|
package/dist/api/decoder.d.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import { CodecContext, Frame } from '../lib/index.js';
|
|
13
13
|
import type { Packet, Stream } from '../lib/index.js';
|
|
14
|
-
import type { DecoderOptions } from './types.js';
|
|
14
|
+
import type { DecoderOptions, StreamInfo } from './types.js';
|
|
15
15
|
/**
|
|
16
16
|
* High-level decoder for media streams.
|
|
17
17
|
*
|
|
@@ -102,6 +102,15 @@ export declare class Decoder implements Disposable {
|
|
|
102
102
|
* Check if decoder is open.
|
|
103
103
|
*/
|
|
104
104
|
get isDecoderOpen(): boolean;
|
|
105
|
+
/**
|
|
106
|
+
* Get output stream information.
|
|
107
|
+
*
|
|
108
|
+
* Returns the actual decoder output format, which may differ from the input stream.
|
|
109
|
+
* For hardware decoders, this returns the hardware pixel format.
|
|
110
|
+
*
|
|
111
|
+
* @returns StreamInfo with decoder output properties
|
|
112
|
+
*/
|
|
113
|
+
getOutputStreamInfo(): StreamInfo;
|
|
105
114
|
/**
|
|
106
115
|
* Decode a packet and return a frame if available.
|
|
107
116
|
*
|
package/dist/api/decoder.js
CHANGED
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
*
|
|
10
10
|
* @module api/decoder
|
|
11
11
|
*/
|
|
12
|
-
import {
|
|
12
|
+
import { AVERROR_EOF, AVMEDIA_TYPE_VIDEO } from '../constants/constants.js';
|
|
13
|
+
import { AVERROR_EAGAIN, Codec, CodecContext, FFmpegError, Frame } from '../lib/index.js';
|
|
13
14
|
/**
|
|
14
15
|
* High-level decoder for media streams.
|
|
15
16
|
*
|
|
@@ -127,24 +128,11 @@ export class Decoder {
|
|
|
127
128
|
codecContext.threadCount = options.threads;
|
|
128
129
|
}
|
|
129
130
|
// Check if this decoder supports hardware acceleration
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
if (!config)
|
|
136
|
-
break;
|
|
137
|
-
// Check if decoder supports HW_DEVICE_CTX method with matching device type
|
|
138
|
-
if ((config.methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX) !== 0 && config.deviceType === options.hardware.deviceType) {
|
|
139
|
-
supportsHardware = true;
|
|
140
|
-
break;
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
// Only apply hardware acceleration if the decoder supports it
|
|
144
|
-
if (supportsHardware) {
|
|
145
|
-
codecContext.hwDeviceCtx = options.hardware.deviceContext;
|
|
146
|
-
}
|
|
147
|
-
// Silently ignore hardware for software decoders
|
|
131
|
+
// Only apply hardware acceleration if the decoder supports it
|
|
132
|
+
// Silently ignore hardware for software decoders
|
|
133
|
+
const isHWDecoder = codec.isHardwareAcceleratedDecoder();
|
|
134
|
+
if (isHWDecoder && options.hardware) {
|
|
135
|
+
codecContext.hwDeviceCtx = options.hardware.deviceContext;
|
|
148
136
|
}
|
|
149
137
|
// Apply codec-specific options via AVOptions
|
|
150
138
|
if (options.options) {
|
|
@@ -158,7 +146,7 @@ export class Decoder {
|
|
|
158
146
|
codecContext.freeContext();
|
|
159
147
|
FFmpegError.throwIfError(openRet, 'Failed to open codec');
|
|
160
148
|
}
|
|
161
|
-
const decoder = new Decoder(codecContext, stream, options.hardware);
|
|
149
|
+
const decoder = new Decoder(codecContext, stream, isHWDecoder ? options.hardware : undefined);
|
|
162
150
|
return decoder;
|
|
163
151
|
}
|
|
164
152
|
/**
|
|
@@ -167,6 +155,40 @@ export class Decoder {
|
|
|
167
155
|
get isDecoderOpen() {
|
|
168
156
|
return this.isOpen;
|
|
169
157
|
}
|
|
158
|
+
/**
|
|
159
|
+
* Get output stream information.
|
|
160
|
+
*
|
|
161
|
+
* Returns the actual decoder output format, which may differ from the input stream.
|
|
162
|
+
* For hardware decoders, this returns the hardware pixel format.
|
|
163
|
+
*
|
|
164
|
+
* @returns StreamInfo with decoder output properties
|
|
165
|
+
*/
|
|
166
|
+
getOutputStreamInfo() {
|
|
167
|
+
if (this.stream.codecpar.codecType === AVMEDIA_TYPE_VIDEO) {
|
|
168
|
+
// For hardware decoders, the codecContext.pixelFormat is not set correctly
|
|
169
|
+
// We need to use the hardware pixel format directly
|
|
170
|
+
const pixelFormat = this.hardware ? this.hardware.getHardwarePixelFormat() : this.codecContext.pixelFormat;
|
|
171
|
+
return {
|
|
172
|
+
type: 'video',
|
|
173
|
+
width: this.codecContext.width,
|
|
174
|
+
height: this.codecContext.height,
|
|
175
|
+
pixelFormat,
|
|
176
|
+
timeBase: this.stream.timeBase,
|
|
177
|
+
frameRate: this.stream.rFrameRate,
|
|
178
|
+
sampleAspectRatio: this.codecContext.sampleAspectRatio,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
// For audio
|
|
183
|
+
return {
|
|
184
|
+
type: 'audio',
|
|
185
|
+
sampleRate: this.codecContext.sampleRate,
|
|
186
|
+
sampleFormat: this.codecContext.sampleFormat,
|
|
187
|
+
channelLayout: this.codecContext.channelLayout,
|
|
188
|
+
timeBase: this.stream.timeBase,
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
}
|
|
170
192
|
/**
|
|
171
193
|
* Decode a packet and return a frame if available.
|
|
172
194
|
*
|
|
@@ -393,11 +415,8 @@ export class Decoder {
|
|
|
393
415
|
this.frame.unref();
|
|
394
416
|
const ret = await this.codecContext.receiveFrame(this.frame);
|
|
395
417
|
if (ret === 0) {
|
|
396
|
-
//
|
|
397
|
-
//
|
|
398
|
-
if (this.hardware && this.frame.hwFramesCtx) {
|
|
399
|
-
this.hardware.framesContext = this.frame.hwFramesCtx;
|
|
400
|
-
}
|
|
418
|
+
// Note: hw_frames_ctx is now available in the frame
|
|
419
|
+
// Other components should get it directly from frames, not from HardwareContext
|
|
401
420
|
// Got a frame, clone it for the user
|
|
402
421
|
return this.frame.clone();
|
|
403
422
|
}
|
package/dist/api/decoder.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"decoder.js","sourceRoot":"","sources":["../../src/api/decoder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"decoder.js","sourceRoot":"","sources":["../../src/api/decoder.ts"],"names":[],"mappings":"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"}
|
package/dist/api/encoder.d.ts
CHANGED
|
@@ -9,9 +9,10 @@
|
|
|
9
9
|
*
|
|
10
10
|
* @module api/encoder
|
|
11
11
|
*/
|
|
12
|
-
import { CodecContext, Packet } from '../lib/index.js';
|
|
13
|
-
import {
|
|
14
|
-
import type {
|
|
12
|
+
import { Codec, CodecContext, Packet } from '../lib/index.js';
|
|
13
|
+
import type { AVCodecID, AVPixelFormat } from '../constants/constants.js';
|
|
14
|
+
import type { FFEncoderCodec } from '../constants/encoders.js';
|
|
15
|
+
import type { Frame } from '../lib/index.js';
|
|
15
16
|
import type { EncoderOptions, StreamInfo } from './types.js';
|
|
16
17
|
/**
|
|
17
18
|
* High-level encoder for media streams.
|
|
@@ -75,7 +76,6 @@ export declare class Encoder implements Disposable {
|
|
|
75
76
|
private supportedFormats;
|
|
76
77
|
private preferredFormat?;
|
|
77
78
|
private hardware?;
|
|
78
|
-
private isHardwareEncoder;
|
|
79
79
|
/**
|
|
80
80
|
* Private constructor - use Encoder.create() instead.
|
|
81
81
|
*
|
|
@@ -83,7 +83,7 @@ export declare class Encoder implements Disposable {
|
|
|
83
83
|
*
|
|
84
84
|
* @param codecContext - Initialized codec context
|
|
85
85
|
* @param codecName - Name of the codec
|
|
86
|
-
* @param hardware - Optional hardware context for
|
|
86
|
+
* @param hardware - Optional hardware context for hardware pixel format
|
|
87
87
|
*/
|
|
88
88
|
private constructor();
|
|
89
89
|
/**
|
|
@@ -96,7 +96,7 @@ export declare class Encoder implements Disposable {
|
|
|
96
96
|
* configures the context with provided options, and opens it.
|
|
97
97
|
* Handles hardware setup including shared frames context for zero-copy.
|
|
98
98
|
*
|
|
99
|
-
* @param
|
|
99
|
+
* @param encoderCodec - Codec to use for encoding
|
|
100
100
|
* @param input - Stream or StreamInfo to copy parameters from
|
|
101
101
|
* @param options - Encoder configuration options
|
|
102
102
|
*
|
|
@@ -121,11 +121,23 @@ export declare class Encoder implements Disposable {
|
|
|
121
121
|
*
|
|
122
122
|
* ```
|
|
123
123
|
*/
|
|
124
|
-
static create(
|
|
124
|
+
static create(encoderCodec: FFEncoderCodec | AVCodecID | Codec, input: StreamInfo, options?: EncoderOptions): Promise<Encoder>;
|
|
125
125
|
/**
|
|
126
126
|
* Check if encoder is open.
|
|
127
127
|
*/
|
|
128
128
|
get isEncoderOpen(): boolean;
|
|
129
|
+
/**
|
|
130
|
+
* Get output stream information.
|
|
131
|
+
*
|
|
132
|
+
* Returns the encoder output format configuration.
|
|
133
|
+
* Useful for setting up subsequent processing stages.
|
|
134
|
+
*
|
|
135
|
+
* For hardware encoders, returns the hardware pixel format even before
|
|
136
|
+
* the first frame is encoded.
|
|
137
|
+
*
|
|
138
|
+
* @returns StreamInfo with encoder output properties
|
|
139
|
+
*/
|
|
140
|
+
getOutputStreamInfo(): StreamInfo;
|
|
129
141
|
/**
|
|
130
142
|
* Encode a frame and return a packet if available.
|
|
131
143
|
*
|
package/dist/api/encoder.js
CHANGED
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
*
|
|
10
10
|
* @module api/encoder
|
|
11
11
|
*/
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
12
|
+
import { AVERROR_EOF, AVMEDIA_TYPE_AUDIO, AVMEDIA_TYPE_VIDEO } from '../constants/constants.js';
|
|
13
|
+
import { AVERROR_EAGAIN, Codec, CodecContext, FFmpegError, Packet, Rational } from '../lib/index.js';
|
|
14
14
|
import { parseBitrate } from './utils.js';
|
|
15
15
|
/**
|
|
16
16
|
* High-level encoder for media streams.
|
|
@@ -73,8 +73,7 @@ export class Encoder {
|
|
|
73
73
|
isOpen = true;
|
|
74
74
|
supportedFormats = [];
|
|
75
75
|
preferredFormat;
|
|
76
|
-
hardware; // Store reference
|
|
77
|
-
isHardwareEncoder = false; // Track if this is a hardware encoder
|
|
76
|
+
hardware; // Store reference for hardware pixel format
|
|
78
77
|
/**
|
|
79
78
|
* Private constructor - use Encoder.create() instead.
|
|
80
79
|
*
|
|
@@ -82,7 +81,7 @@ export class Encoder {
|
|
|
82
81
|
*
|
|
83
82
|
* @param codecContext - Initialized codec context
|
|
84
83
|
* @param codecName - Name of the codec
|
|
85
|
-
* @param hardware - Optional hardware context for
|
|
84
|
+
* @param hardware - Optional hardware context for hardware pixel format
|
|
86
85
|
*/
|
|
87
86
|
constructor(codecContext, codecName, hardware) {
|
|
88
87
|
this.codecContext = codecContext;
|
|
@@ -101,7 +100,7 @@ export class Encoder {
|
|
|
101
100
|
* configures the context with provided options, and opens it.
|
|
102
101
|
* Handles hardware setup including shared frames context for zero-copy.
|
|
103
102
|
*
|
|
104
|
-
* @param
|
|
103
|
+
* @param encoderCodec - Codec to use for encoding
|
|
105
104
|
* @param input - Stream or StreamInfo to copy parameters from
|
|
106
105
|
* @param options - Encoder configuration options
|
|
107
106
|
*
|
|
@@ -126,89 +125,58 @@ export class Encoder {
|
|
|
126
125
|
*
|
|
127
126
|
* ```
|
|
128
127
|
*/
|
|
129
|
-
static async create(
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
128
|
+
static async create(encoderCodec, input, options = {}) {
|
|
129
|
+
let codec = null;
|
|
130
|
+
let codecName = '';
|
|
131
|
+
if (encoderCodec instanceof Codec) {
|
|
132
|
+
codec = encoderCodec;
|
|
133
|
+
codecName = codec.name ?? 'Unknown';
|
|
134
|
+
}
|
|
135
|
+
else if (typeof encoderCodec === 'string') {
|
|
136
|
+
codec = Codec.findEncoderByName(encoderCodec);
|
|
137
|
+
codecName = codec?.name ?? encoderCodec;
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
codec = Codec.findEncoder(encoderCodec);
|
|
141
|
+
codecName = codec?.name ?? encoderCodec.toString();
|
|
142
|
+
}
|
|
133
143
|
if (!codec) {
|
|
134
|
-
throw new Error(`Encoder ${
|
|
144
|
+
throw new Error(`Encoder ${codecName} not found`);
|
|
135
145
|
}
|
|
136
146
|
// Allocate codec context
|
|
137
147
|
const codecContext = new CodecContext();
|
|
138
148
|
codecContext.allocContext3(codec);
|
|
139
|
-
//
|
|
140
|
-
if (input
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
codecContext.
|
|
150
|
-
codecContext.timeBase = input.timeBase;
|
|
151
|
-
// Set framerate if available
|
|
152
|
-
if (input.avgFrameRate && input.avgFrameRate.num > 0 && input.avgFrameRate.den > 0) {
|
|
153
|
-
codecContext.framerate = new Rational(input.avgFrameRate.num, input.avgFrameRate.den);
|
|
154
|
-
}
|
|
155
|
-
else if (input.rFrameRate && input.rFrameRate.num > 0 && input.rFrameRate.den > 0) {
|
|
156
|
-
codecContext.framerate = new Rational(input.rFrameRate.num, input.rFrameRate.den);
|
|
157
|
-
}
|
|
158
|
-
// Copy sample aspect ratio if present
|
|
159
|
-
if (input.sampleAspectRatio && input.sampleAspectRatio.num > 0) {
|
|
160
|
-
codecContext.sampleAspectRatio = new Rational(input.sampleAspectRatio.num, input.sampleAspectRatio.den);
|
|
161
|
-
}
|
|
149
|
+
// It's StreamInfo - apply manually
|
|
150
|
+
if (input.type === 'video' && codec.type === AVMEDIA_TYPE_VIDEO) {
|
|
151
|
+
const videoInfo = input;
|
|
152
|
+
codecContext.width = videoInfo.width;
|
|
153
|
+
codecContext.height = videoInfo.height;
|
|
154
|
+
codecContext.pixelFormat = videoInfo.pixelFormat; // Will be overwritten if it's a hardware encoder
|
|
155
|
+
// Set pkt_timebase and timeBase to input timebase
|
|
156
|
+
codecContext.pktTimebase = new Rational(videoInfo.timeBase.num, videoInfo.timeBase.den);
|
|
157
|
+
codecContext.timeBase = new Rational(videoInfo.timeBase.num, videoInfo.timeBase.den);
|
|
158
|
+
if (videoInfo.frameRate) {
|
|
159
|
+
codecContext.framerate = new Rational(videoInfo.frameRate.num, videoInfo.frameRate.den);
|
|
162
160
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
codecContext.sampleRate = input.codecpar.sampleRate;
|
|
166
|
-
codecContext.sampleFormat = input.codecpar.format;
|
|
167
|
-
// Copy channel layout from input
|
|
168
|
-
// NOTE: This means the encoder will use the same channel configuration as the input
|
|
169
|
-
// If you need different channels, use an audio filter or pass StreamInfo instead
|
|
170
|
-
codecContext.channelLayout = input.codecpar.channelLayout;
|
|
171
|
-
// Set timing information
|
|
172
|
-
codecContext.pktTimebase = input.timeBase;
|
|
173
|
-
codecContext.timeBase = input.timeBase;
|
|
161
|
+
if (videoInfo.sampleAspectRatio) {
|
|
162
|
+
codecContext.sampleAspectRatio = new Rational(videoInfo.sampleAspectRatio.num, videoInfo.sampleAspectRatio.den);
|
|
174
163
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
164
|
+
}
|
|
165
|
+
else if (input.type === 'audio' && codec.type === AVMEDIA_TYPE_AUDIO) {
|
|
166
|
+
const audioInfo = input;
|
|
167
|
+
codecContext.sampleRate = audioInfo.sampleRate;
|
|
168
|
+
codecContext.sampleFormat = audioInfo.sampleFormat;
|
|
169
|
+
codecContext.channelLayout = audioInfo.channelLayout;
|
|
170
|
+
// Set both pkt_timebase and timeBase for audio
|
|
171
|
+
codecContext.pktTimebase = new Rational(audioInfo.timeBase.num, audioInfo.timeBase.den);
|
|
172
|
+
codecContext.timeBase = new Rational(audioInfo.timeBase.num, audioInfo.timeBase.den);
|
|
173
|
+
if (audioInfo.frameSize) {
|
|
174
|
+
codecContext.frameSize = audioInfo.frameSize;
|
|
178
175
|
}
|
|
179
176
|
}
|
|
180
177
|
else {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
const videoInfo = input;
|
|
184
|
-
codecContext.width = videoInfo.width;
|
|
185
|
-
codecContext.height = videoInfo.height;
|
|
186
|
-
codecContext.pixelFormat = videoInfo.pixelFormat;
|
|
187
|
-
// Set pkt_timebase and timeBase to input timebase
|
|
188
|
-
codecContext.pktTimebase = new Rational(videoInfo.timeBase.num, videoInfo.timeBase.den);
|
|
189
|
-
codecContext.timeBase = new Rational(videoInfo.timeBase.num, videoInfo.timeBase.den);
|
|
190
|
-
if (videoInfo.frameRate) {
|
|
191
|
-
codecContext.framerate = new Rational(videoInfo.frameRate.num, videoInfo.frameRate.den);
|
|
192
|
-
}
|
|
193
|
-
if (videoInfo.sampleAspectRatio) {
|
|
194
|
-
codecContext.sampleAspectRatio = new Rational(videoInfo.sampleAspectRatio.num, videoInfo.sampleAspectRatio.den);
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
else if (input.type === 'audio' && codec.type === AVMEDIA_TYPE_AUDIO) {
|
|
198
|
-
const audioInfo = input;
|
|
199
|
-
codecContext.sampleRate = audioInfo.sampleRate;
|
|
200
|
-
codecContext.sampleFormat = audioInfo.sampleFormat;
|
|
201
|
-
codecContext.channelLayout = audioInfo.channelLayout;
|
|
202
|
-
// Set both pkt_timebase and timeBase for audio
|
|
203
|
-
codecContext.pktTimebase = new Rational(audioInfo.timeBase.num, audioInfo.timeBase.den);
|
|
204
|
-
codecContext.timeBase = new Rational(audioInfo.timeBase.num, audioInfo.timeBase.den);
|
|
205
|
-
if (audioInfo.frameSize) {
|
|
206
|
-
codecContext.frameSize = audioInfo.frameSize;
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
else {
|
|
210
|
-
throw new Error(`Codec type mismatch: ${input.type} info but ${codec.type === AVMEDIA_TYPE_VIDEO ? 'video' : 'audio'} codec`);
|
|
211
|
-
}
|
|
178
|
+
codecContext.freeContext();
|
|
179
|
+
throw new Error(`Unsupported codec type for encoder! Input type: ${input.type}, Codec type: ${codec.type}`);
|
|
212
180
|
}
|
|
213
181
|
// Apply encoder-specific options
|
|
214
182
|
if (options.gopSize !== undefined) {
|
|
@@ -235,47 +203,17 @@ export class Encoder {
|
|
|
235
203
|
codecContext.setOption(key, value.toString());
|
|
236
204
|
}
|
|
237
205
|
}
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
// Check encoder's hardware configurations
|
|
242
|
-
for (let i = 0;; i++) {
|
|
243
|
-
const config = codec.getHwConfig(i);
|
|
244
|
-
if (!config)
|
|
245
|
-
break;
|
|
246
|
-
// Check if encoder supports HW_FRAMES_CTX method
|
|
247
|
-
if ((config.methods & AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX) !== 0) {
|
|
248
|
-
supportsHardware = true;
|
|
249
|
-
// If hardware context provided, check if it matches this encoder
|
|
250
|
-
if (options.hardware && config.deviceType === options.hardware.deviceType) {
|
|
251
|
-
isHardwareEncoder = true;
|
|
252
|
-
break;
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
// Validation: Hardware encoder MUST have HardwareContext
|
|
257
|
-
if (supportsHardware && !options.hardware) {
|
|
258
|
-
throw new Error(`Hardware encoder '${actualCodecName}' requires a hardware context. ` + 'Please provide one via options.hardware');
|
|
259
|
-
}
|
|
260
|
-
// Apply hardware acceleration if provided and encoder supports it
|
|
261
|
-
if (options.hardware && isHardwareEncoder) {
|
|
262
|
-
// Check if frames context already available (shared from decoder)
|
|
263
|
-
if (options.hardware.framesContext) {
|
|
264
|
-
codecContext.hwFramesCtx = options.hardware.framesContext;
|
|
265
|
-
codecContext.pixelFormat = options.hardware.getHardwarePixelFormat();
|
|
266
|
-
}
|
|
267
|
-
// Else: Will set hwFramesCtx later in encode() when first frame arrives
|
|
268
|
-
// DO NOT create frames context here - wait for first frame!
|
|
206
|
+
const isHWEncoder = codec.isHardwareAcceleratedEncoder();
|
|
207
|
+
if (isHWEncoder && !options.hardware) {
|
|
208
|
+
throw new Error(`Hardware encoder '${codecName}' requires a hardware context`);
|
|
269
209
|
}
|
|
270
|
-
// Note: Software encoder silently ignores hardware context
|
|
271
210
|
// Open codec
|
|
272
211
|
const openRet = await codecContext.open2(codec, null);
|
|
273
212
|
if (openRet < 0) {
|
|
274
213
|
codecContext.freeContext();
|
|
275
214
|
FFmpegError.throwIfError(openRet, 'Failed to open encoder');
|
|
276
215
|
}
|
|
277
|
-
const encoder = new Encoder(codecContext, codecName,
|
|
278
|
-
encoder.isHardwareEncoder = isHardwareEncoder;
|
|
216
|
+
const encoder = new Encoder(codecContext, codecName, isHWEncoder ? options.hardware : undefined);
|
|
279
217
|
// Get supported formats from codec (for validation and helpers)
|
|
280
218
|
if (codec.pixelFormats) {
|
|
281
219
|
encoder.supportedFormats = codec.pixelFormats;
|
|
@@ -289,6 +227,43 @@ export class Encoder {
|
|
|
289
227
|
get isEncoderOpen() {
|
|
290
228
|
return this.isOpen;
|
|
291
229
|
}
|
|
230
|
+
/**
|
|
231
|
+
* Get output stream information.
|
|
232
|
+
*
|
|
233
|
+
* Returns the encoder output format configuration.
|
|
234
|
+
* Useful for setting up subsequent processing stages.
|
|
235
|
+
*
|
|
236
|
+
* For hardware encoders, returns the hardware pixel format even before
|
|
237
|
+
* the first frame is encoded.
|
|
238
|
+
*
|
|
239
|
+
* @returns StreamInfo with encoder output properties
|
|
240
|
+
*/
|
|
241
|
+
getOutputStreamInfo() {
|
|
242
|
+
if (this.codecContext.codecType === AVMEDIA_TYPE_VIDEO) {
|
|
243
|
+
// For hardware encoders, we need to return the hardware pixel format
|
|
244
|
+
// even if it hasn't been set yet on the codec context
|
|
245
|
+
const pixelFormat = this.hardware?.getHardwarePixelFormat() ?? this.codecContext.pixelFormat;
|
|
246
|
+
return {
|
|
247
|
+
type: 'video',
|
|
248
|
+
width: this.codecContext.width,
|
|
249
|
+
height: this.codecContext.height,
|
|
250
|
+
pixelFormat,
|
|
251
|
+
timeBase: this.codecContext.timeBase,
|
|
252
|
+
frameRate: this.codecContext.framerate,
|
|
253
|
+
sampleAspectRatio: this.codecContext.sampleAspectRatio,
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
// For audio
|
|
258
|
+
return {
|
|
259
|
+
type: 'audio',
|
|
260
|
+
sampleRate: this.codecContext.sampleRate,
|
|
261
|
+
sampleFormat: this.codecContext.sampleFormat,
|
|
262
|
+
channelLayout: this.codecContext.channelLayout,
|
|
263
|
+
timeBase: this.codecContext.timeBase,
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
}
|
|
292
267
|
/**
|
|
293
268
|
* Encode a frame and return a packet if available.
|
|
294
269
|
*
|
|
@@ -317,24 +292,13 @@ export class Encoder {
|
|
|
317
292
|
if (!this.isOpen) {
|
|
318
293
|
throw new Error('Encoder is closed');
|
|
319
294
|
}
|
|
320
|
-
// Late binding of hw_frames_ctx
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
else if (frame?.width && frame.height) {
|
|
327
|
-
// First frame - create frames context for upload
|
|
328
|
-
this.hardware.ensureFramesContext(frame.width, frame.height);
|
|
329
|
-
this.codecContext.hwFramesCtx = this.hardware.framesContext ?? null;
|
|
330
|
-
}
|
|
331
|
-
if (this.codecContext.hwFramesCtx) {
|
|
332
|
-
this.codecContext.pixelFormat = this.hardware.getHardwarePixelFormat();
|
|
333
|
-
}
|
|
295
|
+
// Late binding of hw_frames_ctx for hardware encoders
|
|
296
|
+
// Hardware encoders get hw_frames_ctx from the frames they receive
|
|
297
|
+
if (this.hardware && frame?.hwFramesCtx && !this.codecContext.hwFramesCtx) {
|
|
298
|
+
// Use the hw_frames_ctx from the frame
|
|
299
|
+
this.codecContext.hwFramesCtx = frame.hwFramesCtx;
|
|
300
|
+
this.codecContext.pixelFormat = this.hardware.getHardwarePixelFormat();
|
|
334
301
|
}
|
|
335
|
-
// Software encoder completely ignores hardware context
|
|
336
|
-
// NO MANUAL RESCALING! FFmpeg's avcodec_send_frame() does this internally
|
|
337
|
-
// The encoder needs pkt_timebase to be set for proper rescaling
|
|
338
302
|
// Send frame to encoder
|
|
339
303
|
const sendRet = await this.codecContext.sendFrame(frame);
|
|
340
304
|
if (sendRet < 0 && sendRet !== AVERROR_EOF) {
|