[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