Explorant el motor de VoIP Mediastreamer2. Part 11

El material de l'article està extret del meu canal zen.

Explorant el motor de VoIP Mediastreamer2. Part 11

Mecanisme de moviment de dades

  • Bloc de dades dblk_t
  • Missatge mblk_t
  • Funcions per treballar amb missatges mblk_t
  • Cua queue_t
  • Funcions per treballar amb cues queue_t
  • Connexió de filtres
  • Punt de senyal del gràfic de processament de dades
  • Activitats entre bastidors del ticker
  • Bufferizer (MSBufferizer)
  • Funcions per treballar amb MSBufferizer

En l'últim article hem desenvolupat el nostre propi filtre. Aquest article se centrarà en el mecanisme intern per moure dades entre filtres de reproducció multimèdia. Això us permetrà escriure filtres sofisticats amb menys esforç en el futur.

Mecanisme de moviment de dades

El moviment de dades a l'emissió de mitjans es realitza mitjançant cues descrites per l'estructura queue_t. Cadenas de missatges com mblk_t, que no contenen dades de senyal, sinó que només enllaça amb el missatge anterior, següent i amb el bloc de dades. A més, vull destacar especialment que també hi ha un camp per a un enllaç a un missatge del mateix tipus, que permet organitzar una llista de missatges enllaçats individualment. Anomenarem tupla a un grup de missatges units per una llista així. Així, qualsevol element de la cua pot ser un sol missatge mblk_t, i potser el cap d'una tupla de missatges mblk_t. Cada missatge de tupla pot tenir el seu propi bloc de dades de sala. Discutirem per què es necessiten les tuples una mica més endavant.

Com s'ha esmentat anteriorment, el missatge en si no conté un bloc de dades; en canvi, només conté un punter a l'àrea de memòria on s'emmagatzema el bloc. En aquesta part, la imatge general del treball del streamer de mitjans recorda el magatzem de la porta del dibuix animat "Monsters, Inc.", on les portes (enllaços a sales de dades) es mouen a una velocitat bogeria al llarg dels transportadors superiors, mentre que les sales mateixes romandre immòbil.

Ara, movent-nos al llarg de la jerarquia de baix a dalt, considerem en detall les entitats enumerades del mecanisme de transmissió de dades a la transmissió de mitjans.

Bloc de dades dblk_t

El bloc de dades consta d'una capçalera i una memòria intermèdia de dades. La capçalera es descriu amb l'estructura següent,

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

Els camps de l'estructura contenen punters a l'inici de la memòria intermèdia, al final de la memòria intermèdia i la funció per suprimir la memòria intermèdia de dades. Últim element de la capçalera db_ref — comptador de referència, si arriba a zero, serveix com a senyal per eliminar aquest bloc de la memòria. Si el bloc de dades ha estat creat per la funció datab_alloc() , aleshores la memòria intermèdia de dades es col·locarà a la memòria immediatament després de la capçalera. En tots els altres casos, la memòria intermèdia es pot localitzar en algun lloc per separat. El buffer de dades contindrà mostres de senyal o altres dades que volem processar amb filtres.

Es crea una nova instància d'un bloc de dades mitjançant la funció:

dblk_t *datab_alloc(int size);

Com a paràmetre d'entrada, se li dóna la mida de les dades que emmagatzemarà el bloc. S'assigna més memòria per col·locar una capçalera -estructura- al començament de la memòria assignada dades b. Però quan s'utilitzen altres funcions, això no sempre passa; en alguns casos, la memòria intermèdia de dades es pot localitzar per separat de la capçalera del bloc de dades. Quan es crea una estructura, els camps es configuren de manera que el seu camp db_base va assenyalar l'inici de l'àrea de dades i db_lim fins al seu final. Recompte d'enllaços db_ref està establert en un. El punter de la funció d'eliminació de dades es posa a zero.

Missatge mblk_t

Com s'ha dit, els elements de la cua són de tipus mblk_t, es defineix de la següent manera:

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;

Estructura mblk_t conté punters al principi b_anterior, b_següent, que són necessaris per organitzar una llista doblement enllaçada (que és una cua queue_t).

Després ve el punter b_cont, que només s'utilitza quan el missatge forma part d'una tupla. Per a l'últim missatge de la tupla, aquest punter continua sent nul.

A continuació, veiem un punter a un bloc de dades b_datap, per al qual existeix el missatge. El segueixen els punters a l'àrea dins del buffer de dades del bloc. Camp b_rptr especifica la ubicació des d'on es llegiran les dades de la memòria intermèdia. Camp b_wptr indica la ubicació des d'on es realitzaran les escriptures al buffer.

La resta de camps són de naturalesa de servei i no estan relacionats amb el funcionament del mecanisme de transferència de dades.

A continuació hi ha un únic missatge amb el nom m1 i bloc de dades d1.
Explorant el motor de VoIP Mediastreamer2. Part 11
La figura següent mostra una tupla de tres missatges m1, m1_1, m1_2.
Explorant el motor de VoIP Mediastreamer2. Part 11

Funcions de missatgeria mblk_t

Un missatge nou mblk_t creat per la funció:

mblk_t *allocb(int size, int pri); 

ella posa un missatge nou a la memòria mblk_t amb un bloc de dades de la mida especificada mida, segon argument - pri no s'utilitza en aquesta versió de la biblioteca. Hauria de romandre zero. Durant el funcionament de la funció, s'assignarà memòria per a l'estructura del nou missatge i es cridarà la funció mblk_init(), que restablirà tots els camps de la instància creada de l'estructura i després, utilitzant l'esmentat anteriorment datab_alloc(), crearà un buffer de dades. Després d'això, es configuraran els camps de l'estructura:

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

A la sortida rebem un missatge nou amb camps inicialitzats i un buffer de dades buit. Per afegir dades a un missatge, cal copiar-lo a la memòria intermèdia del bloc de dades:

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

on dades és un punter a la font de dades i mida - la seva mida.
aleshores, heu d'actualitzar el punter al punt d'escriptura perquè torni a apuntar al començament de l'àrea lliure de la memòria intermèdia:

msg->b_wptr = msg->b_wptr + size

Si necessiteu crear un missatge des d'un buffer existent, sense copiar-lo, feu servir la funció:

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

La funció, després de crear el missatge i l'estructura del bloc de dades, configurarà els seus punters a les dades de l'adreça buf. Aquells. en aquest cas, la memòria intermèdia de dades no es troba després dels camps de capçalera del bloc de dades, com va ser el cas en crear un bloc de dades amb la funció datab_alloc(). La memòria intermèdia amb les dades passades a la funció romandrà on estava, però amb l'ajuda de punters s'adjuntarà a la capçalera del bloc de dades acabada de crear, i això, en conseqüència, al missatge.

A un missatge mblk_t Es poden concatenar seqüencialment diversos blocs de dades. Això es fa mitjançant la funció:

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

mp — un missatge al qual s'afegirà un altre bloc de dades;
dades — punter al bloc, una còpia del qual s'afegirà al missatge;
mida - mida de les dades;
coixinet — una bandera que indica que la mida de la memòria assignada s'ha d'alinear al llarg d'un límit de 4 bytes (el farciment es farà amb zeros).

Si hi ha prou espai a la memòria intermèdia de dades del missatge existent, les dades noves s'enganxaran darrere de les que ja hi ha. Si hi ha menys espai lliure a la memòria intermèdia de dades del missatge que mida, aleshores es crea un missatge nou amb una mida de memòria intermèdia suficient i les dades es copien a la memòria intermèdia. Aquest és un missatge nou, enllaçat amb l'original mitjançant un punter b_cont. En aquest cas, el missatge es converteix en una tupla.

Si necessiteu afegir un altre bloc de dades a la tupla, heu d'utilitzar la funció:

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

ella trobarà l'últim missatge a la tupla (el té b_cont serà nul) i cridarà la funció d'aquest missatge appendb().

Podeu esbrinar la mida de les dades en un missatge o tupla mitjançant la funció:

int msgdsize(const mblk_t *mp);

recorrerà tots els missatges de la tupla i retornarà la quantitat total de dades als buffers de dades d'aquests missatges. Per a cada missatge, la quantitat de dades es calcula de la següent manera:

 mp->b_wptr - mp->b_rptr

Per combinar dues tuples, utilitzeu la funció:

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

ella afegeix la tupla noum a la cua de la tupla mp i retorna un punter a l'últim missatge de la tupla resultant.

Si cal, una tupla es pot convertir en un missatge amb un sol bloc de dades; això es fa mitjançant la funció:

void msgpullup(mblk_t *mp,int len);

si argument llen és -1, aleshores la mida del buffer assignat es determina automàticament. Si llen és un nombre positiu, es crearà una memòria intermèdia d'aquesta mida i s'hi copiaran les dades del missatge de tupla. Si la memòria intermèdia s'esgota, la còpia s'aturarà allà. El primer missatge de la tupla rebrà un nou buffer de mida amb les dades copiades. La resta de missatges s'eliminaran i la memòria es tornarà a la pila.

En eliminar una estructura mblk_t el recompte de referència del bloc de dades es té en compte si, en trucar freeb() resulta ser zero, aleshores s'elimina la memòria intermèdia de dades juntament amb la instància mblk_t, que ho apunta.

Inicialització dels camps d'un missatge nou:

void mblk_init(mblk_t *mp);

Afegeix una altra dada al missatge:

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

Si les dades noves no encaixen a l'espai lliure de la memòria intermèdia del missatge, s'adjunta un missatge creat per separat amb una memòria intermèdia de la mida requerida (un punter al missatge afegit s'estableix al primer missatge) i el missatge es converteix en una tupla.

Afegir una dada a una tupla:

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

La funció crida appendb() en un bucle.

Combinant dues tuples en una:

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

Missatge noum s'adjuntarà a mp.

Fent una còpia d'un sol missatge:

mblk_t *copyb(const mblk_t *mp);

Còpia completa d'una tupla amb tots els blocs de dades:

mblk_t *copymsg(const mblk_t *mp);

Els elements de la tupla són copiats per la funció copyb().

Creeu una còpia fàcil d'un missatge mblk_t. En aquest cas, el bloc de dades no es copia, sinó que augmenta el seu comptador de referència db_ref:

mblk_t *dupb(mblk_t *mp);

Fer una còpia lleugera d'una tupla. Els blocs de dades no es copien, només s'incrementen els seus comptadors de referència db_ref:

mblk_t *dupmsg(mblk_t* m);

Enganxar tots els missatges d'una tupla en un sol missatge:

void msgpullup(mblk_t *mp,size_t len);

Si l'argument llen és -1, aleshores la mida del buffer assignat es determina automàticament.

Eliminació d'un missatge, tupla:

void freemsg(mblk_t *mp);

El recompte de referència del bloc de dades es redueix en un. Si arriba a zero, el bloc de dades també s'elimina.

Càlcul de la quantitat total de dades en un missatge o tupla.

size_t msgdsize(const mblk_t *mp);

Recuperant un missatge de la cua de la cua:

mblk_t *ms_queue_peek_last (q);

Copia el contingut dels camps reservats d'un missatge a un altre missatge (de fet, aquests camps contenen senyaladors que s'utilitzen el transmissor multimèdia):

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

Cua queue_t

La cua de missatges a l'emissió de mitjans s'implementa com una llista circular doblement enllaçada. Cada element de llista conté un punter a un bloc de dades amb mostres de senyal. Resulta que només els punters al bloc de dades es mouen al seu torn, mentre que les dades en si es mantenen immòbils. Aquells. només es mouen els enllaços a ells.
Estructura que descriu la cua queue_t, mostrat a continuació:

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

L'estructura conté un camp: un punter _q_tap escriviu *mblk_t, apunta al primer element (missatge) de la cua. El segon camp de l'estructura és el comptador de missatges a la cua.
La figura següent mostra una cua anomenada q1 que conté 4 missatges m1, m2, m3, m4.
Explorant el motor de VoIP Mediastreamer2. Part 11
La figura següent mostra una cua anomenada q1 que conté 4 missatges m1,m2,m3,m4. El missatge m2 és el cap d'una tupla que conté dos missatges més m2_1 i m2_2.

Explorant el motor de VoIP Mediastreamer2. Part 11

Funcions per treballar amb cues queue_t

Inicialització de la cua:

void qinit(queue_t *q);

Camp _q_tap (d'ara endavant l'anomenarem "tap") és inicialitzat per la funció mblk_init(), el seu punter de l'element anterior i del següent element s'ajusten per apuntar-se a si mateix. El comptador d'elements de la cua es reinicia a zero.

Afegeix un element nou (missatges):

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

Nou element m s'afegeix al final de la llista, els punters d'element s'ajusten de manera que el tap es converteixi en l'element següent i esdevingui l'element anterior per al tap. El comptador d'elements de la cua s'incrementa.

Recuperant un element de la cua:

mblk_t * getq(queue_t *q); 

El missatge que ve després de recuperar el tap i disminuir el comptador d'elements. Si no hi ha elements a la cua excepte el stopper, es retorna 0.

Inserir un missatge a una cua:

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

Element mp inserit abans de l'element emp. Si emp=0, llavors el missatge s'afegeix a la cua de la cua.

Recuperant un missatge del cap de la cua:

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

El comptador d'elements es redueix.

Llegint un punter al primer element de la cua:

mblk_t * peekq(queue_t *q); 

Eliminació de tots els elements de la cua mentre s'eliminen els mateixos elements:

void flushq(queue_t *q, int how);

Argument com no utilitzat. El comptador d'elements de la cua està establert a zero.

Macro per llegir un punter a l'últim element de la cua:

mblk_t * qlast(queue_t *q);

Quan treballeu amb cues de missatges, tingueu en compte que quan truqueu ms_queue_put(q, m) amb un punter nul al missatge, la funció fa un bucle. El vostre programa es congelarà. es comporta de la mateixa manera ms_queue_next(q, m).

Connexió de filtres

La cua descrita anteriorment s'utilitza per passar missatges d'un filtre a un altre o d'un a diversos filtres. Els filtres i les seves connexions formen un gràfic dirigit. L'entrada o sortida del filtre s'anomenarà la paraula general "pin". Per descriure l'ordre en què els filtres estan connectats entre si, el transmissor multimèdia utilitza el concepte de "punt de senyal". El punt de senyal és l'estructura _MSCPoint, que conté un punter al filtre i el número d'un dels seus pins; en conseqüència, descriu la connexió d'una de les entrades o sortides del filtre.

Punt de senyal del gràfic de processament de dades

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

Els pins del filtre es numeren a partir de zero.

L'estructura descriu la connexió de dos pins mitjançant una cua de missatges _MSQueue, que conté una cua de missatges i punters als dos punts de senyal que connecta:

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

A aquesta estructura l'anomenarem enllaç de senyal. Cada filtre de transmissió multimèdia conté una taula d'enllaços d'entrada i una taula d'enllaços de sortida (MSQueue). La mida de les taules s'estableix en crear un filtre; ja ho hem fet utilitzant una variable exportada de tipus MSFilterDesc, quan vam desenvolupar el nostre propi filtre. A continuació es mostra una estructura que descriu qualsevol filtre d'un streamer multimèdia, 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;

Després de connectar els filtres al programa C d'acord amb el nostre pla (però no connectar el ticker), vam crear així un gràfic dirigit, els nodes del qual són exemples de l'estructura. MSFilter, i les vores són exemples d'enllaços MSQueue.

Activitats entre bastidors del ticker

Quan us vaig dir que el ticker és un filtre per a la font de les paparres, no era tota la veritat al respecte. Un ticker és un objecte que executa funcions al rellotge procés () tots els filtres del circuit (gràfic) al qual està connectat. Quan connectem un ticker a un filtre de gràfics en un programa C, mostrem al ticker el gràfic que controlarà a partir d'ara fins que el desactivem. Després de connectar-se, el ticker comença a examinar el gràfic confiat a la seva cura, compilant una llista de filtres que l'inclouen. Per no "comptar" el mateix filtre dues vegades, marca els filtres detectats col·locant-hi una casella de selecció. vist. La cerca es realitza mitjançant les taules d'enllaços que té cada filtre.

Durant el seu recorregut introductori pel gràfic, el ticker comprova si entre els filtres n'hi ha almenys un que actuï com a font de blocs de dades. Si no n'hi ha cap, el gràfic es considera incorrecte i el ticker es bloqueja.

Si el gràfic resulta ser "correcte", per a cada filtre trobat, la funció es crida per a la inicialització preprocés (). Tan aviat com arriba el moment del següent cicle de processament (cada 10 mil·lisegons per defecte), el ticker crida a la funció procés () per a tots els filtres d'origen trobats anteriorment i després per als filtres restants de la llista. Si el filtre té enllaços d'entrada, executeu la funció procés () es repeteix fins que les cues d'enllaç d'entrada estiguin buides. Després d'això, passa al següent filtre de la llista i el "desplaça" fins que els enllaços d'entrada estiguin lliures de missatges. El ticker es mou de filtre en filtre fins que la llista acaba. Això completa el processament del cicle.

Ara tornarem a les tuples i parlarem de per què s'ha afegit una entitat d'aquest tipus a la transmissió multimèdia. En general, la quantitat de dades requerides per l'algorisme que opera dins del filtre no coincideix i no és múltiple de la mida dels buffers de dades rebuts a l'entrada. Per exemple, estem escrivint un filtre que realitza una transformada de Fourier ràpida, que per definició només pot processar blocs de dades la mida dels quals és una potència de dos. Que siguin 512 comptes. Si les dades es generen per un canal telefònic, el buffer de dades de cada missatge a l'entrada ens portarà 160 mostres de senyal. És temptador no recollir dades de l'entrada fins que hi hagi la quantitat necessària de dades. Però en aquest cas, es produirà una col·lisió amb el ticker, que intentarà sense èxit desplaçar-se pel filtre fins que l'enllaç d'entrada estigui buit. Anteriorment, vam designar aquesta regla com el tercer principi del filtre. Segons aquest principi, la funció process() del filtre ha d'agafar totes les dades de les cues d'entrada.

A més, no serà possible prendre només 512 mostres de l'entrada, ja que només podeu agafar blocs sencers, és a dir. el filtre haurà de prendre 640 mostres i utilitzar-ne 512, la resta abans d'acumular una nova part de dades. Així, el nostre filtre, a més del seu treball principal, ha de proporcionar accions auxiliars per a l'emmagatzematge intermedi de dades d'entrada. Els desenvolupadors de la transmissió multimèdia i la solució a aquest problema general han desenvolupat un objecte especial: MSBufferizer (bufferer), que resol aquest problema mitjançant tuples.

Bufferizer (MSBufferizer)

Aquest és un objecte que acumularà dades d'entrada dins del filtre i començarà a enviar-les per processar-les tan bon punt la quantitat d'informació sigui suficient per executar l'algorisme del filtre. Mentre la memòria intermèdia acumula dades, el filtre funcionarà en mode inactiu, sense consumir la potència de processament del processador. Però tan bon punt la funció de lectura del buffer retorna un valor diferent de zero, la funció process() del filtre comença a prendre i processar dades del buffer en porcions de la mida requerida, fins que s'esgota.
Les dades que encara no són necessàries romanen a la memòria intermèdia com a primer element de la tupla, al qual s'adjunten blocs de dades d'entrada posteriors.

L'estructura que descriu el buffer:

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

Funcions per treballar amb MSBufferizer

Creació d'una nova instància de memòria intermèdia:

MSBufferizer * ms_bufferizer_new(void);

La memòria està assignada, inicialitzada a ms_bufferizer_init() i es retorna un punter.

Funció d'inicialització:

void ms_bufferizer_init(MSBufferizer *obj); 

La cua s'està inicialitzant q, camp mida es posa a zero.

Afegint un missatge:

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

El missatge m s'afegeix a la cua. S'afegeix la mida calculada dels blocs de dades mida.

Transferència de tots els missatges de la cua de dades d'enllaç a la memòria intermèdia q:

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

Transferència de missatges des d'un enllaç q al buffer es realitza mitjançant la funció ms_bufferizer_put().

Lectura del buffer:

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

Si la mida de les dades acumulades a la memòria intermèdia és inferior a la sol·licitada (datalen), aleshores la funció retorna zero, les dades no es copien a les dades. En cas contrari, es realitza una còpia seqüencial de dades de tuples situades a la memòria intermèdia. Després de la còpia, s'elimina la tupla i s'allibera la memòria. La còpia acaba en el moment en què es copien els bytes de dades. Si s'esgota l'espai al mig d'un bloc de dades, en aquest missatge, el bloc de dades es reduirà a la part restant sense copiar. La propera vegada que truqueu, la còpia continuarà des d'aquest punt.

Llegint la quantitat de dades que hi ha actualment disponible a la memòria intermèdia:

int ms_bufferizer_get_avail(MSBufferizer *obj); 

Retorna el camp mida tampó.

Descartant part de les dades a la memòria intermèdia:

void ms_bufferizer_skip_bytes(MSBufferizer *obj, int bytes);

El nombre especificat de bytes de dades es recuperen i es descarten. Es descarten les dades més antigues.

Esborrant tots els missatges de la memòria intermèdia:

void ms_bufferizer_flush(MSBufferizer *obj); 

El comptador de dades es reinicia a zero.

Esborrant tots els missatges de la memòria intermèdia:

void ms_bufferizer_uninit(MSBufferizer *obj); 

El comptador no es reinicia.

Eliminació de la memòria intermèdia i alliberament de memòria:

void ms_bufferizer_destroy(MSBufferizer *obj);  

Es poden trobar exemples d'ús del buffer al codi font de diversos filtres de reproducció multimèdia. Per exemple, al filtre MS_L16_ENC, que reordena els bytes de les mostres des de l'ordre de la xarxa fins a l'ordre de l'amfitrió: l16.c

En el següent article, analitzarem el problema de l'estimació de la càrrega d'un ticker i les maneres de combatre la càrrega informàtica excessiva en un streamer multimèdia.

Font: www.habr.com

Afegeix comentari