[prev in list] [next in list] [prev in thread] [next in thread]
List: mplayer-users
Subject: [MPlayer-users] avi2mp4.sh v1.1.2, convert videos for your iPod
From: Sebastian Kemper <sebastian_ml () gmx ! net>
Date: 2008-01-29 21:11:50
Message-ID: 20080129211150.GA5920 () section-eight
[Download RAW message or body]
1.1.0: - Remove bogus comma from sed call (BASENAME="...")
- Remove redundant scale command from bc call
- Check for (and prevent) upscaling of video
- Lower the bitrate with regards to BPP
- Move crop detection around
- Update crop detection for special cases w=0 and h=0; this
also fixes a potential division by zero
- Update comments
- Add CH and CW to function c so both get unset
- Dimension -> Resolution
- Display $CW x $CH as resolution if available
- Make sure ID_VIDEO_WIDTH, ID_VIDEO_HEIGHT, ID_VIDEO_FPS and
ID_AUDIO_NCH aren't negative
- Fix the for loop that looks at output resolutions
1.1.1: - Fix behaviour when supplied cropping values are bogus
1.1.2: - Another attempt to correct the behaviour in case of bogus
crop values; only accept numbers and let mencoder do the
dying
- Change loop expression in c-style for-loop once more just for
correctness' sake
["avi2mp4.sh" (application/x-sh)]
#!/bin/bash
# Copyright (C) 2008 Sebastian Kemper (sebastian_ml @ gmx net)
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# This script converts video files in batch mode to MP4s for your iPod.
VERSION="1.1.2"
# History:
# 1.0.4: - Fixed a typo in comments
# - Start version history
# - Change FAAC_ENCOPTS comment
# - Introduce $MFPS for accurate FPS
# - Add '-noskip -mc 0' to mencoder calls
# - Add check for frame rates greater than 30
# - Add lock file
# - Exit on error
# - Set keyint/keyint_min
# - Add note regarding MP4Box and filenames
# - Write down requirements
# 1.0.5: - Small change to comments
# - Use myidentify instead of midentify; now input pixel aspect
# ratio doesn't have to be 1:1 anymore
# - Function c; unset variables containing essential file
# properties and continue
# - Protect mplayer from input while extracting audio
# (-nolirc -noconsolecontrols etc.)
# - Remove AVI requirement; now any file is possible as input
# - Add VFOPTS variable
# 1.0.6: - Remove '-noskip -mc 0' again
# - Change "Usage: ..." info
# - Add rough sketch about what the script does and what it can't
# do
# - Add note about iPod import
# - Print target bitrate and bpp
# - Unset LC_ALL and set LC_NUMERIC to POSIX to make sure we get
# dot instead of comma as decimal separator as bc expects a dot
# 1.0.7: - Add a little enhancement to function c; ability to return to
# the n^th enclosing loop
# - Fix two function c calls returning to the wrong loops
# 1.0.8: - Remove myidentify log when skipping file
# - Use rm -f
# - Add possibility to add options to mencoder calls through
# $MENCODER_OPTS
# 1.0.9: - In case aspect ratio is not set simply assume Width:Height
# - Add -endpos .1 to myidentify to prevent playback of audio
# files; thanks to Reimar Doeffinger for the tip
# - Check $VFOPTS for cropping; if detected calculate new aspect
# ratio so we get a proper output resolution
# 1.1.0: - Remove bogus comma from sed call (BASENAME="...")
# - Remove redundant scale command from bc call
# - Check for (and prevent) upscaling of video
# - Lower the bitrate with regards to BPP
# - Move crop detection around
# - Update crop detection for special cases w=0 and h=0; this
# also fixes a potential division by zero
# - Update comments
# - Add CH and CW to function c so both get unset
# - Dimension -> Resolution
# - Display $CW x $CH as resolution if available
# - Make sure ID_VIDEO_WIDTH, ID_VIDEO_HEIGHT, ID_VIDEO_FPS and
# ID_AUDIO_NCH aren't negative
# - Fix the for loop that looks at output resolutions
# 1.1.1: - Fix behaviour when supplied cropping values are bogus
# 1.1.2: - Another attempt to correct the behaviour in case of bogus
# crop values; only accept numbers and let mencoder do the
# dying
# - Change loop expression in c-style for-loop once more just for
# correctness' sake
# Notes:
# Before putting this script to serious use try encoding a few
# _samples_ first. This is the best way to test your options.
# This script can process multiple input files. For every file the
# script tries to calculate a proper output resolution. If one is found
# the file gets converted to H264 video/AAC LC audio and finally wrapped
# up in MP4. The only video filter applied throughout the process is
# mencoder's "scale" filter (unless the user wants other filters
# prepended; read on for more info).
# This script can't do framerate conversion. Neither can it handle
# variable framerates. Another thing it can't do is select between
# available audio/video tracks. You can influence mencoder's choices via
# $MENCODER_OPTS, though. For instance passing "-alang en,eng," to
# mencoder will guarantee that it picks these two language codes over
# any other.
# There are different ways to import the resulting files onto your iPod.
# For instance you can use amarok or gtkpod. Or you could try iTunes. It
# may be necessary to run MP4Box -ipod <MP4> before iTunes accepts the
# file for transfer. Feedback welcome.
# You can specify extra video filters on a per file basis. To do so
# simply put _one_ line of options in a file named like the input file
# with the suffix .vf (e.g. input.avi.vf for input.avi). This file has
# to be in the same directory as the input file. Your choice of filters
# will be prepended to the preset filter chain (scale=x:y,harddup). This
# can be used to deinterlace and crop.
# Example: "yadif=0,crop=716:576:2:0" (without the quotes)
# MP4Box is a great tool but it has some issues. For instance it can't
# handle filenames very well. So, in case MP4Box dies on you with no
# apparent reason just try this:
#
# a) shorten the filename of your input file
# b) make sure the filename consists of ASCII characters only
#
# I suggest you check the filenames up front each time you call this
# script; imagine you'd have to encode a file all over again just
# because of this silly MP4Box bug.
# Also make sure you have enough space left in your $TMP_DIR and
# $WORK_DIR!
# Requirements:
# - coreutils
# - bc calculator
# - findutils
# - faac audio encoder
# - mplayer (with support for your input files)
# - mencoder (with x264 support)
# - aacgain (to ReplayGain the audio; you should at least have v1.7.0)
# - MP4Box (part of the gpac suite; v0.4.4 or later required)
# Configuration: #
# Options can be set in the script itself or, preferably, in a file in
# the user's home directory, namely ~/.avi2mp4.conf.
# Directory for temporary files. Files created there will be deleted.
#
# Example:
# TMP_DIR="${HOME}/rip/tmp"
TMP_DIR=""
# The directory where the resulting MP4 files will be put.
#
# Example:
# WORK_DIR="${HOME}/rip"
WORK_DIR=""
# The maximum video bitrate you want your videos to have. The bitrate
# will be lowered automatically, depending on BPP (see below), output
# width, height and framerate. Be careful with this setting; don't set
# it too high. Some iPods support up to 1500 kbit/s, others more. Check
# your iPod's manual.
#
# Example:
# MAX_BITRATE="500"
MAX_BITRATE=""
# Your choice for bpp. That's "bits per pixel":
#
# bpp = ( video_bitrate * 1000 ) / ( fps * width * height )
#
# Sane range is 0.15 - 0.25. Higher BPP usually means higher quality but
# this is just a rule of thumb. Anyway, for batch encoding this is a
# good ruler.
#
# Example:
# BPP="0.19"
BPP=""
# faac encoding options. You can usually leave this empty. Keep your
# iPod's audio bitrate limit in mind, though.
# Example:
#
# FAAC_ENCOPTS="-q 80"
FAAC_ENCOPTS=""
# x264 encoding options. "nocabac" and "level_idc=30" will be preset.
# Same goes for "keyint" and "keyint_min".
# Do _not_ enable B-Frames or CABAC! As you probably already know iPods
# do have limitations %)
#
# Example:
# X264_ENCOPTS="frameref=3:turbo=1:partitions=all:mixed_refs=1:fast_pskip=0:threads=auto"
# Check the mencoder man page for more options if you like.
X264_ENCOPTS=""
# Extra options to pass to mencoder. For example I like to use the
# following:
#
# MENCODER_OPTS="-sws 1"
MENCODER_OPTS=""
# End of configuration #
function e {
if [ ${ERROR} != 0 ]
then
echo
echo "An error occurred. Check program output. Exiting."
exit 1
fi
}
function c {
unset -v ID_DEMUXER ID_VIDEO_WIDTH ID_VIDEO_HEIGHT ID_VIDEO_FPS ID_VIDEO_ASPECT \
VFOPTS ID_AUDIO_CODEC ID_AUDIO_NCH CH CW
continue ${1}
}
function myidentify {
mplayer -endpos .1 -vo null -ao null -frames 1 -identify "${1}" 2>/dev/null |
sed -ne '/^ID_/ {
s/[]()|&;<>`'"'"'\\!$" []/\\&/g;p
}'
}
function remlog {
rm -f "${TMP_DIR}"/"${BASENAME}"_myidentify.log
}
AVI2MP4=`basename "${0}"`
echo "${AVI2MP4} v${VERSION}"
[[ -f ~/.avi2mp4.conf ]] && source ~/.avi2mp4.conf
unset -v VFOPTS LC_ALL
export LC_NUMERIC="POSIX"
for i in bc xargs faac mplayer mencoder aacgain MP4Box
do
if ! [ -x "`which ${i} 2>/dev/null`" ]
then
echo
echo "${i} is missing. Exiting."
exit 1
fi
done
for i in WORK_DIR TMP_DIR MAX_BITRATE BPP
do
eval j=\$${i}
if [ -z ${j} ]
then
echo
echo "${i} is not set. Exiting."
exit 1
fi
done
for i in WORK_DIR TMP_DIR
do
eval j=\$${i}
if ! [ -d "${j}" ]
then
echo
echo "${i} does not exist or is not a directory. Exiting."
exit 1
fi
if ! [ -w "${j}" ]
then
echo
echo "${i} is not writable. Exiting."
exit 1
fi
done
if [ ${#} = 0 ]
then
echo
echo "Usage: ${AVI2MP4} <file> [<another file>] ..."
exit 0
fi
if [ ${X264_ENCOPTS} ]
then
X264_ENCOPTS=:${X264_ENCOPTS}
fi
for i in "${@}"
do
BASENAME=`basename "${i}" | sed 's/\(.*\)\.[a-z0-9]*/\1/'`
FILENAME=`basename "${i}"`
DIRNAME=`dirname "${i}"`
echo
echo -e "File:\t\t\t${FILENAME}"
echo
if ! [ -e "${i}" ]
then
echo "Input file does not exist. Skipping."
c
fi
if [ -e "${WORK_DIR}"/"${BASENAME}".mp4 ]
then
echo "File already converted to MP4. Skipping."
c
fi
if [ -e "${TMP_DIR}"/"${BASENAME}".lock ]
then
echo "Conversion of input file already underway. If this is not the case"
echo "remove the stale lock file and run this script again. Skipping."
c
fi
# Get properties of file
myidentify "${i}" > "${TMP_DIR}"/"${BASENAME}"_myidentify.log
source "${TMP_DIR}"/"${BASENAME}"_myidentify.log
for j in ID_DEMUXER ID_VIDEO_WIDTH ID_VIDEO_HEIGHT ID_VIDEO_FPS ID_VIDEO_ASPECT \
ID_AUDIO_CODEC ID_AUDIO_NCH
do
eval k=\$${j}
if ! [ ${k} ]
then
echo "Input file not recognized as a valid media file. Skipping."
remlog
c 2
fi
done
for j in ID_VIDEO_WIDTH ID_VIDEO_HEIGHT ID_VIDEO_FPS ID_AUDIO_NCH
do
eval k=\$${j}
IS_NULL=`echo "${k}<=0" | bc -l`
if [ ${IS_NULL} = 1 ]
then
echo "Input file properties invalid. Skipping."
remlog
c 2
fi
done
if [ `echo "${ID_VIDEO_ASPECT}==0" | bc -l` = 1 ]
then
echo "Video aspect not set. Assuming Width:Height."
echo
ID_VIDEO_ASPECT=`echo "${ID_VIDEO_WIDTH}/${ID_VIDEO_HEIGHT}" | bc -l \
| xargs printf "%1.4f\n"` fi
[[ -f "${i}".vf ]] && VFOPTS=`head -n1 "${i}".vf`
if [ ${VFOPTS} ]
then
VFOPTS=${VFOPTS},
CW=`echo ${VFOPTS} | grep -o crop=[0-9:]* | tail -n1 | sed 's/crop=//' | sed \
's/:.*//'` CH=`echo ${VFOPTS} | grep -o crop=[0-9:]* | tail -n1 | sed 's/crop=//' | \
sed "s/${CW}://" | sed 's/:.*//'`
if [ ${CW} ] || [ ${CH} ]
then
echo "Cropping detected. Calculating new aspect ratio."
echo
if ! [ ${CW} ] || [ ${CW} = 0 ] || [ ${CW} -gt ${ID_VIDEO_WIDTH} ]
then
CW=${ID_VIDEO_WIDTH}
fi
if ! [ ${CH} ] || [ ${CH} = 0 ] || [ ${CH} -gt ${ID_VIDEO_HEIGHT} ]
then
CH=${ID_VIDEO_HEIGHT}
fi
ID_VIDEO_ASPECT=`echo \
"(${CW}*${ID_VIDEO_ASPECT}*${ID_VIDEO_HEIGHT})/(${CH}*${ID_VIDEO_WIDTH})" | bc -l | \
xargs printf "%1.4f\n"` fi
fi
echo -e "Resolution:\t\t${CW:-${ID_VIDEO_WIDTH}}x${CH:-${ID_VIDEO_HEIGHT}}"
echo -e "FPS:\t\t\t${ID_VIDEO_FPS}"
echo -e "Aspect:\t\t\t${ID_VIDEO_ASPECT}"
echo
if [ `echo "${ID_VIDEO_FPS}>30" | bc -l` = 1 ]
then
echo "Input framerate is greater than 30. iPod's can only handle"
echo "up to 30 frames per second. This script doesn't support framerate"
echo "conversion. Skipping."
remlog
c
fi
for ((OUT_HORIZ=640, LEGIT=0; OUT_HORIZ>=16; OUT_HORIZ-=16))
do
# We don't want to scale up the video in any case
if [ ${OUT_HORIZ} -gt ${CW:-${ID_VIDEO_WIDTH}} ]
then
continue
fi
MULTIPLIER=`echo "${OUT_HORIZ}/(${ID_VIDEO_ASPECT}*16)" | bc -l | xargs printf \
"%1.0f\n"`
OUT_VERT=`echo "16*${MULTIPLIER}" | bc -l`
IS_NULL=`echo "${OUT_VERT}<16" | bc -l`
if [ ${IS_NULL} = 1 ]
then
echo "Output height too small. Skipping."
remlog
c 2
fi
if [ ${OUT_VERT} -gt ${CH:-${ID_VIDEO_HEIGHT}} ]
then
continue
fi
OUT_BPP=`echo "((${MAX_BITRATE}*1000)/(${ID_VIDEO_FPS}*${OUT_HORIZ}*${OUT_VERT}))" \
| bc -l | xargs printf "%1.4f\n"` LEGIT=`echo "${OUT_BPP}>=${BPP}" | bc -l`
if [ ${LEGIT} = 1 ]
then
break
fi
done
if [ ${LEGIT} = 0 ]
then
echo "No valid output resolution found. Skipping."
remlog
c
fi
# Adapt the bitrate (see bpp formula in comments)
BITRATE=`echo "(${BPP}*${ID_VIDEO_FPS}*${OUT_VERT}*${OUT_HORIZ})/1000" | bc -l | \
xargs printf "%1.0f\n"`
echo -e "Output resolution:\t${OUT_HORIZ}x${OUT_VERT}"
echo -e "Target video bitrate:\t${BITRATE} kbit/s"
echo -e "Target bits per pixel:\t${BPP}"
echo
echo "Creating lock file:"
touch "${TMP_DIR}"/"${BASENAME}".lock
ERROR=${?}
e
echo "${TMP_DIR}/${BASENAME}.lock"
echo "Lock file created."
echo
# Mencoder likes accurate FPS
if [ ${ID_VIDEO_FPS} = 23.976 ]
then
MFPS='24000/1001'
elif [ ${ID_VIDEO_FPS} = 29.970 ]
then
MFPS='30000/1001'
else
MFPS=${ID_VIDEO_FPS}
fi
# Set keyint/keyint_min depending on $ID_VIDEO_FPS
KEYINT_MIN=`echo "${ID_VIDEO_FPS}" | xargs printf "%1.0f\n"`
KEYINT=`echo "${ID_VIDEO_FPS}*10" | bc -l | xargs printf "%1.0f\n"`
echo "MEncoder 1st pass:"
echo
mencoder "${i}" -oac copy -ovc x264 -vf \
${VFOPTS}scale=${OUT_HORIZ}:${OUT_VERT},harddup -ofps ${MFPS} -x264encopts \ \
pass=1:bitrate=${BITRATE}:keyint=${KEYINT}:keyint_min=${KEYINT_MIN}:nocabac:level_idc=30${X264_ENCOPTS} \
\
-o /dev/null -passlogfile "${TMP_DIR}"/"${BASENAME}"_mencoder.log ${MENCODER_OPTS}
ERROR=${?}
e
echo
echo "MEncoder 2nd pass:"
echo
mencoder "${i}" -oac copy -ovc x264 -vf \
${VFOPTS}scale=${OUT_HORIZ}:${OUT_VERT},harddup -ofps ${MFPS} -x264encopts \ \
pass=2:bitrate=${BITRATE}:keyint=${KEYINT}:keyint_min=${KEYINT_MIN}:nocabac:level_idc=30${X264_ENCOPTS} \
\
-o "${TMP_DIR}"/"${BASENAME}"_mencoder.avi -passlogfile \
"${TMP_DIR}"/"${BASENAME}"_mencoder.log ${MENCODER_OPTS} ERROR=${?}
e
echo
echo "Extracting audio:"
echo
mplayer "${TMP_DIR}"/"${BASENAME}"_mencoder.avi -vc null -vo null -ao \
pcm:fast:file="${TMP_DIR}"/"${BASENAME}"_mplayer.wav -noconsolecontrols \
-nolirc -nojoystick -nomouseinput
ERROR=${?}
e
echo
echo "Encoding audio:"
echo
faac -o "${TMP_DIR}"/"${BASENAME}"_faac.m4a ${FAAC_ENCOPTS} \
"${TMP_DIR}"/"${BASENAME}"_mplayer.wav ERROR=${?}
e
echo
echo "Applying ReplayGain:"
echo
aacgain -r -k "${TMP_DIR}"/"${BASENAME}"_faac.m4a
ERROR=${?}
e
echo
echo "Extracting raw x264 bitstream from video:"
echo
MP4Box -aviraw video "${TMP_DIR}"/"${BASENAME}"_mencoder.avi
ERROR=${?}
e
echo
echo "Muxing:"
echo
MP4Box -itags name="${BASENAME}" -new -add "${TMP_DIR}"/"${BASENAME}"_faac.m4a \
-add "${TMP_DIR}"/"${BASENAME}"_mencoder_video.h264:fps=${ID_VIDEO_FPS} -tmp \
"${TMP_DIR}" \ "${WORK_DIR}"/"${BASENAME}".mp4
ERROR=${?}
e
echo
echo "Cleaning up."
rm -f "${TMP_DIR}"/"${BASENAME}"_mencoder.log \
"${TMP_DIR}"/"${BASENAME}"_mencoder.avi \ "${TMP_DIR}"/"${BASENAME}"_mplayer.wav \
"${TMP_DIR}"/"${BASENAME}"_faac.m4a \ "${TMP_DIR}"/"${BASENAME}"_mencoder_video.h264 \
"${TMP_DIR}"/"${BASENAME}".lock \ "${TMP_DIR}"/"${BASENAME}"_myidentify.log
ERROR=${?}
e
echo "Encoding ${BASENAME}.mp4 finished."
c
done
_______________________________________________
MPlayer-users mailing list
MPlayer-users@mplayerhq.hu
https://lists.mplayerhq.hu/mailman/listinfo/mplayer-users
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic