የ Mediastreamer2 VoIP ሞተርን ማሰስ። ክፍል 11

የጽሁፉ ይዘት ከኔ የተወሰደ ነው። የዜን ቻናል.

የ Mediastreamer2 VoIP ሞተርን ማሰስ። ክፍል 11

የውሂብ እንቅስቃሴ ዘዴ

  • የውሂብ አግድ dblk_t
  • መልእክት mblk_t
  • ከመልእክቶች mblk_t ጋር የመስራት ተግባራት
  • ወረፋ ወረፋ_ት
  • ከወረፋዎች queue_t ጋር የመስራት ተግባራት
  • ማጣሪያዎችን በማገናኘት ላይ
  • የውሂብ ሂደት ግራፍ ምልክት ነጥብ
  • ከትዕይንቱ በስተጀርባ የምልክት ምልክት እንቅስቃሴዎች
  • ቋት (MSBufferizer)
  • ከMSBufferizer ጋር ለመስራት ተግባራት

በመጨረሻው ጽሑፍ የራሳችንን ማጣሪያ አዘጋጅተናል. ይህ ጽሑፍ በሚዲያ ዥረት ማጣሪያዎች መካከል ውሂብን ለማንቀሳቀስ በውስጣዊ አሠራር ላይ ያተኩራል። ይህ ለወደፊቱ በትንሽ ጥረት የተራቀቁ ማጣሪያዎችን እንዲጽፉ ያስችልዎታል።

የውሂብ እንቅስቃሴ ዘዴ

በመገናኛ ብዙሃን ዥረት ውስጥ የውሂብ እንቅስቃሴ የሚከናወነው በመዋቅሩ የተገለጹ ወረፋዎችን በመጠቀም ነው ወረፋ_ት. እንደ መልእክት ሕብረቁምፊዎች mblk_t, እራሳቸው የሲግናል ውሂብን ያልያዙት, ነገር ግን ወደ ቀዳሚው, ወደ ቀጣዩ መልእክት እና ወደ የውሂብ እገዳው አገናኞች ብቻ ናቸው. በተጨማሪም፣ በተለይ አንድ አይነት መልእክት ያለው መልእክት የሚያገናኝበት መስክ እንዳለ አፅንዖት መስጠት እፈልጋለሁ፣ ይህም በነጠላ የተገናኙ የመልእክት ዝርዝሮችን ለማደራጀት ያስችላል። በእንደዚህ ዓይነት ዝርዝር የተዋሃዱ የመልእክት ቡድንን ቱፕል እንለዋለን። ስለዚህ ማንኛውም የወረፋ አካል ነጠላ መልእክት ሊሆን ይችላል። mblk_t, እና ምናልባት የመልእክት tuple ራስ ሊሆን ይችላል mblk_t. እያንዳንዱ የቱፕል መልእክት የራሱ የዎርድ ዳታ ብሎክ ሊኖረው ይችላል። ለምን tuples እንደሚያስፈልግ ትንሽ ቆይተን እንነጋገራለን.

ከላይ እንደተገለፀው መልእክቱ ራሱ የብሎክ ኦፍ ዳታ የለውም፤ ይልቁንስ ማገጃው ወደተቀመጠበት የማስታወሻ ቦታ ጠቋሚ ብቻ ይዟል። በዚህ ክፍል ውስጥ፣ የሚዲያ ዥረት ማሰራጫው አጠቃላይ ምስል በካርቱን “Monsters, Inc.” ውስጥ ያለውን የበሩን መጋዘን ያስታውሳል ፣ በሮች (ከመረጃ ጋር የሚገናኙበት - ክፍሎች) በእብደት ፍጥነት ከአናት ማጓጓዣዎች ጋር ይንቀሳቀሳሉ ፣ ክፍሎቹ ግን እራሳቸው ናቸው ። እንቅስቃሴ አልባ ሆነው ይቆዩ።

አሁን፣ ከሥርዓተ ተዋረድ ጋር በመሆን ከታች ወደ ላይ፣ በመገናኛ ብዙኃን ዥረት ማሰራጫ ውስጥ የተዘረዘሩትን የመረጃ ማስተላለፊያ ዘዴዎች ዝርዝር አካላትን በዝርዝር እንመልከት።

የውሂብ እገዳ dblk_t

የውሂብ እገዳው ራስጌ እና የውሂብ ቋት ያካትታል። ራስጌው በሚከተለው መዋቅር ይገለጻል.

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

የአወቃቀሩ መስኮቹ የጠቋሚውን መጀመሪያ፣ የመያዣውን መጨረሻ እና የመረጃ ቋቱን የመሰረዝ ተግባር ጠቋሚዎችን ይይዛሉ። በርዕስ ውስጥ የመጨረሻው አካል db_ማጣቀሻ - የማጣቀሻ ቆጣሪ, ዜሮ ላይ ከደረሰ, ይህ እገዳውን ከማህደረ ትውስታ ለመሰረዝ እንደ ምልክት ሆኖ ያገለግላል. የውሂብ እገዳው በተግባሩ ከተፈጠረ ዳታብ_አሎክ() , ከዚያም የውሂብ ቋት ከራስጌ በኋላ ወዲያውኑ ወደ ማህደረ ትውስታ ይቀመጣል. በሌሎች በሁሉም ሁኔታዎች, ቋት በተለየ ቦታ ላይ ሊገኝ ይችላል. የመረጃ ቋቱ የሲግናል ናሙናዎችን ወይም ሌላ በማጣሪያዎች ልናስኬደው የምንፈልገውን ውሂብ ይይዛል።

ተግባሩን በመጠቀም የውሂብ እገዳ አዲስ ምሳሌ ተፈጥሯል፡-

dblk_t *datab_alloc(int size);

እንደ የግቤት መለኪያ, እገዳው የሚያከማችበት የውሂብ መጠን ይሰጠዋል. ተጨማሪ ማህደረ ትውስታ ራስጌ ለማስቀመጥ - መዋቅር - በተመደበው ማህደረ ትውስታ መጀመሪያ ላይ ይመደባል ዳታብ. ነገር ግን ሌሎች ተግባራትን ሲጠቀሙ ይህ ሁልጊዜ የሚከሰት አይደለም፡ በአንዳንድ ሁኔታዎች የመረጃ ቋቱ ከዳታ ብሎክ ራስጌ ተለይቶ ሊገኝ ይችላል። መዋቅርን በሚፈጥሩበት ጊዜ, መስኮቹ የሚዋቀሩበት መስክ ነው db_base የውሂብ አካባቢ መጀመሪያ ላይ ጠቁሟል, እና db_lim እስከ መጨረሻው ድረስ. የአገናኝ ብዛት db_ማጣቀሻ ወደ አንድ ተቀናብሯል። የውሂብ ግልጽ ተግባር ጠቋሚው ወደ ዜሮ ተቀናብሯል።

የእርስዎ መልዕክት 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_ቀዳሚ, ለ_ቀጣይ, ድርብ የተገናኘ ዝርዝር ለማደራጀት አስፈላጊ ናቸው (ይህም ወረፋ ነው ወረፋ_ት).

ከዚያም ጠቋሚው ይመጣል ለ_ይቀጥላል, መልእክቱ የ tuple አካል ሲሆን ብቻ ጥቅም ላይ ይውላል. በ tuple ውስጥ ላለው የመጨረሻ መልእክት፣ ይህ ጠቋሚ ዋጋ እንደሌለው ይቆያል።

በመቀጠል ወደ የውሂብ እገዳ ጠቋሚን እናያለን b_ዳታፕመልእክቱ የሚገኝበት። በብሎክ መረጃ ቋት ውስጥ ወዳለው ቦታ ጠቋሚዎች ይከተላል። መስክ b_rptr ከጠባቂው የተገኘው መረጃ የሚነበብበትን ቦታ ይገልጻል። መስክ b_wpr ወደ ቋት የሚጽፍበትን ቦታ ያመለክታል።

የተቀሩት መስኮች የአገልግሎት ባህሪ ያላቸው እና ከውሂብ ማስተላለፊያ ዘዴ አሠራር ጋር አይገናኙም.

ስም ያለው አንድ መልእክት ከዚህ በታች አለ። 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(), ይህም የተፈጠረ መዋቅርን ሁሉንም መስኮች እንደገና ያስጀምራል እና ከዚያም ከላይ የተጠቀሱትን በመጠቀም ዳታብ_አሎክ()፣ የውሂብ ቋት ይፈጥራል። ከዚያ በኋላ በመዋቅሩ ውስጥ ያሉት መስኮች ይዋቀራሉ-

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

ተግባሩ ፣ መልእክቱን እና የውሂብ እገዳውን አወቃቀር ከፈጠረ በኋላ ጠቋሚዎቹን በአድራሻው ላይ ባለው ውሂብ ያዋቅራል። ቡፍ. እነዚያ። በዚህ ሁኔታ ፣ የውሂብ ቋት ከዳታ ማገጃው ራስጌ መስኮች በኋላ የሚገኝ አይደለም ፣ ልክ ከተግባሩ ጋር የውሂብ ማገጃ ሲፈጥሩ እንደነበረው ዳታብ_አሎክ(). ወደ ተግባሩ የተላለፈው ውሂብ ያለው ቋት በነበረበት ይቆያል፣ ነገር ግን በጠቋሚዎች እገዛ አዲስ ከተፈጠረ የውሂብ እገዳ ራስጌ ጋር ይያያዛል፣ እናም በዚህ መሠረት ከመልእክቱ ጋር።

ወደ አንድ መልእክት mblk_t በርካታ የውሂብ ብሎኮች በቅደም ተከተል ሊጣመሩ ይችላሉ። ይህ የሚከናወነው በሚከተለው ተግባር ነው-

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

mp - ሌላ የውሂብ እገዳ የሚጨመርበት መልእክት;
መረጃ - ወደ እገዳው ጠቋሚ, ቅጂው ወደ መልእክቱ የሚጨመርበት;
ልክ - የውሂብ መጠን;
ጥንድ - የተመደበው ማህደረ ትውስታ መጠን በ 4-ባይት ወሰን ላይ መስተካከል ያለበት ባንዲራ (ማቀፊያው በዜሮዎች ይከናወናል)።

አሁን ባለው የመልእክት ዳታ ቋት ውስጥ በቂ ቦታ ካለ፣ አዲሱ መረጃ እዚያ ካለው ውሂብ በስተጀርባ ይለጠፋል። በመልእክት ዳታ ቋት ውስጥ ያነሰ ነፃ ቦታ ካለ ልክ, ከዚያም በቂ ቋት መጠን ያለው አዲስ መልእክት ይፈጠራል እና ውሂቡ ወደ ቋት ይገለበጣል። ይህ አዲስ መልእክት ነው፣ ጠቋሚን በመጠቀም ከመጀመሪያው ጋር የተገናኘ ለ_ይቀጥላል. በዚህ አጋጣሚ መልእክቱ ወደ ቱፕልነት ይለወጣል.

ወደ tuple ሌላ የውሂብ ብሎክ ማከል ከፈለጉ ተግባሩን መጠቀም ያስፈልግዎታል

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

በ tuple ውስጥ የመጨረሻውን መልእክት ታገኛለች (እሱ አለው ለ_ይቀጥላል ባዶ ይሆናል) እና ለዚህ መልእክት ተግባሩን ይጠራል appendb().

ተግባሩን በመጠቀም በመልእክት ወይም በ tuple ውስጥ ያለውን የውሂብ መጠን ማወቅ ይችላሉ-

int msgdsize(const mblk_t *mp);

በ tuple ውስጥ ያሉትን ሁሉንም መልእክቶች በማዞር በእነዚያ መልእክቶች የውሂብ ቋት ውስጥ ያለውን አጠቃላይ የውሂብ መጠን ይመልሳል። ለእያንዳንዱ መልእክት የመረጃው መጠን እንደሚከተለው ይሰላል፡-

 mp->b_wptr - mp->b_rptr

ሁለት ቱፕሎችን ለማጣመር ተግባሩን ይጠቀሙ፡-

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

ቱፕሉን ትይዛለች። newm ወደ ቱፕል ጅራት mp እና አመልካች ወደ ውጤቱ tuple የመጨረሻ መልእክት ይመልሳል።

አስፈላጊ ከሆነ ቱፕል ከአንድ የውሂብ ብሎክ ጋር ወደ አንድ መልእክት ሊቀየር ይችላል ፣ ይህ የሚከናወነው በሚከተለው ተግባር ነው-

void msgpullup(mblk_t *mp,int len);

ክርክር ከሆነ ብቻ ነው -1፣ ከዚያ የተመደበው ቋት መጠን በራስ-ሰር ይወሰናል። ከሆነ ብቻ አዎንታዊ ቁጥር ነው፣ የዚህ መጠን ቋት ይፈጠራል እና የ tuple መልእክት ውሂቡ ወደ እሱ ይገለበጣል። ማስቀመጫው ካለቀ፣ መቅዳት እዚያ ይቆማል። የ tuple የመጀመሪያው መልእክት ከተቀዳው ውሂብ ጋር አዲስ መጠን ቋት ይቀበላል። የተቀሩት መልዕክቶች ይሰረዛሉ እና ማህደረ ትውስታው ወደ ክምር ይመለሳል.

መዋቅርን ሲሰርዝ mblk_t በሚደውሉበት ጊዜ የውሂብ እገዳው የማጣቀሻ ቆጠራ ግምት ውስጥ ይገባል ነፃ () ዜሮ ሆኖ ይወጣል፣ ከዚያ የውሂብ ቋት ከምሳሌው ጋር ይሰረዛል mblk_t, ይህም የሚያመለክተው.

የአዲስ መልእክት መስኮችን ማስጀመር፡-

void mblk_init(mblk_t *mp);

ወደ መልእክቱ ሌላ ቁራጭ ማከል

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

አዲሱ መረጃ ከመልእክት ዳታ ቋት ነፃ ቦታ ጋር የማይጣጣም ከሆነ፣ የሚፈለገው መጠን ያለው ቋት ያለው ለብቻው የተፈጠረ መልእክት ከመልእክቱ ጋር ተያይዟል (የተጨመረው መልእክት ጠቋሚ በመጀመሪያው መልእክት ተቀምጧል) እና መልእክት ወደ ቱፕልነት ይቀየራል።

አንድ የውሂብ ቁራጭ ወደ tuple ማከል

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

ተግባሩ appendb() በ loop ውስጥ ይጠራል።

ሁለት ዱባዎችን በአንድ ላይ በማጣመር;

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

የእርስዎ መልዕክት newm ጋር ተያይዟል mp.

የአንድ ነጠላ መልእክት ቅጂ መስራት፡-

mblk_t *copyb(const mblk_t *mp);

የ tuple ሙሉ ቅጂ ከሁሉም የውሂብ ብሎኮች ጋር፡-

mblk_t *copymsg(const mblk_t *mp);

የ tuple ንጥረ ነገሮች በተግባሩ ይገለበጣሉ ቅጂ ().

ቀላል የመልእክት ቅጂ ይፍጠሩ mblk_t. በዚህ አጋጣሚ የውሂብ እገዳው አልተገለበጠም, ነገር ግን የማጣቀሻ ቆጣሪው ተጨምሯል db_ማጣቀሻ:

mblk_t *dupb(mblk_t *mp);

ቀላል ክብደት ያለው የ tuple ቅጂ መስራት። የውሂብ ብሎኮች አልተገለበጡም፣ የማጣቀሻ ቆጣሪዎቻቸው ብቻ ይጨምራሉ db_ማጣቀሻ:

mblk_t *dupmsg(mblk_t* m);

ሁሉንም የቱፕል መልእክቶች ወደ አንድ መልእክት ማያያዝ፡-

void msgpullup(mblk_t *mp,size_t len);

ክርክር ከሆነ ብቻ ነው -1፣ ከዚያ የተመደበው ቋት መጠን በራስ-ሰር ይወሰናል።

መልእክት በመሰረዝ ላይ፣ tuple:

void freemsg(mblk_t *mp);

የውሂብ እገዳው የማጣቀሻ ብዛት በአንድ ቀንሷል። ዜሮ ከደረሰ, የውሂብ እገዳው እንዲሁ ይሰረዛል.

በመልእክት ወይም በ tuple ውስጥ ያለው አጠቃላይ የውሂብ መጠን ስሌት።

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. መልእክት m2 ሁለት ተጨማሪ መልዕክቶች m2_1 እና m2_2 የያዘ የ tuple ራስ ነው።

የ 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_ቀጣይ(q፣ m).

ማጣሪያዎችን በማገናኘት ላይ

ከላይ የተገለጸው ወረፋ ከአንድ ማጣሪያ ወደ ሌላ ወይም ከአንድ ወደ ብዙ ማጣሪያዎች መልዕክቶችን ለማስተላለፍ ያገለግላል. ማጣሪያዎች እና ግንኙነቶቻቸው የሚመራ ግራፍ ይመሰርታሉ። የማጣሪያው ግቤት ወይም ውፅዓት አጠቃላይ ቃል "ፒን" ተብሎ ይጠራል. ማጣሪያዎች እርስ በእርሳቸው የተገናኙበትን ቅደም ተከተል ለመግለጽ የመገናኛ ብዙሃን ዥረት የ "ምልክት ነጥብ" ጽንሰ-ሐሳብ ይጠቀማል. የሲግናል ነጥብ መዋቅር ነው _MSCP ቅብየማጣሪያውን ጠቋሚ እና የአንዱን ፒን ቁጥር የያዘ፤ በዚህ መሰረት የማጣሪያውን ግብአት ወይም ውፅዓት የአንዱን ግንኙነት ይገልጻል።

የውሂብ ሂደት ግራፍ ምልክት ነጥብ

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

የማጣሪያ ፒኖች ከዜሮ ጀምሮ የተቆጠሩ ናቸው።

የሁለት ፒን ግንኙነት በመልእክት ወረፋ በመዋቅሩ ይገለጻል። _MSQueueየመልእክት ወረፋ እና ጠቋሚዎችን ወደሚያገናኛቸው ሁለት የምልክት ነጥቦች የያዘ፡-

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

ይህንን መዋቅር የሲግናል ማገናኛ እንለዋለን። እያንዳንዱ የሚዲያ ዥረት ማጣሪያ የግቤት አገናኞች ሠንጠረዥ እና የውጤት አገናኞች ሰንጠረዥ ይይዛል (MSQueue). ማጣሪያ በሚፈጥሩበት ጊዜ የጠረጴዛዎች መጠን ይዘጋጃል ፣ ይህንን ወደ ውጭ የተላከ ዓይነት ተለዋዋጭ በመጠቀም አስቀድመን አድርገናል። MSFilterDescየራሳችንን ማጣሪያ ስንሠራ. ከዚህ በታች የሚዲያ ዥረት ማሰራጫ ውስጥ ያለውን ማንኛውንም ማጣሪያ የሚገልጽ መዋቅር ነው። MSFilter:


struct _MSFilter{
    MSFilterDesc *desc;    /* Указатель на дескриптор фильтра. */
    /* Защищенные атрибуты, их нельзя сдвигать или убирать иначе будет нарушена работа с плагинами. */
    ms_mutex_t lock;      /* Семафор. */
    MSQueue **inputs;     /* Таблица входных линков. */
    MSQueue **outputs;    /* Таблица выходных линков. */
    struct _MSFactory *factory; /* Указатель на фабрику, которая создала данный экземпляр фильтра. */
    void *padding;              /* Не используется, будет задействован если добавятся защищенные поля. */
    void *data;                 /* Указатель на произвольную структуру для хранения данных внутреннего состояния фильтра и промежуточных вычислений. */
    struct _MSTicker *ticker;   /* Указатель на объект тикера, который не должен быть нулевым когда вызывается функция process(). */
    /*private attributes, they can be moved and changed at any time*/
    MSList *notify_callbacks; /* Список обратных вызовов, используемых для обработки событий фильтра. */
    uint32_t last_tick;       /* Номер последнего такта, когда выполнялся вызов process(). */ 
    MSFilterStats *stats;     /* Статистика работы фильтра.*/
    int postponed_task; /*Количество отложенных задач. Некоторые фильтры могут откладывать обработку данных (вызов process()) на несколько тактов.*/
    bool_t seen;  /* Флаг, который использует тикер, чтобы помечать что этот экземпляр фильтра он уже обслужил на данном такте.*/
};
typedef struct _MSFilter MSFilter;

በእቅዳችን መሰረት በሲ ፕሮግራም ውስጥ ያሉትን ማጣሪያዎች ካገናኘን በኋላ (ነገር ግን ምልክት ማድረጊያውን አላገናኘንም) ፣ በዚህ መንገድ የሚመራ ግራፍ ፈጠርን ፣ አንጓዎቹ የመዋቅር ምሳሌዎች ናቸው ። MSFilter, እና ጠርዞች የአገናኞች ምሳሌዎች ናቸው MSQueue.

ከትዕይንቱ በስተጀርባ የምልክት ምልክት እንቅስቃሴዎች

መዥገሪያው የመዥገሮች ምንጭ ማጣሪያ እንደሆነ ስነግርዎት, ስለ እሱ ሙሉ በሙሉ እውነት አልነበረም. ምልክት ማድረጊያ በሰዓት ላይ ተግባራትን የሚያከናውን ነገር ነው። ሂደት () የተገናኘበት የወረዳ (ግራፍ) ሁሉም ማጣሪያዎች። በሲ ፕሮግራም ውስጥ መዥገርን ከግራፍ ማጣሪያ ጋር ስናገናኘው፣ እስክናጠፋው ድረስ የሚቆጣጠረውን ግራፍ ለጠቋሚው እናሳያለን። ከተገናኘ በኋላ ምልክት ማድረጊያው ለእሱ እንክብካቤ የተሰጠውን ግራፍ መመርመር ይጀምራል, በውስጡም የማጣሪያዎችን ዝርዝር ያጠናቅራል. ተመሳሳዩን ማጣሪያ ሁለት ጊዜ “ለመቁጠር” እንዳይቻል፣ የተገኙትን ማጣሪያዎች በውስጣቸው አመልካች ሳጥን በማስቀመጥ ምልክት ያደርጋል። የታየው. ፍለጋው የሚከናወነው እያንዳንዱ ማጣሪያ ያላቸውን የአገናኝ ሰንጠረዦችን በመጠቀም ነው.

የግራፉን መግቢያ በሚጎበኝበት ጊዜ ምልክት ማድረጊያው ከማጣሪያዎቹ መካከል እንደ የውሂብ ብሎኮች ምንጭ ሆኖ የሚያገለግል ቢያንስ አንድ መኖሩን ያረጋግጣል። ምንም ከሌሉ ፣ ከዚያ ግራፉ ትክክል እንዳልሆነ ይቆጠራል እና ምልክቱ ይወድቃል።

ግራፉ "ትክክል" ሆኖ ከተገኘ, ለእያንዳንዱ የተገኘ ማጣሪያ, ተግባሩ ለመጀመር ይባላል ቅድመ ሂደት(). ለቀጣዩ የማቀነባበሪያ ዑደት ቅጽበት እንደደረሰ (በነባሪ በየ10 ሚሊሰከንድ) ምልክት ማድረጊያው ተግባሩን ይጠራዋል። ሂደት () ቀደም ሲል ለተገኙት ሁሉም ምንጮች ማጣሪያዎች እና ከዚያ በዝርዝሩ ውስጥ ለተቀሩት ማጣሪያዎች። ማጣሪያው የግቤት አገናኞች ካሉት, ከዚያም ተግባሩን ያሂዱ ሂደት () የግቤት ማገናኛ ወረፋዎች ባዶ እስኪሆኑ ድረስ ይደግማል። ከዚህ በኋላ በዝርዝሩ ውስጥ ወደሚቀጥለው ማጣሪያ ይሸጋገራል እና የግቤት አገናኞች ከመልእክቶች ነጻ እስኪሆኑ ድረስ "ያሸብልል". ዝርዝሩ እስኪያልቅ ድረስ ምልክት ማድረጊያው ከማጣሪያ ወደ ማጣሪያ ይንቀሳቀሳል። ይህ የዑደቱን ሂደት ያጠናቅቃል.

አሁን ወደ tuples እንመለሳለን እና ለምን እንደዚህ ያለ አካል ወደ ሚዲያ ዥረት እንደታከለ እንነጋገራለን ። በአጠቃላይ በማጣሪያው ውስጥ የሚሠራው አልጎሪዝም የሚፈለገው የውሂብ መጠን አይመሳሰልም እና በመግቢያው ላይ ከተቀበሉት የውሂብ ቋት መጠን ብዜት አይደለም። ለምሳሌ፣ ፈጣን ፎሪየር ትራንስፎርምን የሚያከናውን ማጣሪያ እየጻፍን ነው፣ ይህም በትርጉሙ መጠናቸው የሁለት ሃይል የሆነ የውሂብ ብሎኮችን ብቻ ነው። 512 ቆጠራዎች ይሁኑ. መረጃው የሚመነጨው በቴሌፎን ቻናል ከሆነ በመግቢያው ላይ ያለው የእያንዳንዱ መልእክት ዳታ ቋት 160 የሲግናል ናሙናዎችን ያመጣልናል። የሚፈለገው የውሂብ መጠን እስካልተገኘ ድረስ ከግብአት ላይ መረጃ ላለመሰብሰብ ፈታኝ ነው። ነገር ግን በዚህ አጋጣሚ የመግቢያ ማገናኛ ባዶ እስኪሆን ድረስ ማጣሪያውን ለማሸብለል የሚሞክር ከቲከር ጋር ግጭት ይከሰታል። ከዚህ ቀደም ይህንን ደንብ እንደ ማጣሪያው ሦስተኛው መርሆ አድርገን ሰይመንታል። በዚህ መርህ መሰረት የማጣሪያው ሂደት() ተግባር ሁሉንም መረጃዎች ከግቤት ወረፋዎች መውሰድ አለበት።

በተጨማሪም, ከመግቢያው ውስጥ 512 ናሙናዎችን ብቻ መውሰድ አይቻልም, ምክንያቱም ሙሉ ብሎኮችን ብቻ መውሰድ ይችላሉ, ማለትም. ማጣሪያው 640 ናሙናዎችን ወስዶ 512 ቱን መጠቀም ይኖርበታል። ስለዚህ የእኛ ማጣሪያ ከዋና ስራው በተጨማሪ ለመካከለኛ የግብአት ውሂብ ማከማቻ ረዳት እርምጃዎችን መስጠት አለበት። የመገናኛ ብዙሃን ዥረት አዘጋጆች እና ለዚህ አጠቃላይ ችግር መፍትሄ ልዩ ነገር አዘጋጅተዋል - MSBufferizer (bufferer) , ይህንን ችግር ቱፕልስ በመጠቀም ይፈታል.

ቋት (MSBufferizer)

ይህ በማጣሪያው ውስጥ የግቤት ውሂብን የሚያከማች እና የመረጃው መጠን የማጣሪያ አልጎሪዝምን ለማስኬድ እንደበቃ ወዲያውኑ ለሂደቱ ማስገባት ይጀምራል። ቋት ውሂብን እያጠራቀም እያለ ማጣሪያው የማቀነባበሪያውን የማስኬጃ ሃይል ​​ሳይጠቀም በስራ ፈት ሁነታ ይሰራል። ነገር ግን ከጠባቂው የንባብ ተግባር ከዜሮ ውጭ የሆነ እሴት እንደተመለሰ የማጣሪያው ሂደት() ተግባር እስኪያልቅ ድረስ ከመጠባበቂያው ውስጥ መረጃን በሚፈለገው መጠን መውሰድ እና ማካሄድ ይጀምራል።
ገና ያልተፈለገ ውሂብ እንደ የ tuple የመጀመሪያ አካል ሆኖ በመጠባበቂያው ውስጥ ይቆያል፣ ከዚያ በኋላ የግቤት ውሂብ ብሎኮች ተያይዘዋል።

ቋቱን የሚገልጸው መዋቅር፡-

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

በመጠባበቂያው ውስጥ የተከማቸ የውሂብ መጠን ከተጠየቀው ያነሰ ከሆነ (datalen), ከዚያ ተግባሩ ዜሮን ይመልሳል, ውሂብ ወደ ውሂብ አይገለበጥም. ያለበለዚያ ፣ በመጠባበቂያው ውስጥ ከሚገኙት ቱፕሎች ተከታታይ የውሂብ መቅዳት ይከናወናል ። ከተገለበጠ በኋላ, tuple ይሰረዛል እና ማህደረ ትውስታው ይለቀቃል. ዳታለን ባይት በሚገለበጥበት ቅጽበት መቅዳት ያበቃል። በዳታ ብሎክ መካከል ቦታ ካለቀ በዚህ መልእክት ውስጥ የውሂብ እገዳው ወደ ቀሪው ያልተገለበጠ ክፍል ይቀነሳል። በሚቀጥለው ጊዜ ሲደውሉ መቅዳት ከዚህ ነጥብ ይቀጥላል።

በአሁኑ ጊዜ በመጠባበቂያው ውስጥ ያለውን የውሂብ መጠን በማንበብ፡-

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

በሚቀጥለው ርዕስ ላይ የቲኬር ጭነት ግምትን ጉዳይ እና በመገናኛ ዥረቱ ውስጥ ከመጠን በላይ የኮምፒዩተር ጭነት እንዴት እንደሚፈታ እንመለከታለን.

ምንጭ: hab.com

አስተያየት ያክሉ