Skocz do zawartości

Bash; Analiza Pliku Wideo I Zdefiniowanie Zmiennych


LenoX

Rekomendowane odpowiedzi

Pracuje nad skryptem w bash. Chodzi o automat do konwersji filmów pod mój odtwarzacz sieciowy.

 

Chce zczytac kilka parametrów z pliku *.avi. Wykorzystac zmienne do przeliczen (np. kadrowanie, przeskalowanie itd..) W efekcie mencoder otrzymuje parametry do przekonwertowania filmu.

 

Pierwsze podejscie do kodu:

#!/bin/bash


mplayer -identify -endpos 1 -ao null -vo null *.avi

echo $ID_VIDEO_WIDTH

 

generuje raport w terminalu, jego wycinek to:

ID_DEMUXER=avi
ID_VIDEO_FORMAT=XVID
ID_VIDEO_BITRATE=880664
ID_VIDEO_WIDTH=624
ID_VIDEO_HEIGHT=336
ID_VIDEO_FPS=23.976
ID_VIDEO_ASPECT=0.0000
ID_AUDIO_FORMAT=85
ID_AUDIO_BITRATE=118376
ID_AUDIO_RATE=0
ID_AUDIO_NCH=0
ID_START_TIME=0.00
ID_LENGTH=5805.06
ID_SEEKABLE=1
ID_CHAPTERS=0

 

niestety brak jest wyswietlenia $ID_VIDEO_WIDTH poleceniem "echo $ID_VIDEO_WIDTH", czyli upraszczajac ta zmienia jest pusta.

Pytanie: co zrobic aby miec przykladowo zdefiniowana zmienna ID_VIDEO_WIDTH

Odnośnik do komentarza
Udostępnij na innych stronach

[...] czyli upraszczając ta zmienia jest pusta.
Nic dziwnego. Te zmienne są dostępne wyłącznie dla procesu, w którym uruchomiony jest mplayer i dla procesów potomnych. Nadrzędny proces, ten który jest ojcem procesu mplayera nic o nich nie wie - taka natura Linuksa, że dzieci nie męczą rodziców opowiadaniem swoich sekretów ;)
Pytanie: co zrobić aby mieć przykładowo zdefiniowaną zmienną ID_VIDEO_WIDTH
Są pewnie bardziej eleganckie metody, ale ja bym po prostu zrzucił zmienne do pliku tymczasowego i odczytywał je w miarę potrzeby.
Odnośnik do komentarza
Udostępnij na innych stronach

update: teraz uwzglednia spacje w parametrach

#!/bin/bash

# avi info

exec 2> >( grep --color=always \. ) 	# trik koloruje bledy na czerwono

[[ -f $1 ]] && FILM="$1" || { echo "Podaj film jako parametr" >&2 ; exit 1; }
DUMP=$(mplayer -identify -endpos 1 -ao null -vo null "$FILM" )

list_id(){
grep ^ID_ <<<"$DUMP"
}

get_id(){
ID=$1
eval $ID=\"$(grep ^${ID} <<<"$DUMP" | cut -d'=' -f2 )\"
}

list_id

echo ---------------------------------------------------------------------------
get_id ID_FILENAME
echo $ID_FILENAME
echo ---------------------------------------------------------------------------
get_id ID_VIDEO_WIDTH
get_id ID_VIDEO_HEIGHT

echo wymiary: $ID_VIDEO_WIDTH x $ID_VIDEO_HEIGHT

Odnośnik do komentarza
Udostępnij na innych stronach

niby można, ale potem przy eval i tak wyłuskuje konkretne nazwy więc wiele nie zyskujemu

wersja 2: get_id jest już automatyczne

#!/bin/bash

# avi info

exec 2> >( grep --color=always \. ) 	# trik koloruje błędy na czerwono

[[ -f $1 ]] && FILM="$1" || { echo "Podaj film jako parametr" >&2 ; exit 1; }
DUMP=$(mplayer -identify -endpos 1 -ao null -vo null "$FILM" )

list_ids(){
grep ^ID_ <<<"$DUMP" | cut -d'=' -f1
}

for ID in $(list_ids) ; do
eval $ID=\"$(grep ^${ID} <<<"$DUMP" | cut -d'=' -f2- )\"
done

echo ---------------------------------------------------------------------------
list_ids
echo ---------------------------------------------------------------------------
echo tytuł: $ID_FILENAME
echo wymiary: $ID_VIDEO_WIDTH x $ID_VIDEO_HEIGHT

 

w sumie gdyby nie spacje to można by to skrócić nawet do postaci:

TMP=$(mktemp)
trap "rm -f $TMP" EXIT
mplayer -identify -endpos 1 -ao null -vo null "$FILM" | grep ^ID_ > $TMP
. $TMP

Odnośnik do komentarza
Udostępnij na innych stronach

Wielkie dzięki,

muszę przetrawić te robaczki.

Jeszcze muszę wydłubać z 8 innych parametrów... format audio itd. Następnie porobić regułki w zależności czy chce mieć na wyjściu mp3 czy tylko skopiowany ac3

 

przegapiłem, bo byłem na wakacjach http://forum.fedora.pl/index.php?/topic/23150-jak-wydobyc-rozdzielczosc-z-filmu-video-rmvb-avi/

kadrowanie i skalowanie to w sumie prosta sprawa dla skryptu i mencodera. Trochę się dziwie, że do dekodowania był użyty mpeg4. xvid jest mniej zasobożerny i wystarcza przy małych rozdzielczościach. Ale OK

 

W dobie telefonów z dużymi ekranami HD ;-) , taki uniwersalny konwerter jest bardzo wygodny bo pliki wideo typu 320 x (9/16 * 320) są małe i wystarczają na wyświetlaczyki HD.

 

Działający skrypt dodam na końcu wątku.

Odnośnik do komentarza
Udostępnij na innych stronach

ponizej kod, który dowolny plik video konwertuje do HHMM_{nazwa pliku na wejsciu}.avi (xvid + mp3).

nazywa sie >>>mexm<<<

 

mexm wrzuca sie do /usr/sbin

po wejsciu do katalogu gdzie jest film, wpisac 'sh mexm {film}'

 

- po usunieciu opcji qpel, powinno dzialac na kazdym odtwarzaczu do fimów.

- pre-definiowane sa rozmiary kadru (ja preferuje aby byly dzielne przez 16)

- automatyczne kadrowanie i skalowanie

- wykrywa czy byl zrobiony pierwszy przebieg

 

 

/ tutaj nie dziala wtapianie tekstów

/ na wyjsciu tylko audio w formacie mp3, bo to dla xvid nie mozna dolaczyc np. ac3

 

#!/bin/bash

#
#skrypt do konversji dowolnego filmu o proporcjach ekranu => 16/9 z pomoca Mencodera
#na wyjsciu plik *.avi(xvid + mp3) 
#------------------------------------
# plecenie to: sh mexm "plik z filmem"



# avi info
[[ -f $1 ]] && FILM=$1 || { echo "Podaj film jako parametr" >&2 ; exit 1; }



DUMP=$(mplayer -identify -endpos 1 -ao null -vo null "$FILM" )

list_ids(){
       grep ^ID_ <<<"$DUMP" | cut -d'=' -f1
}

for ID in $(list_ids) ; do
       eval $ID=\"$(grep ^${ID} <<<"$DUMP" | cut -d'=' -f2- )\"
done

echo ---------------------------------------------------------------------------
list_ids
echo ---------------------------------------------------------------------------
echo tytul: $ID_FILENAME
echo wymiary: $ID_VIDEO_WIDTH x $ID_VIDEO_HEIGHT
echo ID_AUDIO_FORMAT: $ID_AUDIO_FORMAT

#flilm na wyjsciu do aktualnego katalogu
FILM2=$(date +%H%M)"_"$ID_FILENAME


#h wysokosc
#w szerokosc
#x kadrowanie po szerokosci
#y kadrowanie po wysokosci

#wymiary filmu szerokoscxwysokosc
echo "Wybierz:1)640:360 2) 512:288 3) 768:432 lub wpisz z reki szerokosc:wysokosc"
read k

case $k in
1) scale="640:360" ;;
2) scale="512:288" ;;
3) scale="768:432" ;;
*) scale=$k ;;
esac

#bitrate filmu
echo "Wybierz bitrate 1) 1000 2) 1200 3) 1400 4) 1600 5) 1800 6) 2000 lub wpisz z reki "
read k
case $k in
1) bitrate="1000" ;;
2) bitrate="1200" ;;
3) bitrate="1400" ;;
4) bitrate="1600" ;;
5) bitrate="1800" ;;
6) bitrate="2000" ;;
*) bitrate=$k ;;
esac


#dla xvid w tej wersji tylko mp3 dziala
codecaudio="mp3lame -lameopts abr:br=128 -srate 44100"

echo "wybrane wymiary to "$scale
echo "wybrany bitrate to "$bitrate
echo "wybrany codecaudio to"$codecaudio

sleep 5

#obcinamy brzegi; 
h=$ID_VIDEO_HEIGHT
let w=$ID_VIDEO_HEIGHT*16/9
let w=${w/\.*} #zaokragla w dol
let x=($ID_VIDEO_WIDTH-$w)/2
let x=${x/\.*} #zaokragla w dol


if [ $x -ge 0 ] ; then

if [ $(ls | grep -c "divx2pass.log") = "1"  ]; then # jak jest log do pass 1 to robi pass 2
echo pass 2 ongoing
exec mencoder "$ID_FILENAME" -vf crop=$w:$h:$x:0,scale=$scale -ovc xvid -xvidencopts threads=4:qpel:chroma_opt:vhq=4:bvhq=1:quant_type=mpeg:pass=2:bitrate=$bitrate -oac $codecaudio  -o "$FILM2"

else #nie ma logu dla pass 1
echo pass 1 ongoing than pass 2 
exec mencoder "$ID_FILENAME" -vf crop=$w:$h:$x:0,scale=$scale -ovc xvid -xvidencopts threads=4:qpel:chroma_opt:vhq=4:bvhq=1:quant_type=mpeg:pass=1 -oac $codecaudio  -o /dev/null && mencoder "$ID_FILENAME" -vf crop=$w:$h:$x:0,scale=$scale -ovc xvid -xvidencopts threads=4:qpel:chroma_opt:vhq=4:bvhq=1:quant_type=mpeg:pass=2:bitrate=$bitrate -oac $codecaudio  -o "$FILM2"

fi

else
echo "iloraz szerokosc do wysokosc < 16/9"
fi
#koniec :-)

Odnośnik do komentarza
Udostępnij na innych stronach

poniżej kod, który dowolny plik video konwertuje do HHMM_{nazwa pliku na wejściu}.avi (xvid + mp3).
Brakuje "fi" na samym końcu.

Nigdzie nie jest definiowana zmienna z plikiem wyjściowym ( $FILM2 ) ;)

 

Niedawno walczyłem z konwersja MTS do AVI ( http://forum.fedora....post__p__143720 ) i niestety przykładowy film nie konwertuje się Twoim skryptem

[waldo@F13 test]$ any2avi.sh 00356.MTS
00356.MTS.decoded.avi
---------------------------------------------------------------------------
ID_VIDEO_ID
ID_AUDIO_ID
ID_AUDIO_ID
ID_FILENAME
ID_DEMUXER
ID_VIDEO_FORMAT
ID_VIDEO_BITRATE
ID_VIDEO_WIDTH
ID_VIDEO_HEIGHT
ID_VIDEO_FPS
ID_VIDEO_ASPECT
ID_AUDIO_FORMAT
ID_AUDIO_BITRATE
ID_AUDIO_RATE
ID_AUDIO_NCH
ID_START_TIME
ID_LENGTH
ID_SEEKABLE
ID_CHAPTERS
ID_VIDEO_CODEC
ID_AUDIO_BITRATE
ID_AUDIO_RATE
ID_AUDIO_NCH
ID_AUDIO_CODEC
ID_VIDEO_ASPECT
ID_EXIT
---------------------------------------------------------------------------
tytuł: 00356.MTS
wymiary: 1920 x 1088
ID_AUDIO_FORMAT: 8192
Wybierz:1)640:360 2) 512:288 3) 768:432 lub wpisz z reki szerokosc:wysokosc
1920:1080
Wybierz bitrate 1) 1000 2) 1200 3) 1400 4) 1600 5) 1800 6) 2000 lub wpisz z reki 
17121
wybrane wymiary to 1920:1080
wybrany bitrate to 17121
wybrany codecaudio tomp3lame -lameopts abr:br=128 -srate 44100

$ID_VIDEO_HEIGHT: 1088
$ID_VIDEO_WIDTH: 1920
x: -7
w: 1934
[waldo@F13 test]$ 

00356.MTS.decoded.avi to ustawiona przeze mnie zmienna $FILM2.

Jak widać nieprawidłowo rozpoznana jest wysokość filmu: "wymiary: 1920 x 1088" podczas gdy "ffmpeg -i 00356.MTS" upiera się przy typowym full HD 1920x1080.

Nie wiem co chciałeś osiągnąć przez

let x=($ID_VIDEO_WIDTH-$w)/2

 

 

Próbowałem też na ustawieniach z listy wyboru, czyli 1) 640:360 i bitrate 1) 1000 z podobnym skutkiem.

Jak dopracujesz to chętnie potestuję, bo ciekaw jestem jaka jakość z tego wychodzi i jak długo się to dekoduje ;)

 

Jeszcze się z tym pobawię i za jakiś czas dopiszę dalsze uwagi.

Odnośnik do komentarza
Udostępnij na innych stronach

* Zamiast robic na piechote echo > read > case uzyj polecenia select $ help -m select znak zgloszenia ustalasz przypisujac cos do PS3 np. PS3='[ wybierz nr ]:'

* Zamiast 'sleep 5' wpisz oczekiwanie na klawisz

read -p " -- press any key -- " -sn 1 press_any_key ; echo

* Tego nie kumam

if [ $(ls | grep -c "divx2pass.log") = "1"  ] ; then

ale wydaje mi sie, ze sprawdzasz, czy istnieje plik 'divx2pass.log'. Mozesz uzyc tego co na poczatku skryptu

if [[ -f 'divx2pass.log' ]] ; then

* Na koncu powtarzasz dlugasne parametry trzy razy. Prosciej bedzie Ci zrobic z czesci wspólnej funkcje

Odnośnik do komentarza
Udostępnij na innych stronach

Brakuje "fi" na samym koncu.

Nigdzie nie jest definiowana zmienna z plikiem wyjsciowym ( $FILM2 ) ;)

 

 

Nie wiem co chciales osiagnac przez

let x=($ID_VIDEO_WIDTH-$w)/2

 

 

>1920 x 1088

no tu nie mam pomyslu, i tak skrypt tego narazie nie przekonwertuje bo wysokosc ma byc max: szerokosc x 9/16.

 

>$FILM2

mój blad pokasowalem jakies robocze wiersze z # i:

FILM2=$(date +%H%M)"_"$ID_FILENAME

 

przy kopiowaniu zabraklo paru linijek na koncu.

Juz uzupelnilem kod mi dziala

 

>

let x=($ID_VIDEO_WIDTH-$w)/2

to jest potrzebne przy kadrowaniu, potrzeba zdefiniowac gdzie ma byc górny lewy róg. Czyli szerokosc na wejsciu - szerokosc na wyjsciu dzielona przez 2.

Przy 90%filmów zadziala.

 

Znajde chwile to dopisze kod jak odcinamy góre i dól.

Odnośnik do komentarza
Udostępnij na innych stronach

* Zamiast robić na piechotę echo > read > case użyj polecenia select $ help -m select znak zgłoszenia ustalasz przypisując coś do PS3 np. PS3='[ wybierz nr ]:'

* Zamiast 'sleep 5' wpisz oczekiwanie na klawisz

read -p " -- press any key -- " -sn 1 press_any_key ; echo

* Tego nie kumam

if [ $(ls | grep -c "divx2pass.log") = "1"  ] ; then

ale wydaje mi się, że sprawdzasz, czy istnieje plik 'divx2pass.log'. Możesz użyć tego co na początku skryptu

if [[ -f 'divx2pass.log' ]] ; then

* Na końcu powtarzasz długaśne parametry trzy razy. Prościej będzie Ci zrobić z części wspólnej funkcję

 

> echo > read > case

sorki ale ja się dopiero uczyć ;-(

 

dzięki za

if [[ -f 'divx2pass.log' ]] ; then

!!! nie mogłem tego znaleźć,

 

Jeżeli chodzi o zgrabne połączenie w funkcje to trzeba poczekać, jak będę pakował xvid i ac3 do innego contenera to coś wymyśle. Teraz jest dobra przejrzystość kodu dla mnie.

funkcje porobimy jak będzie full automat, czyli wyszukanie i wtopienie filmów + konwersja audio. Przy audio sprawa się komplikuje.

Odnośnik do komentarza
Udostępnij na innych stronach

sorki ale ja się dopiero uczyć ;-(

spoko :) ja nie oceniam, tylko mówię co można. Taki sobie przykładzik naskrobałem, tyle że wyszło jakoś tak wizualnie więcej kodu :D ...mało edukacyjnie.

get_scale(){
local PS3='[ wybierz nr ]:'
my='custom size'
echo -e "\n\tWymiary filmu 'szerokosc x wysokosc'\n"
select k in 640:360 512:288 768:432 "$my"
do
	if [[ $k == $my ]] ; then
		read -p "x:y = " scale
		# tu by się przydało sprawdzenie co wpisał user
	else
		scale=$k
	fi
	break
done
}

Offtop

* A pro po tego pisania funkcji to zastanawia mnie jedna dziwna rzecz: ludzie unikają funkcji w shell-u, dlaczego ? Wolą sobie robić monstrualne zagnieżdżenia w $(...) zamiast wywalić to osobno. Mało wiem o shell-u, ale mi najwygodniej jest zamykać wszystko w osobnych funkcjach choćby dla łatwej nawigacji i logiki. Nie wiem, może to skrzywienie javove :/

Odnośnik do komentarza
Udostępnij na innych stronach

nowy kod;

- kadruje po wysokosci i szerokosci

 

 

#!/bin/bash

# 20101007
#na wyjsciu plik *.avi(xvid + mp3) 
#------------------------------------
# plecenie to: sh mexm "plik z filmem"



# avi info
[[ -f $1 ]] && FILM=$1 || { echo "Podaj film jako parametr" >&2 ; exit 1; }



DUMP=$(mplayer -identify -endpos 1 -ao null -vo null "$FILM" )

list_ids(){
       grep ^ID_ <<<"$DUMP" | cut -d'=' -f1
}

for ID in $(list_ids) ; do
       eval $ID=\"$(grep ^${ID} <<<"$DUMP" | cut -d'=' -f2- )\"
done

echo ---------------------------------------------------------------------------
list_ids
echo ---------------------------------------------------------------------------
echo tytul: $ID_FILENAME
echo wymiary: $ID_VIDEO_WIDTH x $ID_VIDEO_HEIGHT
echo ID_AUDIO_FORMAT: $ID_AUDIO_FORMAT

FILM2=$(date +%H%M)"_"$ID_FILENAME

#h wysokosc
#w szerokosc
#x kadrowanie po szerokosci
#y kadrowanie po wysokosci

#wymiary filmu szerokoscxwysokosc
echo "Wybierz:1)640:360 2) 512:288 3) 768:432 lub wpisz z reki szerokosc:wysokosc"
read k

case $k in
1) scale="640:360" ;;
2) scale="512:288" ;;
3) scale="768:432" ;;
*) scale=$k ;;
esac

#bitrate filmu
echo "Wybierz bitrate 1) 1000 2) 1200 3) 1400 4) 1600 5) 1800 6) 2000 lub wpisz z reki "
read k
case $k in
1) bitrate="1000" ;;
2) bitrate="1200" ;;
3) bitrate="1400" ;;
4) bitrate="1600" ;;
5) bitrate="1800" ;;
6) bitrate="2000" ;;
*) bitrate=$k ;;
esac

#kodec audio
#echo "Wybierz codec audio: 1) mp3lame -lameopts abr:br=128 -srate 44100  2) copy lub wpisz z reki"
#read k

#case $k in
#1) codecaudio="mp3lame -lameopts abr:br=128 -srate 44100" ;;
#2) codecaudio="copy";;
#*) codecaudio=$k ;;
#esac

#dla xvid w tej wersji tylko mp3 dziala
codecaudio="mp3lame -lameopts abr:br=128 -srate 44100"


echo "wybrane wymiary to "$scale
echo "wybrany bitrate to "$bitrate
echo "wybrany codecaudio to"$codecaudio

sleep 5


#x i y to gorny lewy rog przy kadrowaniu

#obcinamy brzegi; 
h=$ID_VIDEO_HEIGHT
let w=$ID_VIDEO_HEIGHT*16/9
let w=${w/\.*} #zaokragla w dol
let x=($ID_VIDEO_WIDTH-$w)/2
let x=${x/\.*} #zaokragla w dol
let y=0


if [ $x -lt 0 ]; then
#obcinamy gore;
w=$ID_VIDEO_WIDTH
let h=$ID_VIDEO_WIDTH*9/16
let h=${h/\.*} #zaokragla w dol
let x=0
let y=($ID_VIDEO_HEIGHT - $h)/2
let y=${y/\.*} #zaokragla w dol
fi

pass1(){
mencoder "$ID_FILENAME" -vf crop=$w:$h:$x:$y,scale=$scale -ovc xvid -xvidencopts threads=4:qpel:chroma_opt:vhq=4:bvhq=1:quant_type=mpeg:pass=1 -oac $codecaudio  -o /dev/null
}
pass2(){
mencoder "$ID_FILENAME" -vf crop=$w:$h:$x:$y,scale=$scale -ovc xvid -xvidencopts threads=4:qpel:chroma_opt:vhq=4:bvhq=1:quant_type=mpeg:pass=2:bitrate=$bitrate -oac $codecaudio  -o "$FILM2"
}


if [ -f "divx2pass.log" ]; then # jak jest log do pass 1 to robi pass 2
echo pass 2 ongoing
pass2

else #nie ma logu dla pass 1
echo pass 1 ongoing than pass 2 
pass1 && pass2

fi
#!!koniec!!

Odnośnik do komentarza
Udostępnij na innych stronach

Oto jak można do *.avi włożyć XVID + AC3

(Odtwarzacze sieciowe, których jest ostatnio wysyp, w każdym przypadku odtwarzają XVID (pewnie też DV50) oraz MP3 i AC3. Jak ktoś używa upnp av server, to nie pogardzi przerobionym filmem pod kontem indywidualnych preferencji.)

 

Wszystkie strumienie stereo (różne codeki audio) można prze-konwertować do MP3.

Dla dźwięku przestrzennego możemy w poniższy sposób skopiować/prze-konwertować audio do AC3 i włożyć do filmu.

 

 

mencoder *.avi -ffourcc XVID -ovc lavc -lavcopts vcodec=mpeg4:mbd=2:mv0:trell:v4mv:cbp:last_pred=3:predia=2:dia=2:vmax_b_frames=2:vb_strategy=1:precmp=2:cmp=2:subcmp=2:preme=2:qns=2 -oac lavc -lavcopts acodec=ac3 -o film1.avi

 

 

 

przy kadrowaniu i skalowaniu trzeba dodać:

-vf crop=W:H:x:y,scale=w:h

zmienne w zależności od kadru na wejściu

Odnośnik do komentarza
Udostępnij na innych stronach

Jeśli chcesz dodać odpowiedź, zaloguj się lub zarejestruj nowe konto

Jedynie zarejestrowani użytkownicy mogą komentować zawartość tej strony.

Zarejestruj nowe konto

Załóż nowe konto. To bardzo proste!

Zarejestruj się

Zaloguj się

Posiadasz już konto? Zaloguj się poniżej.

Zaloguj się
×
×
  • Dodaj nową pozycję...