Skúmanie enginu Mediastreamer2 VoIP. Časť 11

Materiál článku je prevzatý z môjho zenový kanál.

Skúmanie enginu Mediastreamer2 VoIP. Časť 11

Mechanizmus pohybu údajov

  • Dátový blok dblk_t
  • Správa mblk_t
  • Funkcie pre prácu so správami mblk_t
  • Front queue_t
  • Funkcie pre prácu s frontami queue_t
  • Pripojenie filtrov
  • Signálny bod grafu spracovania údajov
  • Zákulisné aktivity operátora
  • Bufferizer (MSBufferizer)
  • Funkcie pre prácu s MSBufferizer

V poslednom článok vyvinuli sme vlastný filter. Tento článok sa zameria na vnútorný mechanizmus presúvania údajov medzi filtrami streamovania médií. To vám v budúcnosti umožní písať sofistikované filtre s menšou námahou.

Mechanizmus pohybu údajov

Pohyb údajov v streameri médií sa vykonáva pomocou frontov popísaných štruktúrou queue_t. Reťazce správ ako mblk_t, ktoré samotné neobsahujú signálne dáta, ale len odkazujú na predchádzajúcu, nasledujúcu správu a na dátový blok. Okrem toho chcem obzvlášť zdôrazniť, že existuje aj pole pre odkaz na správu rovnakého typu, ktoré vám umožňuje usporiadať jednotlivo prepojený zoznam správ. Skupinu správ zjednotenú takýmto zoznamom nazveme n-ticou. Akýkoľvek prvok frontu teda môže byť jednou správou mblk_ta možno aj hlava n-tice správ mblk_t. Každá správa n-tice môže mať svoj vlastný blok údajov oddelenia. Prečo sú potrebné n-tice, budeme diskutovať o niečo neskôr.

Ako už bolo spomenuté vyššie, samotná správa neobsahuje blok údajov, namiesto toho obsahuje iba ukazovateľ na oblasť pamäte, kde je blok uložený. V tejto časti celkový obraz práce mediálneho streamera pripomína sklad dverí v karikatúre „Monsters, Inc.“, kde sa dvere (odkazy na údaje - miestnosti) pohybujú šialenou rýchlosťou pozdĺž horných dopravníkov, zatiaľ čo samotné miestnosti zostať bez pohybu.

Teraz, pohybujúc sa v hierarchii zdola nahor, podrobne zvážime uvedené entity mechanizmu prenosu údajov v streameri médií.

Dátový blok dblk_t

Dátový blok pozostáva z hlavičky a dátovej vyrovnávacej pamäte. Hlavička je opísaná nasledujúcou štruktúrou,

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

Polia štruktúry obsahujú ukazovatele na začiatok vyrovnávacej pamäte, koniec vyrovnávacej pamäte a funkciu na vymazanie údajovej vyrovnávacej pamäte. Posledný prvok v hlavičke db_ref — referenčné počítadlo, ak dosiahne nulu, slúži to ako signál na vymazanie tohto bloku z pamäte. Ak bol dátový blok vytvorený funkciou datab_alloc() , potom sa dátová vyrovnávacia pamäť umiestni do pamäte hneď za hlavičku. Vo všetkých ostatných prípadoch môže byť vyrovnávacia pamäť umiestnená niekde oddelene. Dátová vyrovnávacia pamäť bude obsahovať vzorky signálov alebo iné dáta, ktoré chceme spracovať pomocou filtrov.

Nová inštancia dátového bloku sa vytvorí pomocou funkcie:

dblk_t *datab_alloc(int size);

Ako vstupný parameter je daná veľkosť dát, ktoré bude blok uchovávať. Viac pamäte je pridelené, aby sa na začiatok pridelenej pamäte umiestnila hlavička - štruktúra datab. Ale pri použití iných funkcií sa to nie vždy stáva, v niektorých prípadoch môže byť dátová vyrovnávacia pamäť umiestnená oddelene od hlavičky dátového bloku. Pri vytváraní štruktúry sa polia konfigurujú tak, že jej pole db_base ukázal na začiatok dátovej oblasti a db_lim do jeho konca. Počet odkazov db_ref je nastavený na jednu. Ukazovateľ funkcie vymazania údajov je nastavený na nulu.

Správa mblk_t

Ako bolo uvedené, prvky frontu sú typu mblk_t, je definovaná takto:

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;

Štruktúra mblk_t obsahuje ukazovatele na začiatku b_prev, b_ďalší, ktoré sú potrebné na usporiadanie dvojito prepojeného zoznamu (čo je front queue_t).

Potom príde ukazovateľ b_cont, ktorý sa používa iba vtedy, keď je správa súčasťou n-tice. Pre poslednú správu v n-tici zostáva tento ukazovateľ nulový.

Ďalej vidíme ukazovateľ na dátový blok b_datap, pre ktorú správa existuje. Za ním nasledujú ukazovatele na oblasť vnútri vyrovnávacej pamäte blokových údajov. Lúka b_rptr určuje miesto, z ktorého sa budú čítať údaje z vyrovnávacej pamäte. Lúka b_wptr označuje miesto, z ktorého sa bude vykonávať zápis do vyrovnávacej pamäte.

Zvyšné polia majú charakter služby a nesúvisia s fungovaním mechanizmu prenosu údajov.

Nižšie je uvedená jedna správa s názvom m1 a dátový blok d1.
Skúmanie enginu Mediastreamer2 VoIP. Časť 11
Nasledujúci obrázok zobrazuje n-ticu troch správ m1, m1_1, m1_2.
Skúmanie enginu Mediastreamer2 VoIP. Časť 11

Funkcie správ mblk_t

Nová správa mblk_t vytvorené funkciou:

mblk_t *allocb(int size, int pri); 

uloží novú správu do pamäte mblk_t s dátovým blokom špecifikovanej veľkosti veľkosť, druhý argument - pri v tejto verzii knižnice sa nepoužíva. Mala by zostať nulová. Počas činnosti funkcie sa pridelí pamäť pre štruktúru novej správy a funkcia sa zavolá mblk_init(), ktorý vynuluje všetky polia vytvorenej inštancie štruktúry a následne pomocou vyššie uvedeného datab_alloc(), vytvorí dátovú vyrovnávaciu pamäť. Potom budú polia v štruktúre nakonfigurované:

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

Na výstupe dostaneme novú správu s inicializovanými poliami a prázdnou vyrovnávacou pamäťou údajov. Ak chcete do správy pridať údaje, musíte ich skopírovať do vyrovnávacej pamäte bloku údajov:

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

kde data je ukazovateľ na zdroj údajov a veľkosť - ich veľkosť.
potom musíte aktualizovať ukazovateľ na bod zápisu tak, aby znova ukazoval na začiatok voľnej oblasti vo vyrovnávacej pamäti:

msg->b_wptr = msg->b_wptr + size

Ak potrebujete vytvoriť správu z existujúcej vyrovnávacej pamäte bez kopírovania, použite funkciu:

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

Funkcia po vytvorení správy a štruktúry bloku údajov nakonfiguruje svoje ukazovatele na údaje na adrese BUF. Tie. v tomto prípade sa dátová vyrovnávacia pamäť nenachádza za poliami hlavičky dátového bloku, ako tomu bolo pri vytváraní dátového bloku s funkciou datab_alloc(). Buffer s dátami odovzdanými funkcii zostane tam, kde bol, ale pomocou pointerov sa pripojí k novovytvorenej hlavičke dátového bloku, a teda k správe.

Na jednu správu mblk_t Niekoľko dátových blokov môže byť zreťazených postupne. Robí sa to pomocou funkcie:

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

mp — správa, ku ktorej sa pridá ďalší blok údajov;
data — ukazovateľ na blok, ktorého kópia bude pridaná do správy;
veľkosť — veľkosť údajov;
podložka — príznak, že veľkosť pridelenej pamäte musí byť zarovnaná pozdĺž 4-bajtovej hranice (vyplnenie sa vykoná nulami).

Ak je v existujúcej vyrovnávacej pamäti údajov správy dostatok miesta, nové údaje sa prilepia za údaje, ktoré tam už sú. Ak je vo vyrovnávacej pamäti údajov správy menej voľného miesta ako veľkosť, potom sa vytvorí nová správa s dostatočnou veľkosťou vyrovnávacej pamäte a údaje sa skopírujú do jej vyrovnávacej pamäte. Toto je nová správa, prepojená s pôvodnou pomocou ukazovateľa b_cont. V tomto prípade sa správa zmení na n-ticu.

Ak potrebujete do n-tice pridať ďalší blok údajov, musíte použiť funkciu:

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

nájde poslednú správu v n-tici (má b_cont bude null) a zavolá funkciu pre túto správu appendb().

Veľkosť údajov v správe alebo n-tici zistíte pomocou funkcie:

int msgdsize(const mblk_t *mp);

bude prechádzať všetkými správami v n-tici a vráti celkové množstvo údajov v dátových bufferoch týchto správ. Pre každú správu sa množstvo údajov vypočíta takto:

 mp->b_wptr - mp->b_rptr

Ak chcete spojiť dve n-tice, použite funkciu:

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

ona pripojí n-ticu newm k chvostu tuple mp a vráti ukazovateľ na poslednú správu výslednej n-tice.

Ak je to potrebné, n-tica sa môže zmeniť na jednu správu s jedným blokom údajov; to sa vykonáva pomocou funkcie:

void msgpullup(mblk_t *mp,int len);

ak argument ľan je -1, potom sa veľkosť pridelenej vyrovnávacej pamäte určí automaticky. Ak ľan je kladné číslo, vytvorí sa vyrovnávacia pamäť tejto veľkosti a skopírujú sa do nej údaje správy n-tice. Ak sa minie vyrovnávacia pamäť, kopírovanie sa tam zastaví. Prvá správa n-tice dostane novú vyrovnávaciu pamäť so skopírovanými údajmi. Zostávajúce správy sa vymažú a pamäť sa vráti na hromadu.

Pri odstraňovaní štruktúry mblk_t referenčný počet dátového bloku sa berie do úvahy, ak pri volaní freeb() ukáže sa, že je nula, potom sa dátová vyrovnávacia pamäť vymaže spolu s inštanciou mblk_t, ktorý na to poukazuje.

Inicializácia polí novej správy:

void mblk_init(mblk_t *mp);

Pridanie ďalšej časti údajov do správy:

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

Ak sa nové dáta nezmestia do voľného priestoru dátovej vyrovnávacej pamäte správy, potom sa k správe pripojí samostatne vytvorená správa s vyrovnávacou pamäťou požadovanej veľkosti (v prvej správe sa nastaví ukazovateľ na pridanú správu) a správa sa zmení na n-ticu.

Pridanie časti údajov do n-tice:

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

Funkcia volá appendb() v slučke.

Spojenie dvoch n-tic do jednej:

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

Správa newm budú pripojené k mp.

Vytvorenie kópie jednej správy:

mblk_t *copyb(const mblk_t *mp);

Kompletné skopírovanie n-tice so všetkými blokmi údajov:

mblk_t *copymsg(const mblk_t *mp);

Prvky n-tice funkcia skopíruje copyb().

Vytvorte jednoduchú kópiu správy mblk_t. V tomto prípade sa blok údajov neskopíruje, ale zvýši sa jeho referenčné počítadlo db_ref:

mblk_t *dupb(mblk_t *mp);

Vytvorenie ľahkej kópie n-tice. Dátové bloky sa nekopírujú, iba sa zvýšia ich referenčné počítadlá db_ref:

mblk_t *dupmsg(mblk_t* m);

Zlepenie všetkých správ n-tice do jednej správy:

void msgpullup(mblk_t *mp,size_t len);

Ak argument ľan je -1, potom sa veľkosť pridelenej vyrovnávacej pamäte určí automaticky.

Odstránenie správy, tuple:

void freemsg(mblk_t *mp);

Počet referencií bloku údajov sa zníži o jednu. Ak dosiahne nulu, vymaže sa aj blok údajov.

Výpočet celkového množstva dát v správe alebo n-tici.

size_t msgdsize(const mblk_t *mp);

Načítanie správy z konca poradia:

mblk_t *ms_queue_peek_last (q);

Kopírovanie obsahu vyhradených polí jednej správy do inej správy (v skutočnosti tieto polia obsahujú príznaky, ktoré používa streamer médií):

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

otočenie queue_t

Front správ v streameri médií je implementovaný ako kruhový dvojito prepojený zoznam. Každý prvok zoznamu obsahuje ukazovateľ na dátový blok so vzorkami signálu. Ukazuje sa, že sa postupne pohybujú iba ukazovatele na dátový blok, zatiaľ čo samotné dáta zostávajú nehybné. Tie. presunú sa iba odkazy na ne.
Štruktúra popisujúca front queue_t, zobrazené nižšie:

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

Štruktúra obsahuje pole - ukazovateľ _q_stopper zadajte *mblk_t, ukazuje na prvý prvok (správu) vo fronte. Druhým poľom štruktúry je počítadlo správ vo fronte.
Obrázok nižšie zobrazuje front s názvom q1 obsahujúci 4 správy m1, m2, m3, m4.
Skúmanie enginu Mediastreamer2 VoIP. Časť 11
Nasledujúci obrázok zobrazuje front s názvom q1 obsahujúci 4 správy m1,m2,m3,m4. Správa m2 je hlavička n-tice, ktorá obsahuje ďalšie dve správy m2_1 a m2_2.

Skúmanie enginu Mediastreamer2 VoIP. Časť 11

Funkcie pre prácu s frontami queue_t

Inicializácia frontu:

void qinit(queue_t *q);

Pole _q_stopper (ďalej to budeme nazývať „zátka“) je inicializovaná funkciou mblk_init(), jeho predchádzajúci prvok a ukazovateľ nasledujúceho prvku sú upravené tak, aby ukazovali na seba. Počítadlo prvkov frontu sa vynuluje.

Pridanie nového prvku (správ):

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

Nový prvok m sa pridá na koniec zoznamu, ukazovatele prvkov sa upravia tak, že zátka sa pre ňu stane ďalším prvkom a stane sa predchádzajúcim prvkom zátky. Počítadlo prvkov frontu sa zvýši.

Načítanie prvku z frontu:

mblk_t * getq(queue_t *q); 

Správa, ktorá príde po vybratí zátky a počítadlo prvkov sa zníži. Ak vo fronte nie sú žiadne prvky okrem zátky, vráti sa 0.

Vloženie správy do frontu:

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

element mp vložené pred prvok zam, ak zam=0, potom sa správa pridá na koniec poradia.

Načítanie správy z hlavy frontu:

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

Počítadlo prvkov sa zníži.

Čítanie ukazovateľa na prvý prvok vo fronte:

mblk_t * peekq(queue_t *q); 

Odstránenie všetkých prvkov z frontu pri odstraňovaní samotných prvkov:

void flushq(queue_t *q, int how);

argument ako nepoužité. Počítadlo prvkov frontu je nastavené na nulu.

Makro na čítanie ukazovateľa na posledný prvok frontu:

mblk_t * qlast(queue_t *q);

Pri práci s frontami správ si uvedomte, že keď voláte ms_queue_put(q, m) s nulovým ukazovateľom na správu sa funkcia zacyklí. Váš program zamrzne. sa správa podobne ms_queue_next(q, m).

Pripojenie filtrov

Vyššie opísaný front sa používa na odovzdávanie správ z jedného filtra do druhého alebo z jedného do viacerých filtrov. Filtre a ich prepojenia tvoria orientovaný graf. Vstup alebo výstup filtra sa bude nazývať všeobecným slovom „pin“. Na opísanie poradia, v ktorom sú filtre navzájom spojené, používa streamer médií koncept „signálneho bodu“. Signálny bod je štruktúra _MSCPoint, ktorý obsahuje ukazovateľ na filter a číslo jedného z jeho pinov, podľa toho popisuje zapojenie jedného zo vstupov alebo výstupov filtra.

Signálny bod grafu spracovania údajov

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

Filtrové kolíky sú očíslované od nuly.

Spojenie dvoch pinov frontom správ popisuje štruktúra _MSQueue, ktorý obsahuje front správ a ukazovatele na dva signálne body, ktoré spája:

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

Túto štruktúru budeme nazývať signálna väzba. Každý filter streamovania médií obsahuje tabuľku vstupných odkazov a tabuľku výstupných odkazov (MSQueue). Veľkosť tabuliek sa nastavuje pri vytváraní filtra, to sme už urobili pomocou exportovanej premennej typu MSFilterDesc, keď sme vyvinuli vlastný filter. Nižšie je uvedená štruktúra, ktorá popisuje akýkoľvek filter v streameri médií, 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;

Po pripojení filtrov v programe C podľa nášho plánu (ale nepripojili sme ticker) sme tak vytvorili orientovaný graf, ktorého uzly sú inštanciami štruktúry MSFilter, a okraje sú inštanciami odkazov MSQueue.

Zákulisné aktivity operátora

Keď som vám povedal, že ticker je filter na zdroj kliešťov, nebola to úplná pravda. Ticker je objekt, ktorý spúšťa funkcie na hodinách proces() všetky filtre obvodu (grafu), ku ktorému je pripojený. Keď pripojíme ticker ku filtru grafov v programe C, ukážeme tickeru graf, ktorý bude odteraz ovládať, kým ho nevypneme. Po pripojení začne ticker skúmať graf zverený do jeho starostlivosti a zostavuje zoznam filtrov, ktoré ho obsahujú. Aby sa ten istý filter „nepočítal“ dvakrát, označí zistené filtre začiarknutím políčka videl. Vyhľadávanie sa vykonáva pomocou tabuliek odkazov, ktoré má každý filter.

Počas úvodnej prehliadky grafu ticker skontroluje, či sa medzi filtrami nachádza aspoň jeden, ktorý funguje ako zdroj dátových blokov. Ak nie sú žiadne, potom sa graf považuje za nesprávny a ticker zlyhá.

Ak sa ukáže, že graf je „správny“, pre každý nájdený filter sa funkcia vyvolá na inicializáciu predbežné spracovanie (). Hneď ako nastane okamih pre ďalší cyklus spracovania (štandardne každých 10 milisekúnd), ticker zavolá funkciu proces() pre všetky predtým nájdené zdrojové filtre a potom pre zostávajúce filtre v zozname. Ak má filter vstupné odkazy, spustí sa funkcia proces() opakuje, kým nie sú fronty vstupných odkazov prázdne. Potom sa presunie na ďalší filter v zozname a „roluje“ ho, kým nebudú vstupné odkazy bez správ. Ticker sa pohybuje od filtra k filtru, kým sa zoznam neskončí. Tým sa dokončí spracovanie cyklu.

Teraz sa vrátime k n-ticám a povieme si, prečo bola takáto entita pridaná do mediálneho streamera. Vo všeobecnosti sa množstvo údajov, ktoré vyžaduje algoritmus pracujúci vo filtri, nezhoduje a nie je násobkom veľkosti dátových vyrovnávacích pamätí prijatých na vstupe. Napríklad píšeme filter, ktorý vykonáva rýchlu Fourierovu transformáciu, ktorá podľa definície dokáže spracovať iba dátové bloky, ktorých veľkosť je mocninou dvoch. Nech je to 512 počtov. Ak sú dáta generované telefónnym kanálom, potom nám dátová vyrovnávacia pamäť každej správy na vstupe prinesie 160 vzoriek signálu. Je lákavé nezbierať údaje zo vstupu, kým tam nie je požadované množstvo údajov. Ale v tomto prípade dôjde ku kolízii s tickerom, ktorý sa neúspešne pokúsi posúvať filter, kým nebude vstupný odkaz prázdny. Predtým sme toto pravidlo označili ako tretí princíp filtra. Podľa tohto princípu musí funkcia process() filtra brať všetky dáta zo vstupných frontov.

Navyše zo vstupu nebude možné odobrať len 512 vzoriek, keďže môžete odoberať len celé bloky, t.j. filter bude musieť odobrať 640 vzoriek a použiť 512 z nich, zvyšok pred zhromaždením novej časti údajov. Náš filter teda okrem svojej hlavnej práce musí zabezpečovať aj pomocné akcie na medziukladanie vstupných dát. Vývojári media streamera a riešenia tohto všeobecného problému vyvinuli špeciálny objekt - MSBufferizer (bufferer), ktorý tento problém rieši pomocou n-tic.

Bufferizer (MSBufferizer)

Toto je objekt, ktorý bude zhromažďovať vstupné údaje vo filtri a začne ich odosielať na spracovanie, akonáhle je množstvo informácií dostatočné na spustenie algoritmu filtra. Kým vyrovnávacia pamäť akumuluje dáta, filter bude pracovať v nečinnom režime bez toho, aby spotreboval výpočtový výkon procesora. Ale akonáhle funkcia čítania z vyrovnávacej pamäte vráti hodnotu inú ako nulu, funkcia process() filtra začne brať a spracovávať dáta z vyrovnávacej pamäte po častiach požadovanej veľkosti, až kým sa nevyčerpá.
Údaje, ktoré ešte nie sú potrebné, zostávajú vo vyrovnávacej pamäti ako prvý prvok n-tice, ku ktorému sú pripojené následné bloky vstupných údajov.

Štruktúra, ktorá popisuje vyrovnávaciu pamäť:

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

Funkcie pre prácu s MSBufferizer

Vytvorenie novej inštancie vyrovnávacej pamäte:

MSBufferizer * ms_bufferizer_new(void);

Pamäť je alokovaná, inicializovaná v ms_bufferizer_init() a vráti sa ukazovateľ.

Funkcia inicializácie:

void ms_bufferizer_init(MSBufferizer *obj); 

Prebieha inicializácia frontu q, lúka veľkosť je nastavený na nulu.

Pridanie správy:

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

Správa m sa pridá do frontu. Pripočíta sa vypočítaná veľkosť blokov údajov veľkosť.

Prenos všetkých správ z frontu údajov o prepojení do vyrovnávacej pamäte q:

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

Prenos správ z odkazu q vo vyrovnávacej pamäti sa vykonáva pomocou funkcie ms_bufferizer_put().

Čítanie z vyrovnávacej pamäte:

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

Ak je veľkosť údajov nahromadených vo vyrovnávacej pamäti menšia ako požadovaná (datalen), potom funkcia vráti nulu, údaje sa neskopírujú do údajov. V opačnom prípade sa vykoná sekvenčné kopírovanie údajov z n-tic umiestnených vo vyrovnávacej pamäti. Po skopírovaní sa n-tica vymaže a pamäť sa uvoľní. Kopírovanie sa ukončí v momente, keď sa skopírujú bajty dátových údajov. Ak sa uprostred bloku údajov minie miesto, v tejto správe sa blok údajov zmenší na zostávajúcu neskopírovanú časť. Keď nabudúce zavoláte, kopírovanie bude pokračovať od tohto bodu.

Čítanie množstva údajov, ktoré je momentálne k dispozícii vo vyrovnávacej pamäti:

int ms_bufferizer_get_avail(MSBufferizer *obj); 

Vráti pole veľkosť vyrovnávacej pamäte.

Vymazanie časti údajov vo vyrovnávacej pamäti:

void ms_bufferizer_skip_bytes(MSBufferizer *obj, int bytes);

Zadaný počet bajtov údajov sa získa a zahodí. Najstaršie údaje sa vyradia.

Odstránenie všetkých správ vo vyrovnávacej pamäti:

void ms_bufferizer_flush(MSBufferizer *obj); 

Počítadlo údajov sa vynuluje.

Odstránenie všetkých správ vo vyrovnávacej pamäti:

void ms_bufferizer_uninit(MSBufferizer *obj); 

Počítadlo sa nevynuluje.

Odstránenie vyrovnávacej pamäte a uvoľnenie pamäte:

void ms_bufferizer_destroy(MSBufferizer *obj);  

Príklady použitia vyrovnávacej pamäte možno nájsť v zdrojovom kóde niekoľkých filtrov streamovania médií. Napríklad vo filtri MS_L16_ENC, ktorý preusporiadava bajty vo vzorkách zo sieťového poradia na hostiteľské poradie: l16.c

V ďalšom článku sa pozrieme na problematiku odhadu zaťaženia tickera a na to, ako sa vysporiadať s nadmerným výpočtovým zaťažením v streameri médií.

Zdroj: hab.com

Pridať komentár