Mediastreamer2 VoIP انجن کی تلاش۔ حصہ 11

مضمون کا مواد میری تحریر سے لیا گیا ہے۔ زین چینل.

Mediastreamer2 VoIP انجن کی تلاش۔ حصہ 11

ڈیٹا کی نقل و حرکت کا طریقہ کار

  • ڈیٹا بلاک dblk_t
  • پیغام mblk_t
  • پیغامات کے ساتھ کام کرنے کے افعال mblk_t
  • قطار قطار_t
  • queues queue_t کے ساتھ کام کرنے کے افعال
  • کنیکٹنگ فلٹرز
  • ڈیٹا پروسیسنگ گراف کا سگنل پوائنٹ
  • پردے کے پیچھے ٹکر کی سرگرمیاں
  • بفرائزر (MSBufferizer)
  • MSBufferizer کے ساتھ کام کرنے کے افعال

ماضی میں آرٹیکل ہم نے اپنا فلٹر تیار کیا ہے۔ یہ مضمون میڈیا اسٹریمر فلٹرز کے درمیان ڈیٹا کو منتقل کرنے کے اندرونی طریقہ کار پر توجہ مرکوز کرے گا۔ یہ آپ کو مستقبل میں کم محنت کے ساتھ جدید ترین فلٹرز لکھنے کی اجازت دے گا۔

ڈیٹا کی نقل و حرکت کا طریقہ کار

میڈیا اسٹریمر میں ڈیٹا کی نقل و حرکت ڈھانچے کے ذریعہ بیان کردہ قطاروں کا استعمال کرتے ہوئے کی جاتی ہے۔ قطار_ٹی. جیسے پیغامات کے تار mblk_t، جو خود سگنل ڈیٹا پر مشتمل نہیں ہے، لیکن صرف پچھلے، اگلے پیغام اور ڈیٹا بلاک کے لنکس ہیں۔ اس کے علاوہ، میں خاص طور پر اس بات پر زور دینا چاہتا ہوں کہ ایک ہی قسم کے پیغام کے لنک کے لیے ایک فیلڈ بھی موجود ہے، جو آپ کو پیغامات کی واحد لنک کردہ فہرست کو ترتیب دینے کی اجازت دیتا ہے۔ ہم اس طرح کی فہرست کے ذریعے متحد پیغامات کے ایک گروپ کو ٹوپل کہیں گے۔ اس طرح، قطار کا کوئی بھی عنصر ایک پیغام ہو سکتا ہے۔ mblk_t، اور شاید ایک میسج ٹیپل کا سر 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_اگلا، جو دوہری منسلک فہرست کو منظم کرنے کے لئے ضروری ہیں (جو ایک قطار ہے۔ قطار_ٹی).

پھر پوائنٹر آتا ہے۔ 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 مخصوص سائز کے ڈیٹا بلاک کے ساتھ سائزدوسری دلیل - انعام لائبریری کے اس ورژن میں استعمال نہیں کیا گیا۔ اسے صفر ہی رہنا چاہیے۔ فنکشن کے آپریشن کے دوران، نئے پیغام کی ساخت کے لیے میموری مختص کی جائے گی اور فنکشن کو کال کیا جائے گا۔ 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*)); 

فنکشن، میسج اور ڈیٹا بلاک کی ساخت بنانے کے بعد، اپنے پوائنٹرز کو ایڈریس پر موجود ڈیٹا کے لیے ترتیب دے گا۔ BF. وہ. اس صورت میں، ڈیٹا بفر ڈیٹا بلاک کے ہیڈر فیلڈز کے بعد واقع نہیں ہوتا، جیسا کہ فنکشن کے ساتھ ڈیٹا بلاک بنانے کے وقت ہوا تھا۔ datab_alloc(). فنکشن میں پاس کیے گئے ڈیٹا کے ساتھ بفر وہیں رہے گا جہاں وہ تھا، لیکن پوائنٹرز کی مدد سے اسے ڈیٹا بلاک کے نئے بنائے گئے ہیڈر کے ساتھ منسلک کر دیا جائے گا، اور اس کے مطابق، پیغام کے ساتھ۔

ایک پیغام کے لیے mblk_t کئی ڈیٹا بلاکس کو ترتیب وار جوڑا جا سکتا ہے۔ یہ فنکشن کے ذریعہ کیا جاتا ہے:

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

mp - ایک پیغام جس میں ایک اور ڈیٹا بلاک شامل کیا جائے گا۔
اعداد و شمار - بلاک کی طرف اشارہ، جس کی ایک کاپی پیغام میں شامل کی جائے گی۔
سائز - ڈیٹا کا سائز؛
پیڈ - ایک جھنڈا جس کے لیے مختص میموری کا سائز 4 بائٹ باؤنڈری کے ساتھ منسلک ہونا چاہیے (پیڈنگ صفر کے ساتھ کی جائے گی)۔

اگر موجودہ میسج ڈیٹا بفر میں کافی جگہ ہے تو نیا ڈیٹا پہلے سے موجود ڈیٹا کے پیچھے چسپاں کر دیا جائے گا۔ اگر میسج ڈیٹا بفر میں خالی جگہ کم ہے۔ سائز، پھر کافی بفر سائز کے ساتھ ایک نیا پیغام بنایا جاتا ہے اور ڈیٹا کو اس کے بفر میں کاپی کیا جاتا ہے۔ یہ ایک نیا پیغام ہے، جو پوائنٹر کا استعمال کرتے ہوئے اصل پیغام سے منسلک ہے۔ b_cont. اس صورت میں، پیغام ایک tuple میں بدل جاتا ہے.

اگر آپ کو ٹوپل میں ڈیٹا کا ایک اور بلاک شامل کرنے کی ضرورت ہے، تو آپ کو فنکشن استعمال کرنے کی ضرورت ہے:

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 اگر کال کرتے وقت ڈیٹا بلاک کے حوالہ شمار کو مدنظر رکھا جاتا ہے۔ 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);

ٹیپل کے عناصر فنکشن کے ذریعہ کاپی کیے جاتے ہیں۔ کاپی بی ().

پیغام کی ایک آسان کاپی بنائیں 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_stopper *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_stopper (اس کے بعد ہم اسے "سٹاپر" کہیں گے) فنکشن کے ذریعہ شروع کیا جاتا ہے۔ 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) میسج کی طرف null پوائنٹر کے ساتھ، فنکشن لوپ ہو جاتا ہے۔ آپ کا پروگرام منجمد ہو جائے گا۔ اسی طرح برتاؤ کرتا ہے ms_queue_next(q, m).

کنیکٹنگ فلٹرز

اوپر بیان کردہ قطار ایک فلٹر سے دوسرے یا ایک سے کئی فلٹرز تک پیغامات کو منتقل کرنے کے لیے استعمال ہوتی ہے۔ فلٹرز اور ان کے کنکشن ایک ہدایت شدہ گراف بناتے ہیں۔ فلٹر کے ان پٹ یا آؤٹ پٹ کو عام لفظ "پن" کہا جائے گا۔ اس ترتیب کو بیان کرنے کے لیے جس میں فلٹرز ایک دوسرے سے جڑے ہوئے ہیں، میڈیا اسٹریمر "سگنل پوائنٹ" کا تصور استعمال کرتا ہے۔ سگنل پوائنٹ ساخت ہے۔ _MSCPpoint، جس میں فلٹر کا ایک پوائنٹر اور اس کے پنوں میں سے ایک کا نمبر ہوتا ہے؛ اس کے مطابق، یہ فلٹر کے ان پٹ یا آؤٹ پٹس میں سے کسی ایک کے کنکشن کو بیان کرتا ہے۔

ڈیٹا پروسیسنگ گراف کا سگنل پوائنٹ

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

فلٹر پنوں کو صفر سے شروع کرکے نمبر دیا جاتا ہے۔

ایک پیغام کی قطار کے ذریعہ دو پنوں کے کنکشن کو ساخت کے ذریعہ بیان کیا گیا ہے۔ _MS قطار، جس میں ایک پیغام کی قطار ہے اور دو سگنل پوائنٹس کی طرف اشارہ کرتا ہے جو اسے جوڑتا ہے:

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

ہم اس ڈھانچے کو سگنل لنک کہیں گے۔ ہر میڈیا اسٹریمر فلٹر میں ان پٹ لنکس کا ایک ٹیبل اور آؤٹ پٹ لنکس کا ایک ٹیبل ہوتا ہے (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;

سی پروگرام میں فلٹرز کو اپنے پلان کے مطابق جوڑنے کے بعد (لیکن ٹکر کو نہیں جوڑا)، ہم نے اس طرح ایک ڈائریکٹڈ گراف بنایا، جس کے نوڈس ساخت کی مثالیں ہیں۔ ایم ایس فلٹر، اور کنارے لنکس کی مثالیں ہیں۔ MSQueue.

پردے کے پیچھے ٹکر کی سرگرمیاں

جب میں نے آپ کو بتایا کہ ٹکر ٹِکس کے ماخذ کے لیے ایک فلٹر ہے، تو یہ اس کے بارے میں پوری سچائی نہیں تھی۔ ٹکر ایک ایسی چیز ہے جو گھڑی پر کام کرتی ہے۔ عمل() سرکٹ کے تمام فلٹرز (گراف) جس سے یہ جڑا ہوا ہے۔ جب ہم کسی ٹکر کو کسی 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); 

پیغام 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); 

اگر بفر میں جمع کردہ ڈیٹا کا سائز درخواست کردہ سے کم ہے (ڈیٹالین)، پھر فنکشن صفر لوٹاتا ہے، ڈیٹا کو ڈیٹا میں کاپی نہیں کیا جاتا ہے۔ بصورت دیگر، بفر میں واقع ٹوپلس سے ڈیٹا کی ترتیب وار کاپی کی جاتی ہے۔ کاپی کرنے کے بعد، ٹیپل کو حذف کر دیا جاتا ہے اور میموری کو آزاد کر دیا جاتا ہے. کاپی کرنا اس وقت ختم ہو جاتا ہے جب ڈیٹالین بائٹس کو کاپی کیا جاتا ہے۔ اگر ڈیٹا بلاک کے بیچ میں جگہ ختم ہو جاتی ہے، تو اس پیغام میں، ڈیٹا بلاک کو کم کر کے بقیہ غیر کاپی شدہ حصے تک پہنچا دیا جائے گا۔ اگلی بار جب آپ کال کریں گے تو اس مقام سے نقل جاری رہے گی۔

ڈیٹا کی مقدار کو پڑھنا جو فی الحال بفر میں دستیاب ہے:

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

نیا تبصرہ شامل کریں