summaryrefslogtreecommitdiffstats
path: root/DOCS/tech/tech-hun.txt
blob: 2af4283498decf20a3b6aba37b748b5df0e12f3f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
Nos, akkor leirom, hogyan is működik ez az egé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ő sectoronkenti bufferelés, seek, skip funkciók,
	 byte-onkénti ill. tetszőleges méretű blockonkénti olvasás.
	 Egy stream (input device/file) leírására a stream_t struktura szolgál.
	 
2. demuxer.c: ez végzi az input szétszedését audio és video csatornákra,
   és a kiválasztott csatornák bufferelt package-enkénti olvasását.
	 A demuxer.c inkább csak egy framework, ami közös minden input
	 formátumra, és az egyes formátumokhoz (mpeg-es,mpeg-ps, avi, avi-ni, asf)
	 külön parser van, ezek a demux_*.c fileokban vannak.
	 A hozza tartozo struktura a demuxer_t. osszesen egy demuxer van.
	 
2.a. demux_packet_t, azaz dp.
   ez egy darab chunk-ot (avi) vagy packet-et (asf,mpg) tartalmaz.
	 memoriaban ezek lancolt listaban vannak, mivel kulonbozo meretuek.

2.b. demuxer stream, azaz ds.
   struct: demux_stream_t
   minden egyes csatornahoz (a/v) tartozik egy ilyen.
	 ez tartalmazza a stream-hez tartozo packeteket (lasd. 2.a.)
	 egyelore demuxer-enkent 3 ilyen lehet:
	 - hang (d_audio)
	 - kep  (d_video)
	 - DVD felirat (d_dvdsub)

2.c. stream header. 2 fele van (egyelore): sh_audio_t es sh_video_t
   ez tartalmaz minden, a dekodolashoz szukseges parametert, igy az input
   es output buffereket, kivalasztott codecet, fps/framerate stb adatokat.
   Annyi van belole, ahany stream van a fileban tarolva. Lesz minimum egy
   a videohoz, ha van hang akkor ahhoz is, de ha tobb audio/video stream
   is van, akkor mindegyikhez lesz egy ilyen struct.
   Ezeket avi/asf eseten a header alapjan tolti fel a header beolvaso,
   mpeg eseten pedig a demux_mpg.c fogja letrehozni ha egy uj streamet
   talal. Uj stream eseten ====> Found audio/video stream: <id>  jelenik meg.
   
   A kivalasztott stream header es a hozza tartozo demuxer stream kolcsonosen
   hivatkoznak egymasra (ds->sh es sh->ds) az egyszerubb hasznalat miatt.
   (igy a funkciotol fuggoen eleg vagy csak a ds vagy csak az sh atadasa)
   
   Pelda: van egy .asf fileunk, abban 6 db stream, ebbol 1 audio es 5 video.
   A header beolvasasakor letre fog jonni 6 db sh struct, 1 audio es 5 video.
   Amikor elkezdi olvasni a packeteket, az elso talalt audio es video
   packethez tartozo streamet
   kivalasztja, es ezekre allitja be a d_audio es d_video sh pointereit.
   Igy kesobbiekben mar csak ezeket a streameket olvassa, a tobbit nem.
   Persze ha az user masik streameket szeretne kivalasztani, akkor
   force-olhatja a -aid es -vid kapcsolokkal.
   Jo pelda erre a DVD, ahol nem mindig az angol szinkron hang az elso
   megtalalt stream, es igy random minden vob mas nyelven szolalhat meg :)
   Ilyenkor kell pl. az -aid 128 kaocsolot hasznalni.
   
  hogy is muxik ez a beolvasosdi?
	 - meghivodik a demuxer.c/demux_read_data(), megkapja melyik ds-bol
	   (audio vagy video), mennyi byteot es hova (memoriacim) szeretnenk 
		 beolvasni. ezt hivogatjak gyakorlatilag a codec-ek.
	 - ez megnezi,hogy az adott ds bufferében van-e valami, ha igen akkor 
	   onnan olvas amennyit kell. ha nincs/nincs eleg, akkor meghivja
		 a ds_fill_buffer()-t ami:
	 - megnezi hogy az adott ds-ben vannak-e bufferelve csomagok (dp-k)
	   ha igen, akkor a legregebbit atrakja a bufferbe es olvas tovabb.
		 ha ures a lancolt lista, akkor meghivja a demux_fill_buffer()-t:
	 - ez az input formatumnak megfelelo parser-t meghivja ami olvassa
	   tovabb a filet, es a talalt csomagokat rakja be a megfelelo bufferbe.
		 na ha mondjuk audio csomagot szeretnenk, de csak egy rakat video csomag
		 van, akkor jon elobb-utobb a DEMUXER: Too many (%d in %d bytes) audio 
		 packets in the buffer... hibauzenet.

Eddig kb tiszta ugy, ezt akarom majd atrakni kulon lib-be.

na nezzuk tovabb:

3. mplayer.c - igen, o a fonok :)
   az idozites eleg erdekesen van megoldva, foleg azert mert minden
	 fileformatumnal maskepp kell/celszeru, es neha tobbfele keppen is lehet.

	 van egy a_frame es egy v_frame nevu float valtozo, ez tarolja az epp
	 lathato/hallhato a/v poziciojat masodpercben.
	 
	 A lejatszo ciklus felepitese:
	 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 lejatszik (hang/kep) akkor a lejatszott valami idotartamaval
	 noveli a megfelelo valtozot:
	 - audional ez a lejatszott byteok / sh_audio->o_bps
	 megj: i_bps = tomoritett byteok szama egy masodpercnyi hanghoz
	       o_bps = tomoritetlen byteok szama egy masodpercnyi hanghoz
	           (ez utobbi == bps*samplerate*channels)
	 - videonal ez altalaban az sh_video->frametime.
	 Ez altalaban == 1.0/fps, persze meg kell jegyeznem hogy videonal nem
	 igazan szamit az fps, asf-nel pl. nincs is olyan, ahelyett duration
	 van es framenkent valtozhat.
	 mpeg2-nel pedig repeat_count van ami 1-2.5 idotartamban elnyujtja
	 a framet... avi-nal van talan egyedul fix fps, meg mpeg1-nel.

	 Na most ez addig nagyon szepen mukodik, amig a hang es kep tokeletes
	 szinkronban van, mivel igy vegulis a hang szol, az adja az idozitest,
	 es amikor eltelt egy framenyi ido akkor kirakja a kovetkezo framet.
	 de mi van ha valamiert az input fileban csuszik a ketto?
	 Akkor jon be a PTS correction. az input demuxer-ek olvassak a csomagokkal
	 egyutt a hozzajuk tartozo PTS-t (presentation timestamp) is, ami alapjan
	 eszreveheto ha el van csuszva a ketto. ilyenkor egy megadott maximalis
	 hataron (lasd -mc opcio) belul kepes az mplayer korrigalni az a_frame 
	 erteket. a korrekciok osszege van a c_total-ban.
	 
	 persze ez meg nem minden szinkron ugyben, van meg nemi gaz.
	 pl. az hogy a hangkartya eleg rendesen kesleltet, ezt az mplayernek
	 korrigalnia kell! Az osszes audio kesleltetes masodpercben ezek osszege:
	 - az utolso timestamp (PTS) ota beolvasott byteok:
	   t1 = d_audio->pts_bytes/sh_audio->i_bps
	 - Win32/ACM eseten az audio input bufferben tarolt byteok:
	   t2 = a_in_buffer_len/sh_audio->i_bps
	 - az audio out bufferben tarolt tomoritetlen byteok:
	   t3 = a_buffer_len/sh_audio->o_bps
	 - a hangkartya buffereben (vagy DMA bufferben) tarolt, meg nem
	   lejatszott byteok:
	   t4 = get_audio_delay()/sh_audio->o_bps
	 
	 Ezekbol kiszamolhato egeszen pontosan, hogy az epp hallhato hanghoz 
	 milyen PTS tartozik, majd ezt osszevetve a video-hoz tartozo PTS-el
	 meg is kapjuk az A-V eltereset!
	 
	 avi-nal sem egyszeru az elet. ott a 'hivatalos' idozitesi mod a
	 BPS-alapu, azaz a headerben le van tarolva hany tomoritett audio
	 byte tartozik egy masodpercnyi (fps darab) kephez.
	 ez persze nem mindig mukodik... miert is mukodne :)
	 ezert en megcsinaltam hogy az mpeg-nel hasznalatos sectoronkenti
	 PTS erteket emulalom avi-ra is, azaz az AVI parser minden beolvasott
	 chunk-nal szamol egy kamu PTS-t a framek tipusa alapjan. es ez
	 alapjan idozitek. es van amikor ez mukodik jobban.
	 persze itt meg bejatszik az is, hogy AVI-nal altalaban elore letarolnak
	 egy nagyobb adag hangot, es csak utana kezdodik a kep. ezt persze
	 bele kell szamolni a kesleltetesbe, ez az Initial PTS delay.
	 ilyen persze 2 is van, az egyik a headerben le is van irva, es
	 nem nagyon hasznlajak :) a masik sehol nincs leirva de hasznaljak, ezt
	 csak merni lehet...

3.a. audio playback:
	 par szo az audio lejatszasrol:
	 az egeszben nem maga a lejatszas a nehez, hanem:
	 1. hogy tudjuk mikor lehet irni a bufferbe, blocking nelkul
	 2. hogy tudjuk, mennyit jatszott mar le abbol amit a bufferbe irtunk
	 Az 1. az audio dekodolashoz kell, valamint hogy a buffert mindig teli
	 allapotban tudjuk tartani (igy sose fog megakadni a hang).
	 A 2. pedig a korrekt idoziteshez szukseges, ugyanis nemely hangkartya
	 akar 3-7 masodpercet is kesleltet, ami azert nem elhanyagolhato!
	 Ezek megvalositasara az OSS tobbfele lehetoseget is kinal:
	 - ioctl(SNDCTL_DSP_GETODELAY): megmondja hany lejatszatlan byte
	   varakozik a hangkartya bufferjeben -> idoziteshez kivallo,
	   de nem minden driver tamogatja :(
	 - ioctl(SNDCTL_DSP_GETOSPACE): megmondja mennyit irhatunk a kartya
	   bufferebe blocking nelkul. ha a driver nem tudja a GETODELAY-t,
	   akkor ezt hasznalhatjuk arra is, hogy megtudjuk a kesleltetest.
	 - select(): meg kene mondja, hogy irhatunk-e a kartya bufferebe
	   blocking nelkul. azt, hogy emnnyit irhatunk, nem mondja meg :(
	   valamint sok driverrel egyaltalan nem, vagy rosszul mukodik :((
	   csak akkor hasznalom, ha egyik fenti ioctl() sem mukodik.

4. codecek. ezek kulonbozo lib-ek szanaszet mindenfelol.
   mint pl. libac3, libmpeg2, xa/*, alaw.c, opendivx/*, loader, mp3lib.
	 az mplayer.c hivogatja oket amikor egy egy darab hangot vagy framet
	 kell lejatszani (lasd 3. pont elejen).
	 ezek pedig hivjak a megfelelo demuxert hogy megkapjak a tomoritett
	 adatokat (lasd 2. pont).
	 parameterkent a megfelelo stream headert (sh_audio/sh_video) kell
	 atadni, ez elvileg tartalmaz minden infot ami szukseges a
	 dekodolashoz (tobbek kozott a demuxert is: sh->ds).
   A codecek szeparalasa folyamatban van, az audio mar el van kulonitve
   (lasd. dec_audio.c), a videon meg dolgozunk. Cel, hogy ne az mplayer.c
   kelljen tudja milyen codecek vannak es hogy kell oket hasznalni, hanem
   egy kozos init/decode audio/video functiont kelljen csak meghivnia.

5. libvo: ez vegzi a kep kirakasat.

  Az img_format.h-ban definialva vannak konstansok a kulonbozo pixel-
  formatumokhoz, ezeket kotelezo hasznalni.
  
  1-1 vo driver a kovetkezoket kell kotelezoen implementalja:

  query_format()  - lekerdezi hogy egy adott pixelformat tamogatott-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 driver kotelezo tamogassa az YV12 formatumot, es
  egyiket (vagy mindkettot) a BGR15 es BGR24 kozul, ha kell, konvertalassal.
  Ha ezeket nem tamogatja, akkor nem fog minden codec-kel mukodni!
  Ennek az az oka, hogy az mpeg codecek csak YV12-t tudnak eloallitani,
  a regebbi Win32 DLL codecek pedig csak 15 es 24bpp-t tudnak.
  Van egy gyors MMX-es 15->16bpp konvertalo, igy az nem okoz kulonosebb
  sebessegcsokkenest!
  
  A BPP tablazat, ha a driver nem tud bpp-t valtani:
      jelenlegi bpp:    ezeket kell elfogadni:
           15                    15
	   16                    15,16
	   24                    24
	   24,32                 24,32

  Ha tud bpp-t valtani (pl. DGA 2, fbdev, svgalib) akkor ha lehet, be kell
  valtani a kert bpp-re. Ha azt a hardver nem tamogatja, akkor a legkozelebbi
  modra (15 eseten 16-ra, 24 eseten 32-re) kell valtani es konvertalni!

  init() - ez hivodik meg a legelso frame kirakasa elott - bufferek foglalasa
           stb a celja.
	   van egy flags parameter is (regen 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 kepet rak ki (3 db plane, egy teljes
	 meretu ami a fenyerot (Y) tartalmazza, es 2 negyedakkora, ami a
	 szin (U,V) infot). ezt hasznaljak az mpeg codecek (libmpeg2,opendivx).
	 ez mar tud olyat hogy nem az egesz kep kirakasa, hanem csak kis
	 reszletek updatelese: ilyenkor a sarkanak es a darabka meretenek
	 megadasaval lehet csinalni.

  draw_frame(): ez a regebbi interface, ez csak komplett framet rak ki,
   es csak packed formatumot (YUY2 stb, RGB/BGR) tud.
	 ezt hasznaljak a win32 codecek (divx,indeo stb).
	 
  draw_alpha(): ez rakja ki a subtitle-t es az OSD-t.
   hasznalata kicsit cseles, mivel ez nem a libvo API resze, hanem egy
   callback jellegu cucc. a flip_page() kell meghivja a vo_draw_text()-et
   ugy, hogy parameterkent atadja a kepernyo mereteit es a pixelformatumnak
   megfelelo draw_alpha() implementaciot (function pointer).
   Ezutan a vo_draw_text() vegigmegy a kirajzolando karaktereken, es egyenkent
   meghivja minden karakterre a draw_alpha()-t.
   Segitseg keppen az osd.c-ben meg van irva a draw_alpha mindenfele
   pixelformatumhoz, ha lehet ezt hasznald!
   
  flip_page(): ez meghivodik minden frame utan, ez kell tenylegesen
   megjelenitse a buffert. double buffering eseten ez lesz a 'swapbuffers'.
  
6. libao2: ez vezerli a hang lejatszast

  A libvo-hoz (lasd 5.) hasonloan itt is kulonbozo driverek vannak, amik
  egy kozos API-t (interface) valositanak meg:
  
static int control(int cmd,int arg);
  Ez egy altalanos celu fuggveny, a driverfuggo es egyeb specialis parameterek
  olvasasara/beallitasara. Egyelore nem nagyon hasznalt.

static int init(int rate,int channels,int format,int flags);
  Driver initje, ilyenkor kell megnyitni a devicet, beallitani samplerate,
  channels, sample format parametereket.
  Sample format: altalaban AFMT_S16_LE vagy AFMT_U8, tovabbi definiciokert
  lasd. dec_audio.c ill. linux/soundcard.h fileok!
  
static void uninit();
  talald ki.
  na jo, segitek: lezarja a devicet, kilepeskor (meg nem) hivodik meg.
  
static void reset();
  reseteli a devicet. egesz pontosan a bufferek torlesere szolgal,
  tehat hogy a reset() utan mar ne szoljon tovabb az amit elotte kapott.
  (pause ill. seek eseten hivodik meg)

static int get_space();
  vissza kell adja hogy hany byte irhato az audio bufferbe anelkul hogy
  blockolna (varakoztatna a hivo processt). amennyiben a buffer (majdnem)
  tele van, 0-t kell visszaadni!
  ha sosem ad vissza 0-at akkor nem fog mukodni az MPlayer!

static int play(void* data,int len,int flags);
  lejatszik egy adag hangot, amit a data cimu memoriateruleten kap, es len
  a merete. a flags meg nem hasznalt. az adatokat at kell masolnia, mert a
  hivas utan felulirodhatnak! nem kell feltetlen minden byetot felhasznalni,
  hanem azt kell visszaadnia mennyit hasznalt fel (masolt a bufferbe).

static int get_delay();
  vissza kell adja hogy hany byte varakozik az audio bufferben. lehetoleg
  minel pontosabban, mert ettol fugg az egesz idozites!
  legrosszabb esetben adja vissza a buffer meretet.

!!!  Mivel a kep a hanghoz (hangkartyahoz) van szinkronizalva, igy nagyon
!!!  fontos hogy a get-space ill. get_delay fuggvenyek korrektul legyenek megirva!