Dernière activité 1 month ago

anduin's Avatar anduin a révisé ce gist 1 month ago. Aller à la révision

Aucun changement

anduin's Avatar anduin a révisé ce gist 1 month ago. Aller à la révision

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 a révisé ce gist 1 month ago. Aller à la révision

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 a révisé ce gist 1 month ago. Aller à la révision

2 files changed, 201 insertions, 192 deletions

Automating AI Video Upscaling with Real ESRGAN and Docker.md (fichier supprimé)

@@ -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(fichier créé)

@@ -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 a révisé ce gist 1 month ago. Aller à la révision

1 file changed, 192 insertions

Automating AI Video Upscaling with Real ESRGAN and Docker.md (fichier créé)

@@ -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\!
Plus récent Plus ancien