Mediastreamer2 वीओआईपी इंजन की खोज। भाग ---- पहला

लेख की सामग्री मेरे से ली गई है ज़ेन चैनल.

Mediastreamer2 वीओआईपी इंजन की खोज। भाग ---- पहला

डेटा संचलन तंत्र

  • डेटा ब्लॉक dblk_t
  • संदेश mblk_t
  • संदेशों के साथ काम करने के लिए फ़ंक्शन mblk_t
  • कतार कतार_t
  • क्यू के साथ काम करने के लिए फ़ंक्शन क्यू_टी
  • फ़िल्टर कनेक्ट करना
  • डेटा प्रोसेसिंग ग्राफ़ का सिग्नल बिंदु
  • टिकर की परदे के पीछे की गतिविधियाँ
  • बफ़राइज़र (एमएसबफ़राइज़र)
  • 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_next, जो एक दोगुनी लिंक्ड सूची (जो एक कतार है) को व्यवस्थित करने के लिए आवश्यक हैं क्यू_टी).

फिर सूचक आता है b_cont, जिसका उपयोग केवल तभी किया जाता है जब संदेश टुपल का हिस्सा हो। टुपल में अंतिम संदेश के लिए, यह सूचक शून्य रहता है।

आगे हम डेटा ब्लॉक के लिए एक पॉइंटर देखते हैं b_datap, जिसके लिए संदेश मौजूद है। इसके बाद ब्लॉक डेटा बफ़र के अंदर के क्षेत्र के संकेतक आते हैं। मैदान b_rptr वह स्थान निर्दिष्ट करता है जहां से बफ़र से डेटा पढ़ा जाएगा। मैदान b_wptr उस स्थान को इंगित करता है जहां से बफ़र पर लिखा जाएगा।

शेष फ़ील्ड सेवा प्रकृति के हैं और डेटा ट्रांसफर तंत्र के संचालन से संबंधित नहीं हैं।

नीचे नाम के साथ एक संदेश है m1 और डेटा ब्लॉक d1.
Mediastreamer2 वीओआईपी इंजन की खोज। भाग ---- पहला
निम्नलिखित चित्र तीन संदेशों का एक समूह दिखाता है m1, एम1_1, एम1_2.
Mediastreamer2 वीओआईपी इंजन की खोज। भाग ---- पहला

संदेश भेजने के कार्य 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*)); 

फ़ंक्शन, संदेश और डेटा ब्लॉक की संरचना बनाने के बाद, पते पर डेटा के लिए अपने पॉइंटर्स को कॉन्फ़िगर करेगा 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 कॉल करते समय डेटा ब्लॉक की संदर्भ गणना को ध्यान में रखा जाता है फ्रीब() यह शून्य हो जाता है, फिर डेटा बफ़र उदाहरण के साथ हटा दिया जाता है 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_स्टॉपर *mblk_t टाइप करें, यह कतार में पहले तत्व (संदेश) को इंगित करता है। संरचना का दूसरा क्षेत्र कतार में संदेशों का काउंटर है।
नीचे दिया गया चित्र q1 नाम की एक कतार दिखाता है जिसमें 4 संदेश m1, m2, m3, m4 हैं।
Mediastreamer2 वीओआईपी इंजन की खोज। भाग ---- पहला
निम्नलिखित चित्र q1 नाम की एक कतार दिखाता है जिसमें 4 संदेश m1,m2,m3,m4 हैं। संदेश m2 एक टुपल का प्रमुख है जिसमें दो और संदेश m2_1 और m2_2 हैं।

Mediastreamer2 वीओआईपी इंजन की खोज। भाग ---- पहला

क्यू के साथ काम करने के लिए फ़ंक्शन क्यू_टी

कतार आरंभीकरण:

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 तत्व से पहले डाला गया रोजगार। अगर रोजगार=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).

फ़िल्टर कनेक्ट करना

ऊपर वर्णित कतार का उपयोग संदेशों को एक फ़िल्टर से दूसरे फ़िल्टर या एक से कई फ़िल्टर में भेजने के लिए किया जाता है। फ़िल्टर और उनके कनेक्शन एक निर्देशित ग्राफ़ बनाते हैं। फ़िल्टर के इनपुट या आउटपुट को सामान्य शब्द "पिन" कहा जाएगा। उस क्रम का वर्णन करने के लिए जिसमें फ़िल्टर एक दूसरे से जुड़े हुए हैं, मीडिया स्ट्रीमर "सिग्नल बिंदु" की अवधारणा का उपयोग करता है। संकेत बिंदु संरचना है _एमएससीप्वाइंट, जिसमें फ़िल्टर के लिए एक सूचक और उसके एक पिन की संख्या होती है; तदनुसार, यह फ़िल्टर के किसी एक इनपुट या आउटपुट के कनेक्शन का वर्णन करता है।

डेटा प्रोसेसिंग ग्राफ़ का सिग्नल बिंदु

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

फ़िल्टर पिनों को शून्य से प्रारंभ करके क्रमांकित किया जाता है।

संदेश कतार द्वारा दो पिनों का कनेक्शन संरचना द्वारा वर्णित है _एमएसक्यू, जिसमें एक संदेश कतार और इससे जुड़ने वाले दो सिग्नल बिंदुओं के संकेतक शामिल हैं:

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

इस संरचना को हम सिग्नल लिंक कहेंगे। प्रत्येक मीडिया स्ट्रीमर फ़िल्टर में इनपुट लिंक की एक तालिका और आउटपुट लिंक की एक तालिका होती है (MSQueue). फ़िल्टर बनाते समय तालिकाओं का आकार निर्धारित किया जाता है; हमने पहले से ही निर्यात किए गए प्रकार के चर का उपयोग करके ऐसा किया है एमएसफ़िल्टरडेस्क, जब हमने अपना स्वयं का फ़िल्टर विकसित किया। नीचे एक संरचना है जो मीडिया स्ट्रीमर में किसी भी फ़िल्टर का वर्णन करती है, एमएसफ़िल्टर:


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 (बफरर), जो टुपल्स का उपयोग करके इस समस्या को हल करता है।

बफ़राइज़र (एमएसबफ़राइज़र)

यह एक ऑब्जेक्ट है जो फ़िल्टर के अंदर इनपुट डेटा जमा करेगा और फ़िल्टर एल्गोरिदम को चलाने के लिए जानकारी की मात्रा पर्याप्त होते ही इसे प्रसंस्करण के लिए सबमिट करना शुरू कर देगा। जबकि बफ़र डेटा जमा कर रहा है, फ़िल्टर प्रोसेसर की प्रोसेसिंग पावर का उपयोग किए बिना, निष्क्रिय मोड में काम करेगा। लेकिन जैसे ही बफ़रर से रीडिंग फ़ंक्शन शून्य के अलावा कोई अन्य मान लौटाता है, फ़िल्टर का प्रोसेस () फ़ंक्शन बफ़रर से आवश्यक आकार के भागों में डेटा लेना और संसाधित करना शुरू कर देता है, जब तक कि यह समाप्त न हो जाए।
जिस डेटा की अभी आवश्यकता नहीं है वह टपल के पहले तत्व के रूप में बफर में रहता है, जिससे इनपुट डेटा के बाद के ब्लॉक जुड़े होते हैं।

वह संरचना जो बफ़र का वर्णन करती है:

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 फ़िल्टर में, जो नमूनों में बाइट्स को नेटवर्क ऑर्डर से होस्ट ऑर्डर तक पुनर्व्यवस्थित करता है: एल16.सी

अगले लेख में, हम टिकर लोड अनुमान के मुद्दे और मीडिया स्ट्रीमर में अत्यधिक कंप्यूटिंग लोड से कैसे निपटें, इस पर गौर करेंगे।

स्रोत: www.habr.com

एक टिप्पणी जोड़ें