Mediastreamer2 VoIP ఇంజిన్‌ను అన్వేషిస్తోంది. 11 వ భాగము

వ్యాసం యొక్క పదార్థం నా నుండి తీసుకోబడింది జెన్ ఛానల్.

Mediastreamer2 VoIP ఇంజిన్‌ను అన్వేషిస్తోంది. 11 వ భాగము

డేటా కదలిక విధానం

  • డేటా బ్లాక్ dblk_t
  • సందేశం mblk_t
  • mblk_t సందేశాలతో పని చేసే విధులు
  • క్యూ క్యూ_t
  • క్యూలు queue_tతో పని చేసే విధులు
  • ఫిల్టర్‌లను కనెక్ట్ చేస్తోంది
  • డేటా ప్రాసెసింగ్ గ్రాఫ్ యొక్క సిగ్నల్ పాయింట్
  • టిక్కర్ యొక్క తెరవెనుక కార్యకలాపాలు
  • బఫరైజర్ (MSBufferizer)
  • MSBufferizerతో పని చేయడానికి విధులు

గతం లో వ్యాసం మేము మా స్వంత ఫిల్టర్‌ని అభివృద్ధి చేసాము. ఈ కథనం మీడియా స్ట్రీమర్ ఫిల్టర్‌ల మధ్య డేటాను తరలించడానికి అంతర్గత మెకానిజంపై దృష్టి పెడుతుంది. ఇది భవిష్యత్తులో తక్కువ ప్రయత్నంతో అధునాతన ఫిల్టర్‌లను వ్రాయడానికి మిమ్మల్ని అనుమతిస్తుంది.

డేటా కదలిక విధానం

మీడియా స్ట్రీమర్‌లోని డేటా కదలిక నిర్మాణం ద్వారా వివరించబడిన క్యూలను ఉపయోగించి నిర్వహించబడుతుంది క్యూ_టి. వంటి సందేశాల స్ట్రింగ్స్ mblk_t, ఇది సిగ్నల్ డేటాను కలిగి ఉండదు, కానీ మునుపటి, తదుపరి సందేశానికి మరియు డేటా బ్లాక్‌కు మాత్రమే లింక్‌లు. అదనంగా, ఒకే రకమైన సందేశానికి లింక్ కోసం ఫీల్డ్ కూడా ఉందని నేను ప్రత్యేకంగా నొక్కి చెప్పాలనుకుంటున్నాను, ఇది సందేశాల యొక్క ఏకంగా లింక్ చేయబడిన జాబితాను నిర్వహించడానికి మిమ్మల్ని అనుమతిస్తుంది. అటువంటి జాబితా ద్వారా ఐక్యమైన సందేశాల సమూహాన్ని మేము టుపుల్ అని పిలుస్తాము. అందువల్ల, క్యూలోని ఏదైనా మూలకం ఒకే సందేశం కావచ్చు mblk_t, మరియు మెసేజ్ టుపుల్ యొక్క హెడ్ కావచ్చు mblk_t. ప్రతి టుపుల్ సందేశం దాని స్వంత వార్డు డేటా బ్లాక్‌ను కలిగి ఉంటుంది. టుపుల్స్ ఎందుకు అవసరమో కొంచెం తరువాత చర్చిస్తాము.

పైన పేర్కొన్నట్లుగా, సందేశం డేటా బ్లాక్‌ను కలిగి ఉండదు; బదులుగా, ఇది బ్లాక్ నిల్వ చేయబడిన మెమరీ ప్రాంతానికి పాయింటర్‌ను మాత్రమే కలిగి ఉంటుంది. ఈ భాగంలో, మీడియా స్ట్రీమర్ యొక్క పని యొక్క మొత్తం చిత్రం "మాన్స్టర్స్, ఇంక్." కార్టూన్‌లోని డోర్ వేర్‌హౌస్‌ను గుర్తుకు తెస్తుంది, ఇక్కడ తలుపులు (డేటా - రూమ్‌లకు లింక్‌లు) ఓవర్‌హెడ్ కన్వేయర్‌ల వెంట వెఱ్ఱి వేగంతో కదులుతాయి, అయితే గదులు స్వయంగా ఉంటాయి. కదలకుండా ఉంటాయి.

ఇప్పుడు, సోపానక్రమంలో దిగువ నుండి పైకి కదులుతూ, మీడియా స్ట్రీమర్‌లోని డేటా ట్రాన్స్‌మిషన్ మెకానిజం యొక్క జాబితా చేయబడిన ఎంటిటీలను వివరంగా పరిశీలిద్దాం.

డేటా బ్లాక్ 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_తదుపరి, రెట్టింపు లింక్ చేయబడిన జాబితాను నిర్వహించడానికి అవసరమైనవి (ఇది క్యూ క్యూ_టి).

అప్పుడు పాయింటర్ వస్తుంది b_cont, సందేశం టుపుల్‌లో భాగమైనప్పుడు మాత్రమే ఉపయోగించబడుతుంది. టుపుల్‌లోని చివరి సందేశం కోసం, ఈ పాయింటర్ శూన్యంగా ఉంటుంది.

తరువాత మనం డేటా బ్లాక్‌కి పాయింటర్‌ని చూస్తాము b_datap, దీని కోసం సందేశం ఉంది. దాని తర్వాత బ్లాక్ డేటా బఫర్ లోపల ఉన్న ప్రాంతానికి పాయింటర్‌లు ఉంటాయి. ఫీల్డ్ b_rptr బఫర్ నుండి డేటా చదవబడే స్థానాన్ని నిర్దేశిస్తుంది. ఫీల్డ్ b_wptr బఫర్‌కు వ్రాయబడిన ప్రదేశాన్ని సూచిస్తుంది.

మిగిలిన ఫీల్డ్‌లు సేవా స్వభావం కలిగి ఉంటాయి మరియు డేటా బదిలీ మెకానిజం యొక్క ఆపరేషన్‌తో సంబంధం కలిగి ఉండవు.

పేరుతో ఒకే సందేశం క్రింద ఉంది m1 మరియు డేటా బ్లాక్ d1.
Mediastreamer2 VoIP ఇంజిన్‌ను అన్వేషిస్తోంది. 11 వ భాగము
కింది బొమ్మ మూడు సందేశాల టూపుల్‌ను చూపుతుంది m1, m1_1, m1_2.
Mediastreamer2 VoIP ఇంజిన్‌ను అన్వేషిస్తోంది. 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*)); 

ఫంక్షన్, సందేశాన్ని మరియు డేటా బ్లాక్ యొక్క నిర్మాణాన్ని సృష్టించిన తర్వాత, చిరునామాలోని డేటాకు దాని పాయింటర్లను కాన్ఫిగర్ చేస్తుంది buf. ఆ. ఈ సందర్భంలో, ఫంక్షన్‌తో డేటా బ్లాక్‌ను సృష్టించేటప్పుడు డేటా బ్లాక్ యొక్క హెడర్ ఫీల్డ్‌ల తర్వాత డేటా బఫర్ కనుగొనబడలేదు. 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 శూన్యం) మరియు ఈ సందేశం కోసం ఫంక్షన్‌కు కాల్ చేస్తుంది అనుబంధం().

మీరు ఫంక్షన్‌ని ఉపయోగించి సందేశం లేదా టుపుల్‌లోని డేటా పరిమాణాన్ని కనుగొనవచ్చు:

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);

వాదన ఉంటే లెన్ -1, అప్పుడు కేటాయించిన బఫర్ పరిమాణం స్వయంచాలకంగా నిర్ణయించబడుతుంది. ఉంటే లెన్ ధనాత్మక సంఖ్య, ఈ పరిమాణంలో బఫర్ సృష్టించబడుతుంది మరియు టుపుల్ మెసేజ్ డేటా అందులోకి కాపీ చేయబడుతుంది. బఫర్ అయిపోతే, కాపీ చేయడం అక్కడ ఆగిపోతుంది. టుపుల్ యొక్క మొదటి సందేశం కాపీ చేయబడిన డేటాతో కొత్త సైజు బఫర్‌ని అందుకుంటుంది. మిగిలిన సందేశాలు తొలగించబడతాయి మరియు మెమరీ తిరిగి కుప్పలోకి వస్తుంది.

నిర్మాణాన్ని తొలగిస్తున్నప్పుడు 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);

వాదన ఉంటే లెన్ -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);

మలుపు క్యూ_టి

మీడియా స్ట్రీమర్‌లోని మెసేజ్ క్యూ సర్క్యులర్ రెట్టింపు లింక్ చేయబడిన జాబితాగా అమలు చేయబడింది. ప్రతి జాబితా మూలకం సిగ్నల్ నమూనాలతో డేటా బ్లాక్‌కు పాయింటర్‌ను కలిగి ఉంటుంది. డేటా బ్లాక్‌కు పాయింటర్‌లు మాత్రమే కదులుతాయని తేలింది, అయితే డేటా కూడా కదలకుండా ఉంటుంది. ఆ. వాటికి లింక్‌లు మాత్రమే తరలించబడతాయి.
క్యూను వివరించే నిర్మాణం క్యూ_టి, క్రింద చూపబడింది:

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

నిర్మాణంలో ఫీల్డ్ ఉంది - పాయింటర్ _q_స్టాపర్ *mblk_t అని టైప్ చేయండి, ఇది క్యూలోని మొదటి మూలకాన్ని (సందేశం) సూచిస్తుంది. నిర్మాణం యొక్క రెండవ ఫీల్డ్ క్యూలో సందేశాల కౌంటర్.
దిగువన ఉన్న బొమ్మ q1 అనే క్యూలో 4 సందేశాలు m1, m2, m3, m4ని చూపుతుంది.
Mediastreamer2 VoIP ఇంజిన్‌ను అన్వేషిస్తోంది. 11 వ భాగము
కింది బొమ్మలో q1 అనే క్యూలో 4 సందేశాలు m1,m2,m3,m4 ఉన్నాయి. Message m2 అనేది tuple యొక్క హెడ్, ఇందులో m2_1 మరియు m2_2 అనే రెండు సందేశాలు ఉన్నాయి.

Mediastreamer2 VoIP ఇంజిన్‌ను అన్వేషిస్తోంది. 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;

ఫిల్టర్ పిన్‌లు సున్నా నుండి ప్రారంభించబడతాయి.

మెసేజ్ క్యూ ద్వారా రెండు పిన్‌ల కనెక్షన్ నిర్మాణం ద్వారా వివరించబడింది _MS క్యూ, ఇది కనెక్ట్ చేసే రెండు సిగ్నల్ పాయింట్‌లకు సందేశ క్యూ మరియు పాయింటర్‌లను కలిగి ఉంటుంది:

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;

మేము మా ప్లాన్‌కు అనుగుణంగా సి ప్రోగ్రామ్‌లోని ఫిల్టర్‌లను కనెక్ట్ చేసిన తర్వాత (కానీ టిక్కర్‌ను కనెక్ట్ చేయలేదు), తద్వారా మేము డైరెక్ట్ గ్రాఫ్‌ను సృష్టించాము, వీటిలో నోడ్‌లు నిర్మాణం యొక్క ఉదాహరణలు MSFilter, మరియు అంచులు లింక్‌ల ఉదాహరణలు MSQueue.

టిక్కర్ యొక్క తెరవెనుక కార్యకలాపాలు

టిక్కర్ అనేది పేలు యొక్క మూలానికి ఫిల్టర్ అని నేను మీకు చెప్పినప్పుడు, దాని గురించి పూర్తి నిజం కాదు. టిక్కర్ అనేది గడియారంలో విధులను అమలు చేసే వస్తువు ప్రక్రియ () ఇది కనెక్ట్ చేయబడిన సర్క్యూట్ (గ్రాఫ్) యొక్క అన్ని ఫిల్టర్లు. మేము C ప్రోగ్రామ్‌లోని గ్రాఫ్ ఫిల్టర్‌కి టిక్కర్‌ను కనెక్ట్ చేసినప్పుడు, మేము దానిని ఆఫ్ చేసే వరకు ఇప్పటి నుండి నియంత్రించే గ్రాఫ్‌ని టిక్కర్‌కి చూపుతాము. కనెక్ట్ చేసిన తర్వాత, టిక్కర్ దాని సంరక్షణకు అప్పగించిన గ్రాఫ్‌ను పరిశీలించడం ప్రారంభిస్తుంది, దానిని కలిగి ఉన్న ఫిల్టర్‌ల జాబితాను కంపైల్ చేస్తుంది. ఒకే ఫిల్టర్‌ని రెండుసార్లు "లెక్కించకుండా" ఉండేందుకు, ఇది గుర్తించబడిన ఫిల్టర్‌లలో చెక్‌బాక్స్‌ని ఉంచడం ద్వారా గుర్తు చేస్తుంది చూసిన. ప్రతి ఫిల్టర్‌ని కలిగి ఉన్న లింక్ పట్టికలను ఉపయోగించి శోధన జరుగుతుంది.

గ్రాఫ్ యొక్క పరిచయ పర్యటన సమయంలో, టిక్కర్ ఫిల్టర్‌లలో డేటా బ్లాక్‌ల మూలంగా పనిచేసే కనీసం ఒకటి ఉందా అని తనిఖీ చేస్తుంది. ఏదీ లేకుంటే, గ్రాఫ్ తప్పుగా పరిగణించబడుతుంది మరియు టిక్కర్ క్రాష్ అవుతుంది.

గ్రాఫ్ "సరైనది" అని తేలితే, ప్రతి కనుగొనబడిన ఫిల్టర్ కోసం, ఫంక్షన్ ప్రారంభించడం కోసం పిలువబడుతుంది ముందస్తు ప్రక్రియ(). తదుపరి ప్రాసెసింగ్ సైకిల్ (డిఫాల్ట్‌గా ప్రతి 10 మిల్లీసెకన్లు) కోసం క్షణం వచ్చిన వెంటనే, టిక్కర్ ఫంక్షన్‌ని పిలుస్తుంది ప్రక్రియ () గతంలో కనుగొనబడిన అన్ని సోర్స్ ఫిల్టర్‌ల కోసం, ఆపై జాబితాలోని మిగిలిన ఫిల్టర్‌ల కోసం. ఫిల్టర్‌లో ఇన్‌పుట్ లింక్‌లు ఉన్నట్లయితే, ఫంక్షన్‌ని అమలు చేయండి ప్రక్రియ () ఇన్‌పుట్ లింక్ క్యూలు ఖాళీ అయ్యే వరకు పునరావృతమవుతుంది. దీని తర్వాత, ఇది జాబితాలోని తదుపరి ఫిల్టర్‌కి వెళుతుంది మరియు ఇన్‌పుట్ లింక్‌లు సందేశాలు లేకుండా ఉండే వరకు దానిని "స్క్రోల్ చేస్తుంది". జాబితా ముగిసే వరకు టిక్కర్ ఫిల్టర్ నుండి ఫిల్టర్‌కు కదులుతుంది. ఇది చక్రం యొక్క ప్రాసెసింగ్‌ను పూర్తి చేస్తుంది.

ఇప్పుడు మేము టుపుల్స్‌కి తిరిగి వస్తాము మరియు మీడియా స్ట్రీమర్‌కు అటువంటి ఎంటిటీ ఎందుకు జోడించబడిందనే దాని గురించి మాట్లాడుతాము. సాధారణంగా, ఫిల్టర్ లోపల పనిచేసే అల్గారిథమ్‌కి అవసరమైన డేటా మొత్తం ఏకీభవించదు మరియు ఇన్‌పుట్ వద్ద స్వీకరించబడిన డేటా బఫర్‌ల పరిమాణంలో గుణకారం కాదు. ఉదాహరణకు, మేము వేగవంతమైన ఫోరియర్ పరివర్తనను అమలు చేసే ఫిల్టర్‌ను వ్రాస్తున్నాము, ఇది నిర్వచనం ప్రకారం రెండు పవర్ ఉన్న డేటా బ్లాక్‌లను మాత్రమే ప్రాసెస్ చేయగలదు. ఇది 512 గణనలుగా ఉండనివ్వండి. డేటా టెలిఫోన్ ఛానెల్ ద్వారా రూపొందించబడినట్లయితే, ఇన్‌పుట్‌లోని ప్రతి సందేశం యొక్క డేటా బఫర్ మాకు 160 సిగ్నల్ నమూనాలను తెస్తుంది. అవసరమైన మొత్తం డేటా వచ్చే వరకు ఇన్‌పుట్ నుండి డేటాను సేకరించకూడదని ఇది ఉత్సాహం కలిగిస్తుంది. కానీ ఈ సందర్భంలో, టిక్కర్‌తో ఘర్షణ ఏర్పడుతుంది, ఇది ఇన్‌పుట్ లింక్ ఖాళీ అయ్యే వరకు ఫిల్టర్‌ను స్క్రోల్ చేయడానికి విఫలమవుతుంది. మునుపు, మేము ఈ నియమాన్ని ఫిల్టర్ యొక్క మూడవ సూత్రంగా నియమించాము. ఈ సూత్రం ప్రకారం, ఫిల్టర్ యొక్క ప్రాసెస్() ఫంక్షన్ తప్పనిసరిగా ఇన్‌పుట్ క్యూల నుండి మొత్తం డేటాను తీసుకోవాలి.

అదనంగా, ఇన్‌పుట్ నుండి 512 నమూనాలను మాత్రమే తీసుకోవడం సాధ్యం కాదు, ఎందుకంటే మీరు మొత్తం బ్లాక్‌లను మాత్రమే తీసుకోగలరు, అనగా. ఫిల్టర్ 640 నమూనాలను తీసుకోవాలి మరియు వాటిలో 512ని ఉపయోగించాలి, మిగిలినవి డేటా యొక్క కొత్త భాగాన్ని సేకరించడానికి ముందు. అందువల్ల, మా ఫిల్టర్, దాని ప్రధాన పనికి అదనంగా, ఇన్‌పుట్ డేటా యొక్క ఇంటర్మీడియట్ నిల్వ కోసం సహాయక చర్యలను అందించాలి. మీడియా స్ట్రీమర్ మరియు ఈ సాధారణ సమస్యకు పరిష్కారం యొక్క డెవలపర్లు ఒక ప్రత్యేక వస్తువును అభివృద్ధి చేశారు - MSBufferizer (బఫరర్), ఇది టుపుల్స్ ఉపయోగించి ఈ సమస్యను పరిష్కరిస్తుంది.

బఫరైజర్ (MSBufferizer)

ఇది ఫిల్టర్ లోపల ఇన్‌పుట్ డేటాను క్రోడీకరించే ఆబ్జెక్ట్ మరియు ఫిల్టర్ అల్గారిథమ్‌ను అమలు చేయడానికి తగినంత సమాచారం ఉన్న వెంటనే ప్రాసెసింగ్ కోసం దానిని సమర్పించడం ప్రారంభమవుతుంది. బఫర్ డేటాను సేకరిస్తున్నప్పుడు, ప్రాసెసర్ యొక్క ప్రాసెసింగ్ శక్తిని ఉపయోగించకుండా ఫిల్టర్ నిష్క్రియ మోడ్‌లో పని చేస్తుంది. కానీ బఫరర్ నుండి రీడింగ్ ఫంక్షన్ సున్నా కాకుండా వేరే విలువను తిరిగి ఇచ్చిన వెంటనే, ఫిల్టర్ యొక్క ప్రాసెస్() ఫంక్షన్ బఫరర్ నుండి డేటా అయిపోయే వరకు అవసరమైన పరిమాణంలోని భాగాలలో తీసుకోవడం మరియు ప్రాసెస్ చేయడం ప్రారంభిస్తుంది.
ఇంకా అవసరం లేని డేటా టుపుల్ యొక్క మొదటి మూలకం వలె బఫర్‌లో మిగిలిపోయింది, దీనికి ఇన్‌పుట్ డేటా యొక్క తదుపరి బ్లాక్‌లు జోడించబడతాయి.

బఫర్‌ను వివరించే నిర్మాణం:

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.c

తర్వాతి కథనంలో, మేము టిక్కర్‌పై లోడ్‌ను అంచనా వేసే సమస్యను మరియు మీడియా స్ట్రీమర్‌లో అధిక కంప్యూటింగ్ లోడ్‌ను ఎదుర్కోవడానికి మార్గాలను పరిశీలిస్తాము.

మూలం: www.habr.com

ఒక వ్యాఖ్యను జోడించండి