Welcome to Software Development on Codidact!
Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.
Post History
I'm having trouble with an ffmpeg script that's supposed to convert videos to a specific resolution and frame rate, but the output video has unexpected dimensions and frame rate. Here's my script a...
#3: Post edited
- I'm having trouble with an ffmpeg script that's supposed to convert videos to a specific resolution and frame rate, but the output video has unexpected dimensions and frame rate. Here's my script and the issue:
- ```bash
- #!/usr/bin/env bash
- # Constants
- MAX_RESOLUTION=540
- MAX_FPS=15
- MAX_BITRATE="500k"
- CRF_VALUE=30
- AUDIO_BITRATE="64k"
- # Check if the directory argument is provided
- if [ $# -eq 0 ]; then
- echo "Usage: $0 <directory>"
- exit 1
- fi
- TARGET_DIR="$1"
- # Function to log messages
- log() {
- echo "$(date '+%Y-%m-%d %H:%M:%S') - $1"
- }
- # Function to handle errors
- handle_error() {
- log "Error occurred: $1"
- exit 1
- }
- for FILE in $(find "$TARGET_DIR" -type f \( -iname "*.mp4" -o -iname "*.mkv" -o -iname "*.avi" -o -iname "*.mov" -o -iname "*.m4v" -o -iname "*.wmv" \)); do
- log "Processing: $FILE"
- # Get video dimensions and frame rate
- DIMENSIONS=$(ffprobe -v error -select_streams v:0 -show_entries stream=width,height -of csv=s=x:p=0 "$FILE")
- WIDTH=$(echo $DIMENSIONS | cut -d'x' -f1)
- HEIGHT=$(echo $DIMENSIONS | cut -d'x' -f2)
- FPS=$(ffprobe -v error -select_streams v:0 -count_packets -show_entries stream=r_frame_rate -of csv=p=0 "$FILE" | bc -l | awk '{printf("%d\n",$1 + 0.5)}')
- # Determine scaling only if necessary
- SCALING=""
- if [ $WIDTH -lt $HEIGHT ]; then
- SHORTER_SIDE=$WIDTH
- if [ $WIDTH -gt $MAX_RESOLUTION ]; then
- SCALING="-vf scale=$MAX_RESOLUTION:-2"
- fi
- else
- SHORTER_SIDE=$HEIGHT
- if [ $HEIGHT -gt $MAX_RESOLUTION ]; then
- SCALING="-vf scale=-2:$MAX_RESOLUTION"
- fi
- fi
- # Add fps filter only if necessary
- FPS_FILTER=""
- if [ $FPS -gt $MAX_FPS ]; then
- FPS_FILTER="-vf fps=$MAX_FPS"
- fi
- # Get codec info
- CODEC_INFO=$(ffprobe -v error -select_streams v:0 -show_entries stream=codec_name -of default=noprint_wrappers=1:nokey=1 "$FILE")
- # Check if conversion is needed
- if [[ "$CODEC_INFO" != "hevc" && "$CODEC_INFO" != "h265" ]] || [ "$FPS" -gt "$MAX_FPS" ] || [ $SHORTER_SIDE -gt $MAX_RESOLUTION ]; then
- OUTPUT_FILE="${FILE%.*}.h265.mkv"
- # Combine scaling, FPS filtering, and codec selection
- ffmpeg_cmd=(
- "-i" "$FILE"
- $SCALING
- $FPS_FILTER
- "-c:v" "libx265"
- "-preset" "slow"
- "-crf" "$CRF_VALUE"
- "-c:a" "aac"
- "-b:a" "$AUDIO_BITRATE"
- "-movflags" "+faststart"
- "$OUTPUT_FILE"
- )
- log "Executing FFmpeg command: ${ffmpeg_cmd[*]}"
- ffmpeg "${ffmpeg_cmd[@]}" || handle_error "FFmpeg failed to encode $FILE"
- log "Conversion completed successfully."
- else
- log "No conversion needed for $FILE"
- fi
- done
- ```
- The problem is that the output video has a different resolution and frame rate than I expect:
- ```
- Input #0
- Stream #0:0[0x1](und): Video: hevc (Main 10) (hvc1 / 0x31637668), yuv420p10le(tv, bt2020nc/bt2020/arib-std-b67), 3840x2160, 94843 kb/s, 59.98 fps, 60 tbr, 600 tbn (default)
- Output #0
- Stream #0:0(und): Video: hevc, yuv420p10le(tv, bt2020nc/bt2020/arib-std-b67, progressive), 406x720, q=2-31, 1000 kb/s, 60 fps, 1k tbn (default)
- ```
- The output is 406x720 instead of the expected 1080x720, and 60 fps instead of the desired 30 fps. How can I fix this issue?
- Please help me understand why this is happening and how to achieve the desired output resolution and frame rate.
- I'm having trouble with an ffmpeg script that's supposed to convert videos to a specific resolution and frame rate, but the output video has unexpected dimensions and frame rate. Here's my script and the issue:
- ```bash
- #!/usr/bin/env bash
- # Constants
- MAX_RESOLUTION=540
- MAX_FPS=15
- MAX_BITRATE="500k"
- CRF_VALUE=30
- AUDIO_BITRATE="64k"
- # Check if the directory argument is provided
- if [ $# -eq 0 ]; then
- echo "Usage: $0 <directory>"
- exit 1
- fi
- TARGET_DIR="$1"
- # Function to log messages
- log() {
- echo "$(date '+%Y-%m-%d %H:%M:%S') - $1"
- }
- # Function to handle errors
- handle_error() {
- log "Error occurred: $1"
- exit 1
- }
- for FILE in $(find "$TARGET_DIR" -type f \( -iname "*.mp4" -o -iname "*.mkv" -o -iname "*.avi" -o -iname "*.mov" -o -iname "*.m4v" -o -iname "*.wmv" \)); do
- log "Processing: $FILE"
- # Get video dimensions and frame rate
- DIMENSIONS=$(ffprobe -v error -select_streams v:0 -show_entries stream=width,height -of csv=s=x:p=0 "$FILE")
- WIDTH=$(echo $DIMENSIONS | cut -d'x' -f1)
- HEIGHT=$(echo $DIMENSIONS | cut -d'x' -f2)
- FPS=$(ffprobe -v error -select_streams v:0 -count_packets -show_entries stream=r_frame_rate -of csv=p=0 "$FILE" | bc -l | awk '{printf("%d\n",$1 + 0.5)}')
- # Determine scaling only if necessary
- SCALING=""
- if [ $WIDTH -lt $HEIGHT ]; then
- SHORTER_SIDE=$WIDTH
- if [ $WIDTH -gt $MAX_RESOLUTION ]; then
- SCALING="-vf scale=$MAX_RESOLUTION:-2"
- fi
- else
- SHORTER_SIDE=$HEIGHT
- if [ $HEIGHT -gt $MAX_RESOLUTION ]; then
- SCALING="-vf scale=-2:$MAX_RESOLUTION"
- fi
- fi
- # Add fps filter only if necessary
- FPS_FILTER=""
- if [ $FPS -gt $MAX_FPS ]; then
- FPS_FILTER="-vf fps=$MAX_FPS"
- fi
- # Get codec info
- CODEC_INFO=$(ffprobe -v error -select_streams v:0 -show_entries stream=codec_name -of default=noprint_wrappers=1:nokey=1 "$FILE")
- # Check if conversion is needed
- if [[ "$CODEC_INFO" != "hevc" && "$CODEC_INFO" != "h265" ]] || [ "$FPS" -gt "$MAX_FPS" ] || [ $SHORTER_SIDE -gt $MAX_RESOLUTION ]; then
- OUTPUT_FILE="${FILE%.*}.h265.mkv"
- # Combine scaling, FPS filtering, and codec selection
- ffmpeg_cmd=(
- "-i" "$FILE"
- $SCALING
- $FPS_FILTER
- "-c:v" "libx265"
- "-preset" "slow"
- "-crf" "$CRF_VALUE"
- "-c:a" "aac"
- "-b:a" "$AUDIO_BITRATE"
- "-movflags" "+faststart"
- "$OUTPUT_FILE"
- )
- log "Executing FFmpeg command: ${ffmpeg_cmd[*]}"
- ffmpeg "${ffmpeg_cmd[@]}" || handle_error "FFmpeg failed to encode $FILE"
- log "Conversion completed successfully."
- else
- log "No conversion needed for $FILE"
- fi
- done
- ```
- The problem is that the output video has a different resolution and frame rate than I expect:
- ```
- Input #0
- Stream #0:0[0x1](und): Video: hevc (Main 10) (hvc1 / 0x31637668), yuv420p10le(tv, bt2020nc/bt2020/arib-std-b67), 3840x2160, 94843 kb/s, 59.98 fps, 60 tbr, 600 tbn (default)
- Output #0
- Stream #0:0(und): Video: hevc, yuv420p10le(tv, bt2020nc/bt2020/arib-std-b67, progressive), 406x720, q=2-31, 1000 kb/s, 60 fps, 1k tbn (default)
- ❯ ffprobe -v error -select_streams v:0 -count_packets -show_entries stream=r_frame_rate -of csv=p=0 "$FILE"
- 60/1,
- ❯ ffprobe -v error -select_streams v:0 -count_packets -show_entries stream=r_frame_rate -of csv=p=0 "$FILE" | bc -l | awk '{printf("%d\n",$1 + 0.5)}'
- (standard_in) 1: syntax error
- ```
- The output is 406x720 instead of the expected 1080x720, and 60 fps instead of the desired 30 fps. How can I fix this issue?
- Please help me understand why this is happening and how to achieve the desired output resolution and frame rate.
#2: Post edited
- I'm having trouble with an ffmpeg script that's supposed to convert videos to a specific resolution and frame rate, but the output video has unexpected dimensions and frame rate. Here's my script and the issue:
- ```bash
- #!/usr/bin/env bash
- if [ $# -eq 0 ]; then
- echo "Usage: $0 <directory>"
- exit 1
- fi
MAX_RESOLUTION=720MAX_FPS=30- TARGET_DIR="$1"
MAX_BITRATE="1M"CRF_VALUE=28AUDIO_BITRATE="128k"# Find all video files recursively in the given directoryfind "$TARGET_DIR" -type f \( -iname "*.mp4" -o -iname "*.mkv" -o -iname "*.avi" -o -iname "*.mov" -o -iname "*.m4v" -o -iname "*.wmv" \) -print0 | while IFS= read -r -d '' FILE; doCODEC_INFO=$(ffprobe -v error -select_streams v:0 -show_entries stream=codec_name -of default=noprint_wrappers=1:nokey=1 "$FILE")BASENAME=$(basename -- "$FILE")NAME="${BASENAME%.*}"EXT="${BASENAME##*.}"OUTPUT_FILE="${FILE%.*}.h265.mkv"- DIMENSIONS=$(ffprobe -v error -select_streams v:0 -show_entries stream=width,height -of csv=s=x:p=0 "$FILE")
- WIDTH=$(echo $DIMENSIONS | cut -d'x' -f1)
- HEIGHT=$(echo $DIMENSIONS | cut -d'x' -f2)
- FPS=$(ffprobe -v error -select_streams v:0 -count_packets -show_entries stream=r_frame_rate -of csv=p=0 "$FILE" | bc -l | awk '{printf("%d\n",$1 + 0.5)}')
- SCALING=""
- if [ $WIDTH -lt $HEIGHT ]; then
- SHORTER_SIDE=$WIDTH
- if [ $WIDTH -gt $MAX_RESOLUTION ]; then
- SCALING="-vf scale=$MAX_RESOLUTION:-2"
- fi
- else
- SHORTER_SIDE=$HEIGHT
- if [ $HEIGHT -gt $MAX_RESOLUTION ]; then
- SCALING="-vf scale=-2:$MAX_RESOLUTION"
- fi
- fi
- FPS_FILTER=""
- if [ $FPS -gt $MAX_FPS ]; then
- FPS_FILTER="-vf fps=$MAX_FPS"
- fi
- if [[ "$CODEC_INFO" != "hevc" && "$CODEC_INFO" != "h265" ]] || [ "$FPS" -gt "$MAX_FPS" ] || [ $SHORTER_SIDE -gt $MAX_RESOLUTION ]; then
ffmpeg -i "$FILE" $SCALING $FPS_FILTER -c:v libx265 -b:v $MAX_BITRATE -crf $CRF_VALUE -c:a aac -b:a $AUDIO_BITRATE -preset slow "$OUTPUT_FILE"- fi
- done
- ```
- The problem is that the output video has a different resolution and frame rate than I expect:
- ```
- Input #0
- Stream #0:0[0x1](und): Video: hevc (Main 10) (hvc1 / 0x31637668), yuv420p10le(tv, bt2020nc/bt2020/arib-std-b67), 3840x2160, 94843 kb/s, 59.98 fps, 60 tbr, 600 tbn (default)
- Output #0
- Stream #0:0(und): Video: hevc, yuv420p10le(tv, bt2020nc/bt2020/arib-std-b67, progressive), 406x720, q=2-31, 1000 kb/s, 60 fps, 1k tbn (default)
- ```
- The output is 406x720 instead of the expected 1080x720, and 60 fps instead of the desired 30 fps. How can I fix this issue?
- Please help me understand why this is happening and how to achieve the desired output resolution and frame rate.
- I'm having trouble with an ffmpeg script that's supposed to convert videos to a specific resolution and frame rate, but the output video has unexpected dimensions and frame rate. Here's my script and the issue:
- ```bash
- #!/usr/bin/env bash
- # Constants
- MAX_RESOLUTION=540
- MAX_FPS=15
- MAX_BITRATE="500k"
- CRF_VALUE=30
- AUDIO_BITRATE="64k"
- # Check if the directory argument is provided
- if [ $# -eq 0 ]; then
- echo "Usage: $0 <directory>"
- exit 1
- fi
- TARGET_DIR="$1"
- # Function to log messages
- log() {
- echo "$(date '+%Y-%m-%d %H:%M:%S') - $1"
- }
- # Function to handle errors
- handle_error() {
- log "Error occurred: $1"
- exit 1
- }
- for FILE in $(find "$TARGET_DIR" -type f \( -iname "*.mp4" -o -iname "*.mkv" -o -iname "*.avi" -o -iname "*.mov" -o -iname "*.m4v" -o -iname "*.wmv" \)); do
- log "Processing: $FILE"
- # Get video dimensions and frame rate
- DIMENSIONS=$(ffprobe -v error -select_streams v:0 -show_entries stream=width,height -of csv=s=x:p=0 "$FILE")
- WIDTH=$(echo $DIMENSIONS | cut -d'x' -f1)
- HEIGHT=$(echo $DIMENSIONS | cut -d'x' -f2)
- FPS=$(ffprobe -v error -select_streams v:0 -count_packets -show_entries stream=r_frame_rate -of csv=p=0 "$FILE" | bc -l | awk '{printf("%d\n",$1 + 0.5)}')
- # Determine scaling only if necessary
- SCALING=""
- if [ $WIDTH -lt $HEIGHT ]; then
- SHORTER_SIDE=$WIDTH
- if [ $WIDTH -gt $MAX_RESOLUTION ]; then
- SCALING="-vf scale=$MAX_RESOLUTION:-2"
- fi
- else
- SHORTER_SIDE=$HEIGHT
- if [ $HEIGHT -gt $MAX_RESOLUTION ]; then
- SCALING="-vf scale=-2:$MAX_RESOLUTION"
- fi
- fi
- # Add fps filter only if necessary
- FPS_FILTER=""
- if [ $FPS -gt $MAX_FPS ]; then
- FPS_FILTER="-vf fps=$MAX_FPS"
- fi
- # Get codec info
- CODEC_INFO=$(ffprobe -v error -select_streams v:0 -show_entries stream=codec_name -of default=noprint_wrappers=1:nokey=1 "$FILE")
- # Check if conversion is needed
- if [[ "$CODEC_INFO" != "hevc" && "$CODEC_INFO" != "h265" ]] || [ "$FPS" -gt "$MAX_FPS" ] || [ $SHORTER_SIDE -gt $MAX_RESOLUTION ]; then
- OUTPUT_FILE="${FILE%.*}.h265.mkv"
- # Combine scaling, FPS filtering, and codec selection
- ffmpeg_cmd=(
- "-i" "$FILE"
- $SCALING
- $FPS_FILTER
- "-c:v" "libx265"
- "-preset" "slow"
- "-crf" "$CRF_VALUE"
- "-c:a" "aac"
- "-b:a" "$AUDIO_BITRATE"
- "-movflags" "+faststart"
- "$OUTPUT_FILE"
- )
- log "Executing FFmpeg command: ${ffmpeg_cmd[*]}"
- ffmpeg "${ffmpeg_cmd[@]}" || handle_error "FFmpeg failed to encode $FILE"
- log "Conversion completed successfully."
- else
- log "No conversion needed for $FILE"
- fi
- done
- ```
- The problem is that the output video has a different resolution and frame rate than I expect:
- ```
- Input #0
- Stream #0:0[0x1](und): Video: hevc (Main 10) (hvc1 / 0x31637668), yuv420p10le(tv, bt2020nc/bt2020/arib-std-b67), 3840x2160, 94843 kb/s, 59.98 fps, 60 tbr, 600 tbn (default)
- Output #0
- Stream #0:0(und): Video: hevc, yuv420p10le(tv, bt2020nc/bt2020/arib-std-b67, progressive), 406x720, q=2-31, 1000 kb/s, 60 fps, 1k tbn (default)
- ```
- The output is 406x720 instead of the expected 1080x720, and 60 fps instead of the desired 30 fps. How can I fix this issue?
- Please help me understand why this is happening and how to achieve the desired output resolution and frame rate.
#1: Initial revision
ffmpeg script outputs video with unexpected resolution and frame rate despite scaling and fps filtering
I'm having trouble with an ffmpeg script that's supposed to convert videos to a specific resolution and frame rate, but the output video has unexpected dimensions and frame rate. Here's my script and the issue: ```bash #!/usr/bin/env bash if [ $# -eq 0 ]; then echo "Usage: $0 <directory>" exit 1 fi MAX_RESOLUTION=720 MAX_FPS=30 TARGET_DIR="$1" MAX_BITRATE="1M" CRF_VALUE=28 AUDIO_BITRATE="128k" # Find all video files recursively in the given directory find "$TARGET_DIR" -type f \( -iname "*.mp4" -o -iname "*.mkv" -o -iname "*.avi" -o -iname "*.mov" -o -iname "*.m4v" -o -iname "*.wmv" \) -print0 | while IFS= read -r -d '' FILE; do CODEC_INFO=$(ffprobe -v error -select_streams v:0 -show_entries stream=codec_name -of default=noprint_wrappers=1:nokey=1 "$FILE") BASENAME=$(basename -- "$FILE") NAME="${BASENAME%.*}" EXT="${BASENAME##*.}" OUTPUT_FILE="${FILE%.*}.h265.mkv" DIMENSIONS=$(ffprobe -v error -select_streams v:0 -show_entries stream=width,height -of csv=s=x:p=0 "$FILE") WIDTH=$(echo $DIMENSIONS | cut -d'x' -f1) HEIGHT=$(echo $DIMENSIONS | cut -d'x' -f2) FPS=$(ffprobe -v error -select_streams v:0 -count_packets -show_entries stream=r_frame_rate -of csv=p=0 "$FILE" | bc -l | awk '{printf("%d\n",$1 + 0.5)}') SCALING="" if [ $WIDTH -lt $HEIGHT ]; then SHORTER_SIDE=$WIDTH if [ $WIDTH -gt $MAX_RESOLUTION ]; then SCALING="-vf scale=$MAX_RESOLUTION:-2" fi else SHORTER_SIDE=$HEIGHT if [ $HEIGHT -gt $MAX_RESOLUTION ]; then SCALING="-vf scale=-2:$MAX_RESOLUTION" fi fi FPS_FILTER="" if [ $FPS -gt $MAX_FPS ]; then FPS_FILTER="-vf fps=$MAX_FPS" fi if [[ "$CODEC_INFO" != "hevc" && "$CODEC_INFO" != "h265" ]] || [ "$FPS" -gt "$MAX_FPS" ] || [ $SHORTER_SIDE -gt $MAX_RESOLUTION ]; then ffmpeg -i "$FILE" $SCALING $FPS_FILTER -c:v libx265 -b:v $MAX_BITRATE -crf $CRF_VALUE -c:a aac -b:a $AUDIO_BITRATE -preset slow "$OUTPUT_FILE" fi done ``` The problem is that the output video has a different resolution and frame rate than I expect: ``` Input #0 Stream #0:0[0x1](und): Video: hevc (Main 10) (hvc1 / 0x31637668), yuv420p10le(tv, bt2020nc/bt2020/arib-std-b67), 3840x2160, 94843 kb/s, 59.98 fps, 60 tbr, 600 tbn (default) Output #0 Stream #0:0(und): Video: hevc, yuv420p10le(tv, bt2020nc/bt2020/arib-std-b67, progressive), 406x720, q=2-31, 1000 kb/s, 60 fps, 1k tbn (default) ``` The output is 406x720 instead of the expected 1080x720, and 60 fps instead of the desired 30 fps. How can I fix this issue? Please help me understand why this is happening and how to achieve the desired output resolution and frame rate.