Explorando o motor de VoIP Mediastreamer2. Parte 11

O material do artigo está tirado do meu canle zen.

Explorando o motor de VoIP Mediastreamer2. Parte 11

Mecanismo de movemento de datos

  • Bloque de datos dblk_t
  • Mensaxe mblk_t
  • Funcións para traballar con mensaxes mblk_t
  • Cola queue_t
  • Funcións para traballar con filas queue_t
  • Filtros de conexión
  • Punto sinal do gráfico de procesamento de datos
  • Actividades entre bastidores do ticker
  • Bufferizer (MSBufferizer)
  • Funcións para traballar con MSBufferizer

No último Artigo desenvolvemos o noso propio filtro. Este artigo centrarase no mecanismo interno para mover datos entre filtros de transmisión multimedia. Isto permitirache escribir filtros sofisticados con menos esforzo no futuro.

Mecanismo de movemento de datos

O movemento de datos no streamer multimedia realízase mediante as colas descritas pola estrutura queue_t. Cadenas de mensaxes como mblk_t, que por si mesmos non conteñen datos de sinal, senón que só enlazan á mensaxe anterior, seguinte e ao bloque de datos. Ademais, quero facer fincapé especialmente en que tamén hai un campo para unha ligazón a unha mensaxe do mesmo tipo, que permite organizar unha lista de mensaxes ligada individualmente. Chamaremos tupla a un grupo de mensaxes unidas por tal lista. Así, calquera elemento da cola pode ser unha única mensaxe mblk_t, e quizais a cabeza dunha tupla de mensaxes mblk_t. Cada mensaxe de tupla pode ter o seu propio bloque de datos de sala. Discutiremos por que son necesarias as tuplas un pouco máis tarde.

Como se mencionou anteriormente, a mensaxe en si non contén un bloque de datos, senón que só contén un punteiro á área de memoria onde se almacena o bloque. Nesta parte, a imaxe xeral do traballo do streamer de medios lembra o almacén de portas no debuxo animado "Monsters, Inc.", onde as portas (enlaces a datos - salas) móvense a unha velocidade demente ao longo dos transportadores superiores, mentres que as propias salas permanecer inmóbil.

Agora, avanzando pola xerarquía de abaixo cara arriba, consideremos en detalle as entidades listadas do mecanismo de transmisión de datos no streamer multimedia.

Bloque de datos dblk_t

O bloque de datos consta dunha cabeceira e un búfer de datos. A cabeceira descríbese coa seguinte estrutura,

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

Os campos da estrutura conteñen punteiros ao comezo do búfer, ao final do búfer e á función para eliminar o búfer de datos. Último elemento da cabeceira db_ref — contador de referencia, se chega a cero, serve como sinal para eliminar este bloque da memoria. Se o bloque de datos foi creado pola función datab_alloc() , entón o búfer de datos colocarase na memoria inmediatamente despois da cabeceira. En todos os demais casos, o búfer pódese localizar nalgún lugar por separado. O búfer de datos conterá mostras de sinal ou outros datos que queremos procesar con filtros.

Créase unha nova instancia dun bloque de datos mediante a función:

dblk_t *datab_alloc(int size);

Como parámetro de entrada, dáselle o tamaño dos datos que almacenará o bloque. Alógase máis memoria para colocar unha cabeceira -estrutura- ao comezo da memoria asignada datos b. Pero cando se usan outras funcións, isto non sempre ocorre; nalgúns casos, o búfer de datos pode estar situado por separado da cabeceira do bloque de datos. Ao crear unha estrutura, os campos configúranse para que o seu campo db_base apuntou ao comezo da área de datos e db_lim ata o seu fin. Conta de ligazóns db_ref está configurado en un. O punteiro da función de borrado de datos está configurado en cero.

Mensaxe mblk_t

Como se dixo, os elementos da cola son do tipo mblk_t, defínese do seguinte xeito:

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;

Estrutura mblk_t contén punteiros ao principio b_prev, b_seguinte, que son necesarios para organizar unha lista dobremente vinculada (que é unha cola queue_t).

Despois vén o punteiro b_cont, que só se usa cando a mensaxe forma parte dunha tupla. Para a última mensaxe da tupla, este punteiro permanece nulo.

A continuación vemos un punteiro a un bloque de datos b_datap, para o que existe a mensaxe. Vai seguido de punteiros á área dentro do búfer de datos do bloque. Campo b_rptr especifica a localización desde a que se lerán os datos do búfer. Campo b_wptr indica a localización desde a que se realizarán as escrituras no búfer.

Os campos restantes son de natureza de servizo e non están relacionados co funcionamento do mecanismo de transferencia de datos.

Abaixo está unha única mensaxe co nome m1 e bloque de datos d1.
Explorando o motor de VoIP Mediastreamer2. Parte 11
A seguinte figura mostra unha tupla de tres mensaxes m1, m1_1, m1_2.
Explorando o motor de VoIP Mediastreamer2. Parte 11

Funcións de mensaxería mblk_t

Unha nova mensaxe mblk_t creado pola función:

mblk_t *allocb(int size, int pri); 

ela coloca unha nova mensaxe na memoria mblk_t cun bloque de datos do tamaño especificado tamaño, segundo argumento - pri non se usa nesta versión da biblioteca. Debe permanecer cero. Durante o funcionamento da función, asignarase memoria para a estrutura da nova mensaxe e chamarase á función mblk_init(), que restablecerá todos os campos da instancia creada da estrutura e, a continuación, utilizando o mencionado anteriormente datab_alloc(), creará un búfer de datos. Despois diso, configuraranse os campos da estrutura:

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

Na saída recibimos unha nova mensaxe con campos inicializados e un búfer de datos baleiro. Para engadir datos a unha mensaxe, cómpre copialos no búfer do bloque de datos:

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

onde datos é un punteiro á fonte de datos e tamaño - o seu tamaño.
entón cómpre actualizar o punteiro ao punto de escritura para que apunte de novo ao comezo da área libre no búfer:

msg->b_wptr = msg->b_wptr + size

Se precisa crear unha mensaxe desde un búfer existente, sen copiala, use a función:

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

A función, despois de crear a mensaxe e a estrutura do bloque de datos, configurará os seus punteiros aos datos do enderezo buff. Eses. neste caso, o búfer de datos non está situado despois dos campos de cabeceira do bloque de datos, como foi o caso ao crear un bloque de datos coa función datab_alloc(). O búfer cos datos pasados ​​á función permanecerá onde estaba, pero coa axuda de punteiros unirase á cabeceira recentemente creada do bloque de datos e, en consecuencia, á mensaxe.

A unha mensaxe mblk_t Pódense concatenar secuencialmente varios bloques de datos. Isto faise coa función:

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

mp — unha mensaxe á que se engadirá outro bloque de datos;
datos — punteiro ao bloque, cuxa copia engadirase á mensaxe;
tamaño - tamaño dos datos;
almofada — un indicador de que o tamaño da memoria asignada debe estar aliñado ao longo dun límite de 4 bytes (o recheo farase con ceros).

Se hai espazo suficiente no búfer de datos da mensaxe existente, os novos datos pegaranse detrás dos que xa están alí. Se hai menos espazo libre no búfer de datos da mensaxe que tamaño, entón créase unha mensaxe nova cun tamaño de búfer suficiente e os datos cópiase no seu búfer. Esta é unha mensaxe nova, ligada á orixinal mediante un punteiro b_cont. Neste caso, a mensaxe convértese nunha tupla.

Se necesitas engadir outro bloque de datos á tupla, debes usar a función:

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

ela atopará a última mensaxe na tupla (el ten b_cont será nulo) e chamará á función desta mensaxe anexar b().

Podes descubrir o tamaño dos datos nunha mensaxe ou tupla usando a función:

int msgdsize(const mblk_t *mp);

recorrerá todas as mensaxes da tupla e devolverá a cantidade total de datos nos búfers de datos desas mensaxes. Para cada mensaxe, a cantidade de datos calcúlase do seguinte xeito:

 mp->b_wptr - mp->b_rptr

Para combinar dúas tuplas, use a función:

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

ela engade a tupla novo á cola da tupla mp e devolve un punteiro á última mensaxe da tupla resultante.

Se é necesario, unha tupla pódese converter nunha única mensaxe cun único bloque de datos; isto faise coa función:

void msgpullup(mblk_t *mp,int len);

se argumento len é -1, entón o tamaño do búfer asignado determínase automaticamente. Se len é un número positivo, crearase un búfer deste tamaño e copiaranse nel os datos da mensaxe da tupla. Se o búfer se esgota, a copia pararase alí. A primeira mensaxe da tupla recibirá un novo búfer de tamaño cos datos copiados. As mensaxes restantes eliminaranse e a memoria devolverase ao montón.

Ao eliminar unha estrutura mblk_t o reconto de referencia do bloque de datos tense en conta se, ao chamar freeb() resulta ser cero, entón o búfer de datos elimínase xunto coa instancia mblk_t, que o apunta.

Iniciando os campos dunha nova mensaxe:

void mblk_init(mblk_t *mp);

Engadindo outro dato á mensaxe:

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

Se os novos datos non encaixan no espazo libre do búfer de datos da mensaxe, engádese á mensaxe unha mensaxe creada por separado cun búfer do tamaño necesario (un punteiro á mensaxe engadida está configurado na primeira mensaxe) e mensaxe convértese nunha tupla.

Engadindo un dato a unha tupla:

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

A función chama a appendb() nun bucle.

Combinando dúas tuplas nunha:

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

Mensaxe novo estará anexo a mp.

Facendo unha copia dunha única mensaxe:

mblk_t *copyb(const mblk_t *mp);

Copia completa dunha tupla con todos os bloques de datos:

mblk_t *copymsg(const mblk_t *mp);

Os elementos da tupla son copiados pola función copyb().

Crea unha copia sinxela dunha mensaxe mblk_t. Neste caso, o bloque de datos non se copia, pero o seu contador de referencia aumenta db_ref:

mblk_t *dupb(mblk_t *mp);

Facendo unha copia lixeira dunha tupla. Os bloques de datos non se copian, só se incrementan os seus contadores de referencia db_ref:

mblk_t *dupmsg(mblk_t* m);

Pegando todas as mensaxes dunha tupla nunha soa mensaxe:

void msgpullup(mblk_t *mp,size_t len);

Se o argumento len é -1, entón o tamaño do búfer asignado determínase automaticamente.

Eliminando unha mensaxe, tupla:

void freemsg(mblk_t *mp);

O reconto de referencia do bloque de datos diminúe nun un. Se chega a cero, o bloque de datos tamén se elimina.

Cálculo da cantidade total de datos nunha mensaxe ou tupla.

size_t msgdsize(const mblk_t *mp);

Recuperando unha mensaxe da cola da cola:

mblk_t *ms_queue_peek_last (q);

Copiando o contido dos campos reservados dunha mensaxe noutra mensaxe (de feito, estes campos conteñen marcas que son utilizadas polo transmisor multimedia):

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

Quenda queue_t

A cola de mensaxes no transmisor de medios implícase como unha lista circular dobremente ligada. Cada elemento da lista contén un punteiro a un bloque de datos con mostras de sinal. Resulta que só os punteiros ao bloque de datos se moven á súa vez, mentres que os propios datos permanecen inmóbiles. Eses. só se moven as ligazóns a elas.
Estrutura que describe a cola queue_t, que se mostra a continuación:

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

A estrutura contén un campo: un punteiro _q_tapón escriba *mblk_t, apunta ao primeiro elemento (mensaxe) da cola. O segundo campo da estrutura é o contador de mensaxes na cola.
A seguinte figura mostra unha cola chamada q1 que contén 4 mensaxes m1, m2, m3, m4.
Explorando o motor de VoIP Mediastreamer2. Parte 11
A seguinte figura mostra unha cola chamada q1 que contén 4 mensaxes m1,m2,m3,m4. A mensaxe m2 é a cabeza dunha tupla que contén dúas mensaxes máis m2_1 e m2_2.

Explorando o motor de VoIP Mediastreamer2. Parte 11

Funcións para traballar con filas queue_t

Inicialización da cola:

void qinit(queue_t *q);

Campo _q_tapón (en diante chamarémolo “tapón”) é inicializado pola función mblk_init(), o seu punteiro de elemento anterior e seguinte axústanse para que se apunten a si mesmo. O contador de elementos da cola restablece a cero.

Engadindo un novo elemento (mensaxes):

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

Novo elemento m engádese ao final da lista, os punteiros do elemento axústanse para que o tapón se converta no seguinte elemento para el e convértese no elemento anterior para o tapón. O contador de elementos da cola increméntase.

Recuperando un elemento da cola:

mblk_t * getq(queue_t *q); 

A mensaxe que aparece despois de que se recupere o tapón e decremente o contador de elementos. Se non hai elementos na cola excepto o tapón, devólvese 0.

Inserir unha mensaxe nunha cola:

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

Элемент mp inserido antes do elemento EMP. Se EMP=0, entón a mensaxe engádese á cola da cola.

Recuperando unha mensaxe da cabeza da cola:

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

O contador de elementos está decrementado.

Lendo un punteiro ao primeiro elemento da cola:

mblk_t * peekq(queue_t *q); 

Eliminando todos os elementos da cola mentres se eliminan os propios elementos:

void flushq(queue_t *q, int how);

argumento como non utilizados. O contador de elementos da cola está configurado en cero.

Macro para ler un punteiro ao último elemento da cola:

mblk_t * qlast(queue_t *q);

Cando traballes con filas de mensaxes, ten en conta que cando chames ms_queue_put(q, m) cun punteiro nulo á mensaxe, a función fai un bucle. O teu programa conxelarase. compórtase de xeito similar ms_queue_next(q, m).

Filtros de conexión

A cola descrita anteriormente utilízase para pasar mensaxes dun filtro a outro ou dun a varios filtros. Os filtros e as súas conexións forman un gráfico dirixido. A entrada ou saída do filtro chamarase palabra xeral "pin". Para describir a orde na que os filtros están conectados entre si, o streamer multimedia usa o concepto de "punto de sinal". O punto de sinal é a estrutura _MSCPoint, que contén un punteiro para o filtro e o número dun dos seus pinos; en consecuencia, describe a conexión dunha das entradas ou saídas do filtro.

Punto sinal do gráfico de procesamento de datos

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

Os pines do filtro están numerados a partir de cero.

A conexión de dous pinos mediante unha cola de mensaxes descríbese na estrutura _MSQueue, que contén unha fila de mensaxes e punteiros aos dous puntos de sinal que conecta:

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

Chamaremos a esta estrutura un enlace de sinal. Cada filtro de transmisión multimedia contén unha táboa de ligazóns de entrada e unha táboa de ligazóns de saída (MSQueue). O tamaño das táboas establécese ao crear un filtro; xa o fixemos mediante unha variable exportada de tipo MSFilterDesc, cando desenvolvemos o noso propio filtro. A continuación móstrase unha estrutura que describe calquera filtro nun streamer multimedia. 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;

Despois de conectar os filtros no programa C de acordo co noso plan (pero non conectar o ticker), creamos así un gráfico dirixido, cuxos nodos son instancias da estrutura. MSFilter, e as beiras son exemplos de ligazóns MSQueue.

Actividades entre bastidores do ticker

Cando che dixen que o ticker é un filtro para a fonte das carrachas, non era toda a verdade sobre iso. Un ticker é un obxecto que executa funcións no reloxo proceso () todos os filtros do circuíto (gráfico) ao que está conectado. Cando conectamos un ticker a un filtro gráfico nun programa C, mostrámoslle ao ticker o gráfico que controlará a partir de agora ata que o desactivemos. Despois de conectarse, o ticker comeza a examinar o gráfico encargado ao seu coidado, compilando unha lista de filtros que o inclúen. Para non "contar" o mesmo filtro dúas veces, marca os filtros detectados marcando neles unha caixa de verificación visto. A busca realízase mediante as táboas de ligazóns que ten cada filtro.

Durante o seu percorrido introductorio ao gráfico, o ticker comproba se entre os filtros hai polo menos un que actúe como fonte de bloques de datos. Se non hai ningunha, entón o gráfico considérase incorrecto e o ticker falla.

Se o gráfico resulta ser "correcto", para cada filtro atopado, a función chámase para a inicialización preproceso (). En canto chega o momento para o seguinte ciclo de procesamento (cada 10 milisegundos por defecto), o ticker chama a función proceso () para todos os filtros de orixe atopados anteriormente e, a continuación, para os filtros restantes da lista. Se o filtro ten ligazóns de entrada, executa a función proceso () repítese ata que as filas de ligazóns de entrada estean baleiras. Despois diso, pasa ao seguinte filtro da lista e "desprázao" ata que as ligazóns de entrada estean libres de mensaxes. O ticker móvese de filtro en filtro ata que remata a lista. Isto completa o procesamento do ciclo.

Agora volveremos ás tuplas e falaremos de por que se engadiu unha entidade deste tipo ao streamer multimedia. En xeral, a cantidade de datos requirida polo algoritmo que opera dentro do filtro non coincide e non é un múltiplo do tamaño dos búfers de datos recibidos na entrada. Por exemplo, estamos escribindo un filtro que realiza unha transformada de Fourier rápida, que por definición só pode procesar bloques de datos cuxo tamaño é unha potencia de dous. Que sexan 512 contas. Se os datos son xerados por unha canle telefónica, entón o búfer de datos de cada mensaxe na entrada traerá 160 mostras de sinal. É tentador non recoller datos da entrada ata que estea alí a cantidade necesaria de datos. Pero neste caso, producirase unha colisión co ticker, que tentará desprazar o filtro sen éxito ata que a ligazón de entrada estea baleira. Anteriormente, designamos esta regra como o terceiro principio do filtro. Segundo este principio, a función process() do filtro debe tomar todos os datos das filas de entrada.

Ademais, non será posible tomar só 512 mostras da entrada, xa que só se poden tomar bloques enteiros, é dicir. o filtro terá que tomar 640 mostras e utilizar 512 delas, o resto antes de acumular unha nova porción de datos. Así, o noso filtro, ademais do seu traballo principal, debe proporcionar accións auxiliares para o almacenamento intermedio dos datos de entrada. Os desenvolvedores do streamer multimedia e a solución a este problema xeral desenvolveron un obxecto especial - MSBufferizer (búfer), que resolve este problema usando tuplas.

Bufferizer (MSBufferizer)

Este é un obxecto que acumulará datos de entrada dentro do filtro e comezará a envialos para procesalos en canto a cantidade de información sexa suficiente para executar o algoritmo do filtro. Mentres o búfer está acumulando datos, o filtro funcionará en modo inactivo, sen gastar a potencia de procesamento do procesador. Pero tan pronto como a función de lectura do búfer devolve un valor distinto de cero, a función process() do filtro comeza a tomar e procesar os datos do búfer en porcións do tamaño necesario, ata que se esgota.
Os datos que aínda non son necesarios permanecen no búfer como primeiro elemento da tupla, ao que se unen os seguintes bloques de datos de entrada.

A estrutura que describe o buffer:

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

Funcións para traballar con MSBufferizer

Creando unha nova instancia de búfer:

MSBufferizer * ms_bufferizer_new(void);

A memoria está asignada, inicializada en ms_bufferizer_init() e devólvese un punteiro.

Función de inicialización:

void ms_bufferizer_init(MSBufferizer *obj); 

A cola estase a inicializar q, campo tamaño está configurado en cero.

Engadindo unha mensaxe:

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

A mensaxe m engádese á cola. Engádese o tamaño calculado dos bloques de datos tamaño.

Transferir todas as mensaxes da cola de datos de ligazóns ao búfer q:

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

Transferir mensaxes desde unha ligazón q no búfer realízase mediante a función ms_bufferizer_put().

Lectura do buffer:

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

Se o tamaño dos datos acumulados no búfer é menor que o solicitado (datos), entón a función devolve cero, os datos non se copian nos datos. En caso contrario, realízase a copia secuencial dos datos das tuplas situadas no búfer. Despois da copia, elimínase a tupla e libérase a memoria. A copia remata no momento no que se copian os bytes de datos. Se o espazo esgota no medio dun bloque de datos, nesta mensaxe, o bloque de datos reducirase á parte restante sen copiar. A próxima vez que chame, a copia continuará dende este punto.

Lendo a cantidade de datos que está actualmente dispoñible no búfer:

int ms_bufferizer_get_avail(MSBufferizer *obj); 

Devolve o campo tamaño tampón.

Descartando parte dos datos no búfer:

void ms_bufferizer_skip_bytes(MSBufferizer *obj, int bytes);

O número especificado de bytes de datos son recuperados e descartados. Descartaranse os datos máis antigos.

Eliminando todas as mensaxes do búfer:

void ms_bufferizer_flush(MSBufferizer *obj); 

O contador de datos restablece a cero.

Eliminando todas as mensaxes do búfer:

void ms_bufferizer_uninit(MSBufferizer *obj); 

O contador non se reinicia.

Eliminando o búfer e liberando memoria:

void ms_bufferizer_destroy(MSBufferizer *obj);  

Pódense atopar exemplos de uso do búfer no código fonte de varios filtros de transmisión multimedia. Por exemplo, no filtro MS_L16_ENC, que reorganiza os bytes nas mostras desde a orde da rede ata a orde do host: l16.c

No seguinte artigo, analizaremos o problema da estimación da carga do ticker e como xestionar a carga de computación excesiva no streamer multimedia.

Fonte: www.habr.com

Engadir un comentario