Artikli sisu on pÀrit minu .

Andmete liikumismehhanism
- 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
- Filtrite ĂŒhendamine
- Andmete töötlemise graafi signaalpunkt
- Tickere tagumine tegevus
- VahemÀlu (MSBufferizer)
- MSBufferizeri töötamise funktsioonid
Eelmises osas Oleme vĂ€lja töötanud oma filtri. Selles artiklis pĂŒhendame tĂ€helepanu andmete liikumismehhanismi sisesele ehitusele, mis toimub meediastreameri filtrite vahel. See vĂ”imaldab tulevikus kirjutada keerukamaid filtreid vĂ€iksema vaevaga.
Andmete liikumismehhanism
Andmete liikumine meediastreameris toimub kirjeldatud struktuuri kaudu queue_t. Andmete liikumine toimub sĂ”numite jada kaudu, mille tĂŒĂŒp on mblk_t, mis ei sisalda enda sees signaali andmeid, vaid ainult lingid eelmise, jĂ€rgmise sĂ”numi ja andmeploki peale. Lisaks tahan rĂ”hutada, et on olemas ka vĂ€li, mis viitab sama tĂŒĂŒpi sĂ”numile, mis vĂ”imaldab korraldada sĂ”numite ĂŒhekordset loetelu. SĂ”numite rĂŒhma, mida ĂŒhendab see loetelu, nimetame kimpuks. Seega vĂ”ib iga jĂ€rjekorra element olla kas ĂŒksik sĂ”num mblk_t, vĂ”i kimpude pea mblk_t. Igal kimpude sĂ”numil vĂ”ib olla oma andmeplokk. Miks on kimbud vajalikud, arutame hiljem.
Nagu eespool mainitud, ei sisalda sĂ”num ise andmeplokki, vaid sisaldab ainult nĂ€idikut mĂ€lupiirkonnas, kus andmeplokk asub. Selles osas sarnaneb meediastreameri toimimise ĂŒldine pilt Disney animatsiooniga "Koletiste ettevĂ”te", kus uksed (andmete lingid â ruumid) liiguvad hullumeelse kiiruseni ĂŒles riputatud konveierite kaudu, samas kui ruumid ise jÀÀvad paigale.
NĂŒĂŒd, liikumine alt ĂŒlesse, vaatame ĂŒksikasjalikult meediastreameris andmete edastamise mehhanismi elemente.
Andmeplokk dblk_t
Andmeplokk koosneb pÀisest ja andmevahemikust. Pealkiri on kirjeldatud jÀrgmise struktuuriga:
typedef struct datab
{
unsigned char *db_base; // NĂ€idik andmevahemiku algusele.
unsigned char *db_lim; // NÀidik andmevahemiku lÔpule.
void (*db_freefn)(void*); // MĂ€lua vabastamise funktsioon ploki eemaldamisel.
int db_ref; // Viidete loendur.
} dblk_t;Struktuuri vĂ€ljad sisaldavad nĂ€idikuid andmevahemiku algusele, lĂ”ppu, andmevahemiku vabastamisefunktsiooni. Viimane element pealkirjas db_ref â viidete loendur, ja kui see jĂ”uab nulli, on see signaal andmeploki eemaldamiseks mĂ€lust. Kui andmeplokk loodi funktsiooni datab_alloc() , siis paigutatakse andmevahemik mĂ€llu vahetult pĂ€rast pealkirja. KĂ”igil muudel juhtudel vĂ”ib andmevahemik paikneda kuskil eraldi. Andmevahemikus asuvad signaali nĂ€idud vĂ”i muud andmed, mida soovime filtritega töödelda.
Uus andmeploki eksemplar luuakse jÀrgnevaga:
dblk_t *datab_alloc(int size);Sellele antakse sisendparameetrina andmete suurus, mida plokk hoiustab. MĂ€lu eraldatakse rohkem, et alguses eraldatud mĂ€lus asetada pealkiri â struktuur datab. Kuid teiste funktsioonide puhul ei toimu see alati, mĂ”ningatel juhtudel vĂ”ib andmevahemik asuda eraldi andmeplokist. Struktuuri vĂ€ljad luuakse selliselt, et selle vĂ€li db_base osutaks andmevahemiku algusele ja db_lim lĂ”pule. Viidete loendur db_ref seatakse ĂŒhte. Andmete puhastamise nĂ€idik seatakse nullile.
Teade mblk_t
Nagu juba öeldud, on jĂ€rjekorra elemendid tĂŒĂŒpi mblk_t, mille definirime jĂ€rgmiselt:
typedef struct msgb
{
struct msgb *b_prev; // NĂ€idik eelmisele loendi elemendile.
struct msgb *b_next; // NÀidik jÀrgmisele loendi elemendile.
struct msgb *b_cont; // NÀidik teiste sÔnumite lisamisest sÔnumile, kimpude loomiseks.
struct datab *b_datap; // NĂ€idik andmeploki struktuurile.
unsigned char *b_rptr; // NĂ€idik andmevahemiku algusele b_datap andmete lugemiseks.
unsigned char *b_wptr; // NĂ€idik andmevahemiku algusele b_datap andmete kirjutamiseks.
uint32_t reserved1; // Reserveeritud vÀli1, meediastreamer paneb sinna teenindusteabe.
uint32_t reserved2; // Reserveeritud vÀli2, meediastreamer paneb sinna teenindusteabe.
#if defined(ORTP_TIMESTAMP)
struct timeval timestamp;
#endif
ortp_recv_addr_t recv_addr;
} mblk_t;Struktuur mblk_t alguses sisaldab nÀidikud b_prev, b_next, mis on vajalikud kahekordse loendi korraldamiseks (millega on jÀrjekord queue_t).
SeejÀrel on nÀidik b_cont, mis kasutatakse ainult siis, kui sÔnum kuulub kimpude. Viimase sÔnumi puhul kimpude jÀÀb see nÀidik nulliks.
Edasi nÀeme nÀidiku andmeploki b_datap, mille, mille jaoks sÔnum eksisteerib. Selle jÀrel on nÀidikud andmebloki sisemisele andmepuhvrile. VÀli b_rptr osutab kohale, kust andmeid loetakse puhvrisse. VÀli b_wptr osutab kohale, kust andmeid kirjutatakse puhvrisse.
ĂlejÀÀnud vĂ€ljad on teenindava iseloomuga ja ei seondu andmete edastamise mehhanismiga.
Allpool on nĂ€idatud ĂŒhekordne sĂ”num nimega m1 ja andmeblokk d1.

JÀrgmises joonises on kujutatud kolme sÔnumi kopleksi m1, m1_1, m1_2.

SÔnumitega töötamise funktsioonid mblk_t
Uue sÔnumi mblk_t loob funktsioon:
mblk_t *allocb(int size, int pri); see eraldab mĂ€lus uue sĂ”numi mblk_t nĂ€idatud suurusega andmebloki. sizeTeine argument â pri ei kasutata arutatava versiooni raamatukogus. See peaks jÀÀma nulliks. Funktsiooni töös eraldatakse mĂ€lu uue sĂ”numi struktuuri jaoks ja kutsutakse vĂ€lja funktsioon mblk_init(), mis nullib loodud struktuuri kĂ”ik vĂ€ljad ja seejĂ€rel, eelnevalt mainitud, loob andmepuhvri. SeejĂ€rel seadistatakse struktuuri vĂ€ljad: datab_alloc()mp->b_datap=datab; mp->b_rptr=mp->b_wptr=datab->db_base; mp->b_next=mp->b_prev=mp->b_cont=NULL;
Saame vĂ€lja uue sĂ”numi alginitseeritud vĂ€ljadega ja tĂŒhja andmepuvriga. Andmete lisamiseks sĂ”numisse tuleb need kopeerida andmebloki puhvrisse:memcpy(msg->b_rptr, data, size);
â nĂ€itaja andmeallikale, jakus data â nende suurus. size jĂ€rel tuleb uuendada kirjutamiskoha nĂ€itajat, et see nĂ€itaks jĂ€lle vaba ala algusesse puhvrisse:
msg->b_wptr = msg->b_wptr + size
Kui on vajalik luua sÔnum juba olemasolevast puhvrist, ilma kopeerimiseta, siis kasutatakse selleks funktsiooni:mblk_t *esballoc(uint8_t *buf, int size, int pri, void (*freefn)(void*));
Funktsioon pĂ€rast sĂ”numi ja andmeploki struktuuri loomist seadistab andmete nĂ€itajad aadressile buf . St. sel juhul andmepuvr ei asu andmeploki pĂ€ise vĂ€ljade taga, nagu see oli andmeploki loomisel funktsiooni abil. Funktsioonile edastatud andmepuvr jÀÀb sinna, kus see oli, kuid nĂ€itajate kaudu suunatakse see just loodud andmeploki pĂ€isele, ja see vastavalt sĂ”numile. datab_alloc()Ăhele sĂ”numile
vÔivad jÀrjestikku kinnituda mitu andmeplokki. See toimub funktsiooni abil: mblk_t mblk_t * appendb(mblk_t *mp, const char *data, int size, bool_t pad);
mp â sĂ”num, millele lisatakse veel ĂŒks andmeplokk; â nĂ€itaja plokile, mille koopia lisatakse sĂ”numisse;
data â andmete suurus;
size pad
â lipp, et eraldatava mĂ€lu suurus peaks olema joondatud 4-baidise piiri jĂ€rgi (tĂ€iendamine toimub nullidega). Kui antud sĂ”numi andmepuvrisse on piisavalt ruumi, siis uued andmed kinnitatakse seal juba olemasolevate andmete taha. Kui sĂ”numi andmepuvrisse on ruumi vĂ€hem kui
, luuakse uus sĂ”num piisava suurusega puhvri jaoks ja andmed kopeeritakse selle puhvri sisse. See uus sĂ”num kinnitatakse algsele lĂ€bi nĂ€itaja size. Sel juhul muutub sĂ”num kopleksiks. b_contKui kopleksile on vaja lisada veel ĂŒks andmeplokk, siis tuleb kasutada funktsiooni:
void msgappend(mblk_t *mp, const char *data, int size, bool_t pad);
see otsib kopleksi viimast sÔnumit (sel onoleb null) ja kutsub sellele sÔnumile vÀlja funktsiooni b_cont appendb() Andmete suuruse mÀÀramine sÔnumis vÔi kopleksis toimub funktsiooni abil:.
int msgdsize(const mblk_t *mp);
see lÀbib kÔik kopleksi sÔnumid ja tagastab nende sÔnumite andmepuvirite kogusumma. Iga sÔnumi andmete maht arvutatakse jÀrgmiselt:mp->b_wptr - mp->b_rptr
Kahte kopleksi ĂŒhendamiseks kasutatakse funktsiooni:mblk_t *concatb(mblk_t *mp, mblk_t *newm);
see lisab kopleksinewm kopleksi lĂ”ppu ja tagastab nĂ€itaja saadud kopleksi viimasele sĂ”numile. â sĂ”num, millele lisatakse veel ĂŒks andmeplokk; Vajadusel vĂ”ib kopleksi muuta ĂŒheks sĂ”numiks, millel on ainus andmeplokk, milleks on funktsioon:
void msgpullup(mblk_t *mp,int len);
kui argumenton -1, siis mÀÀratakse andmepuhvri suurus automaatselt. Kui len on positiivne number, siis luuakse selle suurusega puhvri ja kopeeritakse kopleksi sĂ”numite andmed. Kui puhv tasuta lĂ”peb, siis kopeerimine peatub. Kopleksi esimene sĂ”num saab uue suurusega puhvri kopeeritud andmetega. ĂlejÀÀnud sĂ”numid kaovad ja mĂ€lu tagastatakse kuhja. len Struktuuri eemaldamisel
arvestatakse andmeploki viidete arvu, kui selle vÀÀrtus on vÀljundite kutsumise ajal mblk_t freeb() on null, siis eemaldatakse andmepuhver koos struktuuriga, mis sellele viitab. Uue sÔnumi vÀljade alginitseerimine: mblk_tvoid mblk_init(mblk_t *mp);
Andmete lisamine sĂ”numisse veel ĂŒhe portion:
void mblk_init(mblk_t *mp);SĂ”numile lisatakse veel ĂŒks andmeosa:
mblk_t * appendb(mblk_t *mp, const char *data, size_t size, bool_t pad);Kui uued andmed ei mahu teate andmebufferisse, siis lisatakse teatele eraldi loodud sÔnum, millel on vajalik suurus. (esimeses sÔnumis seadistatakse nÀitaja lisatud sÔnumile) sÔnum muutub tupiks.
Andmepartiis tupisse lisamine:
void msgappend(mblk_t *mp, const char *data, size_t size, bool_t pad); Funktsioon kutsub appendb() vĂ€lja tsĂŒklis.
Kahe tupiku ĂŒhendamine ĂŒheks:
see lisab kopleksiTeade kopleksi lĂ”ppu lisatakse â sĂ”num, millele lisatakse veel ĂŒks andmeplokk;.
Ăhe sĂ”numi koopia loomine:
mblk_t *copyb(const mblk_t *mp);Terve tupiku koopia koos kÔigi andmeblokidega:
mblk_t *copymsg(const mblk_t *mp);Tupiku elemendid kopeeritakse funktsiooni copyb().
Kerge sÔnumi koopia loomine mblk_t. Samal ajal andmeplokki ei kopeerita, vaid selle viidete arvu suurendatakse. db_ref:
mblk_t *dupb(mblk_t *mp);Kerge tupiku koopia loomine. Andmeblokke ei kopeerita, ainult nende viidete arvu suurendatakse. 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 argumendi len vÀÀrtus on -1, siis mÀÀratakse eraldatud bufferi suurus automaatselt.
SÔnumi, tupiku eemaldamine:
void freemsg(mblk_t *mp);Andmeploki viidete arv vĂ€heneb ĂŒhe vĂ”rra. Kui see saavutab nulli, siis eemaldatakse ka andmeplokk.
Teate vÔi tupiku andmete kogumahu arvestamine.
size_t msgdsize(const mblk_t *mp);SÔnumi vÀljavÔtmine jÀrjekorra sabast:
mblk_t *ms_queue_peek_last (q);Teise sÔnumi reservitud vÀljade sisu kopeerimine teise sÔnumisse (tÔepoolest sisaldavad need vÀljad mÀrke, mida meediavoog kasutab):
mblk_meta_copy(const mblk_t *source, mblk *dest);JĂ€rjekord queue_t
Meediavoogude sÔnumite jÀrjekord on rakendatud kui ringikujuline kahekordne lingitud loend. Iga loendi element sisaldab viidatud andmeplokki signaali nÀitudega. Seega liiguvad jÀrjekorras vaid viidatud andmeplokid, samas kui tegelikud andmed jÀÀvad liikumatuks. Ehkki liigutatakse ainult nende viiteid.
JÀrjekorra struktureerimine queue_t, nagu nÀidatud allpool:
typedef struct _queue
{
mblk_t _q_stopper; /* "TĂŒhi" jĂ€rjekorraelement, ei viita andmetele, kasutatakse ainult jĂ€rjekorra haldamiseks. JĂ€rjekorra initsialiseerimisel (qinit()) seadistatakse selle viidatud nii, et nad viitavad sellele endale. */
int q_mcount; // elementide arvu jÀrjekorras.
} queue_t;Struktuur sisaldab vĂ€lja - viidatud _q_stopper tĂŒĂŒpi *mblk_t, see viitab esimesele elemendile (sĂ”num) jĂ€rjekorras. Teine vĂ€lja struktuuris on sĂ”numite arv jĂ€rjekorras.
Alloleval joonisel on jÀrjekord nimega q1, mis sisaldab 4 sÔnumit m1,m2, m3, m4.

JÀrgmine joonis nÀitab jÀrjekorda nimega q1, mis sisaldab 4 sÔnumit m1,m2, m3, m4. SÔnum m2 on tupiku pea, kuhu viivad veel kaks sÔnumit m2_1 ja m2_2.

JÀrjekordadega töötamise funktsioonid queue_t
JĂ€rjekorra initsialiseerimine:
void qinit(queue_t *q);VÀli _q_stopper (edasi nimetame seda "stööriks") initsialiseeritakse funktsiooniga mblk_init(), mille eelmine element ja jÀrgmine element seadistatakse nii, et nad viitavad iseendale. JÀrjekorra elementide arvu loendit nullitakse.
Uue elementi (sÔnumi) lisamine:
void putq(queue_t *q, mblk_t *m);Uus element m lisatakse loendi lÔppu, elemendi nÀitajad seadistatakse nii, et stopp muutub selle jÀrgmiseks elemendiks ja tema eelmine element on stopp. JÀrjekorra elementide arvu suurendatakse.
Elemendi vÀlja tÔmbamine jÀrjekorrast:
mblk_t * getq(queue_t *q); vÀlja tÔmmatakse see sÔnum, mis on stoppist jÀrgmisel kohal, elemendi loendit vÀhendatakse. Kui jÀrjekorras pole muud elemente peale stoppi, siis tagastatakse 0.
SÔnumi jÀrjekorras sisestamine:
void insq(queue_t *q, mblk_t *emp, mblk_t *mp); Element â sĂ”num, millele lisatakse veel ĂŒks andmeplokk; sisestatakse elemendi 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); Elemendi loendit vÀhendatakse.
Viidatud esimese elemendi lugemine jÀrjekorras:
mblk_t * peekq(queue_t *q); KÔikide elementide eemaldamine jÀrjekorrast koos elementide enda eemaldamisega:
void flushq(queue_t *q, int how);Argument how ei kasutata. JĂ€rjekorra elementide arvu seadistatakse nulli.
Makro viidatud viimase jÀrjekorra elemendi lugemiseks:
mblk_t * qlast(queue_t *q);Teatestrateegiate tööpiirkondadega tuleb arvestada, et ms_queue_put(q, m) nullse nĂ€itajaga sĂ”numile kutse tsĂŒkeldub. Teie programm hangub. Sarnaselt kĂ€itub ms_queue_next(q, m).
Filtrite ĂŒhendamine
Ălaltoodud jĂ€rjekorda kasutatakse sĂ”numite edastamiseks ĂŒhest filtrist teise vĂ”i ĂŒhest mitmele filtrile. Filtrid ja nende ĂŒhendused loovad suunatud graafi. Filtri sisenemist vĂ”i vĂ€ljundit nimetame ĂŒldiselt "pin-ks". Filtrite omavahelise ĂŒhendamise jĂ€rjekorra kirjeldamiseks kasutatakse meediastrateegis mĂ”istet "signaalpunkt". Signaalpunkt on struktuur _MSCPoint, mis sisaldab viidatud filtrit ja ĂŒhe selle pin-i numbrit, kirjeldades seega ĂŒhendust ĂŒhe filtri sisendi vĂ”i vĂ€ljundi vahel.
Andmete töötlemise graafi signaalpunkt
typedef struct _MSCPoint{
struct _MSFilter *filter; // Viit filteri meediastrateegis.
int pin; // Ăhe filtrisisendi vĂ”i -vĂ€ljundi number, s.t. pin.
} MSCPoint;
Filtrite pinnad nummerdatakse alates nullist.
Kahte pin-i sĂ”numite jĂ€rjekorraga ĂŒhendust kirjeldab struktuur _MSQueue, mis sisaldab sĂ”numite jĂ€rjekorda ja viiteid kahe signaalpunkti vahel, mida see ĂŒhendab:
typedef struct _MSQueue
{
queue_t q;
MSCPoint prev;
MSCPoint next;
}MSQueue;
Kutsume seda struktuuri signaallinkiks. Igal meediastrateegifiltril on sisend- ja vĂ€ljundlinkide tabelid (MSQueue). Tabelite suurus mÀÀratakse filtri loomisel, mida me juba tegime eksportimise abil, kasutades muutujat tĂŒĂŒbi MSFilterDesc, kui arendasime oma filtrit. Allpool on nĂ€idatud struktuur, mis kirjeldab kĂ”iki filtreid meediastrateegis, MSFilter:
struct _MSFilter{
MSFilterDesc *desc; /* Viit filtri descriptor-ile. */
/* Kaitstud atribuudid, neid ei tohi nihutada vÔi eemaldada, muidu rikutakse pluginatega töötamist. */
ms_mutex_t lock; /* Semafor. */
MSQueue **inputs; /* Sisendlinkide tabel. */
MSQueue **outputs; /* VĂ€ljundlinkide tabel. */
struct _MSFactory *factory; /* Viit tehasele, mis lÔi antud filtrieksampli. */
void *padding; /* Ei kasutata, kasutatakse Àra, kui kaitstud vÀljad on lisatud. */
void *data; /* Viit suvalisele struktuurile filtri sisemise oleku ja vaheandmete salvestamiseks. */
struct _MSTicker *ticker; /* Viit ticker-erille, mis ei tohi olla null, kui kutsutakse funktsiooni process(). */
/* eraatribuudid, neid saab viia ja muuta igal ajal */
MSList *notify_callbacks; /* Tagasikutsumiste loend, mida kasutatakse filtri sĂŒndmuste töötlemiseks. */
uint32_t last_tick; /* Viimane tehke number, kui viidi lÀbi process() kutse. */
MSFilterStats *stats; /* Filtri tööstatistika. */
int postponed_task; /* EdasilĂŒkatud ĂŒlesannete arv. MĂ”ned filtrid vĂ”ivad edasilĂŒkata andmete töötlemist (process() kutse) mitme taktiga. */
bool_t seen; /* Lipp, mida ticker kasutab selleks, et tÀhistada, et antud filtri eksemplar on juba teenindatud antud taktiga. */
};
typedef struct _MSFilter MSFilter;
PĂ€rast seda, kui oleme C-programmis filtrid vastavalt meie kavandile kokku ĂŒhendanud (aga tickerit ei ĂŒhendanud), oleme loonud suunatud graafi, mille sĂ”lmed on struktuuri eksemplarid MSFilter, ning servad on linkide eksemplarid. MSQueue.
Tickere tagumine tegevus
Kui ĂŒtlesin teile, et ticker on taktiallikas, siis see ei olnud kogu tĂ”de tema kohta. Ticker on objekt, mis kĂ€itada kĂ”iki filtreid protsesside (graafik) kĂ€ivitavat funktsiooni process() koosneva kĂ”ikide filtreid, millega ta on ĂŒhendatud. Kui me C-programmis ĂŒhendame tickeri graafi filtri, nĂ€itame tickerile graafi, mida ta juhtima hakkab, kuni me ta vĂ€lja lĂŒlitame. PĂ€rast ĂŒhendamist hakkab ticker vaatama talle antud graafi, koostades loetelu filtritest, mis selles on. Et mitte "loenda" sama filtrit kaks korda, mĂ€rgib ta avastatud filtrid, mÀÀrates neile mĂ€rgi seen. Otsing toimub iga filtri linkide tabelite kaudu.
Oma sissejuhatava ekskursiooni ajal graafis kontrollib ticker, kas filtrite seas on vĂ€hemalt ĂŒks, mis tĂ€idab andmeplokkide allika rolli. Kui selliseid ei leita, loetakse graaf vale ja ticker lĂ”petab hĂ€daolukorraga oma töö.
Kui graaf on "Ă”ige", kutsutakse iga leitud filtri jaoks initsialiseerimise funktsioon preprocess(). Niipea kui saabub aeg jĂ€rgmise töötlemise taktiks (vaikimisi iga 10 millisekundi jĂ€rel), kutsub ticker vĂ€lja funktsiooni process() kĂ”igi eelnevalt leitud allikafiltrite jaoks ja seejĂ€rel ka ĂŒlejÀÀnud filtrile loendis. Kui filtril on sisendlinke, siis invokeeritakse funktsiooni process() korduvalt seni, kuni sisendlinkide jĂ€rjekorrad on tĂŒhjaks saanud. PĂ€rast seda liigub ta jĂ€rgmise filtri juurde loendis ja "kĂ€itab" seda, kuni sisendlinkidelt sĂ”numid vabanevad. Ticker liigub filtrist filtrisse seni, kuni loend lĂ”peb. Sellega töötlemine takt on lĂ”petatud.
NĂŒĂŒd naaseme tuplede juurde ja rÀÀgime, miks selline entiteet on lisatud mediastreamerisse. Ăldiselt on andmemaht, mida algoritm, mis töötab filtri sees, vajab, erinev ega ole suhtega ning ei ole kordne sisenemise andmebufferite suurusega. NĂ€iteks, kui kirjutame filtri, mis teostab kiiret Fourier' muundamist, siis see vĂ”ib töödelda ainult andmeplokke, mille suurus on 2 astmes. Olgu see 512 nĂ€idist. Kui andmed genereeritakse telefonikanali kaudu, siis sisenemise igas sĂ”numis andmebuffer toob meile 160 nĂ€idist signaalist. On kiusatus mitte vĂ”tta andmeid sisenemisest, kuni seal on vajalik hulk andmeid. Kuid sel juhul tekib konflikt ticker'iga, mis pĂŒĂŒab filtri tĂŒhjaks ajada. Varem mĂ€rkasime seda reeglit filtrite kolmanda tööprintsiibina. Selle printsiibi kohaselt peab filtri process() funktsioon vĂ”tma kĂ”ik andmed sisenemise jĂ€rjekordadest.
Lisaks ei saa sisenemisest vĂ”tta lihtsalt 512 nĂ€idist, kuna andmeid saab vĂ”tta ainult tĂ€istehnikas, st filter peab vĂ”tma 640 nĂ€idist ja kasutama neist 512, jĂ€ttes ĂŒlejÀÀnud uute andmepakkide kogunemiseks. Seega peab meie filter, lisaks oma peamisele tööle, tagama abifunktsioonid sisenemise andmete vahepealseks sĂ€ilitamiseks. Mediastreameri arendajad lahendasid selle ĂŒldise ĂŒlesande jaoks spetsiaalse objekti â MSBufferizer (vahebuffer), mis lahendab selle ĂŒlesande tuplede abil.
VahemÀlu (MSBufferizer)
See on objekt, mis hakkab akumuleerima sisenemise andmeid filtri sees ja hakkab edastama neid töötlemiseks, kui teabe hulk on piisav filtri algoritmi kĂ€ivitamiseks. Kui vahebuffer kogub andmeid, töötab filter tĂŒhja reĆŸiimis, raiskamata protsessori arvutusvĂ”imet. Kuid niipea, kui lugemine vahebufferist tagastab vÀÀrtuse, mis pole null, hakkab filtri process() funktsioon vĂ”tma ja töötlema vahebufferist andmeid vajalikus suuruses kuni nende lĂ”puni.
Kasuta kÀsitletud andmed jÀÀvad vahebufferisse kui esimene element tuple'ist, millele liituvad jÀrgmised sisenemisandmete plokid.
Struktuur, mis kirjeldab vahebufferit:
struct _MSBufferizer{
queue_t q; /* SÔnumite jÀrjekord. */
int size; /* Vahebufferis olevate andmete kogus hetkel. */
};
typedef struct _MSBufferizer MSBufferizer;MSBufferizeri töötamise funktsioonid
Uue vahebufferi eksemplari loomine:
MSBufferizer * ms_bufferizer_new(void);MĂ€lu eraldatakse, initsialiseeritakse ms_bufferizer_init() ja tagastatakse viide.
Initsialiseerimise funktsioon:
void ms_bufferizer_init(MSBufferizer *obj); Initsialiseeritakse jÀrjekord q, vÀli size seatakse nulliks.
SÔnumi lisamine:
void ms_bufferizer_put(MSBufferizer *obj, mblk_t *m); SÔnum m lisatakse jÀrjekorda. Arvutatud andmeplokkide suurus liidetakse size.
TÔlge vahebufferisse kÔigist sÔnumitest, mis on andmejÀrjekorras q:
void ms_bufferizer_put_from_queue(MSBufferizer *obj, MSQueue *q); SÔnumite edasiviimine andmejÀrjekorrast q vahebufferisse toimub funktsiooni kaudu ms_bufferizer_put().
Lugemine vahebufferist:
int ms_bufferizer_read(MSBufferizer *obj, uint8_t *data, int datalen); Kui kogus vahebufferis olevatest andmetest on vÀiksem kui nÔutud (datalen), tagastab funktsioon nulli, andmete kopeerimine data'i ei toimu. Vastupidisel juhul toimub jÀrjestikune andmete kopeerimine vahebufferis olevatest tuple'idest. PÀrast kopeerimist tuple eemaldatakse ja mÀlu vabastatakse. Kopeerimine lÔppeb hetkel, kui kopeeritakse datalen baitide suurus. Kui koht lÔpeb andmeploki keskel, siis.antud sÔnumis vÀhendatakse andmeploki suurust allesjÀÀnud kopeerimata osale. JÀrgmise kutsumise korral jÀtkub kopeerimine sealt.
Andmete lugemine, mis on hetkel vahebufferis saadaval:
int ms_bufferizer_get_avail(MSBufferizer *obj); Tagastab vahebufferi. size Andmete osa ignoreerimine, mis asub vahebufferis:
void ms_bufferizer_skip_bytes(MSBufferizer *obj, int bytes);
MÀÀratud andmebaite kogus eemaldatakse ja kÔrvaldatakse. Eemaldatakse vanimad andmed.KÔigi vahebufferis olevate sÔnumite eemaldamine:
void ms_bufferizer_flush(MSBufferizer *obj);
Andmete loendurit nullitakse. void ms_bufferizer_uninit(MSBufferizer *obj);
void ms_bufferizer_flush(MSBufferizer *obj);
Loenduri nullimine ei toimu. Vahebufferi eemaldamine ja mÀlukaartide vabastamine:
void ms_bufferizer_destroy(MSBufferizer *obj);
NĂ€iteid vahebufferi kasutamisest vĂ”ib leida mitme mediastreameri filtri allikakoodist. NĂ€iteks filter MS_L16_ENC, mis teostab baitide aubristikul jĂ€rgset ĂŒmberpaigutust, saates neid vĂ”rgukorra kĂ€tte: l16.c
JĂ€rgmises artiklis kĂ€sitleme koormuse hindamist tikkeril ja viise ĂŒleliigse arvutuskoormuse vĂ€hendamiseks meediastreameris.
Allikas: habr.com
