Studujeme VoIP engine Mediastreamer2. Část 11

Materiál článku je převzat z mého zenového kanálu.

Studujeme VoIP engine Mediastreamer2. Část 11

Mechanismus přenosu dat

  • Datový blok dblk_t
  • Zpráva mblk_t
  • Funkce pro práci se zprávami mblk_t
  • Fronta queue_t
  • Funkce pro práci s frontami queue_t
  • Spojení filtrů
  • Signální bod grafu zpracování dat
  • Pozadí činnosti tickeru
  • Bufferizátor (MSBufferizer)
  • Funkce pro práci s MSBufferizer

V minulosti článku Vytvořili jsme si vlastní filtr. Tento článek věnujeme uspořádání vnitřního mechanismu přenosu dat mezi filtry mediastreameru. To umožní psaní sofistikovaných filtrů s menšími nároky.

Mechanismus přenosu dat

Přenášení dat v mediastreameru se provádí pomocí front popsaných strukturou queue_t. Přes fronty se přenášejí série zpráv typu mblk_t, které samy o sobě neobsahují data signálu, ale pouze odkazy na předchozí, následující zprávu a na datový blok. Kromě toho bych rád zdůraznil, že existuje také pole pro odkaz na zprávu stejného typu, které umožňuje organizovat jednosměrný seznam zpráv. Skupinu zpráv, spojených takovým seznamem, budeme nazývat tuple. Takže jakýkoliv prvek fronty může být jednotlivou zprávou mblk_t, nebo může být hlavou skupiny zpráv mblk_t. Každá zpráva tuple může mít svůj vlastní datový blok. O důvodech existence tuple budeme hovořit později.

Jak již bylo zmíněno, zpráva sama o sobě neobsahuje datový blok, místo toho obsahuje pouze ukazatel na oblast paměti, kde je blok uchován. V této části celkový obraz práce mediastreameru připomíná sklad dveří z animovaného filmu "Jak vycvičit draka", kde dveře (odkazy na data — místnosti) se šílenou rychlostí pohybují po zavěšených dopravnících, přičemž samotné místnosti zůstávají nehybné.

Nyní, pohybující se hierarchií zdola nahoru, podívejme se podrobně na uvedené entity mechanismu přenosu dat v mediastreameru.

Datový blok dblk_t

Datový blok se skládá z hlavičky a datového bufferu. Hlavička je popsána následující strukturou,

typedef struct datab
{
unsigned char *db_base; // Ukazatel na začátek datového bufferu.
unsigned char *db_lim;  // Ukazatel na konec datového bufferu.
void (*db_freefn)(void*); // Funkce pro uvolnění paměti při mazání bloku.
int db_ref; // Počítadlo odkazů.
} dblk_t;

Pole struktury obsahují ukazatele na začátek vyrovnávací paměti, konec vyrovnávací paměti a funkci pro odstranění datové vyrovnávací paměti. Poslední prvek v hlavičce db_ref — počet odkazů, pokud dosáhne nuly, slouží jako signál k odstranění tohoto bloku z paměti. Pokud byl blok dat vytvořen funkcí datab_alloc() , pak bude datová vyrovnávací paměť umístěna v paměti přímo za hlavičkou. Ve všech ostatních případech může být vyrovnávací paměť umístěna někde jinde. Ve vyrovnávací paměti budou umístěny signální vzorky nebo jiná data, která chceme zpracovávat pomocí filtrů.

Nový blok dat je vytvořen pomocí funkce:

dblk_t *datab_alloc(int size);

Jako vstupní parametr je jí předáván velikost dat, která bude blok uchovávat. Paměť je alokována větší, aby na začátku alokované paměti bylo možné umístit hlavičku — strukturu datab. Při použití jiných funkcí to však tak vždy nefunguje, v některých případech může být datová vyrovnávací paměť umístěna odděleně od hlavičky bloku dat. Pole struktury jsou při vytváření nastavena tak, aby její pole db_base ukazovalo na začátek oblasti dat, a db_lim na její konec. Počítadlo odkazů db_ref se nastavuje na jednotku. Ukazatel na funkci pro vyčištění dat se nastavuje na nulu.

Zpráva mblk_t

Jak bylo řečeno, prvky fronty mají typ mblk_t, je definován následovně:

typedef struct msgb
{
  struct msgb *b_prev;   // Ukazatel na předchozí prvek seznamu.
  struct msgb *b_next;   // Ukazatel na následující prvek seznamu.
  struct msgb *b_cont;   // Ukazatel pro podlepování k zprávě jiných zpráv, za účelem vytvoření kroužku zpráv.
  struct datab *b_datap; // Ukazatel na strukturu bloku dat.
  unsigned char *b_rptr; // Ukazatel na začátek oblasti dat pro čtení dat vyrovnávací paměti b_datap.
  unsigned char *b_wptr; // Ukazatel na začátek oblasti dat pro zápis dat vyrovnávací paměti b_datap.
  uint32_t reserved1;    // Rezervované pole1, mediastreamer ukládá informace o službě tam. 
  uint32_t reserved2;    // Rezervované pole2, mediastreamer ukládá informace o službě tam.
  #if defined(ORTP_TIMESTAMP)
  struct timeval timestamp;
  #endif
  ortp_recv_addr_t recv_addr;
} mblk_t;

Struktura mblk_t na začátku obsahuje ukazatele b_prev, b_next, které jsou nezbytné pro organizaci obousměrného seznamu (kterým je fronta queue_t).

Následuje ukazatel b_cont, který se používá pouze tehdy, když zpráva vstupuje do tuple. Pro poslední zprávu v tuplu tento ukazatel zůstává nulový.

Dále vidíme ukazatel na datový blok b_datap, pro který existuje zpráva. Následují ukazatele na oblast uvnitř datového bufferu bloku. Pole b_rptr ukazuje místo, odkud se budou číst data z bufferu. Pole b_wptr ukazuje místo, odkud se budou zapisovat data do bufferu.

Zbylá pole mají servisní charakter a nejsou relevantní pro fungování mechanismu přenosu dat.

Níže je znázorněna jednotlivá zpráva s názvem m1 a datovým blokem d1.
Studujeme VoIP engine Mediastreamer2. Část 11
Na následujícím obrázku je zobrazen tuple ze tří zpráv m1, m1_1, m1_2.
Studujeme VoIP engine Mediastreamer2. Část 11

Funkce pro práci se zprávami mblk_t

Nová zpráva mblk_t je vytvářena funkcí:

mblk_t *allocb(int size, int pri); 

ta alokuje v paměti novou zprávu mblk_t s datovým blokem dané velikosti size, druhý argument — pri se ve zvažované verzi knihovny nepoužívá. Měl by zůstat nulový. Během fungování funkce bude alokována paměť pro strukturu nové zprávy a bude vyvolána funkce mblk_init(), která nulová všechna pole vytvořeného instance struktury a poté, s pomocí výše zmíněného, datab_alloc()vytvoří datový buffer. Poté dojde k nastavení polí ve struktuře:

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ýstupu získáme novou zprávu s inicializovanými poli a prázdným datovým bufferem. Chcete-li do zprávy přidat data, je nutné provést jejich kopii do bufferu datového bloku:

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

kde data — ukazatel na zdroj dat, a size — jejich velikost.
Poté je nutné aktualizovat ukazatel na místo zápisu, aby opět ukazoval na začátek volného místa v bufferu:

msg->b_wptr = msg->b_wptr + size

Pokud je potřeba vytvořit zprávu z již existujícího bufferu, bez kopírování, pak se k tomu používá funkce:

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

Funkce po vytvoření zprávy a struktury datového bloku nastaví její ukazatele na údaje na adrese buf. T.j. v tomto případě se datový buffer nenachází za poli hlavičky datového bloku, jak tomu bylo při vytváření datového bloku funkcí datab_alloc()Předaná funkci buffer s daty zůstane tam, kde byl, ale pomocí ukazatelů bude posunut k právě vytvořené hlavičce bloku dat, a ta samozřejmě k zprávě.

K jedné zprávě mblk_t mohou být postupně připojeny několik bloků dat. To se provádí funkcí:

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

mp — zpráva, k které bude přidán další blok dat;
data — ukazatel na blok, jehož kopie bude přidána do zprávy;
size — velikost dat;
pad — příznak, že velikost alokované paměti by měla být zarovnána na hranici 4 bajtů (doplnění bude provedeno nulami).

Pokud v existujícím bufferu dat zprávy je dostatek místa, nové údaje budou přilepeny za již existujícími tam daty. Pokud bude volného místa v bufferu dat zprávy méně než size, vytvoří se nová zpráva s dostatečnou velikostí bufferu a data se zkopírují do jejího bufferu. Tato nová zpráva se připojí k původní pomocí ukazatele b_cont. V tomto případě se zpráva promění v tuple.

Pokud do tuple je třeba přidat další blok dat, je třeba použít funkci:

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

ta najde poslední zprávu v tuple (ta b_cont bude nulová) a zavolá pro tuto zprávu funkci appendb().

Zjistit velikost dat ve zprávě nebo tuple lze pomocí funkce:

int msgdsize(const mblk_t *mp);

ta projde všemi zprávami tuple a vrátí celkový počet dat v buferch dat těchto zpráv. Pro každou zprávu se množství dat vypočítává takto:

 mp->b_wptr - mp->b_rptr

K sjednocení dvou tuple se používá funkce:

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

ta připojí tuple newm na konec tuple mp a vrátí ukazatel na poslední zprávu vzniklé tuplé.

Pokud je to nutné, můžeme tuple převést na jednu zprávu s jednotným blokem dat, to se provádí funkcí:

void msgpullup(mblk_t *mp,int len);

pokud je argument len rovný -1, pak je velikost vyčleněného bufferu určena automaticky. Pokud len Pokud je číslo kladné, bude vytvořen vyrovnávací paměť této velikosti a do něj budou zkopírována data zpráv tuplíru. Pokud paměť skončí, kopírování se zastaví. První zpráva tuplíru obdrží vyrovnávací paměť nové velikosti se zkopírovanými daty. Ostatní zprávy budou odstraněny a paměť vrácena do haldy.

Při odstraňování struktury mblk_t se zohledňuje čítač referencí bloku dat, pokud při vyvolání freeb() bude rovno nule, pak bude datová paměť odstraněna spolu s instancí mblk_t, na kterou ukazuje.

Inicializace polí nové zprávy:

void mblk_init(mblk_t *mp);

Přidání další dávky dat do zprávy:

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

Pokud nová data nezapadnou do volného místa vyrovnávací paměti zprávy, je k zprávě připojena samostatně vytvořená zpráva s vyrovnávací pamětí potřebné velikosti (v první zprávě je nastavena ukazatel na přidanou zprávu) zpráva se promění na tuplír.

Přidání dávky dat do tuplíru:

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

Funkce volá appendb() v cyklu.

Slučování dvou tuplírů do jednoho:

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

Zpráva newm bude připojeno k mp.

Vytvoření kopie jednotlivé zprávy:

mblk_t *copyb(const mblk_t *mp);

Úplné kopírování tuplíru se všemi bloky dat:

mblk_t *copymsg(const mblk_t *mp);

Prvky tuplíru jsou při tom kopírovány funkcí copyb().

Vytvoření lehké kopie zprávy mblk_t. Při tom není blok dat kopírován, ale zvyšuje se čítač jeho referencí db_ref:

mblk_t *dupb(mblk_t *mp);

Vytvoření lehké kopie tuplíru. Bloky dat nejsou kopírovány, pouze se zvyšují jejich čítače referencí db_ref:

mblk_t *dupmsg(mblk_t* m);

Slučení všech zpráv tuplíru do jedné zprávy:

void msgpullup(mblk_t *mp,size_t len);

Pokud je argument len rovnán -1, pak je velikost vyhrazené vyrovnávací paměti určena automaticky.

Odstranění zprávy, tuplíru:

void freemsg(mblk_t *mp);

Čítač referencí bloku dat se snižuje o jednu. Pokud přitom dosáhne nuly, bloku dat je také odstraněn.

Počítání celkového objemu dat ve zprávě nebo tuplíru.

size_t msgdsize(const mblk_t *mp);

Extrakce zprávy z konce fronty:

mblk_t *ms_queue_peek_last (q);

Kopírování obsahu rezervovaných polí jedné zprávy do jiné zprávy (ve skutečnosti se v těchto polích nacházejí flagy, které používá mediastreamer):

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

Fronta queue_t

Fronta zpráv ve streamovacím médiu je realizována jako kruhový obousměrný seznam. Každý prvek seznamu obsahuje ukazatel na blok dat se záznamy signálu. To znamená, že se po frontě pohybují pouze ukazatele na blok dat, zatímco samotná data zůstávají na svém místě. Tedy se pohybují pouze odkazy na ně.
Struktura popisující frontu queue_t, je znázorněna níže:

typedef struct _queue
{
   mblk_t _q_stopper; 
   /* "Prázdný" prvek fronty, neukazuje na data, používá se pouze pro řízení fronty. Při inicializaci fronty (qinit()) jsou jeho ukazatele nastaveny tak, aby ukazovaly na něj samotného. */
   int q_mcount;        // Počet prvků ve frontě.
} queue_t;

Struktura obsahuje pole – ukazatel _q_stopper typu *mblk_t, ukazuje na první prvek (zprávu) ve frontě. Druhé pole struktury je čítač zpráv, které se nacházejí ve frontě.
Na obrázku níže je znázorněna fronta s názvem q1, obsahující 4 zprávy m1,m2, m3, m4.
Studujeme VoIP engine Mediastreamer2. Část 11
Na následujícím obrázku je znázorněna fronta s názvem q1, obsahující 4 zprávy m1,m2, m3, m4. Zpráva m2 je hlavou n-tice, do níž vedou ještě dvě zprávy m2_1 a m2_2.

Studujeme VoIP engine Mediastreamer2. Část 11

Funkce pro práci s frontami queue_t

Inicializace fronty:

void qinit(queue_t *q);

Pole _q_stopper (následně budeme nazývat "stopor") je inicializován funkcí mblk_init(), jeho ukazatel předchozího prvku a následujícího prvku jsou nastaveny tak, aby ukazovaly na něj samotného. Čítač prvků fronty se nastavuje na nulu.

Přidání nového prvku (zprávy):

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

Nový prvek m je přidán na konec seznamu, ukazatele prvku se nastavují tak, aby se stopor stal pro něj dalším prvkem, a on pro stopor předchozím. Čítač prvků fronty se inkrementuje.

Vyjmutí prvku z fronty:

mblk_t * getq(queue_t *q); 

vyjímá se ta zpráva, která stojí za stoporem, čítač prvků se dekrementuje. Pokud ve frontě kromě stoporu nejsou žádné prvky, vrací se 0.

Vložení zprávy do fronty:

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

Prvek mp je vložen před prvek emp. Pokud emp=0, takže se zpráva přidá na konec fronty.

Vyjmutí zprávy z hlavy fronty:

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

Čítač prvků se dekrementuje.

Čtení ukazatele na první prvek ve frontě:

mblk_t * peekq(queue_t *q); 

Odstranění všech prvků z fronty se odstraněním samotných prvků:

void flushq(queue_t *q, int how);

Argument jak není používán. Počítadlo prvků fronty se nastaví na nulu.

Makro pro čtení ukazatele na poslední prvek fronty:

mblk_t * qlast(queue_t *q);

Při práci s frontami zpráv je třeba mít na paměti, že při volání ms_queue_put(q, m) s nulovým ukazatelem na zprávu se funkce zacyklí. Vaše aplikace se zasekne. Podobně se chová ms_queue_next(q, m).

Spojení filtrů

Uváděná fronta se používá k přenosu zpráv z jednoho filtru na druhý nebo z jednoho na několik filtrů. Filtry a jejich propojení mezi sebou tvoří orientovaný graf. Vstup nebo výstup filtru budeme nazývat souhrnným názvem "pin". K popisu pořadí propojení filtrů se v mediastreameru používá pojem "signální bod". Signální bod je struktura _MSCPoint, která obsahuje ukazatel na filtr a číslo jednoho z jeho pinů, popisuje tedy propojení jednoho z vchodů nebo výstupů filtru.

Signální bod grafu zpracování dat

typedef struct _MSCPoint{
struct _MSFilter *filter; // Ukazatel na filtr mediastreameru.
int pin;                        // Číslo jednoho z vchodů nebo výstupů filtru, tj. pin.
} MSCPoint;

Piny filtrů jsou číslovány od nuly.

Propojení dvou pinů frontou zpráv je popsáno strukturou _MSQueue, která obsahuje frontu zpráv a ukazatele na dva signální body, které propojuje:

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

Budeme tuto strukturu nazývat signálním linkem. Každý filtr mediastreameru obsahuje tabulku vstupních odkazů a tabulku výstupních odkazů (MSQueue). Velikost tabulek je nastavena při vytváření filtru, což jsme již udělali pomocí exportované proměnné typu MSFilterDesc, když jsme vyvíjeli náš vlastní filtr. Následuje struktura popisující jakýkoli filtr v mediastreameru, MSFilter:


struct _MSFilter{
    MSFilterDesc *desc;    
    /* Ukazatel na popisovač filtru. */
    /* Ochranné atributy, které nelze přesunout nebo odstranit, jinak dojde k porušení práce s pluginy. */
    ms_mutex_t lock;      /* Semafor. */
    MSQueue **inputs;     /* Tabulka vstupních odkazů. */
    MSQueue **outputs;    /* Tabulka výstupních odkazů. */
    struct _MSFactory *factory; /* Ukazatel na továrnu, která vytvořila tuto instanci filtru. */
    void *padding;              /* Nepoužívá se, bude využito, pokud budou přidána chráněná pole. */
    void *data;                 /* Ukazatel na libovolnou strukturu pro uchování dat interního stavu filtru a mezivýpočtů. */
    struct _MSTicker *ticker;   /* Ukazatel na objekt tikera, který nesmí být nulový, když je volána funkce process(). */
    /* soukromé atributy, mohou být kdykoli přesunuty a změněny */
    MSList *notify_callbacks; /* Seznam zpětných volání, které se používají k zpracování událostí filtru. */
    uint32_t last_tick;       /* Číslo posledního cyklu, kdy byla volána funkce process(). */
    MSFilterStats *stats;     /* Statistiky práce filtru. */
    int postponed_task; /* Počet odložených úloh. Některé filtry mohou odložit zpracování dat (volání process()) na několik cyklů. */
    bool_t seen;  /* Flag, který používá tikker k označení, že tuto instanci filtru již obsloužil v tomto cyklu. */
};
typedef struct _MSFilter MSFilter;

Poté, co jsme ve své C-programu spojili filtry podle našeho záměru (ale nepřipojili jsme tikker), jsme tím vytvořili orientovanou grafovou strukturu, jejíž uzly tvoří instance struktury MSFilter, a hrany to jsou instance odkazů MSQueue.

Pozadí činnosti tickeru

Když jsem vám říkal, že tikker je zdrojový filtr taktu, nebyla to celá pravda o něm. Tikker je objekt, který pravidelně spouští funkce process() všech filtrů schématu (grafu), ke kterým je připojen. Když v C-programu připojujeme tikker k filtru grafu, ukazujeme tikkeru graf, který od té doby bude řídit, dokud ho neodpojíme. Po připojení tikker začíná prohlížet jemu svěřený graf, sestavuje seznam filtrů, které do něj patří. Aby ne 'počítal' stejný filtr dvakrát, označuje nalezené filtry, nastavuje v nich příznak seen. Vyhledávání se provádí v tabulkách odkazů, které má každý filtr.

Během své úvodní prohlídky grafu ticker kontroluje, zda je mezi filtry alespoň jeden, který funguje jako zdroj datových bloků. Pokud takový filtr nenajde, je graf považován za neplatný a ticker se neočekávaně ukončí.

Pokud je graf "platný", pro každý nalezený filtr se při inicializaci volá funkce preprocess(). Jakmile nastane čas pro další zpracovatelský cyklus (výchozí interval je každých 10 milisekund), ticker vyvolá funkci process() pro všechny dříve nalezené zdrojové filtry a poté i pro ostatní filtry seznamu. Pokud filtr má vstupní linky, vyvolání funkce process() se opakuje, dokud se vstupní fronty nevyprázdní. Poté přechází k dalšímu filtrujícímu prvku seznamu a "posune" jej, dokud nejsou vstupní linky bez zpráv. Ticker přechází od filtru k filtru, dokud seznam neskončí. Tímto zpracování cyklu končí.

Nyní se vrátíme k n-ticím a probereme, proč byla do mediastreameru přidána taková entita. Obecně platí, že objem dat potřebný algoritmu, který pracuje uvnitř filtru, se neshoduje a není násobkem objemu dat přicházejících na vstupu. Například píšeme filtr, který provádí rychlou Fourierovu transformaci, jež podle definice může zpracovávat pouze datové bloky, jejichž velikost je mocnina dvou. Předpokládejme, že je to 512 vzorků. Pokud jsou data generována telefonním kanálem, pak datový buffer každé zprávy na vstupu přináší 160 vzorků signálu. Existuje lákavá tendence neodebírat data ze vstupu, dokud tam nebude potřebné množství dat. V takovém případě však dojde ke kolizi s tickerem, který se bezvýsledně pokouší posunout filtr k vyprázdnění vstupního linku. Dříve jsme toto pravidlo nazvali třetím principem fungování filtru. Podle tohoto principu musí funkce process() filtru odebrat všechna data z vstupních front.

Kromě toho nebude možné na vstupu získat pouze 512 vzorků, protože je možné je brát pouze po celých blocích, tj. filtr bude muset vzít 640 vzorků a použít 512 z nich, zbytek až do načtení nové dávky dat. Tímto způsobem musí náš filtr, kromě své hlavní práce, zajistit také pomocné akce pro meziskladování vstupních dat. Vývojáři mediastreameru pro řešení této obecné úlohy vyvinuli speciální objekt — MSBufferizer (bufferizátor), který tuto úlohu řeší pomocí n-tic.

Bufferizátor (MSBufferizer)

Tento objekt bude hromadit vstupní data uvnitř filtru a začne je vydávat k zpracování, jakmile se množství informací ukáže jako dostatečné pro provedení algoritmu filtru. Zatímco bufferizátor shromažďuje data, filtr bude pracovat v prázdném režimu, nevynaložuje žádné výpočetní zdroje procesoru. Ale jakmile funkce čtení z bufferizátoru vrátí hodnotu jinou než nula, funkce process() filtru začne brát a zpracovávat z bufferizátoru data po dávkách potřebné velikosti, až do jejich vyčerpání.
Dosud nevyužitá data zůstávají v bufferizátoru jako první prvek n-tice, ke kterému se připojují následné bloky vstupních dat.

Struktura, která popisuje bufferizátor:

struct _MSBufferizer{
queue_t q; /* Fronta zpráv. */
int size; /* Celková velikost dat, která se právě nacházejí v bufferizátoru. */
};
typedef struct _MSBufferizer MSBufferizer;

Funkce pro práci s MSBufferizer

Vytvoření nové instance bufferizátoru:

MSBufferizer * ms_bufferizer_new(void);

Vyhrazuje se paměť, inicializuje se v ms_bufferizer_init() a vrací se ukazatel.

Funkce inicializace:

void ms_bufferizer_init(MSBufferizer *obj); 

Inicializuje se fronta q, pole size nastavuje se na nulu.

Přidání zprávy:

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

Zpráva m se přidá do fronty. Vypočtená velikost bloků dat se přidá k size.

Přesun do bufferizátoru všech zpráv fronty datového linku q:

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

Přenos zpráv z linky q do bufferizátoru se provádí pomocí funkce ms_bufferizer_put().

Čtení z bufferizátoru:

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

Pokud velikost akumulovaných v bufferizátoru dat je menší než požadovaná (datalen), funkce vrátí nula, kopírování dat do data se neprovádí. Jinak se provádí sekvenční kopírování dat z n-tic nacházejících se v bufferu. Po zkopírování se n-tice vymaže a paměť se uvolní. Kopírování končí v momentě, kdy je zkopírováno datalen bajtů. Pokud místo skončí uprostřed bloku dat, tento blok dat bude zkrácen na zbývající zkopírovanou část. Při dalším volání bude kopírování pokračovat od tohoto místa.

Čtení počtu dat, která jsou v tuto chvíli dostupná v bufferu:

int ms_bufferizer_get_avail(MSBufferizer *obj); 

Vrátí pole size bufferizéru.

Zahodí část dat, která se nacházejí v bufferu:

void ms_bufferizer_skip_bytes(MSBufferizer *obj, int bytes);

Uvedené množství bajtů dat se vytáhne a zahodí. Zahazuje se nejstarší data.

Odstranění všech zpráv nacházejících se v bufferu:

void ms_bufferizer_flush(MSBufferizer *obj); 

Čítač dat se resetuje na nula.

Odstranění všech zpráv nacházejících se v bufferu:

void ms_bufferizer_uninit(MSBufferizer *obj); 

Resetování čítače se neprovádí.

Odstranění bufferu a uvolnění paměti:

void ms_bufferizer_destroy(MSBufferizer *obj);  

Příklady použití bufferu lze nalézt v zdrojovém kódu několika filtrů mediastreamera. Například ve filtru MS_L16_ENC, který provádí přeskupení bajtů v měření ze síťového pořadí do pořadí hostitele: l16.c

V následujícím článku se budeme zabývat otázkou hodnocení zatížení tickeru a způsoby, jak se vypořádat s nadměrnou výpočetní zátěží v mediastreameru.

Zdroj: habr.com

Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery 🔥 Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery | ProHoster