Utforsker Mediastreamer2 VoIP-motoren. Del 11

Stoffet til artikkelen er hentet fra min zen-kanal.

Utforsker Mediastreamer2 VoIP-motoren. Del 11

Databevegelsesmekanisme

  • Datablokk dblk_t
  • Melding mblk_t
  • Funksjoner for å jobbe med meldinger mblk_t
  • Kø kø queue_t
  • Funksjoner for å jobbe med køer queue_t
  • Koble til filtre
  • Signalpunkt for databehandlingsgraf
  • Bak kulissene aktiviteter av ticker
  • Bufferizer (MSBufferizer)
  • Funksjoner for å jobbe med MSBufferizer

I den siste artikkel vi har utviklet vårt eget filter. Denne artikkelen vil fokusere på den interne mekanismen for å flytte data mellom mediestreamerfiltre. Dette vil tillate deg å skrive sofistikerte filtre med mindre innsats i fremtiden.

Databevegelsesmekanisme

Databevegelse i mediastreameren utføres ved hjelp av køer beskrevet av strukturen kø_t. Strenger av meldinger som mblk_t, som i seg selv ikke inneholder signaldata, men kun lenker til forrige, neste melding og til datablokken. I tillegg vil jeg spesielt understreke at det også er et felt for en lenke til en melding av samme type, som lar deg organisere en enkeltlenket liste med meldinger. Vi vil kalle en gruppe meldinger forent av en slik liste en tuppel. Dermed kan ethvert element i køen være en enkelt melding mblk_t, og kanskje hodet til en meldingstuppel mblk_t. Hver tuppelmelding kan ha sin egen avdelingsdatablokk. Vi vil diskutere hvorfor tuples er nødvendig litt senere.

Som nevnt ovenfor inneholder ikke selve meldingen en blokk med data; i stedet inneholder den bare en peker til minneområdet der blokken er lagret. I denne delen minner helhetsbildet av mediestreamerens arbeid om dørlageret i tegneserien «Monsters, Inc.», der dører (lenker til data - rom) beveger seg i en vanvittig hastighet langs overliggende transportbånd, mens selve rommene forbli urørlig.

Når vi nå beveger oss langs hierarkiet fra bunn til topp, la oss i detalj vurdere de oppførte enhetene til dataoverføringsmekanismen i mediastreameren.

Datablokk dblk_t

Datablokken består av en header og en databuffer. Overskriften er beskrevet av følgende struktur,

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

Feltene i strukturen inneholder pekere til begynnelsen av bufferen, slutten av bufferen og funksjonen for å slette databufferen. Siste element i overskriften db_ref — referanseteller, hvis den når null, tjener dette som et signal for å slette denne blokken fra minnet. Hvis datablokken ble opprettet av funksjonen data_alloc() , vil databufferen bli plassert i minnet umiddelbart etter overskriften. I alle andre tilfeller kan bufferen være plassert et sted separat. Databufferen vil inneholde signalprøver eller andre data som vi ønsker å behandle med filtre.

En ny forekomst av en datablokk opprettes ved hjelp av funksjonen:

dblk_t *datab_alloc(int size);

Som en inngangsparameter er det gitt størrelsen på dataene som blokken vil lagre. Mer minne tildeles for å plassere en overskrift - struktur - i begynnelsen av det tildelte minnet dataab. Men når du bruker andre funksjoner, skjer dette ikke alltid; i noen tilfeller kan databufferen være plassert separat fra datablokkoverskriften. Når du oppretter en struktur, konfigureres feltene slik at dens felt db_base pekte på begynnelsen av dataområdet, og db_lim til slutten. Antall koblinger db_ref er satt til én. Dataslettingsfunksjonspekeren er satt til null.

Beskjed mblk_t

Som nevnt er køelementer av typen mblk_t, det er definert som følger:

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;

Struktur mblk_t inneholder pekere i begynnelsen b_prev, b_neste, som er nødvendige for å organisere en dobbeltlenket liste (som er en kø kø_t).

Så kommer pekeren b_forts, som bare brukes når meldingen er en del av en tuppel. For den siste meldingen i tuppelen forblir denne pekeren null.

Deretter ser vi en peker til en datablokk b_datap, som meldingen eksisterer for. Den etterfølges av pekere til området inne i blokkdatabufferen. Felt b_rptr spesifiserer stedet som data fra bufferen skal leses fra. Felt b_wptr angir stedet som skriving til bufferen skal utføres fra.

De resterende feltene er av tjenestekarakter og er ikke knyttet til driften av dataoverføringsmekanismen.

Nedenfor er en enkelt melding med navnet m1 og datablokk d1.
Utforsker Mediastreamer2 VoIP-motoren. Del 11
Følgende figur viser en tuppel med tre meldinger m1, m1_1, m1_2.
Utforsker Mediastreamer2 VoIP-motoren. Del 11

Meldingsfunksjoner mblk_t

En ny melding mblk_t opprettet av funksjonen:

mblk_t *allocb(int size, int pri); 

hun legger en ny melding i minnet mblk_t med en datablokk av den angitte størrelsen størrelse, andre argument - pri ikke brukt i denne versjonen av biblioteket. Den skal forbli null. Under funksjonens drift vil minne tildeles for strukturen til den nye meldingen og funksjonen kalles opp mblk_init(), som vil tilbakestille alle feltene i den opprettede forekomsten av strukturen og deretter, ved å bruke ovennevnte data_alloc(), vil opprette en databuffer. Deretter vil feltene i strukturen bli konfigurert:

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

Ved utgangen mottar vi en ny melding med initialiserte felt og en tom databuffer. For å legge til data i en melding, må du kopiere den til datablokkbufferen:

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

der dato er en peker til datakilden, og størrelse - størrelsen deres.
så må du oppdatere pekeren til skrivepunktet slik at den peker igjen til begynnelsen av det ledige området i bufferen:

msg->b_wptr = msg->b_wptr + size

Hvis du trenger å lage en melding fra en eksisterende buffer, uten å kopiere, så bruk funksjonen:

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

Funksjonen vil, etter å ha opprettet meldingen og strukturen til datablokken, konfigurere sine pekere til dataene på adressen buf. De. i dette tilfellet er ikke databufferen plassert etter overskriftsfeltene til datablokken, slik tilfellet var når du opprettet en datablokk med funksjonen data_alloc(). Bufferen med data som sendes til funksjonen vil forbli der den var, men ved hjelp av pekere vil den bli knyttet til den nyopprettede overskriften til datablokken, og det følgelig til meldingen.

Til én melding mblk_t Flere datablokker kan kobles sammen sekvensielt. Dette gjøres av funksjonen:

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

mp — en melding som en annen datablokk vil bli lagt til;
dato — peker til blokken, en kopi av denne vil bli lagt til i meldingen;
størrelse — datastørrelse;
pad — et flagg om at størrelsen på det tildelte minnet må justeres langs en 4-byte grense (utfylling vil bli gjort med nuller).

Hvis det er nok plass i den eksisterende meldingsdatabufferen, vil de nye dataene limes inn bak dataene som allerede er der. Hvis det er mindre ledig plass i meldingsdatabufferen enn størrelse, så opprettes en ny melding med tilstrekkelig bufferstørrelse og dataene kopieres til bufferen. Dette er en ny melding, koblet til den opprinnelige ved hjelp av en peker b_forts. I dette tilfellet blir meldingen til en tuppel.

Hvis du trenger å legge til en annen blokk med data til tuppelen, må du bruke funksjonen:

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

hun vil finne den siste meldingen i tuppelen (han har b_forts vil være null) og kaller opp funksjonen for denne meldingen appendb().

Du kan finne ut størrelsen på data i en melding eller tuppel ved å bruke funksjonen:

int msgdsize(const mblk_t *mp);

den vil gå gjennom alle meldingene i tupleen og returnere den totale mengden data i databufferne til disse meldingene. For hver melding beregnes datamengden som følger:

 mp->b_wptr - mp->b_rptr

For å kombinere to tupler, bruk funksjonen:

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

hun legger tuppelen til newm til halen på tuppelen mp og returnerer en peker til den siste meldingen til den resulterende tuppelen.

Om nødvendig kan en tuppel gjøres om til én melding med en enkelt datablokk; dette gjøres av funksjonen:

void msgpullup(mblk_t *mp,int len);

hvis argument len er -1, så bestemmes størrelsen på den tildelte bufferen automatisk. Hvis len er et positivt tall, vil en buffer av denne størrelsen bli opprettet og tuppelmeldingsdataene vil bli kopiert inn i den. Hvis bufferen går tom, stopper kopieringen der. Den første meldingen til tupelen vil motta en ny størrelsesbuffer med de kopierte dataene. De gjenværende meldingene vil bli slettet og minnet returnert til haugen.

Når du sletter en struktur mblk_t referansetellingen til datablokken tas i betraktning hvis, når du ringer freeb() det viser seg å være null, så slettes databufferen sammen med instansen mblk_t, som peker på det.

Initialisere feltene i en ny melding:

void mblk_init(mblk_t *mp);

Legge til en annen del av data i meldingen:

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

Hvis de nye dataene ikke passer inn i den ledige plassen til meldingsdatabufferen, legges en separat opprettet melding med en buffer av nødvendig størrelse til meldingen (en peker til den tilføyde meldingen settes i den første meldingen) og melding blir til en tuppel.

Legge til et stykke data til en tuppel:

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

Funksjonen kaller appendb() i en løkke.

Kombiner to tuples til en:

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

Beskjed newm vil bli knyttet til mp.

Lage en kopi av en enkelt melding:

mblk_t *copyb(const mblk_t *mp);

Fullstendig kopiering av en tuppel med alle datablokker:

mblk_t *copymsg(const mblk_t *mp);

Elementene i tupelen kopieres av funksjonen copyb().

Lag en enkel kopi av en melding mblk_t. I dette tilfellet kopieres ikke datablokken, men dens referanseteller økes db_ref:

mblk_t *dupb(mblk_t *mp);

Å lage en lett kopi av en tuppel. Datablokker kopieres ikke, bare referansetellerne deres økes db_ref:

mblk_t *dupmsg(mblk_t* m);

Lim alle meldinger fra en tuppel inn i én melding:

void msgpullup(mblk_t *mp,size_t len);

Hvis argumentet len er -1, så bestemmes størrelsen på den tildelte bufferen automatisk.

Sletter en melding, tuple:

void freemsg(mblk_t *mp);

Datablokkens referansetelling reduseres med én. Hvis den når null, slettes også datablokken.

Beregning av den totale mengden data i en melding eller tuppel.

size_t msgdsize(const mblk_t *mp);

Henter en melding fra halen av køen:

mblk_t *ms_queue_peek_last (q);

Kopiering av innholdet i de reserverte feltene i en melding til en annen melding (faktisk inneholder disse feltene flagg som brukes av mediastreameren):

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

kø_t

Meldingskøen i mediastreameren er implementert som en sirkulær dobbeltlenket liste. Hvert listeelement inneholder en peker til en datablokk med signaleksempler. Det viser seg at bare pekere til datablokken beveger seg etter tur, mens selve dataene forblir ubevegelige. De. bare lenker til dem flyttes.
Struktur som beskriver køen kø_t, Vist under:

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

Strukturen inneholder et felt - en peker _q_stopper skriv *mblk_t, den peker på det første elementet (meldingen) i køen. Det andre feltet i strukturen er telleren for meldinger i køen.
Figuren nedenfor viser en kø kalt q1 som inneholder 4 meldinger m1, m2, m3, m4.
Utforsker Mediastreamer2 VoIP-motoren. Del 11
Følgende figur viser en kø kalt q1 som inneholder 4 meldinger m1,m2,m3,m4. Melding m2 er hodet til en tuppel som inneholder ytterligere to meldinger m2_1 og m2_2.

Utforsker Mediastreamer2 VoIP-motoren. Del 11

Funksjoner for å jobbe med køer queue_t

Køinitialisering:

void qinit(queue_t *q);

Feltet _q_stopper (heretter vil vi kalle det "stopper") initialiseres av funksjonen mblk_init(), dets forrige element og neste elementpeker justeres for å peke på seg selv. Køelementtelleren tilbakestilles til null.

Legge til et nytt element (meldinger):

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

Nytt element m legges til på slutten av listen, justeres elementpekerne slik at stopperen blir neste element for den, og den blir forrige element for stopperen. Køelementtelleren økes.

Henter et element fra køen:

mblk_t * getq(queue_t *q); 

Meldingen som kommer etter at stopperen er hentet, og elementtelleren dekrementeres. Hvis det ikke er noen elementer i køen bortsett fra stopperen, returneres 0.

Sette inn en melding i en kø:

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

element mp satt inn foran elementet emp. om emp=0, så legges meldingen til i halen av køen.

Henter en melding fra lederen av køen:

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

Elementtelleren reduseres.

Lese en peker til det første elementet i køen:

mblk_t * peekq(queue_t *q); 

Fjerne alle elementer fra køen mens du sletter selve elementene:

void flushq(queue_t *q, int how);

argument hvordan ikke brukt. Køelementtelleren er satt til null.

Makro for å lese en peker til det siste elementet i køen:

mblk_t * qlast(queue_t *q);

Når du jobber med meldingskøer, vær oppmerksom på at når du ringer ms_queue_put(q, m) med en null-peker til meldingen, går funksjonen i loop. Programmet ditt vil fryse. oppfører seg likt ms_queue_next(q, m).

Koble til filtre

Køen beskrevet ovenfor brukes til å sende meldinger fra ett filter til et annet eller fra ett til flere filtre. Filtre og deres forbindelser danner en rettet graf. Inngangen eller utgangen til filteret vil bli kalt det generelle ordet "pin". For å beskrive rekkefølgen filtrene er koblet til hverandre, bruker mediastreameren konseptet et "signalpunkt". Signalpunkt er struktur _MSCPoint, som inneholder en peker til filteret og nummeret på en av dets pinner; følgelig beskriver den tilkoblingen til en av inngangene eller utgangene til filteret.

Signalpunkt for databehandlingsgraf

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

Filterstifter er nummerert fra null.

Sammenkoblingen av to pinner ved en meldingskø er beskrevet av strukturen _MSQueue, som inneholder en meldingskø og pekere til de to signalpunktene den kobler sammen:

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

Vi vil kalle denne strukturen en signalkobling. Hvert mediestreamerfilter inneholder en tabell over inngangslenker og en tabell med utgangslenker (MSQueue). Størrelsen på tabeller angis når du oppretter et filter; vi har allerede gjort dette ved å bruke en eksportert variabel av typen MSFilterDesc, da vi utviklet vårt eget filter. Nedenfor er en struktur som beskriver ethvert filter i en mediastreamer, 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;

Etter at vi koblet filtrene i C-programmet i samsvar med planen vår (men ikke koblet tickeren), laget vi dermed en rettet graf, hvis noder er forekomster av strukturen MSFilter, og kanter er forekomster av koblinger MSQueue.

Bak kulissene aktiviteter av ticker

Da jeg fortalte deg at tickeren er et filter for kilden til flått, var det ikke hele sannheten om det. En ticker er et objekt som kjører funksjoner på klokken prosess() alle filtrene til kretsen (grafen) som den er koblet til. Når vi kobler en ticker til et graffilter i et C-program, viser vi tickeren grafen som den vil kontrollere fra nå av til vi slår den av. Etter tilkobling begynner tickeren å undersøke grafen som er betrodd dens omsorg, og kompilerer en liste over filtre som inkluderer den. For ikke å "telle" det samme filteret to ganger, merker det de oppdagede filtrene ved å sette en avmerkingsboks i dem sett. Søket utføres ved hjelp av lenketabellene som hvert filter har.

Under sin introduksjonsrunde i grafen sjekker tickeren om det blant filtrene er minst ett som fungerer som en kilde til datablokker. Hvis det ikke er noen, anses grafen som feil og tickeren krasjer.

Hvis grafen viser seg å være "riktig", for hvert funnet filter, kalles funksjonen for initialisering forprosess(). Så snart øyeblikket kommer for neste behandlingssyklus (hvert 10. millisekund som standard), kaller ticker funksjonen prosess() for alle tidligere funnet kildefiltre, og deretter for de gjenværende filtrene i listen. Hvis filteret har inngangskoblinger, kjører du funksjonen prosess() gjentas til input-link-køene er tomme. Etter dette går den videre til neste filter i listen og "ruller" den til inndatalenkene er fri for meldinger. Tickeren beveger seg fra filter til filter til listen slutter. Dette fullfører behandlingen av syklusen.

Nå skal vi gå tilbake til tuples og snakke om hvorfor en slik enhet ble lagt til mediestreameren. Generelt faller ikke mengden data som kreves av algoritmen som opererer inne i filteret sammen og er ikke et multiplum av størrelsen på databufferne mottatt ved inngangen. For eksempel skriver vi et filter som utfører en rask Fourier-transformasjon, som per definisjon bare kan behandle datablokker hvis størrelse er en potens av to. La det være 512 tellinger. Hvis dataene genereres av en telefonkanal, vil databufferen til hver melding ved inngangen gi oss 160 signalprøver. Det er fristende å ikke samle inn data fra input før den nødvendige mengden data er der. Men i dette tilfellet vil det oppstå en kollisjon med tickeren, som uten hell vil prøve å rulle filteret til inngangskoblingen er tom. Tidligere utpekte vi denne regelen som det tredje prinsippet for filteret. I henhold til dette prinsippet må filterets process()-funksjon ta alle data fra inngangskøene.

I tillegg vil det ikke være mulig å ta kun 512 prøver fra inngangen, siden man kun kan ta hele blokker, dvs. filteret må ta 640 prøver og bruke 512 av dem, resten før det samler en ny del av data. Dermed må filteret vårt, i tillegg til hovedarbeidet, gi hjelpehandlinger for mellomlagring av inngangsdata. Utviklerne av mediastreameren og løsningen på dette generelle problemet har utviklet et spesielt objekt - MSBufferizer (buffer), som løser dette problemet ved hjelp av tuples.

Bufferizer (MSBufferizer)

Dette er et objekt som vil akkumulere inndata inne i filteret og begynne å sende det inn for behandling så snart informasjonsmengden er tilstrekkelig til å kjøre filteralgoritmen. Mens bufferen akkumulerer data, vil filteret fungere i hvilemodus, uten å bruke opp prosessorkraften til prosessoren. Men så snart lesefunksjonen fra bufferen returnerer en annen verdi enn null, begynner prosess()-funksjonen til filteret å ta og behandle data fra bufferen i deler av den nødvendige størrelsen, til den er oppbrukt.
Data som ennå ikke er nødvendig forblir i bufferen som det første elementet i tupelen, som påfølgende blokker med inndata er knyttet til.

Strukturen som beskriver bufferen:

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

Funksjoner for å jobbe med MSBufferizer

Opprette en ny bufferforekomst:

MSBufferizer * ms_bufferizer_new(void);

Minne er allokert, initialisert inn ms_bufferizer_init() og en peker returneres.

Initialiseringsfunksjon:

void ms_bufferizer_init(MSBufferizer *obj); 

Køen initialiseres q, felt størrelse er satt til null.

Legge til en melding:

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

Melding m legges til i køen. Den beregnede størrelsen på datablokker legges til størrelse.

Overfører alle meldinger fra koblingsdatakøen til bufferen q:

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

Overføre meldinger fra en lenke q i bufferen utføres ved hjelp av funksjonen ms_bufferizer_put().

Leser fra bufferen:

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

Hvis størrelsen på dataene som er akkumulert i bufferen er mindre enn den forespurte (datalen), så returnerer funksjonen null, data kopieres ikke til data. Ellers utføres sekvensiell kopiering av data fra tupler som ligger i bufferen. Etter kopiering slettes tuppelen og minnet frigjøres. Kopieringen avsluttes i det øyeblikket dataalenbytes kopieres. Hvis plass går tom i midten av en datablokk, vil datablokken i denne meldingen reduseres til den gjenværende ukopierte delen. Neste gang du ringer, fortsetter kopieringen fra dette tidspunktet.

Lese mengden data som for øyeblikket er tilgjengelig i bufferen:

int ms_bufferizer_get_avail(MSBufferizer *obj); 

Returnerer feltet størrelse buffer.

Kast deler av dataene i bufferen:

void ms_bufferizer_skip_bytes(MSBufferizer *obj, int bytes);

Det angitte antallet byte med data hentes og forkastes. De eldste dataene forkastes.

Sletter alle meldinger i bufferen:

void ms_bufferizer_flush(MSBufferizer *obj); 

Datatelleren tilbakestilles til null.

Sletter alle meldinger i bufferen:

void ms_bufferizer_uninit(MSBufferizer *obj); 

Telleren er ikke tilbakestilt.

Fjerne bufferen og frigjøre minne:

void ms_bufferizer_destroy(MSBufferizer *obj);  

Eksempler på bruk av bufferen finner du i kildekoden til flere mediastreamerfiltre. For eksempel, i MS_L16_ENC-filteret, som omorganiserer bytene i prøvene fra nettverksrekkefølgen til vertsrekkefølgen: l16.c

I den neste artikkelen vil vi se på spørsmålet om å estimere belastningen på en ticker og måter å bekjempe overdreven databelastning i en mediestreamer.

Kilde: www.habr.com

Legg til en kommentar