суббота, 8 декабря 2007 г.

Скрипт конвертирования видеофайлов для просмотра на КПК

С каждым днем мы становимся все мобильнее. Плеер для прослушивания музыки, аудиокниг и подкастов есть практически у каждого. В последнее же время стали распространятся и карманные видеоплееры. В качестве карманного видеоплеера я использую свой КПК. Но для того, чтобы посмотреть на нем какой-либо фильм, требуется сперва перекодировать видеофайл (уменьшить разрешение и битрейт), чтобы файл занимал как можно меньше места и не сильно загружал процессор при декодировании.

Поэтому я написал скрипт, выполняющий все необходимые для этого действия.

Краткая справка по возможностям скрипта:
$ my_video2pda -h
Использование: video2pda [-q] [-c] [-W pixels] [-H pixels] [-v bitrate] [-a bitrate] files...

video2pda предназначен для перекодирования видеофайлов для просмотра их на КПК и других карманных устройствах.
Видео кодируется кодеком Xvid, аудио - Vorbis. В качестве контейнера используется OGM. Если в одной папке с фильмом будут лежать субтитры, скрипт подхватит их и "вклеит" в видео (предполагается, что субтитры в кодировке cp1251).

Ключи:
-h : выводит это сообщение
-q : кодировать видео с высоким качеством - при кодировании используется двухпроходное сжатие и другие опции, улучшающие качество изображения (уменьшает скорость кодирования видео, но увеличивает качество)
-c : включить автоматическое кадрирование изображения (обрезает лишние пиксели по краям изображения, если таковые существуют)
-W : ширина экрана на устройстве (по умолчанию 320)
-H : высота экрана на устройстве (по умолчанию 240)
-v : битрейт видео (по умолчанию 300)
-a : битрейт аудио (по умолчанию 64)
Сам скрипт:
#!/bin/bash
#***************************************************************************
#*   Copyright (C) 2007, Konishchev Dmitry                                 *
#*   http://konishchevdmitry.blogspot.com/                                 *
#*                                                                         *
#*   This program is free software; you can redistribute it and/or modify  *
#*   it under the terms of the GNU General Public License as published by  *
#*   the Free Software Foundation; either version 3 of the License, or     *
#*   (at your option) any later version.                                   *
#*                                                                         *
#*   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.                          *
#**************************************************************************/

# Значения по умолчанию -->
screen_width=320
screen_height=240
video_bitrate=300
audio_bitrate=64
video_quality_settings=''
is_crop=0
# Значения по умолчанию <--

tmp_mplayer_output_file=/tmp/video2pda_mplayer_output_$$
tmp_audio_file=/tmp/video2pda_audio_$$
tmp_vorbis_audio_file=/tmp/video2pda_vorbis_audio_$$
tmp_video_file=/tmp/video2pda_video_$$
tmp_subtitles_file=/tmp/video2pda_subtitles_$$

usage="video2pda -h for help"
usage_describe="Использование: video2pda [-q] [-c] [-W pixels] [-H pixels] [-v bitrate] [-a bitrate] files...

video2pda предназначен для перекодирования видеофайлов для просмотра их на КПК и других карманных устройствах.
Видео кодируется кодеком Xvid, аудио - Vorbis. В качестве контейнера используется OGM. Если в одной папке с фильмом будут лежать субтитры, скрипт подхватит их и \"вклеит\" в видео (предполагается, что субтитры в кодировке cp1251).

Ключи:
-h : выводит это сообщение
-q : кодировать видео с высоким качеством - при кодировании используется двухпроходное сжатие и другие опции, улучшающие качество изображения (уменьшает скорость кодирования видео, но увеличивает качество)
-c : включить автоматическое кадрирование изображения (обрезает лишние пиксели по краям изображения, если таковые существуют)
-W : ширина экрана на устройстве (по умолчанию 320)
-H : высота экрана на устройстве (по умолчанию 240)
-v : битрейт видео (по умолчанию 300)
-a : битрейт аудио (по умолчанию 64)"

# Выводит страницу помощи
print_help()
{
echo -e "$usage_describe"
}

# Удаляет временные файлы
cleanup()
{
rm $tmp_mplayer_output_file $tmp_audio_file $tmp_vorbis_audio_file $tmp_video_file $tmp_subtitles_file divx2pass.log > /dev/null 2>&1
}

# Выводит ошибку
error()
{
echo "Ошибка! $1" | grep --color '.' >&2
if [ "$2" != "" ]
then
echo "Вывод $2:" >&2
echo "$3" | grep --color '.' >&2
fi
echo -e "Кодирование файла '$file' завершилось неудачей.\n" >&2

cleanup
}

# Получаем параметры, заданные пользователем -->
while getopts "hqcW:H:v:a:" option
do
case $option in
h ) print_help; exit 0;;
q ) video_quality_settings=':me_quality=6:vhq=4';;
c ) is_crop=1;;
W ) screen_width=$OPTARG;;
H ) screen_height=$OPTARG;;
v ) video_bitrate=$OPTARG;;
a ) audio_bitrate=$OPTARG;;
\? ) echo $usage; exit 1;;
* ) echo $usage; exit 1;;
esac
done

shift $(($OPTIND - 1))
# Получаем параметры, заданные пользователем <--

# Проверяем, передан ли хотя бы один файл -->
if [ "$1" == "" ]
then
echo $usage
exit 1
fi
# Проверяем, передан ли хотя бы один файл <--

# Проверяем, установлены ли у пользователя все необходимые программы -->
needed_soft=''

which 'mplayer' > /dev/null 2>&1
if [ $? -ne 0 ]
then
needed_soft="$needed_soft mplayer"
fi
which 'mencoder' > /dev/null 2>&1
if [ $? -ne 0 ]
then
needed_soft="$needed_soft mencoder"
fi
which 'oggenc' > /dev/null 2>&1
if [ $? -ne 0 ]
then
needed_soft="$needed_soft oggenc"
fi
which 'ogmmerge' > /dev/null 2>&1
if [ $? -ne 0 ]
then
needed_soft="$needed_soft ogmmerge"
fi

if [ "$needed_soft" != "" ]
then
echo "Для работы скрипта требуются следующие программы:$needed_soft." >&2
exit 1
fi
# Проверяем, установлены ли у пользователя все необходимые программы <--

# Кодируем каждый файл -->
while [ "$1" != "" ]
do
file="$1"

echo "Кодируется файл '$file'..."

# Проверяем, существует ли такой файл -->
if [ ! -e "$file" ]
then
error "Файла '$file' не существует."
shift
continue
fi
# Проверяем, существует ли такой файл <--

output_file=`basename "$file".ogm`
subtitles_file=`echo "$file" | sed 's/\\.avi$/\\.srt/'`

# Получаем размер исходного изображения -->
output=`mplayer "$file" -frames 1 -vo null -ao null 2>&1 > $tmp_mplayer_output_file`
mplayer_source_video_size=`egrep -o 'VO: \[null\] [[:digit:]]+x[[:digit:]]+ =>' $tmp_mplayer_output_file 2>/dev/null | egrep -o '[[:digit:]]+x[[:digit:]]+' 2>/dev/null`
if [ "$mplayer_source_video_size" == "" ]
then
error "Определение размеров исходного изображения завершилось неудачей." "mplayer" "$output"
shift
continue
fi
video_width=`echo "$mplayer_source_video_size" | sed 's/x/\n/g' | head --lines 1`
video_height=`echo "$mplayer_source_video_size" | sed 's/x/\n/g' | head --lines 2 | tail --lines 1`
echo "Размер исходного изображения: ${video_width}x${video_height}"
# Получаем размер исходного изображения <--


# Получаем звуковую дорожку и, если нужно, кадрируем изображение -->
echo "Получаем звуковую дорожку..."

# Если требуется кадрировать изображение
if [ $is_crop -ne 0 ]
then
output=`mplayer "$file" -vf cropdetect -ao pcm:fast:file=$tmp_audio_file -vo null 2>&1 > $tmp_mplayer_output_file`
# Если не требуется кадрировать изображение
else
output=`mplayer "$file" -ao pcm:fast:file=$tmp_audio_file -vo null 2>&1 > /dev/null`
fi

if [ $? -ne 0 ]
then
error "При получении звуковой дорожки произошла ошибка." "mplayer" "$output"
shift
continue
fi

# Дополнительная проверка, т. к. mplayer почему-то не возвращает ошибки даже если
# запрашиваемого файла не существует
if [ ! -e $tmp_audio_file ]
then
error "При получении звуковой дорожки произошла ошибка." "mplayer" "$output"
shift
continue
fi

# Если требуется кадрировать изображение
if [ $is_crop -ne 0 ]
then
mplayer_vf_value=`egrep -o 'crop=[[:digit:]]+:[[:digit:]]+:[[:digit:]]+:[[:digit:]]+' $tmp_mplayer_output_file 2>/dev/null | tail --lines=1 2>/dev/null`
if [ "$mplayer_vf_value" == "" ]
then
error "При получении информации об автоматическом кадрировании произошла ошибка." "mplayer" "$output"
shift
continue
fi

mplayer_vf_value="$mplayer_vf_value,"
video_width=`echo $mplayer_vf_value | sed 's/=/\\n/g' | sed 's/:/\\n/g' | egrep '[[:digit:]]+' | head --lines 1`
video_height=`echo $mplayer_vf_value | sed 's/=/\\n/g' | sed 's/:/\\n/g' | egrep '[[:digit:]]+' | head --lines 2 | tail --lines 1`
echo "Размер кадрированного исходного изображения: ${video_width}x${video_height}"
fi
# Получаем звуковую дорожку и, если нужно, кадрируем изображение <--

# Получаем размер конечного изображения -->
# Если размер изображения превышает размеры экрана
if [ $screen_width -lt $video_width -o $screen_height -lt $video_height ]
then
(( test_height = video_height * screen_width / video_width ))
if [ $test_height -le $screen_height ]
then
video_width=$screen_width
video_height=$test_height 
else
(( video_width = video_width * screen_height / video_height ))
video_height=$screen_height 
fi
fi

echo "Размер конечного изображения: ${video_width}x${video_height}"
# Получаем размер конечного изображения <--

# Кодируем звуковую дорожку -->
echo "Кодируем звуковую дорожку..."

if [ $audio_bitrate -lt 45 ]
then
is_mono='--downmix'
else
is_mono=''
fi

output=`oggenc --quiet $is_mono --bitrate=$audio_bitrate -o $tmp_vorbis_audio_file $tmp_audio_file 2>&1`
if [ $? -ne 0 ]
then
error "При кодировании звуковой дорожки произошла ошибка." "oggenc" "$output"
shift
continue
fi
# Кодируем звуковую дорожку <--

# Кодируем видео -->
echo "Кодируем видео..."

# Определяем, нужно ли вклеивать субтитры в видеофайл -->
if [ -e "$subtitles_file" ]
then
iconv -f cp1251 -t utf8 --silent -c "$subtitles_file" > $tmp_subtitles_file
subtitles="-sub $tmp_subtitles_file -subfont-text-scale 3 -utf8"
else
subtitles=''
fi
# Определяем, нужно ли вклеивать субтитры в видеофайл <--

# Если кодируем с обычным качеством
if [ "$video_quality_settings" == "" ]
then
output=`mencoder "$file" $subtitles -vf ${mplayer_vf_value}scale=$video_width:$video_height -oac copy -ovc xvid -xvidencopts bitrate=$video_bitrate -o $tmp_video_file -ffourcc xvid -forceidx 2>&1 >/dev/null`
if [ $? -ne 0 ]
then
error "При кодировании видео произошла ошибка." "mencoder" "$output"
shift
continue
fi
# Кодирование с повышенным качеством
else
for pass in 1 2
do
output=`mencoder "$file" $subtitles -vf ${mplayer_vf_value}scale=$video_width:$video_height -oac copy -ovc xvid -xvidencopts pass=$pass:bitrate=$video_bitrate$video_quality_settings -o $tmp_video_file -ffourcc xvid -forceidx 2>&1 >/dev/null`
if [ $? -ne 0 ]
then
error "При кодировании видео произошла ошибка." "mencoder" "$output"
shift
continue 2
fi
done
fi
# Кодируем видео <--

# Сливаем видео с аудио -->
echo "Формируем конечный файл..."

output=`ogmmerge -o "$output_file" -A $tmp_video_file $tmp_vorbis_audio_file 2>&1 > /dev/null`
if [ $? -ne 0 ]
then
error "При формировании конечного файла произошла ошибка." "ogmmerge" "$output"
shift
continue
fi
# Сливаем видео с аудио <--

cleanup

echo -e "OK\n"

shift
done
# Кодируем каждый файл <--

3 комментария:

dimanish комментирует...

Спасиб.

Роман Сыроежкин комментирует...

а как этим скриптом можно воспользоваться.

ну как файлик я его сохранил, а чего дальше?

Dmitry Konishchev комментирует...

Дайте этому файлу права на исполнение:
$ chmod +x video2pda
И можете запускать:
$ ./video2pda /path/to/video/file