Истражување на VoIP моторот Mediastreamer2. Дел 11

Материјалот на статијата е преземен од моето зен канал.

Истражување на VoIP моторот Mediastreamer2. Дел 11

Механизам за движење на податоци

  • Блок на податоци dblk_t
  • Порака mblk_t
  • Функции за работа со пораки mblk_t
  • Редица queue_t
  • Функции за работа со редици queue_t
  • Поврзување на филтри
  • График на сигнална точка на обработка на податоци
  • Задкулисните активности на тикерот
  • Баферизер (MSBufferizer)
  • Функции за работа со MSBufferizer

Во последниот Член ние развивме сопствен филтер. Оваа статија ќе се фокусира на внатрешниот механизам за преместување податоци помеѓу филтрите за медиумски пренос. Ова ќе ви овозможи да пишувате софистицирани филтри со помалку напор во иднина.

Механизам за движење на податоци

Движењето на податоците во медиумскиот стример се врши со користење на редици опишани од структурата queue_t. Низи пораки како mblk_t, кои самите не содржат сигнални податоци, туку само линкови до претходната, следната порака и до блокот на податоци. Дополнително, сакам особено да нагласам дека има и поле за врска до порака од ист тип, што ви овозможува да организирате единечно поврзана листа на пораки. Групата пораки обединети со таква листа ќе ја наречеме торка. Така, секој елемент од редот може да биде една порака mblk_t, а можеби и главата на порака торка mblk_t. Секоја топла порака може да има свој блок податоци од одделението. Зошто се потребни торки, ќе разговараме малку подоцна.

Како што споменавме погоре, самата порака не содржи блок од податоци, наместо тоа, таа содржи само покажувач до областа на меморијата каде што е зачуван блокот. Во овој дел, целокупната слика за работата на медиумскиот стример потсетува на магацинот на вратата во цртаниот филм „Monsters, Inc.“, каде вратите (врски до податоци - соби) се движат со луда брзина по надземните транспортери, додека самите простории остануваат неподвижни.

Сега, движејќи се по хиерархијата од дното кон врвот, да ги разгледаме детално наведените ентитети на механизмот за пренос на податоци во медиумскиот стример.

Блок на податоци dblk_t

Блокот на податоци се состои од заглавие и бафер за податоци. Заглавието е опишано со следнава структура,

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

Полињата на структурата содржат покажувачи кон почетокот на баферот, крајот на баферот и функцијата за бришење на баферот за податоци. Последен елемент во заглавието db_ref — референтниот бројач, ако достигне нула, ова служи како сигнал за бришење на овој блок од меморијата. Ако податочниот блок е создаден од функцијата datab_alloc() , тогаш баферот за податоци ќе се стави во меморијата веднаш по заглавието. Во сите други случаи, тампонот може да се наоѓа некаде посебно. Баферот за податоци ќе содржи примероци на сигнал или други податоци што сакаме да ги обработиме со филтри.

Со помош на функцијата се креира нов примерок на податочен блок:

dblk_t *datab_alloc(int size);

Како влезен параметар, му е дадена големината на податоците што блокот ќе ги складира. Се доделува повеќе меморија за да се постави заглавие - структура - на почетокот на доделената меморија база на податоци. Но, кога користите други функции, тоа не се случува секогаш; во некои случаи, баферот за податоци може да се наоѓа одделно од заглавието на блокот на податоци. При креирање на структура, полињата се конфигурирани така што нејзиното поле db_base покажа на почетокот на податочната област и db_lim до нејзиниот крај. Број на врски db_ref е поставено на еден. Покажувачот на функцијата за чистење податоци е поставен на нула.

Порака mblk_t

Како што е наведено, елементите на редот се од тип mblk_t, тоа е дефинирано на следниов начин:

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;

Структура mblk_t содржи покажувачи на почетокот b_prev, b_следно, кои се неопходни за организирање на двојно поврзана листа (што е редица queue_t).

Потоа доаѓа покажувачот b_cont, што се користи само кога пораката е дел од торка. За последната порака во торката, овој покажувач останува нула.

Следно, гледаме покажувач кон блок на податоци b_datap, за што постои пораката. Тоа е проследено со покажувачи кон областа во внатрешноста на блок-баферот за податоци. Поле b_rptr ја одредува локацијата од која ќе се читаат податоците од баферот. Поле b_wptr ја означува локацијата од која ќе се врши запишување во баферот.

Останатите полиња се од услужна природа и не се однесуваат на работата на механизмот за пренос на податоци.

Подолу е една порака со името m1 и блок на податоци d1.
Истражување на VoIP моторот Mediastreamer2. Дел 11
На следната слика е прикажана торка од три пораки m1, m1_1, m1_2.
Истражување на VoIP моторот Mediastreamer2. Дел 11

Функции за размена на пораки mblk_t

Нова порака mblk_t создадена од функцијата:

mblk_t *allocb(int size, int pri); 

таа става нова порака во меморијата mblk_t со блок на податоци со одредената големина големина, втор аргумент - pri не се користи во оваа верзија на библиотеката. Треба да остане нула. За време на работата на функцијата, меморијата ќе биде распределена за структурата на новата порака и функцијата ќе се повика mblk_init (), кој ќе ги ресетира сите полиња од креираната инстанца на структурата и потоа, користејќи го горенаведеното datab_alloc(), ќе создаде бафер за податоци. После тоа, полињата во структурата ќе бидат конфигурирани:

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

На излезот добиваме нова порака со иницијализирани полиња и празен бафер за податоци. За да додадете податоци во пораката, треба да ги копирате во баферот за блок податоци:

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

каде што податоци е покажувач кон изворот на податоци и големина - нивната големина.
тогаш треба да го ажурирате покажувачот до точката за запишување, така што тој повторно покажува на почетокот на слободната област во баферот:

msg->b_wptr = msg->b_wptr + size

Ако треба да креирате порака од постоечки бафер, без копирање, тогаш користете ја функцијата:

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

Функцијата, по креирањето на пораката и структурата на податочниот блок, ќе ги конфигурира своите покажувачи кон податоците на адресата буф. Оние. во овој случај, баферот за податоци не се наоѓа по полињата за заглавие на блокот за податоци, како што беше случај при креирање блок на податоци со функцијата datab_alloc(). Баферот со податоци предадени на функцијата ќе остане таму каде што беше, но со помош на покажувачи ќе се прикачи на новосоздаденото заглавие на податочниот блок и тоа, соодветно, на пораката.

На една порака mblk_t Неколку податочни блокови може да се спојат последователно. Ова се прави со функцијата:

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

mp — порака на која ќе се додаде друг блок на податоци;
податоци — покажувач кон блокот, чија копија ќе биде додадена на пораката;
големина — големина на податоци;
рампа — знаменце дека големината на доделената меморија мора да биде порамнета по граница од 4 бајти (пополнувањето ќе се врши со нули).

Ако има доволно простор во постојниот бафер за податоци за пораки, тогаш новите податоци ќе бидат залепени зад податоците што се веќе таму. Ако има помалку слободен простор во баферот за податоци за пораки од големина, потоа се креира нова порака со доволна големина на баферот и податоците се копираат во неговиот бафер. Ова е нова порака, поврзана со оригиналната со помош на покажувач b_cont. Во овој случај, пораката се претвора во торка.

Ако треба да додадете друг блок на податоци во торката, тогаш треба да ја користите функцијата:

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

таа ќе ја најде последната порака во торката (тој ја има b_cont ќе биде нула) и ќе ја повика функцијата за оваа порака appendb ().

Можете да ја дознаете големината на податоците во порака или торка користејќи ја функцијата:

int msgdsize(const mblk_t *mp);

ќе ги прелистува сите пораки во торката и ќе ја врати вкупната количина на податоци во баферите за податоци на тие пораки. За секоја порака, количината на податоци се пресметува на следниов начин:

 mp->b_wptr - mp->b_rptr

За да комбинирате две торки, користете ја функцијата:

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

таа ја прикачува торката нов до опашката на торката mp и враќа покажувач до последната порака од добиената торка.

Доколку е потребно, торката може да се претвори во една порака со еден блок податоци; тоа се прави со функцијата:

void msgpullup(mblk_t *mp,int len);

ако аргумент len е -1, тогаш големината на доделениот бафер се одредува автоматски. Ако len е позитивен број, ќе се креира тампон со оваа големина и во него ќе се копираат податоците од тократната порака. Ако баферот се потроши, копирањето ќе престане таму. Првата порака од торката ќе добие бафер со нова големина со копираните податоци. Останатите пораки ќе бидат избришани и меморијата ќе се врати на купот.

При бришење структура mblk_t референтниот број на податочниот блок се зема предвид ако, при повикување freeb () излегува дека е нула, тогаш баферот за податоци се брише заедно со инстанцата mblk_t, што укажува на тоа.

Иницијализирање на полињата на нова порака:

void mblk_init(mblk_t *mp);

Додавање уште еден податок во пораката:

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

Доколку новите податоци не се вклопуваат во слободниот простор на баферот за податоци за пораки, тогаш на пораката се прикачува посебно креирана порака со бафер со потребната големина (покажувачот кон додадената порака е поставен во првата порака) и пораката се претвора во торка.

Додавање на податок во торка:

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

Функцијата повикува appendb() во циклус.

Комбинирање на две торки во едно:

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

Порака нов ќе биде прикачен на mp.

Правење копија од една порака:

mblk_t *copyb(const mblk_t *mp);

Целосно копирање на торка со сите блокови на податоци:

mblk_t *copymsg(const mblk_t *mp);

Елементите на торката се копираат со функцијата copyb ().

Направете лесна копија од порака mblk_t. Во овој случај, блокот на податоци не се копира, но неговиот референтен бројач е зголемен db_ref:

mblk_t *dupb(mblk_t *mp);

Изработка на лесна копија од торка. Блоковите на податоци не се копираат, само нивните референтни бројачи се зголемуваат db_ref:

mblk_t *dupmsg(mblk_t* m);

Лепење на сите пораки од торка во една порака:

void msgpullup(mblk_t *mp,size_t len);

Доколку аргументот len е -1, тогаш големината на доделениот бафер се одредува автоматски.

Бришење порака, дуплирање:

void freemsg(mblk_t *mp);

Бројот на референци на блокот на податоци се намалува за еден. Ако достигне нула, блокот на податоци исто така се брише.

Пресметка на вкупниот износ на податоци во порака или торка.

size_t msgdsize(const mblk_t *mp);

Враќање порака од опашката на редот:

mblk_t *ms_queue_peek_last (q);

Копирање на содржината на резервираните полиња на една порака во друга порака (всушност, овие полиња содржат знаменца што ги користи медиумскиот стример):

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

Редица queue_t

Редот за пораки во медиумскиот стример се имплементира како кружна, двојно поврзана листа. Секој елемент од списокот содржи покажувач кон податочен блок со примероци на сигнали. Излегува дека само покажувачите на податочниот блок се движат за возврат, додека самите податоци остануваат неподвижни. Оние. се преместуваат само врските до нив.
Структура што ја опишува редицата queue_t, прикажано подолу:

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

Структурата содржи поле - покажувач _q_затка напишете *mblk_t, покажува на првиот елемент (порака) во редот. Второто поле на структурата е бројачот на пораки во редот.
На сликата подолу е прикажана редица со име q1 која содржи 4 пораки m1, m2, m3, m4.
Истражување на VoIP моторот Mediastreamer2. Дел 11
На следната слика е прикажана редица со име q1 која содржи 4 пораки m1,m2,m3,m4. Пораката m2 е глава на торка која содржи уште две пораки m2_1 и m2_2.

Истражување на VoIP моторот Mediastreamer2. Дел 11

Функции за работа со редици queue_t

Иницијализација на редот:

void qinit(queue_t *q);

столб _q_затка (во натамошниот текст ќе го нарекуваме „затка“) се иницијализира со функцијата mblk_init (), неговиот претходен елемент и покажувачот на следниот елемент се приспособени да покажуваат кон себе. Бројачот на елементот на редот е ресетиран на нула.

Додавање нов елемент (пораки):

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

Нов елемент m се додава на крајот од листата, покажувачите на елементот се приспособуваат така што стоперот станува следен елемент за него, а тој станува претходен елемент за затката. Бројачот на елементот на редот се зголемува.

Враќање елемент од редот:

mblk_t * getq(queue_t *q); 

Пораката што доаѓа по затката е преземена, а бројачот на елементот се намалува. Ако нема елементи во редот освен затката, тогаш се враќа 0.

Вметнување порака во редица:

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

Елемент mp вметната пред елементот EMP. Ако EMP=0, потоа пораката се додава на опашката на редот.

Враќање порака од шефот на редот:

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

Бројачот на елементот е намален.

Читање покажувач до првиот елемент во редот:

mblk_t * peekq(queue_t *q); 

Отстранување на сите елементи од редот додека се бришат самите елементи:

void flushq(queue_t *q, int how);

Аргумент како не се користи. Бројачот на елементот на редот е поставен на нула.

Макро за читање покажувач до последниот елемент од редот:

mblk_t * qlast(queue_t *q);

Кога работите со редици за пораки, имајте предвид дека кога се јавувате ms_queue_put (q, m) со нула покажувач на пораката, функцијата се врти. Вашата програма ќе замрзне. се однесува слично ms_queue_next(q, m).

Поврзување на филтри

Редот опишан погоре се користи за пренесување пораки од еден филтер до друг или од еден до неколку филтри. Филтрите и нивните врски формираат насочен график. Влезот или излезот на филтерот ќе се нарекува општ збор „игла“. За да се опише редоследот по кој филтрите се поврзани едни со други, медиумскиот стример го користи концептот на „сигнална точка“. Сигналната точка е структура _MSCP-точка, кој содржи покажувач на филтерот и бројот на еден од неговите пинови; соодветно, го опишува поврзувањето на еден од влезовите или излезите на филтерот.

График на сигнална точка на обработка на податоци

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

Пиновите на филтерот се нумерирани почнувајќи од нула.

Поврзувањето на два пина со редица пораки е опишано со структурата _MSQueue, која содржи редица за пораки и покажувачи до двете сигнални точки што ги поврзува:

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

Оваа структура ќе ја наречеме сигнална врска. Секој филтер за медиумски стример содржи табела со влезни врски и табела со излезни врски (MSQueue). Големината на табелите се поставува при креирање на филтер; ние веќе го направивме тоа користејќи извезена променлива од типот MSFilterDesc, кога развивме сопствен филтер. Подолу е структура која опишува кој било филтер во медиумски стример, 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;

Откако ги поврзавме филтрите во програмата C во согласност со нашиот план (но не го поврзавме тикерот), со тоа создадовме насочен график, чии јазли се примери на структурата MSFilter, а рабовите се примери на врски MSQueue.

Задкулисните активности на тикерот

Кога ти кажав дека тикерот е филтер за изворот на крлежите, тоа не беше целата вистина за тоа. Тикер е објект што извршува функции на часовникот процес () сите филтри на колото (графикот) на кое е поврзан. Кога поврзуваме тикер со графички филтер во програма C, на тикерот му го покажуваме графикот што ќе го контролира отсега па натаму додека не го исклучиме. По поврзувањето, тикерот почнува да го испитува графикот што му е доверен, составувајќи листа на филтри што го вклучуваат. За да не се „брои“ двапати истиот филтер, ги означува откриените филтри со ставање поле за избор во нив види. Пребарувањето се врши со помош на табелите за врски што ги има секој филтер.

За време на неговата воведна обиколка на графиконот, тикерот проверува дали меѓу филтрите има барем еден што делува како извор на блокови на податоци. Ако ги нема, тогаш графикот се смета за неточен и тикерот паѓа.

Ако графикот се покаже дека е „точен“, за секој пронајден филтер, функцијата се повикува за иницијализација претпроцес (). Штом пристигне моментот за следниот циклус на обработка (стандардно на секои 10 милисекунди), тикерот ја повикува функцијата процес () за сите претходно пронајдени изворни филтри, а потоа и за преостанатите филтри во списокот. Ако филтерот има влезни врски, тогаш стартувајте ја функцијата процес () се повторува додека редиците за влезни врски не се испразнат. По ова, се префрла на следниот филтер во списокот и го „прелистува“ додека влезните врски не се ослободат од пораки. Тикерот се движи од филтер до филтер додека списокот не заврши. Ова ја комплетира обработката на циклусот.

Сега ќе се вратиме на торките и ќе разговараме зошто таков ентитет е додаден на медиумскиот стример. Општо земено, количината на податоци што ја бара алгоритмот што работи внатре во филтерот не се совпаѓа и не е множител на големината на баферите за податоци добиени на влезот. На пример, пишуваме филтер кој врши брза Фуриеова трансформација, која по дефиниција може да обработува само податочни блокови чија големина е моќност од два. Нека биде 512 брои. Ако податоците се генерирани од телефонски канал, тогаш податочниот бафер на секоја порака на влезот ќе ни донесе 160 примероци на сигнал. Примамливо е да не се собираат податоци од влезот додека не се најде потребната количина на податоци. Но, во овој случај, ќе се случи судир со тикерот, кој неуспешно ќе се обиде да го лизга филтерот додека влезната врска не се испразни. Претходно, ова правило го назначивме како трет принцип на филтерот. Според овој принцип, функцијата process() на филтерот мора да ги земе сите податоци од влезните редици.

Покрај тоа, нема да може да се земат само 512 примероци од влезот, бидејќи може да земете само цели блокови, т.е. филтерот ќе треба да земе 640 примероци и да искористи 512 од нив, а остатокот пред да акумулира нов дел од податоците. Така, нашиот филтер, покрај неговата главна работа, мора да обезбеди и помошни дејства за средно складирање на влезните податоци. Програмерите на медиумскиот стример и решението за овој општ проблем развија специјален објект - MSBufferizer (баферер), кој го решава овој проблем користејќи торки.

Баферизер (MSBufferizer)

Ова е објект што ќе ги акумулира влезните податоци во филтерот и ќе започне да ги испраќа за обработка веднаш штом количината на информации е доволна за да се изврши алгоритмот за филтрирање. Додека баферот акумулира податоци, филтерот ќе работи во режим на мирување, без да ја користи процесорската моќ на процесорот. Но, штом функцијата за читање од баферерот врати вредност различна од нула, функцијата process() на филтерот почнува да зема и обработува податоци од баферерот во делови од потребната големина, додека не се исцрпи.
Податоците што сè уште не се потребни остануваат во баферот како прв елемент од торката, на која се прикачени следните блокови од влезни податоци.

Структурата што го опишува баферот:

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

Функции за работа со MSBufferizer

Креирање на нов примерок на тампон:

MSBufferizer * ms_bufferizer_new(void);

Меморијата е распределена, иницијализирана во ms_bufferizer_init() и се враќа покажувач.

Функција за иницијализација:

void ms_bufferizer_init(MSBufferizer *obj); 

Редот се иницијализира q, Поле големина е поставена на нула.

Додавање порака:

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

Пораката m е додадена на редот. Се додава пресметаната големина на податочните блокови големина.

Пренесување на сите пораки од редот за податоци за врски во баферот q:

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

Пренесување пораки од врска q во баферот се врши со користење на функцијата ms_bufferizer_put().

Читање од баферот:

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

Ако големината на податоците акумулирани во баферот е помала од бараната (датален), потоа функцијата враќа нула, податоците не се копираат на податоци. Во спротивно, се врши секвенцијално копирање на податоци од торки лоцирани во баферот. По копирањето, торката се брише и меморијата се ослободува. Копирањето завршува во моментот кога се копираат податоците од бајтите. Ако снема простор во средината на блок со податоци, тогаш во оваа порака, блокот на податоци ќе се намали на преостанатиот некопиран дел. Следниот пат кога ќе се јавите, копирањето ќе продолжи од оваа точка.

Читање на количината на податоци што е моментално достапна во баферот:

int ms_bufferizer_get_avail(MSBufferizer *obj); 

Го враќа полето големина тампон.

Отфрлање на дел од податоците во баферот:

void ms_bufferizer_skip_bytes(MSBufferizer *obj, int bytes);

Наведениот број бајти податоци се преземаат и отфрлаат. Најстарите податоци се отфрлени.

Бришење на сите пораки во баферот:

void ms_bufferizer_flush(MSBufferizer *obj); 

Бројачот на податоци се ресетира на нула.

Бришење на сите пораки во баферот:

void ms_bufferizer_uninit(MSBufferizer *obj); 

Бројачот не се ресетира.

Отстранување на баферот и ослободување меморија:

void ms_bufferizer_destroy(MSBufferizer *obj);  

Примери за користење на баферерот може да се најдат во изворниот код на неколку филтри за медиумски стример. На пример, во филтерот MS_L16_ENC, кој ги преуредува бајтите во примероците од редот на мрежата до редот на домаќинот: l16.в

Во следната статија, ќе го разгледаме прашањето за проценка на оптоварувањето на тикер и како да се справиме со прекумерното пресметковно оптоварување во медиумскиот стример.

Извор: www.habr.com

Додадете коментар