Explorarea motorului VoIP Mediastreamer2. Partea 11

Materialul articolului este preluat de pe mine canal zen.

Explorarea motorului VoIP Mediastreamer2. Partea 11

Mecanismul de mișcare a datelor

  • Bloc de date dblk_t
  • Mesaj mblk_t
  • Funcții pentru lucrul cu mesajele mblk_t
  • coadă coadă_t
  • Funcții pentru lucrul cu cozi queue_t
  • Conectarea filtrelor
  • Punctul de semnal al graficului de prelucrare a datelor
  • Activitățile din culise ale tickerului
  • Bufferizer (MSBufferizer)
  • Funcții pentru lucrul cu MSBufferizer

În trecut articol am dezvoltat propriul nostru filtru. Acest articol se va concentra asupra mecanismului intern de mutare a datelor între filtrele de streamer media. Acest lucru vă va permite să scrieți filtre sofisticate cu mai puțin efort în viitor.

Mecanismul de mișcare a datelor

Mișcarea datelor în streamer-ul media se realizează folosind cozile descrise de structură coada_t. Șiruri de mesaje ca mblk_t, care ele însele nu conțin date de semnal, ci doar legături către mesajul anterior, următorul și către blocul de date. În plus, vreau să subliniez în mod special faptul că există și un câmp pentru un link către un mesaj de același tip, care vă permite să organizați o listă de mesaje conectată individual. Vom numi tuplu un grup de mesaje unite printr-o astfel de listă. Astfel, orice element al cozii poate fi un singur mesaj mblk_t, și poate capul unui tuplu de mesaj mblk_t. Fiecare mesaj tuplu poate avea propriul bloc de date ale secției. Vom discuta de ce sunt necesare tupluri puțin mai târziu.

După cum sa menționat mai sus, mesajul în sine nu conține un bloc de date; în schimb, conține doar un pointer către zona de memorie în care este stocat blocul. În această parte, imaginea de ansamblu a muncii streamerului media amintește de depozitul de uși din desenul animat „Monsters, Inc.”, unde ușile (linkuri către camere de date) se mișcă cu o viteză nebună de-a lungul transportoarelor aeriene, în timp ce încăperile în sine. rămâne nemișcat.

Acum, deplasându-ne de-a lungul ierarhiei de jos în sus, să luăm în considerare în detaliu entitățile enumerate ale mecanismului de transmitere a datelor în streamer-ul media.

Bloc de date dblk_t

Blocul de date constă dintr-un antet și un buffer de date. Antetul este descris de următoarea structură,

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

Câmpurile structurii conțin pointeri către începutul buffer-ului, sfârșitul buffer-ului și funcția de ștergere a tamponului de date. Ultimul element din antet db_ref — contor de referință, dacă ajunge la zero, acesta servește drept semnal pentru ștergerea acestui bloc din memorie. Dacă blocul de date a fost creat de funcție datab_alloc() , apoi tamponul de date va fi plasat în memorie imediat după antet. În toate celelalte cazuri, tamponul poate fi localizat undeva separat. Bufferul de date va conține mostre de semnal sau alte date pe care dorim să le procesăm cu filtre.

O nouă instanță a unui bloc de date este creată folosind funcția:

dblk_t *datab_alloc(int size);

Ca parametru de intrare, i se dă dimensiunea datelor pe care blocul le va stoca. Este alocată mai multă memorie pentru a plasa un antet - structură - la începutul memoriei alocate dateb. Dar atunci când utilizați alte funcții, acest lucru nu se întâmplă întotdeauna; în unele cazuri, tamponul de date poate fi localizat separat de antetul blocului de date. La crearea unei structuri, câmpurile sunt configurate astfel încât câmpul acesteia db_base a indicat începutul zonei de date și db_lim până la capătul ei. Număr de linkuri db_ref este setat la unu. Indicatorul funcției de ștergere a datelor este setat la zero.

Mesaj mblk_t

După cum sa menționat, elementele de coadă sunt de tip mblk_t, este definit astfel:

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;

Structura mblk_t conține indicatori la început b_prev, b_next, care sunt necesare pentru a organiza o listă dublu legată (care este o coadă coada_t).

Apoi vine indicatorul b_cont, care este folosit numai atunci când mesajul face parte dintr-un tuplu. Pentru ultimul mesaj din tuplu, acest indicator rămâne nul.

Apoi vedem un pointer către un bloc de date b_datap, pentru care mesajul există. Este urmată de pointeri către zona din interiorul tamponului de date bloc. Camp b_rptr specifică locația din care vor fi citite datele din buffer. Camp b_wptr indică locația din care vor fi efectuate scrierile în buffer.

Câmpurile rămase sunt de natură de serviciu și nu se referă la funcționarea mecanismului de transfer de date.

Mai jos este un singur mesaj cu numele m1 și bloc de date d1.
Explorarea motorului VoIP Mediastreamer2. Partea 11
Figura următoare prezintă un tuplu de trei mesaje m1, m1_1, m1_2.
Explorarea motorului VoIP Mediastreamer2. Partea 11

Funcții de mesagerie mblk_t

Un mesaj nou mblk_t creat de funcția:

mblk_t *allocb(int size, int pri); 

ea plasează un nou mesaj în memorie mblk_t cu un bloc de date de dimensiunea specificată mărimea, al doilea argument - pri nu este utilizat în această versiune a bibliotecii. Ar trebui să rămână zero. În timpul funcționării funcției, va fi alocată memorie pentru structura noului mesaj și va fi apelată funcția mblk_init(), care va reseta toate câmpurile instanței create a structurii și apoi, folosind cele menționate mai sus datab_alloc(), va crea un buffer de date. După care se vor configura câmpurile din structură:

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

La ieșire primim un mesaj nou cu câmpuri inițializate și un buffer de date gol. Pentru a adăuga date la un mesaj, trebuie să-l copiați în buffer-ul blocului de date:

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

unde de date este un pointer către sursa de date și mărimea - dimensiunea lor.
apoi trebuie să actualizați indicatorul la punctul de scriere, astfel încât să indice din nou la începutul zonei libere din buffer:

msg->b_wptr = msg->b_wptr + size

Dacă trebuie să creați un mesaj dintr-un buffer existent, fără a copia, atunci utilizați funcția:

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

Funcția, după crearea mesajului și a structurii blocului de date, își va configura pointerii către datele de la adresa buf. Acestea. în acest caz, tamponul de date nu este localizat după câmpurile antet ale blocului de date, așa cum a fost cazul la crearea unui bloc de date cu funcția datab_alloc(). Buffer-ul cu datele trecute funcției va rămâne acolo unde a fost, dar cu ajutorul pointerilor va fi atașat la antetul nou creat al blocului de date și, în consecință, la mesaj.

La un mesaj mblk_t Mai multe blocuri de date pot fi concatenate secvenţial. Acest lucru se realizează prin funcția:

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

mp — un mesaj la care se va adăuga un alt bloc de date;
de date — pointer către bloc, a cărui copie va fi adăugată la mesaj;
mărimea - dimensiunea datelor;
tampon — un semnalizare conform căreia dimensiunea memoriei alocate trebuie să fie aliniată de-a lungul unei granițe de 4 octeți (completarea se va face cu zerouri).

Dacă există suficient spațiu în buffer-ul de date pentru mesaje existent, atunci noile date vor fi lipite în spatele datelor deja existente. Dacă există mai puțin spațiu liber în memoria tampon de date pentru mesaje decât mărimea, apoi se creează un mesaj nou cu o dimensiune suficientă a memoriei tampon și datele sunt copiate în memoria tampon. Acesta este un mesaj nou, legat de cel original folosind un indicator b_cont. În acest caz, mesajul se transformă într-un tuplu.

Dacă trebuie să adăugați un alt bloc de date la tuplu, atunci trebuie să utilizați funcția:

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

ea va găsi ultimul mesaj în tuplu (el are b_cont va fi nul) și va apela funcția pentru acest mesaj appendb().

Puteți afla dimensiunea datelor dintr-un mesaj sau tuplu folosind funcția:

int msgdsize(const mblk_t *mp);

va parcurge toate mesajele din tuplu și va returna cantitatea totală de date din bufferele de date ale acestor mesaje. Pentru fiecare mesaj, cantitatea de date este calculată după cum urmează:

 mp->b_wptr - mp->b_rptr

Pentru a combina două tupluri, utilizați funcția:

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

ea adaugă tuplu noum la coada tuplului mp și returnează un pointer la ultimul mesaj al tuplului rezultat.

Dacă este necesar, un tuplu poate fi transformat într-un singur mesaj cu un singur bloc de date; acest lucru se realizează prin funcția:

void msgpullup(mblk_t *mp,int len);

dacă argument len este -1, atunci dimensiunea buffer-ului alocat este determinată automat. Dacă len este un număr pozitiv, va fi creat un buffer de această dimensiune și datele mesajului tuplu vor fi copiate în el. Dacă tamponul se epuizează, copierea se va opri acolo. Primul mesaj al tuplului va primi un nou buffer de dimensiune cu datele copiate. Mesajele rămase vor fi șterse, iar memoria va fi returnată în heap.

La ștergerea unei structuri mblk_t se ia în considerare numărul de referinţă al blocului de date dacă, la apelare freeb() se dovedește a fi zero, apoi tamponul de date este șters împreună cu instanța mblk_t, care indică.

Inițializarea câmpurilor unui mesaj nou:

void mblk_init(mblk_t *mp);

Adăugarea unei alte date la mesaj:

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

Dacă noile date nu se încadrează în spațiul liber al buffer-ului de date pentru mesaje, atunci mesajului este atașat un mesaj creat separat cu un buffer de dimensiunea necesară (un indicator către mesajul adăugat este setat în primul mesaj) și mesajul se transformă într-un tuplu.

Adăugarea unei date la un tuplu:

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

Funcția apelează appendb() într-o buclă.

Combinând două tupluri într-unul singur:

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

Mesaj noum va fi atașat la mp.

Realizarea unei copii a unui singur mesaj:

mblk_t *copyb(const mblk_t *mp);

Copierea completă a unui tuplu cu toate blocurile de date:

mblk_t *copymsg(const mblk_t *mp);

Elementele tuplului sunt copiate de funcție copyb().

Creați o copie ușoară a unui mesaj mblk_t. În acest caz, blocul de date nu este copiat, dar contorul său de referință este mărit db_ref:

mblk_t *dupb(mblk_t *mp);

Realizarea unei copii ușoare a unui tuplu. Blocurile de date nu sunt copiate, doar contoarele lor de referință sunt incrementate db_ref:

mblk_t *dupmsg(mblk_t* m);

Lipirea tuturor mesajelor unui tuplu într-un singur mesaj:

void msgpullup(mblk_t *mp,size_t len);

Dacă argumentul len este -1, atunci dimensiunea buffer-ului alocat este determinată automat.

Ștergerea unui mesaj, tuplu:

void freemsg(mblk_t *mp);

Numărul de referință al blocului de date este decrementat cu unu. Dacă ajunge la zero, blocul de date este și el șters.

Calculul cantității totale de date dintr-un mesaj sau tuplu.

size_t msgdsize(const mblk_t *mp);

Preluarea unui mesaj din coada cozii:

mblk_t *ms_queue_peek_last (q);

Copierea conținutului câmpurilor rezervate ale unui mesaj într-un alt mesaj (de fapt, aceste câmpuri conțin steaguri care sunt utilizate de streamer-ul media):

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

Întoarce-te coada_t

Coada de mesaje din streamer-ul media este implementată ca o listă circulară dublu legată. Fiecare element de listă conține un pointer către un bloc de date cu mostre de semnal. Se pare că doar pointerii către blocul de date se mișcă pe rând, în timp ce datele în sine rămân nemișcate. Acestea. sunt mutate doar linkurile către ele.
Structura care descrie coada coada_t, prezentat mai jos:

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

Structura conține un câmp - un pointer _q_stop tastați *mblk_t, indică primul element (mesaj) din coadă. Al doilea câmp al structurii este contorul de mesaje din coadă.
Figura de mai jos arată o coadă numită q1 care conține 4 mesaje m1, m2, m3, m4.
Explorarea motorului VoIP Mediastreamer2. Partea 11
Următoarea figură arată o coadă numită q1 care conține 4 mesaje m1,m2,m3,m4. Mesajul m2 este capul unui tuplu care conține încă două mesaje m2_1 și m2_2.

Explorarea motorului VoIP Mediastreamer2. Partea 11

Funcții pentru lucrul cu cozi queue_t

Inițializare coadă:

void qinit(queue_t *q);

Câmp _q_stop (în continuare îl vom numi „stop”) este inițializat de funcție mblk_init(), elementul său anterior și indicatorul elementului următor sunt ajustate pentru a indica el însuși. Contorul de elemente din coadă este resetat la zero.

Adăugarea unui nou element (mesaje):

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

Element nou m este adăugat la sfârșitul listei, pointerii elementului sunt ajustați astfel încât opritorul să devină următorul element pentru acesta și să devină elementul anterior pentru opritor. Contorul de elemente de coadă este incrementat.

Preluarea unui element din coadă:

mblk_t * getq(queue_t *q); 

Mesajul care vine după ce opritorul este preluat, iar contorul de elemente este decrementat. Dacă nu există elemente în coadă cu excepția opritorului, atunci este returnat 0.

Inserarea unui mesaj într-o coadă:

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

element mp introdus înaintea elementului emp. dacă emp=0, apoi mesajul este adăugat la coada cozii.

Preluarea unui mesaj de la capul cozii:

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

Contorul de elemente este decrementat.

Citirea unui pointer către primul element din coadă:

mblk_t * peekq(queue_t *q); 

Eliminarea tuturor elementelor din coadă în timp ce ștergeți elementele în sine:

void flushq(queue_t *q, int how);

Argument cum nefolosit. Contorul de elemente de coadă este setat la zero.

Macro pentru citirea unui pointer către ultimul element al cozii:

mblk_t * qlast(queue_t *q);

Când lucrați cu cozi de mesaje, rețineți că atunci când sunați ms_queue_put(q, m) cu un pointer nul către mesaj, funcția este în buclă. Programul tău se va îngheța. se comportă similar ms_queue_next(q, m).

Conectarea filtrelor

Coada descrisă mai sus este folosită pentru a trece mesaje de la un filtru la altul sau de la unul la mai multe filtre. Filtrele și conexiunile lor formează un grafic direcționat. Intrarea sau ieșirea filtrului va fi numită cuvântul general „pin”. Pentru a descrie ordinea în care filtrele sunt conectate între ele, streamer-ul media folosește conceptul de „punct de semnal”. Punctul de semnal este structura _MSCPoint, care conține un indicator către filtru și numărul unuia dintre pinii acestuia; în consecință, descrie conectarea uneia dintre intrările sau ieșirile filtrului.

Punctul de semnal al graficului de prelucrare a datelor

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

Pinii filtrului sunt numerotate începând de la zero.

Conexiunea a doi pini printr-o coadă de mesaje este descrisă de structură _MSQueue, care conține o coadă de mesaje și indicii către cele două puncte de semnal pe care le conectează:

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

Vom numi această structură o legătură de semnal. Fiecare filtru de streamer media conține un tabel de legături de intrare și un tabel de legături de ieșire (MSQueue). Mărimea tabelelor este setată la crearea unui filtru; am făcut deja acest lucru folosind o variabilă de tip exportată MSFilterDesc, când am dezvoltat propriul nostru filtru. Mai jos este o structură care descrie orice filtru dintr-un streamer media, 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;

După ce am conectat filtrele în programul C în conformitate cu planul nostru (dar nu am conectat ticker-ul), am creat astfel un grafic direcționat, ale cărui noduri sunt instanțe ale structurii MSFilter, iar marginile sunt exemple de legături MSQueue.

Activitățile din culise ale tickerului

Când v-am spus că ticker-ul este un filtru pentru sursa căpușelor, nu era tot adevărul despre el. Un ticker este un obiect care rulează funcții pe ceas proces() toate filtrele circuitului (grafic) la care este conectat. Când conectăm un ticker la un filtru de grafic într-un program C, arătăm tickerului graficul pe care îl va controla de acum înainte până când îl dezactivăm. După conectare, tickerul începe să examineze graficul încredințat îngrijirii sale, alcătuind o listă de filtre care îl includ. Pentru a nu „număra” același filtru de două ori, marchează filtrele detectate prin plasarea unei casete de selectare în ele văzut. Căutarea se efectuează folosind tabelele de linkuri pe care le are fiecare filtru.

În timpul turului său introductiv al graficului, tickerul verifică dacă printre filtre există cel puțin unul care acționează ca sursă de blocuri de date. Dacă nu există, atunci graficul este considerat incorect și ticker-ul se blochează.

Dacă graficul se dovedește a fi „corect”, pentru fiecare filtru găsit, funcția este apelată pentru inițializare preprocesare(). De îndată ce sosește momentul pentru următorul ciclu de procesare (la fiecare 10 milisecunde în mod implicit), tickerul apelează funcția proces() pentru toate filtrele sursă găsite anterior și apoi pentru filtrele rămase din listă. Dacă filtrul are legături de intrare, atunci rulați funcția proces() se repetă până când cozile de link-uri de intrare sunt goale. După aceasta, trece la următorul filtru din listă și îl „defilează” până când linkurile de intrare sunt libere de mesaje. Tickerul se mută de la filtru la filtru până la sfârșitul listei. Aceasta completează procesarea ciclului.

Acum vom reveni la tupluri și vom vorbi despre motivul pentru care o astfel de entitate a fost adăugată la streamer-ul media. În general, cantitatea de date cerută de algoritmul care funcționează în interiorul filtrului nu coincide și nu este un multiplu al mărimii bufferelor de date primite la intrare. De exemplu, scriem un filtru care realizează o transformare Fourier rapidă, care prin definiție poate procesa doar blocuri de date a căror dimensiune este o putere de două. Să fie 512 numere. Dacă datele sunt generate de un canal telefonic, atunci tamponul de date al fiecărui mesaj de la intrare ne va aduce 160 de mostre de semnal. Este tentant să nu colectați date de la intrare până când nu există cantitatea necesară de date. Dar, în acest caz, va avea loc o coliziune cu tickerul, care va încerca fără succes să deruleze filtrul până când linkul de intrare este gol. Anterior, am desemnat această regulă drept al treilea principiu al filtrului. Conform acestui principiu, funcția process() a filtrului trebuie să preia toate datele din cozile de intrare.

În plus, nu va fi posibil să luați doar 512 mostre de la intrare, deoarece puteți lua doar blocuri întregi, de exemplu. filtrul va trebui să ia 640 de mostre și să folosească 512 dintre ele, restul înainte de a acumula o nouă porțiune de date. Astfel, filtrul nostru, pe lângă activitatea sa principală, trebuie să ofere acțiuni auxiliare pentru stocarea intermediară a datelor de intrare. Dezvoltatorii media streamerului și soluția la această problemă generală au dezvoltat un obiect special - MSBufferizer (bufferer), care rezolvă această problemă folosind tupluri.

Bufferizer (MSBufferizer)

Acesta este un obiect care va acumula date de intrare în filtru și va începe să le trimită pentru procesare de îndată ce cantitatea de informații este suficientă pentru a rula algoritmul de filtru. În timp ce tamponul acumulează date, filtrul va funcționa în modul inactiv, fără a consuma puterea de procesare a procesorului. Dar de îndată ce funcția de citire din bufferer returnează o altă valoare decât zero, funcția process() a filtrului începe să preia și să proceseze date din bufferer în porțiuni de dimensiunea necesară, până când este epuizată.
Datele care nu sunt încă necesare rămân în buffer ca prim element al tuplului, la care sunt atașate blocurile ulterioare de date de intrare.

Structura care descrie tamponul:

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

Funcții pentru lucrul cu MSBufferizer

Crearea unei noi instanțe tampon:

MSBufferizer * ms_bufferizer_new(void);

Memoria este alocată, inițializată în ms_bufferizer_init() iar un pointer este returnat.

Funcția de inițializare:

void ms_bufferizer_init(MSBufferizer *obj); 

Coada se inițializează q, camp mărimea este setat la zero.

Adăugarea unui mesaj:

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

Mesajul m este adăugat la coadă. Se adaugă dimensiunea calculată a blocurilor de date mărimea.

Transferarea tuturor mesajelor din coada de date link în buffer q:

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

Transferarea mesajelor dintr-un link q în buffer se realizează cu ajutorul funcției ms_bufferizer_put().

Citirea din buffer:

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

Dacă dimensiunea datelor acumulate în buffer este mai mică decât cea solicitată (datalen), atunci funcția returnează zero, datele nu sunt copiate în date. În caz contrar, se realizează copierea secvențială a datelor de la tupluri situate în buffer. După copiere, tuplul este șters și memoria este eliberată. Copierea se termină în momentul în care sunt copiați octeții de date. Dacă spațiul se epuizează în mijlocul unui bloc de date, atunci în acest mesaj, blocul de date va fi redus la partea rămasă necopiată. Data viitoare când suni, copierea va continua din acest punct.

Citirea cantității de date disponibile în prezent în buffer:

int ms_bufferizer_get_avail(MSBufferizer *obj); 

Returnează câmpul mărimea tampon.

Aruncarea unei părți a datelor din buffer:

void ms_bufferizer_skip_bytes(MSBufferizer *obj, int bytes);

Numărul specificat de octeți de date sunt preluați și aruncați. Cele mai vechi date sunt eliminate.

Ștergerea tuturor mesajelor din buffer:

void ms_bufferizer_flush(MSBufferizer *obj); 

Contorul de date este resetat la zero.

Ștergerea tuturor mesajelor din buffer:

void ms_bufferizer_uninit(MSBufferizer *obj); 

Contorul nu este resetat.

Îndepărtarea tamponului și eliberarea memoriei:

void ms_bufferizer_destroy(MSBufferizer *obj);  

Exemple de utilizare a tamponului pot fi găsite în codul sursă al mai multor filtre media streamer. De exemplu, în filtrul MS_L16_ENC, care rearanjează octeții din eșantioanele de la ordinea rețelei la ordinea gazdei: l16.c

În articolul următor, ne vom uita la problema estimării încărcării tickerului și a modului de a face față sarcinii excesive de calcul în streamer-ul media.

Sursa: www.habr.com

Adauga un comentariu