Posts Tagged ‘mplayer’

Записване на онлайн радио

Thursday, April 3rd, 2014

От известно време слушам Eurodance канала на Digitally Imported. Отвреме навреме пускат уникални миксове, които не могат да бъдат намерени никъде из нета. За това се захванах и написах едно кратко скриптче за да ги рипна.

Радиото излъчва ICY таг, който съдържа името на песента. По този таг може да се разделят песните в общия стрийм, като единствения кусур е че идва с няколко секунди закъснение или предварение.

Използвах -dumpstream опцията на mplayer за записване на потока. Паралелно с това върви още един mplayer процес, който наблюдава за пристигането на ICY таг и пуска ново записване в нов файл. Скрипта създава нова директория за всеки ден, като песните които запазва са с префикс на времето в което са излъчени.

  1. #!/bin/bash
  2.  
  3. # задаваме някой директории и файлове
  4. FIFO=/tmp/mplayer_recording
  5. OUT_DIR=/home/ivanatora/di.fm
  6.  
  7. LAST_PID=0
  8. LAST_SONG=""
  9.  
  10. if [ ! -e "$FIFO" ]
  11. then
  12.     mkfifo $FIFO
  13. fi
  14.  
  15. # това е процесът, който следи таговете с имената на песните и ги изпраща в едно FIFO
  16. nohup mplayer -ao null http://pub3.di.fm:80/di_eurodance | stdbuf -o L grep ICY > /tmp/mplayer_recording &
  17.  
  18. # тук четем от FIFO-то и пускаме нов записващ процес при получаване на ICY таг
  19.  
  20. while read LINE < $FIFO; do
  21.     DATE=`date +%F`
  22.     if [ ! -d "$OUT_DIR/$DATE" ]
  23.     then
  24.         mkdir "$OUT_DIR/$DATE"
  25.     fi
  26.  
  27.     echo "—–"
  28.     echo $LINE
  29.     # името на песента е заградена в единични кавички
  30.     # @TODO: понякога в самото име има единични кавички – да се обмисли този случай
  31.     SONG=`echo $LINE | cut -d\‘ -f2 | sed -e ‘s/ /_/g‘`
  32.    echo "Last: $LAST_SONG"
  33.    echo "Current: $SONG"
  34.    # тук имам един бъг някъде – получавам таговете по два пъти. Това е workaround, който дава да се продължи само ако тагът който идва е различен от предния.
  35.    if [ "$SONG" != "$LAST_SONG" ]
  36.    then
  37.        TIME=`date +%T`
  38.        echo "##### $TIME"
  39.  
  40.        # ако вече имаме записващ процес – време е да го спрем и да пуснем нов
  41.  
  42.        if [ $LAST_PID -ne 0 ]
  43.        then
  44.            kill $LAST_PID
  45.        fi
  46.  
  47.        nohup mplayer http://pub3.di.fm:80/di_eurodance -dumpstream -dumpfile "$OUT_DIR/$DATE/$TIME"_"$SONG".mp3 &
  48.        LAST_PID=$!
  49.        LAST_SONG="$SONG"
  50.    fi
  51. done

Тук имам следние проблеми:
1) Таговете ми идват по два пъти.
2) Закъснението на таговете, което не е константа, която може да бъде уловена и компенсирана. На практика няколко секунди от началото на песента се записват в предния файл.
3) Предполагам че може да бъде оптимизирано и направено само с 1 mplayer процес.
4) Ако ми умре нета за секунда, mplayer-ите се прекратяват, което минава през фифото и цикъла `while read` заминава.

Някой bash-майстор може да се произнесе с идеи 🙂

Hello, Android!

Tuesday, April 23rd, 2013

От едно време насам като се прибера вкъщи и си пускам да слушам онлайн радиа. А от както открих Digitally Imported и си лягам с пуснато радио.

Понеже аз съм доста мързелив тип (признавам си), по едно време ми стана тежко както си седя на дивана с крака върху масата да ставам да ходя до десктопа и да сменям радиото или да го спирам. Слава богу – има SSH и mplayer, така че тези неща мога да ги правя от лаптопа който се намира на фундаменталното разстояние на 3 метра от бюрото. Другия проблем е че искам радиото да се спира половин час след като си легна. Има много приспиващи станцийки, но не искам да бучат през цялата вечер.

Първия ми порив беше да сложа rc0.d скрипт на лаптопа, който преди shutdown да се вързва към десктопа и да прави някаква магия с `at` и `killall mplayer` която да гаси радиото след 30 минути. Но това щеше да бъде много лесно, а пък ми се занимаваше с нещо ново.

И нали сега са модерни мобилните приложения, реших да пробвам да си напиша апп за телефона. Свалих официалния ADT-bundle с инструментите за разработка и почнах. Тук да спомена че с Java имам един-единствен опит от университета и нищо повече. Какви са ми впечатленията:

Eclipse
+ той бил много читав редактор с всичките нужни code completion-и, javadoc popup-и, syntax highlights и т.н.
+ превъзходна интеграция с дебъгера на андроида – разработчиците от Google са си свършили работата
+ интеграция с емулатора, който е идеален за тестване на бутони, поведение… доста е тежък обаче и този апп през повечето време съм го тествал директно на телефона
+ logcat – инструмент, който вади директно дебъг съобщенията от емулатора или телефона в еклипса. Първия път като го свързах към телефона и се шашнах. МАЛЕ, всички нишки и процеси продуцират огромно количество дебъг съобщения и exceptions 😀 Хората не си ли махат дебъга в продукшън версиите на приложенията?
+ понякога logcat решава че няма да работи повече, което се оправя с рестарт на IDE-то
+ еклипса много ограничава писането на кода в добрия смисъл – не те оставя да пишеш глупости, за всеки проблем (примерно assign type mismatch) излизат възможните решения и кода често се пише с цък от мишката
+ кода наистина се пише с цък от мишката – ако ви трябва да имплементирате метод от parent class, 3 клика и шаблона ви се налива във вашия код
+ няма вградена интеграция с SVN
+ от много ум понякога изтрещява и започва да дава несъществуващи грешки, което се оправя с рестарт на IDE-то
Java
+ струва ми се много странен език като идвам от web програмирането
+ по-ниска степен на абстракция от web езиците и следователно:
+ нещата стават с адски много писане. Примерно един file_get_contents(“http://domain.com”) от PHP в Java става с 30 реда плътно изписан код, в който се ползват 15 различни типа обекти
+ няма асоциативни масиви, което сериозно ми бърка в здравето. Има разни workaround-и като да се ползват обекти, ама не е същото.
+ много грозни stack trace-ове, на които още не мога да свикна 🙂

Android
+ доста подреден lifecycle на приложенията
+ подробна документация на официалното място, но ми се струва доста суха. В Stackoverflow обаче има хиляди материали с примерен код
+ във връзка с горното, 90% от писането на кода е да намериш вече решения проблем и да го copy-paste-неш правилно 🙂
+ нишки и кой код в коя нишка се изпълнява… редовно се опитвам да достъпвам елементи от UI-нишката от друга нишка и естествено не се получава 🙂 Другия проблем е програмно да си извадите бавните операции в задна нишка, защото иначе се получава лагване на апп-а.
+ layouts, където си седи презентационната логика и activities, където си седи бизнес логиката
+ broadcast receivers, или слушатели за глобални събития
+ запазване на settings между различните изпълнения на апп-а, обаче settings трябва да са от много примитивен тип
+ куриозно е да се опиташ да натъпчеш UI в такива малки разделителни способности – буквално след третото текстово поле и мястото свършва 🙂
Първата идея беше на десктопа да направя няколко PHP скрипта, които общо взето да правят system(‘mplayer нещоси’) и от телефона да ги изпълнявам с HTTP GET заявки. Но се оказа че, да направиш HTTP GET в Android е грозно, голямо и ужасно, поне за текущите ми умения, така че тази идея беше отхвърлена още на първата вечер. Втората идея беше да се ползва SSH като от телефона директно се пращат командите към десктопа. Това се оказа доста по-лесно, че и целия апп стана много универсален.

И ето го апп-а My Multimedia Controller, който вече взе да придобива малко търговски вид. Качвам и кода, някой ако иска да ми се подиграва 🙂 Сериозно, не бих се подписал под него и мисля че трябва да бъде принтиран на хартия и ритуално изгорен. Обаче пък приложението работи.
Features:
+ управлява нивото на звука на десктопа
+ превключва измежду няколко радио станции
+ запомняне на “домашна WiFi мрежа”. Ако се конектнете към нея, ще получите нотификация, от която да се пусне апп-а
+ sleep mode – таймер за спиране на радиото, точно като sleep timer-а на телевизорите 🙂

Prerequestes:
+ Linux desktop, `amixer` за контрол на нивото на звука (`amixer` вече не е задължително изискване от r17 натам), `mplayer` за свирене на радио станциите
+ Android 2.2+ device

Required permissions:
+ INTERNET – за да работи SSH
+ ACCESS_NETWORK_STATE и ACCESS_WIFI_STATE – за нотификацията при конект към домашната мрежа. В една по-ранна версия на приложението при такъв конект се пускаше самото приложение, но с практиката се оказа че това е доста intrusive behavior и оставих само нотификация 🙂

 

TODO:
+ профили за SSH – да запазва данните за конект за повече от 1 PC добавено в r13
+ повече контрол върху различни миксер канали и възможност за софтуерно volume добавено в r17
+ динамично въвеждане на радио станции, че в момента URL-тата са хардкоднати
+ иконката да се смени с по-добра
+ обратна връзка за текущо свирената песен (ICY info тага, ако го има)

 

 

Download:

Project r20 – 1.7MB

APK r20 – 337KB

Не е финална версия 🙂

Енкодване на клипове за k800 с mencoder и ffmpeg

Monday, September 1st, 2008

От месеци се мъчех да си смачкам някое друго видео, което да мога да си го гледам на телефона. GSM е Sony Ericsson k800. По спецификации поддържа:
– видео 3GPP (H263, H264), MP4, Real8
– аудио MP4 (AAC, AAC+, E-AAC+), MP3, M4A, WMA, 3GP, AMR, WAV, G-MIDI 1, Real 8
– максимална разделителна способност 320х240
– максимален битрейт – 400 kb/s – като това е общо видео битрейт + аудио битрейт
До сега имам поне към 500 неуспешни опита да енкодна видео с mencoder и то да тръгне на телефона. Във файловия мениджър се появява една иконка с пакетче и контекстен бутон Send (като на всички непознати файлове) и толкоз. Никакъв опит за по-съществен дебъг. Какво не му харесва? Тук вече става въпрос за много сложна комбинация от видео енкодер, аудио енкодер, видео формат, видео контейнер, аудио кодек, битрейти…
Ето някой от неуспешните опити с mencoder:

mencoder input.avi -ovc lavc -lavcopts acodec=ac3:abitrate=64:vcodec=mpeg4:vbitrate=300 -oac mp3lame -lameopts br=64 -vf scale=320:240 -of lavf -lavfopts format=mp4 -o output.mp4

Сега като го гледам този, не ми е чудно че не тръгва. Опитвам се да ползвам за аудио кодек АС3, а телефона май не го поддържа

mencoder input.avi -ovc x264 -x264encopts bitrate=350 -oac mp3lame -lameopts br=64 -vf scale=320:240 -o output.mp4

Едно време си мислех че x264 == MPEG-4, сега си мисля че не е точно така. Вече почнах да се обърквам кое е енкодер, кое е кодек и кое е контейнер…
Та това са само последните два от няколкостотин опита и килограми изхабени нерви по mencoder. Не искам да кажа че mencoder си върши работата зле – виновно е задклавиатурното устройство 🙂 В други случаи mencoder върши чудесна работа, примерно това рипване на DVD:

mencoder dvd://3 -dvd-device /mnt/cdrom/ -ovc lavc -lavcopts vcodec=mpeg4:vhq:vbitrate=”800″ -oac mp3lame -lameopts br=128 -o dvd.avi

По едно време ми писна и се залових за алтернативния софтуер – ffmpeg. Не ми хареса man страницата му, където са описани по-малко от половината опции. Въпреки това, работата горе долу стана.
Първо пробвах да преобразувам клипчето в 3GP, но се оказа че формата има комплект валидни разделителни способности, най-високата от които да ми върши работа беше 176х144. Не мерси.
Съсредоточих се върху MP4:

ffmpeg -i input.avi -ar 8000 -ac 1 -acodec libfaac -vcodec mpeg4 -s 320×240 -r 24 -b 300000 -ab 48000 -t 30 output.mp4

Видеото излезе с подходящия thumbnail в мениджъра на телефона, даже и тръгна. Единствения кусур беше звука, който беше с отвратително качество.
Ето подобрение:

ffmpeg -i input.avi -ar 44100 -ac 1 -acodec libfaac -vcodec mpeg4 -s 320×240 -r 24 -b 250000 -ab 64000 output.mp4

Аудио енкодера не ми даде да вдигна аудио битрейта докато не вдигнах и sampling rate-а. Намалих и видео битрейта, понеже на някои места видеото забавяше и се получаваше framedrop ефект. Накрая всичко тръгна на сто процента 🙂

И mplayer беше се предал

Wednesday, October 31st, 2007

…пред моите опити за ъпгрейд на библиотеки.
Имаше
mplayer: error while loading shared libraries: libglib-1.2.so.0: cannot open shared object file: No such file or directory
И докато не върнах стария glib-1 не тръгна.
Пробвах да компилирам MPlayer 1.0rc2 (последната версия, която беше достъпна за сваляне) и там имаше неуспех…
(more…)