diff --git a/linglong.yaml b/linglong.yaml new file mode 100644 index 0000000..fdd1f93 --- /dev/null +++ b/linglong.yaml @@ -0,0 +1,741 @@ +version: '1' + +package: + id: io.github.babitmf.bmf + kind: app + name: "BMF" + version: "0.2.0.0" + description: "Babit Multimedia Framework (BMF) - multimedia/video processing framework." + +base: org.deepin.base/25.2.1 + +buildext: + apt: + build_depends: + - ca-certificates + - git + - pkg-config + - cmake + - make + - gcc + - g++ + - binutils-dev + - libssl-dev + - ffmpeg + - libavcodec-dev + - libavdevice-dev + - libavfilter-dev + - libavformat-dev + - libavutil-dev + - libpostproc-dev + - libswresample-dev + - libswscale-dev + # Enable CUDA build (FindCUDAToolkit) + - nvidia-cuda-toolkit + + depends: + - libavformat60 + - libavcodec60 + - libavutil58 + - libavfilter9 + - libavdevice60 + - libswscale7 + - libswresample4 + - libpostproc57 + - libblas3 + - liblapack3 + - libgfortran5 + # CUDA runtime: bundle libcudart into the app to avoid pulling in driver/dkms/sudo + # via apt dependency chain during runtime check. + +command: + - "/opt/apps/io.github.babitmf.bmf/files/bin/bmf" + +build: | + set -eux + # cp -a /project/bmf /project/linglong/sources/ + cd /project/linglong/sources/bmf + + # Fix build with FFmpeg 6+: av_mallocz_array was removed from libavutil. + # Use an idempotent in-place edit (avoid patch prompts / malformed diffs). + FF_HELPER=bmf/hmp/include/hmp/ffmpeg/ff_helper.h + if ! grep -q "FFmpeg 6+ removed av_mallocz_array" "$FF_HELPER"; then + awk ' + { print } + /#include / { + print "#include " + print "#include " + print "" + print "#if LIBAVUTIL_VERSION_MAJOR >= 58" + print "// FFmpeg 6+ removed av_mallocz_array; use av_calloc as replacement." + print "static inline void *av_mallocz_array(size_t nmemb, size_t size) {" + print " return av_calloc(nmemb, size);" + print "}" + print "#endif" + } + ' "$FF_HELPER" > /tmp/ff_helper.h + mv /tmp/ff_helper.h "$FF_HELPER" + fi + + # BMF 顶层 CMakeLists.txt 需要 BMF_BUILD_VERSION,且默认会启用 CUDA/Python, + # 在玲珑基础环境中通常更稳妥的做法是先关掉 Python/CUDA/Test。 + cmake -S . -B build \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX="$PREFIX" \ + -DCMAKE_INSTALL_RPATH='\$ORIGIN/../lib' \ + -DCMAKE_BUILD_WITH_INSTALL_RPATH=ON \ + -DBMF_BUILD_VERSION="0.2.0.0" \ + -DBMF_BUILD_COMMIT="0" \ + -DBMF_ENABLE_TEST=OFF \ + -DBMF_ENABLE_PYTHON=OFF \ + -DBMF_ENABLE_CUDA=ON \ + -DBMF_ENABLE_TORCH=OFF \ + -DBMF_ENABLE_BREAKPAD=OFF \ + -DBMF_ENABLE_JNI=OFF + + cmake --build build -j"$(nproc)" + cmake --install build + + # Upstream hmp library isn't installed by default; package it explicitly. + install -d "$PREFIX/lib" + if [ -d build/output/bmf/lib ]; then + cp -a build/output/bmf/lib/libhmp.so* "$PREFIX/lib/" || true + fi + + # Provide a minimal telemetry uploader library to satisfy optional dlopen + # in bmf_sdk::BMFStat (avoids runtime "libbmf_data_reporter.so missing" logs). + # This stub does not send anything; it simply implements the expected symbols. + cat > /tmp/bmf_data_reporter_stub.cpp <<'CPP' + #include + #include + #include + + class NullKafkaReporter final : public BMFKafkaReporterI { + public: + bool produce(const std::string&) override { return true; } + void flush() override {} + int64_t get_num_produced() const override { return 0; } + }; + + extern "C" { + BMFKafkaReporterI* create_bmf_kafka_reporter_default_online() { + return new NullKafkaReporter(); + } + BMFKafkaReporterI* create_bmf_kafka_reporter_default_boe() { + return new NullKafkaReporter(); + } + void destroy_kafka_reporter(BMFKafkaReporterI* reporter) { + delete reporter; + } + } + CPP + g++ -shared -fPIC -O2 -std=c++17 \ + -I bmf/sdk/cpp_sdk/include \ + -Wl,-soname,libbmf_data_reporter.so \ + -o "$PREFIX/lib/libbmf_data_reporter.so" \ + /tmp/bmf_data_reporter_stub.cpp + + # Some FFmpeg filter dependencies (e.g. libplacebo) may pull in BLAS/LAPACK + # which are not guaranteed to exist in the runtime container. + # Bundle the minimal set of numerical runtime libs into the package. + bundle_soname() { + soname="$1" + path="$(ldconfig -p 2>/dev/null | awk -v s="$soname" '$1==s {print $NF; exit}' || true)" + if [ -z "$path" ]; then + path="$(find /usr/lib -maxdepth 5 -name "$soname" 2>/dev/null | head -n 1 || true)" + fi + if [ -n "$path" ] && [ -e "$path" ]; then + real="$(readlink -f "$path" 2>/dev/null || printf '%s' "$path")" + cp -a "$real" "$PREFIX/lib/" || true + if [ "$(basename "$real")" != "$soname" ]; then + ln -sf "$(basename "$real")" "$PREFIX/lib/$soname" || true + fi + fi + } + + # Linglong runtime may not provide FFmpeg runtime libs even if we declare apt depends. + # Bundle the minimal FFmpeg shared libs required by builtin ffmpeg modules. + bundle_soname libavformat.so.60 + bundle_soname libavcodec.so.60 + bundle_soname libavutil.so.58 + bundle_soname libavfilter.so.9 + bundle_soname libavdevice.so.60 + bundle_soname libswscale.so.7 + bundle_soname libswresample.so.4 + bundle_soname libpostproc.so.57 + + # CUDA runtime (do NOT rely on apt installing libcudart12 into the app filesystem). + # Host driver-side libcuda is provided by Linglong's NVIDIA driver integration. + bundle_soname libcudart.so.12 + + bundle_soname libblas.so.3 + bundle_soname liblapack.so.3 + bundle_soname libgfortran.so.5 + bundle_soname libquadmath.so.0 + + # ModuleManager locates BUILTIN_CONFIG.json by searching: + # 1) directory of libbmf_module_sdk.so (usually $PREFIX/lib) + # 2) its parent (usually $PREFIX) + # 3) current working directory + # The chosen directory becomes builtin_root, and builtin modules are then resolved under: + # /lib/libbuiltin_modules.so + # So we must place BUILTIN_CONFIG.json under $PREFIX (not $PREFIX/lib), otherwise it becomes + # =$PREFIX/lib and resolves to a wrong path: $PREFIX/lib/lib/libbuiltin_modules.so. + if [ -f bmf/c_modules/meta/BUILTIN_CONFIG.json ]; then + install -m 0644 bmf/c_modules/meta/BUILTIN_CONFIG.json "$PREFIX/BUILTIN_CONFIG.json" + elif [ -f build/output/bmf/BUILTIN_CONFIG.json ]; then + install -m 0644 build/output/bmf/BUILTIN_CONFIG.json "$PREFIX/BUILTIN_CONFIG.json" + fi + rm -f "$PREFIX/lib/BUILTIN_CONFIG.json" || true + + # 可选:给用户一个导出环境的小工具(运行后打印 export 语句) + install -d "$PREFIX/bin" + cat > "$PREFIX/bin/bmf_env" <<'EOF' + #!/bin/sh + ROOT="$(cd "$(dirname "$0")/.." && pwd)" + echo "export BMF_ROOT=${ROOT}" + echo "export LD_LIBRARY_PATH=${ROOT}/lib:\$LD_LIBRARY_PATH" + echo "export LIBRARY_PATH=${ROOT}/lib:\$LIBRARY_PATH" + echo "export CPATH=${ROOT}/include:\$CPATH" + echo "export PKG_CONFIG_PATH=${ROOT}/lib/pkgconfig:\$PKG_CONFIG_PATH" + EOF + chmod +x "$PREFIX/bin/bmf_env" + + # Provide a friendly entrypoint for Linglong: ll-builder/ll-cli run (no args) should not fail. + cat > "$PREFIX/bin/bmf" <<'EOF' + #!/bin/sh + set -eu + + BIN_DIR="$(cd "$(dirname "$0")" && pwd)" + + usage() { + printf '%s\n' \ + 'BMF (Linglong package)' \ + '' \ + 'Usage:' \ + ' bmf run ' \ + ' bmf demo-transcode [--input in.mp4] [--output out.mp4] [options]' \ + ' bmf demo-transcode-cuda [--input in.mp4] [--output out.mp4] [options]' \ + ' bmf config ' \ + ' bmf module_manager [args...]' \ + ' bmf run_bmf_graph ' \ + '' \ + 'demo-transcode options:' \ + ' --scale WxH (e.g. 1280x720; updates scale + encoder width/height)' \ + ' --crf N (e.g. 18..28)' \ + ' --preset NAME (e.g. veryfast, fast, medium)' \ + ' --ab RATE (audio bitrate, e.g. 128k, 192k)' \ + ' --vflip/--no-vflip (toggle vflip node in default graph)' \ + ' --hflip/--no-hflip (toggle hflip node in default graph)' \ + '' \ + 'demo-transcode-cuda notes:' \ + ' - Tries hwaccel decode (cuda) + NVENC encode (h264_nvenc) first.' \ + ' - If CUDA/NVENC is unavailable, it auto-falls back to demo-transcode.' \ + ' - For NVENC, preset values are typically p1..p7 (differs from x264 presets).' \ + '' \ + 'Default paths (editable default config):' \ + ' config: $HOME/bmf/bmf_graph.json' \ + ' cuda config: $HOME/bmf/bmf_graph_cuda.json' \ + ' workdir: $HOME/bmf (override with BMF_WORKDIR)' \ + '' \ + 'Notes:' \ + ' - demo-transcode does NOT overwrite the default config; it renders a run graph in workdir.' \ + ' - You can edit $HOME/bmf/*.json to change defaults (then run demo-transcode again).' \ + '' \ + 'Run examples:' \ + ' - Debug (workspace): ll-builder run -f linglong.yaml -- bmf demo-transcode --input /path/in.mp4' \ + ' - Release (installed): ll-cli run io.github.babitmf.bmf -- bmf demo-transcode --input /path/in.mp4' + } + + if [ "$#" -eq 0 ]; then + usage + exit 0 + fi + + CONFIG_DIR="${BMF_CONFIGDIR:-$HOME/bmf}" + WORKDIR="${BMF_WORKDIR:-$CONFIG_DIR}" + CONFIG="$CONFIG_DIR/bmf_graph.json" + CUDA_CONFIG="$CONFIG_DIR/bmf_graph_cuda.json" + GRAPH_RUN="$WORKDIR/bmf_graph.run.json" + CUDA_GRAPH_RUN="$WORKDIR/bmf_graph_cuda.run.json" + + mkdir -p "$CONFIG_DIR" "$WORKDIR" + + json_escape() { + # Escape backslash and double quote for JSON string values. + printf '%s' "$1" | sed -e 's|\\|\\\\|g' -e 's|"|\\"|g' + } + + parse_bitrate() { + # Accept: 128000, 128k, 192K, 1m, 1M + v="$1" + case "$v" in + *[Kk]) n="${v%[Kk]}"; printf '%s' "$((n * 1000))" ;; + *[Mm]) n="${v%[Mm]}"; printf '%s' "$((n * 1000000))" ;; + *) printf '%s' "$v" ;; + esac + } + + write_default_config() { + cat > "$CONFIG" <<'JSON' + { + "mode": "normal", + "input_streams": [], + "output_streams": [], + "option": { "dump_graph": 1 }, + "nodes": [ + { + "id": 0, + "option": { "input_path": "__INPUT__" }, + "input_streams": [], + "output_streams": [ + { "identifier": "audio:ffmpeg_decoder_0_2", "alias": "" }, + { "identifier": "video:ffmpeg_decoder_0_1", "alias": "" } + ], + "module_info": { "name": "c_ffmpeg_decoder", "type": "", "path": "", "entry": "" }, + "input_manager": "immediate", + "scheduler": 0, + "meta_info": { "premodule_id": -1, "callback_bindings": [] } + }, + { + "id": 1, + "option": { "name": "scale", "para": "320:240" }, + "input_streams": [ { "identifier": "ffmpeg_decoder_0_1", "alias": "" } ], + "output_streams": [ { "identifier": "ffmpeg_filter_1_0", "alias": "" } ], + "module_info": { "name": "c_ffmpeg_filter", "type": "", "path": "", "entry": "" }, + "input_manager": "immediate", + "scheduler": 0, + "meta_info": { "premodule_id": -1, "callback_bindings": [] } + }, + { + "id": 2, + "option": { "name": "vflip" }, + "input_streams": [ { "identifier": "ffmpeg_filter_1_0", "alias": "" } ], + "output_streams": [ { "identifier": "ffmpeg_filter_2_0", "alias": "" } ], + "module_info": { "name": "c_ffmpeg_filter", "type": "", "path": "", "entry": "" }, + "input_manager": "immediate", + "scheduler": 0, + "meta_info": { "premodule_id": -1, "callback_bindings": [] } + }, + { + "id": 3, + "option": { "name": "null" }, + "input_streams": [ { "identifier": "ffmpeg_filter_2_0", "alias": "" } ], + "output_streams": [ { "identifier": "ffmpeg_filter_3_0", "alias": "" } ], + "module_info": { "name": "c_ffmpeg_filter", "type": "", "path": "", "entry": "" }, + "input_manager": "immediate", + "scheduler": 0, + "meta_info": { "premodule_id": -1, "callback_bindings": [] } + }, + { + "id": 4, + "option": { + "video_params": { "width": 320, "height": 240, "codec": "h264", "crf": 23, "preset": "veryfast" }, + "audio_params": { "channels": 2, "bit_rate": 128000, "codec": "aac", "sample_rate": 44100 }, + "output_path": "__OUTPUT__" + }, + "input_streams": [ + { "identifier": "ffmpeg_filter_3_0", "alias": "" }, + { "identifier": "ffmpeg_decoder_0_2", "alias": "" } + ], + "output_streams": [], + "module_info": { "name": "c_ffmpeg_encoder", "type": "", "path": "", "entry": "" }, + "input_manager": "immediate", + "scheduler": 1, + "meta_info": { "premodule_id": -1, "callback_bindings": [] } + } + ] + } + JSON + } + + write_cuda_config() { + # CUDA/NVENC template: + # - Decoder: hwaccel=cuda + # - Encoder: h264_nvenc + cat > "$CUDA_CONFIG" <<'JSON' + { + "mode": "normal", + "input_streams": [], + "output_streams": [], + "option": { "dump_graph": 1 }, + "nodes": [ + { + "id": 0, + "option": { "input_path": "__INPUT__", "video_params": { "hwaccel": "cuda", "hwaccel_check": 0 } }, + "input_streams": [], + "output_streams": [ + { "identifier": "audio:ffmpeg_decoder_0_2", "alias": "" }, + { "identifier": "video:ffmpeg_decoder_0_1", "alias": "" } + ], + "module_info": { "name": "c_ffmpeg_decoder", "type": "", "path": "", "entry": "" }, + "input_manager": "immediate", + "scheduler": 0, + "meta_info": { "premodule_id": -1, "callback_bindings": [] } + }, + { + "id": 1, + "option": { "name": "scale", "para": "320:240" }, + "input_streams": [ { "identifier": "ffmpeg_decoder_0_1", "alias": "" } ], + "output_streams": [ { "identifier": "ffmpeg_filter_1_0", "alias": "" } ], + "module_info": { "name": "c_ffmpeg_filter", "type": "", "path": "", "entry": "" }, + "input_manager": "immediate", + "scheduler": 0, + "meta_info": { "premodule_id": -1, "callback_bindings": [] } + }, + { + "id": 2, + "option": { "name": "vflip" }, + "input_streams": [ { "identifier": "ffmpeg_filter_1_0", "alias": "" } ], + "output_streams": [ { "identifier": "ffmpeg_filter_2_0", "alias": "" } ], + "module_info": { "name": "c_ffmpeg_filter", "type": "", "path": "", "entry": "" }, + "input_manager": "immediate", + "scheduler": 0, + "meta_info": { "premodule_id": -1, "callback_bindings": [] } + }, + { + "id": 3, + "option": { "name": "null" }, + "input_streams": [ { "identifier": "ffmpeg_filter_2_0", "alias": "" } ], + "output_streams": [ { "identifier": "ffmpeg_filter_3_0", "alias": "" } ], + "module_info": { "name": "c_ffmpeg_filter", "type": "", "path": "", "entry": "" }, + "input_manager": "immediate", + "scheduler": 0, + "meta_info": { "premodule_id": -1, "callback_bindings": [] } + }, + { + "id": 4, + "option": { + "video_params": { "width": 320, "height": 240, "codec": "h264_nvenc", "bit_rate": 2000000, "preset": "p4" }, + "audio_params": { "channels": 2, "bit_rate": 128000, "codec": "aac", "sample_rate": 44100 }, + "output_path": "__OUTPUT__" + }, + "input_streams": [ + { "identifier": "ffmpeg_filter_3_0", "alias": "" }, + { "identifier": "ffmpeg_decoder_0_2", "alias": "" } + ], + "output_streams": [], + "module_info": { "name": "c_ffmpeg_encoder", "type": "", "path": "", "entry": "" }, + "input_manager": "immediate", + "scheduler": 1, + "meta_info": { "premodule_id": -1, "callback_bindings": [] } + } + ] + } + JSON + } + + ensure_config() { + if [ ! -f "$CONFIG" ]; then + write_default_config + fi + } + + ensure_cuda_config() { + if [ ! -f "$CUDA_CONFIG" ]; then + write_cuda_config + fi + } + + render_graph() { + base="$1" + in_path="$2" + out_path="$3" + out_file="$4" + + in_esc="$(json_escape "$in_path")" + out_esc="$(json_escape "$out_path")" + + awk \ + -v in_esc="$in_esc" \ + -v out_esc="$out_esc" \ + -v have_scale="$HAVE_SCALE" \ + -v scale_para="$SCALE_PARA" \ + -v scale_w="$SCALE_W" \ + -v scale_h="$SCALE_H" \ + -v have_crf="$HAVE_CRF" \ + -v crf="$CRF" \ + -v have_preset="$HAVE_PRESET" \ + -v preset="$PRESET" \ + -v have_ab="$HAVE_AB" \ + -v ab="$AB" \ + -v have_vflip="$HAVE_VFLIP" \ + -v vflip_name="$VFLIP_NAME" \ + -v have_hflip="$HAVE_HFLIP" \ + -v hflip_name="$HFLIP_NAME" \ + ' + BEGIN { node = -1 } + { + # Track current node by matching: "id": N + if (match($0, /"id"[[:space:]]*:[[:space:]]*[0-9]+/)) { + s = substr($0, RSTART, RLENGTH) + sub(/.*:/, "", s) + gsub(/[[:space:]]*/, "", s) + node = s + 0 + } + + # Always patch input/output path + if ($0 ~ /"input_path"[[:space:]]*:/) { + sub(/"input_path"[[:space:]]*:[[:space:]]*"[^"]*"/, "\"input_path\": \"" in_esc "\"") + } + if ($0 ~ /"output_path"[[:space:]]*:/) { + sub(/"output_path"[[:space:]]*:[[:space:]]*"[^"]*"/, "\"output_path\": \"" out_esc "\"") + } + + # scale node (id=1) + if (have_scale == 1 && node == 1 && $0 ~ /"para"[[:space:]]*:/) { + sub(/"para"[[:space:]]*:[[:space:]]*"[^"]*"/, "\"para\": \"" scale_para "\"") + } + + # vflip node (id=2), hflip node (id=3) - option/name usually on same line in template + if (have_vflip == 1 && node == 2 && $0 ~ /"name"[[:space:]]*:/) { + sub(/"name"[[:space:]]*:[[:space:]]*"[^"]*"/, "\"name\": \"" vflip_name "\"") + } + if (have_hflip == 1 && node == 3 && $0 ~ /"name"[[:space:]]*:/) { + sub(/"name"[[:space:]]*:[[:space:]]*"[^"]*"/, "\"name\": \"" hflip_name "\"") + } + + # encoder node (id=4) + if (node == 4) { + if (have_scale == 1 && $0 ~ /"width"[[:space:]]*:/) { + sub(/"width"[[:space:]]*:[[:space:]]*[0-9]+/, "\"width\": " scale_w) + } + if (have_scale == 1 && $0 ~ /"height"[[:space:]]*:/) { + sub(/"height"[[:space:]]*:[[:space:]]*[0-9]+/, "\"height\": " scale_h) + } + if (have_crf == 1 && $0 ~ /"crf"[[:space:]]*:/) { + sub(/"crf"[[:space:]]*:[[:space:]]*[0-9]+/, "\"crf\": " crf) + } + if (have_preset == 1 && $0 ~ /"preset"[[:space:]]*:/) { + sub(/"preset"[[:space:]]*:[[:space:]]*"[^"]*"/, "\"preset\": \"" preset "\"") + } + # 注意:这里会匹配 node=4 里的 bit_rate(音频),模板里 video_params 用 bit_rate 或 crf,不会冲突 + if (have_ab == 1 && $0 ~ /"bit_rate"[[:space:]]*:/) { + sub(/"bit_rate"[[:space:]]*:[[:space:]]*[0-9]+/, "\"bit_rate\": " ab) + } + } + + print + } + ' "$base" > "$out_file" + } + + cmd="$1" + shift || true + + case "$cmd" in + run) + graph="${1:-}" + if [ -z "$graph" ]; then + echo "Usage: bmf run " >&2 + exit 2 + fi + exec "$BIN_DIR/run_bmf_graph" "$graph" + ;; + + config) + sub="${1:-}" + case "$sub" in + init) + ensure_config + ensure_cuda_config + echo "Config: $CONFIG" >&2 + echo "CUDA config: $CUDA_CONFIG" >&2 + ;; + reset) + if [ -f "$CONFIG" ]; then + cp -a "$CONFIG" "$CONFIG.bak.$(date +%Y%m%d_%H%M%S)" || true + fi + if [ -f "$CUDA_CONFIG" ]; then + cp -a "$CUDA_CONFIG" "$CUDA_CONFIG.bak.$(date +%Y%m%d_%H%M%S)" || true + fi + write_default_config + write_cuda_config + echo "Reset config: $CONFIG" >&2 + echo "Reset CUDA config: $CUDA_CONFIG" >&2 + ;; + show) + ensure_config + cat "$CONFIG" + ;; + show-cuda) + ensure_cuda_config + cat "$CUDA_CONFIG" + ;; + path) + echo "$CONFIG" + ;; + path-cuda) + echo "$CUDA_CONFIG" + ;; + *) + echo "Usage: bmf config " >&2 + exit 2 + ;; + esac + ;; + + demo-transcode|demo-transcode-cuda) + subcmd="$cmd" + + # defaults for args + INPUT="" + OUTPUT="" + + HAVE_SCALE=0 + SCALE_PARA="" + SCALE_W=0 + SCALE_H=0 + + HAVE_CRF=0 + CRF=0 + + HAVE_PRESET=0 + PRESET="" + + HAVE_AB=0 + AB=0 + + HAVE_VFLIP=0 + VFLIP_NAME="vflip" + + HAVE_HFLIP=0 + HFLIP_NAME="null" + + # parse args + while [ "$#" -gt 0 ]; do + case "$1" in + --help|-h) + usage + exit 0 + ;; + --input) + shift + INPUT="${1:-}" + ;; + --output) + shift + OUTPUT="${1:-}" + ;; + --scale) + shift + s="${1:-}" + s="$(printf '%s' "$s" | tr 'xX' ':')" + SCALE_W="${s%%:*}" + SCALE_H="${s##*:}" + SCALE_PARA="$SCALE_W:$SCALE_H" + HAVE_SCALE=1 + ;; + --crf) + shift + CRF="${1:-0}" + HAVE_CRF=1 + ;; + --preset) + shift + PRESET="${1:-}" + HAVE_PRESET=1 + ;; + --ab|--audio-bitrate) + shift + AB="$(parse_bitrate "${1:-0}")" + HAVE_AB=1 + ;; + --vflip) + HAVE_VFLIP=1 + VFLIP_NAME="vflip" + ;; + --no-vflip) + HAVE_VFLIP=1 + VFLIP_NAME="null" + ;; + --hflip) + HAVE_HFLIP=1 + HFLIP_NAME="hflip" + ;; + --no-hflip) + HAVE_HFLIP=1 + HFLIP_NAME="null" + ;; + --) + shift + break + ;; + -*) + echo "Unknown option: $1" >&2 + echo "Tip: bmf demo-transcode --help" >&2 + exit 2 + ;; + *) + if [ -z "$INPUT" ]; then + INPUT="$1" + elif [ -z "$OUTPUT" ]; then + OUTPUT="$1" + else + echo "Unexpected argument: $1" >&2 + exit 2 + fi + ;; + esac + shift || true + done + + if [ -z "$INPUT" ]; then + INPUT="$WORKDIR/in.mp4" + fi + if [ -z "$OUTPUT" ]; then + OUTPUT="$WORKDIR/out.mp4" + fi + + if [ ! -f "$INPUT" ]; then + echo "Input not found: $INPUT" >&2 + echo "Tip: cp /path/to/video.mp4 \"$WORKDIR/in.mp4\"" >&2 + echo "Config path: $CONFIG" >&2 + exit 0 + fi + + if [ "$subcmd" = "demo-transcode" ]; then + ensure_config + render_graph "$CONFIG" "$INPUT" "$OUTPUT" "$GRAPH_RUN" + echo "Run graph: $GRAPH_RUN" >&2 + exec "$BIN_DIR/run_bmf_graph" "$GRAPH_RUN" + fi + + # demo-transcode-cuda: + ensure_cuda_config + render_graph "$CUDA_CONFIG" "$INPUT" "$OUTPUT" "$CUDA_GRAPH_RUN" + echo "Run CUDA graph: $CUDA_GRAPH_RUN" >&2 + + if "$BIN_DIR/run_bmf_graph" "$CUDA_GRAPH_RUN"; then + exit 0 + fi + + echo "CUDA/NVENC path failed; falling back to software demo-transcode." >&2 + ensure_config + render_graph "$CONFIG" "$INPUT" "$OUTPUT" "$GRAPH_RUN" + echo "Run graph: $GRAPH_RUN" >&2 + exec "$BIN_DIR/run_bmf_graph" "$GRAPH_RUN" + ;; + + run_bmf_graph|module_manager|trace_format_log) + exec "$BIN_DIR/$cmd" "$@" + ;; + + *) + # Default: treat args as run_bmf_graph arguments + exec "$BIN_DIR/run_bmf_graph" "$cmd" "$@" + ;; + esac + EOF + + chmod +x "$PREFIX/bin/bmf" + +sources: + - kind: git + url: https://github.com/BabitMF/bmf.git + name: bmf + commit: v0.2.0 + version: v0.2.0 + submodules: true + # linglong:gen_deb_source sources amd64 https://ci.deepin.com/repo/deepin/deepin-community/stable crimson/release main commercial community + # linglong:gen_deb_source install libhmp1 \ No newline at end of file