Uurime VoIP mootorit Mediastreamer2. Osa 11

Artikli materjal on saadud minu Dzen-kanalist.

Uurime VoIP mootorit Mediastreamer2. Osa 11

Andmete ĂŒlekande mehhanism

  • Andmeplokk dblk_t
  • SĂ”num mblk_t
  • SĂ”numitega töötamise funktsioonid mblk_t
  • JĂ€rjekord queue_t
  • JĂ€rjekordadega töötamise funktsioonid queue_t
  • Filterite ĂŒhendamine
  • Signaalipunkt andmeprotsessi graafikus
  • Tickere kulisside tegevus
  • MĂ€buffer (MSBufferizer)
  • MSBufferizeriga töötamise funktsioonid

Eelmisel artiklis Oleme arendanud oma filtri. Selle artikli pĂŒhendame meedia edastusfiltrite vaheliste andmete ĂŒlekande sisemiste mehhanismide seadmele. See vĂ”imaldab tulevikus kirjutada keerukaid filtreid vĂ€iksema vaevaga.

Andmete ĂŒlekande mehhanism

Andmete ĂŒlekande protsess meedia edastusfiltris toimub jĂ€rjekordade abil, mille struktuuri kirjeldatakse queue_t. JĂ€rjekordades liigutatakse sĂ”numite jadad, mis on tĂŒĂŒbi mblk_t, mis ise ei sisaldanud signaalide andmeid, vaid ainult viite eelnenud ja jĂ€rgmise sĂ”numi ja andmeploki juurde. Lisaks tahan eraldi rĂ”hutada, et on olemas ka vĂ€li sama tĂŒĂŒpi sĂ”numite viitamiseks, mis vĂ”imaldab korraldada seotud sĂ”numite nimekirja. Kogumit sĂ”numeid, mis on sellesse nimekirja koondunud, nimetame tupleks. Seega vĂ”ib iga elemendi jĂ€rjekorras olla kas ĂŒksik sĂ”num mblk_t, vĂ”i tuple sĂ”numite pea mblk_t. Igal tuple sĂ”numil vĂ”ib olla oma seotud andmeplokk. Miks me vajame tupleid, arutame veidi hiljem.

Nagu eespool mainitud, ei sisalda sĂ”num ise andmeplokki, vaid sisaldab ainult viidat mĂ€lu alale, kus andmeplokk asub. Selles osas meenutab meedia edastusfiltri töö ĂŒldine pilt multika 'Koletiste korporatsioon' uksehoidjate ladustamist, kus uksed (andmete viidatud — ruumid) liiguvad meeletu kiirusel rippkonveieridel, samas kui toad ise jÀÀvad paigale.

NĂŒĂŒd, liikudes hierarhias alt ĂŒles, vaatame lĂ€hemalt andmete edastamise mehhanismis loetletud ĂŒksusi meedia edastusfiltris.

Andmeplokk dblk_t

Andmeplokk koosneb pÀisest ja andmebufferist. Pealkiri mÀÀratletakse jÀrgmise struktuuri abil,

typedef struct datab
{
unsigned char *db_base; // Viidatud andmebufferi algus.
unsigned char *db_lim;  // Viidatud andmebufferi lÔpp.
void (*db_freefn)(void*); // Funktsioon mÀlu vabastamiseks ploki kustutamisel.
int db_ref; // Viidete loendur.
} dblk_t;

Struktuuri valdkonnad sisaldavad viiteid puutöö algusele, puutöö lĂ”ppule ja andmete puhastamise funktsiooni. Peamine element on pealkirjas db_ref — viidete loendur, kui see jĂ”uab nullini, on see signaal, et see plokk tuleks mĂ€lust eemaldada. Kui andmeplokk loodi funktsiooni datab_alloc() , siis andmepuhver paigutatakse mĂ€llu kohe pealkirja jĂ€rele. KĂ”igil muudel juhtudel vĂ”ib puhver asuda kuskil eraldi. Andmepuhvrisse paigutatakse signaali andmed vĂ”i muud andmed, mida soovime filtreerimisega töödelda.

Uus andmeploki eksemplar luuakse funktsiooni abil:

dblk_t *datab_alloc(int size);

Sisendparameetrina edastatakse sellele andmete suurus, mida plokk talletab. MĂ€lu eraldatakse rohkem, et eraldatud mĂ€lu algusesse paigutada pealkiri — struktuur datab. Kuid teiste funktsioonide kasutamisel ei pruugi see alati nii olla, mĂ”nel juhul vĂ”ib andmepuhver asuda eraldi andmeploki pealkirjast. Struktuuri vĂ€ljad seadistatakse loomisel nii, et tema vĂ€li db_base osutaks andmeala algusele ja db_lim tema lĂ”ppu. Viidete loendur db_ref seatakse ĂŒhele. Andmete puhastamise funktsiooni viidatakse nulli.

Teade mblk_t

Nagu öeldud, jĂ€rjekorra elemendid on tĂŒĂŒpi mblk_t, see on mÀÀratletud jĂ€rgmiselt:

typedef struct msgb
{
  struct msgb *b_prev;   // Viidatud eelmine elemendi nimekiri.
  struct msgb *b_next;   // Viidatud jÀrgmine elemendi nimekiri.
  struct msgb *b_cont;   // Viidatud, et kleepida teistele sÔnumitele, et luua sÔnumite kombinatsioon.
  struct datab *b_datap; // Viidatud andmeploki struktuurile.
  unsigned char *b_rptr; // Viidatud andmeala algusele andmete lugemiseks b_datap puhvrist.
  unsigned char *b_wptr; // Viidatud andmeala algusele andmete salvestamiseks b_datap puhvrist.
  uint32_t reserved1;    // Reserveeritud vÀli1, meedia voogedastaja paigutab sinna teenuseinformatsiooni. 
  uint32_t reserved2;    // Reserveeritud vÀli2, meedia voogedastaja paigutab sinna teenuseinformatsiooni.
  #if defined(ORTP_TIMESTAMP)
  struct timeval timestamp;
  #endif
  ortp_recv_addr_t recv_addr;
} mblk_t;

Struktuur mblk_t alguses sisaldab viidatud b_prev, b_next, mis on vajalikud kahekordse lingi loomiseks (milleks on jÀrjekord queue_t).

SeejÀrel tuleb viidatud b_cont, mis seda kasutatakse ainult siis, kui sÔnum siseneb tuplesse. Viimase sÔnumi jaoks tuples jÀÀb viitamine nulliks.

JÀrgmisena nÀeme viidet andmeblokkile b_datap, mille tÔttu ja eksisteerib sÔnum. Selle jÀrel tulevad viidatud blokkide andmebufferi sees. VÀlja b_rptr nÀitab kohta, kust andmed luetakse bufferist. VÀlja b_wptr nÀitab kohta, kust andmed kirjutatakse bufferisse.

ÜlejÀÀnud vĂ€ljad on teenuslikud ja ei seostu andmete edastamise mehhanismi toimingutega.

Allpool on nĂ€idatud ĂŒksik sĂ”num nimega m1 ja andmeblokk d1.
Uurime VoIP mootorit Mediastreamer2. Osa 11
JÀrgmises joonises on kujutatud kolme sÔnumi tupliku m1, m1_1, m1_2.
Uurime VoIP mootorit Mediastreamer2. Osa 11

SÔnumite töötlemise funktsioonid mblk_t

Uus sÔnum mblk_t loodakse funktsiooni abil:

mblk_t *allocb(int size, int pri); 

see allotab mĂ€lus uue sĂ”numi mblk_t mooduliga, mille andmeblokki suurus on size, teine argument — pri ei kasutata antud teegi versioonis. See peab jÀÀma nulliks. Funktsiooni töö kĂ€igus eraldatakse mĂ€lu uue sĂ”numi struktuuri jaoks ja kutsutakse vĂ€lja funktsioon mblk_init(), mis nullib kĂ”ik loodud struktuuri vĂ€ljad ja seejĂ€rel, kasutades eelpool mainitud, datab_alloc()loob andmebufferi. PĂ€rast seda seadistatakse vĂ€ljad struktuuris:

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

VĂ€ljundina saame uue sĂ”numi initsialiseeritud vĂ€ljade ja tĂŒhja andmebufferiga. Andmete lisamiseks sĂ”numisse tuleb nad kopeerida andmebloki bufferisse:

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

kus data — viit andmeallikale, ja size — nende suurus.
siis tuleb uuendada kirjutamise viit, et see osutaks taas vaba ala algusele bufferis:

msg->b_wptr = msg->b_wptr + size

Kui on vaja luua sÔnum juba olemasolevast bufferist, ilma kopeerimiseta, siis selleks kasutatakse funktsiooni:

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

Funktsioon seadistab pÀrast sÔnumi ja andmebloki struktuuri loomist selle viidete andmed aadressil buf. St. sel juhul ei asu andmebuffer headeri vÀljade jÀrel, nagu see oli andmebloki loomisel funktsiooni abil. datab_alloc()KÀivitatud funktsioonile edastatud andmepuhver jÀÀb sinna, kus ta oli, kuid nÀidikute abil suunatakse see just loodud andmeploki pÀisele, mis omakorda suunatakse sÔnumile.

Ühe sĂ”numiga mblk_t vĂ”ib jĂ€rjestikku liita mitu andmeplokki. Seda teeb funktsioon:

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

mp — sĂ”num, millele lisatakse veel ĂŒks andmeplokk;
data — nĂ€idik plokile, mille koopia lisatakse sĂ”numisse;
size — andmete suurus;
pad — lipp, et mÀÀratud mĂ€luruumi suurus peaks olema jagatav 4 baidi piiriga (tĂ€iendamine toimub nullidega).

Kui olemasolevas sÔnumi andmepuhveres on piisavalt ruumi, siis uued andmed liidetakse seal juba olevatele andmetele. Kui sÔnumi andmepuvris on vÀhem ruumi kui size, siis luuakse uus sÔnum, millel on piisava suurusega puhver ja andmed kopeeritakse selle puhpvrisse. See uus sÔnum kinnitatakse algsega nÀidiku abil b_cont. Sel juhul muutub sÔnum tupleks.

Kui tuplekusse tuleb lisada veel ĂŒks andmeplokk, tuleb kasutada funktsiooni:

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

see leiab tuple lÔpus oleva viimase sÔnumi (tal b_cont on null) ja kutsub selle sÔnumi jaoks vÀlja funktsiooni appendb().

Andmete suurust sÔnumis vÔi tupleksis saab teada funktsiooni abil:

int msgdsize(const mblk_t *mp);

see lÀbib kÔik tuple sÔnumid ja tagastab andmete koguhulga nende sÔnumite andmepuvrites. Iga sÔnumi andmete hulga arvutamine toimub nii:

 mp->b_wptr - mp->b_rptr

Kaks tuplekust ĂŒhendamiseks kasutatakse funktsiooni:

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

see liidab tuple newm tuple lÔppu mp ja tagastab nÀidiku saadud tuple viimasele sÔnumile.

Kui on vajalik, vĂ”ib tuple muundada ĂŒheks sĂ”numiks ĂŒhe andmeplokiga, seda teeb funktsioon:

void msgpullup(mblk_t *mp,int len);

kui argument len on -1, siis mÀÀratakse eraldatud puhvri suurus automaatselt. Kui len Kui see on positiivne number, luuakse selle suuruse puhver ja sinna kopeeritakse sĂ”numite tupikandja andmed. Kui puhver tĂ€itub, siis kopeerimine lĂ”petatakse. Esimene tupikusĂ”num saab uue suurusega puhvri koos kopeeritud andmetega. ÜlejÀÀnud sĂ”numid kustutatakse ja mĂ€lu tagastatakse kuhja.

Struktuuri eemaldamisel mblk_t arvestatakse andmeploki viidete loendit, kui kutse ajal freeb() on see null, siis andmepuhver eemaldatakse koos eksemplariga mblk_t, millele see viitab.

Uue sÔnumi vÀljade initsialiseerimine:

void mblk_init(mblk_t *mp);

Andmete lisamine sÔnumile:

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

Kui uued andmed ei mahu sÔnumi andmepuhvri vabasse ruumi, lisatakse sÔnumile eraldi loodud sÔnum soovitud suurusega puhvri jaoks (esimeses sÔnumis mÀÀratakse viit lisatud sÔnumile) ja sÔnum muutub tupikuks.

Andmete lisamine tupikusse:

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

Funktsioon kutsub appendb() tsĂŒklis.

Kahte tupikut liitmine ĂŒheks:

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

Teade newm seda lisatakse mp.

Ühe sĂ”numi koopia loomine:

mblk_t *copyb(const mblk_t *mp);

Terve tupiku tÀielik kopeerimine koos kÔikide andmeplokkidega:

mblk_t *copymsg(const mblk_t *mp);

Tupiku elemendid kopeeritakse funktsiooni copyb().

Kerge koopia loomine sÔnumist. mblk_tSiinjuures andmeplokk ei kopeerita, vaid selle viidete loend suurendab. db_ref:

mblk_t *dupb(mblk_t *mp);

Kerge koopia loomine tupikust. Andmeplokke ei kopeerita, ainult nende viidete loendid suurenevad. db_ref:

mblk_t *dupmsg(mblk_t* m);

KĂ”ikide tupiku sĂ”numite liitmine ĂŒheks sĂ”numiks:

void msgpullup(mblk_t *mp,size_t len);

Kui argument len on -1, siis mÀÀratakse puhvri suurus automaatselt.

SÔnumi, tupiku eemaldamine:

void freemsg(mblk_t *mp);

Andmeploki viidete loend vĂ€heneb ĂŒhe vĂ”rra. Kui see saavutab nulli, eemaldatakse ka andmeplokk.

SÔnumi vÔi tupiku andmemahtude koguse arvutamine.

size_t msgdsize(const mblk_t *mp);

SÔnumi eemaldamine rea sabast:

mblk_t *ms_queue_peek_last (q);

Ühe sĂ”numi reserveeritud vĂ€ljade sisu kopeerimine teise sĂ”numisse (neis vĂ€ljad on tĂ”eliselt lipud, mida meediavooluote kasutab):

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

JĂ€rjekord queue_t

SÔnumite jÀrjekord meediastreamer'is on teostatud kui ringikujuline kahekordne seotud loend. Iga loendi element sisaldab nÀidikut andm blokkide kohta signaali nÀidudega. Tulemuseks on see, et liigutatakse ainult viiteid andm blokkidele, samas kui andmed jÀÀvad liikumatuks. St. liiguvad ainult viidatud.
JĂ€rjekorra struktuur queue_t, on toodud allpool:

typedef struct _queue
{
   mblk_t _q_stopper; /* "TĂŒhi" jĂ€rjekorra element, mis ei viita andmetele, kasutatakse ainult jĂ€rjekorra haldamiseks. JĂ€rjekorra algatamisel (qinit()) seadistatakse selle viidatud nii, et need osutavad sellele endast. */
   int q_mcount;        // Elementide arv jÀrjekorras.
} queue_t;

Struktuur sisaldab vĂ€lja - viidatud _q_stopper tĂŒĂŒbist *mblk_t, mis osutab esimesele elemendile (sĂ”numile) jĂ€rjekorras. Struktuuri teine vĂ€li on sĂ”numite loendur, mis asub jĂ€rjekorras.
Alloleval joonisel on kujutatud jÀrjekord nimega q1, mis sisaldab 4 sÔnumit m1, m2, m3, m4.
Uurime VoIP mootorit Mediastreamer2. Osa 11
JÀrgmises joonises on kujutatud jÀrjekord nimega q1, mis sisaldab 4 sÔnumit m1, m2, m3, m4. SÔnum m2 on paarituse pea, kuhu sisenevad veel kaks sÔnumit m2_1 ja m2_2.

Uurime VoIP mootorit Mediastreamer2. Osa 11

JÀrjekordadega töötamise funktsioonid queue_t

JĂ€rjekorra algatamine:

void qinit(queue_t *q);

VÀli _q_stopper (edaspidi nimetame seda "peatus") algatatakse funktsiooni kaudu mblk_init(), tema eelmine ja jÀrgmine elemendi viidatud seadistatakse nii, et nad osutavad sellele endale. JÀrjekorra elementide loendur nullitakse.

Uue elemendi (sÔnumi) lisamine:

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

Uus element m lisatakse loendi lÔppu, elemendi viidatud seadistatakse nii, et peatus muutub selle jÀrgneks elemendiks ja tema jaoks peatus eelneks. JÀrjekorra elementide loendurit suurendatakse.

Elemendi eemaldamine jÀrjekorrast:

mblk_t * getq(queue_t *q); 

eemaldatakse see sÔnum, mis on peatusest jÀrgmine, jÀrjekorra elementide loendurit vÀhendatakse. Kui jÀrjekorras, peale peatuse, elemente pole, tagastatakse 0.

SÔnumi sisestamine jÀrjekorda:

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

Element mp sisestatakse enne elementi emp. Kui emp=0, siis sÔnum lisatakse jÀrjekorra sabasse.

SÔnumi eemaldamine jÀrjekorra peast:

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

Elementide loendurit vÀhendatakse.

Viidatud esimesele elemendile jÀrjekorras:

mblk_t * peekq(queue_t *q); 

KĂŒsimise kĂ”ikide elementide eemaldamine jĂ€rjekorrast koos elementide eemaldamisega:

void flushq(queue_t *q, int how);

Argumendiks how ei kasutata. Ooteelemendi arv loenduri seadistamine toimub nulli.

Makro lugemisnÀitaja viimase ooteelemendi jaoks:

mblk_t * qlast(queue_t *q);

Kasutades sÔnumi jÀrjekordi, tuleb meeles pidada, et kutsudes ms_queue_put(q, m) nullnÀidikuga sÔnumile, sumbub funktsioon. Teie programm hangub. Samuti kÀitub ms_queue_next(q, m).

Filterite ĂŒhendamine

Ülaltoodud jĂ€rjekord kasutatakse sĂ”numite edastamiseks ĂŒhelt filtrilt teisele vĂ”i ĂŒhelt mitmele filtrile. Filtrid ja nende ĂŒhendused omavahel moodustavad suunatud graafi. Filtri sisendit vĂ”i vĂ€ljundit nimetatakse ĂŒldiselt "pin". Filtritevahelise ĂŒhenduse jĂ€rjekorra kirjeldamiseks kasutatakse meediastreameris mĂ”istet "signaalpunkt". Signaalpunkt on struktuur _MSCPoint, mis sisaldab nĂ€idikut filtrile ja numbri ĂŒhe oma pin'ist, seega kirjeldab see ĂŒhe filtri sisendi vĂ”i vĂ€ljundi ĂŒhendust.

Signaalipunkt andmeprotsessi graafikus

typedef struct _MSCPoint{
struct _MSFilter *filter; // NĂ€idik meediastreameri filtrile.
int pin;                        // Ühe filtri sisendi vĂ”i vĂ€ljundi number, st pin.
} MSCPoint;

Filtri pins on nummerdatud alates nullist.

Kahte pinni ĂŒhendav sĂ”numijĂ€rjekord on kirjeldatud struktuuris _MSQueue, mis sisaldab sĂ”numijĂ€rjekorda ja nĂ€idikuid kahe signaalpunkti vahel, mida see ĂŒhendab:

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

Kutsume seda struktuuri signaallingiks. Igal meediastreameri filtril on sisendi linkide tabel ja vĂ€ljundi linkide tabel (MSQueue). Tabelite suurus mÀÀratakse filtri loomisel, seda oleme juba teinud eksporditud muutuja tĂŒĂŒbi abil MSFilterDesc, kui töötasime vĂ€lja oma filtri. Allpool on toodud struktuur, mis kirjeldab igat filtrit meediastreameris, MSFilter:


struct _MSFilter{
    MSFilterDesc *desc;    
    /* NĂ€idik filtrile. */
    /* Kaitstud atribuudid, neid ei tohi nihutada ega eemaldada, vastasel juhul lakkab pluginatega töötamine. */
    ms_mutex_t lock;      /* Semafor. */
    MSQueue **inputs;     /* SissepÀÀsude lingid. */
    MSQueue **outputs;    /* VĂ€ljundite lingid. */
    struct _MSFactory *factory; /* NÀidik tehasele, mis lÔi selle filtrite jÀlje. */
    void *padding;              /* Mitte kasutatav, kasutatakse, kui lisatakse kaitstud vÀljad. */
    void *data;                 /* NĂ€idik suvalisele struktuurile filtrite sisemise oleku ja vahepealsete arvutuste andmete hoidmiseks. */
    struct _MSTicker *ticker;   /* NÀidik tikker-objektile, mis ei tohi olla null, kui kutsutakse vÀlja funktsiooni process(). */
    /*privaatsed atribuudid, neid saab igal ajal nihutada ja muuta*/
    MSList *notify_callbacks; /* Tagasiside nimekiri, mida kasutatakse filtrite sĂŒndmuste töötlemiseks. */
    uint32_t last_tick;       /* Viimane takti number, mil process() funktsiooni kutsuti. */
    MSFilterStats *stats;     /* Filtri tööstatistika.*/
    int postponed_task; /*Õhtukeelustatud ĂŒlesannete arv. MĂ”ned filtrid vĂ”ivad edasilĂŒkata andmete töötlemist (process() funktsiooni kutse) mitmeks taktimiseks.*/
    bool_t seen;  /* Lipp, mida tikker kasutab, et tÀhistada, et see filtrite jÀlgimine on selle takti jooksul möödunud.*/
};
typedef struct _MSFilter MSFilter;

PĂ€rast seda, kui oleme C-programmis filtrid vastavalt meie kavandile kokku ĂŒhendanud (kuid tikkerit ei ole ĂŒhendatud), oleme loonud suunatud graafi, mille sĂ”lmed on struktuuri eksemplarid MSFilter, ja servad on lingi eksemplarid MSQueue.

Tickere kulisside tegevus

Kui ma ĂŒtlesin, et tikker on taktimine filtri allikas, siis see polnud kogu tĂ”de tema kohta. Tikker on objekt, mis kĂ€ivitab funktsioone vastavalt kellale process() kĂ”ikide filtrite skeemi (graafi) kohta, kuhu ta on ĂŒhendatud. Kui me C-programmis ĂŒhendame tikkeri graafi filtriga, nĂ€itame tikkerile graafi, mida ta hakkab haldama, kuni me ta lahti ĂŒhendame. PĂ€rast ĂŒhendamist hakkab tikker vaatama temale usaldatud graafi, koostades nimekirja filtritest, kuhu ta kuulub. Et mitte "loendada" sama filtrit kaks korda, mĂ€rgib ta kindlaks leitud filtrid, seades neisse lipu seen. Otsing toimub iga filtri lingi tabelite kaudu.

Ekskursiooni ajal kontrollib ticker, kas filtrite seas on vĂ€hemalt ĂŒks, mis tĂ€idab andmeplokkide allika rolli. Kui selliseid ei leidu, tunnistatakse graaf vÀÀraks ja ticker lĂ”petab töö.

Kui graaf osutub "Ă”igeks", kutsutakse iga leitud filtri jaoks initsialiseerimiseks vĂ€lja funktsioon preprocess(). Kui tuleb aeg jĂ€rgmise töötlemise tsĂŒkli jaoks (vaikimisi iga 10 millisecondi jĂ€rel), kutsub ticker vĂ€lja funktsiooni process() kĂ”igi varem leitud allikafilterite jaoks ning seejĂ€rel ka ĂŒlejÀÀnud filtrite loendis. Kui filtril on sisendlingid, siis kĂ€ivitatakse funktsioon process() uuesti, kuni sisendlinkide jĂ€rjekorrad on tĂŒhjad. PĂ€rast seda liigub ta jĂ€rgmise filtri juurde loendis ja "kerib" selle, kuni sĂ”numid on sisendlinkidelt vabastatud. Ticker liigub filtrilt filtrile, kuni loend lĂ”ppeb. Sellega lĂ”peb tsĂŒkli töötlemine.

NĂŒĂŒd pöördume tupikute juurde ja rÀÀgime, miks on meediastreamerisse lisatud selline entiteet. Üldiselt ei ĂŒhti ja ei ole proportsionaalne algoritmi jaoks vajalik andmemahu suurus, mis töötab filtris, sisenevate andmebufferite suurusega. NĂ€iteks kirjutame filtri, mis teostab kiire Fourier' transformatsiooni, mis definitsiooni kohaselt suudab töödelda ainult andmeplokke, mille suurus on kahe astme. Olgu see 512 nĂ€idust. Kui andmed genereeritakse telefoniĂŒhenduse kaudu, toob iga sĂ”numi sisenemise buffer andmed meile 160 nĂ€idust signaalist. On kiusatus mitte vĂ”tta andmeid sisse, kuni vajalik andmemahu hulk on tĂ€is. Kuid sel juhul tekib konflikt tickeriga, mis ĂŒritab tulutult kerida filtrit, kuni sisendlink on tĂŒhjendatud. Oleme varem mÀÀratlenud selle reegli kui filtri töö kolmanda pĂ”himĂ”tte. Selle pĂ”himĂ”tte kohaselt peab filtri funktsioon process() vĂ”tma kĂ”ik andmed sisendjoontest.

Lisaks ei saa sissevoolust vĂ”tta ainult 512 arvestust, kuna neid vĂ”ib vĂ”tta ainult tĂ€isarvudena, st filter peab vĂ”tma 640 arvestust ja kasutades neist 512, jÀÀb ĂŒlejÀÀk uue andmepartiini kogumiseks. Seega peab meie filter, peale oma pĂ”hifunktsioonide, tagama ka abitegevused sisendandmete vahepealseks salvestamiseks. Meediavoodetootjate lahenduste jaoks selle ĂŒldise ĂŒlesande tĂ€itmiseks on vĂ€lja töötatud spetsiaalne objekt - MSBufferizer (puhvritaja), mis lahendab selle ĂŒlesande kasutades tuplette.

MĂ€buffer (MSBufferizer)

See on objekt, mis kogub sisendandmeid filtri sees ja hakkab neid töötlemiseks andma, kui informatsiooni kogus on piisav filtri algoritmi kĂ€ivitamiseks. Seni, kuni puhvritaja kogub andmeid, töötab filter tĂŒhja reĆŸiimis, mitte raisates protsessori arvutusvĂ”imet. Kuid niipea kui funktsioon, mis loeb puhvritajast, tagastab vÀÀrtuse, mis ei ole null, alustab filtri process() funktsioon ekraanilolliste andmete kogumist ja töötlemist tĂ€pses koguses kuni nende lĂ”ppemiseni.
Kasutamata andmed jÀÀvad puhvritajas esimeseks elementiks tupletes, kuhu kinnitatakse jÀrgmised sisendandmeplokid.

Struktuur, mis kirjeldab puhvritajat:

struct _MSBufferizer{
queue_t q; /* Teate jÀrjekord. */
int size; /* Kokku andmete suurus, mis asub praegu puhvritajas. */
};
typedef struct _MSBufferizer MSBufferizer;

MSBufferizeriga töötamise funktsioonid

Uue puhvritaja eksemplari loomine:

MSBufferizer * ms_bufferizer_new(void);

MĂ€lu eraldatakse, initsialiseeritakse ms_bufferizer_init() ja tagastatakse osuti.

Initsialiseerimise funktsioon:

void ms_bufferizer_init(MSBufferizer *obj); 

Initsialiseeritakse jÀrjekord q, vÀli size seadistatakse nulliks.

Teate lisamine:

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

Teade m lisatakse jÀrjekorda. Arvutatud plokkide andmete suurus lisatakse size.

KÔik teated, mis on jÀrjekorras andmelingis, ummistuvad puhvritajasse q:

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

Teate edastamine lingist q puhvritajasse toimub funktsiooni kaudu ms_bufferizer_put().

Lugemine puhvritajast:

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

Kui puhvritajasse kogutud andmete suurus on vÀiksem kui nÔutud (datalen), siis funktsioon tagastab null, andmete kopeerimine data ei toimu. Vastupidisel juhul toimub jÀrjestikune andmete kopeerimine puhvrisse salvestatud tuple'itest. PÀrast kopeerimist eemaldatakse tuple ja mÀlu vabastatakse. Kopeerimine lÔppeb hetkel, kui on kopeeritud datalen bait'i. Kui koht lÔppeb andmeploki keskel, siis piiratakse selle sÔnumi andmeplokk jÀrelejÀÀnud kopeerimata osani. JÀrgmise kutse ajal jÀtkatakse kopeerimist sellest kohast.

Andmete hulga lugemine, mis on praegu puhvris saadaval:

int ms_bufferizer_get_avail(MSBufferizer *obj); 

Tagastab valdkonna size puhvrisse.

Puhvri andmete osa mahaviskamine:

void ms_bufferizer_skip_bytes(MSBufferizer *obj, int bytes);

MÀÀratud hulga baite andmeid eemaldatakse ja mahaviskatakse. Mahaviskamine toimub vanematest andmetest.

Kogu puhvris olevate sÔnumite eemaldamine:

void ms_bufferizer_flush(MSBufferizer *obj); 

Andmete loendur lÀhtestatakse nulli.

Kogu puhvris olevate sÔnumite eemaldamine:

void ms_bufferizer_uninit(MSBufferizer *obj); 

Loenduri nullimist ei toimu.

Puhvri eemaldamine ja mÀlu vabastamine:

void ms_bufferizer_destroy(MSBufferizer *obj);  

Puhvrile kasutamise nĂ€iteid vĂ”ib leida mitmest meediastrimmeri filtri lĂ€htekoodist. NĂ€iteks filtris MS_L16_ENC, mis teostab baitide ĂŒmberkorraldamist vĂ”rgujĂ€rjekorrast hosti jĂ€rjestusse: l16.c

JĂ€rgmises artiklis kĂ€sitleme koormuse hindamise kĂŒsimust tickeril ja viise, kuidas vĂ€ltida ĂŒlemÀÀrast arvutuskoormust meediastrimmeris.

Allikas: habr.com

Osta usaldusvÀÀrne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid đŸ”„ Osta usaldusvÀÀrne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid | ProHoster