Exploration du moteur VoIP Mediastreamer2. Partie 11

Le matériel de l'article est tiré de mon canal zen.

Exploration du moteur VoIP Mediastreamer2. Partie 11

Mécanisme de déplacement des données

  • Bloc de données dblk_t
  • Messagemblk_t
  • Fonctions pour travailler avec les messages mblk_t
  • File d'attente queue_t
  • Fonctions pour travailler avec les files d'attente queue_t
  • Connexion des filtres
  • Point signal du graphique de traitement des données
  • Activités en coulisses du téléscripteur
  • Tampon (MSBufferizer)
  • Fonctions pour travailler avec MSBufferizer

À la fin article nous avons développé notre propre filtre. Cet article se concentrera sur le mécanisme interne de déplacement des données entre les filtres de flux multimédia. Cela vous permettra d'écrire des filtres sophistiqués avec moins d'effort à l'avenir.

Mécanisme de déplacement des données

Le mouvement des données dans le streamer multimédia est effectué à l'aide de files d'attente décrites par la structure file d'attente_t. Des chaînes de messages comme mblk_t, qui eux-mêmes ne contiennent pas de données de signal, mais uniquement des liens vers le message précédent et suivant et vers le bloc de données. De plus, je tiens particulièrement à souligner qu'il existe également un champ pour un lien vers un message du même type, qui permet d'organiser une liste de messages liée de manière unique. Nous appellerons un groupe de messages réunis par une telle liste un tuple. Ainsi, n'importe quel élément de la file d'attente peut être un seul message mblk_t, et peut-être la tête d'un tuple de message mblk_t. Chaque message de tuple peut avoir son propre bloc de données de salle. Nous verrons pourquoi les tuples sont nécessaires un peu plus tard.

Comme mentionné ci-dessus, le message lui-même ne contient pas de bloc de données ; il contient uniquement un pointeur vers la zone mémoire où le bloc est stocké. Dans cette partie, l'image globale du travail du streamer multimédia rappelle l'entrepôt de portes du dessin animé « Monsters, Inc. », où les portes (liens vers les salles de données) se déplacent à une vitesse folle le long de convoyeurs aériens, tandis que les pièces elles-mêmes rester immobile.

Maintenant, en parcourant la hiérarchie de bas en haut, examinons en détail les entités répertoriées du mécanisme de transmission de données dans le streamer multimédia.

Bloc de données dblk_t

Le bloc de données se compose d'un en-tête et d'un tampon de données. L'en-tête est décrit par la structure suivante,

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

Les champs de la structure contiennent des pointeurs vers le début du tampon, la fin du tampon et la fonction de suppression du tampon de données. Dernier élément de l'en-tête db_ref — compteur de référence, s'il atteint zéro, cela sert de signal pour supprimer ce bloc de la mémoire. Si le bloc de données a été créé par la fonction datab_alloc() , alors le tampon de données sera placé en mémoire immédiatement après l'en-tête. Dans tous les autres cas, le tampon peut être situé quelque part séparément. Le tampon de données contiendra des échantillons de signaux ou d'autres données que nous souhaitons traiter avec des filtres.

Une nouvelle instance d'un bloc de données est créée à l'aide de la fonction :

dblk_t *datab_alloc(int size);

En tant que paramètre d'entrée, la taille des données que le bloc va stocker est donnée. Plus de mémoire est allouée afin de placer un en-tête - structure - au début de la mémoire allouée donnéesb. Mais lors de l'utilisation d'autres fonctions, cela ne se produit pas toujours : dans certains cas, le tampon de données peut être situé séparément de l'en-tête du bloc de données. Lors de la création d'une structure, les champs sont configurés pour que son champ db_base pointé vers le début de la zone de données, et db_lim jusqu'à sa fin. Nombre de liens db_ref est défini sur un. Le pointeur de la fonction d'effacement des données est mis à zéro.

Post mblk_t

Comme indiqué, les éléments de file d'attente sont de type mblk_t, il est défini comme suit :

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;

structure mblk_t contient des pointeurs au début b_prev, b_suivant, qui sont nécessaires pour organiser une liste doublement chaînée (qui est une file d'attente file d'attente_t).

Vient ensuite le pointeur b_cont, qui n'est utilisé que lorsque le message fait partie d'un tuple. Pour le dernier message du tuple, ce pointeur reste nul.

Ensuite, nous voyons un pointeur vers un bloc de données b_datap, pour lequel le message existe. Il est suivi de pointeurs vers la zone à l'intérieur du tampon de données de bloc. Champ b_rptr spécifie l'emplacement à partir duquel les données du tampon seront lues. Champ b_wptr indique l'emplacement à partir duquel les écritures dans le tampon seront effectuées.

Les champs restants sont de nature service et ne concernent pas le fonctionnement du mécanisme de transfert de données.

Vous trouverez ci-dessous un seul message avec le nom m1 et bloc de données d1.
Exploration du moteur VoIP Mediastreamer2. Partie 11
La figure suivante montre un tuple de trois messages m1, m1_1, m1_2.
Exploration du moteur VoIP Mediastreamer2. Partie 11

Fonctions de messagerie mblk_t

Un nouveau message mblk_t créé par la fonction :

mblk_t *allocb(int size, int pri); 

elle place un nouveau message en mémoire mblk_t avec un bloc de données de la taille spécifiée taille, deuxième argument - pri non utilisé dans cette version de la bibliothèque. Il devrait rester nul. Pendant le fonctionnement de la fonction, de la mémoire sera allouée pour la structure du nouveau message et la fonction sera appelée mblk_init(), qui réinitialisera tous les champs de l'instance créée de la structure puis, en utilisant le mentionné ci-dessus datab_alloc(), créera un tampon de données. Après quoi les champs de la structure seront configurés :

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

En sortie, nous recevons un nouveau message avec des champs initialisés et un tampon de données vide. Pour ajouter des données à un message, vous devez les copier dans le tampon du bloc de données :

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

données est un pointeur vers la source de données, et taille - leur taille.
alors vous devez mettre à jour le pointeur vers le point d'écriture afin qu'il pointe à nouveau vers le début de la zone libre dans le tampon :

msg->b_wptr = msg->b_wptr + size

Si vous devez créer un message à partir d'un tampon existant, sans le copier, alors utilisez la fonction :

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

La fonction, après avoir créé le message et la structure du bloc de données, configurera ses pointeurs vers les données à l'adresse buf. Ceux. dans ce cas, le tampon de données ne se trouve pas après les champs d'en-tête du bloc de données, comme c'était le cas lors de la création d'un bloc de données avec la fonction datab_alloc(). Le tampon avec les données transmises à la fonction restera là où il se trouvait, mais à l'aide de pointeurs, il sera attaché à l'en-tête nouvellement créé du bloc de données et, par conséquent, au message.

À un message mblk_t Plusieurs blocs de données peuvent être concaténés séquentiellement. Cela se fait par la fonction :

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

mp — un message auquel un autre bloc de données sera ajouté ;
données — pointeur vers le bloc dont une copie sera ajoutée au message ;
taille — taille des données ;
chemin — un indicateur indiquant que la taille de la mémoire allouée doit être alignée le long d'une limite de 4 octets (le remplissage sera effectué avec des zéros).

S'il y a suffisamment d'espace dans le tampon de données de message existant, les nouvelles données seront collées derrière les données déjà présentes. S'il y a moins d'espace libre dans le tampon de données du message que taille, puis un nouveau message est créé avec une taille de tampon suffisante et les données sont copiées dans son tampon. Ceci est un nouveau message, lié à l'original à l'aide d'un pointeur b_cont. Dans ce cas, le message se transforme en tuple.

Si vous devez ajouter un autre bloc de données au tuple, vous devez alors utiliser la fonction :

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

elle trouvera le dernier message du tuple (il a b_cont sera nul) et appellera la fonction pour ce message appendb().

Vous pouvez connaître la taille des données dans un message ou un tuple en utilisant la fonction :

int msgdsize(const mblk_t *mp);

il parcourra tous les messages du tuple et renverra la quantité totale de données dans les tampons de données de ces messages. Pour chaque message, la quantité de données est calculée comme suit :

 mp->b_wptr - mp->b_rptr

Pour combiner deux tuples, utilisez la fonction :

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

elle ajoute le tuple nouveau à la queue du tuple mp et renvoie un pointeur vers le dernier message du tuple résultant.

Si nécessaire, un tuple peut être transformé en un seul message avec un seul bloc de données ; cela se fait par la fonction :

void msgpullup(mblk_t *mp,int len);

si argument len est -1, alors la taille du tampon alloué est déterminée automatiquement. Si len est un nombre positif, un tampon de cette taille sera créé et les données du message du tuple y seront copiées. Si le tampon est épuisé, la copie s'arrêtera là. Le premier message du tuple recevra un nouveau tampon de taille avec les données copiées. Les messages restants seront supprimés et la mémoire renvoyée dans le tas.

Lors de la suppression d'une structure mblk_t le compteur de références du bloc de données est pris en compte si lors de l'appel gratuitb() il s'avère être nul, puis le tampon de données est supprimé avec l'instance mblk_t, ce qui le pointe.

Initialiser les champs d'un nouveau message :

void mblk_init(mblk_t *mp);

Ajout d'une autre donnée au message :

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

Si les nouvelles données ne rentrent pas dans l'espace libre du tampon de données du message, alors un message créé séparément avec un tampon de la taille requise est attaché au message (un pointeur vers le message ajouté est défini dans le premier message) et le le message se transforme en tuple.

Ajouter une donnée à un tuple :

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

La fonction appelle appendb() dans une boucle.

Combiner deux tuples en un :

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

Post nouveau sera attaché à mp.

Faire une copie d'un seul message :

mblk_t *copyb(const mblk_t *mp);

Copie complète d'un tuple avec tous les blocs de données :

mblk_t *copymsg(const mblk_t *mp);

Les éléments du tuple sont copiés par la fonction copieb().

Créer une copie simple d'un message mblk_t. Dans ce cas, le bloc de données n'est pas copié, mais son compteur de référence est augmenté db_ref:

mblk_t *dupb(mblk_t *mp);

Faire une copie légère d'un tuple. Les blocs de données ne sont pas copiés, seuls leurs compteurs de référence sont incrémentés db_ref:

mblk_t *dupmsg(mblk_t* m);

Coller tous les messages d'un tuple en un seul message :

void msgpullup(mblk_t *mp,size_t len);

Si l'argumentation len est -1, alors la taille du tampon alloué est déterminée automatiquement.

Suppression d'un message, tuple :

void freemsg(mblk_t *mp);

Le nombre de références du bloc de données est décrémenté de un. S'il atteint zéro, le bloc de données est également supprimé.

Calcul de la quantité totale de données dans un message ou un tuple.

size_t msgdsize(const mblk_t *mp);

Récupération d'un message en fin de file d'attente :

mblk_t *ms_queue_peek_last (q);

Copie du contenu des champs réservés d'un message dans un autre message (en fait, ces champs contiennent des drapeaux qui sont utilisés par le streamer multimédia) :

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

File d'attente file d'attente_t

La file d'attente de messages dans le streamer multimédia est implémentée sous la forme d'une liste circulaire à double lien. Chaque élément de liste contient un pointeur vers un bloc de données contenant des échantillons de signaux. Il s'avère que seuls les pointeurs vers le bloc de données se déplacent à leur tour, tandis que les données elles-mêmes restent immobiles. Ceux. seuls les liens vers eux sont déplacés.
Structure décrivant la file d'attente file d'attente_t, indiqué ci-dessous:

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

La structure contient un champ - un pointeur _q_stopper tapez *mblk_t, il pointe vers le premier élément (message) de la file d'attente. Le deuxième champ de la structure est le compteur de messages dans la file d'attente.
La figure ci-dessous montre une file d'attente nommée q1 contenant 4 messages m1, m2, m3, m4.
Exploration du moteur VoIP Mediastreamer2. Partie 11
La figure suivante montre une file d'attente nommée q1 contenant 4 messages m1, m2, m3, m4. Le message m2 est la tête d'un tuple qui contient deux autres messages m2_1 et m2_2.

Exploration du moteur VoIP Mediastreamer2. Partie 11

Fonctions pour travailler avec les files d'attente queue_t

Initialisation de la file d'attente :

void qinit(queue_t *q);

Champ _q_stopper (nous l’appellerons ci-après « stopper ») est initialisé par la fonction mblk_init(), son élément précédent et son pointeur d'élément suivant sont ajustés pour pointer vers lui-même. Le compteur d'éléments de file d'attente est remis à zéro.

Ajout d'un nouvel élément (messages) :

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

Nouvel élément m est ajouté à la fin de la liste, les pointeurs d'élément sont ajustés de sorte que le bouchon devienne l'élément suivant pour celui-ci et qu'il devienne l'élément précédent pour le bouchon. Le compteur d'éléments de file d'attente est incrémenté.

Récupération d'un élément de la file d'attente :

mblk_t * getq(queue_t *q); 

Le message qui vient après le stopper est récupéré et le compteur d'éléments est décrémenté. S'il n'y a aucun élément dans la file d'attente à l'exception du stoppeur, alors 0 est renvoyé.

Insérer un message dans une file d'attente :

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

membre mp inséré avant l'élément emp. Si emp=0, alors le message est ajouté à la queue de la file d'attente.

Récupération d'un message en tête de file d'attente :

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

Le compteur d'éléments est décrémenté.

Lecture d'un pointeur vers le premier élément de la file d'attente :

mblk_t * peekq(queue_t *q); 

Supprimer tous les éléments de la file d'attente tout en supprimant les éléments eux-mêmes :

void flushq(queue_t *q, int how);

Argument how non utilisé. Le compteur d'éléments de file d'attente est mis à zéro.

Macro de lecture d'un pointeur vers le dernier élément de la file d'attente :

mblk_t * qlast(queue_t *q);

Lorsque vous travaillez avec des files d'attente de messages, sachez que lorsque vous appelez ms_queue_put(q,m) avec un pointeur nul vers le message, la fonction boucle. Votre programme va se bloquer. se comporte de la même manière ms_queue_next(q, m).

Connexion des filtres

La file d'attente décrite ci-dessus permet de transmettre des messages d'un filtre à un autre ou d'un à plusieurs filtres. Les filtres et leurs connexions forment un graphe orienté. L'entrée ou la sortie du filtre sera appelée le mot général « pin ». Pour décrire l'ordre dans lequel les filtres sont connectés les uns aux autres, le streamer multimédia utilise le concept de « point de signal ». Le point signal est une structure _MSCPoint, qui contient un pointeur vers le filtre et le numéro d'une de ses broches ; il décrit ainsi la connexion d'une des entrées ou sorties du filtre.

Point signal du graphique de traitement des données

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

Les broches du filtre sont numérotées à partir de zéro.

La connexion de deux broches par une file de messages est décrite par la structure _MSQueue, qui contient une file d'attente de messages et des pointeurs vers les deux points de signal qu'elle connecte :

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

Nous appellerons cette structure une liaison de signal. Chaque filtre de flux multimédia contient un tableau de liens d'entrée et un tableau de liens de sortie (File d'attente MS). La taille des tableaux est définie lors de la création d'un filtre ; nous l'avons déjà fait à l'aide d'une variable exportée de type MSFilterDesc, lorsque nous avons développé notre propre filtre. Vous trouverez ci-dessous une structure qui décrit n'importe quel filtre dans un streamer multimédia, MSFiltre:


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;

Après avoir connecté les filtres dans le programme C conformément à notre plan (mais sans connecter le ticker), nous avons ainsi créé un graphe orienté dont les nœuds sont des instances de la structure MSFiltre, et les arêtes sont des instances de liens File d'attente MS.

Activités en coulisses du téléscripteur

Quand je vous ai dit que le ticker était un filtre pour la source des tiques, ce n'était pas toute la vérité à ce sujet. Un ticker est un objet qui exécute des fonctions sur l'horloge traiter() tous les filtres du circuit (graphique) auquel il est connecté. Lorsque nous connectons un ticker à un filtre graphique dans un programme C, nous montrons au ticker le graphique qu'il contrôlera désormais jusqu'à ce que nous le désactivions. Après la connexion, le ticker commence à examiner le graphique qui lui est confié, en dressant une liste de filtres qui l'incluent. Afin de ne pas « compter » deux fois le même filtre, il marque les filtres détectés en y cochant une case. vu. La recherche s'effectue à l'aide des tables de liens dont dispose chaque filtre.

Lors de sa visite introductive du graphique, le ticker vérifie si parmi les filtres il y en a au moins un qui fait office de source de blocs de données. S’il n’y en a pas, le graphique est considéré comme incorrect et le téléscripteur plante.

Si le graphique s'avère « correct », pour chaque filtre trouvé, la fonction est appelée pour initialisation prétraiter(). Dès que vient le moment du prochain cycle de traitement (toutes les 10 millisecondes par défaut), le ticker appelle la fonction traiter() pour tous les filtres source trouvés précédemment, puis pour les filtres restants dans la liste. Si le filtre a des liens d'entrée, alors exécutez la fonction traiter() se répète jusqu'à ce que les files d'attente des liens d'entrée soient vides. Après cela, il passe au filtre suivant dans la liste et le « fait défiler » jusqu'à ce que les liens d'entrée soient exempts de messages. Le ticker se déplace de filtre en filtre jusqu'à la fin de la liste. Ceci termine le traitement du cycle.

Nous allons maintenant revenir aux tuples et expliquer pourquoi une telle entité a été ajoutée au streamer multimédia. En général, la quantité de données requise par l'algorithme fonctionnant à l'intérieur du filtre ne coïncide pas et n'est pas un multiple de la taille des tampons de données reçus en entrée. Par exemple, nous écrivons un filtre qui effectue une transformée de Fourier rapide, qui par définition ne peut traiter que des blocs de données dont la taille est une puissance de deux. Que ce soit 512 chefs d'accusation. Si les données sont générées par un canal téléphonique, alors le tampon de données de chaque message à l'entrée nous apportera 160 échantillons de signal. Il est tentant de ne pas collecter de données à partir de l’entrée tant que la quantité de données requise n’est pas disponible. Mais dans ce cas, une collision se produira avec le ticker, qui tentera en vain de faire défiler le filtre jusqu'à ce que le lien d'entrée soit vide. Auparavant, nous avions désigné cette règle comme le troisième principe du filtre. Selon ce principe, la fonction process() du filtre doit récupérer toutes les données des files d'attente d'entrée.

De plus, il ne sera pas possible de prélever uniquement 512 échantillons de l'entrée, puisque vous ne pouvez prélever que des blocs entiers, c'est-à-dire le filtre devra prélever 640 échantillons et en utiliser 512, le reste avant d'accumuler une nouvelle partie de données. Ainsi, notre filtre, en plus de son travail principal, doit fournir des actions auxiliaires pour le stockage intermédiaire des données d'entrée. Les développeurs du streamer multimédia et de la solution à ce problème général ont développé un objet spécial - MSBufferizer (bufferer), qui résout ce problème à l'aide de tuples.

Tampon (MSBufferizer)

Il s'agit d'un objet qui accumulera les données d'entrée à l'intérieur du filtre et commencera à les soumettre pour traitement dès que la quantité d'informations sera suffisante pour exécuter l'algorithme de filtre. Pendant que le tampon accumule des données, le filtre fonctionnera en mode veille, sans utiliser la puissance de traitement du processeur. Mais dès que la fonction de lecture du tampon renvoie une valeur autre que zéro, la fonction process() du filtre commence à prendre et à traiter les données du tampon par portions de la taille requise, jusqu'à ce qu'elles soient épuisées.
Les données qui ne sont pas encore requises restent dans le tampon en tant que premier élément du tuple, auquel les blocs suivants de données d'entrée sont attachés.

La structure qui décrit le tampon :

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

Fonctions pour travailler avec MSBufferizer

Création d'une nouvelle instance de tampon :

MSBufferizer * ms_bufferizer_new(void);

La mémoire est allouée, initialisée dans ms_bufferizer_init() et un pointeur est renvoyé.

Fonction d'initialisation :

void ms_bufferizer_init(MSBufferizer *obj); 

La file d'attente s'initialise q, champ taille est mis à zéro.

Ajout d'un message :

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

Le message m est ajouté à la file d'attente. La taille calculée des blocs de données est ajoutée à taille.

Transfert de tous les messages de la file d'attente de données de lien vers le tampon q:

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

Transférer des messages à partir d'un lien q dans le tampon est effectué à l'aide de la fonction ms_bufferizer_put().

Lecture depuis le tampon :

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

Si la taille des données accumulées dans le tampon est inférieure à celle demandée (données), alors la fonction renvoie zéro, les données ne sont pas copiées dans data. Sinon, une copie séquentielle des données des tuples situés dans le tampon est effectuée. Après copie, le tuple est supprimé et la mémoire est libérée. La copie se termine au moment où les octets de données sont copiés. Si l'espace manque au milieu d'un bloc de données, alors dans ce message, le bloc de données sera réduit à la partie restante non copiée. La prochaine fois que vous appellerez, la copie continuera à partir de ce point.

Lecture de la quantité de données actuellement disponibles dans le tampon :

int ms_bufferizer_get_avail(MSBufferizer *obj); 

Renvoie le champ taille tampon.

Suppression d'une partie des données dans le tampon :

void ms_bufferizer_skip_bytes(MSBufferizer *obj, int bytes);

Le nombre spécifié d'octets de données est récupéré et supprimé. Les données les plus anciennes sont supprimées.

Suppression de tous les messages dans le tampon :

void ms_bufferizer_flush(MSBufferizer *obj); 

Le compteur de données est remis à zéro.

Suppression de tous les messages dans le tampon :

void ms_bufferizer_uninit(MSBufferizer *obj); 

Le compteur n'est pas réinitialisé.

Suppression du tampon et libération de mémoire :

void ms_bufferizer_destroy(MSBufferizer *obj);  

Des exemples d'utilisation du tampon peuvent être trouvés dans le code source de plusieurs filtres de streaming multimédia. Par exemple, dans le filtre MS_L16_ENC, qui réorganise les octets dans les échantillons de l'ordre réseau à l'ordre hôte : l16.c

Dans le prochain article, nous examinerons la question de l'estimation de la charge du ticker et comment gérer une charge de calcul excessive dans le streamer multimédia.

Source: habr.com

Ajouter un commentaire