Naposledy aktivní 1 month ago

anduin's Avatar anduin revidoval tento gist 1 month ago. Přejít na revizi

Žádné změny

anduin's Avatar anduin revidoval tento gist 1 month ago. Přejít na revizi

1 file changed, 47 insertions, 6 deletions

p.sh

@@ -12,7 +12,7 @@ EXEC_PATH="$APP_DIR/realesrgan-ncnn-vulkan"
12 12 # 模型可选: realesrgan-x4plus (适合真实影像), realesrgan-x4plus-anime (适合动漫)
13 13 MODEL_NAME="realesrgan-x4plus"
14 14 SCALE=4
15 - # 显卡ID,自动探测一般填0,如果多卡可修改
15 + # 显卡ID,自动探测一般填0
16 16 GPU_ID=0
17 17
18 18 # 下载链接
@@ -85,6 +85,10 @@ fi
85 85
86 86 echo -e "${GREEN}找到 ${#video_files[@]} 个视频文件,开始处理...${NC}"
87 87
88 + # 进度条绘制用的全长字符串
89 + FULL_BAR="##################################################"
90 + BAR_WIDTH=50
91 +
88 92 for INPUT_VIDEO in "${video_files[@]}"; do
89 93 BASE_NAME=$(basename "$INPUT_VIDEO")
90 94 FILENAME="${BASE_NAME%.*}"
@@ -109,19 +113,56 @@ for INPUT_VIDEO in "${video_files[@]}"; do
109 113 continue
110 114 fi
111 115
116 + # 统计总帧数 (ls -1U 速度较快,不排序)
117 + TOTAL_FRAMES=$(ls -1U "$TMP_FRAMES" | wc -l)
118 + echo "总帧数: $TOTAL_FRAMES"
119 +
112 120 # Step 2: AI 超分
113 121 echo -e "${YELLOW}[2/3] 正在进行 AI 超分 (Real-ESRGAN GPU)...${NC}"
114 122 echo "模型: $MODEL_NAME | 放大倍数: x$SCALE"
115 123
124 + # 1. 以后台方式启动 (&),并将标准输出和错误输出都扔进黑洞
116 125 "$EXEC_PATH" \
117 126 -i "$TMP_FRAMES" \
118 127 -o "$OUT_FRAMES" \
119 128 -n "$MODEL_NAME" \
120 129 -s "$SCALE" \
121 130 -g "$GPU_ID" \
122 - -f png
131 + -f png > /dev/null 2>&1 &
132 +
133 + PID=$! # 获取进程ID
134 +
135 + # 2. 循环监控进度
136 + while kill -0 $PID 2> /dev/null; do
137 + # 统计已生成的文件数
138 + CURRENT_FRAMES=$(ls -1U "$OUT_FRAMES" | wc -l)
123 139
124 - if [ $? -ne 0 ]; then
140 + # 计算百分比
141 + if [ "$TOTAL_FRAMES" -gt 0 ]; then
142 + PERCENT=$(( CURRENT_FRAMES * 100 / TOTAL_FRAMES ))
143 + else
144 + PERCENT=0
145 + fi
146 +
147 + # 防止文件系统统计延迟导致超过 100%
148 + if [ "$PERCENT" -gt 100 ]; then PERCENT=100; fi
149 +
150 + # 计算进度条填充长度
151 + FILLED_LEN=$(( PERCENT * BAR_WIDTH / 100 ))
152 +
153 + # 打印进度条 (\r 回车不换行)
154 + printf "\r[${GREEN}%-${BAR_WIDTH}s${NC}] %3d%% (%d/%d)" "${FULL_BAR:0:FILLED_LEN}" "$PERCENT" "$CURRENT_FRAMES" "$TOTAL_FRAMES"
155 +
156 + sleep 1
157 + done
158 +
159 + # 等待进程彻底退出并获取退出码
160 + wait $PID
161 + EXIT_CODE=$?
162 +
163 + echo "" # 进度条跑完换个行
164 +
165 + if [ $EXIT_CODE -ne 0 ]; then
125 166 echo -e "${RED}AI 超分失败,请检查显卡驱动或显存是否足够。${NC}"
126 167 rm -rf "$TMP_FRAMES" "$OUT_FRAMES"
127 168 continue
@@ -133,10 +174,10 @@ for INPUT_VIDEO in "${video_files[@]}"; do
133 174 # 获取原视频帧率
134 175 FPS=$(ffprobe -v error -select_streams v -of default=noprint_wrappers=1:nokey=1 -show_entries stream=r_frame_rate "$INPUT_VIDEO")
135 176
136 - # 极限画质合成: H.265 + CRF 18 + veryslow
177 + # 修复点:保持双引号防止 nullglob 错误
137 178 ffmpeg -v error -stats \
138 179 -framerate "$FPS" -i "$OUT_FRAMES/frame%08d.png" \
139 - -i "$INPUT_VIDEO" -map 0:v:0 -map 1:a:0? -c:a copy \
180 + -i "$INPUT_VIDEO" -map 0:v:0 -map "1:a:0?" -c:a copy \
140 181 -c:v libx265 -preset veryslow -crf 18 -pix_fmt yuv420p -tag:v hvc1 \
141 182 "$OUTPUT_VIDEO"
142 183
@@ -144,7 +185,7 @@ for INPUT_VIDEO in "${video_files[@]}"; do
144 185 echo -e "${YELLOW}H.265 编码失败,尝试回退到 H.264...${NC}"
145 186 ffmpeg -v error -stats \
146 187 -framerate "$FPS" -i "$OUT_FRAMES/frame%08d.png" \
147 - -i "$INPUT_VIDEO" -map 0:v:0 -map 1:a:0? -c:a copy \
188 + -i "$INPUT_VIDEO" -map 0:v:0 -map "1:a:0?" -c:a copy \
148 189 -c:v libx264 -preset veryslow -crf 18 -pix_fmt yuv420p \
149 190 "$OUTPUT_VIDEO"
150 191 fi

anduin's Avatar anduin revidoval tento gist 1 month ago. Přejít na revizi

1 file changed, 5 insertions, 47 deletions

p.sh

@@ -85,10 +85,6 @@ fi
85 85
86 86 echo -e "${GREEN}找到 ${#video_files[@]} 个视频文件,开始处理...${NC}"
87 87
88 - # 进度条绘制用的全长字符串
89 - FULL_BAR="##################################################"
90 - BAR_WIDTH=50
91 -
92 88 for INPUT_VIDEO in "${video_files[@]}"; do
93 89 BASE_NAME=$(basename "$INPUT_VIDEO")
94 90 FILENAME="${BASE_NAME%.*}"
@@ -113,56 +109,19 @@ for INPUT_VIDEO in "${video_files[@]}"; do
113 109 continue
114 110 fi
115 111
116 - # 统计总帧数 (ls -1U 速度较快,不排序)
117 - TOTAL_FRAMES=$(ls -1U "$TMP_FRAMES" | wc -l)
118 - echo "总帧数: $TOTAL_FRAMES"
119 -
120 112 # Step 2: AI 超分
121 113 echo -e "${YELLOW}[2/3] 正在进行 AI 超分 (Real-ESRGAN GPU)...${NC}"
122 114 echo "模型: $MODEL_NAME | 放大倍数: x$SCALE"
123 115
124 - # 1. 以后台方式启动 (&),并将标准输出和错误输出都扔进黑洞
125 116 "$EXEC_PATH" \
126 117 -i "$TMP_FRAMES" \
127 118 -o "$OUT_FRAMES" \
128 119 -n "$MODEL_NAME" \
129 120 -s "$SCALE" \
130 121 -g "$GPU_ID" \
131 - -f png > /dev/null 2>&1 &
132 -
133 - PID=$! # 获取进程ID
134 -
135 - # 2. 循环监控进度
136 - while kill -0 $PID 2> /dev/null; do
137 - # 统计已生成的文件数
138 - CURRENT_FRAMES=$(ls -1U "$OUT_FRAMES" | wc -l)
139 -
140 - # 计算百分比
141 - if [ "$TOTAL_FRAMES" -gt 0 ]; then
142 - PERCENT=$(( CURRENT_FRAMES * 100 / TOTAL_FRAMES ))
143 - else
144 - PERCENT=0
145 - fi
146 -
147 - # 防止文件系统统计延迟导致超过 100%
148 - if [ "$PERCENT" -gt 100 ]; then PERCENT=100; fi
122 + -f png
149 123
150 - # 计算进度条填充长度
151 - FILLED_LEN=$(( PERCENT * BAR_WIDTH / 100 ))
152 -
153 - # 打印进度条 (\r 回车不换行)
154 - printf "\r[${GREEN}%-${BAR_WIDTH}s${NC}] %3d%% (%d/%d)" "${FULL_BAR:0:FILLED_LEN}" "$PERCENT" "$CURRENT_FRAMES" "$TOTAL_FRAMES"
155 -
156 - sleep 1
157 - done
158 -
159 - # 等待进程彻底退出并获取退出码
160 - wait $PID
161 - EXIT_CODE=$?
162 -
163 - echo "" # 进度条跑完换个行
164 -
165 - if [ $EXIT_CODE -ne 0 ]; then
124 + if [ $? -ne 0 ]; then
166 125 echo -e "${RED}AI 超分失败,请检查显卡驱动或显存是否足够。${NC}"
167 126 rm -rf "$TMP_FRAMES" "$OUT_FRAMES"
168 127 continue
@@ -174,19 +133,18 @@ for INPUT_VIDEO in "${video_files[@]}"; do
174 133 # 获取原视频帧率
175 134 FPS=$(ffprobe -v error -select_streams v -of default=noprint_wrappers=1:nokey=1 -show_entries stream=r_frame_rate "$INPUT_VIDEO")
176 135
177 - # 修复点:给 map 参数加上双引号 "1:a:0?",防止 nullglob 导致参数丢失
136 + # 极限画质合成: H.265 + CRF 18 + veryslow
178 137 ffmpeg -v error -stats \
179 138 -framerate "$FPS" -i "$OUT_FRAMES/frame%08d.png" \
180 - -i "$INPUT_VIDEO" -map 0:v:0 -map "1:a:0?" -c:a copy \
139 + -i "$INPUT_VIDEO" -map 0:v:0 -map 1:a:0? -c:a copy \
181 140 -c:v libx265 -preset veryslow -crf 18 -pix_fmt yuv420p -tag:v hvc1 \
182 141 "$OUTPUT_VIDEO"
183 142
184 143 if [ $? -ne 0 ]; then
185 144 echo -e "${YELLOW}H.265 编码失败,尝试回退到 H.264...${NC}"
186 - # 修复点:fallback 命令同样加上引号
187 145 ffmpeg -v error -stats \
188 146 -framerate "$FPS" -i "$OUT_FRAMES/frame%08d.png" \
189 - -i "$INPUT_VIDEO" -map 0:v:0 -map "1:a:0?" -c:a copy \
147 + -i "$INPUT_VIDEO" -map 0:v:0 -map 1:a:0? -c:a copy \
190 148 -c:v libx264 -preset veryslow -crf 18 -pix_fmt yuv420p \
191 149 "$OUTPUT_VIDEO"
192 150 fi

anduin's Avatar anduin revidoval tento gist 1 month ago. Přejít na revizi

2 files changed, 201 insertions, 192 deletions

Automating AI Video Upscaling with Real ESRGAN and Docker.md (smazal soubor)

@@ -1,192 +0,0 @@
1 -
2 - If you have a library of old, low-resolution videos that you want to restore, manually processing them frame-by-frame or using GUI tools can be tedious. In this post, I'm sharing a "set it and forget it" solution using Docker and Real-ESRGAN.
3 -
4 - This setup uses an NVIDIA GPU to automate the entire pipeline: splitting the video into frames, upscaling them with AI, and merging them back into a high-quality video file.
5 -
6 - ### Prerequisites
7 -
8 - * A machine with an NVIDIA GPU.
9 - * Docker Desktop or Docker Engine installed.
10 - * **NVIDIA Container Toolkit** (to allow Docker to access your GPU).
11 -
12 - -----
13 -
14 - ## 1\. The Environment: Dockerfile
15 -
16 - First, we need a consistent environment. This Dockerfile builds on top of an NVIDIA base image, installs `ffmpeg` and `vulkan` drivers, and pre-downloads the Real-ESRGAN executable so we don't have to download it every time we run the container.
17 -
18 - **Dockerfile**
19 -
20 - ```dockerfile
21 - # Use a base image with CUDA drivers and Ubuntu to support GPU
22 - FROM hub.aiursoft.com/aiursoft/internalimages/nvidia:latest
23 -
24 - # Set environment variables to avoid interactive prompts during the build
25 - ENV DEBIAN_FRONTEND=noninteractive
26 -
27 - # Update package lists and install required dependencies: wget, unzip, ffmpeg, and vulkan loader
28 - RUN apt-get update && apt-get install -y --no-install-recommends \
29 - wget \
30 - unzip \
31 - ffmpeg \
32 - libvulkan1 \
33 - && rm -rf /var/lib/apt/lists/*
34 -
35 - # Set the working directory
36 - WORKDIR /app
37 -
38 - # Download, unzip, and setup Real-ESRGAN during the image build
39 - # This is more efficient than downloading every time the container starts
40 - RUN wget https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.5.0/realesrgan-ncnn-vulkan-20220424-ubuntu.zip && \
41 - unzip realesrgan-ncnn-vulkan-20220424-ubuntu.zip && \
42 - rm realesrgan-ncnn-vulkan-20220424-ubuntu.zip && \
43 - chmod +x realesrgan-ncnn-vulkan
44 -
45 - # Copy the automation script to the container's /app/ directory
46 - COPY process_videos.sh .
47 - # Grant execution permissions to the script
48 - RUN chmod +x process_videos.sh
49 -
50 - # Define mount points for external directory mapping
51 - VOLUME /input
52 - VOLUME /output
53 -
54 - # Set our processing script as the container's entrypoint
55 - # This script will execute automatically when the container starts
56 - ENTRYPOINT ["/app/process_videos.sh"]
57 - ```
58 -
59 - -----
60 -
61 - ## 2\. The Logic: Processing Script
62 -
63 - This bash script handles the heavy lifting. It scans the `/input` folder for videos, and for every file it finds, it performs three steps:
64 -
65 - 1. **Extract:** Uses `ffmpeg` to dump all frames to a temp folder.
66 - 2. **Upscale:** Runs `realesrgan-ncnn-vulkan` on that folder to create 4x larger frames.
67 - 3. **Assemble:** Stitches the new frames back together using hardware acceleration (`h264_nvenc`) if available, or falls back to CPU encoding.
68 -
69 - **process\_videos.sh**
70 -
71 - ```bash
72 - #!/bin/bash
73 -
74 - # Set input and output directories
75 - INPUT_DIR="/input"
76 - OUTPUT_DIR="/output"
77 -
78 - # Ensure the output directory exists
79 - mkdir -p "$OUTPUT_DIR"
80 -
81 - echo "Starting video enhancement tasks..."
82 - # Enable nullglob to handle cases where no files match a pattern
83 - shopt -s nullglob
84 -
85 - # Find all supported video files
86 - video_files=("$INPUT_DIR"/*.mp4 "$INPUT_DIR"/*.mov "$INPUT_DIR"/*.avi)
87 -
88 - # Check if any video files were found
89 - if [ ${#video_files[@]} -eq 0 ]; then
90 - echo "No supported video files found in $INPUT_DIR (.mp4, .mov, .avi)."
91 - exit 0
92 - fi
93 -
94 - echo "Found ${#video_files[@]} video files. Starting processing..."
95 -
96 - # Loop through the found video files
97 - for INPUT_VIDEO in "${video_files[@]}"; do
98 - # Check if the file exists and is a regular file
99 - if [ ! -f "$INPUT_VIDEO" ]; then
100 - continue
101 - fi
102 -
103 - echo "--- Processing: $INPUT_VIDEO ---"
104 -
105 - # --- Configuration ---
106 - SCALE=4 # Upscaling scale
107 - MODEL="realesrgan-x4plus" # Model to use
108 - GPU_ID=0 # GPU index to use
109 - REALESRGAN_EXEC="/app/realesrgan-ncnn-vulkan" # Path to Real-ESRGAN executable
110 -
111 - # Create a temporary working directory for frames
112 - WORK_DIR=$(mktemp -d)
113 - mkdir -p "$WORK_DIR/out"
114 - echo "Working directory: $WORK_DIR"
115 -
116 - # Define output video path
117 - BASE_NAME=$(basename "$INPUT_VIDEO")
118 - OUTPUT_VIDEO="$OUTPUT_DIR/${BASE_NAME%.*}_enhanced_x${SCALE}.mp4"
119 -
120 - # --- 1. Extract Frames ---
121 - echo "Step 1: Splitting video into frames..."
122 - ffmpeg -i "$INPUT_VIDEO" -qscale:v 1 -qmin 1 -vsync 0 "$WORK_DIR/in_%08d.png"
123 - if [ $? -ne 0 ]; then
124 - echo "Error: ffmpeg failed to split '$INPUT_VIDEO'."
125 - rm -rf "$WORK_DIR" # Clean up temp files
126 - continue # Continue to the next video
127 - fi
128 -
129 - # --- 2. Process Frames with AI Model ---
130 - echo "Step 2: Upscaling frames using Real-ESRGAN..."
131 - $REALESRGAN_EXEC \
132 - -i "$WORK_DIR" \
133 - -o "$WORK_DIR/out" \
134 - -n "$MODEL" \
135 - -s "$SCALE" \
136 - -g "$GPU_ID" \
137 - -f png
138 - if [ $? -ne 0 ]; then
139 - echo "Error: Real-ESRGAN failed to process frames for '$INPUT_VIDEO'."
140 - rm -rf "$WORK_DIR"
141 - continue
142 - fi
143 -
144 - # --- 3. Assemble Video ---
145 - echo "Step 3: Assembling processed frames into video..."
146 - FPS=$(ffprobe -v error -select_streams v -of default=noprint_wrappers=1:nokey=1 -show_entries stream=r_frame_rate "$INPUT_VIDEO")
147 - # Attempt to use NVIDIA GPU hardware encoding
148 - ffmpeg -framerate "$FPS" -i "$WORK_DIR/out/in_%08d.png" \
149 - -i "$INPUT_VIDEO" -map 0:v:0 -map 1:a:0? -c:a copy \
150 - -c:v h264_nvenc -preset slow -cq 18 "$OUTPUT_VIDEO"
151 - if [ $? -ne 0 ]; then
152 - echo "Warning: NVIDIA hardware encoding (h264_nvenc) failed. Trying CPU encoding (libx264)..."
153 - # Fallback to CPU encoding if GPU encoding fails
154 - ffmpeg -framerate "$FPS" -i "$WORK_DIR/out/in_%08d.png" \
155 - -i "$INPUT_VIDEO" -map 0:v:0 -map 1:a:0? -c:a copy \
156 - -c:v libx264 -preset medium -crf 22 "$OUTPUT_VIDEO"
157 - fi
158 -
159 - # --- 4. Cleanup ---
160 - echo "Step 4: Cleaning up temporary files..."
161 - rm -rf "$WORK_DIR"
162 -
163 - echo "--- Finished processing: $INPUT_VIDEO. Output file: $OUTPUT_VIDEO ---"
164 - done
165 -
166 - echo "All videos processed."
167 - ```
168 -
169 - -----
170 -
171 - ## How to Run It
172 -
173 - ### 1\. Build the Image
174 -
175 - In the directory containing the `Dockerfile` and the `process_videos.sh` script, run:
176 -
177 - ```bash
178 - docker build -t video-enhancer .
179 - ```
180 -
181 - ### 2\. Run the Container
182 -
183 - Prepare a folder named `videos_to_process` with your source files and an empty `enhanced_videos` folder. Then run:
184 -
185 - ```bash
186 - docker run --gpus all --rm \
187 - -v $(pwd)/videos_to_process:/input \
188 - -v $(pwd)/enhanced_videos:/output \
189 - video-enhancer
190 - ```
191 -
192 - The container will spin up, process every video in the input folder, save the 4x upscaled versions to the output folder, and then shut down cleanly. Happy upscaling\!

p.sh(vytvořil soubor)

@@ -0,0 +1,201 @@
1 + #!/bin/bash
2 +
3 + # =================配置区域=================
4 + # 基础路径配置
5 + BASE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
6 + INPUT_DIR="$BASE_DIR/videos_to_process"
7 + OUTPUT_DIR="$BASE_DIR/enhanced_videos"
8 + APP_DIR="$BASE_DIR/app"
9 + EXEC_PATH="$APP_DIR/realesrgan-ncnn-vulkan"
10 +
11 + # Real-ESRGAN 配置
12 + # 模型可选: realesrgan-x4plus (适合真实影像), realesrgan-x4plus-anime (适合动漫)
13 + MODEL_NAME="realesrgan-x4plus"
14 + SCALE=4
15 + # 显卡ID,自动探测一般填0,如果多卡可修改
16 + GPU_ID=0
17 +
18 + # 下载链接
19 + DOWNLOAD_URL="https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.5.0/realesrgan-ncnn-vulkan-20220424-ubuntu.zip"
20 + ZIP_FILE="realesrgan-ncnn-vulkan-20220424-ubuntu.zip"
21 +
22 + # =========================================
23 +
24 + # 颜色定义
25 + GREEN='\033[0;32m'
26 + YELLOW='\033[1;33m'
27 + RED='\033[0;31m'
28 + NC='\033[0m' # No Color
29 +
30 + # 0. 检查依赖 (ffmpeg)
31 + if ! command -v ffmpeg &> /dev/null; then
32 + echo -e "${RED}Error: ffmpeg 未安装。${NC}"
33 + echo "请运行: sudo apt update && sudo apt install ffmpeg"
34 + exit 1
35 + fi
36 +
37 + # 1. 准备目录和环境
38 + mkdir -p "$OUTPUT_DIR"
39 + mkdir -p "$APP_DIR"
40 +
41 + # 检查并下载 Real-ESRGAN
42 + if [ ! -f "$EXEC_PATH" ]; then
43 + echo -e "${YELLOW}Real-ESRGAN 可执行文件未找到,准备下载...${NC}"
44 +
45 + # 进入 app 目录下载
46 + cd "$APP_DIR" || exit
47 +
48 + if [ -f "$ZIP_FILE" ]; then
49 + rm "$ZIP_FILE"
50 + fi
51 +
52 + echo "正在下载: $DOWNLOAD_URL"
53 + wget -q --show-progress "$DOWNLOAD_URL"
54 +
55 + if [ $? -ne 0 ]; then
56 + echo -e "${RED}下载失败,请检查网络连接。${NC}"
57 + exit 1
58 + fi
59 +
60 + echo "正在解压..."
61 + unzip -q "$ZIP_FILE"
62 +
63 + # 赋予执行权限
64 + chmod +x realesrgan-ncnn-vulkan
65 +
66 + # 清理压缩包
67 + rm "$ZIP_FILE"
68 +
69 + echo -e "${GREEN}Real-ESRGAN 安装完成!${NC}"
70 +
71 + # 回到基础目录
72 + cd "$BASE_DIR" || exit
73 + else
74 + echo -e "${GREEN}Real-ESRGAN 已安装,跳过下载。${NC}"
75 + fi
76 +
77 + # 2. 开始扫描视频并处理
78 + shopt -s nullglob
79 + video_files=("$INPUT_DIR"/*.mp4 "$INPUT_DIR"/*.mov "$INPUT_DIR"/*.avi "$INPUT_DIR"/*.mkv)
80 +
81 + if [ ${#video_files[@]} -eq 0 ]; then
82 + echo -e "${YELLOW}在 $INPUT_DIR 中没有找到支持的视频文件。${NC}"
83 + exit 0
84 + fi
85 +
86 + echo -e "${GREEN}找到 ${#video_files[@]} 个视频文件,开始处理...${NC}"
87 +
88 + # 进度条绘制用的全长字符串
89 + FULL_BAR="##################################################"
90 + BAR_WIDTH=50
91 +
92 + for INPUT_VIDEO in "${video_files[@]}"; do
93 + BASE_NAME=$(basename "$INPUT_VIDEO")
94 + FILENAME="${BASE_NAME%.*}"
95 + OUTPUT_VIDEO="$OUTPUT_DIR/${FILENAME}_x${SCALE}.mp4"
96 +
97 + echo "----------------------------------------------------------------"
98 + echo -e "正在处理: ${YELLOW}$BASE_NAME${NC}"
99 + echo "----------------------------------------------------------------"
100 +
101 + # 创建临时目录
102 + TMP_FRAMES=$(mktemp -d -p "$BASE_DIR" "tmp_frames_XXXXXX")
103 + OUT_FRAMES=$(mktemp -d -p "$BASE_DIR" "out_frames_XXXXXX")
104 +
105 + # Step 1: 拆帧
106 + echo -e "${YELLOW}[1/3] 正在提取帧 (使用 ffmpeg)...${NC}"
107 + # 使用 png 格式以保证无损画质传入 AI
108 + ffmpeg -v error -stats -i "$INPUT_VIDEO" -qscale:v 1 -qmin 1 -fps_mode passthrough "$TMP_FRAMES/frame%08d.png"
109 +
110 + if [ $? -ne 0 ]; then
111 + echo -e "${RED}拆帧失败,跳过此视频。${NC}"
112 + rm -rf "$TMP_FRAMES" "$OUT_FRAMES"
113 + continue
114 + fi
115 +
116 + # 统计总帧数 (ls -1U 速度较快,不排序)
117 + TOTAL_FRAMES=$(ls -1U "$TMP_FRAMES" | wc -l)
118 + echo "总帧数: $TOTAL_FRAMES"
119 +
120 + # Step 2: AI 超分
121 + echo -e "${YELLOW}[2/3] 正在进行 AI 超分 (Real-ESRGAN GPU)...${NC}"
122 + echo "模型: $MODEL_NAME | 放大倍数: x$SCALE"
123 +
124 + # 1. 以后台方式启动 (&),并将标准输出和错误输出都扔进黑洞
125 + "$EXEC_PATH" \
126 + -i "$TMP_FRAMES" \
127 + -o "$OUT_FRAMES" \
128 + -n "$MODEL_NAME" \
129 + -s "$SCALE" \
130 + -g "$GPU_ID" \
131 + -f png > /dev/null 2>&1 &
132 +
133 + PID=$! # 获取进程ID
134 +
135 + # 2. 循环监控进度
136 + while kill -0 $PID 2> /dev/null; do
137 + # 统计已生成的文件数
138 + CURRENT_FRAMES=$(ls -1U "$OUT_FRAMES" | wc -l)
139 +
140 + # 计算百分比
141 + if [ "$TOTAL_FRAMES" -gt 0 ]; then
142 + PERCENT=$(( CURRENT_FRAMES * 100 / TOTAL_FRAMES ))
143 + else
144 + PERCENT=0
145 + fi
146 +
147 + # 防止文件系统统计延迟导致超过 100%
148 + if [ "$PERCENT" -gt 100 ]; then PERCENT=100; fi
149 +
150 + # 计算进度条填充长度
151 + FILLED_LEN=$(( PERCENT * BAR_WIDTH / 100 ))
152 +
153 + # 打印进度条 (\r 回车不换行)
154 + printf "\r[${GREEN}%-${BAR_WIDTH}s${NC}] %3d%% (%d/%d)" "${FULL_BAR:0:FILLED_LEN}" "$PERCENT" "$CURRENT_FRAMES" "$TOTAL_FRAMES"
155 +
156 + sleep 1
157 + done
158 +
159 + # 等待进程彻底退出并获取退出码
160 + wait $PID
161 + EXIT_CODE=$?
162 +
163 + echo "" # 进度条跑完换个行
164 +
165 + if [ $EXIT_CODE -ne 0 ]; then
166 + echo -e "${RED}AI 超分失败,请检查显卡驱动或显存是否足够。${NC}"
167 + rm -rf "$TMP_FRAMES" "$OUT_FRAMES"
168 + continue
169 + fi
170 +
171 + # Step 3: 合成视频
172 + echo -e "${YELLOW}[3/3] 正在合成视频 (High Quality H.265)...${NC}"
173 +
174 + # 获取原视频帧率
175 + FPS=$(ffprobe -v error -select_streams v -of default=noprint_wrappers=1:nokey=1 -show_entries stream=r_frame_rate "$INPUT_VIDEO")
176 +
177 + # 修复点:给 map 参数加上双引号 "1:a:0?",防止 nullglob 导致参数丢失
178 + ffmpeg -v error -stats \
179 + -framerate "$FPS" -i "$OUT_FRAMES/frame%08d.png" \
180 + -i "$INPUT_VIDEO" -map 0:v:0 -map "1:a:0?" -c:a copy \
181 + -c:v libx265 -preset veryslow -crf 18 -pix_fmt yuv420p -tag:v hvc1 \
182 + "$OUTPUT_VIDEO"
183 +
184 + if [ $? -ne 0 ]; then
185 + echo -e "${YELLOW}H.265 编码失败,尝试回退到 H.264...${NC}"
186 + # 修复点:fallback 命令同样加上引号
187 + ffmpeg -v error -stats \
188 + -framerate "$FPS" -i "$OUT_FRAMES/frame%08d.png" \
189 + -i "$INPUT_VIDEO" -map 0:v:0 -map "1:a:0?" -c:a copy \
190 + -c:v libx264 -preset veryslow -crf 18 -pix_fmt yuv420p \
191 + "$OUTPUT_VIDEO"
192 + fi
193 +
194 + # 清理临时文件
195 + echo -e "${GREEN}清理临时文件...${NC}"
196 + rm -rf "$TMP_FRAMES" "$OUT_FRAMES"
197 +
198 + echo -e "${GREEN}完成! 输出文件: $OUTPUT_VIDEO${NC}"
199 + done
200 +
201 + echo -e "${GREEN}所有任务已完成。${NC}"

anduin's Avatar anduin revidoval tento gist 1 month ago. Přejít na revizi

1 file changed, 192 insertions

Automating AI Video Upscaling with Real ESRGAN and Docker.md (vytvořil soubor)

@@ -0,0 +1,192 @@
1 +
2 + If you have a library of old, low-resolution videos that you want to restore, manually processing them frame-by-frame or using GUI tools can be tedious. In this post, I'm sharing a "set it and forget it" solution using Docker and Real-ESRGAN.
3 +
4 + This setup uses an NVIDIA GPU to automate the entire pipeline: splitting the video into frames, upscaling them with AI, and merging them back into a high-quality video file.
5 +
6 + ### Prerequisites
7 +
8 + * A machine with an NVIDIA GPU.
9 + * Docker Desktop or Docker Engine installed.
10 + * **NVIDIA Container Toolkit** (to allow Docker to access your GPU).
11 +
12 + -----
13 +
14 + ## 1\. The Environment: Dockerfile
15 +
16 + First, we need a consistent environment. This Dockerfile builds on top of an NVIDIA base image, installs `ffmpeg` and `vulkan` drivers, and pre-downloads the Real-ESRGAN executable so we don't have to download it every time we run the container.
17 +
18 + **Dockerfile**
19 +
20 + ```dockerfile
21 + # Use a base image with CUDA drivers and Ubuntu to support GPU
22 + FROM hub.aiursoft.com/aiursoft/internalimages/nvidia:latest
23 +
24 + # Set environment variables to avoid interactive prompts during the build
25 + ENV DEBIAN_FRONTEND=noninteractive
26 +
27 + # Update package lists and install required dependencies: wget, unzip, ffmpeg, and vulkan loader
28 + RUN apt-get update && apt-get install -y --no-install-recommends \
29 + wget \
30 + unzip \
31 + ffmpeg \
32 + libvulkan1 \
33 + && rm -rf /var/lib/apt/lists/*
34 +
35 + # Set the working directory
36 + WORKDIR /app
37 +
38 + # Download, unzip, and setup Real-ESRGAN during the image build
39 + # This is more efficient than downloading every time the container starts
40 + RUN wget https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.5.0/realesrgan-ncnn-vulkan-20220424-ubuntu.zip && \
41 + unzip realesrgan-ncnn-vulkan-20220424-ubuntu.zip && \
42 + rm realesrgan-ncnn-vulkan-20220424-ubuntu.zip && \
43 + chmod +x realesrgan-ncnn-vulkan
44 +
45 + # Copy the automation script to the container's /app/ directory
46 + COPY process_videos.sh .
47 + # Grant execution permissions to the script
48 + RUN chmod +x process_videos.sh
49 +
50 + # Define mount points for external directory mapping
51 + VOLUME /input
52 + VOLUME /output
53 +
54 + # Set our processing script as the container's entrypoint
55 + # This script will execute automatically when the container starts
56 + ENTRYPOINT ["/app/process_videos.sh"]
57 + ```
58 +
59 + -----
60 +
61 + ## 2\. The Logic: Processing Script
62 +
63 + This bash script handles the heavy lifting. It scans the `/input` folder for videos, and for every file it finds, it performs three steps:
64 +
65 + 1. **Extract:** Uses `ffmpeg` to dump all frames to a temp folder.
66 + 2. **Upscale:** Runs `realesrgan-ncnn-vulkan` on that folder to create 4x larger frames.
67 + 3. **Assemble:** Stitches the new frames back together using hardware acceleration (`h264_nvenc`) if available, or falls back to CPU encoding.
68 +
69 + **process\_videos.sh**
70 +
71 + ```bash
72 + #!/bin/bash
73 +
74 + # Set input and output directories
75 + INPUT_DIR="/input"
76 + OUTPUT_DIR="/output"
77 +
78 + # Ensure the output directory exists
79 + mkdir -p "$OUTPUT_DIR"
80 +
81 + echo "Starting video enhancement tasks..."
82 + # Enable nullglob to handle cases where no files match a pattern
83 + shopt -s nullglob
84 +
85 + # Find all supported video files
86 + video_files=("$INPUT_DIR"/*.mp4 "$INPUT_DIR"/*.mov "$INPUT_DIR"/*.avi)
87 +
88 + # Check if any video files were found
89 + if [ ${#video_files[@]} -eq 0 ]; then
90 + echo "No supported video files found in $INPUT_DIR (.mp4, .mov, .avi)."
91 + exit 0
92 + fi
93 +
94 + echo "Found ${#video_files[@]} video files. Starting processing..."
95 +
96 + # Loop through the found video files
97 + for INPUT_VIDEO in "${video_files[@]}"; do
98 + # Check if the file exists and is a regular file
99 + if [ ! -f "$INPUT_VIDEO" ]; then
100 + continue
101 + fi
102 +
103 + echo "--- Processing: $INPUT_VIDEO ---"
104 +
105 + # --- Configuration ---
106 + SCALE=4 # Upscaling scale
107 + MODEL="realesrgan-x4plus" # Model to use
108 + GPU_ID=0 # GPU index to use
109 + REALESRGAN_EXEC="/app/realesrgan-ncnn-vulkan" # Path to Real-ESRGAN executable
110 +
111 + # Create a temporary working directory for frames
112 + WORK_DIR=$(mktemp -d)
113 + mkdir -p "$WORK_DIR/out"
114 + echo "Working directory: $WORK_DIR"
115 +
116 + # Define output video path
117 + BASE_NAME=$(basename "$INPUT_VIDEO")
118 + OUTPUT_VIDEO="$OUTPUT_DIR/${BASE_NAME%.*}_enhanced_x${SCALE}.mp4"
119 +
120 + # --- 1. Extract Frames ---
121 + echo "Step 1: Splitting video into frames..."
122 + ffmpeg -i "$INPUT_VIDEO" -qscale:v 1 -qmin 1 -vsync 0 "$WORK_DIR/in_%08d.png"
123 + if [ $? -ne 0 ]; then
124 + echo "Error: ffmpeg failed to split '$INPUT_VIDEO'."
125 + rm -rf "$WORK_DIR" # Clean up temp files
126 + continue # Continue to the next video
127 + fi
128 +
129 + # --- 2. Process Frames with AI Model ---
130 + echo "Step 2: Upscaling frames using Real-ESRGAN..."
131 + $REALESRGAN_EXEC \
132 + -i "$WORK_DIR" \
133 + -o "$WORK_DIR/out" \
134 + -n "$MODEL" \
135 + -s "$SCALE" \
136 + -g "$GPU_ID" \
137 + -f png
138 + if [ $? -ne 0 ]; then
139 + echo "Error: Real-ESRGAN failed to process frames for '$INPUT_VIDEO'."
140 + rm -rf "$WORK_DIR"
141 + continue
142 + fi
143 +
144 + # --- 3. Assemble Video ---
145 + echo "Step 3: Assembling processed frames into video..."
146 + FPS=$(ffprobe -v error -select_streams v -of default=noprint_wrappers=1:nokey=1 -show_entries stream=r_frame_rate "$INPUT_VIDEO")
147 + # Attempt to use NVIDIA GPU hardware encoding
148 + ffmpeg -framerate "$FPS" -i "$WORK_DIR/out/in_%08d.png" \
149 + -i "$INPUT_VIDEO" -map 0:v:0 -map 1:a:0? -c:a copy \
150 + -c:v h264_nvenc -preset slow -cq 18 "$OUTPUT_VIDEO"
151 + if [ $? -ne 0 ]; then
152 + echo "Warning: NVIDIA hardware encoding (h264_nvenc) failed. Trying CPU encoding (libx264)..."
153 + # Fallback to CPU encoding if GPU encoding fails
154 + ffmpeg -framerate "$FPS" -i "$WORK_DIR/out/in_%08d.png" \
155 + -i "$INPUT_VIDEO" -map 0:v:0 -map 1:a:0? -c:a copy \
156 + -c:v libx264 -preset medium -crf 22 "$OUTPUT_VIDEO"
157 + fi
158 +
159 + # --- 4. Cleanup ---
160 + echo "Step 4: Cleaning up temporary files..."
161 + rm -rf "$WORK_DIR"
162 +
163 + echo "--- Finished processing: $INPUT_VIDEO. Output file: $OUTPUT_VIDEO ---"
164 + done
165 +
166 + echo "All videos processed."
167 + ```
168 +
169 + -----
170 +
171 + ## How to Run It
172 +
173 + ### 1\. Build the Image
174 +
175 + In the directory containing the `Dockerfile` and the `process_videos.sh` script, run:
176 +
177 + ```bash
178 + docker build -t video-enhancer .
179 + ```
180 +
181 + ### 2\. Run the Container
182 +
183 + Prepare a folder named `videos_to_process` with your source files and an empty `enhanced_videos` folder. Then run:
184 +
185 + ```bash
186 + docker run --gpus all --rm \
187 + -v $(pwd)/videos_to_process:/input \
188 + -v $(pwd)/enhanced_videos:/output \
189 + video-enhancer
190 + ```
191 +
192 + The container will spin up, process every video in the input folder, save the 4x upscaled versions to the output folder, and then shut down cleanly. Happy upscaling\!
Novější Starší