Að kanna Mediastreamer2 VoIP vélina. 11. hluti

Efni greinarinnar er tekið úr mínum zen rás.

Að kanna Mediastreamer2 VoIP vélina. 11. hluti

Gagnaflutningskerfi

  • Gagnablokk dblk_t
  • Skilaboð mblk_t
  • Aðgerðir til að vinna með skilaboð mblk_t
  • Biðröð biðröð_t
  • Aðgerðir til að vinna með biðraðir queue_t
  • Að tengja síur
  • Merkjapunktur gagnavinnslu línurits
  • Á bak við tjöldin starfsemi auðkennisins
  • Bufferizer (MSBufferizer)
  • Aðgerðir til að vinna með MSBufferizer

Í fortíðinni grein við höfum þróað okkar eigin síu. Þessi grein mun einbeita sér að innri vélbúnaði til að flytja gögn á milli fjölmiðlastraumsía. Þetta gerir þér kleift að skrifa háþróaðar síur með minni fyrirhöfn í framtíðinni.

Gagnaflutningskerfi

Gagnahreyfing í miðlunarstraumnum er framkvæmd með því að nota biðraðir sem lýst er af uppbyggingunni biðröð_t. Strengir af skilaboðum eins og mblk_t, sem sjálfir innihalda ekki merkjagögn, heldur aðeins tengla á fyrri, næstu skilaboð og gagnablokkina. Að auki vil ég sérstaklega leggja áherslu á að það er einnig reit fyrir tengil á skilaboð af sömu gerð, sem gerir þér kleift að skipuleggja einn tengdan lista yfir skilaboð. Við munum kalla hóp skilaboða sem sameinast af slíkum lista tuple. Þannig getur hvaða þáttur sem er í biðröðinni verið ein skilaboð mblk_t, og ef til vill yfirmaður skilaboðaþuls mblk_t. Hver tuple skilaboð geta haft sína eigin deildargagnablokk. Við munum ræða hvers vegna tuples er þörf aðeins síðar.

Eins og getið er hér að ofan, innihalda skilaboðin sjálf ekki gagnablokk, heldur inniheldur þau aðeins bendil á minnissvæðið þar sem blokkin er geymd. Í þessum hluta minnir heildarmyndin af verkum fjölmiðlastraumarans á hurðageymsluna í teiknimyndinni „Monsters, Inc.,“ þar sem hurðir (tenglar á gögn - herbergi) fara á geðveikum hraða meðfram færiböndum á meðan herbergin sjálf. vera hreyfingarlaus.

Nú, þegar við færum eftir stigveldinu frá botni til topps, skulum við íhuga í smáatriðum skráðar einingar gagnaflutningskerfisins í fjölmiðlastreymi.

Gagnablokk dblk_t

Gagnablokkin samanstendur af haus og gagnabuffi. Hausnum er lýst með eftirfarandi uppbyggingu,

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

Reitirnir í uppbyggingu innihalda benda á upphaf biðminni, lok biðminni og aðgerðina til að eyða gagnabuffi. Síðasti þáttur í haus db_ref — viðmiðunarteljari, ef hann nær núlli, þjónar þetta sem merki um að eyða þessum reit úr minni. Ef gagnablokkin var búin til af aðgerðinni datab_alloc() , þá verður gagnaminnið settur í minni strax á eftir hausnum. Í öllum öðrum tilvikum getur biðminni verið staðsett einhvers staðar sérstaklega. Gagnaminnið mun innihalda merkjasýni eða önnur gögn sem við viljum vinna með síum.

Nýtt tilvik af gagnablokk er búið til með því að nota aðgerðina:

dblk_t *datab_alloc(int size);

Sem inntaksfæribreyta er hún gefin upp stærð gagna sem blokkin mun geyma. Meira minni er úthlutað til að setja haus - uppbyggingu - í upphafi úthlutaðs minnis gagnabanka. En þegar aðrar aðgerðir eru notaðar gerist þetta ekki alltaf; í sumum tilfellum getur gagnaminnið verið staðsett aðskilið frá gagnablokkhausnum. Þegar skipulag er búið til eru reitirnir stilltir þannig að reiturinn hennar db_grunnur benti á upphaf gagnasvæðisins, og db_lim til enda þess. Tenglafjöldi db_ref er stillt á einn. Gagnahreinsunarbendillinn er stilltur á núll.

Skilaboð mblk_t

Eins og fram kemur eru biðraðir þættir af gerðinni mblk_t, það er skilgreint sem hér segir:

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;

Uppbygging mblk_t inniheldur ábendingar í upphafi b_prev, b_næsta, sem eru nauðsynlegar til að skipuleggja tvöfalt tengdan lista (sem er biðröð biðröð_t).

Svo kemur bendillinn b_frh, sem er aðeins notað þegar skilaboðin eru hluti af tuple. Fyrir síðustu skilaboðin í túpunni er þessi bendill ógildur.

Næst sjáum við bendi í gagnablokk b_datap, sem skilaboðin eru til. Það er fylgt eftir með ábendingum á svæðið inni í blokkgagnabuffi. Field b_rptr tilgreinir staðsetninguna sem gögn úr biðminni verða lesin frá. Field b_wptr gefur til kynna staðsetninguna þaðan sem skrif á biðminni verða framkvæmd.

Eftirstöðvarnar eru þjónustueðli og tengjast ekki virkni gagnaflutningskerfisins.

Hér að neðan er ein skilaboð með nafninu m1 og gagnablokk d1.
Að kanna Mediastreamer2 VoIP vélina. 11. hluti
Eftirfarandi mynd sýnir túlla af þremur skilaboðum m1, m1_1, m1_2.
Að kanna Mediastreamer2 VoIP vélina. 11. hluti

Skilaboðaaðgerðir mblk_t

Ný skilaboð mblk_t búin til af aðgerðinni:

mblk_t *allocb(int size, int pri); 

hún setur ný skilaboð í minninguna mblk_t með gagnablokk af tilgreindri stærð stærð, önnur rök - pri ekki notað í þessari útgáfu af bókasafninu. Það ætti að vera núll. Á meðan aðgerðin er í gangi verður minni úthlutað fyrir uppbyggingu nýju skilaboðanna og aðgerðin verður kölluð mblk_init(), sem mun endurstilla alla reiti stofnaðs tilviks uppbyggingarinnar og nota síðan ofangreint datab_alloc(), mun búa til gagnabuffi. Eftir það verða reitirnir í uppbyggingunni stilltir:

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

Við úttakið fáum við ný skilaboð með frumstilltum reitum og tómum gagnabuffi. Til að bæta gögnum við skilaboð þarftu að afrita þau í biðminni fyrir gagnablokk:

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

þar sem gögn er vísir að gagnagjafanum og stærð - stærð þeirra.
þá þarftu að uppfæra bendilinn á skrifpunktinn þannig að hann bendi aftur á upphaf lausa svæðisins í biðminni:

msg->b_wptr = msg->b_wptr + size

Ef þú þarft að búa til skilaboð úr biðminni sem fyrir er, án þess að afrita, notaðu þá aðgerðina:

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

Aðgerðin, eftir að hafa búið til skilaboðin og uppbyggingu gagnablokkarinnar, mun stilla ábendingar sínar á gögnin á heimilisfanginu buff. Þeir. í þessu tilviki er gagnaminnið ekki staðsett á eftir hausreitum gagnablokkarinnar, eins og var þegar búið var til gagnablokk með aðgerðinni datab_alloc(). Biðminnið með gögnum sem send eru til aðgerðarinnar verður áfram þar sem það var, en með hjálp ábendinga verður það fest við nýstofnaðan haus gagnablokkarinnar og það, í samræmi við það, við skilaboðin.

Til ein skilaboð mblk_t Hægt er að tengja saman nokkra gagnablokka í röð. Þetta er gert með aðgerðinni:

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

mp — skilaboð sem öðrum gagnareit verður bætt við;
gögn — bendi á blokkina, afriti af honum verður bætt við skilaboðin;
stærð - stærð gagna;
púði — fáni um að stærð úthlutaðs minnis verði að vera stillt eftir 4-bæta mörkum (fylling verður gerð með núllum).

Ef það er nóg pláss í núverandi skilaboðagagnabuffi, þá verða nýju gögnin límd á bak við þau gögn sem þegar eru til staðar. Ef minna laust pláss er í biðminni fyrir skilaboðagögn en stærð, þá eru ný skilaboð búin til með nægilegri biðminni og gögnin afrituð í biðminni. Þetta er ný skilaboð, tengd þeim upprunalegu með bendili b_frh. Í þessu tilviki breytast skilaboðin í tuple.

Ef þú þarft að bæta öðrum blokk af gögnum við tuple, þá þarftu að nota aðgerðina:

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

hún mun finna síðustu skilaboðin í túpunni (hann hefur b_frh verður núll) og kallar á aðgerðina fyrir þessi skilaboð appendb().

Þú getur fundið út stærð gagna í skilaboðum eða túlkun með því að nota aðgerðina:

int msgdsize(const mblk_t *mp);

það mun fara í gegnum öll skilaboðin í tuplenum og skila heildarmagni gagna í gagnabuffum þessara skilaboða. Fyrir hvert skeyti er gagnamagnið reiknað sem hér segir:

 mp->b_wptr - mp->b_rptr

Til að sameina tvo túlla, notaðu aðgerðina:

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

hún bætir túpunni ným í skottið á túpunni mp og skilar bendi á síðustu skilaboðin í túpunni sem myndast.

Ef nauðsyn krefur er hægt að breyta tuple í ein skilaboð með einum gagnablokk; þetta er gert með aðgerðinni:

void msgpullup(mblk_t *mp,int len);

ef rök len er -1, þá er stærð úthlutaðs biðminni ákvörðuð sjálfkrafa. Ef len er jákvæð tala, verður biðminni af þessari stærð búinn til og gögnin fyrir tuple skilaboðin verða afrituð inn í það. Ef biðminni klárast mun afritun stöðvast þar. Fyrstu skilaboð tuplesins munu fá nýja stærð biðminni með afrituðum gögnum. Skilaboðunum sem eftir eru verður eytt og minnið sett aftur í hrúguna.

Þegar mannvirki er eytt mblk_t tekið er tillit til viðmiðunarfjölda gagnablokkarinnar ef, þegar hringt er freeb() það reynist vera núll, þá er gagnabuffi eytt ásamt tilvikinu mblk_t, sem bendir til þess.

Frumstillir reiti nýrra skilaboða:

void mblk_init(mblk_t *mp);

Að bæta öðru gögnum við skilaboðin:

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

Ef nýju gögnin passa ekki inn í laust pláss í biðminni skilaboðagagna, þá er sérstaklega búið til skeyti með biðminni af tilskildri stærð fest við skilaboðin (bendill á skilaboðin sem bætt var við er stillt í fyrstu skilaboðunum) og skilaboð breytast í túpel.

Að bæta gögnum við tuple:

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

Fallið kallar á appendb() í lykkju.

Að sameina tvo tuple í einn:

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

Skilaboð ným verður fest við mp.

Afrit af einni skilaboðum:

mblk_t *copyb(const mblk_t *mp);

Ljúka afritun af tuple með öllum gagnablokkum:

mblk_t *copymsg(const mblk_t *mp);

Þættirnir í tuple eru afritaðir af fallinu copyb().

Búðu til einfalt afrit af skilaboðum mblk_t. Í þessu tilviki er gagnablokkinn ekki afritaður heldur er viðmiðunarteljarinn aukinn db_ref:

mblk_t *dupb(mblk_t *mp);

Að búa til létt afrit af túpel. Gagnablokkir eru ekki afritaðir, aðeins tilvísunarteljarar þeirra eru hækkaðir db_ref:

mblk_t *dupmsg(mblk_t* m);

Að líma öll skilaboð tupels í eitt skilaboð:

void msgpullup(mblk_t *mp,size_t len);

Ef rökin len er -1, þá er stærð úthlutaðs biðminni ákvörðuð sjálfkrafa.

Skilaboðum eytt, tuple:

void freemsg(mblk_t *mp);

Viðmiðunarfjölda gagnablokkarinnar er lækkuð um einn. Ef það nær núlli er gagnablokkinni einnig eytt.

Útreikningur á heildarmagni gagna í skilaboðum eða túllum.

size_t msgdsize(const mblk_t *mp);

Að sækja skilaboð úr röðinni:

mblk_t *ms_queue_peek_last (q);

Að afrita innihald frátekinna reita eins skeytis í önnur skilaboð (reyndar innihalda þessir reitir fánar sem eru notaðir af miðlunarstraumspilaranum):

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

Biðröð biðröð_t

Skilaboðaröðin í fjölmiðlastreymi er útfærð sem hringlaga tvítengdur listi. Hver listaþáttur inniheldur bendil á gagnablokk með merkjasýnum. Það kemur í ljós að aðeins ábendingar um gagnablokkina hreyfast aftur á móti á meðan gögnin sjálf haldast hreyfingarlaus. Þeir. aðeins tenglar á þá eru færðir.
Uppbygging sem lýsir biðröðinni biðröð_t, sýnt hér að neðan:

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

Uppbyggingin inniheldur reit - bendi _q_stoppari sláðu inn *mblk_t, það bendir á fyrsta þáttinn (skilaboð) í biðröðinni. Annað svið skipulagsins er teljari skilaboða í biðröðinni.
Myndin hér að neðan sýnir biðröð sem heitir q1 og inniheldur 4 skilaboð m1, m2, m3, m4.
Að kanna Mediastreamer2 VoIP vélina. 11. hluti
Eftirfarandi mynd sýnir biðröð sem heitir q1 og inniheldur 4 skilaboð m1,m2,m3,m4. Skilaboð m2 er höfuð tuple sem inniheldur tvö skilaboð til viðbótar m2_1 og m2_2.

Að kanna Mediastreamer2 VoIP vélina. 11. hluti

Aðgerðir til að vinna með biðraðir queue_t

Uppsetning biðraðar:

void qinit(queue_t *q);

Field _q_stoppari (hér eftir munum við kalla það „tappa“) er frumstillt af aðgerðinni mblk_init(), fyrri þáttur hans og bendill fyrir næsta þátt eru stilltir til að benda á sjálfan sig. Teljari biðraðarþáttar er núllstilltur.

Nýjum þætti bætt við (skilaboð):

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

Nýr þáttur m er bætt við enda listans, eru þáttabendarnir stilltir þannig að tappi verður næsti þáttur fyrir hann og hann verður fyrri þáttur fyrir tappa. Teljari biðraðarþáttar er aukinn.

Að sækja þátt úr röðinni:

mblk_t * getq(queue_t *q); 

Skilaboðin sem koma eftir að tappa er sótt og þáttateljarinn er lækkaður. Ef engir þættir eru í biðröðinni nema stoppinn, þá er 0 skilað.

Skilaboð sett inn í biðröð:

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

Element mp sett á undan frumefninu EMP. Ef EMP=0, þá er skilaboðunum bætt við aftan á biðröðina.

Að sækja skilaboð frá höfuð biðröðarinnar:

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

Einingateljarinn er lækkaður.

Að lesa bendi í fyrsta þáttinn í biðröðinni:

mblk_t * peekq(queue_t *q); 

Fjarlægir alla þætti úr biðröðinni á meðan þeir eyða sjálfum þáttunum:

void flushq(queue_t *q, int how);

Rök hvernig ónotað. Biðraðareiningarteljarinn er stilltur á núll.

Fjölva til að lesa bendilinn á síðasta þáttinn í biðröðinni:

mblk_t * qlast(queue_t *q);

Þegar þú vinnur með skilaboðabiðraðir skaltu hafa í huga að þegar þú hringir ms_queue_put(q, m) með núllbendingu á skilaboðin fer aðgerðin í lykkjur. Forritið þitt mun frysta. hagar sér svipað ms_queue_next(q, m).

Að tengja síur

Biðröðin sem lýst er hér að ofan er notuð til að senda skilaboð frá einni síu til annarrar eða frá einni í nokkrar síur. Síur og tengingar þeirra mynda beint línurit. Inntak eða úttak síunnar verður kallað almenna orðið „pinna“. Til að lýsa í hvaða röð síur eru tengdar hver við aðra notar fjölmiðlastraumarinn hugtakið „merkjapunktur“. Merkjapunktur er uppbygging _MSCPoint, sem inniheldur bendil á síuna og númer eins pinna hennar; í samræmi við það lýsir það tengingu eins inntaks eða úttaks síunnar.

Merkjapunktur gagnavinnslu línurits

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

Síupinnar eru númeraðir frá núlli.

Tenging tveggja pinna með skilaboðaröð er lýst af uppbyggingunni _MS biðröð, sem inniheldur skilaboðaröð og ábendingar um merkjapunktana tvo sem það tengir:

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

Við munum kalla þessa uppbyggingu merkjatengil. Hver miðlunarstraumsía inniheldur töflu yfir inntakstengla og töflu yfir úttakstengla (MSQueue). Stærð taflna er stillt þegar þú býrð til síu; við höfum þegar gert þetta með því að nota útflutta breytu af gerðinni MSFilterDesc, þegar við þróuðum okkar eigin síu. Hér að neðan er uppbygging sem lýsir hvaða síu sem er í fjölmiðlastraumspilara, 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;

Eftir að við tengdum síurnar í C ​​forritinu í samræmi við áætlun okkar (en tengdum ekki merkið) bjuggum við til stýrt línurit, þar sem hnútarnir eru dæmi um uppbygginguna MSFilter, og brúnir eru dæmi um tengla MSQueue.

Á bak við tjöldin starfsemi auðkennisins

Þegar ég sagði þér að merkið væri sía fyrir uppsprettu titilsins, þá var það ekki allur sannleikurinn um það. Auðkenni er hlutur sem keyrir aðgerðir á klukkunni ferli() allar síur rásarinnar (grafið) sem það er tengt við. Þegar við tengjum ticker við línuritssíu í C forriti sýnum við merkinu grafið sem það mun stjórna héðan í frá þar til við slökkva á því. Eftir tengingu byrjar auðkennið að skoða línuritið sem það hefur umsjón með og safnar saman lista yfir síur sem innihalda það. Til að „telja“ ekki sömu síuna tvisvar, merkir hún þær síur sem fundust með því að setja gátreit í þær séð. Leitin er framkvæmd með því að nota tenglatöflurnar sem hver sía hefur.

Í kynningarferð sinni um línuritið athugar auðkennið hvort meðal síanna sé að minnsta kosti ein sem virkar sem uppspretta gagnablokka. Ef þær eru engar, þá er grafið talið rangt og auðkennið hrynur.

Ef grafið reynist „rétt“ fyrir hverja síu sem fannst, er aðgerðin kölluð til frumstillingar forvinnsla(). Um leið og augnablikið kemur fyrir næstu vinnslulotu (sjálfgefið á 10 millisekúndna fresti) kallar táknið á fallið ferli() fyrir allar áður fundnar upprunasíur og síðan fyrir þær síur sem eftir eru á listanum. Ef sían hefur inntakstengla skaltu keyra aðgerðina ferli() endurtekur þar til inntakstengla biðraðir eru tómar. Eftir þetta fer það yfir í næstu síu á listanum og „skrollar“ hana þar til inntakstenglar eru lausir við skilaboð. Merkið færist frá síu til síu þar til listinn endar. Þetta lýkur vinnslu hringrásarinnar.

Nú munum við snúa aftur að tuples og tala um hvers vegna slíkri aðili var bætt við fjölmiðlastrauminn. Almennt séð fellur gagnamagnið sem reikniritið sem starfar inni í síunni þarf ekki saman og er ekki margfeldi af stærð gagnabuffa sem berast við inntakið. Til dæmis erum við að skrifa síu sem framkvæmir hraðvirka Fourier-umbreytingu, sem samkvæmt skilgreiningu getur aðeins unnið úr gagnablokkum sem eru í krafti tveggja. Látum það vera 512 tölur. Ef gögnin eru mynduð af símarás, þá mun gagnabuffi hvers skilaboða við inntakið færa okkur 160 merkjasýni. Það er freistandi að safna ekki gögnum úr inntakinu fyrr en nauðsynlegt magn gagna er fyrir hendi. En í þessu tilviki mun árekstur eiga sér stað við merkið, sem mun árangurslaust reyna að fletta síunni þar til inntakstengillinn er tómur. Áður tilnefndum við þessa reglu sem þriðja meginreglu síunnar. Samkvæmt þessari meginreglu verður process() fall síunnar að taka öll gögn úr inntaksröðunum.

Að auki verður ekki hægt að taka aðeins 512 sýni úr inntakinu þar sem aðeins er hægt að taka heila kubba, þ.e. sían verður að taka 640 sýni og nota 512 af þeim, afganginn áður en nýr hluti af gögnum safnast saman. Þannig verður sían okkar, auk aðalstarfs hennar, að veita aukaaðgerðir fyrir milligeymslu inntaksgagna. Hönnuðir fjölmiðlastraumsins og lausn á þessu almenna vandamáli hafa þróað sérstakan hlut - MSBufferizer (buffer), sem leysir þetta vandamál með því að nota tuples.

Bufferizer (MSBufferizer)

Þetta er hlutur sem mun safna inntaksgögnum inni í síunni og byrja að senda þau til vinnslu um leið og magn upplýsinga er nægilegt til að keyra síualgrímið. Á meðan biðminni er að safna gögnum mun sían starfa í aðgerðalausri stillingu, án þess að nota upp vinnsluorku örgjörvans. En um leið og lestrarfallið frá biðminni skilar öðru gildi en núlli byrjar process() fall síunnar að taka og vinna úr gögnum úr biðminni í skömmtum af tilskildri stærð, þar til þau eru uppurin.
Gögn sem enn er ekki krafist eru áfram í biðminni sem fyrsti þátturinn í tuple, sem síðari blokkir af inntaksgögnum eru tengdar við.

Uppbyggingin sem lýsir biðminni:

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

Aðgerðir til að vinna með MSBufferizer

Að búa til nýtt biðminnistilvik:

MSBufferizer * ms_bufferizer_new(void);

Minni er úthlutað, frumstillt í ms_bufferizer_init() og bendill er skilað.

Frumstillingaraðgerð:

void ms_bufferizer_init(MSBufferizer *obj); 

Röð er að frumstilla q, sviði stærð er stillt á núll.

Bætir við skilaboðum:

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

Skilaboð m bætast í biðröðina. Reiknuð stærð gagnablokka er bætt við stærð.

Flytur öll skilaboð úr tengigagnaröðinni yfir í biðminni q:

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

Að flytja skilaboð frá hlekk q í biðminni er framkvæmt með því að nota aðgerðina ms_bufferizer_put().

Að lesa úr biðminni:

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

Ef stærð gagna sem safnast í biðminni er minni en umbeðin (datalen), þá skilar fallið núlli, gögn eru ekki afrituð í gögn. Annars er raðafritun gagna frá túllum sem staðsettar eru í biðminni framkvæmt. Eftir afritun er túllinu eytt og minnið losað. Afritun lýkur á því augnabliki sem dataalen bæti eru afrituð. Ef plássið klárast í miðri gagnablokk, þá verður gagnablokkinn minnkaður í þennan óafritaða hluta sem eftir er. Næst þegar þú hringir mun afritun halda áfram frá þessum tímapunkti.

Að lesa magn gagna sem nú er tiltækt í biðminni:

int ms_bufferizer_get_avail(MSBufferizer *obj); 

Skilar vellinum stærð biðminni.

Að fleygja hluta gagna í biðminni:

void ms_bufferizer_skip_bytes(MSBufferizer *obj, int bytes);

Tilgreindur fjöldi bæta af gögnum er sóttur og fleygt. Elstu gögnunum er hent.

Eyðir öllum skilaboðum í biðminni:

void ms_bufferizer_flush(MSBufferizer *obj); 

Gagnateljarinn er núllstilltur.

Eyðir öllum skilaboðum í biðminni:

void ms_bufferizer_uninit(MSBufferizer *obj); 

Teljarinn er ekki endurstilltur.

Að fjarlægja biðminni og losa minni:

void ms_bufferizer_destroy(MSBufferizer *obj);  

Dæmi um notkun biðminni má finna í frumkóða nokkurra fjölmiðlastraumsía. Til dæmis, í MS_L16_ENC síunni, sem endurraðar bæti í sýnunum frá netröð til hýsilpöntunar: l16.c

Í næstu grein munum við skoða málið um mat á auðkennisálagi og hvernig á að takast á við of mikið tölvuálag í fjölmiðlastreymi.

Heimild: www.habr.com

Bæta við athugasemd