view DOCS/tech/tech-hun.txt @ 986:fadb8eeff7a8

commitus interruptus
author gabucino
date Mon, 04 Jun 2001 08:06:20 +0000
parents dcf8d81eed48
children 4f61dc71a8e2
line wrap: on
line source

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!