1263
|
1 Nos, akkor leírom, hogyan is működik ez az egész.
|
86
|
2
|
|
3 A fő modulok:
|
|
4
|
861
|
5 1. streamer.c: ez az input layer, azaz ez olvassa a filet, VCD-t vagy stdin-t.
|
1263
|
6 amit tudnia kell: megfelelő sectoronkénti bufferelés, seek, skip funkciók,
|
86
|
7 byte-onkénti ill. tetszőleges méretű blockonkénti olvasás.
|
1263
|
8 Egy stream (input device/file) leírására a stream_t struktúra szolgál.
|
|
9
|
86
|
10 2. demuxer.c: ez végzi az input szétszedését audio és video csatornákra,
|
861
|
11 és a kiválasztott csatornák bufferelt package-enkénti olvasását.
|
86
|
12 A demuxer.c inkább csak egy framework, ami közös minden input
|
1263
|
13 formátumra, és az egyes formátumokhoz (mpeg-es, mpeg-ps, avi, avi-ni,
|
|
14 asf) külön parser van, ezek a demux_*.c file-okban vannak.
|
|
15 A hozzá tartozó struktúra a demuxer_t. Összesen egy demuxer van.
|
|
16
|
544
|
17 2.a. demux_packet_t, azaz dp.
|
1263
|
18 ez egy darab chunk-ot (avi) vagy packet-et (asf, mpg) tartalmaz.
|
|
19 memóriában ezek láncolt listában vannak, mivel különböző méretűek.
|
86
|
20
|
861
|
21 2.b. demuxer stream, azaz ds.
|
|
22 struct: demux_stream_t
|
1263
|
23 minden egyes csatornához (a/v) tartozik egy ilyen.
|
|
24 ez tartalmazza a stream-hez tartozó packeteket (lásd. 2.a.)
|
|
25 egyelőre demuxer-enként 3 ilyen lehet:
|
861
|
26 - hang (d_audio)
|
1263
|
27 - kép (d_video)
|
861
|
28 - DVD felirat (d_dvdsub)
|
544
|
29
|
1263
|
30 2.c. stream header. 2 féle van (egyelőre): sh_audio_t és sh_video_t
|
|
31 ez tartalmaz minden, a dekódoláshoz szükséges paramétert, így az input
|
|
32 és output buffereket, kiválasztott codecet, fps/framerate stb adatokat.
|
|
33 Annyi van belőle, ahány stream van a file-ban tárolva. Lesz minimum egy
|
|
34 a videohoz, ha van hang akkor ahhoz is, de ha több audio/video stream
|
544
|
35 is van, akkor mindegyikhez lesz egy ilyen struct.
|
1263
|
36 Ezeket avi/asf esetén a header alapján tölti fel a header beolvasó,
|
|
37 mpeg esetén pedig a demux_mpg.c fogja létrehozni, ha egy új streamet
|
|
38 talál. Új stream esetén ====> Found audio/video stream: <id> jelenik meg.
|
|
39
|
|
40 A kiválasztott stream header és a hozzá tartozó demuxer stream kölcsönösen
|
|
41 hivatkoznak egymásra (ds->sh és sh->ds) az egyszerűbb használat végett.
|
|
42 (így a funkciótól függően elég vagy csak a ds vagy csak az sh átadása)
|
|
43
|
|
44 Példa: van egy .asf file-unk, abban 6 db stream, ebből 1 audio és 5 video.
|
|
45 A header beolvasásakor létre fog jönni 6 db sh struct, 1 audio és 5 video.
|
|
46 Amikor elkezdi olvasni a packeteket, az első talált audio és video
|
|
47 packethez tartozó streamet kivalasztja, es ezekre allitja be a d_audio
|
|
48 és d_video sh pointereit.
|
|
49 Így a későbbiekben már csak ezeket a streameket olvassa, a többit nem.
|
|
50 Persze, ha a user másik streameket szeretne kiválasztani, akkor
|
|
51 force-olhatja az -aid és -vid kapcsolókkal.
|
|
52 Jó pelda erre a DVD, ahol nem mindig az angol szinkron hang az első
|
|
53 megtalált stream, és így random minden vob más nyelven szólalhat meg :)
|
|
54 Ilyenkor kell pl. az -aid 128 kapcsolót használni.
|
|
55
|
|
56 hogy is műxik ez a beolvasósdi?
|
|
57 - meghívódik a demuxer.c/demux_read_data(), megkapja melyik ds-ből
|
|
58 (audio vagy video), mennyi byte-ot és hova (memóriacím) szeretnénk
|
|
59 beolvasni. Ezt hívogatják gyakorlatilag a codec-ek.
|
|
60 - ez megnézi, hogy az adott ds bufferében van-e valami, ha igen akkor
|
|
61 onnan olvas, amennyit kell. Ha nincs/nincs elég, akkor meghívja
|
86
|
62 a ds_fill_buffer()-t ami:
|
1263
|
63 - megnézi, hogy az adott ds-ben vannak-e bufferelve csomagok (dp-k)
|
|
64 ha igen, akkor a legrégebbit átrakja a bufferbe és olvas tovább. Ha
|
|
65 üres a láncolt lista, akkor meghívja a demux_fill_buffer()-t:
|
|
66 - ez az input formátumnak megfelelő parser-t hívja meg, ami továbbol-
|
|
67 vassa a file-t, és a talált csomagokat berakja a megfelelő bufferbe.
|
|
68 Na, ha mondjuk audio csomagot szeretnénk, de csak egy rakat
|
|
69 video csomag van, akkor jön előbb-utóbb a DEMUXER: Too many
|
|
70 (%d in %d bytes) audio packets in the buffer... hibaüzenet.
|
86
|
71
|
1263
|
72 Eddig kb. tiszta ügy, ezt akarom majd átrakni külön lib-be.
|
86
|
73
|
1263
|
74 na nézzuk tovább:
|
86
|
75
|
1263
|
76 3. mplayer.c - igen, ő a főnök :)
|
|
77 az időzítes élég érdekesen van megoldva, főleg azért mert minden file-
|
|
78 formátumnál másképp kell/célszerű, és néha többféle képpen is lehet.
|
861
|
79
|
1263
|
80 van egy a_frame és egy v_frame nevű float változó, ez tárolja az épp
|
|
81 látható/hallható a/v pozícióját másodpercben.
|
|
82
|
|
83 A lejátszó ciklus felépítése:
|
861
|
84 while(not EOF) {
|
|
85 fill audio buffer (read & decode audio) + increase a_frame
|
|
86 read & decode a single video frame + increase v_frame
|
|
87 sleep (wait until a_frame>=v_frame)
|
|
88 display the frame
|
|
89 apply A-V PTS correction to a_frame
|
|
90 check for keys -> pause,seek,...
|
|
91 }
|
1263
|
92
|
|
93 amikor lejátszik (hang/kép) akkor a lejátszott valami időtartamával
|
|
94 növeli a megfelelő változót:
|
|
95 - audionál ez a lejátszott byte-ok / sh_audio->o_bps
|
|
96 megj.: i_bps = tömörített byte-ok széma egy másodpercnyi hanghoz
|
|
97 o_bps = tömörítetlen byte-ok száma egy másodpercnyi hanghoz
|
|
98 (ez utóbbi == bps*samplerate*channels)
|
|
99 - videonál ez általában az sh_video->frametime.
|
|
100 Ez általában == 1.0/fps, persze meg kell jegyeznem, hogy videonál nem
|
|
101 igazán számít az fps, asf-nél pl. nincs is olyan, ahelyett duration
|
|
102 van és frame-enként változhat.
|
|
103 mpeg2-nél pedig repeat_count van, ami 1-2.5 időtartamban elnyújtja
|
|
104 a frame-et... avi-nál van talán egyedül fix fps, meg mpeg1-nél.
|
|
105
|
|
106 Na most ez addig nagyon szépen működik, amíg a hang és kép tökéletes
|
|
107 szinkronban van, mivel így végülis a hang szól, az adja az időzítést,
|
|
108 és amikor eltelt egy frame-nyi idő, akkor kirakja a következő frame-et.
|
|
109 De mi van, ha valamiért az input file-ban csúszik a kettő?
|
|
110 Akkor jön be a PTS correction. Az input demuxer-ek olvassák a
|
|
111 csomagokkal együtt a hozzájuk tartozó PTS-t (presentation timestamp)
|
|
112 is, ami alapján észrevehető, ha el van csúszva a kettő. Ilyenkor egy
|
|
113 megadott maximális határon (lásd -mc opció) belül képes az mplayer
|
|
114 korrigalni az a_frame értékét. A korrekciók összege van a c_total-ban.
|
86
|
115
|
1263
|
116 Persze ez még nem minden szinkron ügyben, van még némi gáz. Pl. az,
|
|
117 hogy a hangkártya elég rendesen késleltet, ezt az mplayernek korrigálnia
|
|
118 kell! Az összes audio késleltetés másodpercben ezek összege:
|
|
119 - az utolsó timestamp (PTS) óta beolvasott byte-ok:
|
861
|
120 t1 = d_audio->pts_bytes/sh_audio->i_bps
|
1263
|
121 - Win32/ACM esetén az audio input bufferben tárolt byte-ok:
|
861
|
122 t2 = a_in_buffer_len/sh_audio->i_bps
|
1263
|
123 - az audio out bufferben tárolt tömörítetlen byte-ok:
|
861
|
124 t3 = a_buffer_len/sh_audio->o_bps
|
1263
|
125 - a hangkártya bufferében (vagy DMA bufferben) tárolt, még nem
|
|
126 lejátszott byte-ok:
|
861
|
127 t4 = get_audio_delay()/sh_audio->o_bps
|
1263
|
128
|
|
129 Ezekből kiszámolható egészen pontosan, hogy az épp hallható hanghoz
|
|
130 milyen PTS tartozik, majd ezt összevetve a video-hoz tartozo PTS-el
|
|
131 meg is kapjuk az A-V eltérését!
|
|
132
|
|
133 Avi-nál sem egyszerű az élet. Ott a 'hivatalos' időzítési mód a
|
|
134 BPS-alapú, azaz a headerben le van tárolva, hány tömörített audio
|
|
135 byte tartozik egy másodpercnyi (fps darab) képhez.
|
|
136 ez persze nem mindig működik... miért is működne :)
|
|
137 Ezért én megcsináltam, hogy az mpeg-nél használatos sectoronkénti
|
|
138 PTS értéket emulálom avi-ra is, azaz az AVI parser minden beolvasott
|
|
139 chunk-nál számol egy kamu PTS-t a frame-ek típusa alapján, és ez
|
|
140 alapjan idozitek. És van amikor ez működik jobban.
|
|
141 Persze itt még bejátszik az is, hogy AVI-nál általában előre
|
|
142 letárolnak egy nagyobb adag hangot, és csak utána kezdődik a kép.
|
|
143 Ezt persze bele kell számolni a késleltetésbe, ez az Initial PTS delay.
|
|
144 Ilyen persze 2 is van, az egyik a headerben le is van írva, és
|
|
145 nem nagyon használják. :) A másik sehol nincs leírva, de használják,
|
|
146 ezt csak mérni lehet...
|
861
|
147
|
|
148 3.a. audio playback:
|
1263
|
149 pár szó az audio lejátszásról:
|
|
150 az egészben nem maga a lejátszás a nehéz, hanem:
|
|
151 1. hogy tudjuk, mikor lehet írni a bufferbe, blocking nélkül
|
|
152 2. hogy tudjuk, mennyit játszott már le abból, amit a bufferbe írtunk
|
|
153 Az 1. az audio dekódoláshoz kell, valamint hogy a buffert mindig teli
|
|
154 állapotban tudjuk tartani (így sose fog megakadni a hang).
|
|
155 A 2. pedig a korrekt időzítéshez szükséges, ugyanis némely hangkártya
|
|
156 akár 3-7 másodpercet is késleltet, ami azért nem elhanyagolható!
|
|
157 Ezek megvalósítására az OSS többféle lehetőséget is kínál:
|
|
158 - ioctl(SNDCTL_DSP_GETODELAY): megmondja, hány lejátszatlan byte
|
|
159 várakozik a hangkártya bufferében -> időzítéshez kiváló,
|
|
160 de nem minden driver támogatja :(
|
|
161 - ioctl(SNDCTL_DSP_GETOSPACE): megmondja, mennyit írhatunk a kártya
|
|
162 bufferébe blocking nélkül. Ha a driver nem tudja a GETODELAY-t,
|
|
163 akkor ezt hasznalhatjuk arra is, hogy megtudjuk a késleltetést.
|
|
164 - select(): meg kéne mondja, hogy írhatunk-e a kártya bufferébe
|
|
165 blocking nélkül. Azt, hogy mennyit írhatunk, nem mondja meg :(
|
|
166 valamint sok driverrel egyáltalán nem, vagy rosszul működik :((
|
|
167 csak akkor használom, ha egyik fenti ioctl() sem működik.
|
861
|
168
|
1263
|
169 4. codecek. ezek különböző lib-ek szanaszét mindenfelől.
|
86
|
170 mint pl. libac3, libmpeg2, xa/*, alaw.c, opendivx/*, loader, mp3lib.
|
1263
|
171 az mplayer.c hívogatja őket, amikor egy-egy darab hangot vagy frame-et
|
|
172 kell lejátszani (lásd 3. pont elején).
|
|
173 ezek pedig hívják a megfelelő demuxert, hogy megkapják a tömörített
|
|
174 adatokat (lásd 2. pont).
|
|
175 paraméterként a megfelelő stream headert (sh_audio/sh_video) kell
|
|
176 átadni, ez elvileg tartalmaz minden infót, ami szükséges a
|
|
177 dekódoláshoz (többek között a demuxert is: sh->ds).
|
|
178 A codecek szeparálasa folyamatban van, az audio már el van különítve
|
|
179 (lásd. dec_audio.c), a videon még dolgozunk. Cél, hogy ne az mplayer.c
|
|
180 kelljen tudja, milyen codecek vannak és hogy kell őket használni, hanem
|
|
181 egy közös init/decode audio/video functiont kelljen csak meghívnia.
|
86
|
182
|
1263
|
183 5. libvo: ez végzi a kép kirakását.
|
544
|
184
|
1263
|
185 Az img_format.h-ban definiálva vannak konstansok a különböző pixel-
|
|
186 formátumokhoz, ezeket kötelező használni.
|
544
|
187
|
1263
|
188 1-1 vo drivernek a következőket kell kötelezően implementálnia:
|
|
189
|
|
190 query_format() - lekérdezi, hogy egy adott pixelformat támogatott-e.
|
544
|
191 return value: flags:
|
|
192 0x1 - supported (by hardware or with conversion)
|
|
193 0x2 - supported (by hardware, without conversion)
|
|
194 0x4 - sub/osd supported (has draw_alpha)
|
1263
|
195 FONTOS: minden vo drivernek kötelező támogatnia az YV12 formátumot, és
|
|
196 egyiket (vagy mindkettőt) a BGR15 és BGR24 közül, ha kell, konvertálással.
|
|
197 Ha ezeket nem támogatja, akkor nem fog minden codec-kel működni!
|
|
198 Ennek az az oka, hogy az mpeg codecek csak YV12-t tudnak előállítani,
|
|
199 a régebbi Win32 DLL codecek pedig csak 15 és 24bpp-t tudnak.
|
|
200 Van egy gyors MMX-es 15->16bpp konvertáló, így az nem okoz különösebb
|
|
201 sebességcsökkenést!
|
|
202
|
|
203 A BPP táblázat, ha a driver nem tud bpp-t váltani:
|
544
|
204 jelenlegi bpp: ezeket kell elfogadni:
|
|
205 15 15
|
|
206 16 15,16
|
|
207 24 24
|
|
208 24,32 24,32
|
|
209
|
1263
|
210 Ha tud bpp-t váltani (pl. DGA 2, fbdev, svgalib) akkor, ha lehet, be kell
|
|
211 váltani a kért bpp-re. Ha azt a hardver nem támogatja, akkor a legközelebbi
|
|
212 módra (15 esetén 16-ra, 24 esetén 32-re) kell váltani és konvertálni!
|
544
|
213
|
1263
|
214 init() - ez hívódik meg a legelső frame kirakása előtt - bufferek foglalása
|
|
215 stb a célja.
|
|
216 van egy flags paraméter is (régen fullscreen volt a neve):
|
861
|
217 0x01 - fullscreen (-fs)
|
|
218 0x02 - vidmode switch (-vm)
|
|
219 0x04 - scaling enabled (-zoom)
|
|
220 0x08 - flip image (upside-down)
|
544
|
221
|
1263
|
222 draw_slice(): ez planar YV12 képet rak ki (3 db plane, egy teljes
|
|
223 méretű, ami a fényerőt (Y) tartalmazza, és 2 negyedakkora, ami a
|
|
224 szín (U,V) infót). ezt használják az mpeg codecek (libmpeg2, opendivx).
|
|
225 ez már tud olyat, hogy nem az egész kép kirakása, hanem csak kis
|
|
226 részletek update-elése: ilyenkor a sarkának és a darabka méretének
|
|
227 megadásával lehet használni.
|
|
228
|
|
229 draw_frame(): ez a régebbi interface, ez csak komplett frame-et rak ki,
|
|
230 és csak packed formátumot (YUY2 stb, RGB/BGR) tud.
|
|
231 ezt használják a win32 codecek (divx, indeo stb).
|
544
|
232
|
1263
|
233 draw_alpha(): ez rakja ki a subtitle-t és az OSD-t.
|
|
234 használata kicsit cseles, mivel ez nem a libvo API része, hanem egy
|
|
235 callback jellegű cucc. a flip_page() kell meghívja a vo_draw_text()-et
|
|
236 úgy, hogy paraméterként átadja a képernyő méreteit és a pixel-
|
|
237 formátumnak megfelelő draw_alpha() implementációt (function pointer).
|
|
238 Ezután a vo_draw_text() végigmegy a kirajzolandó karaktereken, és
|
|
239 egyenként meghívja minden karakterre a draw_alpha()-t.
|
|
240 Segítség képpen az osd.c-ben meg van írva a draw_alpha mindenféle
|
|
241 pixelformátumhoz, ha lehet ezt használd!
|
544
|
242
|
1263
|
243 flip_page(): ez meghívódik minden frame után, ennek kell ténylegesen meg-
|
|
244 jeleníteni a buffert. double buffering esetén ez lesz a 'swapbuffers'.
|
|
245
|
|
246 6. libao2: ez vezérli a hang lejátszást
|
|
247
|
|
248 A libvo-hoz (lásd 5.) hasonlóan itt is különböző driverek vannak, amik
|
|
249 egy közös API-t (interface) valósítanak meg:
|
|
250
|
971
|
251 static int control(int cmd,int arg);
|
1263
|
252 Ez egy általános célú függvény, a driverfüggő és egyéb speciális paraméterek
|
|
253 olvasására/beállítására. Egyelőre nem nagyon használt.
|
544
|
254
|
971
|
255 static int init(int rate,int channels,int format,int flags);
|
1263
|
256 Driver initje, ilyenkor kell megnyitni a device-t, beállítani samplerate,
|
|
257 channels, sample format paramétereket.
|
|
258 Sample format: általában AFMT_S16_LE vagy AFMT_U8, további definíciókért
|
|
259 lásd. dec_audio.c ill. linux/soundcard.h file-okat!
|
|
260
|
971
|
261 static void uninit();
|
1263
|
262 Találd ki!
|
|
263 Na jó, segítek: lezárja a device-t, kilépéskor (még nem) hívódik meg.
|
|
264
|
971
|
265 static void reset();
|
1263
|
266 Reseteli a device-t. Egész pontosan a bufferek törlésére szolgál,
|
|
267 tehát hogy a reset() után már ne szóljon tovább az, amit előtte kapott.
|
|
268 (pause ill. seek esetén hívódik meg)
|
971
|
269
|
|
270 static int get_space();
|
1263
|
271 Vissza kell adja, hogy hány byte írható az audio bufferbe anélkül, hogy
|
|
272 blockolna (várakoztatná a hívó processt). Amennyiben a buffer (majdnem)
|
971
|
273 tele van, 0-t kell visszaadni!
|
1263
|
274 Ha sosem ad vissza 0-t, akkor nem fog működni az MPlayer!
|
971
|
275
|
|
276 static int play(void* data,int len,int flags);
|
1263
|
277 Lejátszik egy adag hangot, amit a data című memóriaterületen kap és len
|
|
278 a mérete. a flags még nem használt. Az adatokat át kell másolnia, mert a
|
|
279 hívás után felülíródhatnak! Nem kell feltétlen minden byte-ot felhasználni,
|
|
280 hanem azt kell visszaadnia, mennyit használt fel (másolt a bufferbe).
|
971
|
281
|
|
282 static int get_delay();
|
1263
|
283 Vissza kell adja, hogy hány byte várakozik az audio bufferben. lehetőleg
|
|
284 minél pontosabban, mert ettől függ az egész időzítés!
|
|
285 Legrosszabb esetben adja vissza a buffer méretét!
|
971
|
286
|
1263
|
287 !!! Mivel a kép a hanghoz (hangkártyához) van szinkronizálva, így nagyon fontos,
|
|
288 !!! hogy a get_space ill. get_delay függvények korrektül legyenek megírva!
|
971
|
289
|