12024
|
1 /*
|
|
2 The mediastreamer library aims at providing modular media processing and I/O
|
|
3 for linphone, but also for any telephony application.
|
|
4 Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
|
|
5
|
|
6 This library is free software; you can redistribute it and/or
|
|
7 modify it under the terms of the GNU Lesser General Public
|
|
8 License as published by the Free Software Foundation; either
|
|
9 version 2.1 of the License, or (at your option) any later version.
|
|
10
|
|
11 This library is distributed in the hope that it will be useful,
|
|
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
14 Lesser General Public License for more details.
|
|
15
|
|
16 You should have received a copy of the GNU Lesser General Public
|
|
17 License along with this library; if not, write to the Free Software
|
|
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
19 */
|
|
20
|
|
21
|
|
22 #include <errno.h>
|
|
23 #include "msfilter.h"
|
|
24
|
|
25
|
|
26
|
|
27 void ms_filter_init(MSFilter *filter)
|
|
28 {
|
|
29 filter->finputs=0;
|
|
30 filter->foutputs=0;
|
|
31 filter->qinputs=0;
|
|
32 filter->qoutputs=0;
|
|
33 filter->infifos=NULL;
|
|
34 filter->outfifos=NULL;
|
|
35 filter->inqueues=NULL;
|
|
36 filter->outqueues=NULL;
|
|
37 filter->lock=g_mutex_new();
|
|
38 filter->min_fifo_size=0x7fff;
|
|
39 filter->notify_event=NULL;
|
|
40 filter->userdata=NULL;
|
|
41 }
|
|
42
|
|
43 void ms_filter_uninit(MSFilter *filter)
|
|
44 {
|
|
45 g_mutex_free(filter->lock);
|
|
46 }
|
|
47
|
|
48 void ms_filter_class_init(MSFilterClass *filterclass)
|
|
49 {
|
|
50 filterclass->name=NULL;
|
|
51 filterclass->max_finputs=0;
|
|
52 filterclass->max_foutputs=0;
|
|
53 filterclass->max_qinputs=0;
|
|
54 filterclass->max_qoutputs=0;
|
|
55 filterclass->r_maxgran=0;
|
|
56 filterclass->w_maxgran=0;
|
|
57 filterclass->r_offset=0;
|
|
58 filterclass->w_offset=0;
|
|
59 filterclass->set_property=NULL;
|
|
60 filterclass->get_property=NULL;
|
|
61 filterclass->setup=NULL;
|
|
62 filterclass->unsetup=NULL;
|
|
63 filterclass->process=NULL;
|
|
64 filterclass->destroy=NULL;
|
|
65 filterclass->attributes=0;
|
|
66 filterclass->ref_count=0;
|
|
67 }
|
|
68
|
|
69 /* find output queue */
|
|
70 gint find_oq(MSFilter *m1,MSQueue *oq)
|
|
71 {
|
|
72 gint i;
|
|
73
|
|
74 for (i=0;i<MS_FILTER_GET_CLASS(m1)->max_qoutputs;i++){
|
|
75 if (m1->outqueues[i]==oq) return i;
|
|
76 }
|
|
77
|
|
78 return -1;
|
|
79 }
|
|
80
|
|
81 /* find input queue */
|
|
82 gint find_iq(MSFilter *m1,MSQueue *iq)
|
|
83 {
|
|
84 gint i;
|
|
85 for (i=0;i<MS_FILTER_GET_CLASS(m1)->max_qinputs;i++){
|
|
86 if (m1->inqueues[i]==iq) return i;
|
|
87 }
|
|
88 return -1;
|
|
89 }
|
|
90
|
|
91 /* find output fifo */
|
|
92 gint find_of(MSFilter *m1,MSFifo *of)
|
|
93 {
|
|
94 gint i;
|
|
95 for (i=0;i<MS_FILTER_GET_CLASS(m1)->max_foutputs;i++){
|
|
96 if (m1->outfifos[i]==of) return i;
|
|
97 }
|
|
98
|
|
99 return -1;
|
|
100 }
|
|
101
|
|
102 /* find input fifo */
|
|
103 gint find_if(MSFilter *m1,MSFifo *inf)
|
|
104 {
|
|
105 gint i;
|
|
106
|
|
107 for (i=0;i<MS_FILTER_GET_CLASS(m1)->max_finputs;i++){
|
|
108 if (m1->infifos[i]==inf) return i;
|
|
109 }
|
|
110
|
|
111 return -1;
|
|
112 }
|
|
113
|
|
114 #define find_free_iq(_m1) find_iq(_m1,NULL)
|
|
115 #define find_free_oq(_m1) find_oq(_m1,NULL)
|
|
116 #define find_free_if(_m1) find_if(_m1,NULL)
|
|
117 #define find_free_of(_m1) find_of(_m1,NULL)
|
|
118
|
|
119 int ms_filter_add_link(MSFilter *m1, MSFilter *m2)
|
|
120 {
|
|
121 gint m1_q=-1;
|
|
122 gint m1_f=-1;
|
|
123 gint m2_q=-1;
|
|
124 gint m2_f=-1;
|
|
125 /* determine the type of link we can add */
|
|
126 m1_q=find_free_oq(m1);
|
|
127 m1_f=find_free_of(m1);
|
|
128 m2_q=find_free_iq(m2);
|
|
129 m2_f=find_free_if(m2);
|
|
130 if ((m1_q!=-1) && (m2_q!=-1)){
|
|
131 /* link with queues */
|
|
132 ms_trace("m1_q=%i , m2_q=%i",m1_q,m2_q);
|
|
133 return ms_filter_link(m1,m1_q,m2,m2_q,LINK_QUEUE);
|
|
134 }
|
|
135 if ((m1_f!=-1) && (m2_f!=-1)){
|
|
136 /* link with queues */
|
|
137 ms_trace("m1_f=%i , m2_f=%i",m1_f,m2_f);
|
|
138 return ms_filter_link(m1,m1_f,m2,m2_f,LINK_FIFO);
|
|
139 }
|
|
140 g_warning("ms_filter_add_link: could not link.");
|
|
141 return -1;
|
|
142 }
|
|
143 /**
|
|
144 * ms_filter_link:
|
|
145 * @m1: A #MSFilter object.
|
|
146 * @pin1: The pin number on @m1.
|
|
147 * @m2: A #MSFilter object.
|
|
148 * @pin2: The pin number on @m2.
|
|
149 * @linktype: Type of connection, it may be #LINK_QUEUE, #LINK_FIFOS.
|
|
150 *
|
|
151 * This function links two MSFilter object between them. It must be used to make chains of filters.
|
|
152 * All data outgoing from pin1 of m1 will go to the input pin2 of m2.
|
|
153 * The way to communicate can be fifos or queues, depending of the nature of the filters. Filters can have
|
|
154 * multiple queue pins and multiple fifo pins, but most of them have only one queue input/output or only one
|
|
155 * fifo input/output. Fifos are usally used by filters doing audio processing, while queues are used by filters doing
|
|
156 * video processing.
|
|
157 *
|
|
158 * Returns: 0 if successfull, a negative value reprensenting the errno.h error.
|
|
159 */
|
|
160 int ms_filter_link(MSFilter *m1, gint pin1, MSFilter *m2,gint pin2, int linktype)
|
|
161 {
|
|
162 MSQueue *q;
|
|
163 MSFifo *fifo;
|
|
164
|
|
165 g_message("ms_filter_add_link: %s,%i -> %s,%i",m1->klass->name,pin1,m2->klass->name,pin2);
|
|
166 switch(linktype)
|
|
167 {
|
|
168 case LINK_QUEUE:
|
|
169 /* Are filter m1 and m2 able to accept more queues connections ?*/
|
|
170 g_return_val_if_fail(m1->qoutputs<MS_FILTER_GET_CLASS(m1)->max_qoutputs,-EMLINK);
|
|
171 g_return_val_if_fail(m2->qinputs<MS_FILTER_GET_CLASS(m2)->max_qinputs,-EMLINK);
|
|
172 /* Are filter m1 and m2 valid with their inputs and outputs ?*/
|
|
173 g_return_val_if_fail(m1->outqueues!=NULL,-EFAULT);
|
|
174 g_return_val_if_fail(m2->inqueues!=NULL,-EFAULT);
|
|
175 /* are the requested pins exists ?*/
|
|
176 g_return_val_if_fail(pin1<MS_FILTER_GET_CLASS(m1)->max_qoutputs,-EINVAL);
|
|
177 g_return_val_if_fail(pin2<MS_FILTER_GET_CLASS(m2)->max_qinputs,-EINVAL);
|
|
178 /* are the requested pins free ?*/
|
|
179 g_return_val_if_fail(m1->outqueues[pin1]==NULL,-EBUSY);
|
|
180 g_return_val_if_fail(m2->inqueues[pin2]==NULL,-EBUSY);
|
|
181
|
|
182 q=ms_queue_new();
|
|
183 m1->outqueues[pin1]=m2->inqueues[pin2]=q;
|
|
184 m1->qoutputs++;
|
|
185 m2->qinputs++;
|
|
186 q->prev_data=(void*)m1;
|
|
187 q->next_data=(void*)m2;
|
|
188 break;
|
|
189 case LINK_FIFO:
|
|
190 /* Are filter m1 and m2 able to accept more fifo connections ?*/
|
|
191 g_return_val_if_fail(m1->foutputs<MS_FILTER_GET_CLASS(m1)->max_foutputs,-EMLINK);
|
|
192 g_return_val_if_fail(m2->finputs<MS_FILTER_GET_CLASS(m2)->max_finputs,-EMLINK);
|
|
193 /* Are filter m1 and m2 valid with their inputs and outputs ?*/
|
|
194 g_return_val_if_fail(m1->outfifos!=NULL,-EFAULT);
|
|
195 g_return_val_if_fail(m2->infifos!=NULL,-EFAULT);
|
|
196 /* are the requested pins exists ?*/
|
|
197 g_return_val_if_fail(pin1<MS_FILTER_GET_CLASS(m1)->max_foutputs,-EINVAL);
|
|
198 g_return_val_if_fail(pin2<MS_FILTER_GET_CLASS(m2)->max_finputs,-EINVAL);
|
|
199 /* are the requested pins free ?*/
|
|
200 g_return_val_if_fail(m1->outfifos[pin1]==NULL,-EBUSY);
|
|
201 g_return_val_if_fail(m2->infifos[pin2]==NULL,-EBUSY);
|
|
202
|
|
203 if (MS_FILTER_GET_CLASS(m1)->attributes & FILTER_IS_SOURCE)
|
|
204 {
|
|
205 /* configure min_fifo_size */
|
|
206 fifo=ms_fifo_new_with_buffer(MS_FILTER_GET_CLASS(m2)->r_maxgran,
|
|
207 MS_FILTER_GET_CLASS(m1)->w_maxgran,
|
|
208 MS_FILTER_GET_CLASS(m2)->r_offset,
|
|
209 MS_FILTER_GET_CLASS(m1)->w_offset,
|
|
210 MS_FILTER_GET_CLASS(m1)->w_maxgran);
|
|
211 m2->min_fifo_size=MS_FILTER_GET_CLASS(m1)->w_maxgran;
|
|
212 }
|
|
213 else
|
|
214 {
|
|
215 gint next_size;
|
|
216 ms_trace("ms_filter_add_link: min_fifo_size=%i",m1->min_fifo_size);
|
|
217 fifo=ms_fifo_new_with_buffer(MS_FILTER_GET_CLASS(m2)->r_maxgran,
|
|
218 MS_FILTER_GET_CLASS(m1)->w_maxgran,
|
|
219 MS_FILTER_GET_CLASS(m2)->r_offset,
|
|
220 MS_FILTER_GET_CLASS(m1)->w_offset,
|
|
221 m1->min_fifo_size);
|
|
222 if (MS_FILTER_GET_CLASS(m2)->r_maxgran>0){
|
|
223 next_size=(m1->min_fifo_size*
|
|
224 (MS_FILTER_GET_CLASS(m2)->w_maxgran)) /
|
|
225 (MS_FILTER_GET_CLASS(m2)->r_maxgran);
|
|
226 }else next_size=m1->min_fifo_size;
|
|
227 ms_trace("ms_filter_add_link: next_size=%i",next_size);
|
|
228 m2->min_fifo_size=next_size;
|
|
229 }
|
|
230
|
|
231
|
|
232 m1->outfifos[pin1]=m2->infifos[pin2]=fifo;
|
|
233 m1->foutputs++;
|
|
234 m2->finputs++;
|
|
235 fifo->prev_data=(void*)m1;
|
|
236 fifo->next_data=(void*)m2;
|
|
237 break;
|
|
238 }
|
|
239 return 0;
|
|
240 }
|
|
241 /**
|
|
242 * ms_filter_unlink:
|
|
243 * @m1: A #MSFilter object.
|
|
244 * @pin1: The pin number on @m1.
|
|
245 * @m2: A #MSFilter object.
|
|
246 * @pin2: The pin number on @m2.
|
|
247 * @linktype: Type of connection, it may be #LINK_QUEUE, #LINK_FIFOS.
|
|
248 *
|
|
249 * Unlink @pin1 of filter @m1 from @pin2 of filter @m2. @linktype specifies what type of connection is removed.
|
|
250 *
|
|
251 * Returns: 0 if successfull, a negative value reprensenting the errno.h error.
|
|
252 */
|
|
253 int ms_filter_unlink(MSFilter *m1, gint pin1, MSFilter *m2,gint pin2,gint linktype)
|
|
254 {
|
|
255 switch(linktype)
|
|
256 {
|
|
257 case LINK_QUEUE:
|
|
258 /* Are filter m1 and m2 valid with their inputs and outputs ?*/
|
|
259 g_return_val_if_fail(m1->outqueues!=NULL,-EFAULT);
|
|
260 g_return_val_if_fail(m2->inqueues!=NULL,-EFAULT);
|
|
261 /* are the requested pins exists ?*/
|
|
262 g_return_val_if_fail(pin1<MS_FILTER_GET_CLASS(m1)->max_qoutputs,-EINVAL);
|
|
263 g_return_val_if_fail(pin2<MS_FILTER_GET_CLASS(m2)->max_qinputs,-EINVAL);
|
|
264 /* are the requested pins busy ?*/
|
|
265 g_return_val_if_fail(m1->outqueues[pin1]!=NULL,-ENOENT);
|
|
266 g_return_val_if_fail(m2->inqueues[pin2]!=NULL,-ENOENT);
|
|
267 /* are the two pins connected together ?*/
|
|
268 g_return_val_if_fail(m1->outqueues[pin1]==m2->inqueues[pin2],-EINVAL);
|
|
269
|
|
270 ms_queue_destroy(m1->outqueues[pin1]);
|
|
271 m1->outqueues[pin1]=m2->inqueues[pin2]=NULL;
|
|
272 m1->qoutputs--;
|
|
273 m2->qinputs--;
|
|
274
|
|
275 break;
|
|
276 case LINK_FIFO:
|
|
277 /* Are filter m1 and m2 valid with their inputs and outputs ?*/
|
|
278 g_return_val_if_fail(m1->outfifos!=NULL,-EFAULT);
|
|
279 g_return_val_if_fail(m2->infifos!=NULL,-EFAULT);
|
|
280 /* are the requested pins exists ?*/
|
|
281 g_return_val_if_fail(pin1<MS_FILTER_GET_CLASS(m1)->max_foutputs,-EINVAL);
|
|
282 g_return_val_if_fail(pin2<MS_FILTER_GET_CLASS(m2)->max_finputs,-EINVAL);
|
|
283 /* are the requested pins busy ?*/
|
|
284 g_return_val_if_fail(m1->outfifos[pin1]!=NULL,-ENOENT);
|
|
285 g_return_val_if_fail(m2->infifos[pin2]!=NULL,-ENOENT);
|
|
286 /* are the two pins connected together ?*/
|
|
287 g_return_val_if_fail(m1->outfifos[pin1]==m2->infifos[pin2],-EINVAL);
|
|
288 ms_fifo_destroy_with_buffer(m1->outfifos[pin1]);
|
|
289 m1->outfifos[pin1]=m2->infifos[pin2]=NULL;
|
|
290 m1->foutputs--;
|
|
291 m2->finputs--;
|
|
292 break;
|
|
293 }
|
|
294 return 0;
|
|
295 }
|
|
296
|
|
297 /**
|
|
298 *ms_filter_remove_links:
|
|
299 *@m1: a filter
|
|
300 *@m2: another filter.
|
|
301 *
|
|
302 * Removes all links between m1 and m2.
|
|
303 *
|
|
304 *Returns: 0 if one more link have been removed, -1 if not.
|
|
305 **/
|
|
306 gint ms_filter_remove_links(MSFilter *m1, MSFilter *m2)
|
|
307 {
|
|
308 int i,j;
|
|
309 int removed=-1;
|
|
310 MSQueue *qo;
|
|
311 MSFifo *fo;
|
|
312 /* takes all outputs of m1, and removes the one that goes to m2 */
|
|
313 if (m1->outqueues!=NULL){
|
|
314 for (i=0;i<MS_FILTER_GET_CLASS(m1)->max_qoutputs;i++)
|
|
315 {
|
|
316 qo=m1->outqueues[i];
|
|
317 if (qo!=NULL){
|
|
318 MSFilter *rmf;
|
|
319 /* test if the queue connects to m2 */
|
|
320 rmf=(MSFilter*)qo->next_data;
|
|
321 if (rmf==m2){
|
|
322 j=find_iq(rmf,qo);
|
|
323 if (j==-1) g_error("Could not find input queue: impossible case.");
|
|
324 ms_filter_unlink(m1,i,m2,j,LINK_QUEUE);
|
|
325 removed=0;
|
|
326 }
|
|
327 }
|
|
328 }
|
|
329 }
|
|
330 if (m1->outfifos!=NULL){
|
|
331 for (i=0;i<MS_FILTER_GET_CLASS(m1)->max_foutputs;i++)
|
|
332 {
|
|
333 fo=m1->outfifos[i];
|
|
334 if (fo!=NULL){
|
|
335 MSFilter *rmf;
|
|
336 /* test if the queue connects to m2 */
|
|
337 rmf=(MSFilter*)fo->next_data;
|
|
338 if (rmf==m2){
|
|
339 j=find_if(rmf,fo);
|
|
340 if (j==-1) g_error("Could not find input fifo: impossible case.");
|
|
341 ms_filter_unlink(m1,i,m2,j,LINK_FIFO);
|
|
342 removed=0;
|
|
343 }
|
|
344 }
|
|
345 }
|
|
346 }
|
|
347 return removed;
|
|
348 }
|
|
349
|
|
350 /**
|
|
351 * ms_filter_fifos_have_data:
|
|
352 * @f: a #MSFilter object.
|
|
353 *
|
|
354 * Tells if the filter has enough data in its input fifos in order to be executed succesfully.
|
|
355 *
|
|
356 * Returns: 1 if it can be executed, 0 else.
|
|
357 */
|
|
358 gint ms_filter_fifos_have_data(MSFilter *f)
|
|
359 {
|
|
360 gint i,j;
|
|
361 gint max_inputs=f->klass->max_finputs;
|
|
362 gint con_inputs=f->finputs;
|
|
363 MSFifo *fifo;
|
|
364 /* test fifos */
|
|
365 for(i=0,j=0; (i<max_inputs) && (j<con_inputs);i++)
|
|
366 {
|
|
367 fifo=f->infifos[i];
|
|
368 if (fifo!=NULL)
|
|
369 {
|
|
370 j++;
|
|
371 if (fifo->readsize==0) return 0;
|
|
372 if (fifo->readsize>=f->r_mingran) return 1;
|
|
373 }
|
|
374 }
|
|
375 return 0;
|
|
376 }
|
|
377
|
|
378 /**
|
|
379 * ms_filter_queues_have_data:
|
|
380 * @f: a #MSFilter object.
|
|
381 *
|
|
382 * Tells if the filter has enough data in its input queues in order to be executed succesfully.
|
|
383 *
|
|
384 * Returns: 1 if it can be executed, 0 else.
|
|
385 */
|
|
386 gint ms_filter_queues_have_data(MSFilter *f)
|
|
387 {
|
|
388 gint i,j;
|
|
389 gint max_inputs=f->klass->max_qinputs;
|
|
390 gint con_inputs=f->qinputs;
|
|
391 MSQueue *q;
|
|
392 /* test queues */
|
|
393 for(i=0,j=0; (i<max_inputs) && (j<con_inputs);i++)
|
|
394 {
|
|
395 q=f->inqueues[i];
|
|
396 if (q!=NULL)
|
|
397 {
|
|
398 j++;
|
|
399 if (ms_queue_can_get(q)) return 1;
|
|
400 }
|
|
401 }
|
|
402 return 0;
|
|
403 }
|
|
404
|
|
405
|
|
406
|
|
407 void ms_filter_destroy(MSFilter *f)
|
|
408 {
|
|
409 /* first check if the filter is disconnected from any others */
|
|
410 g_return_if_fail(f->finputs==0);
|
|
411 g_return_if_fail(f->foutputs==0);
|
|
412 g_return_if_fail(f->qinputs==0);
|
|
413 g_return_if_fail(f->qoutputs==0);
|
|
414 f->klass->destroy(f);
|
|
415 }
|
|
416
|
|
417 GList *filter_list=NULL;
|
|
418
|
|
419 void ms_filter_register(MSFilterInfo *info)
|
|
420 {
|
|
421 gpointer tmp;
|
|
422 tmp=g_list_find(filter_list,info);
|
|
423 if (tmp==NULL) filter_list=g_list_append(filter_list,(gpointer)info);
|
|
424 }
|
|
425
|
|
426 void ms_filter_unregister(MSFilterInfo *info)
|
|
427 {
|
|
428 filter_list=g_list_remove(filter_list,(gpointer)info);
|
|
429 }
|
|
430
|
|
431 static gint compare_names(gpointer info, gpointer name)
|
|
432 {
|
|
433 MSFilterInfo *i=(MSFilterInfo*) info;
|
|
434 return (strcmp(i->name,name));
|
|
435 }
|
|
436
|
|
437 MSFilterInfo * ms_filter_get_by_name(const gchar *name)
|
|
438 {
|
|
439 GList *elem=g_list_find_custom(filter_list,
|
|
440 (gpointer)name,(GCompareFunc)compare_names);
|
|
441 if (elem!=NULL){
|
|
442 return (MSFilterInfo*)elem->data;
|
|
443 }
|
|
444 return NULL;
|
|
445 }
|
|
446
|
|
447
|
|
448
|
|
449 MSFilter * ms_filter_new_with_name(const gchar *name)
|
|
450 {
|
|
451 MSFilterInfo *info=ms_filter_get_by_name(name);
|
|
452 if (info!=NULL) return info->constructor();
|
|
453 g_warning("ms_filter_new_with_name: no filter named %s found.",name);
|
|
454 return NULL;
|
|
455 }
|
|
456
|
|
457
|
|
458 /* find the first codec in the left part of the stream */
|
|
459 MSFilter * ms_filter_search_upstream_by_type(MSFilter *f,MSFilterType type)
|
|
460 {
|
|
461 MSFilter *tmp=f;
|
|
462 MSFilterInfo *info;
|
|
463
|
|
464 if ((tmp->infifos!=NULL) && (tmp->infifos[0]!=NULL)){
|
|
465 tmp=(MSFilter*) tmp->infifos[0]->prev_data;
|
|
466 while(1){
|
|
467 info=MS_FILTER_GET_CLASS(tmp)->info;
|
|
468 if (info!=NULL){
|
|
469 if ( (info->type==type) ){
|
|
470 return tmp;
|
|
471 }
|
|
472 }
|
|
473 if ((tmp->infifos!=NULL) && (tmp->infifos[0]!=NULL))
|
|
474 tmp=(MSFilter*) tmp->infifos[0]->prev_data;
|
|
475 else break;
|
|
476 }
|
|
477 }
|
|
478 tmp=f;
|
|
479 if ((tmp->inqueues!=NULL) && (tmp->inqueues[0]!=NULL)){
|
|
480 tmp=(MSFilter*) tmp->inqueues[0]->prev_data;
|
|
481 while(1){
|
|
482
|
|
483 info=MS_FILTER_GET_CLASS(tmp)->info;
|
|
484 if (info!=NULL){
|
|
485 if ( (info->type==type)){
|
|
486 return tmp;
|
|
487 }
|
|
488 }else g_warning("ms_filter_search_upstream_by_type: filter %s has no info."
|
|
489 ,MS_FILTER_GET_CLASS(tmp)->name);
|
|
490 if ((tmp->inqueues!=NULL) && (tmp->inqueues[0]!=NULL))
|
|
491 tmp=(MSFilter*) tmp->inqueues[0]->prev_data;
|
|
492 else break;
|
|
493 }
|
|
494 }
|
|
495 return NULL;
|
|
496 }
|
|
497
|
|
498
|
|
499 int ms_filter_set_property(MSFilter *f, MSFilterProperty prop,void *value)
|
|
500 {
|
|
501 if (f->klass->set_property!=NULL){
|
|
502 return f->klass->set_property(f,prop,value);
|
|
503 }
|
|
504 return 0;
|
|
505 }
|
|
506
|
|
507 int ms_filter_get_property(MSFilter *f, MSFilterProperty prop,void *value)
|
|
508 {
|
|
509 if (f->klass->get_property!=NULL){
|
|
510 return f->klass->get_property(f,prop,value);
|
|
511 }
|
|
512 return -1;
|
|
513 }
|
|
514
|
|
515 void ms_filter_set_notify_func(MSFilter* filter,MSFilterNotifyFunc func, gpointer userdata)
|
|
516 {
|
|
517 filter->notify_event=func;
|
|
518 filter->userdata=userdata;
|
|
519 }
|
|
520
|
|
521 void ms_filter_notify_event(MSFilter *filter,gint event, gpointer arg)
|
|
522 {
|
|
523 if (filter->notify_event!=NULL){
|
|
524 filter->notify_event(filter,event,arg,filter->userdata);
|
|
525 }
|
|
526 }
|
|
527
|
|
528 void swap_buffer(gchar *buffer, gint len)
|
|
529 {
|
|
530 int i;
|
|
531 gchar tmp;
|
|
532 for (i=0;i<len;i+=2){
|
|
533 tmp=buffer[i];
|
|
534 buffer[i]=buffer[i+1];
|
|
535 buffer[i+1]=tmp;
|
|
536 }
|
|
537 }
|