mpv/DOCS/tech/tech-hun.txt

295 lines
14 KiB
Plaintext
Raw Normal View History

Nos, akkor le<6C>rom, hogyan is m<>k<EFBFBD>dik ez az eg<65>sz.
A f<> modulok:
1. streamer.c: ez az input layer, azaz ez olvassa a filet, VCD-t vagy stdin-t.
amit tudnia kell: megfelel<65> sectoronk<6E>nti bufferel<65>s, seek, skip funkci<63>k,
byte-onk<6E>nti ill. tetsz<73>leges m<>ret<65> blockonk<6E>nti olvas<61>s.
Egy stream (input device/file) le<6C>r<EFBFBD>s<EFBFBD>ra a stream_t strukt<6B>ra szolg<6C>l.
2. demuxer.c: ez v<>gzi az input sz<73>tszed<65>s<EFBFBD>t audio <20>s video csatorn<72>kra,
<20>s a kiv<69>lasztott csatorn<72>k bufferelt package-enk<6E>nti olvas<61>s<EFBFBD>t.
A demuxer.c ink<6E>bb csak egy framework, ami k<>z<EFBFBD>s minden input
form<72>tumra, <20>s az egyes form<72>tumokhoz (mpeg-es, mpeg-ps, avi, avi-ni,
asf) k<>l<EFBFBD>n parser van, ezek a demux_*.c file-okban vannak.
A hozz<7A> tartoz<6F> strukt<6B>ra a demuxer_t. <20>sszesen egy demuxer van.
2.a. demux_packet_t, azaz dp.
ez egy darab chunk-ot (avi) vagy packet-et (asf, mpg) tartalmaz.
mem<65>ri<72>ban ezek l<>ncolt list<73>ban vannak, mivel k<>l<EFBFBD>nb<6E>z<EFBFBD> m<>ret<65>ek.
2.b. demuxer stream, azaz ds.
struct: demux_stream_t
minden egyes csatorn<72>hoz (a/v) tartozik egy ilyen.
ez tartalmazza a stream-hez tartoz<6F> packeteket (l<>sd. 2.a.)
egyel<65>re demuxer-enk<6E>nt 3 ilyen lehet:
- hang (d_audio)
- k<>p (d_video)
- DVD felirat (d_dvdsub)
2.c. stream header. 2 f<>le van (egyel<65>re): sh_audio_t <20>s sh_video_t
ez tartalmaz minden, a dek<65>dol<6F>shoz sz<73>ks<6B>ges param<61>tert, <20>gy az input
<20>s output buffereket, kiv<69>lasztott codecet, fps/framerate stb adatokat.
Annyi van bel<65>le, ah<61>ny stream van a file-ban t<>rolva. Lesz minimum egy
a videohoz, ha van hang akkor ahhoz is, de ha t<>bb audio/video stream
is van, akkor mindegyikhez lesz egy ilyen struct.
Ezeket avi/asf eset<65>n a header alapj<70>n t<>lti fel a header beolvas<61>,
mpeg eset<65>n pedig a demux_mpg.c fogja l<>trehozni, ha egy <20>j streamet
tal<61>l. <20>j stream eset<65>n ====> Found audio/video stream: <id> jelenik meg.
A kiv<69>lasztott stream header <20>s a hozz<7A> tartoz<6F> demuxer stream k<>lcs<63>n<EFBFBD>sen
hivatkoznak egym<79>sra (ds->sh <20>s sh->ds) az egyszer<65>bb haszn<7A>lat v<>gett.
(<28>gy a funkci<63>t<EFBFBD>l f<>gg<67>en el<65>g vagy csak a ds vagy csak az sh <20>tad<61>sa)
P<>lda: van egy .asf file-unk, abban 6 db stream, ebb<62>l 1 audio <20>s 5 video.
A header beolvas<61>sakor l<>tre fog j<>nni 6 db sh struct, 1 audio <20>s 5 video.
Amikor elkezdi olvasni a packeteket, az els<6C> tal<61>lt audio <20>s video
packethez tartoz<6F> streamet kivalasztja, es ezekre allitja be a d_audio
<20>s d_video sh pointereit.
<20>gy a k<>s<EFBFBD>bbiekben m<>r csak ezeket a streameket olvassa, a t<>bbit nem.
Persze, ha a user m<>sik streameket szeretne kiv<69>lasztani, akkor
force-olhatja az -aid <20>s -vid kapcsol<6F>kkal.
J<> pelda erre a DVD, ahol nem mindig az angol szinkron hang az els<6C>
megtal<61>lt stream, <20>s <20>gy random minden vob m<>s nyelven sz<73>lalhat meg :)
Ilyenkor kell pl. az -aid 128 kapcsol<6F>t haszn<7A>lni.
hogy is m<>xik ez a beolvas<61>sdi?
- megh<67>v<EFBFBD>dik a demuxer.c/demux_read_data(), megkapja melyik ds-b<>l
(audio vagy video), mennyi byte-ot <20>s hova (mem<65>riac<61>m) szeretn<74>nk
beolvasni. Ezt h<>vogatj<74>k gyakorlatilag a codec-ek.
- ez megn<67>zi, hogy az adott ds buffer<65>ben van-e valami, ha igen akkor
onnan olvas, amennyit kell. Ha nincs/nincs el<65>g, akkor megh<67>vja
a ds_fill_buffer()-t ami:
- megn<67>zi, hogy az adott ds-ben vannak-e bufferelve csomagok (dp-k)
ha igen, akkor a legr<67>gebbit <20>trakja a bufferbe <20>s olvas tov<6F>bb. Ha
<20>res a l<>ncolt lista, akkor megh<67>vja a demux_fill_buffer()-t:
- ez az input form<72>tumnak megfelel<65> parser-t h<>vja meg, ami tov<6F>bbol-
vassa a file-t, <20>s a tal<61>lt csomagokat berakja a megfelel<65> bufferbe.
Na, ha mondjuk audio csomagot szeretn<74>nk, de csak egy rakat
video csomag van, akkor j<>n el<65>bb-ut<75>bb a DEMUXER: Too many
(%d in %d bytes) audio packets in the buffer... hiba<62>zenet.
Eddig kb. tiszta <20>gy, ezt akarom majd <20>trakni k<>l<EFBFBD>n lib-be.
na n<>zzuk tov<6F>bb:
3. mplayer.c - igen, <20> a f<>n<EFBFBD>k :)
F<> feladata a k<>l<EFBFBD>nb<6E>z<EFBFBD> modulok <20>sszekapcsol<6F>sa, illetve az A-V
szinkron biztos<6F>t<EFBFBD>sa.
Az adott stream aktu<74>lis poz<6F>ci<63>ja a megfelelo stream header
(sh_audio / sh_video) timer field-ben van.
(R<>gen ez volt az a_frame <20>s egy v_frame nev<65> float v<>ltoz<6F>)
A lej<65>tsz<73> ciklus fel<65>p<EFBFBD>t<EFBFBD>se:
while(not EOF) {
fill audio buffer (read & decode audio) + increase a_frame
read & decode a single video frame + increase v_frame
sleep (wait until a_frame>=v_frame)
display the frame
apply A-V PTS correction to a_frame
check for keys -> pause,seek,...
}
amikor lej<65>tszik (hang/k<>p) akkor a lej<65>tszott valami id<69>tartam<61>val
n<>veli a megfelel<65> v<>ltoz<6F>t:
- audion<6F>l ez a lej<65>tszott byte-ok / sh_audio->o_bps
megj.: i_bps = t<>m<EFBFBD>r<EFBFBD>tett byte-ok sz<73>ma egy m<>sodpercnyi hanghoz
o_bps = t<>m<EFBFBD>r<EFBFBD>tetlen byte-ok sz<73>ma egy m<>sodpercnyi hanghoz
(ez ut<75>bbi == bps*samplerate*channels)
- videon<6F>l ez <20>ltal<61>ban az sh_video->frametime.
Ez <20>ltal<61>ban == 1.0/fps, persze meg kell jegyeznem, hogy videon<6F>l nem
igaz<61>n sz<73>m<EFBFBD>t az fps, asf-n<>l pl. nincs is olyan, ahelyett duration
van <20>s frame-enk<6E>nt v<>ltozhat.
mpeg2-n<>l pedig repeat_count van, ami 1-2.5 id<69>tartamban elny<6E>jtja
a frame-et... avi-n<>l van tal<61>n egyed<65>l fix fps, meg mpeg1-n<>l.
Na most ez addig nagyon sz<73>pen m<>k<EFBFBD>dik, am<61>g a hang <20>s k<>p t<>k<EFBFBD>letes
szinkronban van, mivel <20>gy v<>g<EFBFBD>lis a hang sz<73>l, az adja az id<69>z<EFBFBD>t<EFBFBD>st,
<20>s amikor eltelt egy frame-nyi id<69>, akkor kirakja a k<>vetkez<65> frame-et.
De mi van, ha valami<6D>rt az input file-ban cs<63>szik a kett<74>?
Akkor j<>n be a PTS correction. Az input demuxer-ek olvass<73>k a
csomagokkal egy<67>tt a hozz<7A>juk tartoz<6F> PTS-t (presentation timestamp)
is, ami alapj<70>n <20>szrevehet<65>, ha el van cs<63>szva a kett<74>. Ilyenkor egy
megadott maxim<69>lis hat<61>ron (l<>sd -mc opci<63>) bel<65>l k<>pes az mplayer
korrigalni az a_frame <20>rt<72>k<EFBFBD>t. A korrekci<63>k <20>sszege van a c_total-ban.
Persze ez m<>g nem minden szinkron <20>gyben, van m<>g n<>mi g<>z. Pl. az,
hogy a hangk<67>rtya el<65>g rendesen k<>sleltet, ezt az mplayernek korrig<69>lnia
kell! Az <20>sszes audio k<>sleltet<65>s m<>sodpercben ezek <20>sszege:
- az utols<6C> timestamp (PTS) <20>ta beolvasott byte-ok:
t1 = d_audio->pts_bytes/sh_audio->i_bps
- Win32/ACM eset<65>n az audio input bufferben t<>rolt byte-ok:
t2 = a_in_buffer_len/sh_audio->i_bps
- az audio out bufferben t<>rolt t<>m<EFBFBD>r<EFBFBD>tetlen byte-ok:
t3 = a_buffer_len/sh_audio->o_bps
- a hangk<67>rtya buffer<65>ben (vagy DMA bufferben) t<>rolt, m<>g nem
lej<65>tszott byte-ok:
t4 = get_audio_delay()/sh_audio->o_bps
Ezekb<6B>l kisz<73>molhat<61> eg<65>szen pontosan, hogy az <20>pp hallhat<61> hanghoz
milyen PTS tartozik, majd ezt <20>sszevetve a video-hoz tartozo PTS-el
meg is kapjuk az A-V elt<6C>r<EFBFBD>s<EFBFBD>t!
Avi-n<>l sem egyszer<65> az <20>let. Ott a 'hivatalos' id<69>z<EFBFBD>t<EFBFBD>si m<>d a
BPS-alap<61>, azaz a headerben le van t<>rolva, h<>ny t<>m<EFBFBD>r<EFBFBD>tett audio
byte vagy chunk tartozik egy m<>sodpercnyi (fps darab) k<>phez.
Az AVI stream headerben van 2 fontos mezo, a dwSampleSize, es
a dwRate/dwScale ar<61>nyp<79>r:
- Ha a dwSampleSize 0, akkor VBR stream, tehat nem konstans a
bitrate. Ilyenkor 1 chunk tarol 1 sample-t, es a masodpercenkenti
chunkok szamat adja a dwRate/dwScale.
- Ha a dwSampleSize>0, akkor constant bitrate van, es az ido igy
szamolhato: time = (bytepos/dwSampleSize) / (dwRate/dwScale)
(tehat a sample sorszamat elosztjuk a samplerate-el)
Ilyenkor stream-kent kezelheto az audio, ami tetszolegesen
chunk-okra van darabolva, de lehet akar 1 db chunk is az egesz.
A m<>sik lehet<65>s<EFBFBD>g csak az interleaved fileokn<6B>l haszn<7A>lhat<61>: a
chunk-ok sorrendj<64>b<EFBFBD>l sz<73>molhat<61> egy timestamp (PTS) <20>rt<72>k.
A video chunkok PTS-e egyszer<65>: chunk sz<73>ma * fps
Az audio pedig az el<65>tte lev<65> video chunk-<2D>val azonos.
Ilyenkor viszont szamolni kell az ugynev. "audio preload"-al is,
azaz van egy fix kesleltetes az audio es video stream-ek kozott.
Ez altalaban 0.5-1.0 sec, de van amikor egeszen mas.
A pontos erteket regen mertuk, most a demux_avi.c kezeli le:
az elso video utani audio chunknal kiszamolja az A-V elterest,
es ezt veszi az audio preload mertekenek.
3.a. audio playback:
p<>r sz<73> az audio lej<65>tsz<73>sr<73>l:
az eg<65>szben nem maga a lej<65>tsz<73>s a neh<65>z, hanem:
1. hogy tudjuk, mikor lehet <20>rni a bufferbe, blocking n<>lk<6C>l
2. hogy tudjuk, mennyit j<>tszott m<>r le abb<62>l, amit a bufferbe <20>rtunk
Az 1. az audio dek<65>dol<6F>shoz kell, valamint hogy a buffert mindig teli
<20>llapotban tudjuk tartani (<28>gy sose fog megakadni a hang).
A 2. pedig a korrekt id<69>z<EFBFBD>t<EFBFBD>shez sz<73>ks<6B>ges, ugyanis n<>mely hangk<67>rtya
ak<61>r 3-7 m<>sodpercet is k<>sleltet, ami az<61>rt nem elhanyagolhat<61>!
Ezek megval<61>s<EFBFBD>t<EFBFBD>s<EFBFBD>ra az OSS t<>bbf<62>le lehet<65>s<EFBFBD>get is k<>n<EFBFBD>l:
- ioctl(SNDCTL_DSP_GETODELAY): megmondja, h<>ny lej<65>tszatlan byte
v<>rakozik a hangk<67>rtya buffer<65>ben -> id<69>z<EFBFBD>t<EFBFBD>shez kiv<69>l<EFBFBD>,
de nem minden driver t<>mogatja :(
- ioctl(SNDCTL_DSP_GETOSPACE): megmondja, mennyit <20>rhatunk a k<>rtya
buffer<65>be blocking n<>lk<6C>l. Ha a driver nem tudja a GETODELAY-t,
akkor ezt hasznalhatjuk arra is, hogy megtudjuk a k<>sleltet<65>st.
- select(): meg k<>ne mondja, hogy <20>rhatunk-e a k<>rtya buffer<65>be
blocking n<>lk<6C>l. Azt, hogy mennyit <20>rhatunk, nem mondja meg :(
valamint sok driverrel egy<67>ltal<61>n nem, vagy rosszul m<>k<EFBFBD>dik :((
csak akkor haszn<7A>lom, ha egyik fenti ioctl() sem m<>k<EFBFBD>dik.
4. codecek. ezek k<>l<EFBFBD>nb<6E>z<EFBFBD> lib-ek szanasz<73>t mindenfel<65>l.
mint pl. libac3, libmpeg2, xa/*, alaw.c, opendivx/*, loader, mp3lib.
Az mplayer.c nem kozvetlenul hivja oket, hanem a dec_audio.c es a
dec_video.c fileokon keresztul, igy az mplayer.c-nek nem kell semmit
sem tudnia a codecrol.
5. libvo: ez v<>gzi a k<>p kirak<61>s<EFBFBD>t.
Az img_format.h-ban defini<6E>lva vannak konstansok a k<>l<EFBFBD>nb<6E>z<EFBFBD> pixel-
form<72>tumokhoz, ezeket k<>telez<65> haszn<7A>lni.
1-1 vo drivernek a k<>vetkez<65>ket kell k<>telez<65>en implement<6E>lnia:
query_format() - lek<65>rdezi, hogy egy adott pixelformat t<>mogatott-e.
return value: flags:
0x1 - supported (by hardware or with conversion)
0x2 - supported (by hardware, without conversion)
0x4 - sub/osd supported (has draw_alpha)
FONTOS: minden vo drivernek k<>telez<65> t<>mogatnia az YV12 form<72>tumot, <20>s
egyiket (vagy mindkett<74>t) a BGR15 <20>s BGR24 k<>z<EFBFBD>l, ha kell, konvert<72>l<EFBFBD>ssal.
Ha ezeket nem t<>mogatja, akkor nem fog minden codec-kel m<>k<EFBFBD>dni!
Ennek az az oka, hogy az mpeg codecek csak YV12-t tudnak el<65><6C>ll<6C>tani,
a r<>gebbi Win32 DLL codecek pedig csak 15 <20>s 24bpp-t tudnak.
Van egy gyors MMX-es 15->16bpp konvert<72>l<EFBFBD>, <20>gy az nem okoz k<>l<EFBFBD>n<EFBFBD>sebb
sebess<73>gcs<63>kken<65>st!
A BPP t<>bl<62>zat, ha a driver nem tud bpp-t v<>ltani:
jelenlegi bpp: ezeket kell elfogadni:
15 15
16 15,16
24 24
24,32 24,32
Ha tud bpp-t v<>ltani (pl. DGA 2, fbdev, svgalib) akkor, ha lehet, be kell
v<>ltani a k<>rt bpp-re. Ha azt a hardver nem t<>mogatja, akkor a legk<67>zelebbi
m<>dra (15 eset<65>n 16-ra, 24 eset<65>n 32-re) kell v<>ltani <20>s konvert<72>lni!
init() - ez h<>v<EFBFBD>dik meg a legels<6C> frame kirak<61>sa el<65>tt - bufferek foglal<61>sa
stb a c<>lja.
van egy flags param<61>ter is (r<>gen fullscreen volt a neve):
0x01 - fullscreen (-fs)
0x02 - vidmode switch (-vm)
0x04 - scaling enabled (-zoom)
0x08 - flip image (upside-down)
draw_slice(): ez planar YV12 k<>pet rak ki (3 db plane, egy teljes
m<>ret<65>, ami a f<>nyer<65>t (Y) tartalmazza, <20>s 2 negyedakkora, ami a
sz<73>n (U,V) inf<6E>t). ezt haszn<7A>lj<6C>k az mpeg codecek (libmpeg2, opendivx).
ez m<>r tud olyat, hogy nem az eg<65>sz k<>p kirak<61>sa, hanem csak kis
r<>szletek update-el<65>se: ilyenkor a sark<72>nak <20>s a darabka m<>ret<65>nek
megad<61>s<EFBFBD>val lehet haszn<7A>lni.
draw_frame(): ez a r<>gebbi interface, ez csak komplett frame-et rak ki,
<20>s csak packed form<72>tumot (YUY2 stb, RGB/BGR) tud.
ezt haszn<7A>lj<6C>k a win32 codecek (divx, indeo stb).
draw_alpha(): ez rakja ki a subtitle-t <20>s az OSD-t.
haszn<7A>lata kicsit cseles, mivel ez nem a libvo API r<>sze, hanem egy
callback jelleg<65> cucc. a flip_page() kell megh<67>vja a vo_draw_text()-et
<20>gy, hogy param<61>terk<72>nt <20>tadja a k<>perny<6E> m<>reteit <20>s a pixel-
form<72>tumnak megfelel<65> draw_alpha() implement<6E>ci<63>t (function pointer).
Ezut<75>n a vo_draw_text() v<>gigmegy a kirajzoland<6E> karaktereken, <20>s
egyenk<6E>nt megh<67>vja minden karakterre a draw_alpha()-t.
Seg<65>ts<74>g k<>ppen az osd.c-ben meg van <20>rva a draw_alpha mindenf<6E>le
pixelform<72>tumhoz, ha lehet ezt haszn<7A>ld!
flip_page(): ez megh<67>v<EFBFBD>dik minden frame ut<75>n, ennek kell t<>nylegesen meg-
jelen<65>teni a buffert. double buffering eset<65>n ez lesz a 'swapbuffers'.
6. libao2: ez vez<65>rli a hang lej<65>tsz<73>st
A libvo-hoz (l<>sd 5.) hasonl<6E>an itt is k<>l<EFBFBD>nb<6E>z<EFBFBD> driverek vannak, amik
egy k<>z<EFBFBD>s API-t (interface) val<61>s<EFBFBD>tanak meg:
static int control(int cmd,int arg);
Ez egy <20>ltal<61>nos c<>l<EFBFBD> f<>ggv<67>ny, a driverf<72>gg<67> <20>s egy<67>b speci<63>lis param<61>terek
olvas<61>s<EFBFBD>ra/be<62>ll<6C>t<EFBFBD>s<EFBFBD>ra. Egyel<65>re nem nagyon haszn<7A>lt.
static int init(int rate,int channels,int format,int flags);
Driver initje, ilyenkor kell megnyitni a device-t, be<62>ll<6C>tani samplerate,
channels, sample format param<61>tereket.
Sample format: <20>ltal<61>ban AFMT_S16_LE vagy AFMT_U8, tov<6F>bbi defin<69>ci<63>k<EFBFBD>rt
l<>sd. dec_audio.c ill. linux/soundcard.h file-okat!
static void uninit();
Tal<61>ld ki!
Na j<>, seg<65>tek: lez<65>rja a device-t, kil<69>p<EFBFBD>skor (m<>g nem) h<>v<EFBFBD>dik meg.
static void reset();
Reseteli a device-t. Eg<45>sz pontosan a bufferek t<>rl<72>s<EFBFBD>re szolg<6C>l,
teh<65>t hogy a reset() ut<75>n m<>r ne sz<73>ljon tov<6F>bb az, amit el<65>tte kapott.
(pause ill. seek eset<65>n h<>v<EFBFBD>dik meg)
static int get_space();
Vissza kell adja, hogy h<>ny byte <20>rhat<61> az audio bufferbe an<61>lk<6C>l, hogy
blockolna (v<>rakoztatn<74> a h<>v<EFBFBD> processt). Amennyiben a buffer (majdnem)
tele van, 0-t kell visszaadni!
Ha sosem ad vissza 0-t, akkor nem fog m<>k<EFBFBD>dni az MPlayer!
static int play(void* data,int len,int flags);
Lej<65>tszik egy adag hangot, amit a data c<>m<EFBFBD> mem<65>riater<65>leten kap <20>s len
a m<>rete. a flags m<>g nem haszn<7A>lt. Az adatokat <20>t kell m<>solnia, mert a
h<>v<EFBFBD>s ut<75>n fel<65>l<EFBFBD>r<EFBFBD>dhatnak! Nem kell felt<6C>tlen minden byte-ot felhaszn<7A>lni,
hanem azt kell visszaadnia, mennyit haszn<7A>lt fel (m<>solt a bufferbe).
static int get_delay();
Vissza kell adja, hogy h<>ny byte v<>rakozik az audio bufferben. lehet<65>leg
min<69>l pontosabban, mert ett<74>l f<>gg az eg<65>sz id<69>z<EFBFBD>t<EFBFBD>s!
Legrosszabb esetben adja vissza a buffer m<>ret<65>t!
!!! Mivel a k<>p a hanghoz (hangk<67>rty<74>hoz) van szinkroniz<69>lva, <20>gy nagyon fontos,
!!! hogy a get_space ill. get_delay f<>ggv<67>nyek korrekt<6B>l legyenek meg<65>rva!