1
 
 

I write this to convert my old, multiple GiB, multimedia files to formats that are smaller in size and royalty free.

remove_extension() {
  sed -E 's/^(.+)\.[^.]+$/\1/'
}

get_extension() {
  sed -E '/^\.?[^.]+$/d; s/^.+\.([^.]*)$/\1/'
}

ffmpeg_av1_opus() {
  if [ "$#" -lt 4 ]; then
    return
  fi
  ffmpeg -n -i "$4" -c:v libsvtav1 -preset "$1" -crf "$2" -c:a libopus -vbr:a 1 -b:a "$3" "${5:-"$(echo "$4" | remove_extension)_ffmpeg_av1_$1_$2_opus_$3.mkv"}"
}

ffmpeg_av1_lossless_flac() {
  if [ "$#" -eq 0 ]; then
    return
  fi
  ffmpeg -n -i "$1" -c:v libsvtav1 -svtav1-params lossless=1 -preset -2 -c:a flac "${2:-"$(echo "$1" | remove_extension)_ffmpeg_av1_lossless_flac.mkv"}"
}

ffmpeg_opus() {
  if [ "$#" -lt 2 ]; then
    return
  fi
  ffmpeg -n -i "$2" -c:a libopus -vbr:a 1 -b:a "$1" "${3:-"$(echo "$2" | remove_extension)_ffmpeg_opus_$1.opus"}"
}

ffmpeg_flac() {
  if [ "$#" -eq 0 ]; then
    return
  fi
  ffmpeg -n -i "$1" -c:a flac "${2:-"$(echo "$1" | remove_extension)_ffmpeg_flac.flac"}"
}

ffmpeg_segment() {
  if [ "$#" -lt 2 ]; then
    return
  fi
  ffmpeg -n -i "$2" -c copy -map 0 -segment_time "$1" -f segment -reset_timestamps 1 "${3:-"$(echo "$2" | remove_extension)_ffmpeg_%04d.$(echo "$2" | get_extension)"}"
}

ffmpeg_concat_auto() {
  local files=()
  if [ "$#" -eq 0 ]; then
    for f in *; do
      test -f "$f" && files+=("$f")
    done
  else
    files=("$@")
  fi
  ffmpeg -n -f concat -safe 0 -i <(printf "file '$PWD/%s'\n" "${files[@]}") -c copy "$(echo "${files[0]}" | remove_extension | sed -E 's/_ffmpeg_[0-9]+$//').$(echo "${files[0]}" | get_extension)"
}

ffmpeg_concat() {
  if [ "$#" -lt 2 ]; then
    return
  fi
  ffmpeg -n -f concat -safe 0 -i <(printf "file '$PWD/%s'\n" "${@:2}") -c copy "$1"
}

echo_non_ffmpeg() {
  while IFS= read -r -d '' f; do
    case "$f" in
      *ffmpeg_*) ;;
      *)
        echo "$f"
        ;;
    esac
  done < <(find . -type f -print0)
}

remove_non_ffmpeg() {
  while IFS= read -r -d '' f; do
    case "$f" in
      *ffmpeg_*) ;;
      *)
        rm -f -- "$f"
        ;;
    esac
  done < <(find . -type f -print0)
}

echo_ffmpeg() {
  while IFS= read -r -d '' f; do
    case "$f" in
      *ffmpeg_*)
        echo "$f"
        ;;
      *) ;;
    esac
  done < <(find . -type f -print0)
}

remove_ffmpeg() {
  while IFS= read -r -d '' f; do
    case "$f" in
      *ffmpeg_*)
        rm -f -- "$f"
        ;;
      *) ;;
    esac
  done < <(find . -type f -print0)
}

jxl_lossy() {
  if [ "$#" -lt 2 ]; then
    return
  fi
  cjxl -j 0 -e 10 -d "$1" "$2" "${3:-"$(echo "$2" | remove_extension).jxl"}"
}

jxl_lossless() {
  if [ "$#" -eq 0 ]; then
    return
  fi
  cjxl -j 1 -e 10 -d 0 "$1" "${2:-"$(echo "$1" | remove_extension).jxl"}"
}

multimedia_convert() {
  (
    shopt -s globstar nullglob
    for f in **/*; do
      [[ -f $f ]] || continue
      local file=${f##*/}
      local dir=${f%/*}
      [[ $dir == "$f" ]] && dir=.
      case ${file,,} in
        *.gif)
          if [[ ${file##*.} != gif ]]; then
            if [[ -e "${f%.*}.gif" ]]; then
              printf 'Skipping: output exists: %s\n' "$f" >&2
              continue
            fi
            mv -- "$f" "${f%.*}.gif"
          fi
          ;;
        *.flac)
          if [[ ${file##*.} != flac ]]; then
            if [[ -e "${f%.*}.flac" ]]; then
              printf 'Skipping: output exists: %s\n' "$f" >&2
              continue
            fi
            mv -- "$f" "${f%.*}.flac"
          fi
          ;;
        *.jpg | *.jpeg | *.png)
          local jxl="${file%.*}.jxl"
          if [[ -e "$dir/$jxl" ]]; then
            printf 'Skipping: output exists: %s\n' "$f" >&2
            continue
          fi
          (
            cd "$dir" &&
              jxl_lossy 1 "./$file" "./$jxl" &&
              rm -- "$file"
          )
          ;;
        *.avif | *.bmp | *.heic | *.ico | *.jp2 | *.tif | *.webp)
          local png="${file%.*}.png"
          if [[ -e "$dir/$png" ]]; then
            printf 'Skipping: intermediate png exists: %s\n' "$f" >&2
            continue
          fi
          local jxl="${file%.*}.jxl"
          if [[ -e "$dir/$jxl" ]]; then
            printf 'Skipping: output exists: %s\n' "$f" >&2
            continue
          fi
          (
            cd "$dir" &&
              magick "./$file" "./$png" && {
              jxl_lossy 1 "./$png" "./$jxl" &&
                rm -- "$file" ||
                true
            } &&
              rm -f -- "$png"
          )
          ;;
        *.3gp | *.mov | *.vob | *.wmv)
          (
            cd "$dir" &&
              ffmpeg_av1_opus 4 40 24k "./$file" &&
              rm -- "$file"
          )
          ;;
        *.avi | *.mkv | *.mp4)
          (
            cd "$dir" &&
              ffmpeg_av1_opus 4 32 72k "./$file" &&
              rm -- "$file"
          )
          ;;
        *.aac | *.mp3 | *.m4a | *.ogg)
          (
            cd "$dir" &&
              ffmpeg_opus 96k "./$file" &&
              rm -- "$file"
          )
          ;;
        *.wav)
          (
            cd "$dir" &&
              ffmpeg_flac "./$file" &&
              rm -- "$file"
          )
          ;;
        *)
          continue
          ;;
      esac
    done
  )
}
2
submitted 5 days ago* (last edited 3 days ago) by to c/ffmpeg@programming.dev
 
 
remove_extension() {
  sed -E 's/^(.+)\.[^.]+$/\1/'
}

get_extension() {
  sed -E '/^\.?[^.]+$/d; s/^.+\.([^.]*)$/\1/'
}

ffmpeg_av1_opus() {
  if [ "$#" -lt 4 ]; then
    return
  fi
  ffmpeg -i "$4" -c:v libsvtav1 -preset "$1" -crf "$2" -c:a libopus -vbr:a 1 -b:a "$3" "${5:-"$(echo "$4" | remove_extension)_ffmpeg_av1_$1_$2_opus_$3.mkv"}"
}

ffmpeg_av1_lossless_flac() {
  if [ "$#" -eq 0 ]; then
    return
  fi
  ffmpeg -i "$1" -c:v libsvtav1 -svtav1-params lossless=1 -preset -2 -c:a flac "${2:-"$(echo "$1" | remove_extension)_ffmpeg_av1_lossless_flac.mkv"}"
}

ffmpeg_opus() {
  if [ "$#" -lt 2 ]; then
    return
  fi
  ffmpeg -i "$2" -c:a libopus -vbr:a 1 -b:a "$1" "${3:-"$(echo "$2" | remove_extension)_ffmpeg_opus_$1.opus"}"
}

ffmpeg_flac() {
  if [ "$#" -eq 0 ]; then
    return
  fi
  ffmpeg -i "$1" -c:a flac "${2:-"$(echo "$1" | remove_extension)_ffmpeg_flac.flac"}"
}

ffmpeg_segment() {
  if [ "$#" -lt 2 ]; then
    return
  fi
  ffmpeg -i "$2" -c copy -map 0 -segment_time "$1" -f segment -reset_timestamps 1 "${3:-"$(echo "$2" | remove_extension)_ffmpeg_%04d.$(echo "$2" | get_extension)"}"
}

ffmpeg_concat_auto() {
  local files=()
  if [ "$#" -eq 0 ]; then
    for f in *; do
      test -f "$f" && files+=("$f")
    done
  else
    files=("$@")
  fi
  ffmpeg -f concat -safe 0 -i <(printf "file '$PWD/%s'\n" "${files[@]}") -c copy "$(echo "${files[0]}" | remove_extension | sed -E 's/_ffmpeg_[0-9]+$//').$(echo "${files[0]}" | get_extension)"
}

ffmpeg_concat() {
  if [ "$#" -lt 2 ]; then
    return
  fi
  ffmpeg -f concat -safe 0 -i <(printf "file '$PWD/%s'\n" "${@:2}") -c copy "$1"
}

echo_non_ffmpeg() {
  while IFS= read -r -d '' f; do
    case "$f" in
      *ffmpeg_*) ;;
      *)
        echo "$f"
        ;;
    esac
  done < <(find . -type f -print0)
}

remove_non_ffmpeg() {
  while IFS= read -r -d '' f; do
    case "$f" in
      *ffmpeg_*) ;;
      *)
        rm -f "$f"
        ;;
    esac
  done < <(find . -type f -print0)
}

echo_ffmpeg() {
  while IFS= read -r -d '' f; do
    case "$f" in
      *ffmpeg_*)
        echo "$f"
        ;;
      *) ;;
    esac
  done < <(find . -type f -print0)
}

remove_ffmpeg() {
  while IFS= read -r -d '' f; do
    case "$f" in
      *ffmpeg_*)
        rm -f "$f"
        ;;
      *) ;;
    esac
  done < <(find . -type f -print0)
}

mv_space_underscore() {
  while IFS= read -r -d '' f; do
    new="${f// /_}"
    [[ -e "$new" ]] && {
      echo "skipping '$f', '$new' exists"
      continue
    }
    mv -- "$f" "$new"
  done < <(find . -depth -name '* *' -print0)
}

mv_space_hyphen() {
  while IFS= read -r -d '' f; do
    new="${f// /-}"
    [[ -e "$new" ]] && {
      echo "skipping '$f', '$new' exists"
      continue
    }
    mv -- "$f" "$new"
  done < <(find . -depth -name '* *' -print0)
}

Edit: Add -vbr:a 1 to opus, thanks to exdor.

3
Welcome! Introduction (programming.dev)
submitted 5 days ago* by [M] to c/ffmpeg@programming.dev
 
 

Hi all!

Only after I made an account on this instance I saw that there already is a community on lemmy.world. many instances might defederate, so this one is useful.

My motivation: I use / have used ffmpeg for

  • encoding any audio to opus, variable bitrate (there are 2 modes, not sure why and mode 1 seems to be better)
  • converting stereo audio to mono, duplicated to 2 channels
  • cutting audio and video
  • encoding any kind of video to AV1, using svt_av1 (the software encoder which sadly produces way better results than qsv_av1 on my Intel Arc)
  • extracting screenshots from video
  • converting multiple images into a video for timelapse recordings
  • converting videos to animated images (webp)
  • add metadata to videos and audios
  • concatenate audiobooks in several folders to a single file including chapter metadata
  • ...

I will post all my scripts here in some time and hope for an engaging community to exchange tips, parameters etc! Ffmpeg is not very easy to use but incredibly efficient!