A Mediastreamer2 VoIP motor felfedezése. 11. rész

A cikk anyaga az én zen csatorna.

A Mediastreamer2 VoIP motor felfedezése. 11. rész

Adatmozgatási mechanizmus

  • Adatblokk dblk_t
  • Üzenet: mblk_t
  • Az üzenetekkel való munkavégzés funkciói mblk_t
  • Queue queue_t
  • Funkciók a queue_t sorokkal való munkavégzéshez
  • Szűrők csatlakoztatása
  • Az adatfeldolgozási grafikon jelpontja
  • A ticker színfalai mögötti tevékenységei
  • Puffer (MSBufferizer)
  • Funkciók az MSBufferizerrel való munkavégzéshez

Az utolsóban cikk saját szűrőt fejlesztettünk ki. Ez a cikk az adatátviteli médiaszűrők közötti belső mechanizmusra összpontosít. Ez lehetővé teszi, hogy a jövőben kevesebb erőfeszítéssel kifinomult szűrőket írjon.

Adatmozgatási mechanizmus

Az adatátvitel a média streamerben a struktúra által leírt várólisták segítségével történik queue_t. Üzenetek sora, mint pl mblk_t, amelyek önmagukban nem tartalmaznak jeladatokat, hanem csak az előző, következő üzenetre és az adatblokkra hivatkoznak. Ezen túlmenően szeretném külön hangsúlyozni, hogy van egy mező is az azonos típusú üzenetre mutató hivatkozás számára, amely lehetővé teszi az üzenetek egyenként linkelt listájának rendszerezését. Az ilyen listával egyesített üzenetek csoportját sornak nevezzük. Így a sor bármely eleme lehet egyetlen üzenet mblk_t, és talán egy üzenetsor feje mblk_t. Minden sor üzenetnek lehet saját kórtermi adatblokkja. Egy kicsit később megvitatjuk, miért van szükség sorokra.

Mint fentebb említettük, maga az üzenet nem tartalmaz adatblokkot, hanem csak egy mutatót tartalmaz arra a memóriaterületre, ahol a blokk tárolva van. Ebben a részben a média streamer munkájának összképe a „Monsters, Inc.” rajzfilm ajtóraktárára emlékeztet, ahol az ajtók (hivatkozások az adatokhoz - szobák) őrült sebességgel mozognak a felső szállítószalagokon, míg maguk a helyiségek mozdulatlan maradjon.

Most a hierarchiában alulról felfelé haladva nézzük meg részletesen a média streamer adatátviteli mechanizmusának felsorolt ​​entitásait.

Adatblokk dblk_t

Az adatblokk egy fejlécből és egy adatpufferből áll. A fejlécet a következő szerkezet írja le:

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

A struktúra mezői tartalmazzák a puffer elejére, a puffer végére és az adatpuffer törlésének funkciójára mutató mutatókat. Utolsó elem a fejlécben db_ref — referenciaszámláló, ha eléri a nullát, ez jelzésként szolgál a blokk törlésére a memóriából. Ha az adatblokkot a függvény hozta létre datab_alloc() , akkor az adatpuffer közvetlenül a fejléc után kerül a memóriába. Minden más esetben a puffer valahol külön is elhelyezhető. Az adatpuffer jelmintákat vagy egyéb adatokat tartalmaz majd, amelyeket szűrőkkel szeretnénk feldolgozni.

Az adatblokk új példánya a következő függvény használatával jön létre:

dblk_t *datab_alloc(int size);

Bemeneti paraméterként megadjuk a blokk által tárolt adatok méretét. Több memória kerül lefoglalásra annak érdekében, hogy a lefoglalt memória elejére egy fejléc - struktúra - kerüljön adatb. Más funkciók használatakor azonban ez nem mindig történik meg, bizonyos esetekben az adatpuffer az adatblokk fejlécétől külön is elhelyezhető. Struktúra létrehozásakor a mezők úgy vannak beállítva, hogy annak mezője db_base az adatterület elejére mutatott, és db_lim a végére. Linkek száma db_ref egyre van állítva. Az adattörlés funkció mutatója nullára van állítva.

üzenet mblk_t

Mint említettük, a sorelemek típusúak mblk_t, a következőképpen van meghatározva:

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;

Szerkezet mblk_t elején mutatókat tartalmaz b_prev, b_next, amelyek szükségesek egy duplán linkelt lista (ami egy sor queue_t).

Aztán jön a mutató b_cont, amely csak akkor használatos, ha az üzenet egy sor része. A sor utolsó üzeneténél ez a mutató nulla marad.

Ezután egy adatblokkra mutató mutatót látunk b_datap, amelyhez az üzenet létezik. Ezt követik a blokk adatpufferen belüli területre mutató mutatók. Terület b_rptr megadja azt a helyet, ahonnan a pufferből származó adatok beolvasásra kerülnek. Terület b_wptr jelzi azt a helyet, ahonnan a pufferbe írás történik.

A fennmaradó mezők szolgáltatás jellegűek, és nem kapcsolódnak az adatátviteli mechanizmus működéséhez.

Az alábbiakban egyetlen üzenet található a névvel m1 és adatblokk d1.
A Mediastreamer2 VoIP motor felfedezése. 11. rész
A következő ábra három üzenetből álló sorozatot mutat be m1, m1_1, m1_2.
A Mediastreamer2 VoIP motor felfedezése. 11. rész

Üzenetküldési funkciók mblk_t

Új üzenet mblk_t a függvény hozta létre:

mblk_t *allocb(int size, int pri); 

új üzenetet helyez el a memóriájában mblk_t a megadott méretű adatblokkkal méret, második érv - a nem használják a könyvtár ezen verziójában. Nullának kell maradnia. A funkció működése során az új üzenet szerkezetéhez memória kerül lefoglalásra és a függvény meghívásra kerül mblk_init(), amely visszaállítja a struktúra létrehozott példányának összes mezőjét, majd a fent említettek használatával datab_alloc(), létrehoz egy adatpuffert. Ezután a struktúra mezői konfigurálódnak:

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

A kimeneten új üzenetet kapunk inicializált mezőkkel és üres adatpufferrel. Ha adatokat szeretne hozzáadni egy üzenethez, át kell másolnia azt az adatblokk pufferbe:

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

ahol dátum egy mutató az adatforrásra, és méret - méretük.
akkor frissítenie kell a mutatót az írási pontra, hogy ismét a puffer szabad területének elejére mutasson:

msg->b_wptr = msg->b_wptr + size

Ha üzenetet kell létrehoznia egy meglévő pufferből, másolás nélkül, akkor használja a következő funkciót:

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

A függvény az üzenet és az adatblokk szerkezetének létrehozása után konfigurálja a mutatóit a címen lévő adatokra barnássárga. Azok. ebben az esetben az adatpuffer nem az adatblokk fejlécmezői után helyezkedik el, mint az adatblokk létrehozásánál a funkcióval. datab_alloc(). A függvénynek átadott adatokat tartalmazó puffer ugyanott marad, ahol volt, de mutatók segítségével az adatblokk újonnan létrehozott fejlécéhez, és ennek megfelelően az üzenethez csatolódik.

Egy üzenethez mblk_t Több adatblokk egymás után összefűzhető. Ezt a következő függvény teszi:

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

mp — egy üzenet, amelyhez újabb adatblokk kerül hozzáadásra;
dátum — mutató a blokkra, amelynek egy példánya hozzáadásra kerül az üzenethez;
méret — adatméret;
párna — egy jelző, amely szerint a lefoglalt memória méretét egy 4 bájtos határ mentén kell igazítani (a kitöltés nullákkal történik).

Ha van elég hely a meglévő üzenetadat-pufferben, akkor az új adatok a már ott lévő adatok mögé kerülnek beillesztésre. Ha kevesebb szabad hely van az üzenet adatpufferében, mint méret, akkor létrejön egy új üzenet megfelelő puffermérettel, és az adatok átmásolódnak a pufferébe. Ez egy új üzenet, amely mutató segítségével kapcsolódik az eredetihez b_cont. Ebben az esetben az üzenet sorba változik.

Ha újabb adatblokkot kell hozzáadnia a sorhoz, akkor a következő függvényt kell használnia:

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

az utolsó üzenetet megtalálja a sorban (van b_cont null lesz), és meghívja az üzenet függvényét appendb().

A függvény segítségével megtudhatja az üzenetben vagy sorban lévő adatok méretét:

int msgdsize(const mblk_t *mp);

végigfut a sor összes üzenetén, és visszaadja az üzenetek adatpuffereiben lévő teljes adatmennyiséget. Minden egyes üzenethez a következőképpen számítjuk ki az adatmennyiséget:

 mp->b_wptr - mp->b_rptr

Két sor kombinálásához használja a következő függvényt:

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

hozzáfűzi a sort newm a tuple farkához mp és visszaad egy mutatót az eredményül kapott sor utolsó üzenetére.

Ha szükséges, egy sor egyetlen adatblokkból egyetlen üzenetté alakítható, ezt a következő függvény teszi meg:

void msgpullup(mblk_t *mp,int len);

ha érvelés len értéke -1, akkor a lefoglalt puffer mérete automatikusan meghatározásra kerül. Ha len pozitív szám, akkor egy ekkora puffer jön létre, és a sor üzenet adatait másoljuk bele. Ha a puffer kifogy, a másolás itt leáll. A sor első üzenete új méretű puffert kap a másolt adatokkal. A fennmaradó üzenetek törlődnek, és a memória visszakerül a kupacba.

Struktúra törlésekor mblk_t az adatblokk referenciaszámát veszik figyelembe, ha híváskor freeb() nullának bizonyul, akkor az adatpuffer törlődik a példánysal együtt mblk_t, ami rámutat.

Új üzenet mezőinek inicializálása:

void mblk_init(mblk_t *mp);

Újabb adat hozzáadása az üzenethez:

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

Ha az új adatok nem férnek el az üzenet adatpuffer szabad helyére, akkor az üzenethez egy külön elkészített üzenetet csatolunk a szükséges méretű pufferrel (az első üzenetben a hozzáadott üzenetre mutató mutató kerül beállításra), és a üzenet sorrá változik.

Adatok hozzáadása egy sorhoz:

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

A függvény ciklusban hívja meg az appendb() függvényt.

Két sor egyesítése egybe:

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

üzenet newm csatolni fogják mp.

Egyetlen üzenet másolatának készítése:

mblk_t *copyb(const mblk_t *mp);

Egy sor teljes másolása az összes adatblokkkal:

mblk_t *copymsg(const mblk_t *mp);

A sor elemeit a függvény másolja copyb().

Készítsen egyszerű másolatot az üzenetről mblk_t. Ebben az esetben az adatblokkot nem másolják, hanem a referenciaszámlálóját növelik db_ref:

mblk_t *dupb(mblk_t *mp);

Egy tuple könnyű másolatának készítése. Az adatblokkok nem másolódnak, csak a referenciaszámlálóik növekszik db_ref:

mblk_t *dupmsg(mblk_t* m);

Egy sor összes üzenetének összeragasztása egy üzenetbe:

void msgpullup(mblk_t *mp,size_t len);

Ha az érvelés len értéke -1, akkor a lefoglalt puffer mérete automatikusan meghatározásra kerül.

Üzenet törlése, sor:

void freemsg(mblk_t *mp);

Az adatblokk referenciaszáma eggyel csökken. Ha eléri a nullát, az adatblokk is törlődik.

Az üzenetben vagy sorban lévő adatok teljes mennyiségének kiszámítása.

size_t msgdsize(const mblk_t *mp);

Üzenet lekérése a sor végéről:

mblk_t *ms_queue_peek_last (q);

Egy üzenet fenntartott mezőinek tartalmának másolása egy másik üzenetbe (valójában ezek a mezők a média streamer által használt jelzőket tartalmazzák):

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

fordulat queue_t

A média streamer üzenetsora körkörös, kétszeresen összekapcsolt listaként van megvalósítva. Minden listaelem tartalmaz egy mutatót egy jelmintákat tartalmazó adatblokkra. Kiderült, hogy csak az adatblokkra mutató mutatók mozognak felváltva, miközben maga az adat mozdulatlan marad. Azok. csak a rájuk mutató hivatkozások kerülnek áthelyezésre.
A sort leíró struktúra queue_t, lásd alább:

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

A szerkezet tartalmaz egy mezőt - egy mutatót _q_dugó írja be az *mblk_t parancsot, ez a sor első elemére (üzenetére) mutat. A struktúra második mezője a sorban lévő üzenetek számlálója.
Az alábbi ábrán egy q1 nevű sor látható, amely 4 üzenetet tartalmaz m1, m2, m3, m4.
A Mediastreamer2 VoIP motor felfedezése. 11. rész
A következő ábra egy q1 nevű sort mutat, amely 4 üzenetet tartalmaz m1,m2,m3,m4. Az m2 üzenet egy sor feje, amely további két m2_1 és m2_2 üzenetet tartalmaz.

A Mediastreamer2 VoIP motor felfedezése. 11. rész

Funkciók a queue_t sorokkal való munkavégzéshez

Sor inicializálása:

void qinit(queue_t *q);

Mező _q_dugó (a továbbiakban „dugónak” nevezzük) a függvény inicializálja mblk_init(), az előző eleme és a következő elem mutatója úgy van beállítva, hogy önmagára mutasson. A sorelem-számláló nullázódik.

Új elem hozzáadása (üzenetek):

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

Új elem m felkerül a lista végére, az elemmutatókat úgy állítjuk be, hogy az ütköző legyen a következő eleme, és az legyen az ütköző előző eleme. A sorelem-számláló növekszik.

Elem lekérése a sorból:

mblk_t * getq(queue_t *q); 

Az ütköző lekérése és az elemszámláló csökkentése után megjelenő üzenet. Ha az ütközőn kívül nincsenek elemek a sorban, akkor 0-t ad vissza.

Üzenet beszúrása a sorba:

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

Элемент mp az elem elé illesztve emp... Ha emp=0, akkor az üzenet hozzáadódik a sor végéhez.

Üzenet lekérése a sor fejéből:

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

Az elemszámláló csökken.

Mutató beolvasása a sor első elemére:

mblk_t * peekq(queue_t *q); 

Az összes elem eltávolítása a sorból, miközben maguk az elemek törlődnek:

void flushq(queue_t *q, int how);

Érv hogyan nem használt. A sorelem-számláló nullára van állítva.

Makró a sor utolsó elemére mutató mutató olvasásához:

mblk_t * qlast(queue_t *q);

Amikor üzenetsorokkal dolgozik, ügyeljen arra, hogy amikor hív ms_queue_put(q, m) nulla mutatóval az üzenetre, a függvény hurkok. A program lefagy. hasonlóan viselkedik ms_queue_next(q, m).

Szűrők csatlakoztatása

A fent leírt várólista üzenetek továbbítására szolgál egyik szűrőről a másikra vagy egyről több szűrőre. A szűrők és kapcsolataik irányított gráfot alkotnak. A szűrő bemenetét vagy kimenetét általános „pin” szónak nevezzük. A szűrők egymáshoz csatlakoztatásának sorrendjének leírására a média streamer a „jelpont” fogalmát használja. A jelzőpont a szerkezet _MSCPpoint, amely a szűrőre mutató mutatót és annak egyik érintkezőjének számát tartalmazza, ennek megfelelően leírja a szűrő valamelyik be- vagy kimenetének csatlakoztatását.

Az adatfeldolgozási grafikon jelpontja

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

A szűrőtüskék számozása nullától kezdődően történik.

Két érintkező üzenetsor általi összekapcsolását a szerkezet írja le _MSQueue, amely egy üzenetsort és az általa összekapcsolt két jelpontra mutató mutatókat tartalmaz:

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

Ezt a struktúrát jelkapcsolatnak nevezzük. Minden média streamer szűrő tartalmaz egy táblázatot a bemeneti hivatkozásokról és egy táblázatot a kimeneti hivatkozásokról (MSQueue). A táblázatok méretét a szűrő létrehozásakor állítjuk be, ezt már megtettük egy exportált típusú változóval MSFilterDesc, amikor kifejlesztettük a saját szűrőnket. Az alábbiakban egy olyan struktúra látható, amely leírja a médiastreamer bármely szűrőjét, 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;

Miután a C programban tervünknek megfelelően összekapcsoltuk a szűrőket (de a tickert nem kötöttük össze), így létrehoztunk egy irányított gráfot, melynek csomópontjai a struktúra példányai. MSFilter, az élek pedig hivatkozások példányai MSQueue.

A ticker színfalai mögötti tevékenységei

Amikor elmondtam, hogy a ticker a kullancsok forrásának szűrője, nem volt benne a teljes igazság. A ticker olyan objektum, amely funkciókat futtat az órán folyamat() annak az áramkörnek (grafikonnak) az összes szűrője, amelyhez csatlakoztatva van. Amikor egy C programban egy tickert csatlakoztatunk egy gráfszűrőhöz, megmutatjuk a tickernek azt a grafikont, amelyet mostantól ki nem kapcsol. A csatlakozás után a ticker elkezdi vizsgálni a rábízott grafikont, és összeállítja az azt tartalmazó szűrők listáját. Annak érdekében, hogy ugyanazt a szűrőt ne „számolja meg” kétszer, az észlelt szűrőket egy jelölőnégyzet behelyezésével megjelöli látott. A keresés az egyes szűrőkhöz tartozó hivatkozási táblázatok segítségével történik.

A grafikon bevezető körútja során a ticker ellenőrzi, hogy a szűrők között van-e legalább olyan, amely adatblokkok forrásaként működik. Ha nincs ilyen, akkor a grafikon hibásnak minősül, és a ticker összeomlik.

Ha a grafikon „helyes”-nek bizonyul, minden egyes talált szűrő esetében a függvény inicializálásra kerül előfeldolgozás (). Amint elérkezik a pillanat a következő feldolgozási ciklushoz (alapértelmezés szerint 10 ezredmásodpercenként), a ticker meghívja a függvényt folyamat() az összes korábban talált forrásszűrőhöz, majd a lista többi szűrőjéhez. Ha a szűrő rendelkezik bemeneti hivatkozásokkal, akkor futtassa a funkciót folyamat() addig ismétlődik, amíg a bemeneti hivatkozási sorok ki nem ürülnek. Ezt követően a listában a következő szűrőre lép, és addig „görgeti”, amíg a bemeneti hivatkozások üzenetmentesek nem lesznek. A ticker szűrőről szűrőre mozog a lista végéig. Ezzel befejeződik a ciklus feldolgozása.

Most visszatérünk a sorokhoz, és arról beszélünk, hogy miért került egy ilyen entitás a média streamerhez. Általánosságban elmondható, hogy a szűrőn belül működő algoritmus által igényelt adatmennyiség nem esik egybe, és nem többszöröse a bemeneten fogadott adatpufferek méretének. Például írunk egy gyors Fourier-transzformációt végrehajtó szűrőt, amely definíció szerint csak olyan adatblokkokat tud feldolgozni, amelyek mérete kettős hatvány. Legyen 512 szám. Ha az adatot telefonos csatorna generálja, akkor minden üzenet adatpuffere a bemeneten 160 jelmintát hoz nekünk. Csábító, hogy ne gyűjtsünk adatokat a bemenetről, amíg meg nem áll a szükséges adatmennyiség. De ebben az esetben ütközés történik a tickerrel, amely sikertelenül próbálja görgetni a szűrőt, amíg a bemeneti hivatkozás ki nem ürül. Korábban ezt a szabályt jelöltük meg a szűrő harmadik alapelvének. Ezen elv szerint a szűrő process() függvényének minden adatot el kell vennie a bemeneti sorokból.

Ráadásul nem lehet majd csak 512 mintát venni a bemenetről, mivel csak egész blokkokat, pl. a szűrőnek 640 mintát kell vennie, és ebből 512-t kell felhasználnia, a maradékot az új adatrész felhalmozása előtt. Így a szűrőnknek a fő munkája mellett segédműveleteket kell biztosítania a bemeneti adatok közbenső tárolására. A média streamer és az általános probléma megoldásának fejlesztői kifejlesztettek egy speciális objektumot - MSBufferizer (puffer), amely ezt a problémát sorok segítségével oldja meg.

Puffer (MSBufferizer)

Ez egy olyan objektum, amely a szűrőn belül felhalmozza a bemeneti adatokat, és megkezdi a feldolgozásra való elküldését, amint az információ mennyisége elegendő a szűrőalgoritmus futtatásához. Amíg a puffer adatokat halmoz fel, a szűrő készenléti üzemmódban működik, anélkül, hogy a processzor feldolgozási teljesítményét felhasználná. De amint az olvasási függvény a pufferből nullától eltérő értéket ad vissza, a szűrő process() függvénye megkezdi az adatok felvételét és feldolgozását a pufferből a kívánt méretű részekben, amíg az ki nem merül.
A még nem szükséges adatok a pufferben maradnak a tuple első elemeként, amelyhez a következő bemeneti adatok blokkjai kapcsolódnak.

A puffert leíró szerkezet:

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

Funkciók az MSBufferizerrel való munkavégzéshez

Új pufferpéldány létrehozása:

MSBufferizer * ms_bufferizer_new(void);

A memória lefoglalása, inicializálása megtörtént ms_bufferizer_init() és egy mutatót adnak vissza.

Inicializálási funkció:

void ms_bufferizer_init(MSBufferizer *obj); 

A sor inicializálása folyamatban van q, terület méret nullára van állítva.

Üzenet hozzáadása:

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

Az m üzenet hozzáadódik a sorhoz. Az adatblokkok számított mérete hozzáadódik méret.

Az összes üzenet átvitele a hivatkozási adatsorból a pufferbe q:

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

Üzenetek átvitele linkről q a pufferben a funkció segítségével történik ms_bufferizer_put().

Olvasás a pufferből:

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

Ha a pufferben felhalmozott adatok mérete kisebb, mint a kért (datalen), akkor a függvény nullát ad vissza, az adatok nem másolódnak adatba. Ellenkező esetben az adatok szekvenciális másolása történik a pufferben található sorokból. Másolás után a sor törlődik és a memória felszabadul. A másolás abban a pillanatban ér véget, amikor a Datalen byte-ok másolásra kerülnek. Ha egy adatblokk közepén elfogy a hely, akkor ebben az üzenetben az adatblokk a fennmaradó másolatlan részre csökken. A következő híváskor a másolás ettől a ponttól folytatódik.

A pufferben jelenleg elérhető adatmennyiség leolvasása:

int ms_bufferizer_get_avail(MSBufferizer *obj); 

Visszaadja a mezőt méret puffer.

A pufferben lévő adatok egy részének elvetése:

void ms_bufferizer_skip_bytes(MSBufferizer *obj, int bytes);

A megadott számú bájtnyi adatot lekéri és eldobja. A legrégebbi adatok el lesznek vetve.

Az összes üzenet törlése a pufferben:

void ms_bufferizer_flush(MSBufferizer *obj); 

Az adatszámláló nullázódik.

Az összes üzenet törlése a pufferben:

void ms_bufferizer_uninit(MSBufferizer *obj); 

A számláló nincs nullázva.

A puffer eltávolítása és a memória felszabadítása:

void ms_bufferizer_destroy(MSBufferizer *obj);  

A puffer használatára számos média streamer szűrő forráskódjában találunk példákat. Például az MS_L16_ENC szűrőben, amely átrendezi a minták bájtjait a hálózati sorrendből a gazdagép sorrendbe: l16.c

A következő cikkben megvizsgáljuk a ticker terhelésének becslését és a média streamer túlzott számítási terhelése elleni küzdelem módjait.

Forrás: will.com

Hozzászólás