File size: 3,692 Bytes
11fcc5a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
import LibAVWrapper from "$lib/libav";
import type { FileInfo } from "$lib/types/libav";

const ffmpeg = async (
    variant: string,
    files: File[],
    args: string[],
    output: FileInfo,
    yesthreads: boolean = false,
) => {
    if (!(files && output && args)) {
        self.postMessage({
            cobaltFFmpegWorker: {
                error: "queue.ffmpeg.no_args",
            }
        });
        return;
    }

    const ff = new LibAVWrapper((progress) => {
        self.postMessage({
            cobaltFFmpegWorker: {
                progress: {
                    durationProcessed: progress.out_time_sec,
                    speed: progress.speed,
                    size: progress.total_size,
                    currentFrame: progress.frame,
                    fps: progress.fps,
                }
            }
        })
    });

    ff.init({ variant, yesthreads });

    const error = (code: string) => {
        self.postMessage({
            cobaltFFmpegWorker: {
                error: code,
            }
        });
        ff.terminate();
    }

    try {
        // probing just the first file in files array (usually audio) for duration progress
        const probeFile = files[0];
        if (!probeFile) {
            return error("queue.ffmpeg.probe_failed");
        }

        let file_info;

        try {
            file_info = await ff.probe(probeFile);
        } catch (e) {
            console.error("error from ffmpeg worker @ file_info:");
            if (e instanceof Error && e?.message?.toLowerCase().includes("out of memory")) {
                console.error(e);

                error("queue.ffmpeg.out_of_memory");
                return self.close();
            } else {
                console.error(e);
                return error("queue.ffmpeg.probe_failed");
            }
        }

        if (!file_info?.format) {
            return error("queue.ffmpeg.no_input_format");
        }

        // handle the edge case when a video doesn't have an audio track
        // but user still tries to extract it
        if (files.length === 1 && file_info.streams?.length === 1) {
            if (output.type?.startsWith("audio") && file_info.streams[0].codec_type !== "audio") {
                return error("queue.ffmpeg.no_audio_channel");
            }
        }

        self.postMessage({
            cobaltFFmpegWorker: {
                progress: {
                    duration: Number(file_info.format.duration),
                }
            }
        });

        for (const file of files) {
            if (!file.type) {
                return error("queue.ffmpeg.no_input_type");
            }
        }

        let render;

        try {
            render = await ff.render({
                files,
                output,
                args,
            });
        } catch (e) {
            console.error("error from the ffmpeg worker @ render:");
            console.error(e);
            // TODO: more granular error codes
            return error("queue.ffmpeg.crashed");
        }

        if (!render) {
            return error("queue.ffmpeg.no_render");
        }

        await ff.terminate();

        self.postMessage({
            cobaltFFmpegWorker: {
                render
            }
        });
    } catch (e) {
        console.error("error from the ffmpeg worker:")
        console.error(e);
        return error("queue.ffmpeg.crashed");
    }
}

self.onmessage = async (event: MessageEvent) => {
    const ed = event.data.cobaltFFmpegWorker;
    if (ed?.variant && ed?.files && ed?.args && ed?.output) {
        await ffmpeg(ed.variant, ed.files, ed.args, ed.output, ed.yesthreads);
    }
}