-
-
Notifications
You must be signed in to change notification settings - Fork 21
Expand file tree
/
Copy pathapi-sw-transcode.ts
More file actions
105 lines (88 loc) · 3.13 KB
/
Copy pathapi-sw-transcode.ts
File metadata and controls
105 lines (88 loc) · 3.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
/**
* Full Software Transcode Example
*
* This example demonstrates:
* - Software decoding (CPU)
* - Software encoding (CPU)
* - Maximum compatibility and control
*
* Use case: When you need maximum compatibility, specific codec features,
* or when hardware acceleration is not available
*
* Usage: tsx api-sw-transcode.ts <input> <output>
* Example: tsx examples/api-sw-transcode.ts testdata/video.mp4 examples/.tmp/api-sw-transcode.mp4
*/
import { Decoder, Demuxer, Encoder, FF_ENCODER_LIBX264, Muxer } from '../src/index.js';
const inputFile = process.argv[2];
const outputFile = process.argv[3];
if (!inputFile || !outputFile) {
console.log('Usage: tsx api-sw-transcode.ts <input> <output>');
console.log('Example: tsx api-sw-transcode.ts input.mp4 output.mp4');
process.exit(1);
}
console.log(`Input: ${inputFile}`);
console.log(`Output: ${outputFile}`);
// Open input file
await using input = await Demuxer.open(inputFile);
const videoStream = input.video();
const audioStream = input.audio();
if (!videoStream) {
throw new Error('No video stream found in input file');
}
console.log('Input Information:');
console.log(`Format: ${input.formatLongName}`);
console.log(`Duration: ${input.duration.toFixed(2)} seconds`);
console.log(`Video: ${videoStream.codecpar.width}x${videoStream.codecpar.height}`);
if (audioStream) {
console.log(`Audio: ${audioStream.codecpar.sampleRate}Hz, ${audioStream.codecpar.channels} channels`);
}
// Create software decoder (CPU)
console.log('Setting up software decoder...');
const decoder = await Decoder.create(videoStream);
// Create software encoder (CPU)
console.log('Setting up software encoder...');
const encoder = await Encoder.create(FF_ENCODER_LIBX264, {
decoder,
bitrate: '2M',
gopSize: 60,
options: {
preset: 'medium',
crf: 23,
profile: 'high',
level: '4.1',
},
});
// Create output using Muxer
await using output = await Muxer.open(outputFile);
const outputStreamIndex = output.addStream(encoder);
// Process video
console.log('🎥 Processing video...');
console.log(' Pure software pipeline: CPU decode → CPU encode');
console.log('');
let frameCount = 0;
let packetCount = 0;
const startTime = Date.now();
for await (using packet of input.packets(videoStream.index)) {
// Software decode → Software encode
for await (using frame of decoder.frames(packet)) {
if (frame) frameCount++;
// Software encode (null passes through to flush encoder)
for await (using encodedPacket of encoder.packets(frame)) {
await output.writePacket(encodedPacket, outputStreamIndex);
if (encodedPacket) packetCount++;
}
// Progress indicator
if (frameCount % 30 === 0) {
const elapsed = (Date.now() - startTime) / 1000;
const fps = frameCount / elapsed;
console.log(`Processed ${frameCount} frames @ ${fps.toFixed(1)} fps`);
}
}
}
const elapsed = (Date.now() - startTime) / 1000;
const avgFps = frameCount / elapsed;
console.log('Done!');
console.log(`Frames processed: ${frameCount}`);
console.log(`Packets written: ${packetCount}`);
console.log(`Time: ${elapsed.toFixed(2)} seconds`);
console.log(`Average FPS: ${avgFps.toFixed(1)}`);