Mediastreamer2:n VoIP-moottorin tutkiminen. Osa 11

Artikkelin materiaali on otettu minun zen kanava.

Mediastreamer2:n VoIP-moottorin tutkiminen. Osa 11

Tiedonsiirtomekanismi

  • Tietolohko dblk_t
  • Viesti mblk_t
  • Toiminnot viestien käsittelyyn mblk_t
  • Jono queue_t
  • Toiminnot jonojen kanssa työskentelyyn queue_t
  • Suodattimien liittäminen
  • Tietojenkäsittelykaavion signaalipiste
  • Kulissien takana toimintaa ticker
  • Puskurointi (MSBufferizer)
  • Toiminnot MSBufferizerin kanssa työskentelyyn

Viimeisessä статье olemme kehittäneet oman suodattimen. Tämä artikkeli keskittyy sisäiseen mekanismiin tietojen siirtämiseksi median striimaussuodattimien välillä. Näin voit kirjoittaa kehittyneitä suodattimia pienemmällä vaivalla tulevaisuudessa.

Tiedonsiirtomekanismi

Datan siirto mediastriimerissä suoritetaan rakenteen kuvaamien jonojen avulla queue_t. Viestijonoja, kuten mblk_t, jotka itsessään eivät sisällä signaalidataa, vaan linkittävät vain edelliseen, seuraavaan viestiin ja tietolohkoon. Lisäksi haluan erityisesti korostaa, että samantyyppiseen viestiin on myös linkkikenttä, jonka avulla voit järjestää yksitellen linkitettyjen viestien luettelon. Kutsumme tällaisen luettelon yhdistämää viestiryhmää tupleksi. Siten mikä tahansa jonon elementti voi olla yksi viesti mblk_t, ja ehkä viestiketjun pää mblk_t. Jokaisella monikkoviestillä voi olla oma osastotietolohkonsa. Keskustelemme hieman myöhemmin, miksi tupleja tarvitaan.

Kuten edellä mainittiin, itse viesti ei sisällä tietolohkoa, vaan se sisältää vain osoittimen muistialueelle, johon lohko on tallennettu. Tässä osassa mediastriimaajan työn kokonaiskuva muistuttaa sarjakuvan "Monsters, Inc." ovivarastoa, jossa ovet (linkit dataan - huoneet) liikkuvat järjettömällä nopeudella yläkuljettimia pitkin, kun taas itse huoneet pysyä liikkumattomana.

Nyt, siirryttäessä hierarkiaa pitkin alhaalta ylöspäin, tarkastellaan yksityiskohtaisesti lueteltuja tiedonsiirtomekanismin entiteettejä mediasuoratoistossa.

Tietolohko dblk_t

Tietolohko koostuu otsikosta ja datapuskurista. Otsikko on kuvattu seuraavalla rakenteella,

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

Rakenteen kentät sisältävät osoittimet puskurin alkuun, puskurin loppuun ja datapuskurin poistotoimintoon. Viimeinen elementti otsikossa db_ref — referenssilaskuri, jos se saavuttaa nollan, tämä toimii signaalina tämän lohkon poistamiseksi muistista. Jos tietolohko on luotu funktiolla datab_alloc() , niin datapuskuri sijoitetaan muistiin heti otsikon jälkeen. Kaikissa muissa tapauksissa puskuri voi sijaita jossain erikseen. Datapuskuri sisältää signaalinäytteitä tai muuta dataa, jonka haluamme käsitellä suodattimilla.

Tietolohkon uusi esiintymä luodaan funktiolla:

dblk_t *datab_alloc(int size);

Syöttöparametrina sille annetaan sen datan koko, jonka lohko tallentaa. Lisää muistia varataan, jotta varatun muistin alkuun voidaan sijoittaa otsikko - rakenne datab. Mutta muita toimintoja käytettäessä näin ei aina tapahdu, vaan joissain tapauksissa datapuskuri voi sijaita erillään tietolohkon otsikosta. Rakennetta luotaessa kentät konfiguroidaan siten, että sen kenttä db_base osoitti tietoalueen alkuun ja db_lim sen loppuun asti. Linkkien määrä db_ref on asetettu yhdeksi. Tietojen tyhjennystoiminnon osoitin on asetettu nollaan.

Viesti mblk_t

Kuten todettiin, jonoelementit ovat tyyppiä mblk_t, se määritellään seuraavasti:

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;

Rakenne mblk_t sisältää viitteitä alussa b_edellinen, b_seuraava, joita tarvitaan kaksinkertaisesti linkitetyn luettelon järjestämiseen (joka on jono queue_t).

Sitten tulee osoitin b_cont, jota käytetään vain, kun viesti on osa monikkoa. Lukion viimeisen viestin kohdalla tämä osoitin pysyy tyhjänä.

Seuraavaksi näemme osoittimen tietolohkoon b_datap, jolle viesti on olemassa. Sitä seuraavat osoittimet lohkotietopuskurin sisällä olevalle alueelle. Ala b_rptr määrittää sijainnin, josta puskurin tiedot luetaan. Ala b_wptr osoittaa paikan, josta puskuriin kirjoitetaan.

Loput kentät ovat palveluluonteisia eivätkä liity tiedonsiirtomekanismin toimintaan.

Alla on yksi viesti, jossa on nimi m1 ja datalohko d1.
Mediastreamer2:n VoIP-moottorin tutkiminen. Osa 11
Seuraavassa kuvassa on kolmen viestin joukko m1, m1_1, m1_2.
Mediastreamer2:n VoIP-moottorin tutkiminen. Osa 11

Viestintätoiminnot mblk_t

Uusi viesti mblk_t luotu funktiolla:

mblk_t *allocb(int size, int pri); 

hän laittaa uuden viestin muistiin mblk_t määritetyn kokoisen tietolohkon kanssa koko, toinen argumentti - PRI ei käytetä tässä kirjaston versiossa. Sen pitäisi pysyä nollassa. Toiminnon toiminnan aikana varataan muistia uuden viestin rakenteelle ja toimintoa kutsutaan mblk_init(), joka nollaa kaikki luodun rakenteen ilmentymän kentät ja sitten käyttämällä yllä mainittua datab_alloc(), luo tietopuskurin. Tämän jälkeen rakenteen kentät konfiguroidaan:

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

Lähdössä saamme uuden viestin, jossa on alustetut kentät ja tyhjä tietopuskuri. Jos haluat lisätä dataa viestiin, sinun on kopioitava se tietolohkopuskuriin:

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

missä tiedot on osoitin tietolähteeseen ja koko - niiden koko.
sitten sinun on päivitettävä osoitin kirjoituspisteeseen niin, että se osoittaa jälleen puskurin vapaan alueen alkuun:

msg->b_wptr = msg->b_wptr + size

Jos sinun on luotava viesti olemassa olevasta puskurista kopioimatta, käytä toimintoa:

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

Luotuaan viestin ja tietolohkon rakenteen toiminto määrittää osoittimet osoitteen tietoihin harrastaja. Nuo. tässä tapauksessa tietopuskuri ei sijaitse tietolohkon otsikkokenttien jälkeen, kuten tapahtui luotaessa tietolohkoa funktiolla datab_alloc(). Puskuri funktiolle välitetyillä tiedoilla jää entiseen paikkaan, mutta se liitetään osoittimien avulla tietolohkon juuri luotuun otsikkoon ja sen mukaisesti viestiin.

Yhteen viestiin mblk_t Useita datalohkoja voidaan ketjuttaa peräkkäin. Tämä tehdään toiminnolla:

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

mp — viesti, johon lisätään toinen tietolohko;
tiedot — osoitin lohkoon, jonka kopio lisätään viestiin;
koko — tiedon koko;
tyyny — lippu, jonka mukaan varatun muistin koko on kohdistettava 4 tavun rajaa pitkin (täyte tehdään nollien kanssa).

Jos olemassa olevassa viestitietopuskurissa on tarpeeksi tilaa, uudet tiedot liitetään olemassa olevien tietojen taakse. Jos viestitietopuskurissa on vähemmän vapaata tilaa kuin koko, sitten luodaan uusi viesti, jossa on riittävä puskurikoko ja tiedot kopioidaan sen puskuriin. Tämä on uusi viesti, joka on linkitetty alkuperäiseen osoittimen avulla b_cont. Tässä tapauksessa viesti muuttuu tupleksi.

Jos sinun on lisättävä monikkoon toinen tietolohko, sinun on käytettävä toimintoa:

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

hän löytää viimeisen viestin ketjusta (hänellä on b_cont on nolla) ja kutsuu tämän viestin funktiota appendb().

Voit selvittää viestin tai moninkertaisen datan koon funktiolla:

int msgdsize(const mblk_t *mp);

se käy läpi kaikki monikkoviestit ja palauttaa näiden viestien tietopuskureissa olevan datan kokonaismäärän. Kunkin viestin datamäärä lasketaan seuraavasti:

 mp->b_wptr - mp->b_rptr

Jos haluat yhdistää kaksi monikkoa, käytä toimintoa:

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

hän lisää ketjun newm tuplen häntään mp ja palauttaa osoittimen tuloksena olevan monikon viimeiseen viestiin.

Tarvittaessa monikko voidaan muuttaa yhdeksi viestiksi yhdellä tietolohkolla; tämä tapahtuu funktiolla:

void msgpullup(mblk_t *mp,int len);

jos argumentti len on -1, silloin varatun puskurin koko määritetään automaattisesti. Jos len on positiivinen luku, tämän kokoinen puskuri luodaan ja monikkoviestin tiedot kopioidaan siihen. Jos puskuri loppuu, kopiointi loppuu tähän. Monikon ensimmäinen viesti vastaanottaa uuden kokoisen puskurin kopioiduilla tiedoilla. Loput viestit poistetaan ja muisti palautetaan kasaan.

Kun poistat rakenteen mblk_t tietolohkon viiteluku otetaan huomioon, jos kutsuttaessa freeb() se osoittautuu nollaksi, sitten tietopuskuri poistetaan esiintymän mukana mblk_t, mikä viittaa siihen.

Uuden viestin kenttien alustaminen:

void mblk_init(mblk_t *mp);

Toisen tiedon lisääminen viestiin:

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

Jos uudet tiedot eivät mahdu sanomatietopuskurin vapaaseen tilaan, niin viestiin liitetään erikseen luotu viesti, jossa on vaaditun kokoinen puskuri (ensimmäiseen viestiin asetetaan osoitin lisättyyn viestiin) ja viesti muuttuu ketjuksi.

Tietojen lisääminen monitoon:

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

Funktio kutsuu appendb():tä silmukassa.

Kahden ketjun yhdistäminen yhdeksi:

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

Viesti newm liitetään mp.

Kopion tekeminen yhdestä viestistä:

mblk_t *copyb(const mblk_t *mp);

Täydellinen monikkokopiointi kaikilla tietolohkoilla:

mblk_t *copymsg(const mblk_t *mp);

Funktio kopioi monikon elementit kopioib().

Luo viestistä helppo kopio mblk_t. Tässä tapauksessa datalohkoa ei kopioida, mutta sen viitelaskinta kasvatetaan db_ref:

mblk_t *dupb(mblk_t *mp);

Kevyen kopion tekeminen tuplesta. Tietolohkoja ei kopioida, vain niiden viitelaskureita kasvatetaan db_ref:

mblk_t *dupmsg(mblk_t* m);

Kaikkien monikon viestien liimaaminen yhdeksi viestiksi:

void msgpullup(mblk_t *mp,size_t len);

Jos argumentti len on -1, silloin varatun puskurin koko määritetään automaattisesti.

Viestin poistaminen, tuple:

void freemsg(mblk_t *mp);

Tietolohkon viitemäärää vähennetään yhdellä. Jos se saavuttaa nollan, myös tietolohko poistetaan.

Viestin tai monikon datan kokonaismäärän laskeminen.

size_t msgdsize(const mblk_t *mp);

Viestin hakeminen jonon päästä:

mblk_t *ms_queue_peek_last (q);

Yhden viestin varattujen kenttien sisällön kopioiminen toiseen viestiin (itse asiassa nämä kentät sisältävät lippuja, joita mediasuoratoistolaite käyttää):

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

käännä queue_t

Mediastreamerin viestijono on toteutettu pyöreänä kaksoislinkitettynä luettelona. Jokainen listaelementti sisältää osoittimen datalohkoon, jossa on signaalinäytteitä. Osoittautuu, että vain osoittimet datalohkoon liikkuvat vuorotellen, kun taas itse data pysyy liikkumattomana. Nuo. vain linkit niihin siirretään.
Jonoa kuvaava rakenne queue_t, nähtävissä alapuolella:

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

Rakenne sisältää kentän - osoittimen _q_tulppa kirjoita *mblk_t, se osoittaa jonon ensimmäiseen elementtiin (viestiin). Rakenteen toinen kenttä on jonossa olevien viestien laskuri.
Alla olevassa kuvassa on q1-niminen jono, joka sisältää 4 viestiä m1, m2, m3, m4.
Mediastreamer2:n VoIP-moottorin tutkiminen. Osa 11
Seuraavassa kuvassa on q1-niminen jono, joka sisältää 4 viestiä m1,m2,m3,m4. Viesti m2 on monikko, joka sisältää kaksi muuta viestiä m2_1 ja m2_2.

Mediastreamer2:n VoIP-moottorin tutkiminen. Osa 11

Toiminnot jonojen kanssa työskentelyyn queue_t

Jonon alustus:

void qinit(queue_t *q);

Kenttä _q_tulppa (jäljempänä kutsumme sitä "stopperiksi") alustetaan toiminnolla mblk_init(), sen edellinen elementti ja seuraavan elementin osoitin säädetään osoittamaan itseään. Jonoelementin laskuri nollataan.

Uuden elementin lisääminen (viestit):

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

Uusi elementti m lisätään luettelon loppuun, elementtiosoittimet säädetään siten, että pysäyttimestä tulee sen seuraava elementti ja siitä tulee pysäyttimen edellinen elementti. Jonoelementtilaskuria kasvatetaan.

Elementin hakeminen jonosta:

mblk_t * getq(queue_t *q); 

Pysäyttimen jälkeen tuleva viesti haetaan ja elementtilaskuria pienennetään. Jos jonossa ei ole muita elementtejä pysäyttimen lisäksi, palautetaan 0.

Viestin lisääminen jonoon:

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

elementti mp lisätty ennen elementtiä emp. jos emp=0, niin viesti lisätään jonon loppupäähän.

Viestin hakeminen jonon päästä:

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

Elementtilaskuri pienenee.

Osoittimen lukeminen jonon ensimmäiseen elementtiin:

mblk_t * peekq(queue_t *q); 

Kaikkien elementtien poistaminen jonosta samalla kun itse elementit poistetaan:

void flushq(queue_t *q, int how);

perustelu miten ei käytetty. Jonoelementtien laskuri on asetettu nollaan.

Makro osoittimen lukemiseksi jonon viimeiseen elementtiin:

mblk_t * qlast(queue_t *q);

Kun työskentelet viestijonojen kanssa, ota huomioon, että kun soitat ms_queue_put(q, m) nollaosoittimella viestiin funktio silmukat. Ohjelmasi jäätyy. käyttäytyy samalla tavalla ms_queue_next(q, m).

Suodattimien liittäminen

Yllä kuvattua jonoa käytetään viestien välittämiseen suodattimesta toiseen tai yhdestä useampaan suodattimeen. Suodattimet ja niiden liitännät muodostavat suunnatun graafin. Suodattimen tuloa tai lähtöä kutsutaan yleissanaksi "pin". Kuvatakseen järjestystä, jossa suodattimet kytketään toisiinsa, mediastriimaaja käyttää "signaalipisteen" käsitettä. Signaalipiste on rakenne _MSCPoint, joka sisältää osoittimen suodattimeen ja sen yhden nastan numeron; vastaavasti se kuvaa suodattimen yhden tulon tai lähdön kytkentää.

Tietojenkäsittelykaavion signaalipiste

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

Suodattimen tapit on numeroitu nollasta alkaen.

Kahden nastan yhdistäminen viestijonolla on kuvattu rakenteella _MSQueue, joka sisältää viestijonon ja osoittimet kahteen signaalipisteeseen, jotka se yhdistää:

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

Kutsumme tätä rakennetta signaalilinkiksi. Jokainen mediastriimaussuodatin sisältää taulukon tulolinkkeistä ja taulukon lähtölinkkeistä (MSQueue). Taulukoiden koko asetetaan suodatinta luotaessa; olemme jo tehneet tämän käyttämällä vietyä tyyppistä muuttujaa MSFilterDesc, kun kehitimme oman suodattimen. Alla on rakenne, joka kuvaa mitä tahansa mediasuorittimen suodatinta, 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;

Kun olemme yhdistäneet C-ohjelmassa suodattimet suunnitelmamme mukaisesti (mutta emme yhdistäneet tickeriä), loimme siten suunnatun graafin, jonka solmut ovat rakenteen esiintymiä. MSFilter, ja reunat ovat linkkien esiintymiä MSQueue.

Kulissien takana toimintaa ticker

Kun kerroin, että ticker on suodatin punkkien lähteelle, se ei ollut koko totuus siitä. Tikkuri on objekti, joka suorittaa toimintoja kellossa prosessi() kaikki sen piirin suodattimet (kaavio), johon se on kytketty. Kun yhdistämme tickerin graafisuotimeen C-ohjelmassa, näytämme tickerille kuvaajaa, jota se ohjaa tästä lähtien, kunnes sammutamme sen. Yhdistyksen jälkeen ticker alkaa tutkia sen hoitoon uskottua kuvaajaa ja laatii luettelon sen sisältävistä suodattimista. Jotta samaa suodatinta ei "laskettaisi" kahdesti, se merkitsee havaitut suodattimet lisäämällä niihin valintaruudun nähneet. Haku suoritetaan kunkin suodattimen linkkitaulukoiden avulla.

Kaavion esittelykierroksella ticker tarkistaa, onko suodattimien joukossa vähintään yksi tietolohkojen lähteenä toimiva. Jos niitä ei ole, kaaviota pidetään virheellisenä ja ticker kaatuu.

Jos kuvaaja osoittautuu "oikeaksi", jokaiselle löydetylle suodattimelle funktiota kutsutaan alustusta varten esikäsittely (). Heti kun seuraavan käsittelyjakson hetki koittaa (oletuksena 10 millisekunnin välein), ticker kutsuu funktiota prosessi() kaikille aiemmin löydetyille lähdesuodattimille ja sitten muille luettelossa oleville suodattimille. Jos suodattimessa on tulolinkkejä, suorita toiminto prosessi() toistuu, kunnes syöttölinkin jonot ovat tyhjiä. Tämän jälkeen se siirtyy luettelon seuraavaan suodattimeen ja "vieritä" sitä, kunnes syöttölinkeissä ei ole viestejä. Ticker liikkuu suodattimesta toiseen, kunnes luettelo päättyy. Tämä päättää syklin käsittelyn.

Nyt palaamme moniin ja puhumme siitä, miksi tällainen kokonaisuus lisättiin mediasuoraan. Yleensä suodattimen sisällä toimivan algoritmin vaatima datamäärä ei ole sama eikä se ole tuloon vastaanotettujen datapuskurien koon monikerta. Kirjoitamme esimerkiksi nopean Fourier-muunnoksen suorittavaa suodatinta, joka voi määritelmän mukaan käsitellä vain datalohkoja, joiden koko on potenssi kaksi. Olkoon se 512 laskua. Jos data on muodostettu puhelinkanavalla, niin jokaisen viestin datapuskuri sisääntulossa tuo meille 160 signaalinäytettä. On houkuttelevaa olla keräämättä tietoja syötteestä ennen kuin tarvittava määrä dataa on siellä. Mutta tässä tapauksessa tapahtuu törmäys tickerin kanssa, joka yrittää epäonnistuneesti vierittää suodatinta, kunnes tulolinkki on tyhjä. Aiemmin määritimme tämän säännön suodattimen kolmanneksi periaatteeksi. Tämän periaatteen mukaan suodattimen process()-funktion tulee ottaa kaikki tiedot syöttöjonoista.

Lisäksi syötteestä ei voi ottaa vain 512 näytettä, koska voit ottaa vain kokonaisia ​​lohkoja, ts. suodattimen on otettava 640 näytettä ja käytettävä niistä 512, loput ennen uuden tiedon keräämistä. Siten suodattimemme tulee päätyönsä lisäksi tarjota aputoimintoja syöttötietojen välivarastointiin. Median streamerin ja tämän yleisen ongelman ratkaisun kehittäjät ovat kehittäneet erityisen objektin - MSBufferizer (puskuri), joka ratkaisee tämän ongelman monikoiden avulla.

Puskurointi (MSBufferizer)

Tämä on objekti, joka kerää syöttödataa suodattimen sisään ja aloittaa sen lähettämisen käsittelyyn heti, kun informaatiomäärä on riittävä suodatinalgoritmin suorittamiseen. Kun puskuri kerää tietoja, suodatin toimii lepotilassa kuluttamatta prosessorin prosessointitehoa. Mutta heti kun lukutoiminto puskurista palauttaa muun arvon kuin nolla, suodattimen process()-funktio alkaa ottaa ja käsitellä puskurista dataa vaaditun kokoisina osina, kunnes se on käytetty loppuun.
Tiedot, joita ei vielä tarvita, jää puskuriin monikon ensimmäisenä elementtinä, johon liitetään seuraavat syöttötietolohkot.

Puskuria kuvaava rakenne:

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

Toiminnot MSBufferizerin kanssa työskentelyyn

Uuden puskuriinstanssin luominen:

MSBufferizer * ms_bufferizer_new(void);

Muisti on varattu, alustettu sisään ms_bufferizer_init() ja osoitin palautetaan.

Alustustoiminto:

void ms_bufferizer_init(MSBufferizer *obj); 

Jonoa alustetaan q, kenttä koko on asetettu nollaan.

Viestin lisääminen:

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

Viesti m lisätään jonoon. Tietolohkojen laskettu koko lisätään koko.

Kaikkien viestien siirtäminen linkkidatajonosta puskuriin q:

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

Viestien siirtäminen linkistä q puskurissa suoritetaan käyttämällä toimintoa ms_bufferizer_put().

Puskurista luettavaa:

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

Jos puskuriin kertyneen tiedon koko on pienempi kuin pyydetty (datalen), funktio palauttaa nollan, tietoja ei kopioida tietoihin. Muussa tapauksessa suoritetaan tietojen peräkkäinen kopiointi puskurissa olevista monikoista. Kopioinnin jälkeen monikko poistetaan ja muisti vapautetaan. Kopiointi päättyy sillä hetkellä, kun datalen-tavut kopioidaan. Jos tila loppuu kesken datalohkon, tässä viestissä datalohko pienennetään jäljelle jääväksi kopioimattomaksi osaksi. Kun soitat seuraavan kerran, kopiointi jatkuu tästä kohdasta.

Puskurissa tällä hetkellä saatavilla olevan datamäärän lukeminen:

int ms_bufferizer_get_avail(MSBufferizer *obj); 

Palauttaa kentän koko puskuri.

Osa puskurissa olevista tiedoista hylätään:

void ms_bufferizer_skip_bytes(MSBufferizer *obj, int bytes);

Määritetty määrä tavuja dataa haetaan ja hylätään. Vanhimmat tiedot hylätään.

Kaikkien viestien poistaminen puskurista:

void ms_bufferizer_flush(MSBufferizer *obj); 

Datalaskuri nollataan.

Kaikkien viestien poistaminen puskurista:

void ms_bufferizer_uninit(MSBufferizer *obj); 

Laskuria ei nollata.

Puskurin poistaminen ja muistin vapauttaminen:

void ms_bufferizer_destroy(MSBufferizer *obj);  

Esimerkkejä puskurin käytöstä löytyy useiden mediastriimaussuodattimien lähdekoodista. Esimerkiksi MS_L16_ENC-suodattimessa, joka järjestää näytteiden tavut uudelleen verkkotilauksesta isäntäjärjestykseen: l16.c

Seuraavassa artikkelissa tarkastellaan ticker-kuormituksen arviointia ja sitä, kuinka käsitellä liiallista laskentakuormaa mediasuorassa.

Lähde: will.com

Lisää kommentti