如何按空间维度将视频分割为N×M个视频瓦片文件?
Hey there! Splitting a video into an N×M grid of spatial tiles is a common task, and FFmpeg is the perfect tool for the job—it's powerful, flexible, and free. Let's break down exactly how to do this, step by step.
Before calculating tile sizes, you need to know the exact width and height of your input video. Run this FFmpeg command (replace test.video with your actual file):
ffprobe -v error -select_streams v:0 -show_entries stream=width,height -of csv=s=x:p=0 test.video
This will output something like 1920x1080—note down these values as W (width) and H (height).
Next, figure out the size of each tile. Let's say you want an N×M grid (e.g., 3 columns × 2 rows):
- For columns (N): Each tile's width will be
W // Nfor the firstN-1tiles. The last tile in the row will take the remaining width:W - (N-1)*(W//N)(this handles cases where W isn't evenly divisible by N). - For rows (M): Each tile's height follows the same logic:
H // Mfor the firstM-1rows, andH - (M-1)*(H//M)for the last row.
For example, if your video is 1920x1081 and you want a 2×2 grid:
- Tile width:
1920//2 = 960(all tiles have the same width here) - Tile height: First row tiles are
1081//2 = 540, last row tile is1081 - 540 = 541
Instead of running FFmpeg manually for each tile, use a loop to generate all N×M tiles at once. Here's a bash script example (adjust N and M to your needs):
# Set your parameters INPUT_VIDEO="test.video" N=2 # Number of columns M=3 # Number of rows # Get video resolution RES=$(ffprobe -v error -select_streams v:0 -show_entries stream=width,height -of csv=s=x:p=0 "$INPUT_VIDEO") W=$(echo "$RES" | cut -d'x' -f1) H=$(echo "$RES" | cut -d'x' -f2) # Calculate base tile dimensions BASE_TILE_W=$((W / N)) BASE_TILE_H=$((H / M)) # Loop through each tile position for ((i=0; i<N; i++)); do for ((j=0; j<M; j++)); do # Calculate tile width (handle last column if needed) if [ $i -eq $((N-1)) ]; then TILE_W=$((W - i * BASE_TILE_W)) else TILE_W=$BASE_TILE_W fi # Calculate tile height (handle last row if needed) if [ $j -eq $((M-1)) ]; then TILE_H=$((H - j * BASE_TILE_H)) else TILE_H=$BASE_TILE_H fi # Calculate x/y offset from top-left corner X_OFFSET=$((i * BASE_TILE_W)) Y_OFFSET=$((j * BASE_TILE_H)) # Output filename (adjust extension if needed, e.g., .mkv) OUTPUT_FILE="tile_${i}_${j}.mp4" # Run FFmpeg to crop and save the tile ffmpeg -i "$INPUT_VIDEO" \ -filter:v "crop=w=$TILE_W:h=$TILE_H:x=$X_OFFSET:y=$Y_OFFSET" \ -c:v libx264 -crf 18 \ # Use H.264 with high quality (adjust CRF for size/quality tradeoff) -an \ # Remove audio (remove this line if you want to keep audio in each tile) "$OUTPUT_FILE" done done
Key notes about the script:
- Codec/Quality: The
-c:v libx264 -crf 18ensures high-quality encoding. Lower CRF values (down to 0) mean better quality but larger files; higher values (up to 51) mean smaller files but lower quality. - Audio: The
-anflag removes audio from each tile. If you want to include audio, just delete that line—each tile will have the full audio track from the original video. - File Extensions: Adjust the output file extension (
.mp4) to match your input or desired format (e.g.,.mov,.mkv).
If you just want to test with one tile first, here's a standalone command (using the 1920x1080 example, cropping the top-left 960x540 tile):
ffmpeg -i test.video -filter:v "crop=w=960:h=540:x=0:y=0" -c:v libx264 -crf 18 -an tile_0_0.mp4
That's it! Run the script, and you'll have your full N×M grid of video tiles. Let me know if you run into any edge cases (like non-standard resolutions) and I can help tweak the logic.
内容的提问来源于stack exchange,提问作者Fuxing Yang

