Mediastreamer2 VoIP motorra arakatzen. 11. zatia

Artikuluaren materiala niretik hartua da zen kanala.

Mediastreamer2 VoIP motorra arakatzen. 11. zatia

Datuen mugimenduaren mekanismoa

  • Datu-blokea dblk_t
  • Mezua mblk_t
  • Mblk_t mezuekin lan egiteko funtzioak
  • Ilara ilara_t
  • Ilarekin lan egiteko funtzioak queue_t
  • Iragazkiak konektatzea
  • Datuak prozesatzeko grafikoaren seinale-puntua
  • Ticker-aren eszenaren atzean
  • Bufferizatzailea (MSBufferizer)
  • MSBufferizer-ekin lan egiteko funtzioak

Azkenean Artikulu gure iragazki propioa garatu dugu. Artikulu hau multimedia-streamer-iragazkien artean datuak mugitzeko barne-mekanismoari buruz arituko da. Horri esker, etorkizunean esfortzu gutxiagorekin iragazki sofistikatuak idazteko aukera izango duzu.

Datuen mugimenduaren mekanismoa

Multimedia-streamer-en datuen mugimendua egiturak deskribatutako ilarak erabiliz egiten da ilara_t. Horrelako mezu kateak mblk_t, beraiek ez baitute seinale-daturik, baina aurreko, hurrengo mezurako eta datu-blokerako estekak baino ez dituzte. Horrez gain, bereziki azpimarratu nahi dut mota bereko mezu baterako esteketarako eremu bat ere badagoela, eta horrek aukera ematen du banaka loturiko mezuen zerrenda antolatzeko. Horrelako zerrenda batek batzen dituen mezu multzo bati tupla deituko diogu. Horrela, ilararen edozein elementu mezu bakarra izan daiteke mblk_t, eta agian mezu tupla baten burua mblk_t. Mezu tupla bakoitzak bere auzoko datu-blokea izan dezake. Tuplak zergatik behar diren aztertuko dugu pixka bat geroago.

Goian esan bezala, mezuak berak ez du datu-blokerik; horren ordez, blokea gordetzen den memoria-eremurako erakuslea besterik ez du. Zati honetan, komunikabideen streamer-aren lanaren irudi orokorrak "Monsters, Inc." marrazki biziduneko ate biltegia gogorarazten du, non ateak (datuetarako estekak - gelak) abiadura zoroan mugitzen diren goialdeko garraiagailuetan zehar, gelak beraiek bitartean. geldirik egon.

Orain, hierarkian behetik gora mugituz, azter ditzagun zehatz-mehatz datu-transmisio-mekanismoaren zerrendako entitateak multimedia-streamer-en.

Datu blokea dblk_t

Datu-blokea goiburu batek eta datu-buffer batek osatzen dute. Goiburua honako egitura honek deskribatzen du,

typedef struct datab
{
unsigned char *db_base; // Указатель на начало буфер данных.
unsigned char *db_lim;  // Указатель на конец буфер данных.
void (*db_freefn)(void*); // Функция освобождения памяти при удалении блока.
int db_ref; // Счетчик ссылок.
} dblk_t;

Egituraren eremuek buffer-aren hasierarako, buffer-aren amaierarako eta datu-bufferra ezabatzeko funtziorako erakusleak dituzte. Goiburuko azken elementua db_erref — Erreferentzia-kontagailua, zerora iristen bada, bloke hau memoriatik ezabatzeko seinale gisa balio du. Datu-blokea funtzioak sortu badu datab_alloc() , orduan datu-buffer-a memorian jarriko da goiburuaren ondoren. Gainerako kasuetan, buffera nonbait bereizita egon daiteke. Datu-buffer-ak seinale-laginak edo iragazkiekin prozesatu nahi ditugun beste datu batzuk izango ditu.

Datu-bloke baten instantzia berri bat sortzen da funtzio hau erabiliz:

dblk_t *datab_alloc(int size);

Sarrera-parametro gisa, blokeak gordeko dituen datuen tamaina ematen da. Memoria gehiago esleitzen da esleitutako memoriaren hasieran goiburua -egitura- jartzeko datuakb. Baina beste funtzio batzuk erabiltzean, hori ez da beti gertatzen; kasu batzuetan, datu-buffera datu-blokearen goiburutik bereizita egon daiteke. Egitura bat sortzean, eremuak bere eremua izateko konfiguratzen dira db_base datu-eremuaren hasiera seinalatu zuen, eta db_lim bere amaieraraino. Esteka kopurua db_erref batean ezarrita dago. Datuak garbitzeko funtzioaren erakuslea zeroan ezarrita dago.

Mezua mblk_t

Esan bezala, ilararen elementuak motakoak dira mblk_t, honela definitzen da:

typedef struct msgb
{
  struct msgb *b_prev;   // Указатель на предыдущий элемент списка.
  struct msgb *b_next;   // Указатель на следующий элемент списка.
  struct msgb *b_cont;   // Указатель для подклейки к сообщению других сообщений, для создания кортежа сообщений.
  struct datab *b_datap; // Указатель на структуру блока данных.
  unsigned char *b_rptr; // Указатель на начало области данных для чтения данных буфера b_datap.
  unsigned char *b_wptr; // Указатель на начало области данных для записи данных буфера b_datap.
  uint32_t reserved1;    // Зарезервированное поле1, медиастример помещает туда служебную информацию. 
  uint32_t reserved2;    // Зарезервированное поле2, медиастример помещает туда служебную информацию.
  #if defined(ORTP_TIMESTAMP)
  struct timeval timestamp;
  #endif
  ortp_recv_addr_t recv_addr;
} mblk_t;

Egitura mblk_t erakusleak ditu hasieran b_aurreko, b_hurrengo, beharrezkoak direnak bi loturiko zerrenda bat antolatzeko (ilara bat dena ilara_t).

Ondoren, erakuslea dator b_kont, mezua tupla baten parte denean bakarrik erabiltzen dena. Tuplako azken mezurako, erakusle hau nulua izaten jarraitzen du.

Ondoren, datu-bloke baten erakuslea ikusiko dugu b_datap, eta horretarako mezua existitzen da. Jarraian, blokearen datu-buffer barruko eremuaren erakusleak daude. Eremua b_rptr Buffer-eko datuak zein tokitatik irakurriko diren zehazten du. Eremua b_wptr bufferera idazketak zein kokapenetik egingo diren adierazten du.

Gainerako eremuek zerbitzu izaera dute eta ez dute zerikusirik datuak transferitzeko mekanismoaren funtzionamenduarekin.

Jarraian mezu bakarra dago izena duen m1 eta datu-blokea d1.
Mediastreamer2 VoIP motorra arakatzen. 11. zatia
Hurrengo irudian hiru mezuren tupla bat erakusten da m1, m1_1, m1_2.
Mediastreamer2 VoIP motorra arakatzen. 11. zatia

Mezularitza-funtzioak mblk_t

Mezu berri bat mblk_t funtzioak sortua:

mblk_t *allocb(int size, int pri); 

mezu berri bat jartzen du oroimenean mblk_t zehaztutako tamainako datu-bloke batekin tamaina, bigarren argumentua - pRI ez da liburutegiaren bertsio honetan erabiltzen. Zero mantendu behar da. Funtzioa funtzionatzen duen bitartean, mezu berriaren egiturarako memoria esleituko da eta funtzioari deituko zaio mblk_init(), egituraren sortutako instantziaren eremu guztiak berrezarriko dituena eta, ondoren, aipatutakoa erabiliz datab_alloc(), datu-buffer bat sortuko du. Horren ondoren, egiturako eremuak konfiguratuko dira:

mp->b_datap=datab;
mp->b_rptr=mp->b_wptr=datab->db_base;
mp->b_next=mp->b_prev=mp->b_cont=NULL;

Irteeran mezu berri bat jasoko dugu hasieratutako eremuekin eta datu-buffer hutsarekin. Mezu bati datuak gehitzeko, datu-blokearen bufferera kopiatu behar dituzu:

memcpy(msg->b_rptr, data, size);

non datuak datu-iturbururako erakuslea da, eta tamaina - haien tamaina.
ondoren, erakuslea idazketa puntura eguneratu behar duzu, berriro buffer-eko eremu librearen hasierara seinalatzeko:

msg->b_wptr = msg->b_wptr + size

Lehendik dagoen buffer batetik mezu bat sortu behar baduzu, kopiatu gabe, erabili funtzioa:

mblk_t *esballoc(uint8_t *buf, int size, int pri, void (*freefn)(void*)); 

Funtzioak, mezua eta datu-blokearen egitura sortu ondoren, helbideko datuetara bere erakusleak konfiguratuko ditu buff. Horiek. kasu honetan, datu-buffer-a ez da datu-blokearen goiburuko eremuen ondoren kokatzen, funtzioarekin datu-bloke bat sortzean gertatu zen bezala. datab_alloc(). Funtzioari pasatutako datuak dituen buffer-a zegoen lekuan geratuko da, baina erakusleen laguntzaz datu-blokearen goiburu sortu berriari erantsiko zaio, eta hori, horren arabera, mezuari.

Mezu bati mblk_t Hainbat datu-bloke sekuentzialki kateatu daitezke. Hau funtzioak egiten du:

mblk_t * appendb(mblk_t *mp, const char *data, int size, bool_t pad); 

mp — beste datu-bloke bat gehituko zaion mezu bat;
datuak — blokearen erakuslea, eta horren kopia bat gehituko zaio mezuari;
tamaina - datuen tamaina;
pad — Esleitutako memoriaren tamaina 4 byteko muga batean lerrokatu behar dela adierazten duen bandera (betetzea zeroekin egingo da).

Lehendik dagoen mezuen datuen bufferean nahikoa leku badago, datu berriak lehendik dauden datuen atzean itsatsiko dira. Mezuen datuen bufferean baino leku libre gutxiago badago tamaina, orduan mezu berri bat sortzen da buffer tamaina nahikoarekin eta datuak bere bufferera kopiatzen dira. Mezu berri bat da, erakuslea erabiliz jatorrizkoari lotua b_kont. Kasu honetan, mezua tupla bihurtzen da.

Tuplari beste datu-bloke bat gehitu behar baduzu, funtzio hau erabili behar duzu:

void msgappend(mblk_t *mp, const char *data, int size, bool_t pad);

azken mezua tuplaan aurkituko du (du b_kont nulua izango da) eta mezu honen funtzioari deituko dio eranskin().

Mezu edo tupla bateko datuen tamaina jakin dezakezu funtzio hau erabiliz:

int msgdsize(const mblk_t *mp);

tuplako mezu guztiak zeharkatuko ditu eta datu-kopuru osoa itzuliko du mezu horien datu-bufferetan. Mezu bakoitzeko, datu kopurua honela kalkulatzen da:

 mp->b_wptr - mp->b_rptr

Bi tupla konbinatzeko, erabili funtzioa:

mblk_t *concatb(mblk_t *mp, mblk_t *newm);

tupla eransten du berria tuplaren isatsera mp eta ondoriozko tuplaren azken mezurako erakuslea itzultzen du.

Beharrezkoa bada, tupla bat mezu bakar batean bihur daiteke datu-bloke bakarrarekin; hau funtzioak egiten du:

void msgpullup(mblk_t *mp,int len);

argumentua bada len -1 da, orduan esleitutako buffer-aren tamaina automatikoki zehazten da. Bada len zenbaki positiboa da, tamaina horretako buffer bat sortuko da eta tuplaren mezuen datuak bertan kopiatuko dira. Buffer-a agortzen bada, kopiatzea bertan geldituko da. Tuplaren lehen mezuak tamaina-buffer berri bat jasoko du kopiatutako datuekin. Gainerako mezuak ezabatu egingo dira eta memoria pilara itzuliko da.

Egitura bat ezabatzean mblk_t datu-blokearen erreferentzia-zenbaketa kontuan hartzen da baldin, deitzean freeb() zero da, orduan datu-buffer-a ezabatzen da instantziarekin batera mblk_t, seinalatzen duena.

Mezu berri baten eremuak hasieratzen:

void mblk_init(mblk_t *mp);

Mezuari beste datu bat gehitzea:

mblk_t * appendb(mblk_t *mp, const char *data, size_t size, bool_t pad);

Datu berriak ez badira sartzen mezuen datuen buffer-aren espazio librean, orduan, behar den tamainako buffer batekin bereizita sortutako mezu bat erantsiko zaio mezuari (gehitutako mezuaren erakuslea ezartzen da lehenengo mezuan) eta mezua tupla bihurtzen da.

Tupla bati datu bat gehitzea:

void msgappend(mblk_t *mp, const char *data, size_t size, bool_t pad); 

Funtzioak appendb() deitzen du begizta batean.

Bi tupla bakarrean konbinatuz:

mblk_t *concatb(mblk_t *mp, mblk_t *newm);

Mezua berria erantsiko zaio mp.

Mezu bakar baten kopia bat egitea:

mblk_t *copyb(const mblk_t *mp);

Datu-bloke guztiekin tupla baten kopia osoa:

mblk_t *copymsg(const mblk_t *mp);

Tuplaren elementuak funtzioak kopiatzen ditu copyb().

Sortu mezu baten kopia erraz bat mblk_t. Kasu honetan, datu-blokea ez da kopiatzen, baina bere erreferentzia-kontagailua handitu egiten da db_erref:

mblk_t *dupb(mblk_t *mp);

Tupla baten kopia arin bat egitea. Datu-blokeak ez dira kopiatzen, haien erreferentzia-kontagailuak bakarrik handitzen dira db_erref:

mblk_t *dupmsg(mblk_t* m);

Tupla baten mezu guztiak mezu bakarrean itsatsi:

void msgpullup(mblk_t *mp,size_t len);

Argudioa bada len -1 da, orduan esleitutako buffer-aren tamaina automatikoki zehazten da.

Mezu bat ezabatzen, tupla:

void freemsg(mblk_t *mp);

Datu-blokearen erreferentzia-zenbaketa bat gutxitzen da. Zerora iristen bada, datu-blokea ere ezabatzen da.

Mezu edo tupla bateko datu kopuru osoaren kalkulua.

size_t msgdsize(const mblk_t *mp);

Ilararen buztanetik mezu bat berreskuratzen:

mblk_t *ms_queue_peek_last (q);

Mezu baten erreserbatutako eremuen edukia beste mezu batean kopiatzea (hain zuzen ere, eremu hauek multimedia-streamer-ak erabiltzen dituen banderak dituzte):

mblk_meta_copy(const mblk_t *source, mblk *dest);

piztu ilara_t

Multimedia streamer-eko mezu-ilara bikoitzeko estekatutako zerrenda zirkular gisa inplementatzen da. Zerrendako elementu bakoitzak seinale-laginak dituen datu-bloke baterako erakuslea dauka. Bihurtzen da datu-blokearen erakusleak bakarrik mugitzen direla txandaka, eta datuak berak geldirik geratzen diren bitartean. Horiek. haiekiko estekak bakarrik mugitzen dira.
Ilara deskribatzen duen egitura ilara_t, behean agertzen dena:

typedef struct _queue
{
   mblk_t _q_stopper; /* "Холостой" элемент очереди, не указывает на данные, используется только для управления очередью. При инициализации очереди (qinit()) его указатели настраиваются так, чтобы они указывали на него самого. */
   int q_mcount;        // Количество элементов в очереди.
} queue_t;

Egiturak eremu bat dauka - erakuslea _q_tapoia idatzi *mblk_t, ilaran dagoen lehen elementura (mezua) seinalatzen du. Egituraren bigarren eremua ilaran dauden mezuen kontagailua da.
Beheko irudian m1, m4, m1, m2 3 mezu dituen q4 izeneko ilara bat erakusten da.
Mediastreamer2 VoIP motorra arakatzen. 11. zatia
Hurrengo irudian q1 izeneko ilara bat erakusten da, m4,m1,m2,m3 4 mezu dituena. m2 mezua m2_1 eta m2_2 beste bi mezu dituen tupla baten burua da.

Mediastreamer2 VoIP motorra arakatzen. 11. zatia

Ilarekin lan egiteko funtzioak queue_t

Ilararen hasieratzea:

void qinit(queue_t *q);

Field _q_tapoia (aurrerantzean “tapoia” deituko diogu) funtzioak hasieratzen du mblk_init(), bere aurreko elementua eta hurrengo elementuaren erakuslea berera seinalatzeko doitzen dira. Ilararen elementuen kontagailua zerora berrezarri da.

Elementu berri bat gehitzea (mezuak):

void putq(queue_t *q, mblk_t *m);

Elementu berria m zerrendaren amaieran gehitzen da, elementu erakusleak doitzen dira, tapoia haren hurrengo elementua izan dadin eta tapoiaren aurreko elementua izan dadin. Ilararen elementuen kontagailua handitzen da.

Elementu bat ilaratik berreskuratzen:

mblk_t * getq(queue_t *q); 

Tapoia berreskuratu eta elementuen kontagailua txikiagotu ondoren datorren mezua. Tapoia izan ezik ilaran elementurik ez badago, 0 itzultzen da.

Mezu bat ilara batean sartzea:

void insq(queue_t *q, mblk_t *emp, mblk_t *mp); 

elementu mp elementuaren aurretik sartuta EMP. bada EMP=0, orduan mezua ilararen buztanera gehitzen da.

Ilararen burutik mezu bat berreskuratzen:

void remq(queue_t *q, mblk_t *mp); 

Elementu-kontagailua gutxitu egiten da.

Ilararen lehen elementuaren erakuslea irakurtzea:

mblk_t * peekq(queue_t *q); 

Elementu guztiak ilaratik kentzea elementuak beraiek ezabatzen dituzun bitartean:

void flushq(queue_t *q, int how);

Argudioa nola ez erabiltzen. Ilararen elementuen kontagailua zeroan ezarri da.

Ilararen azken elementurako erakuslea irakurtzeko makroa:

mblk_t * qlast(queue_t *q);

Mezu-ilarekin lan egiten duzunean, kontutan izan deitzen duzunean ms_queue_put(q, m) mezuaren erakusle nulu batekin, funtzioak begiztak egiten ditu. Zure programa izoztu egingo da. antzera jokatzen du ms_queue_next(q, m).

Iragazkiak konektatzea

Goian azaldutako ilara mezuak iragazki batetik bestera edo iragazki batetik bestera pasatzeko erabiltzen da. Iragazkiak eta haien konexioek grafiko zuzendua osatzen dute. Iragazkiaren sarrera edo irteerari "pin" hitz orokorra deituko zaio. Iragazkiak elkarren artean konektatzen diren ordena deskribatzeko, multimedia-streamer-ak "seinale-puntu" kontzeptua erabiltzen du. Seinale-puntua egitura da _MSCPpoint, iragazkiaren erakuslea eta bere pin baten zenbakia dituena; horren arabera, iragazkien sarrera edo irteeraren baten konexioa deskribatzen du.

Datuak prozesatzeko grafikoaren seinale-puntua

typedef struct _MSCPoint{
struct _MSFilter *filter; // Указатель на фильтр медиастримера.
int pin;                        // Номер одного из входов или выходов фильтра, т.е. пин.
} MSCPoint;

Iragazkien pinak zerotik hasita zenbatzen dira.

Mezu-ilara baten bidez bi pin konektatzea egiturak deskribatzen du _MSQueue, mezu-ilara bat eta konektatzen dituen bi seinale puntuetarako erakusleak dituena:

typedef struct _MSQueue
{
queue_t q;
MSCPoint prev;
MSCPoint next;
}MSQueue;

Egitura honi seinale-lotura deituko diogu. Multimedia erreproduzitzaileen iragazki bakoitzak sarrerako esteken taula eta irteerako esteken taula ditu (MSQueue). Taulen tamaina iragazki bat sortzean ezartzen da; hori dagoeneko egin dugu esportatutako motako aldagai bat erabiliz MSFilterDesc, gure iragazki propioa garatu genuenean. Jarraian, multimedia-streamer bateko edozein iragazki deskribatzen duen egitura dago. MSFilter:


struct _MSFilter{
    MSFilterDesc *desc;    /* Указатель на дескриптор фильтра. */
    /* Защищенные атрибуты, их нельзя сдвигать или убирать иначе будет нарушена работа с плагинами. */
    ms_mutex_t lock;      /* Семафор. */
    MSQueue **inputs;     /* Таблица входных линков. */
    MSQueue **outputs;    /* Таблица выходных линков. */
    struct _MSFactory *factory; /* Указатель на фабрику, которая создала данный экземпляр фильтра. */
    void *padding;              /* Не используется, будет задействован если добавятся защищенные поля. */
    void *data;                 /* Указатель на произвольную структуру для хранения данных внутреннего состояния фильтра и промежуточных вычислений. */
    struct _MSTicker *ticker;   /* Указатель на объект тикера, который не должен быть нулевым когда вызывается функция process(). */
    /*private attributes, they can be moved and changed at any time*/
    MSList *notify_callbacks; /* Список обратных вызовов, используемых для обработки событий фильтра. */
    uint32_t last_tick;       /* Номер последнего такта, когда выполнялся вызов process(). */ 
    MSFilterStats *stats;     /* Статистика работы фильтра.*/
    int postponed_task; /*Количество отложенных задач. Некоторые фильтры могут откладывать обработку данных (вызов process()) на несколько тактов.*/
    bool_t seen;  /* Флаг, который использует тикер, чтобы помечать что этот экземпляр фильтра он уже обслужил на данном такте.*/
};
typedef struct _MSFilter MSFilter;

C programan iragazkiak gure planaren arabera konektatu ondoren (baina ticker-a konektatu gabe), horrela grafiko zuzendu bat sortu dugu, zeinaren nodoak egituraren instantziak diren. MSFilter, eta ertzak esteken instantzia dira MSQueue.

Ticker-aren eszenaren atzean

Ticker-a akainen iturriaren iragazkia dela esan nizunean, ez zen horren egia osoa. Ticker bat erlojuan funtzioak exekutatzen dituen objektu bat da prozesua() konektatuta dagoen zirkuituaren (grafiko) iragazki guztiak. Ticker bat C programa batean grafiko-iragazki batera konektatzen dugunean, ticker-ari hemendik aurrera kontrolatuko duen grafikoa erakusten diogu itzali arte. Konektatu ondoren, ticker-a bere ardurapean utzitako grafikoa aztertzen hasten da, berau barne hartzen duten iragazkien zerrenda osatuz. Iragazki bera bi aldiz "zenbatzeko" ez dadin, detektatutako iragazkiak markatzen ditu haietan kontrol-lauki bat jarriz ikusi. Bilaketa iragazki bakoitzak dituen esteka-taulak erabiliz egiten da.

Grafikoaren aurkezpen-ibilaldian, ticker-ak egiaztatzen du iragazkien artean datu-blokeen iturri gisa jokatzen duen gutxienez bat dagoen. Ez badago, grafikoa okertzat hartzen da eta ticker-a huts egiten du.

Grafikoa "zuzena" bihurtzen bada, aurkitutako iragazki bakoitzeko, funtzioa hasieratzeko deitzen da aurreprozesatu(). Hurrengo prozesatzeko ziklorako unea iritsi bezain laster (lehenespenez 10 milisegundo behin), ticker-ak funtzioari deitzen dio prozesua() aurrez aurkitutako iturburu-iragazki guztientzat, eta, ondoren, zerrendako gainerako iragazkietarako. Iragazkiak sarrerako estekak baditu, exekutatu funtzioa prozesua() errepikatzen da sarrerako estekaren ilarak hutsik egon arte. Honen ondoren, zerrendako hurrengo iragazkira igarotzen da eta "korritzen" du sarrerako estekak mezurik gabe geratu arte. Ticker-a iragazkiz iragazki mugitzen da zerrenda amaitu arte. Horrek zikloaren prozesamendua amaitzen du.

Orain tupleetara itzuliko gara eta komunikabide-streamer-era halako entitate bat zergatik gehitu den hitz egingo dugu. Oro har, iragazkien barruan funtzionatzen duen algoritmoak eskatzen duen datu kopurua ez dator bat eta ez da sarreran jasotako datu-bufferen tamainaren multiplo bat. Esate baterako, Fourier transformazio azkarra egiten duen iragazki bat idazten ari gara, definizioz, tamaina biko potentzia duten datu-blokeak soilik prozesatu ditzakeena. Izan bedi 512 zenbaketa. Datuak telefono-kanal batek sortzen baditu, orduan sarrerako mezu bakoitzaren datu-buffer-ak 160 seinale-lagin ekarriko dizkigu. Sarrerako datuak ez biltzea tentagarria da behar den datu kopurua egon arte. Baina kasu honetan, talka bat gertatuko da ticker-arekin, eta iragazkia korritzen saiatuko da arrakastarik gabe sarrerako esteka hutsik egon arte. Aurretik, arau hau iragazkiaren hirugarren printzipio gisa izendatu genuen. Printzipio horren arabera, iragazkiaren process() funtzioak sarrera-ilaretako datu guztiak hartu behar ditu.

Horrez gain, ezin izango da sarreratik 512 lagin bakarrik hartu, bloke osoak bakarrik hartu ditzakezulako, hau da. iragazkiak 640 lagin hartu eta horietatik 512 erabili beharko ditu, gainerakoa datu-zati berri bat pilatu aurretik. Horrela, gure iragazkiak, bere lan nagusiaz gain, sarrerako datuak tarteko biltegiratzeko ekintza osagarriak eman behar ditu. Media streamer-aren garatzaileek eta arazo orokor honen konponbidea objektu berezi bat garatu dute - MSBufferizer (bufferer), arazo hau tuplak erabiliz konpontzen duena.

Bufferizatzailea (MSBufferizer)

Iragazkiaren barruan sarrerako datuak pilatuko dituen objektu bat da eta iragazkiaren algoritmoa exekutatzeko informazio kopurua nahikoa den bezain laster prozesatzeko bidaltzen hasiko dena. Buffer-ak datuak pilatzen dituen bitartean, iragazkiak inaktibo moduan funtzionatuko du, prozesadorearen prozesatzeko ahalmena erabili gabe. Baina bufferreko irakurketa-funtzioak zero ez den balio bat itzultzen duen bezain laster, iragazkien process() funtzioa bufferreko datuak behar den tamainako zatietan hartzen eta prozesatzen hasten da, agortu arte.
Oraindik beharrezkoak ez diren datuak bufferean geratzen dira tuplaren lehen elementu gisa, eta horri sarrerako datuen ondorengo blokeak eransten zaizkio.

Buffer-a deskribatzen duen egitura:

struct _MSBufferizer{
queue_t q; /* Очередь сообщений. */
int size; /* Суммарный размер данных находящихся в буферизаторе в данный момент. */
};
typedef struct _MSBufferizer MSBufferizer;

MSBufferizer-ekin lan egiteko funtzioak

Buffer instantzia berri bat sortzea:

MSBufferizer * ms_bufferizer_new(void);

Memoria esleituta dago, hasieran hasten da ms_bufferizer_init() eta erakuslea itzultzen da.

Hasierako funtzioa:

void ms_bufferizer_init(MSBufferizer *obj); 

Ilara hasieratzen ari da q, eremua tamaina zeroan ezartzen da.

Mezu bat gehitzea:

void ms_bufferizer_put(MSBufferizer *obj, mblk_t *m); 

m mezua gehitzen da ilaran. Datu-blokeen tamaina kalkulatua gehitzen zaio tamaina.

Estekaren datu-ilaratik mezu guztiak bufferera transferitzea q:

void ms_bufferizer_put_from_queue(MSBufferizer *obj, MSQueue *q);   

Esteka batetik mezuak transferitzea q bufferean funtzioa erabiliz egiten da ms_bufferizer_put().

Bufferetik irakurtzen:

int ms_bufferizer_read(MSBufferizer *obj, uint8_t *data, int datalen); 

Bufferean pilatutako datuen tamaina eskatutakoa baino txikiagoa bada (datalen), orduan funtzioak zero itzultzen du, datuak ez dira datuetara kopiatzen. Bestela, bufferean kokatutako tuplaren datuen kopia sekuentziala egiten da. Kopiatu ondoren, tupla ezabatzen da eta memoria askatzen da. Kopiatzea datuen byteak kopiatzen diren unean amaitzen da. Datu-bloke baten erdian tokia agortzen bada, mezu honetan, datu-blokea kopiatu gabeko gainerako zatira murriztuko da. Deitzen duzun hurrengoan, kopiatzen jarraituko da puntu honetatik.

Bufferean une honetan eskuragarri dagoen datu kopurua irakurtzea:

int ms_bufferizer_get_avail(MSBufferizer *obj); 

Eremua itzultzen du tamaina buffering.

Buffer-eko datuen zati bat baztertzea:

void ms_bufferizer_skip_bytes(MSBufferizer *obj, int bytes);

Zehaztutako datuen byte kopurua berreskuratzen eta baztertzen da. Datu zaharrenak baztertu egiten dira.

Buffer-eko mezu guztiak ezabatzen:

void ms_bufferizer_flush(MSBufferizer *obj); 

Datu-kontagailua zerora berrezarri da.

Buffer-eko mezu guztiak ezabatzen:

void ms_bufferizer_uninit(MSBufferizer *obj); 

Kontadorea ez da berrezarri.

Buffer-a kendu eta memoria askatu:

void ms_bufferizer_destroy(MSBufferizer *obj);  

Bufferer-a erabiltzeko adibideak hainbat multimedia-streamer-iragazkiren iturburu-kodean aurki daitezke. Adibidez, MS_L16_ENC iragazkia, sareko ordenatik ostalariaren ordenara laginetako byteak berrantolatzen dituena: l16.c

Hurrengo artikuluan, ticker baten karga kalkulatzeko eta multimedia-streamer batean gehiegizko informatika-kargari aurre egiteko moduak aztertuko ditugu.

Iturria: www.habr.com

Gehitu iruzkin berria