Reorg folders and use core as ffmpeg from now on
This commit is contained in:
15
src/bind/.eslintrc.cjs
Normal file
15
src/bind/.eslintrc.cjs
Normal file
@@ -0,0 +1,15 @@
|
||||
module.exports = {
|
||||
extends: "eslint:recommended",
|
||||
rules: {
|
||||
"@typescript-eslint/no-empty-function": 0,
|
||||
"@typescript-eslint/no-unsafe-assignment": 0,
|
||||
"@typescript-eslint/restrict-plus-operands": 0,
|
||||
"@typescript-eslint/no-unsafe-call": 0,
|
||||
"@typescript-eslint/no-unsafe-return": 0,
|
||||
"@typescript-eslint/no-unsafe-member-access": 0,
|
||||
},
|
||||
globals: {
|
||||
Module: true,
|
||||
console: true,
|
||||
},
|
||||
};
|
||||
@@ -1,3 +0,0 @@
|
||||
const EXPORTED_FUNCTIONS = ["_ffmpeg"];
|
||||
|
||||
console.log(EXPORTED_FUNCTIONS.join(","));
|
||||
96
src/bind/ffmpeg/bind.js
Normal file
96
src/bind/ffmpeg/bind.js
Normal file
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* Constants
|
||||
*/
|
||||
|
||||
const NULL = 0;
|
||||
const SIZE_I32 = Uint32Array.BYTES_PER_ELEMENT;
|
||||
const DEFAULT_ARGS = ["./ffmpeg", "-nostdin", "-y"];
|
||||
|
||||
Module["NULL"] = NULL;
|
||||
Module["SIZE_I32"] = SIZE_I32;
|
||||
Module["DEFAULT_ARGS"] = DEFAULT_ARGS;
|
||||
|
||||
/**
|
||||
* Variables
|
||||
*/
|
||||
|
||||
Module["ret"] = -1;
|
||||
Module["timeout"] = -1;
|
||||
Module["logger"] = () => {};
|
||||
Module["progress"] = () => {};
|
||||
|
||||
/**
|
||||
* Functions
|
||||
*/
|
||||
|
||||
function stringToPtr(str) {
|
||||
const len = Module["lengthBytesUTF8"](str) + 1;
|
||||
const ptr = Module["_malloc"](len);
|
||||
Module["stringToUTF8"](str, ptr, len);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
function stringsToPtr(strs) {
|
||||
const len = strs.length;
|
||||
const ptr = Module["_malloc"](len * SIZE_I32);
|
||||
for (let i = 0; i < len; i++) {
|
||||
Module["setValue"](ptr + SIZE_I32 * i, stringToPtr(strs[i]), "i32");
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
function print(message) {
|
||||
Module["logger"]({ type: "stdout", message });
|
||||
}
|
||||
|
||||
function printErr(message) {
|
||||
if (!message.startsWith("Aborted(native code called abort())"))
|
||||
Module["logger"]({ type: "stderr", message });
|
||||
}
|
||||
|
||||
function exec(_args) {
|
||||
const args = [...Module["DEFAULT_ARGS"], ..._args];
|
||||
try {
|
||||
Module["_ffmpeg"](args.length, stringsToPtr(args));
|
||||
} catch (e) {
|
||||
if (!e.message.startsWith("Aborted")) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
return Module["ret"];
|
||||
}
|
||||
|
||||
function setLogger(logger) {
|
||||
Module["logger"] = logger;
|
||||
}
|
||||
|
||||
function setTimeout(timeout) {
|
||||
Module["timeout"] = timeout;
|
||||
}
|
||||
|
||||
function setProgress(handler) {
|
||||
Module["progress"] = handler;
|
||||
}
|
||||
|
||||
function receiveProgress(progress) {
|
||||
Module["progress"](progress);
|
||||
}
|
||||
|
||||
function reset() {
|
||||
Module["ret"] = -1;
|
||||
Module["timeout"] = -1;
|
||||
}
|
||||
|
||||
Module["stringToPtr"] = stringToPtr;
|
||||
Module["stringsToPtr"] = stringsToPtr;
|
||||
Module["print"] = print;
|
||||
Module["printErr"] = printErr;
|
||||
|
||||
Module["exec"] = exec;
|
||||
Module["setLogger"] = setLogger;
|
||||
Module["setTimeout"] = setTimeout;
|
||||
Module["setProgress"] = setProgress;
|
||||
Module["reset"] = reset;
|
||||
Module["receiveProgress"] = receiveProgress;
|
||||
3
src/bind/ffmpeg/export.js
Normal file
3
src/bind/ffmpeg/export.js
Normal file
@@ -0,0 +1,3 @@
|
||||
const EXPORTED_FUNCTIONS = ["_ffmpeg", "_abort"];
|
||||
|
||||
console.log(EXPORTED_FUNCTIONS.join(","));
|
||||
4
src/fftools/Makefile
Normal file
4
src/fftools/Makefile
Normal file
@@ -0,0 +1,4 @@
|
||||
all: build
|
||||
|
||||
build:
|
||||
cd ../../ && make
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <math.h>
|
||||
#include <emscripten.h>
|
||||
|
||||
/* Include only the enabled headers since some compilers (namely, Sun
|
||||
Studio) will not omit unused inline functions and create undefined
|
||||
@@ -95,7 +96,23 @@ void exit_program(int ret)
|
||||
if (program_exit)
|
||||
program_exit(ret);
|
||||
|
||||
exit(ret);
|
||||
/*
|
||||
* abort() is used instead of exit() because exit() not only
|
||||
* terminates ffmpeg but also the whole node.js program, which
|
||||
* is not ideal.
|
||||
*
|
||||
* abort() terminiates the ffmpeg with an JS exception
|
||||
*
|
||||
* RuntimeError: Aborted...
|
||||
*
|
||||
* This excpetion is catch and not visible to users.
|
||||
*
|
||||
*/
|
||||
EM_ASM({
|
||||
Module.ret = $0;
|
||||
}, ret);
|
||||
abort();
|
||||
// exit(ret);
|
||||
}
|
||||
|
||||
double parse_number_or_die(const char *context, const char *numstr, int type,
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <limits.h>
|
||||
#include <stdatomic.h>
|
||||
#include <stdint.h>
|
||||
#include <emscripten.h>
|
||||
|
||||
#if HAVE_IO_H
|
||||
#include <io.h>
|
||||
@@ -1504,6 +1505,10 @@ static void print_final_stats(int64_t total_size)
|
||||
}
|
||||
}
|
||||
|
||||
EM_JS(void, send_progress, (double progress), {
|
||||
Module.receiveProgress(progress);
|
||||
});
|
||||
|
||||
static void print_report(int is_last_report, int64_t timer_start, int64_t cur_time)
|
||||
{
|
||||
AVBPrint buf, buf_script;
|
||||
@@ -1629,6 +1634,24 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti
|
||||
nb_frames_drop += ost->last_dropped;
|
||||
}
|
||||
|
||||
/* send_progress here only works when the duration of
|
||||
* input and output file are the same, other cases (ex. trim)
|
||||
* still WIP.
|
||||
*
|
||||
* TODO: support cases like trim.
|
||||
*/
|
||||
int64_t duration = -1;
|
||||
int64_t pts_abs = FFABS(pts);
|
||||
/* Use the longest duration among all input files.
|
||||
*/
|
||||
for (int i = 0; i < nb_input_files; i++) {
|
||||
int64_t file_duration = input_files[i]->ctx->duration;
|
||||
if (file_duration > duration) {
|
||||
duration = file_duration;
|
||||
}
|
||||
}
|
||||
send_progress((double)pts_abs / (double)duration);
|
||||
|
||||
secs = FFABS(pts) / AV_TIME_BASE;
|
||||
us = FFABS(pts) % AV_TIME_BASE;
|
||||
mins = secs / 60;
|
||||
@@ -1710,8 +1733,11 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti
|
||||
|
||||
first_report = 0;
|
||||
|
||||
if (is_last_report)
|
||||
print_final_stats(total_size);
|
||||
if (is_last_report) {
|
||||
// Make sure the progress is ended with 1.
|
||||
if (pts_abs != duration) send_progress(1);
|
||||
print_final_stats(total_size);
|
||||
}
|
||||
}
|
||||
|
||||
static int ifilter_parameters_from_codecpar(InputFilter *ifilter, AVCodecParameters *par)
|
||||
@@ -4321,6 +4347,16 @@ static int transcode_step(void)
|
||||
return reap_filters(0);
|
||||
}
|
||||
|
||||
/* is_timeout checks if transcode() is running longer
|
||||
* than a timeout value, return 1 when timeout.
|
||||
*/
|
||||
EM_JS(int, is_timeout, (int64_t diff), {
|
||||
if (Module.timeout === -1) return 0;
|
||||
else {
|
||||
return Module.timeout <= diff;
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* The following code is the main loop of the file converter
|
||||
*/
|
||||
@@ -4351,6 +4387,8 @@ static int transcode(void)
|
||||
while (!received_sigterm) {
|
||||
int64_t cur_time= av_gettime_relative();
|
||||
|
||||
if (is_timeout((cur_time - timer_start) / 1000) == 1) exit_program(1);
|
||||
|
||||
/* if 'q' pressed, exits */
|
||||
if (stdin_interaction)
|
||||
if (check_keyboard_interaction(cur_time) < 0)
|
||||
@@ -4513,8 +4551,55 @@ static int64_t getmaxrss(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
/* init_globals initializes global variables to enable multiple
|
||||
* calls of ffmpeg().
|
||||
*
|
||||
* This is not required in the original command line version as
|
||||
* the global varialbes are always re-initialized when calling
|
||||
* main() function.
|
||||
*/
|
||||
void init_globals() {
|
||||
nb_frames_dup = 0;
|
||||
dup_warning = 1000;
|
||||
nb_frames_drop = 0;
|
||||
nb_output_dumped = 0;
|
||||
want_sdp = 1;
|
||||
|
||||
progress_avio = NULL;
|
||||
|
||||
input_streams = NULL;
|
||||
nb_input_streams = 0;
|
||||
input_files = NULL;
|
||||
nb_input_files = 0;
|
||||
|
||||
output_streams = NULL;
|
||||
nb_output_streams = 0;
|
||||
output_files = NULL;
|
||||
nb_output_files = 0;
|
||||
|
||||
filtergraphs = NULL;
|
||||
nb_filtergraphs = 0;
|
||||
|
||||
received_sigterm = 0;
|
||||
received_nb_signals = 0;
|
||||
transcode_init_done = ATOMIC_VAR_INIT(0);
|
||||
ffmpeg_exited = 0;
|
||||
main_return_code = 0;
|
||||
copy_ts_first_pts = AV_NOPTS_VALUE;
|
||||
}
|
||||
|
||||
/* ffmpeg() is simply a rename of main(), but it makes things easier to
|
||||
* control as main() is a special function name that might trigger
|
||||
* some hidden mechanisms.
|
||||
*
|
||||
* One example is that when using multi-threading, a proxy_main() function
|
||||
* might be used instead of main().
|
||||
*/
|
||||
int ffmpeg(int argc, char **argv)
|
||||
// int main(int argc, char **argv)
|
||||
{
|
||||
init_globals();
|
||||
|
||||
int i, ret;
|
||||
BenchmarkTimeStamps ti;
|
||||
|
||||
|
||||
10
src/types/core/ffmpeg-core.d.ts
vendored
10
src/types/core/ffmpeg-core.d.ts
vendored
@@ -1,10 +0,0 @@
|
||||
/// <reference types="emscripten" />
|
||||
|
||||
type Pointer = number;
|
||||
type StringArrayPointer = Pointer;
|
||||
|
||||
interface FFmpegCoreModule extends EmscriptenModule {
|
||||
_ffmpeg: (number, StringArrayPointer) => number;
|
||||
}
|
||||
declare const createFFmpegCore: EmscriptenModuleFactory<FFmpegCoreModule>;
|
||||
export default createFFmpegCore;
|
||||
39
src/types/ffmpeg/ffmpeg.d.ts
vendored
Normal file
39
src/types/ffmpeg/ffmpeg.d.ts
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
type Pointer = number;
|
||||
type StringPointer = Pointer;
|
||||
type StringArrayPointer = Pointer;
|
||||
|
||||
export interface FS {
|
||||
mkdir: (fileName: string) => void;
|
||||
readFile: (fileName: string) => Uint8Array;
|
||||
readdir: (pathName: string) => string[];
|
||||
unlink: (fileName: string) => void;
|
||||
writeFile: (fileName: string, binaryData: Uint8Array | string) => void;
|
||||
}
|
||||
|
||||
export interface Log {
|
||||
type: string;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export interface FFmpegModule {
|
||||
DEFAULT_ARGS: string[];
|
||||
FS: FS;
|
||||
NULL: Pointer;
|
||||
SIZE_I32: number;
|
||||
|
||||
ret: number;
|
||||
timeout: number;
|
||||
|
||||
exec: (args: string[]) => number;
|
||||
reset: () => void;
|
||||
setLogger: (logger: (log: Log) => void) => void;
|
||||
setTimeout: (timeout: number) => void;
|
||||
setProgress: (handler: (progress: number) => void) => void;
|
||||
|
||||
_ffmpeg: (args: number, argv: StringArrayPointer) => number;
|
||||
stringToPtr: (str: string) => Pointer;
|
||||
stringsToPtr: (strs: string[]) => Pointer;
|
||||
}
|
||||
|
||||
declare function createFFmpeg(): Promise<FFmpegModule>;
|
||||
export default createFFmpeg;
|
||||
Reference in New Issue
Block a user