Materiali i artikullit është marrë nga kanali im .

Mekanizmi i transferit të të dhënave
- Blloku i të dhënave dblk_t
- Mesazhi mblk_t
- Funksionet për menaxhimin e mesazheve mblk_t
- Rrjeti queue_t
- Funksionet për menaxhimin e rrjeteve queue_t
- Lidhja e filtrave
- Pika e sinjalizimit në grafikun e përpunimit të të dhënave
- Aktiviteti i prapaskenës i ticker-it
- Bufferizuesi (MSBufferizer)
- Funksionet për menaxhimin e MSBufferizer
Në të kaluarën Ne kemi zhvilluar filtrin tonë. Ky artikull do t'i kushtohet mekanizmit të brendshëm të transferit të të dhënave midis filtrave të mediastream-it. Kjo do të lejojë krijimin e filtrave më të sofistikuar me më pak përpjekje.
Mekanizmi i transferit të të dhënave
Transferimi i tĂ« dhĂ«nave nĂ« mediastream realizohet pĂ«rmes rrjeteve tĂ« pĂ«rshkruara nga struktura queue_t. PĂ«rmes rrjeteve kalojnĂ« seri mesazhesh tĂ« tipit mblk_t, tĂ« cilat vetĂ« nuk pĂ«rmbajnĂ« tĂ« dhĂ«na sinjali, por vetĂ«m referencia pĂ«r mesazhin e mĂ«parshĂ«m, atĂ« tĂ« ardhshĂ«m dhe bllokun e tĂ« dhĂ«nave. PĂ«r mĂ« tepĂ«r, dĂ«shiroj tĂ« theksoj se ka njĂ« fushĂ« pĂ«r referencĂ« nĂ« njĂ« mesazh tĂ« njĂ«jtĂ«, e cila lejon organizimin e njĂ« liste tĂ« lidhur nga mesazhet. Grupin e mesazheve tĂ« bashkuara kĂ«shtu, do ta quajmĂ« tuple. Pra, çdo element i rrjetit mund tĂ« jetĂ« njĂ« mesazh i vetĂ«m mblk_t, ose mund tĂ« jetĂ« kryefjala e njĂ« tuple mesazhesh mblk_t. Ădo mesazh nĂ« tuple mund tĂ« ketĂ« bllokun e tij tĂ« dhĂ«nave nĂ«n mbikĂ«qyrje. Pse na duhen tuple, do ta diskutojmĂ« pak mĂ« vonĂ«.
Siç u tha mĂ« sipĂ«r, mesazhi vetĂ« nuk pĂ«rmban bllok tĂ« dhĂ«nash, por pĂ«rmban vetĂ«m njĂ« tregues pĂ«r zonĂ«n e memories ku ruhen blloket. NĂ« kĂ«tĂ« pjesĂ«, pamja e pĂ«rgjithshme e punĂ«s sĂ« mediastream-it ngjan me njĂ« magazinĂ« dyersh nĂ« filmin 'Korporata e Monsters', ku dyert (referencat nĂ« tĂ« dhĂ«na â dhomat) lĂ«vizin me njĂ« shpejtĂ«si tĂ« çmendur nĂ«pĂ«r konveyorĂ« tĂ« pezulluar, ndĂ«rkohĂ« qĂ« dhomat vetĂ« mbeten tĂ« palĂ«vizshme.
Tani, duke u lëvizur në hierarki nga poshtë lart, le të shqyrtojmë në detaje entitetet e listuara të mekanizmit të transferit të të dhënave në mediastream.
Blloku i të dhënave dblk_t
Blloku i të dhënave përbëhet nga një krye dhe një buffer të dhënash. Krye i përshkruar nga struktura e mëposhtme,
typedef struct datab
{
unsigned char *db_base; // Tregues për fillimin e buffer të dhënash.
unsigned char *db_lim; // Tregues për fundin e buffer të dhënash.
void (*db_freefn)(void*); // Funksioni për lirimin e memories kur fshihet blloku.
int db_ref; // Numëruesi i referencave.
} dblk_t;Fushat e strukturĂ«s pĂ«rmbajnĂ« tregues pĂ«r fillimin e bufferit, fundin e bufferit, funksionin e fshirjes tĂ« bufferit tĂ« dhĂ«nash. Elementi i fundit nĂ« krye db_ref â numĂ«ruesi i referencave, nĂ«se arrin zero, sinjalizon fshirjen e kĂ«tij blloku nga memoria. NĂ«se blloku i tĂ« dhĂ«nave Ă«shtĂ« krijuar nga funksioni datab_alloc() , atĂ«herĂ« bufferi i tĂ« dhĂ«nave do tĂ« vendoset nĂ« memorie menjĂ«herĂ« pas krye-sĂ«. NĂ« tĂ« gjitha rastet e tjera, bufferi mund tĂ« ndodhet diku tjetĂ«r. NĂ« bufferin e tĂ« dhĂ«nave do tĂ« ruhen tĂ« dhĂ«nat e sinjalit ose tĂ« tjera tĂ« dhĂ«na qĂ« dĂ«shirojmĂ« tĂ« pĂ«rpunojmĂ« me filtrat.
Një instancë e re e bllokut të të dhënave krijohet me funksionin:
dblk_t *datab_alloc(int size);Si parametĂ«r hyrĂ«s kalon madhĂ«sia e tĂ« dhĂ«nave qĂ« do tĂ« mbahen nga blloku. Memoria e ndan mĂ« shumĂ« pĂ«r tĂ« vendosur nĂ« fillim tĂ« memories tĂ« dedikuar krye-nĂ« â strukturĂ«n datab. Por nĂ« pĂ«rdorimin e funksioneve tĂ« tjera, kjo nuk ndodh gjithmonĂ«, nĂ« disa raste bufferi i tĂ« dhĂ«nave mund tĂ« ndodhet veçmas nga krye-i i bllokut tĂ« tĂ« dhĂ«nave. Fushat e strukturĂ«s, kur krijohen, rregullohen nĂ« mĂ«nyrĂ« qĂ« fusha e saj db_base tregues qĂ« tĂ« jetĂ« nĂ« fillim tĂ« zonĂ«s sĂ« tĂ« dhĂ«nave, dhe db_lim nĂ« fundin e saj. NumĂ«ruesi i referencave db_ref vendoset nĂ« njĂ«.
Mesazhi mblk_t
Siç u tha, elementet e rrjetit kanë tipin mblk_t, i cili është përcaktuar si mëposhtë:
typedef struct msgb
{
struct msgb *b_prev; // Tregues për elementin e mëparshëm të listës.
struct msgb *b_next; // Tregues për elementin e ardhshëm të listës.
struct msgb *b_cont; // Tregues për ngjitjen e mesazheve të tjera në mesazh, për krijimin e tuple mesazhesh.
struct datab *b_datap; // Tregues për strukturën e bllokut të të dhënave.
unsigned char *b_rptr; // Tregues për fillimin e zonës së të dhënave për të lexuar të dhënat nga bufferi b_datap.
unsigned char *b_wptr; // Tregues për fillimin e zonës së të dhënave për të shkruar të dhënat në bufferin b_datap.
uint32_t reserved1; // Fushë e rezervuar1, mediastream-i e vendos aty informacion shërbimi.
uint32_t reserved2; // Fushë e rezervuar2, mediastream-i e vendos aty informacion shërbimi.
#if defined(ORTP_TIMESTAMP)
struct timeval timestamp;
#endif
ortp_recv_addr_t recv_addr;
} mblk_t;Struktura mblk_t në fillim ka treguesit b_prev, b_next,të cilët janë të nevojshëm për organizimin e një liste dyfishe (e cila është rrjeti queue_t).
Pastaj vjen treguesi b_cont,i cili përdoret vetëm kur mesazhi hyn në tuple. Për mesazhin e fundit në tuple, ky tregues mbetet zero.
Më pas shohim treguesin për bllokun e të dhënave b_datap, për të cilin ekziston mesazhi. Pas tij vijnë treguesit në zonën brenda buffer-it të të dhënave të bllokut. Fusha b_rptr tregon vendin nga i cili do të lexohen të dhënat nga buffer-i. Fusha b_wptr tregon vendin nga i cili do të kryhet shkruajta në buffer.
Fushat e mbetura kanë karakter të ndihmës dhe nuk lidhen me funksionin e mekanizmit të transmetimit të të dhënave.
Më poshtë ilustrohet një mesazh i vetëm me emrin m1 dhe blloku i të dhënave d1.

Në figurën në vazhdim është paraqitur një tuple prej tre mesazhesh m1, m1_1, m1_2.

Funksionet që lidhen me mesazhet mblk_t
Mesazhi i ri mblk_t krijohet nga funksioni:
mblk_t *allocb(int size, int pri); ai alokon nĂ« memorie njĂ« mesazh tĂ« ri mblk_t mĂ« bllok tĂ« dhĂ«nash tĂ« caktuar. size, argumenti i dytĂ« â pri nuk pĂ«rdoret nĂ« versionin qĂ« po shqyrtohet tĂ« bibliotekĂ«s. Ai duhet tĂ« mbetet zero. NĂ« procesin e funksionit do tĂ« alokohet memorie pĂ«r strukturĂ«n e mesazhit tĂ« ri dhe do tĂ« thirret funksioni mblk_init(), i cili do tĂ« zerojĂ« tĂ« gjitha fushat e instancĂ«s sĂ« krijuar tĂ« strukturĂ«s dhe pastaj, me anĂ« tĂ« tĂ« pĂ«rmendurĂ«s mĂ« lart, datab_alloc(), do tĂ« krijojĂ« buffer-in e tĂ« dhĂ«nave. Pas kĂ«saj do tĂ« bĂ«het konfigurimi i fushave nĂ« strukturĂ«:
mp->b_datap=datab;
mp->b_rptr=mp->b_wptr=datab->db_base;
mp->b_next=mp->b_prev=mp->b_cont=NULL;Në dalje marrim një mesazh të ri me fushat e inicializuara dhe buffer-in e të dhënave bosh. Për të shtuar të dhëna në mesazh, duhet të kryhet kopjimi në buffer-in e bllokut të të dhënave:
memcpy(msg->b_rptr, data, size);ku data â treguesi nĂ« burimin e tĂ« dhĂ«nave, dhe size â madhĂ«sia e tyre.
Pastaj duhet të përditësohet treguesi te pika e shkruajtes, në mënyrë që përsëri të tregojë për fillimin e zonës së lirë në buffer:
msg->b_wptr = msg->b_wptr + sizeNëse kërkohet të krijojmë një mesazh nga një buffer ekzistues, pa kopjim, atëherë për këtë përdoret funksioni:
mblk_t *esballoc(uint8_t *buf, int size, int pri, void (*freefn)(void*)); Funksioni pas krijimit të mesazhit dhe strukturës së bllokut të të dhënave, do të konfigurojë treguesit e tij për të dhëna në adresën buf. Pra, në këtë rast buffer-in e të dhënave nuk ndodhet pas fushave të titullit të bllokut të të dhënave, siç ishte kur u krijua blloku i të dhënave nga funksioni datab_alloc(). Buffer-i i të dhënave i kaluar funksionit do të mbetet atje ku ishte, por me anë të treguesve do të lidhet me titullin e sapokrijuar të bllokut të të dhënave, dhe ai përkatësisht me mesazhin.
Një mesazhi mblk_t mundu të lidhen disa blloqe të dhënash radhazi. Kjo bëhet me funksionin:
mblk_t * appendb(mblk_t *mp, const char *data, int size, bool_t pad); mp â mesazhi nĂ« tĂ« cilin do tĂ« shtohet njĂ« bllok i ri tĂ« dhĂ«nash;
data â treguesi nĂ« bllokun, kopja e tĂ« cilit do tĂ« shtohet nĂ« mesazh;
size â madhĂ«sia e tĂ« dhĂ«nave;
pad â flamuri qĂ« tregon se madhĂ«sia e memories e alokuar duhet tĂ« jetĂ« e pĂ«rputhshme me kufirin 4 byte (plotĂ«simi do tĂ« kryhet me zeros).
Nëse në buffer-in ekzistues të mesazhit ka mjaft vend, data e re do të lidhet pas të dhënave atje që janë tashmë. Nëse nuk ka mjaft vend në buffer-in e të dhënave të mesazhit size, atëherë krijohet një mesazh i ri, me një buffer të mjaftueshëm dhe të dhënat kopjohen në buffer-in e tij. Ky mesazh i ri do të lidhet me origjinalin me anë të treguesit b_cont,. Në këtë rast mesazhi shndërrohet në një tuple.
Nëse në tuple kërkohet të shtohet një bllok i ri të dhënash, atëherë duhet të përdoret funksioni:
void msgappend(mblk_t *mp, const char *data, int size, bool_t pad);ai do të gjejë mesazhin e fundit në tuple (ai b_cont, do të ketë zero) dhe do të thërrasë për këtë mesazh funksionin appendb().
Për të ditur madhësinë e të dhënave në mesazh ose tuple mund të përdoret funksioni:
int msgdsize(const mblk_t *mp);ai do të kalojë nëpër të gjitha mesazhet e tuple dhe do të kthejë numrin total të të dhënave në buffer-at e këtyre mesazheve. Për çdo mesazh numri i të dhënave llogaritet kështu:
mp->b_wptr - mp->b_rptrPër të bashkuar dy tuple aplikohet funksioni:
mblk_t *concatb(mblk_t *mp, mblk_t *newm);ai lidhet tuple newm në fund të tuple mp dhe kthen treguesin në mesazhin e fundit të tuple të krijuar.
Nëse është e nevojshme, tuple mund të shndërrohet në një mesazh të vetme me një bllok të vetëm të dhënash, kjo bëhet me funksionin:
void msgpullup(mblk_t *mp,int len);nĂ«se argumenti len Ă«shtĂ« i barabartĂ« me -1, atĂ«herĂ« madhĂ«sia e buffer-it tĂ« alokuar pĂ«rcaktohet automatikisht. NĂ«se len Ă«shtĂ« njĂ« numĂ«r pozitiv, atĂ«herĂ« do tĂ« krijohet njĂ« buffer i kĂ«tij madhĂ«sie dhe nĂ« tĂ« do tĂ« kopjohen tĂ« dhĂ«nat e mesazheve tĂ« tuple. NĂ«se buffer-i pĂ«rfundon, atĂ«herĂ« kopjimi do tĂ« ndĂ«rpritet kĂ«tu. Mesazhi i parĂ« i tuple do tĂ« marrĂ« njĂ« buffer tĂ« madhĂ«sisĂ« sĂ« re me tĂ« dhĂ«na tĂ« kopjuara. Mesazhet e tjera do tĂ« fshihen dhe memoria do tâi kthehet grumbullit.
Në heqjen e strukturës mblk_t merret parasysh numri i referencave të bllokut të të dhënave, nëse gjatë thirrjes freeb() ai rezulton të jetë zero, atëherë buffer-i i të dhënave hiqet së bashku me instancën mblk_tqë e tregon atë.
Inicializimi i fushave të mesazhit të ri:
void mblk_init(mblk_t *mp);Shtimi në mesazh një sasie të re të të dhënave:
mblk_t * appendb(mblk_t *mp, const char *data, size_t size, bool_t pad);Nëse të dhënat e reja nuk përshtaten në hapësirën e lirë të buffers, do t'i bashkëlidhet mesazhit një mesazh i krijuar veçmas me bufferin e nevojshëm (në mesazhin e parë vendoset një tregues drejt mesazhit të shtuar) mesazhi shndërrohet në një tuple.
Shtimi i një porcioni të dhënash në tuple:
void msgappend(mblk_t *mp, const char *data, size_t size, bool_t pad); Funksioni thërret appendb() në një cikël.
Përbashkimi i dy tuple në një:
mblk_t *concatb(mblk_t *mp, mblk_t *newm);Mesazhi newm do të bashkëlidhet me mp.
Krijimi i një kopjeje të një mesazhi:
mblk_t *copyb(const mblk_t *mp);Kopjimi i plotë i tuple me të gjitha blloqet e të dhënave:
mblk_t *copymsg(const mblk_t *mp);Elementet e tuple në këtë mënyrë kopjohen nga funksioni copyb().
Krijimi i një kopje të lehtë të mesazhit. Në këtë rast, blloku i të dhënave nuk kopjohet, por numri i referencave të tij rritet mblk_tmblk_t *dupb(mblk_t *mp); db_ref:
Krijimi i një kopjeje të lehtë të tuple. Blloqet e të dhënave nuk kopjohen, vetëm numrat e referencave rritenmblk_t *dupmsg(mblk_t* m); db_ref:
Bashkimi i të gjitha mesazheve të tuple në një mesazh:void msgpullup(mblk_t *mp, size_t len);
Nëse argumentiështë i barabartë me -1, atëherë madhësia e bufferit të rezervuar përcaktohet automatikisht. len Kastrimi i mesazhit, tuple:
void freemsg(mblk_t *mp);
Numri i referencave të bllokut të të dhënave zvogëlohet me një. Nëse arrin zero, atëherë blloku i të dhënave gjithashtu fshihet.Numërimi i volumit total të të dhënave në mesazh ose tuple.
size_t msgdsize(const mblk_t *mp);
Nxjerrja e mesazhit nga bishti i radhës:mblk_t *ms_queue_peek_last (q);
Kopjimi i përmbajtjes së fushave të rezervuara të një mesazhi në një mesazh tjetër (në të vërtetë në këto fusha ndodhen flamujt që përdoren nga media streameri):mblk_meta_copy(const mblk_t *source, mblk *dest);
RadhĂ«t e mesazheve nĂ« media streamer janĂ« tĂ« implementuara si njĂ« listĂ« dyfishe cirkulluese. Ădo element i listĂ«s pĂ«rmban njĂ« tregues drejtpĂ«rdrejt nĂ« bllokun e tĂ« dhĂ«nave me matjet e sinjalit. KĂ«shtu, nĂ« radhĂ« lĂ«vizin vetĂ«m treguesit nĂ« bllokun e tĂ« dhĂ«nave, ndĂ«rsa vetĂ« tĂ« dhĂ«nat mbeten tĂ« palĂ«vizshme. Pra, lĂ«vizin vetĂ«m referencat pĂ«r to.Radhitja queue_t
Struktura që përshkruan radhën
, tregohet më poshtë: queue_ttypedef struct _queue { mblk_t _q_stopper; /* "Element i zbrazët" i radhës, nuk tregon në të dhëna, përdoret vetëm për menaxhimin e radhës. Gjatë inicializimit të radhës (qinit()) treguesit e tij konfigurohen që të tregojnë për veten e tij. */ int q_mcount; // Numri i elementeve në radhë. } queue_t;
Struktura përmban një fushë - treguesin_q_stopper në tipin *mblk_t, ai tregon në elementin e parë (mesazhin) në radhë. Fusha e dytë e strukturës është numri i mesazheve që ndodhen në radhë. Në figurën më poshtë tregohet radhë c me emrin q1, që përmban 4 mesazhe m1, m2, m3, m4.
Në figurën tjetër tregohet radhë c me emrin q1, që përmban 4 mesazhe m1, m2, m3, m4. Mesazhi m2 është koka e tuple, në të cilën lidhen edhe dy mesazhe m2_1 dhe m2_2.

Inicializimi i radhës:

Funksionet për menaxhimin e rrjeteve queue_t
void qinit(queue_t *q);
(më tej do ta quajmë "stoper") inicializohet nga funksioniFusha në tipin *mblk_t, ai tregon në elementin e parë (mesazhin) në radhë. Fusha e dytë e strukturës është numri i mesazheve që ndodhen në radhë. , treguesi i elementit të mëparshëm dhe i elementit të ardhshëm konfigurohen që të tregojnë në veten e tyre. Numri i elementeve të radhës inicializohet në zero. mblk_init()Shtimi i një elementi të ri (mesazhit):
void putq(queue_t *q, mblk_t *m);
Elementi i rishtohet në fund të listës, treguesit e elementit konfigurohen që stopper të bëhet elementi i ardhshëm për të, dhe ai për stopperin e mëparshëm. Numri i elementeve të radhës rritet. m Nxjerrja e një elementi nga radhë:
mblk_t * getq(queue_t *q);
nxjerret ai mesazh që ndodhet pas stopperit, numri i elementeve zvogëlohet. Nëse në radhë, përveç stoperit, nuk ka elemente, atëherë kthehet 0. Shtimi i mesazhit në radhë:
void insq(queue_t *q, mblk_t *emp, mblk_t *mp);
shtohet para elementit Element mp emp =0, atëherë mesazhi shtohet në fund të radhës.. Nëse =0, atëherë mesazhi shtohet në fund të radhës.Nxjerrja e mesazhit nga koka e radhës:
void remq(queue_t *q, mblk_t *mp);
Numri i elementeve zvogëlohet. Leximi i treguesit të elementit të parë në radhë:
mblk_t * peekq(queue_t *q);
Fshirja e të gjithë elementeve nga radha me fshirjen e vetë elementeve: void flushq(queue_t *q, int how);
siArgumenti nuk përdoret. Numri i elementeve të radhës vendoset në zero. Makro për leximin e treguesit në elementin e fundit të radhës:
mblk_t * qlast(queue_t *q);
Gjatë punës me radhët e mesazheve duhet të kemi parasysh se gjatë thirrjesms_queue_put(q, m) me një tregues null në mesazh, funksioni do të ngulfatet. Programi juaj do të ngecë. Njëlloj sillet edhe ms_queue_next(q, m) ms_queue_next(q, m).
Lidhja e filtrave
Kjo radhë e përshkruar më sipër përdoret për të transferuar mesazhe nga një filtër në tjetër ose nga një filtër në disa filtra. Filtrat dhe lidhjet e tyre formojnë një grafik të drejtuar. Hyrja ose dalja e filtri do ta quajmë termin e përgjithshëm "pin". Për të përshkruar rendin e lidhjeve midis filtrave, në mediastreamer përdoret koncepti i "pikës së sinjalit". Pika e sinjalit është një strukturë _MSCPoint, e cila përmban një tregues në filtër dhe numrin e njërit prej pins, përkatësisht ajo përshkruan lidhjen e njërit prej hyrjeve ose daljeve të filtrit.
Pika e sinjalizimit në grafikun e përpunimit të të dhënave
typedef struct _MSCPoint{
struct _MSFilter *filter; // Treguesi në filtërin e mediastreamer.
int pin; // Numri i njërit prej hyrjeve ose daljeve të filtrit, dmth. pin.
} MSCPoint;
Pin e filtrave numërohen duke filluar nga zero.
Lidhja midis dy pins me radhën e mesazheve përshkruhet nga struktura _MSQueue, e cila përmban një radhë mesazhesh dhe tregues në dy pika sinjali, të cilat ajo i lidh:
typedef struct _MSQueue
{
queue_t q;
MSCPoint prev;
MSCPoint next;
}MSQueue;
Do ta quajmĂ« kĂ«tĂ« strukturĂ« si lidhjen e sinjalit. Ădo filtĂ«r i mediastreamer, pĂ«rmban njĂ« tabelĂ« lidhjesh hyrĂ«se dhe njĂ« tabelĂ« lidhjesh dalĂ«se (MSQueue). MadhĂ«sia e tabelave pĂ«rcaktohet kur krijohet filtri, ne tashmĂ« kemi bĂ«rĂ« kĂ«tĂ« me ndihmĂ«n e njĂ« variabli tĂ« eksportuar tĂ« tipit MSFilterDesc, kur po zhvillonim filtrin tonĂ«. MĂ« poshtĂ« Ă«shtĂ« e paraqitur struktura qĂ« pĂ«rshkruan çdo filtĂ«r nĂ« mediastreamer, MSFilter:
struct _MSFilter{
MSFilterDesc *desc; /* Treguesi në deshkruesin e filtrit. */
/* Atributet e mbrojtura, nuk mund të lëvizen apo hiqen ndryshe do të dëmtohet funksionimi me pluginet. */
ms_mutex_t lock; /* Semafori. */
MSQueue **inputs; /* Tabela e lidhjeve hyrëse. */
MSQueue **outputs; /* Tabela e lidhjeve dalëse. */
struct _MSFactory *factory; /* Treguesi në fabrikën që krijoi këtë instancë filtri. */
void *padding; /* Nuk përdoret, do të aktivizohet nëse shtohen fusha të mbrojtura. */
void *data; /* Treguesi në një strukturë të rastësishme për ruajtjen e të dhënave të gjendjes së brendshme të filtrit dhe llogaritjeve ndërmjetëse. */
struct _MSTicker *ticker; /* Treguesi në objektin ticker, i cili nuk duhet të jetë zero kur thirret funksioni process(). */
/* Atributet private, ato mund të lëvizen dhe ndryshohen në çdo kohë */
MSList *notify_callbacks; /* Lista e thirrjeve kthyes, që përdoren për të trajtuar ngjarjet e filtrit. */
uint32_t last_tick; /* Numri i ciklit të fundit, kur është kryer thirrja process(). */
MSFilterStats *stats; /* Statistika e punës së filtrit.*/
int postponed_task; /*Numri i detyrave të shtyra. Disa filtra mund të shtyjnë përpunimin e të dhënave (thirjen e process()) për disa cikle.*/
bool_t seen; /* Flaqi, që përdoret nga ticker, për të shënuar se ky instancë filtri e ka shërbyer tashmë në këtë cikël.*/
};
typedef struct _MSFilter MSFilter;
Pas lidhjes së filtrave në programin C sipas konceptit tonë (por pa lidhur ticker-in), ne kështu krijuam një grafik të drejtuar, ku nodet janë instancat e strukturës MSFilter, ndërsa skajorët janë instancat e lidhjeve MSQueue.
Aktiviteti i prapaskenës i ticker-it
Kur ju thashë se ticker është një filtër burimi i cikleve, nuk ishte e vërteta e plotë për të. Ticker është një objekt që për çdo cikël ekzekuton funksionet process() e të gjithë filtrave të skemës (grafikut) me të cilin ai është lidhur. Kur ne lidhim ticker-in në një filtër të grafikut në programin C, ne tregojmë ticker-it grafik që nga ky moment ai do të menaxhojë, derisa ne ta shkëpusim. Pas lidhjes, ticker fillon të shqyrtojë grafikun që i është besuar, duke hartuar një listë filtrash në të cilat ai përfshihet. Për të mos "numëruar" një filtër të njëjtë dy herë, ai shënon filtrat e zbuluar, duke vendosur një flamur seen. Kërkimi zhvillohet nëpër tabelat e lidhjeve që ka çdo filtër.
Gjatë excursioneve të tij informative nëpër grafik, ticker kontrollon nëse ka ndonjë filtër që luan rolin e burimit të blokëve të të dhënave. Nëse nuk gjenden të tillë, grafiku shpallet i gabuar dhe ticker përfundon punën në mënyrë emergjente.
Nëse grafiku doli "i saktë", për çdo filtër të gjetur, për inkuadrim, thirret funksioni preprocess(). Sa herë që arrin momenti për ciklin tjetër të përpunimit (me default çdo 10 milisekonda), ticker thërret funksionin process() për të gjithë filtrat burimë të gjetur më parë dhe më pas edhe për filtrat e tjerë të listës. Nëse filtër ka lidhje hyrëse, atëherë aktivizimi i funksionit process() Përfundon deri sa radhët e lidhjeve hyrëse të zbrazën. Pas kësaj, ai kalon në filtër tjetër të listës dhe "kalon" atë deri në lirimin e lidhjeve hyrëse nga mesazhet. Ticker kalon nga filtri në filtër deri sa të mbarojë lista. Këtu përfundon përpunimi i ciklit.
Tani, ne do të kthehemi tek tuples dhe do të flasim për arsyen pse një strukturë e tillë u shtua në mediastreamer. Në përgjithësi, sasia e të dhënave të nevojshme për algoritmin që funksionon brenda filtrit nuk përputhet dhe nuk është shumëfish i madhësisë së bufereve të të dhënave që po vijnë. Për shembull, ne shkruajmë një filtrë që bën një transformim të shpejtë të Fourier-it, i cili sipas definicionit mund të përpunojë vetëm blloqe të të dhënave, ku madhësia është një fuqi e dyshes. Le të jetë kjo 512 pika. Nëse të dhënat gjenerohen nga një kanal telefonik, buffering i çdo mesazhi në hyrje do të na sjellë 160 pika sinjali. Ekziston një tundim për të mos marrë të dhëna nga hyrja derisa të ketë sasi të nevojshme të të dhënave. Por në këtë rast do të shfaqej një konflikt me ticker-in, i cili do të përpiqej pa sukses të rrotullonte filtrin deri sa të zbrazte linjën e hyrjes. Më parë e kemi quajtur këtë rregull si parimi i tretë i funksionimit të filtrit. Sipas këtij parimi, funksioni process() i filtrit duhet të marrë të gjitha të dhënat nga radhët hyrëse.
PĂ«rveç kĂ«saj, nga hyrja nuk mund tĂ« merren vetĂ«m 512 pika, pasi qĂ« mund tĂ« merren vetĂ«m blloqe tĂ« plota, pra, filtrit do tâi duhet tĂ« marrĂ« 640 pika dhe duke pĂ«rdorur 512 nga ato, derisa tĂ« akumulojĂ« sasinĂ« e re tĂ« tĂ« dhĂ«nave. NĂ« kĂ«tĂ« mĂ«nyrĂ«, filtrat tanĂ«, pĂ«rveç funksionit tĂ« tij kryesor, duhet tĂ« sigurojĂ« veprime ndihmĂ«se pĂ«r ruajtjen e pĂ«rkohshme tĂ« tĂ« dhĂ«nave nĂ« hyrje. Zhvilluesit e mediastreamer-it pĂ«r zgjidhjen e kĂ«saj problemi tĂ« pĂ«rgjithshĂ«m kanĂ« zhvilluar njĂ« objekt tĂ« veçantĂ« - MSBufferizer (bufferizer), i cili zgjidh kĂ«tĂ« problem duke pĂ«rdorur tuples.
Bufferizuesi (MSBufferizer)
Ky është një objekt që do të akumulojë të dhënat hyrëse brenda filtrit dhe do të fillojë t'i japë ato për përpunim, sapo sasia e informacionit të jetë e mjaftueshme për të realizuar algoritmin e filtrit. Ndërsa bufferizatori akumulohet të dhëna, filtri do të punojë në modin bosh, pa shpenzuar kapacitetin llogaritës të procesorit. Por sapo funksioni i leximit nga bufferizatori të kthejë një vlerë të ndryshme nga zero, funksioni process() i filtrit fillon të marrë dhe të përpunojë të dhënat nga bufferizatori në sasi të nevojshme, deri në përfundimin e tyre.
Të dhënat e pa kërkuara mbeten në bufferizator si elementi i parë i tuples, i cili lidhet me blloqet e ardhshme të të dhënave hyrëse.
Struktura që përshkruan bufferizatorin:
struct _MSBufferizer{
queue_t q; /* Radhët e mesazheve. */
int size; /* Sasia totale e të dhënave që ndodhen në bufferizator në këtë moment. */
};
typedef struct _MSBufferizer MSBufferizer;Funksionet për menaxhimin e MSBufferizer
Krijimi i një ekzemplar të ri të bufferizatorit:
MSBufferizer * ms_bufferizer_new(void);Memoria ndahet, inicializohet në ms_bufferizer_init() dhe kthehet treguesi.
Funksioni i inicializimit:
void ms_bufferizer_init(MSBufferizer *obj); Inicializohet radhët q, fushë size vendoset në zero.
Shtimi i një mesazhi:
void ms_bufferizer_put(MSBufferizer *obj, mblk_t *m); Mesazhi m shtohet në radhë. Madhësia e llogaritur e bllokut të të dhënave shtohet në size.
Transferta në bufferizator e të gjitha mesazheve nga radhët e të dhënave të lidhjes q:
void ms_bufferizer_put_from_queue(MSBufferizer *obj, MSQueue *q); Transferimi i mesazheve nga lidhja q në bufferizator bëhet me funksionin ms_bufferizer_put().
Leximi nga bufferizatori:
int ms_bufferizer_read(MSBufferizer *obj, uint8_t *data, int datalen); Nëse madhësia e të dhënave të akumuluara në bufferizator është më e vogël se e kërkuara (datalen), funksioni kthen zero, kopjimi i të dhënave në data nuk kryhet. Në rastin e tjetër kryhet kopjimi i rendit të të dhënave nga tuples që ndodhen në bufferizator. Pas kopjimit, tuple fshihet dhe memoria lirohet. Kopjimi përfundon kur të jenë kopjuar datalen byte. Nëse vendi mbaron në mes të një blloku të të dhënave, atëherë në këtë mesazh, blloku i të dhënave do të shkurtohet deri në pjesën e mbetur që nuk është kopjuar. Në thirrjen e ardhshme, kopjimi do të vazhdojë nga ky vend.
Leximi i sasisë së të dhënave që janë në dispozicion në këtë moment në bufferizator:
int ms_bufferizer_get_avail(MSBufferizer *obj); Kthen fushën size bufferizatorit.
Hedhja e një pjese të të dhënave që ndodhen në bufferizator:
void ms_bufferizer_skip_bytes(MSBufferizer *obj, int bytes);Sasia e specifikuar e byte të dhënave shkurtohet dhe hidhet. Hidhën të dhënat më të vjetra.
Fshirja e të gjitha mesazheve në bufferizator:
void ms_bufferizer_flush(MSBufferizer *obj); Numri i të dhënave rikthehet në zero.
Fshirja e të gjitha mesazheve në bufferizator:
void ms_bufferizer_uninit(MSBufferizer *obj); Zeroimi i numrit nuk kryhet.
Fshirja e bufferizatorit dhe lirimi i memories:
void ms_bufferizer_destroy(MSBufferizer *obj); Shembujt e përdorimit të bufferizatorit mund të gjenden në kodin burimor të disa filtrave në mediastreamer. Për shembull, në filtrin MS_L16_ENC, i cili kryen ri-renditjen e byte-ve në pikë nga rendi rrjetor në rendin e hostit:
Në artikullin e ardhshëm, ne do të shqyrtojmë çështjen e vlerësimit të ngarkesës në ticker dhe mënyrat për të përballuar ngarkesën e tepruar të llogaritjeve në mediastreamer.
Burimi: habr.com
