Udforskning af Mediastreamer2 VoIP-motoren. Del 11

Artiklens materiale er hentet fra min zen kanal.

Udforskning af Mediastreamer2 VoIP-motoren. Del 11

Databevægelsesmekanisme

  • Datablok dblk_t
  • Besked mblk_t
  • Funktioner til at arbejde med beskeder mblk_t
  • Kø kø_t
  • Funktioner til at arbejde med køer queue_t
  • Tilslutning af filtre
  • Signalpunkt for databehandlingsgraf
  • Tickerens aktiviteter bag kulisserne
  • Bufferizer (MSBufferizer)
  • Funktioner til at arbejde med MSBufferizer

I fortiden artiklen vi har udviklet vores eget filter. Denne artikel vil fokusere på den interne mekanisme til at flytte data mellem mediestreamerfiltre. Dette vil give dig mulighed for at skrive sofistikerede filtre med mindre indsats i fremtiden.

Databevægelsesmekanisme

Databevægelse i mediestreameren udføres ved hjælp af køer beskrevet af strukturen kø_t. Strenge af beskeder som mblk_t, som i sig selv ikke indeholder signaldata, men kun linker til den forrige, næste besked og til datablokken. Derudover vil jeg især understrege, at der også er et felt til et link til en besked af samme type, som giver dig mulighed for at organisere en enkelt linket liste af beskeder. Vi vil kalde en gruppe meddelelser, der er forenet af en sådan liste, for en tuple. Ethvert element i køen kan således være en enkelt besked mblk_t, og måske lederen af ​​en besked-tupel mblk_t. Hver tupelmeddelelse kan have sin egen afdelingsdatablok. Vi vil diskutere hvorfor tuples er nødvendige lidt senere.

Som nævnt ovenfor indeholder meddelelsen i sig selv ikke en blok af data; i stedet indeholder den kun en pointer til hukommelsesområdet, hvor blokken er gemt. I denne del minder det overordnede billede af mediestreamerens arbejde om dørlageret i tegnefilmen "Monsters, Inc.," hvor døre (links til data - rum) bevæger sig med en vanvittig hastighed langs overliggende transportører, mens selve værelserne forblive ubevægelig.

Nu, når vi bevæger os langs hierarkiet fra bund til top, lad os i detaljer overveje de anførte enheder af datatransmissionsmekanismen i mediestreameren.

Datablok dblk_t

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

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

Felterne i strukturen indeholder pointere til begyndelsen af ​​bufferen, slutningen af ​​bufferen og funktionen til sletning af databufferen. Sidste element i overskriften db_ref — referencetæller, hvis den når nul, tjener dette som et signal til at slette denne blok fra hukommelsen. Hvis datablokken er oprettet af funktionen data_alloc() , så vil databufferen blive placeret i hukommelsen umiddelbart efter headeren. I alle andre tilfælde kan bufferen placeres et sted separat. Databufferen vil indeholde signalprøver eller andre data, som vi ønsker at behandle med filtre.

En ny forekomst af en datablok oprettes ved hjælp af funktionen:

dblk_t *datab_alloc(int size);

Som inputparameter er det givet størrelsen af ​​de data, som blokken vil gemme. Mere hukommelse er allokeret for at placere en header - struktur - i begyndelsen af ​​den allokerede hukommelse datab. Men når du bruger andre funktioner, sker dette ikke altid; i nogle tilfælde kan databufferen være placeret separat fra datablokheaderen. Når du opretter en struktur, konfigureres felterne, så dens felt db_base pegede på begyndelsen af ​​dataområdet, og db_lim til sin ende. Linkantal db_ref er indstillet til en. Datarydningsfunktionsmarkøren er sat til nul.

besked mblk_t

Som nævnt er køelementer af typen mblk_t, det er defineret 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 indeholder pointer i begyndelsen b_forrige, b_næste, som er nødvendige for at organisere en dobbelt linket liste (som er en kø kø_t).

Så kommer pointeren b_fortsat, som kun bruges, når beskeden er en del af en tupel. For den sidste besked i tuplen forbliver denne pointer nul.

Dernæst ser vi en pegepind til en datablok b_datap, som meddelelsen eksisterer for. Det efterfølges af pointere til området inde i blokdatabufferen. Mark b_rptr angiver det sted, hvorfra data fra bufferen vil blive læst. Mark b_wptr angiver det sted, hvorfra skrivning til bufferen vil blive udført.

De resterende felter er af servicekarakter og vedrører ikke driften af ​​dataoverførselsmekanismen.

Nedenfor er en enkelt besked med navnet m1 og datablok d1.
Udforskning af Mediastreamer2 VoIP-motoren. Del 11
Den følgende figur viser en række af tre beskeder m1, m1_1, m1_2.
Udforskning af Mediastreamer2 VoIP-motoren. Del 11

Beskedfunktioner mblk_t

En ny besked mblk_t oprettet af funktionen:

mblk_t *allocb(int size, int pri); 

hun placerer en ny besked i hukommelsen mblk_t med en datablok af den angivne størrelse størrelse, andet argument - pri ikke brugt i denne version af biblioteket. Det skal forblive nul. Under funktionens drift vil der blive allokeret hukommelse til strukturen af ​​den nye besked, og funktionen vil blive kaldt mblk_init(), som vil nulstille alle felter i den oprettede forekomst af strukturen og derefter ved hjælp af ovennævnte data_alloc(), vil oprette en databuffer. Hvorefter felterne i strukturen konfigureres:

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

Ved udgangen modtager vi en ny besked med initialiserede felter og en tom databuffer. For at tilføje data til en besked skal du kopiere den til datablokbufferen:

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

где data er en pegepind til datakilden, og størrelse - deres størrelse.
så skal du opdatere markøren til skrivepunktet, så den igen peger på begyndelsen af ​​det frie område i bufferen:

msg->b_wptr = msg->b_wptr + size

Hvis du har brug for at oprette en besked fra en eksisterende buffer, uden at kopiere, så brug funktionen:

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

Funktionen vil, efter at have oprettet meddelelsen og strukturen af ​​datablokken, konfigurere sine pointere til dataene på adressen buff. De der. i dette tilfælde er databufferen ikke placeret efter datablokkens overskriftsfelter, som det var tilfældet ved oprettelse af en datablok med funktionen data_alloc(). Bufferen med data, der sendes til funktionen, forbliver, hvor den var, men ved hjælp af pointere vil den blive knyttet til den nyoprettede header af datablokken, og det følgelig til meddelelsen.

Til én besked mblk_t Flere datablokke kan sammenkædes sekventielt. Dette gøres ved hjælp af funktionen:

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

mp — en meddelelse, hvortil en anden datablok vil blive tilføjet;
data — pointer til blokken, hvoraf en kopi vil blive tilføjet til meddelelsen;
størrelse — datastørrelse;
pad — et flag om, at størrelsen af ​​den allokerede hukommelse skal justeres langs en 4-byte grænse (udfyldning vil blive udført med nuller).

Hvis der er nok plads i den eksisterende meddelelsesdatabuffer, vil de nye data blive indsat bag de data, der allerede er der. Hvis der er mindre ledig plads i meddelelsesdatabufferen end størrelse, så oprettes en ny besked med en tilstrækkelig bufferstørrelse, og dataene kopieres til dens buffer. Dette er en ny besked, knyttet til den originale ved hjælp af en markør b_fortsat. I dette tilfælde bliver beskeden til en tupel.

Hvis du skal tilføje endnu en datablok til tuplet, skal du bruge funktionen:

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

hun vil finde den sidste besked i tuplet (han har b_fortsat vil være null) og kalder funktionen for denne besked appendb().

Du kan finde ud af størrelsen af ​​data i en besked eller tuple ved hjælp af funktionen:

int msgdsize(const mblk_t *mp);

den vil gennemgå alle meddelelserne i tuplet og returnere den samlede mængde data i databufferne for disse meddelelser. For hver besked beregnes mængden af ​​data som følger:

 mp->b_wptr - mp->b_rptr

For at kombinere to tupler, brug funktionen:

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

hun tilføjer tuplet NEWM til tuplens hale mp og returnerer en pointer til den sidste besked i den resulterende tupel.

Om nødvendigt kan en tuple omdannes til én besked med en enkelt datablok; dette gøres ved funktionen:

void msgpullup(mblk_t *mp,int len);

hvis argument len er -1, så bestemmes størrelsen af ​​den tildelte buffer automatisk. Hvis len er et positivt tal, vil en buffer af denne størrelse blive oprettet, og tuple-meddelelsesdataene vil blive kopieret ind i den. Hvis bufferen løber tør, stopper kopieringen der. Den første besked fra tuplet vil modtage en ny størrelse buffer med de kopierede data. De resterende beskeder vil blive slettet, og hukommelsen returneres til heapen.

Når du sletter en struktur mblk_t datablokkens referencetælling tages i betragtning, hvis der ved opkald freeb() det viser sig at være nul, så slettes databufferen sammen med instansen mblk_t, hvilket peger på det.

Initialisering af felterne i en ny besked:

void mblk_init(mblk_t *mp);

Tilføjelse af endnu et stykke data til beskeden:

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

Hvis de nye data ikke passer ind i den ledige plads i meddelelsesdatabufferen, vedhæftes en separat oprettet meddelelse med en buffer af den påkrævede størrelse til meddelelsen (en pointer til den tilføjede meddelelse er sat i den første meddelelse) og besked bliver til en tupel.

Tilføjelse af et stykke data til en tuple:

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

Funktionen kalder appendb() i en løkke.

Kombinerer to tupler til en:

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

besked NEWM vil blive knyttet til mp.

Sådan laver du en kopi af en enkelt besked:

mblk_t *copyb(const mblk_t *mp);

Komplet kopiering af en tuple med alle datablokke:

mblk_t *copymsg(const mblk_t *mp);

Tuplens elementer kopieres af funktionen copyb().

Opret en nem kopi af en besked mblk_t. I dette tilfælde kopieres datablokken ikke, men dens referencetæller øges db_ref:

mblk_t *dupb(mblk_t *mp);

At lave en let kopi af en tupel. Datablokke kopieres ikke, kun deres referencetællere øges db_ref:

mblk_t *dupmsg(mblk_t* m);

Lim alle beskeder fra en tuple ind i én besked:

void msgpullup(mblk_t *mp,size_t len);

Hvis argumentet len er -1, så bestemmes størrelsen af ​​den tildelte buffer automatisk.

Sletning af en besked, tuple:

void freemsg(mblk_t *mp);

Datablokkens referencetælling formindskes med én. Hvis den når nul, slettes datablokken også.

Beregning af den samlede mængde data i en besked eller tuple.

size_t msgdsize(const mblk_t *mp);

Henter en besked fra køens ende:

mblk_t *ms_queue_peek_last (q);

Kopiering af indholdet af de reserverede felter i en besked til en anden besked (faktisk indeholder disse felter flag, der bruges af mediestreameren):

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

Tur kø_t

Meddelelseskøen i mediestreameren er implementeret som en cirkulær dobbeltlinket liste. Hvert listeelement indeholder en pointer til en datablok med signaleksempler. Det viser sig, at kun pointere til datablokken bevæger sig på skift, mens selve dataene forbliver ubevægelige. De der. kun links til dem flyttes.
Struktur, der beskriver køen kø_t, vist nedenfor:

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

Strukturen indeholder et felt - en pointer _q_stopper skriv *mblk_t, det peger på det første element (meddelelse) i køen. Det andet felt i strukturen er tælleren af ​​meddelelser i køen.
Nedenstående figur viser en kø med navnet q1 indeholdende 4 beskeder m1, m2, m3, m4.
Udforskning af Mediastreamer2 VoIP-motoren. Del 11
Følgende figur viser en kø med navnet q1, der indeholder 4 beskeder m1,m2,m3,m4. Besked m2 er hovedet på en tupel, der indeholder yderligere to meddelelser m2_1 og m2_2.

Udforskning af Mediastreamer2 VoIP-motoren. Del 11

Funktioner til at arbejde med køer queue_t

Køinitialisering:

void qinit(queue_t *q);

Field _q_stopper (herefter kalder vi det "stopper") initialiseres af funktionen mblk_init(), dets forrige element og næste element-markør justeres til at pege på sig selv. Køelementtælleren nulstilles.

Tilføjelse af et nyt element (meddelelser):

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

Nyt element m tilføjes til slutningen af ​​listen, justeres elementmarkørerne, så stopperen bliver det næste element for den, og den bliver det forrige element for stopperen. Køelementtælleren øges.

Hentning af et element fra køen:

mblk_t * getq(queue_t *q); 

Beskeden, der kommer efter proppen er hentet, og elementtælleren dekrementeres. Hvis der ikke er nogen elementer i køen undtagen stopperen, returneres 0.

Indsættelse af en besked i en kø:

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

element mp indsat før elementet emp. hvis emp=0, så føjes beskeden til køens ende.

Henter en besked fra lederen af ​​køen:

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

Elementtælleren dekrementeres.

Læsning af en pointer til det første element i køen:

mblk_t * peekq(queue_t *q); 

Fjernelse af alle elementer fra køen, mens du sletter selve elementerne:

void flushq(queue_t *q, int how);

argument hvordan anvendes ikke. Køelementtælleren er sat til nul.

Makro til at læse en pointer til det sidste element i køen:

mblk_t * qlast(queue_t *q);

Når du arbejder med beskedkøer, skal du være opmærksom på, at når du ringer ms_queue_put(q, m) med en nul-markør til beskeden, går funktionen i loop. Dit program fryser. opfører sig ens ms_queue_next(q, m).

Tilslutning af filtre

Køen beskrevet ovenfor bruges til at sende beskeder fra et filter til et andet eller fra et til flere filtre. Filtre og deres forbindelser danner en rettet graf. Filterets input eller output vil blive kaldt det generelle ord "pin". For at beskrive rækkefølgen, hvori filtre er forbundet med hinanden, bruger mediestreameren begrebet et "signalpunkt". Signalpunkt er struktur _MSCPoint, som indeholder en pegepind til filteret og nummeret på et af dets ben; derfor beskriver det tilslutningen af ​​en af ​​filterets ind- eller udgange.

Signalpunkt for databehandlingsgraf

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

Filterstifter er nummererede fra nul.

Forbindelsen af ​​to ben ved en beskedkø er beskrevet af strukturen _MSKø, som indeholder en beskedkø og pointere til de to signalpunkter, den forbinder:

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

Vi vil kalde denne struktur en signalforbindelse. Hvert mediestreamerfilter indeholder en tabel over inputlinks og en tabel over outputlinks (MSQueue). Størrelsen på tabeller indstilles, når der oprettes et filter; vi har allerede gjort dette ved at bruge en eksporteret variabel af typen MSFilterDesc, da vi udviklede vores eget filter. Nedenfor er en struktur, der beskriver ethvert filter i en mediestreamer, 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;

Efter at vi tilsluttede filtrene i C-programmet i overensstemmelse med vores plan (men ikke tilsluttede tickeren), skabte vi derved en rettet graf, hvis noder er forekomster af strukturen MSFilter, og kanter er forekomster af links MSQueue.

Tickerens aktiviteter bag kulisserne

Da jeg fortalte dig, at tickeren er et filter for kilden til flåter, var det ikke hele sandheden om det. En ticker er et objekt, der kører funktioner på uret behandle() alle filtre i kredsløbet (grafen), som det er tilsluttet. Når vi forbinder en ticker til et graffilter i et C-program, viser vi tickeren den graf, som den vil styre fra nu af, indtil vi slukker den. Efter tilslutning begynder tickeren at undersøge grafen, der er betroet dens pleje, og kompilerer en liste over filtre, der inkluderer den. For ikke at "tælle" det samme filter to gange, markerer det de detekterede filtre ved at placere et afkrydsningsfelt i dem set. Søgningen udføres ved hjælp af de linktabeller, som hvert filter har.

Under sin indledende rundvisning i grafen tjekker tickeren, om der blandt filtrene er mindst én, der fungerer som kilde til datablokke. Hvis der ikke er nogen, anses grafen for at være forkert, og tickeren går ned.

Hvis grafen viser sig at være "korrekt", for hvert fundet filter, kaldes funktionen for initialisering forproces(). Så snart tidspunktet kommer for den næste behandlingscyklus (hvert 10. millisekund som standard), kalder tickeren funktionen behandle() for alle tidligere fundne kildefiltre og derefter for de resterende filtre på listen. Hvis filteret har input-links, skal du køre funktionen behandle() gentages, indtil input-link-køerne er tomme. Herefter går det videre til det næste filter på listen og "scroller" det, indtil inputlinkene er fri for beskeder. Tickeren flytter sig fra filter til filter, indtil listen slutter. Dette afslutter behandlingen af ​​cyklussen.

Nu vil vi vende tilbage til tuples og tale om, hvorfor en sådan enhed blev tilføjet til mediestreameren. Generelt er mængden af ​​data, der kræves af algoritmen, der opererer inde i filteret, ikke sammenfaldende og er ikke et multiplum af størrelsen af ​​de databuffere, der modtages ved indgangen. For eksempel skriver vi et filter, der udfører en hurtig Fourier-transformation, som per definition kun kan behandle datablokke, hvis størrelse er en potens af to. Lad det være 512 tæller. Hvis dataene genereres af en telefonkanal, vil databufferen for hver besked ved indgangen give os 160 signaleksempler. Det er fristende ikke at indsamle data fra input, før den nødvendige mængde data er der. Men i dette tilfælde vil der forekomme en kollision med tickeren, som uden held vil forsøge at rulle filteret, indtil inputlinket er tomt. Tidligere har vi udpeget denne regel som filterets tredje princip. Ifølge dette princip skal filterets process()-funktion tage alle data fra inputkøerne.

Derudover vil det ikke være muligt kun at tage 512 prøver fra inputtet, da man kun kan tage hele blokke, dvs. filteret skal tage 640 prøver og bruge 512 af dem, resten, før der akkumuleres en ny del af data. Vores filter skal således ud over sit hovedarbejde give hjælpehandlinger til mellemlagring af inputdata. Udviklerne af mediestreameren og løsningen på dette generelle problem har udviklet et specielt objekt - MSBufferizer (buffer), som løser dette problem ved hjælp af tuples.

Bufferizer (MSBufferizer)

Dette er et objekt, der vil akkumulere inputdata inde i filteret og begynde at sende dem til behandling, så snart mængden af ​​information er tilstrækkelig til at køre filteralgoritmen. Mens bufferen akkumulerer data, vil filteret fungere i inaktiv tilstand uden at opbruge processorkraften. Men så snart læsefunktionen fra bufferen returnerer en anden værdi end nul, begynder filterets process()-funktion at tage og behandle data fra bufferen i dele af den påkrævede størrelse, indtil den er opbrugt.
Data, der endnu ikke er påkrævet, forbliver i bufferen som det første element i tuplet, hvortil efterfølgende blokke af inputdata er knyttet.

Strukturen, der beskriver bufferen:

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

Funktioner til at arbejde med MSBufferizer

Oprettelse af en ny bufferforekomst:

MSBufferizer * ms_bufferizer_new(void);

Hukommelse er allokeret, initialiseret i ms_bufferizer_init() og en pointer returneres.

Initialiseringsfunktion:

void ms_bufferizer_init(MSBufferizer *obj); 

Køen initialiseres q, Mark størrelse er sat til nul.

Tilføjelse af en besked:

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

Besked m tilføjes til køen. Den beregnede størrelse af datablokke tilføjes størrelse.

Overførsel af alle meddelelser fra linkdatakøen til bufferen q:

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

Overførsel af beskeder fra et link q i bufferen udføres ved hjælp af funktionen ms_bufferizer_put().

Læsning fra bufferen:

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

Hvis størrelsen af ​​de akkumulerede data i bufferen er mindre end den anmodede (datalen), så returnerer funktionen nul, data kopieres ikke til data. Ellers udføres sekventiel kopiering af data fra tuples placeret i bufferen. Efter kopiering slettes tuplen, og hukommelsen frigøres. Kopieringen slutter i det øjeblik, da dataalen-bytes kopieres. Hvis plads løber tør i midten af ​​en datablok, vil datablokken i denne meddelelse blive reduceret til den resterende ukopierede del. Næste gang du ringer, fortsætter kopieringen fra dette tidspunkt.

Læsning af mængden af ​​data, der i øjeblikket er tilgængelig i bufferen:

int ms_bufferizer_get_avail(MSBufferizer *obj); 

Returnerer feltet størrelse buffer.

Kassering af en del af dataene i bufferen:

void ms_bufferizer_skip_bytes(MSBufferizer *obj, int bytes);

Det angivne antal bytes data hentes og kasseres. De ældste data kasseres.

Sletning af alle meddelelser i bufferen:

void ms_bufferizer_flush(MSBufferizer *obj); 

Datatælleren nulstilles.

Sletning af alle meddelelser i bufferen:

void ms_bufferizer_uninit(MSBufferizer *obj); 

Tælleren er ikke nulstillet.

Fjernelse af bufferen og frigørelse af hukommelse:

void ms_bufferizer_destroy(MSBufferizer *obj);  

Eksempler på brug af bufferen kan findes i kildekoden til flere mediestreamerfiltre. For eksempel i MS_L16_ENC-filteret, som omarrangerer bytes i samplerne fra netværksrækkefølgen til værtsrækkefølgen: l16.c

I den næste artikel vil vi se på spørgsmålet om at estimere belastningen på en ticker og måder at bekæmpe overdreven computerbelastning i en mediestreamer.

Kilde: www.habr.com

Tilføj en kommentar