From fd2a75dce23222e22abf4273c7c75a3bd0df196f Mon Sep 17 00:00:00 2001 From: yizhi <946185759@qq.com> Date: Wed, 26 Mar 2025 19:00:28 +0800 Subject: [PATCH] =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E6=90=AD=E5=BB=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 6 +++ CMakeLists.txt | 96 +++++++++++++++++++++++++++++++++++ README.md | 25 +++++++++ cxx/main.cc | 28 ++++++++++ package.json | 20 ++++++++ thirdpart/build_ffmpeg_win.js | 82 ++++++++++++++++++++++++++++++ thirdpart/cmake-js-util.js | 19 +++++++ 7 files changed, 276 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 README.md create mode 100644 cxx/main.cc create mode 100644 package.json create mode 100644 thirdpart/build_ffmpeg_win.js create mode 100644 thirdpart/cmake-js-util.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7e59bff --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +/.vscode +/build +/node_modules +/thirdpart/_source +/thirdpart/FFmpeg +/package-lock.json diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..61425bf --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,96 @@ +cmake_minimum_required(VERSION 3.10.0) +project(ai-box VERSION 0.1.0 LANGUAGES C CXX) +set(CMAKE_CXX_STANDARD 17) + +if (POLICY CMP0091) +cmake_policy(SET CMP0091 NEW) +endif (POLICY CMP0091) + +if(NOT DEFINED CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release) +endif() + +set(NODE_ADDON_FOUND OFF) + +include_directories(cxx) + +# FFmpeg +set(FFMPEG_CMAKE_FILE ${CMAKE_SOURCE_DIR}/thirdpart/FFmpeg/config.cmake) +if(EXISTS ${FFMPEG_CMAKE_FILE}) + include(${FFMPEG_CMAKE_FILE}) + message(STATUS "FFMPEG_LIB_DIR: ${FFMPEG_LIB_DIR}") + message(STATUS "FFMPEG_INCLUDE_DIR: ${FFMPEG_INCLUDE_DIR}") + message(STATUS "FFMPEG_LIBS: ${FFMPEG_LIBS}") + include_directories(${FFMPEG_INCLUDE_DIR}) + link_directories(${FFMPEG_LIB_DIR}) +else() + message(FATAL_ERROR "FFmpeg not found") +endif() + +# NodeJS +execute_process( + COMMAND node ${CMAKE_SOURCE_DIR}/thirdpart/cmake-js-util.js --include + RESULT_VARIABLE CMAKE_JS_RESULT + OUTPUT_VARIABLE CMAKE_JS_INC + OUTPUT_STRIP_TRAILING_WHITESPACE +) +if(CMAKE_JS_RESULT EQUAL 0) + execute_process( + COMMAND node ${CMAKE_SOURCE_DIR}/thirdpart/cmake-js-util.js --src + RESULT_VARIABLE CMAKE_JS_RESULT + OUTPUT_VARIABLE CMAKE_JS_SRC + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + if(CMAKE_JS_RESULT EQUAL 0) + execute_process( + COMMAND node ${CMAKE_SOURCE_DIR}/thirdpart/cmake-js-util.js --lib + RESULT_VARIABLE CMAKE_JS_RESULT + OUTPUT_VARIABLE CMAKE_JS_LIB + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + endif() + # ReleaseVersion + if(CMAKE_JS_RESULT EQUAL 0) + execute_process( + COMMAND node ${CMAKE_SOURCE_DIR}/thirdpart/cmake-js-util.js --release + RESULT_VARIABLE CMAKE_JS_RESULT + OUTPUT_VARIABLE RELEASE_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + if(CMAKE_JS_RESULT EQUAL 0) + message(STATUS "RELEASE_VERSION: ${RELEASE_VERSION}") + add_compile_definitions(RELEASE_VERSION="${RELEASE_VERSION}") + endif() + endif() + + # NAPI + if(CMAKE_JS_RESULT EQUAL 0) + execute_process( + COMMAND node ${CMAKE_SOURCE_DIR}/thirdpart/cmake-js-util.js --napi + RESULT_VARIABLE CMAKE_JS_RESULT + OUTPUT_VARIABLE NODE_ADDON_API_DIR + ) + endif() + if(CMAKE_JS_RESULT EQUAL 0) + message(STATUS "CMAKE_JS_INC: ${CMAKE_JS_INC}") + message(STATUS "CMAKE_JS_SRC: ${CMAKE_JS_SRC}") + message(STATUS "CMAKE_JS_LIB: ${CMAKE_JS_LIB}") + message(STATUS "NODE_ADDON_API_DIR: ${NODE_ADDON_API_DIR}") + include_directories(${CMAKE_JS_INC} ${NODE_ADDON_API_DIR}) + set(NODE_ADDON_FOUND ON) + endif() +endif() +if(NOT (CMAKE_JS_RESULT EQUAL 0)) + message(FATAL_ERROR "cmake js config failed") +endif() + + +# 平台特定的库 +if(MSVC) + set(PLATFORM_LIBS ws2_32 winmm strmiids mfplat mfuuid Ws2_32 Secur32 Bcrypt) +endif() + +include_directories(thirdpart/FFmpeg/include) +link_directories(thirdpart/FFmpeg/lib) +add_executable(ffmpeg cxx/main.cc) +target_link_libraries(ffmpeg ${PLATFORM_LIBS} ${FFMPEG_LIBS}) diff --git a/README.md b/README.md new file mode 100644 index 0000000..2f84e08 --- /dev/null +++ b/README.md @@ -0,0 +1,25 @@ + +## Windows下的FFmpeg 编译 + +1. 安装msys2 + + 从 https://www.msys2.org 下载Windows安装包进行安装。 + +1. 安装 Visual Studio Build Tools + +1. 打开构建工具(x64),并启动msys2。 + + 可以在msys2的安装目录下新建一个`msvc_build.bat`,并输入以下内容: + ``` + call "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Auxiliary\Build\vcvars64.bat" + msys2_shell.cmd -mingw64 + ``` + +1. 安装依赖库 + +1. 编译项目 + 在msys2中执行: + ``` + cd /path/to/project + node thirdpart/build_ffmpeg_win.js + ``` diff --git a/cxx/main.cc b/cxx/main.cc new file mode 100644 index 0000000..fb0f9f2 --- /dev/null +++ b/cxx/main.cc @@ -0,0 +1,28 @@ +#include +// #pragma comment(lib, "ws2_32.lib") +// #pragma comment(lib, "winmm.lib") +// #pragma comment(lib, "strmiids") +// #pragma comment(lib, "mfplat") +// #pragma comment(lib, "mfuuid") +// #pragma comment(lib, "Ws2_32") +// #pragma comment(lib, "Secur32") +// #pragma comment(lib, "Bcrypt") + +#ifdef __cplusplus +extern "C" +{ +#endif +#include +#ifdef __cplusplus +} +#endif + +int main(int, char **) +{ + AVFormatContext *ifmt_ctx = nullptr; + if (avformat_open_input(&ifmt_ctx, "http://vjs.zencdn.net/v/oceans.mp4", nullptr, nullptr) < 0) + printf("avformat_open_input failed\n"); + printf("nb_stream=%d\n", ifmt_ctx->nb_streams); + + std::cout << "Hello, from ffmpeg!\n"; +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..3dd1a21 --- /dev/null +++ b/package.json @@ -0,0 +1,20 @@ +{ + "name": "@yizhi/ffmpeg", + "version": "1.0.1", + "releaseVersion": "1.0.1", + "main": "dist/index.js", + "types": "typing/index.d.ts", + "scripts": { + "build": "rm -rf dist typing && tsc", + "watch": "tsc -w --inlineSourceMap" + }, + "keywords": [], + "author": "", + "license": "ISC", + "description": "", + "devDependencies": { + "@types/node": "^22.13.5", + "cmake-js": "^7.3.0", + "node-addon-api": "^8.3.1" + } + } \ No newline at end of file diff --git a/thirdpart/build_ffmpeg_win.js b/thirdpart/build_ffmpeg_win.js new file mode 100644 index 0000000..9299adc --- /dev/null +++ b/thirdpart/build_ffmpeg_win.js @@ -0,0 +1,82 @@ +const { spawnSync } = require("child_process"); +const fs = require("fs"); +const path = require("path"); +const os = require("os"); + +const FFMPEG_REPO = "https://git.ffmpeg.org/ffmpeg.git"; +const FFMPEG_TAG = "release/7.1" +const FFMPEG_SOURCE_DIR = path.join(__dirname, "_source/FFmpeg"); +const FFMPEG_INSTALL_DIR = path.join(__dirname, "FFmpeg"); + +function checkEnv() { + if (!process.env.MSYSTEM_PREFIX) throw new Error("Please use msys2 environment to run this script"); + const bash = process.env.SHELL; + if (!bash || !bash.endsWith("bash.exe")) throw new Error("bash.exe is not found in environments"); +} + +function download() { + console.log("Downloading ffmpeg source..."); + if (0 != spawnSync("git", [ + "clone", FFMPEG_REPO, + "-b", FFMPEG_TAG, FFMPEG_SOURCE_DIR + ], { stdio: "inherit" }).status) throw new Error("Failed to download ffmpeg"); +} + +function build() { + //configure + if (!fs.existsSync(path.join(FFMPEG_SOURCE_DIR, "ffbuild/config.mak"))) { + console.log("Configuring ffmpeg..."); + if (0 != spawnSync(process.env.SHELL, [ + path.join(FFMPEG_SOURCE_DIR, "configure"), + `--prefix=${FFMPEG_INSTALL_DIR}`, + "--enable-static", + "--enable-small", + "--toolchain=msvc", + "--disable-programs", + ], { stdio: "inherit", cwd: FFMPEG_SOURCE_DIR }).status) throw new Error("Failed to configure ffmpeg"); + } + //make + if (0 != spawnSync("make", [ + "-j", os.cpus().length.toString(), + ], { stdio: "inherit" }).status) throw new Error("Failed to build ffmpeg"); + //install + if (0 != spawnSync("make", [ + "install", + ], { stdio: "inherit", cwd: FFMPEG_SOURCE_DIR }).status) throw new Error("Failed to install ffmpeg"); +} + +function resolve() { + console.log("Resolving ffmpeg ..."); + const libs = []; + for (const file of fs.readdirSync(path.join(FFMPEG_INSTALL_DIR, "lib"))) { + if (path.extname(file) == ".a") { + const libName = file.replace(/\.a$/, "").replace(/^lib/, ""); + fs.renameSync(path.join(FFMPEG_INSTALL_DIR, "lib", file), path.join(FFMPEG_INSTALL_DIR, "lib", libName + ".lib")); + libs.push(libName); + } + } + fs.writeFileSync(path.join(FFMPEG_INSTALL_DIR, "config.cmake"), [ + "set(FFMPEG_INCLUDE_DIR ${CMAKE_CURRENT_LIST_DIR}/include)", + "set(FFMPEG_LIB_DIR ${CMAKE_CURRENT_LIST_DIR}/lib)", + `set(FFMPEG_LIBS ${libs.join(" ")})`, + "", + ].join("\n")); + +} + +async function main() { + fs.mkdirSync(path.dirname(FFMPEG_SOURCE_DIR), { recursive: true }); + fs.mkdirSync(path.dirname(FFMPEG_INSTALL_DIR), { recursive: true }); + + checkEnv(); + + if (!fs.existsSync(path.join(FFMPEG_SOURCE_DIR, "configure"))) download(); + if (!fs.existsSync(path.join(FFMPEG_INSTALL_DIR, "config.cmake"))) { + build(); + resolve(); + } + + console.log(`FFmpeg build done !`); +} + +main().catch(err => console.error(err.message)); diff --git a/thirdpart/cmake-js-util.js b/thirdpart/cmake-js-util.js new file mode 100644 index 0000000..5c6c334 --- /dev/null +++ b/thirdpart/cmake-js-util.js @@ -0,0 +1,19 @@ +const os = require("os"); +const path = require("path"); +const { execSync, spawnSync, exec } = require("child_process"); + +const args = process.argv.slice(2); + +const cmakeJS = path.join(__dirname, "../node_modules/.bin/cmake-js") + + +function runCmakeJS(args) { + const child = exec(`${cmakeJS} ${args.join(" ")}`, (err, stdout, stderr) => console.log(stdout)); + child.once("close", code => process.exit(code)); +} + +if (args.includes("--include")) runCmakeJS(["print-cmakejs-include"]); +else if (args.includes("--src")) runCmakeJS(["print-cmakejs-src"]); +else if (args.includes("--lib")) runCmakeJS(["print-cmakejs-lib"]); +else if (args.includes("--napi")) console.log(require("node-addon-api").include.replace(/^"/, "").replace(/"$/, "")); +else if (args.includes("--release")) console.log(require("../package.json").releaseVersion); \ No newline at end of file