GUI-конвертер pspvc конечно отлично подходит для создания одного-двух фильмов для PSP, удобен быстрым интуитивным доступом к настройкам и возможностью точно сгенерировать превью, однако удобным быть перестаёт в случае необходимости конвертирования целого набора видеофайлов.

В связи с этим выкладываю скрипт для пакетного конвертирования сразу нескольких видеофайлов для просмотра на PSP под Linux с gentoo-wiki с моими небольшими доработками, а именно:

1) Добавлен мини-конфиг: можно прописать путь к перекодированным файлам, задержку при создании превью и путь к ffmpeg (я, как видите,
использую не стандартный ffmpeg, а оный из поставки pspvc)

2) Проблема в том, что если вы перекодировали файл, переместили его на psp, а затем перекодировали ещё один,
имя нового файла так же будет M4V10001.MP4, потому что скрипт конечно не знает о существовании файла с таким же именем на psp
(и, конечно, никто кроме вас об этом не знает).
Я предлагаю решение: каждый раз при запуске скрипта вбивать некое значение (постфикс), которое будет прибавляться к цифровой части имени файла.
Это особенно удобно если вы например кодируете сериал: первый сезон с постфиксом 101, второй 201 и т.п. для получения говорящих имён файлов.
По умолчанию файлы по прежнему начинают именоваться с M4V10001.MP4, так что если не предвидиться конфликтов имён, вместо ввода постфикса можно просто нажать enter.

Собственно листинг:



#!/bin/bash
#script name: make_psp_movie.sh
# Converter for batch video encoding for PSP in Linux.
# http://damnsmallblog.blogspot.com
# Originally: http://gentoo-wiki.com/HOWTO_PSP#Converting_all_your_videofiles_at_once

### CONFIG -->

# Prefix for 100MNV01 dir (originally "/tmp/`echo $LOGNAME`/pspmovies/MP_ROOT/")
prefix="/home/`echo $LOGNAME`"

# Preview pic time position in seconds (originally 5)
ss=10

# Path to ffmpeg binary (originally ffmeg)
ffmpeg=/opt/psp/pspvc/share/pspvc/bin/ffmpeg

### CONFIG <--


if [ $# == 0 ]
then
echo "Use: make_psp_movie video1 video2 video3 ..."
fi

# First file's name postfix - number from 1 to 9999 (originally "1" - file name M4V10001.MP4) -->
output="10000"
postfix=0

until (("1" <= "$postfix" && "$postfix" <= "9999"))
do
echo -n "Enter first file's name postfix (from 1 to 9999): "
read postfix

if [ "$postfix" == "" ]
then
postfix=1
fi
done

let "output += $postfix"
# First file's name postfix - number from 1 to 9999 (originally "1" - file name M4V10001.MP4) <--

# target dir
target="$prefix/100MNV01"
mkdir -p "$target"

for m in "$@"
do
echo "-------------------"
echo "Start converting $m"
echo "-------------------"
#output="10001"
while [ -f "$target/M4V${output}.MP4" ]
do
let "output += 1"
done
#generate video
#If "-r 29.97" does NOT work try "-r 14.985"
$ffmpeg -i "$m" -f psp -r 29.97 -b 768k -ar 24000 -ab 64k -s 320x240 "${target}/M4V${output}.MP4"
#generate thumbnail
$ffmpeg -y -i "$m" -f image2 -ss $ss -vframes 1 -s 160x120 -an "${target}/M4V${output}.THM"
#list the files that were just generated
ls -l "${target}/M4V${output}.MP4" "${target}/M4V${output}.THM"
done
echo
echo "---------------------------------------------------------------------------"
echo "You will find any newly generated PSP videos in:"
echo " ${target}"
echo
echo "Please copy them to your PSP's 'MP_ROOT/100MNV01/' folder."
echo
echo "Note: if that folder doesn't already exist, just create the folders first."
echo "---------------------------------------------------------------------------"


По долгу службы встала необходимость создать презентацию для последующего показа под windows.

Итак, как сделать презентацию, гарантированно работающую на любой современной win32-машине (а именно создать exe-файл с презентацией, запускающийся даже на "голой" винде):

1) Делаем презентацию в OOO и экспортируем в sfw.
2) Качаем standalone-флэшплеер с сайта adobe. Я брал конкретно вот этот архив: flash_player_update3_mx2004_win.zip
3) В архиве, кроме всего прочего, присутствует файл SAFlashPlayer.exe - это и есть standalone-флэшплеер.
4) Запускаем его в wine и открываем свою swf-презентацию (File->Open).
5) Сохраняем в exe-файл (File->Create projector).
6) Проверяем полученный файл в том же wine.

Итак, есть задача автоматического создания xml-файла с программой передач (EPG, он же Electronic Program Guide) на российские каналы для последующего использования в софтине типа MMS или Freevo, либо для просмотра например в gshowtv.
Стандартное (но, увы не всегда качественное) для таких случаев linux-решение - набор утилит xmltv. Скрипт поддержки русских каналов можно взять здесь.

Я же предлагаю альтернативное решение - TVxb.
На сайте можно найти не только наборы каналов для разных стран, но и наборы для различных тв-провайдеров (из российиских, кроме пакета со стандартными метровыми и дециметровыми каналами, есть также ini-файлы для Stream-ТВ, Космос-ТВ и НТВ+).

На сайте есть zip-архив предназначенный для linux-пользователей, однако к сожелению это лишь удобно упакованные win32-бинарики, которые придется пускать под неэмулятором wine (ну спасибо и на том: хоть такое минимальное, но всё же внимание к линуксоидам).
После скачивания архива программу естественно необходимо установить и настроить:


# Распаковываем например в /opt/
sudo unzip -d /opt/ TVxb-1.0108-Linux\ distribution.zip
# Переходим в директорию с программой
cd /opt/TVxb/
# Делаем доступными для записи директории с изменяющимися файлами
sudo chmod a+w -R ./cache/ ./ini/ ./log/ ./xml/
# Создаем скрипт запуска...
sudo echo '#!/bin/sh' > /usr/local/bin/TVxb ; sudo echo 'wine /opt/TVxb/bin/TVxb.exe' >> /usr/local/bin/TVxb
# ...и делаем его исполняемым
sudo chmod +x /usr/local/bin/TVxb

Далее скачиваем ini-файл нужного нам набора программ отсюда и кладем его вместо файла TVxb.ini, например:

cp ./TVxb_Russia_Main_Channels.ini /opt/TVxb/ini/TVxb.ini

При необходимости можно скомбинировать несколько наборов и удалить ненужные каналы редактируя ini-файл.

Теперь запускаем TVxb для обновления и ждём загрузки программы передач:


Полученный xml-файл (/opt/TVxb/xml/xmltv.xml) можно просмотреть например программой GShowTV (gshowtv):

Расскажу о двух фичах, которые можно реализовать на роутере с прошивкой DD-WRT на примере роутера Linksys WRT54GL.

1) Файловая система JFFS.

На роутере можно без труда организовать небольшое энергонезависимое хранилище файлов.
Для этого в веб-интерфейсе включаем поддержку jffs (по туториолу из официального вики dd-wrt):

1. Откройте вкладку "Administration".
2. Перейдите к секции "JFFS2 Support".
3. Кликаем "Enable JFFS".
4. Затем жмём "Save".
5. Ждём несколько секунд и жмём "Apply".
6. Опять ждём. Идём обратно к опции "Enable JFFS", кликаем "Clean JFFS".
7. Не кликая "Save", жмём вместо этого "Apply".

Теперь если мы приконнектимся к роутеру по ssh команда "df -h" расскажет нам о наличие новой файловой системы, смонтированной в катаалоге /jffs/, и её размере (размер очень сильно зависит от типа вашей прошивки, для получения хоть сколько-нибудь полезного свободного пространства для jffs рекомендуется установить mini-версию dd-wrt).

2) Индикация активности wifi по лампе на корпусе роутера.

Теперь используем возможности jffs - разместим на ней скрипт (с того же вики dd-wrt), который заставляет гореть лампу янтарным светом при подключенных wifi-клиентах и мигать белым при трансфере данных через WLAN.

Для установки скрипта:
1. Коннектимся по ssh.
2. Переходим в каталог /jffs/ и создаем директорию bin:
# cd /jffs/
# mkdir ./bin

3. Как видно /jffs/bin уже прописан в переменной поиска команд PATH:
# echo $PATH
/bin:/usr/bin:/sbin:/usr/sbin:/jffs/sbin:/jffs/bin:/jffs/usr/sbin:/jffs/usr/bin

4. Создаем файл скрипта (# vi ./wlan.sh) со следующим содержанием:


#!/bin/sh
I=`nvram get wl0_ifname`

while sleep 1; do
if [ "`wl assoclist`" != "" ]; then
XFER=`ifconfig $I|grep bytes`
if [ "$XFER" != "$PXFER" ]; then
LED='gpio disable 3 ; gpio disable 2'
PXFER=$XFER
else
LED='gpio disable 3 ; gpio enable 2'
fi
else
LED='gpio enable 3 ; gpio enable 2'
fi

if [ "$LED" != "$PLED" ]; then
eval $LED
PLED=$LED
fi
done

5. Делаем скрипт исполняемым:
# chmod +x ./wlan.sh

Готово!
Скрипт теперь можно запускать командой wlan.sh или прописать в автозагрузку.

Я думаю многим знакома проблема с вставкой сколько-либо сложного текста в свой блог на blogger.com или в форму на каком-либо другом сайте с поддержкой синтаксиса html в сообщениях.

Когда, например, простой фрагмент вставленного кода отображается не как нужно:



#include <gtk/gtkwidget.h>


, а примерно так:

#include


Сегодня совершенно случайно наткнулся на sed-скрипт на небезызвестном сайте http://www.w3.org/ который эту проблему успешно лечит, а именно:


#! /bin/sed -f
# Generate HTML for plain text from plain text
s/&/\&amp;/g
s/</\&lt;/g
1i\
<PRE>
$a\
</PRE>



Так же там можно найти несколько других вариаций скриптов (в т.ч. под альтернативные ОС вроде MacOSX и win32), занимающихся тем же самым (конвертированием простого текста в html, который в браузере отображается как первоначальный текст).

Бывает необходимо приложить к сообщению небольшой бинарный файл там, где такой встроенной возможности нет (хотя бы как здесь, на blogger.com).

Один из вариантов - архиватор Shar из комплекта GNU Sharutils.
Для дополнительного сжатия файлов с помощью gzip архиватор следует запускать командой вроде:
shar -z {каталог или файл для архивирования} > ./archive.shar
В итоге получится файл archive.shar, являющийся по сути скриптом, который достаточно просто запустить для распаковки и получения исходных данных.

Содержание файла чисто текстовое, поэтому его содержание можно смело вставлять в сообщения, e-mail или др. средства текстовой связи. Если сайт попытается найти и обработать html-синтаксис в тексте shar-скрипта, побив его тем самым (как это делает тот же blogger), необходимо сначала сконвертить shar-текст скриптом txt2html.

Расплатой за удобство служит необходимость наличия sharutils на принимающей стороне (что в общем-то справедливо и в случае использования любого другого архиватора), а так же gzip, если использовалось дополнительное сжатие (опция -z).

Для примера прикладываю скрипт-архив со вложенными директориями, тестовым и бинарным (png-изображение) файлами.





#!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.4).
# To extract the files from this archive, save it to some FILE, remove
# everything before the `!/bin/sh' line above, then type `sh FILE'.
#
#
# Existing files will *not* be overwritten unless `-c' is specified.
#
# This shar contains:
# length mode name
# ------ ---------- ------------------------------------------
# 10 -rw-r--r-- TEST/test.txt
# 0 -rw-r--r-- TEST/empty
# 0 -rw-r--r-- TEST/test_dir/2nd_empty
# 781 -rw-r--r-- TEST/gnuplot.png
#
save_IFS="${IFS}"
IFS="${IFS}:"
gettext_dir=FAILED
locale_dir=FAILED
first_param="$1"
for dir in $PATH
do
if test "$gettext_dir" = FAILED && test -f $dir/gettext \
&& ($dir/gettext --version >/dev/null 2>&1)
then
case `$dir/gettext --version 2>&1 | sed 1q` in
*GNU*) gettext_dir=$dir ;;
esac
fi
if test "$locale_dir" = FAILED && test -f $dir/shar \
&& ($dir/shar --print-text-domain-dir >/dev/null 2>&1)
then
locale_dir=`$dir/shar --print-text-domain-dir`
fi
done
IFS="$save_IFS"
if test "$locale_dir" = FAILED || test "$gettext_dir" = FAILED
then
echo=echo
else
TEXTDOMAINDIR=$locale_dir
export TEXTDOMAINDIR
TEXTDOMAIN=sharutils
export TEXTDOMAIN
echo="$gettext_dir/gettext -s"
fi
if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
shar_n= shar_c='
'
else
shar_n=-n shar_c=
fi
else
shar_n= shar_c='\c'
fi
if touch -am -t 200112312359.59 $$.touch >/dev/null 2>&1 && test ! -f 200112312359.59 && test -f $$.touch; then
shar_touch='touch -am -t $1$2$3$4$5$6.$7 "$8"'
elif touch -am 123123592001.59 $$.touch >/dev/null 2>&1 && test ! -f 123123592001.59 && test ! -f 123123592001.5 && test -f $$.touch; then
shar_touch='touch -am $3$4$5$6$1$2.$7 "$8"'
elif touch -am 1231235901 $$.touch >/dev/null 2>&1 && test ! -f 1231235901 && test -f $$.touch; then
shar_touch='touch -am $3$4$5$6$2 "$8"'
else
shar_touch=:
echo
$echo 'WARNING: not restoring timestamps. Consider getting and'
$echo "installing GNU \`touch', distributed in GNU File Utilities..."
echo
fi
rm -f 200112312359.59 123123592001.59 123123592001.5 1231235901 $$.touch
#
$echo $shar_n 'x -' 'lock directory' "\`_sh09789': "$shar_c
if mkdir _sh09789; then
$echo 'created'
else
$echo 'failed to create'
exit 1
fi
# ============= TEST/test.txt ==============
if test ! -d 'TEST'; then
$echo $echo_n 'x -' 'TEST: '$echo_c
if mkdir 'TEST'; then $echo 'created'; else $echo 'failed to create'; fi
fi
if test -f 'TEST/test.txt' && test "$first_param" != -c; then
$echo 'x -' SKIPPING 'TEST/test.txt' '(file already exists)'
else
$echo 'x -' extracting 'TEST/test.txt' '(gzipped)'
sed 's/^X//' << 'SHAR_EOF' | uudecode &&
begin 600 _sh09789/gzi
>'XL(`)A8T4<"`RO.STU5*$FM*.$"`+SF+!D*````
`
end
SHAR_EOF
$echo 'gunzipping file' 'TEST/test.txt' &&
gzip -d < _sh09789/gzi > 'TEST/test.txt' &&
(set 20 08 03 07 18 00 40 'TEST/test.txt'; eval "$shar_touch") &&
chmod 0644 'TEST/test.txt' ||
$echo 'restore of' 'TEST/test.txt' 'failed'
if ( md5sum --help </dev/null 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
&& ( md5sum --version </dev/null 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
md5sum -c << SHAR_EOF >/dev/null 2>&1 \
|| $echo 'TEST/test.txt:' 'MD5 check failed'
4d93d51945b88325c213640ef59fc50b TEST/test.txt
SHAR_EOF
else
shar_count="`LC_ALL=C wc -c < 'TEST/test.txt'`"
test 10 -eq "$shar_count" ||
$echo 'TEST/test.txt:' 'original size' '10,' 'current size' "$shar_count!"
fi
fi
# ============= TEST/empty ==============
if test ! -d 'TEST'; then
$echo $echo_n 'x -' 'TEST: '$echo_c
if mkdir 'TEST'; then $echo 'created'; else $echo 'failed to create'; fi
fi
if test -f 'TEST/empty' && test "$first_param" != -c; then
$echo 'x -' SKIPPING 'TEST/empty' '(file already exists)'
else
$echo 'x -' extracting 'TEST/empty' '(empty)'
> 'TEST/empty' &&
(set 20 08 03 07 18 00 28 'TEST/empty'; eval "$shar_touch") &&
chmod 0644 'TEST/empty' ||
$echo 'restore of' 'TEST/empty' 'failed'
if ( md5sum --help </dev/null 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
&& ( md5sum --version </dev/null 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
md5sum -c << SHAR_EOF >/dev/null 2>&1 \
|| $echo 'TEST/empty:' 'MD5 check failed'
d41d8cd98f00b204e9800998ecf8427e TEST/empty
SHAR_EOF
else
shar_count="`LC_ALL=C wc -c < 'TEST/empty'`"
test 0 -eq "$shar_count" ||
$echo 'TEST/empty:' 'original size' '0,' 'current size' "$shar_count!"
fi
fi
# ============= TEST/test_dir/2nd_empty ==============
if test ! -d 'TEST/test_dir'; then
$echo $echo_n 'x -' 'TEST/test_dir: '$echo_c
if mkdir 'TEST/test_dir'; then $echo 'created'; else $echo 'failed to create'; fi
fi
if test -f 'TEST/test_dir/2nd_empty' && test "$first_param" != -c; then
$echo 'x -' SKIPPING 'TEST/test_dir/2nd_empty' '(file already exists)'
else
$echo 'x -' extracting 'TEST/test_dir/2nd_empty' '(empty)'
> 'TEST/test_dir/2nd_empty' &&
(set 20 08 03 07 18 00 28 'TEST/test_dir/2nd_empty'; eval "$shar_touch") &&
chmod 0644 'TEST/test_dir/2nd_empty' ||
$echo 'restore of' 'TEST/test_dir/2nd_empty' 'failed'
if ( md5sum --help </dev/null 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
&& ( md5sum --version </dev/null 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
md5sum -c << SHAR_EOF >/dev/null 2>&1 \
|| $echo 'TEST/test_dir/2nd_empty:' 'MD5 check failed'
d41d8cd98f00b204e9800998ecf8427e TEST/test_dir/2nd_empty
SHAR_EOF
else
shar_count="`LC_ALL=C wc -c < 'TEST/test_dir/2nd_empty'`"
test 0 -eq "$shar_count" ||
$echo 'TEST/test_dir/2nd_empty:' 'original size' '0,' 'current size' "$shar_count!"
fi
fi
# ============= TEST/gnuplot.png ==============
if test -f 'TEST/gnuplot.png' && test "$first_param" != -c; then
$echo 'x -' SKIPPING 'TEST/gnuplot.png' '(file already exists)'
else
$echo 'x -' extracting 'TEST/gnuplot.png' '(gzipped)'
sed 's/^X//' << 'SHAR_EOF' | uudecode &&
begin 600 _sh09789/gzi
M'XL(`/;86CP"`P$-`_+\B5!.1PT*&@H````-24A$4@```"`````@"`,```!$
MI(K&```!(%!,5$4\/#I+-C53(R-60D-5555J8%]B8F%\:FIZ>GJ!7UZ*;&RU
M4U*U5UBB:&>J;6RK<W*R<W2R>GN\=7.[=WB]?W_%>WO(>GK;<7':?WZW?X"Z
M@'^&AH:0D)"=G)RGEYBDF9FJEI>U@H*Y@X.]CY&YD(Z[DY2MJZRXN+C!AX;$
MC8W)C8W%DY+,EI;.G)S4AH;6BXK5FYK+GZ#5G:#-IZ;+J*;2I*;:HJ';K:W:
ML:_5O;[;L[/<O+SRBHG\G)WGIJ3BJ*?JHZ/HJ*CCL*_@MK?FNKOKM+3LO;WP
MHJ#UL;#RNKK_OK[$Q,3+P<'EP<'JRLOPR,C]P\/_R\KST]']TM/]W-O\W^'_
MX-__X^/_Z.;_[>W_[_'_\.__]?3_]_G_^/?^_?UX6LLN```!J$E$051XVG72
M"4_",!0'\'IBO!`#\<!A.-0L,C5JHH@B48P':B8K8[/OO7W_;V';;3(&:]*D
M77][:?\M"]*-B*_O[#H43=DT@*>NY]:(L@"**@!\W0%F`&ARDLT<90`<-7V2
M&^G8-!L`MU1QZIS#3("B<`?R7^+;&<`O@CH`^9L]+=@W3`+'"C^`L^6I$2N*
M"8&7/U$<HLA#X%,2P'X\)]-5!V5G;K("PKZ(@5?3X-5.`K@:Q%,2!0VZ=I2I
M7O?W8%RLR17HY%M+?=F693_)/6^TCE?DR"CW/UM'C=9GG]4;N;E#PS"8[`<+
MF_E*>5&.5I8-H[(ZWS@TF(IVO$?[!E(G8L&P.3XHO+\D`#6X`F`.Z7]?54BD
M0MP,-.#_;^EZ,`'<.DB`S@7%!:Q!,E9T32!YF[\6#Y-`[]1+`A(6EP#AN1V!
MD3EQ+[)B3\@*V.Z%89*;!D[>4P\&]WP-L"K2[Z_TH$%!`_R^@13`CWL-7M[5
M,X5>FRA5P5ECX>Y_D0AJ(K4>!'Z)Q0$%-*I-K0<PT$!&[`/4W6!&8]$EO7GV
G+60#Y.>E1S$3_`&C4U;\WYN)V0````!)14Y$KD)@@NW>I6\-`P``
`
end
SHAR_EOF
$echo 'gunzipping file' 'TEST/gnuplot.png' &&
gzip -d < _sh09789/gzi > 'TEST/gnuplot.png' &&
(set 20 02 02 01 21 05 42 'TEST/gnuplot.png'; eval "$shar_touch") &&
chmod 0644 'TEST/gnuplot.png' ||
$echo 'restore of' 'TEST/gnuplot.png' 'failed'
if ( md5sum --help </dev/null 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
&& ( md5sum --version </dev/null 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
md5sum -c << SHAR_EOF >/dev/null 2>&1 \
|| $echo 'TEST/gnuplot.png:' 'MD5 check failed'
afe5ff1db943f6bfad21b568e79047e9 TEST/gnuplot.png
SHAR_EOF
else
shar_count="`LC_ALL=C wc -c < 'TEST/gnuplot.png'`"
test 781 -eq "$shar_count" ||
$echo 'TEST/gnuplot.png:' 'original size' '781,' 'current size' "$shar_count!"
fi
fi
$echo $shar_n 'x -' 'lock directory' "\`_sh09789': " $shar_c
if rm -fr _sh09789; then
$echo 'removed'
else
$echo 'failed to remove'
fi
exit 0




 

Copyright © 2007 DamnSmallBlog. Content is licensed under Creative Commons Attribution-Noncommercial.

Design: GeckoandFly and Blogcrowds.