Mediastreamer2 VoIP انجڻ جي ڳولا. حصو 11

مضمون جو مواد منهنجي طرفان ورتو ويو آهي زين چينل.

Mediastreamer2 VoIP انجڻ جي ڳولا. حصو 11

ڊيٽا جي حرڪت واري ميڪانيزم

  • ڊيٽا بلاڪ dblk_t
  • پيغام mblk_t
  • پيغامن سان ڪم ڪرڻ جا ڪم mblk_t
  • قطار قطار_t
  • queues queue_t سان ڪم ڪرڻ جا ڪم
  • ڳنڍڻ وارا فلٽر
  • ڊيٽا پروسيسنگ گراف جي سگنل پوائنٽ
  • پردي جي پويان ٽڪر جي سرگرمين
  • بفرائزر (MSBufferizer)
  • MSBufferizer سان ڪم ڪرڻ لاءِ ڪم

آخري ۾ مضمون اسان پنهنجو فلٽر ٺاهيو آهي. هي آرٽيڪل ميڊيا اسٽريمر فلٽرن جي وچ ۾ ڊيٽا کي منتقل ڪرڻ جي اندروني ميڪانيزم تي ڌيان ڏيندو. اهو توهان کي مستقبل ۾ گهٽ ڪوشش سان نفيس فلٽر لکڻ جي اجازت ڏيندو.

ڊيٽا جي حرڪت واري ميڪانيزم

ميڊيا اسٽريمر ۾ ڊيٽا جي حرڪت ڪئي وئي آهي قطار ذريعي بيان ڪيل ساخت جي ذريعي قطار_t. پيغامن جون تارون جهڙوڪ mblk_t، جيڪي پاڻ ۾ سگنل ڊيٽا تي مشتمل نه آهن، پر صرف پوئين، ايندڙ پيغام ۽ ڊيٽا بلاڪ ڏانهن لنڪس. ان کان علاوه، مان خاص طور تي زور ڏيڻ چاهيان ٿو ته ساڳئي قسم جي پيغام جي لنڪ لاء هڪ فيلڊ پڻ آهي، جيڪا توهان کي منظم ڪرڻ جي اجازت ڏئي ٿي پيغامن جي هڪ اڪيلو ڳنڍيل فهرست. اسان کي سڏينداسين پيغامن جي هڪ گروهه کي گڏيل طور تي اهڙي فهرست طرفان هڪ ٽوپل. اهڙيء طرح، قطار جي ڪنهن به عنصر هڪ واحد پيغام ٿي سگهي ٿو mblk_t, ۽ ٿي سگهي ٿو هڪ پيغام tuple جي سر mblk_t. هر ٽوپل پيغام کي پنهنجي وارڊ ڊيٽا بلاڪ ڪري سگھي ٿو. اسان بحث ڪنداسين ڇو ته ٽوپل جي ضرورت آهي ٿوري دير بعد.

جيئن مٿي ذڪر ڪيو ويو آهي، پيغام پاڻ ۾ ڊيٽا جي بلاڪ تي مشتمل ناهي؛ ان جي بدران، اهو صرف هڪ پوائنٽر تي مشتمل آهي ياداشت واري علائقي ڏانهن جتي بلاڪ محفوظ ٿيل آهي. هن حصي ۾، ميڊيا اسٽريمر جي ڪم جي مجموعي تصوير ڪارٽون “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_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_اڳيون، جيڪي ٻه ڀيرا ڳنڍيل لسٽ کي منظم ڪرڻ لاءِ ضروري آهن (جيڪي هڪ قطار آهي قطار_t).

پوءِ اشارو اچي ٿو b_cont، جيڪو صرف استعمال ڪيو ويندو آهي جڏهن پيغام هڪ ٽوپل جو حصو آهي. ٽوپل ۾ آخري پيغام لاء، هي اشارو null رهي ٿو.

اڳيون اسان ڏسون ٿا هڪ پوائنٽر هڪ ڊيٽا بلاڪ ڏانهن 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 مخصوص سائيز جي ڊيٽا بلاڪ سان ڪرائون سائيز واريٻيو دليل - پريو لائبريري جي هن نسخي ۾ استعمال نه ڪيو ويو آهي. اهو صفر رهڻ گهرجي. فنڪشن جي آپريشن دوران، ميموري کي نئين پيغام جي جوڙجڪ لاء مختص ڪيو ويندو ۽ فنڪشن کي سڏيو ويندو 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*)); 

فنڪشن، پيغام ٺاهڻ ۽ ڊيٽا بلاڪ جي جوڙجڪ کان پوء، ان جي اشارن کي ايڊريس تي ڊيٽا ڏانهن ترتيب ڏيندو. خوشبو. اهي. انهي صورت ۾، ڊيٽا بفر ڊيٽا بلاڪ جي هيڊر فيلڊ کان پوء واقع نه آهي، جيئن اهو معاملو هو جڏهن فنڪشن سان ڊيٽا بلاڪ ٺاهي. 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 null) ۽ هن پيغام لاءِ فنڪشن کي ڪال ڪندو ضميمو ().

توھان ڳولھي سگھوٿا ڊيٽا جي سائيز کي پيغام ۾ يا ٽپل ۾ فنڪشن استعمال ڪندي:

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 ڊيٽا بلاڪ جي حوالن جي ڳڻپ کي حساب ۾ ورتو وڃي ٿو، جيڪڏهن، ڪال ڪرڻ وقت آزاد() اهو صفر ٿي ويو، پوء ڊيٽا بفر مثال سان گڏ ختم ٿي ويو آهي 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);

ٽوپل جا عناصر فنڪشن طرفان نقل ڪيا ويا آهن ڪاپي بي ().

پيغام جي هڪ آسان ڪاپي ٺاهيو 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);

قطار قطار_t

ميڊيا اسٽريمر ۾ پيغام جي قطار هڪ سرڪلر ٻيڻو ڳنڍيل فهرست جي طور تي لاڳو ڪيو ويو آهي. هر لسٽ عنصر تي مشتمل آهي هڪ پوائنٽر هڪ ڊيٽا بلاڪ ڏانهن سگنل نموني سان. اهو ظاهر ٿئي ٿو ته صرف ڊيٽا بلاڪ ڏانهن اشارو ڦيرايو وڃي ٿو، جڏهن ته ڊيٽا پاڻ کي متحرڪ رهي ٿو. اهي. صرف انهن سان ڳنڍيل آهن.
ساخت جو بيان قطار قطار_t، هيٺ ڏيکاريل آهي:

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.

Mediastreamer2 VoIP انجڻ جي ڳولا. حصو 11

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

اسان هن ساخت کي هڪ سگنل لنڪ سڏينداسين. هر ميڊيا اسٽريمر فلٽر ان پٽ لنڪس جي ٽيبل ۽ آئوٽ پٽ لنڪس جي ٽيبل تي مشتمل آهي (ايم ايس قطار). فلٽر ٺاهڻ وقت جدولن جي سائيز مقرر ڪئي وئي آهي؛ اسان اڳ ۾ ئي اهو ڪيو آهي قسم جي برآمد ٿيل متغير استعمال ڪندي MSFilterDesc، جڏهن اسان پنهنجو فلٽر ٺاهيو. هيٺ ڏنل هڪ ڍانچي آهي جيڪا بيان ڪري ٿي ڪنهن به فلٽر کي ميڊيا اسٽريمر ۾، ايم ايس فلٽر:


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;

اسان جي منصوبي مطابق C پروگرام ۾ فلٽرن کي ڳنڍڻ کان پوءِ (پر ٽِڪر کي ڳنڍيو نه ويو)، اسان ان طرح هڪ هدايت وارو گراف ٺاهيو، جنهن جا نوڊس ڍانچي جا مثال آهن. ايم ايس فلٽر، ۽ ڪنڊا لنڪ جا مثال آهن ايم ايس قطار.

پردي جي پويان ٽڪر جي سرگرمين

جڏهن مون توهان کي ٻڌايو ته ٽِڪر ٽِڪن جي ماخذ لاءِ هڪ فلٽر آهي، اهو ان بابت مڪمل سچ نه هو. ٽِڪر هڪ اعتراض آهي جيڪو ڪلاڪ تي ڪم ڪندو آهي عمل () سرڪٽ جا سڀئي فلٽر (گراف) جنهن سان اهو ڳنڍيل آهي. جڏهن اسان هڪ ٽڪر کي سي پروگرام ۾ گراف فلٽر سان ڳنڍيندا آهيون، اسان ٽڪر کي گراف ڏيکاريندا آهيون ته اهو هن وقت کان ڪنٽرول ڪندو جيستائين اسان ان کي بند نه ڪريون. ڳنڍڻ کان پوء، ٽڪر ان جي سنڀال جي حوالي سان گراف کي جانچڻ شروع ڪري ٿو، فلٽرن جي هڪ فهرست مرتب ڪندي جنهن ۾ شامل آهي. ساڳئي فلٽر کي ٻه ڀيرا ”ڳڻڻ“ نه ڏيڻ لاءِ، اهو نشان لڳل فلٽرن کي نشان لڳائي ٿو انهن ۾ چيڪ باڪس رکي ڏٺو. ڳولها ڪئي وئي آهي ڪڙي جدولن کي استعمال ڪندي جيڪا هر فلٽر وٽ آهي.

گراف جي ان جي تعارفي دوري دوران، ٽِڪر چيڪ ڪري ٿو ته فلٽرن ۾ گھٽ ۾ گھٽ ھڪڙو آھي جيڪو ڊيٽا بلاڪ جي ماخذ طور ڪم ڪري ٿو. جيڪڏهن ڪو به نه آهي، پوء گراف کي غلط سمجهيو ويندو آهي ۽ ٽڪر حادثو.

جيڪڏهن گراف نڪرندو آهي "درست"، هر فلٽر لاء، فنڪشن کي شروعات لاء سڏيو ويندو آهي. اڳڀرائي (). جيئن ئي لمحو ايندڙ پروسيسنگ چڪر لاءِ پهچندو آهي (هر 10 مليس سيڪنڊن ۾ ڊفالٽ)، ٽڪر فنڪشن کي سڏيندو آهي عمل () سڀ کان پهريان مليل ماخذ فلٽرن لاءِ، ۽ پوءِ لسٽ ۾ باقي فلٽرن لاءِ. جيڪڏهن فلٽر ان پٽ لنڪس آهن، پوء فنڪشن کي هلائڻ عمل () ورجائي ٿو جيستائين ان پٽ لنڪ جون قطارون خالي نه ٿين. ان کان پوء، اهو لسٽ ۾ ايندڙ فلٽر ڏانهن هلندو آهي ۽ ان کي "اسڪرول" ڪندو جيستائين ان پٽ لنڪس پيغامن کان خالي نه آهن. ٽڪر فلٽر کان فلٽر تائين هلندو آهي جيستائين لسٽ ختم ٿئي. هي چڪر جي پروسيسنگ کي مڪمل ڪري ٿو.

هاڻي اسان ٽوپلز ڏانهن واپس ڪنداسين ۽ انهي بابت ڳالهائينداسين ڇو ته اهڙي اداري کي ميڊيا اسٽريمر ۾ شامل ڪيو ويو. عام طور تي، فلٽر اندر ڪم ڪندڙ الورورٿم طرفان گهربل ڊيٽا جو مقدار هڪجهڙائي نٿو رکي ۽ ان پٽ تي حاصل ڪيل ڊيٽا بفرن جي سائيز جو هڪ کان وڌيڪ نه آهي. مثال طور، اسان هڪ فلٽر لکي رهيا آهيون جيڪو هڪ تيز فوريئر ٽرانسفارم کي انجام ڏئي ٿو، جيڪو تعريف سان صرف ڊيٽا بلاڪ کي پروسيس ڪري سگهي ٿو جن جي سائيز ٻن جي طاقت آهي. اچو ته ان کي 512 شمار ڪيو وڃي. جيڪڏهن ڊيٽا هڪ ٽيليفون چينل ذريعي ٺاهي وئي آهي، پوء هر پيغام جي ڊيٽا بفر ان پٽ تي اسان کي 160 سگنل نموني آڻيندو. اهو ان پٽ مان ڊيٽا گڏ نه ڪرڻ جي ڪوشش ڪري رهيو آهي جيستائين ڊيٽا جي گهربل مقدار موجود ناهي. پر انهي صورت ۾، ٽڪر سان ٽڪر ٿيندو، جيڪو فلٽر کي اسڪرول ڪرڻ جي ناڪام ڪوشش ڪندو جيستائين ان پٽ لنڪ خالي نه آهي. اڳي، اسان هن قاعدي کي فلٽر جي ٽئين اصول طور نامزد ڪيو. هن اصول جي مطابق، فلٽر جي عمل () فنڪشن کي ان پٽ قطارن مان سڀ ڊيٽا وٺڻ گهرجي.

ان کان علاوه، ان پٽ مان صرف 512 نمونن وٺڻ ممڪن نه ٿيندو، ڇو ته توھان صرف مڪمل بلاڪ وٺي سگھو ٿا، يعني. فلٽر کي 640 نمونا وٺڻا پوندا ۽ انهن مان 512 استعمال ڪرڻا پوندا، باقي ڊيٽا جو نئون حصو گڏ ڪرڻ کان اڳ. اهڙيء طرح، اسان جي فلٽر، ان جي مکيه ڪم کان علاوه، ان پٽ ڊيٽا جي وچولي اسٽوريج لاء معاون ڪارناما مهيا ڪرڻ گهرجن. ميڊيا اسٽريمر جي ڊولپرز ۽ هن عام مسئلي جي حل لاء هڪ خاص اعتراض ٺاهيا آهن - MSBufferizer (بفرر)، جيڪو هن مسئلي کي حل ڪري ٿو tuples استعمال ڪندي.

بفرائزر (MSBufferizer)

هي هڪ اعتراض آهي جيڪو فلٽر اندر ان پٽ ڊيٽا گڏ ڪندو ۽ ان کي پروسيسنگ لاءِ جمع ڪرڻ شروع ڪندو جيئن ئي معلومات جو مقدار فلٽر الگورٿم کي هلائڻ لاءِ ڪافي هوندو. جڏهن بفر ڊيٽا گڏ ڪري رهيو آهي، فلٽر پروسيسر جي پروسيسنگ پاور کي استعمال ڪرڻ کان سواء، بيڪار موڊ ۾ ڪم ڪندو. پر جيئن ئي بفرر کان پڙهڻ وارو فعل صفر کان سواءِ ٻي قيمت ڏي ٿو، فلٽر جو عمل () فنڪشن شروع ٿئي ٿو ۽ بفرر کان ڊيٽا کي گهربل سائيز جي حصن ۾ وٺڻ ۽ پروسيس ڪرڻ شروع ڪري، جيستائين اهو ختم نه ٿئي.
ڊيٽا جيڪا اڃا گهربل نه آهي اها بفر ۾ رهي ٿي ٽپل جي پهرين عنصر جي طور تي، جنهن ۾ ان پٽ ڊيٽا جا ايندڙ بلاڪ ڳنڍيل آهن.

اها جوڙجڪ جيڪا بفر کي بيان ڪري ٿي:

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

MSBufferizer سان ڪم ڪرڻ لاءِ ڪم

ھڪڙو نئون بفر مثال ٺاھيو:

MSBufferizer * ms_bufferizer_new(void);

ياداشت مختص ڪئي وئي آهي، شروعات ۾ ms_buffeizer_init() ۽ هڪ اشارو واپس ڪيو ويندو.

شروعاتي فنڪشن:

void ms_bufferizer_init(MSBufferizer *obj); 

قطار جي شروعات ٿي رهي آهي q، ميدان ڪرائون سائيز واري صفر تي مقرر ڪيو ويو آهي.

پيغام شامل ڪرڻ:

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

ميسيج ايم کي قطار ۾ شامل ڪيو ويو آهي. ڊيٽا بلاڪ جي حساب سان سائيز شامل ڪئي وئي آهي ڪرائون سائيز واري.

سڀني پيغامن کي لنڪ ڊيٽا جي قطار مان بفر ڏانهن منتقل ڪرڻ q:

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

هڪ لنڪ مان پيغامن جي منتقلي q بفر ۾ فنڪشن استعمال ڪندي ڪيو ويندو آهي ms_buffeizer_put().

بفر مان پڙهڻ:

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

جيڪڏهن بفر ۾ گڏ ڪيل ڊيٽا جي ماپ درخواست ڪيل هڪ کان گهٽ آهي (ڊيٽالن)، پوء فنڪشن واپسي صفر، ڊيٽا کي نقل نه ڪيو ويو آهي ڊيٽا ڏانهن. ٻي صورت ۾، بفر ۾ واقع tuples مان ڊيٽا جي ترتيب وار نقل ڪئي وئي آهي. ڪاپي ڪرڻ کان پوء، ٽوپل ختم ٿي ويو آهي ۽ ميموري آزاد ٿي وئي آهي. نقل ڪرڻ وقت ختم ٿي ويندو آهي جڏهن ڊيٽالين بائيٽس ڪاپي ڪيا ويندا آهن. جيڪڏهن ڊيٽا بلاڪ جي وچ ۾ خلا ختم ٿي وڃي، ته پوء هن پيغام ۾، ڊيٽا بلاڪ کي گهٽجي ويندو باقي اڻ ڪاپي ٿيل حصو تائين. ايندڙ وقت توهان کي سڏيندو، نقل هن نقطي کان جاري رهندو.

ڊيٽا جو مقدار پڙهڻ جيڪو هن وقت بفر ۾ موجود آهي:

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

تبصرو شامل ڪريو