Last active
May 6, 2026 09:30
-
-
Save jmkim/6e1a49de73d2cccff7b6845efea70587 to your computer and use it in GitHub Desktop.
아이리버 딕플 D7용 비디오 인코더 (mencoder XviD + MP3, 480x272, 30.000fps)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/sh | |
| # | |
| # encode_d7.sh -- IRIVER D7 video encoder (mencoder, XviD+MP3, 480x272, 30fps) | |
| # | |
| # POSIX /bin/sh | |
| # | |
| # SPDX-License-Identifier: MIT | |
| # Copyright: 2026 Jongmin Kim <jmkim@debian.org> | |
| set -u | |
| PROG=$(basename "$0") | |
| # ---------------- Tunables (env로도 override 가능) -------- | |
| : "${FPS:=30.000}" | |
| : "${WIDTH:=480}" | |
| : "${HEIGHT:=272}" | |
| : "${VBITRATE:=1000}" # XviD bitrate, kbps | |
| : "${VTHREADS:=$(getconf _NPROCESSORS_ONLN 2>/dev/null \ | |
| || nproc 2>/dev/null \ | |
| || echo 4)}" | |
| : "${ARATE:=44100}" # audio sample rate, Hz | |
| : "${ABITRATE:=128}" # MP3 CBR bitrate, kbps | |
| : "${PASSES:=2}" # 1 = single-pass, 2 = 2-pass (high quality, default) | |
| : "${VIDEO_EXTS:=avi mp4 m4v mkv mov wmv flv webm mpg mpeg ts}" | |
| # ---------------------------------------------------------- | |
| # 2-pass 통계 파일 정리 | |
| XVID_STATS=xvid-twopass.stats | |
| trap 'rm -f -- "$XVID_STATS"' EXIT INT TERM | |
| usage() { | |
| cat <<EOF | |
| Usage: $PROG [-h] INPUT [OUTPUT] | |
| IRIVER D7용 비디오 인코더 (mencoder XviD + MP3, ${WIDTH}x${HEIGHT}, ${FPS}fps). | |
| Arguments: | |
| INPUT 입력 파일 또는 디렉토리 | |
| OUTPUT 출력 경로 (선택) | |
| OUTPUT 결정 규칙: | |
| INPUT이 파일일 때: | |
| OUTPUT 미지정 -> <INPUT 부모>/<이름>.d7.avi | |
| OUTPUT이 디렉토리 -> <OUTPUT>/<이름>.avi | |
| OUTPUT이 파일 -> 지정 경로 그대로 사용 | |
| INPUT이 디렉토리일 때: | |
| OUTPUT 미지정 -> <INPUT>/d7_out | |
| OUTPUT이 디렉토리 -> 그 안에 각 영상이 <이름>.avi | |
| Options: | |
| -h 이 도움말을 출력하고 종료 | |
| Environment overrides (현재값): | |
| EOF | |
| printf ' %-14s %s\n' "FPS=$FPS" "프레임레이트" | |
| printf ' %-14s %s\n' "WIDTH=$WIDTH" "가로 해상도 (px)" | |
| printf ' %-14s %s\n' "HEIGHT=$HEIGHT" "세로 해상도 (px)" | |
| printf ' %-14s %s\n' "VBITRATE=$VBITRATE" "XviD 비트레이트 (kbps)" | |
| printf ' %-14s %s\n' "VTHREADS=$VTHREADS" "XviD 스레드 (기본: CPU 코어 수 자동 감지)" | |
| printf ' %-14s %s\n' "ARATE=$ARATE" "오디오 샘플레이트 (Hz)" | |
| printf ' %-14s %s\n' "ABITRATE=$ABITRATE" "MP3 CBR 비트레이트 (kbps)" | |
| printf ' %-14s %s\n' "PASSES=$PASSES" "1 = 단일패스, 2 = 2-pass (기본, 고품질)" | |
| printf " VIDEO_EXTS='%s'\n" "$VIDEO_EXTS" | |
| cat <<EOF | |
| Examples: | |
| $PROG video.mkv | |
| $PROG video.mkv out.avi | |
| $PROG video.mkv outdir/ | |
| $PROG indir/ outdir/ | |
| VBITRATE=1200 $PROG video.mkv | |
| ABITRATE=192 $PROG indir/ outdir/ | |
| EOF | |
| } | |
| # ---- option parsing (POSIX getopts) ---- | |
| while getopts 'h' opt; do | |
| case "$opt" in | |
| h) usage; exit 0 ;; | |
| ?) usage >&2; exit 2 ;; | |
| esac | |
| done | |
| shift $((OPTIND - 1)) | |
| if [ $# -lt 1 ] || [ $# -gt 2 ]; then | |
| usage >&2 | |
| exit 2 | |
| fi | |
| INPUT=$1 | |
| OUTPUT=${2:-} | |
| # ---- helpers ---- | |
| # 공통 mencoder 호출. $1=in, $2=out, $3=xvid extra (예: pass=1), $4=audio(yes|no) | |
| # 서브쉘 함수: 내부 변수 할당이 호출자에게 누출되지 않도록. | |
| run_mencoder() ( | |
| _in=$1 | |
| _out=$2 | |
| _xvid_extra=$3 | |
| _audio=$4 | |
| if [ -n "$_xvid_extra" ]; then | |
| _xvid="threads=${VTHREADS}:${_xvid_extra}:bitrate=${VBITRATE}" | |
| else | |
| _xvid="threads=${VTHREADS}:bitrate=${VBITRATE}" | |
| fi | |
| set -- "$_in" -o "$_out" \ | |
| -mc 0 \ | |
| -audio-preload 0.0 \ | |
| -noodml \ | |
| -ofps "$FPS" \ | |
| -vf-add "dsize=${WIDTH}:${HEIGHT}:0" \ | |
| -vf-add "scale=0:0" \ | |
| -vf-add "expand=${WIDTH}:${HEIGHT}:-1:-1:1" \ | |
| -ovc xvid \ | |
| -xvidencopts "$_xvid" | |
| if [ "$_audio" = yes ]; then | |
| set -- "$@" \ | |
| -srate "$ARATE" \ | |
| -oac mp3lame \ | |
| -lameopts "cbr:br=${ABITRATE}:mode=1:aq=0:padding=3" | |
| else | |
| set -- "$@" -nosound | |
| fi | |
| mencoder "$@" | |
| ) | |
| encode_one() { | |
| _in=$1 | |
| _out=$2 | |
| if [ "$PASSES" = 2 ]; then | |
| printf '==> %s [pass 1/2 analyze]\n' "$_in" | |
| run_mencoder "$_in" /dev/null pass=1 no || return $? | |
| printf ' -> %s [pass 2/2 encode]\n' "$_out" | |
| run_mencoder "$_in" "$_out" pass=2 yes | |
| else | |
| printf '==> %s\n -> %s\n' "$_in" "$_out" | |
| run_mencoder "$_in" "$_out" '' yes | |
| fi | |
| } | |
| # basename에서 확장자만 .avi 로 교체 | |
| to_avi_name() { | |
| _n=$(basename "$1") | |
| case "$_n" in | |
| *.*) printf '%s.avi\n' "${_n%.*}" ;; | |
| *) printf '%s.avi\n' "$_n" ;; | |
| esac | |
| } | |
| # 비디오 확장자인지 (대소문자 무시, $VIDEO_EXTS 기준) | |
| is_video_file() { | |
| _n=$(basename "$1") | |
| case "$_n" in | |
| *.*) _ext=${_n##*.} ;; | |
| *) return 1 ;; | |
| esac | |
| # to lower | |
| _ext=$(printf '%s' "$_ext" | tr '[:upper:]' '[:lower:]') | |
| for _e in $VIDEO_EXTS; do | |
| [ "$_ext" = "$_e" ] && return 0 | |
| done | |
| return 1 | |
| } | |
| check_mencoder() { | |
| command -v mencoder >/dev/null 2>&1 && return 0 | |
| { | |
| printf 'Error: mencoder가 설치되어 있지 않습니다.\n\n' | |
| printf '설치 방법:\n' | |
| if command -v apt >/dev/null 2>&1; then | |
| printf ' Debian/Ubuntu : sudo apt install mencoder\n' | |
| elif command -v dnf >/dev/null 2>&1; then | |
| printf ' Fedora/RHEL : sudo dnf install mencoder # RPM Fusion 활성화 필요\n' | |
| elif command -v zypper >/dev/null 2>&1; then | |
| printf ' openSUSE : sudo zypper install mplayer\n' | |
| elif command -v pacman >/dev/null 2>&1; then | |
| printf ' Arch Linux : yay -S mplayer-vaapi # 공식 저장소에서 제외됨, AUR 사용\n' | |
| elif command -v xbps-install >/dev/null 2>&1; then | |
| printf ' Void Linux : sudo xbps-install -S mplayer\n' | |
| elif command -v emerge >/dev/null 2>&1; then | |
| printf ' Gentoo : sudo emerge media-video/mplayer\n' | |
| elif command -v nix-env >/dev/null 2>&1; then | |
| printf ' NixOS : nix-env -iA nixpkgs.mplayer\n' | |
| elif command -v apk >/dev/null 2>&1; then | |
| printf ' Alpine : sudo apk add mplayer\n' | |
| elif [ "$(uname -s)" = Darwin ] && command -v brew >/dev/null 2>&1; then | |
| printf ' macOS (brew) : brew install mplayer\n' | |
| elif command -v brew >/dev/null 2>&1; then | |
| printf ' Homebrew : brew install mplayer\n' | |
| else | |
| printf ' 패키지 매니저를 자동 감지하지 못했습니다.\n' | |
| printf ' http://www.mplayerhq.hu/ 에서 빌드된 mencoder를 받거나\n' | |
| printf ' 사용 배포판의 패키지 매니저로 mplayer/mencoder를 설치하세요.\n' | |
| fi | |
| } >&2 | |
| exit 127 | |
| } | |
| # ---- dispatch ---- | |
| check_mencoder | |
| rc=0 | |
| if [ -f "$INPUT" ]; then | |
| if [ -z "$OUTPUT" ]; then | |
| _dir=$(dirname "$INPUT") | |
| _name=$(basename "$INPUT") | |
| case "$_name" in | |
| *.*) _stem=${_name%.*} ;; | |
| *) _stem=$_name ;; | |
| esac | |
| OUTPUT="${_dir}/${_stem}.d7.avi" | |
| elif [ -d "$OUTPUT" ]; then | |
| OUTPUT="${OUTPUT%/}/$(to_avi_name "$INPUT")" | |
| fi | |
| encode_one "$INPUT" "$OUTPUT" || rc=$? | |
| elif [ -d "$INPUT" ]; then | |
| if [ -z "$OUTPUT" ]; then | |
| OUTPUT="${INPUT%/}/d7_out" | |
| fi | |
| if [ -e "$OUTPUT" ] && [ ! -d "$OUTPUT" ]; then | |
| printf 'Error: INPUT은 디렉토리지만 OUTPUT이 디렉토리가 아닙니다: %s\n' "$OUTPUT" >&2 | |
| exit 1 | |
| fi | |
| mkdir -p "$OUTPUT" || exit 1 | |
| ok=0 | |
| fail=0 | |
| for f in "$INPUT"/*; do | |
| [ -f "$f" ] || continue | |
| is_video_file "$f" || continue | |
| out="${OUTPUT%/}/$(to_avi_name "$f")" | |
| if encode_one "$f" "$out"; then | |
| ok=$((ok + 1)) | |
| else | |
| fail=$((fail + 1)) | |
| rc=1 | |
| fi | |
| done | |
| if [ "$ok" -eq 0 ] && [ "$fail" -eq 0 ]; then | |
| printf 'Warning: %s 안에 비디오 파일이 없습니다.\n' "$INPUT" >&2 | |
| fi | |
| printf 'Done. success=%d failed=%d\n' "$ok" "$fail" | |
| else | |
| printf 'Error: INPUT 경로가 없거나 파일/디렉토리가 아닙니다: %s\n' "$INPUT" >&2 | |
| exit 1 | |
| fi | |
| exit "$rc" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment