1 /*
2 * GPAC - Multimedia Framework C SDK
3 *
4 * Authors: Jean Le Feuvre
5 * Copyright (c) Telecom ParisTech 2017-2018
6 * All rights reserved
7 *
8 * This file is part of GPAC / unit test filters
9 *
10 * GPAC is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Lesser General Public License as published by
12 * the Free Software Foundation; either version 2, or (at your option)
13 * any later version.
14 *
15 * GPAC is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; see the file COPYING. If not, write to
22 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 */
25
26 #include <gpac/filters.h>
27 #include <gpac/list.h>
28
29 typedef struct
30 {
31 GF_FilterPid *src_pid;
32 GF_FilterPid *dst_pid;
33 GF_SHA1Context *sha_ctx;
34 u32 nb_packets, pck_del;
35
36 GF_FilterFrameInterface frame_ifce;
37 u8 ifce_data[10];
38 } PIDCtx;
39
40 enum
41 {
42 UTF_MODE_SOURCE=0,
43 UTF_MODE_SINK,
44 UTF_MODE_FILTER,
45 };
46 typedef struct
47 {
48 GF_List *pids;
49
50 //0: source, 1: sink, 2: filter
51 u32 mode;
52 u32 max_pck;
53 s32 max_out;
54 const char *pid_att;
55 Bool alloc;
56 u32 nb_pids;
57 u32 fwd;
58 u32 framing;
59 Bool cov;
60 Bool norecfg;
61 const char *update;
62
63 Bool gsftest;
64 GF_Fraction64 dummy1;
65 } GF_UnitTestFilter;
66
test_pck_del(GF_Filter * filter,GF_FilterPid * pid,GF_FilterPacket * pck)67 static void test_pck_del(GF_Filter *filter, GF_FilterPid *pid, GF_FilterPacket *pck)
68 {
69 PIDCtx *stack = (PIDCtx *) gf_filter_pid_get_udta(pid);
70 stack->pck_del++;
71 assert(stack->nb_packets >= stack->pck_del);
72 GF_LOG(GF_LOG_DEBUG, GF_LOG_APP, ("%s: Packet deleted - %d out there (%d sent %d destroyed)\n", gf_filter_get_name(filter), stack->nb_packets - stack->pck_del, stack->nb_packets, stack->pck_del));
73 }
74
75
dump_properties(GF_FilterPacket * pck,u32 nb_pck)76 void dump_properties(GF_FilterPacket *pck, u32 nb_pck)
77 {
78 u32 idx = 0;
79 while (1) {
80 u32 p4cc;
81 const char *pname;
82 const GF_PropertyValue *p = gf_filter_pck_enum_properties(pck, &idx, &p4cc, &pname);
83 if (!p) break;
84 //dump_property(pck, nb_pck, p4cc, pname, p);
85 }
86 if (nb_pck==1) {
87 gf_filter_pck_get_property(pck, GF_4CC('c','u','s','t'));
88 gf_filter_pck_get_property_str(pck, "custom");
89 }
90 }
91
ut_filter_finalize(GF_Filter * filter)92 static void ut_filter_finalize(GF_Filter *filter)
93 {
94 u32 i, count;
95 u8 digest[GF_SHA1_DIGEST_SIZE];
96 GF_UnitTestFilter *stack = (GF_UnitTestFilter *) gf_filter_get_udta(filter);
97
98 count = gf_list_count(stack->pids);
99 for (i=0; i<count; i++) {
100 PIDCtx *pidctx = gf_list_get(stack->pids, i);
101 if (pidctx->sha_ctx && (stack->mode!=UTF_MODE_SOURCE) ) {
102 gf_sha1_finish(pidctx->sha_ctx, digest);
103
104 if (!pidctx->src_pid) {
105 GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("[%s] Pid %d Source PID not available while dumping SHA1\n", gf_filter_get_name(filter), i+1 ));
106 } else {
107 const GF_PropertyValue *p = gf_filter_pid_get_property(pidctx->src_pid, GF_4CC('s','h','a','1') );
108 if (!p) {
109 GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("[%s] Pid %d sha1 property not found on input pid\n", gf_filter_get_name(filter), i+1 ));
110 } else if (p->value.data.size != GF_SHA1_DIGEST_SIZE) {
111 GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("[%s] Pid %d wrong size for sha1 property\n", gf_filter_get_name(filter), i+1 ));
112 } else if (memcmp(p->value.data.ptr, digest, p->value.data.size )) {
113 GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("[%s] Pid %d wrong hash after execution\n", gf_filter_get_name(filter), i+1 ));
114 } else {
115 GF_LOG(GF_LOG_WARNING, GF_LOG_APP, ("[%s] Pid %d hash OK after execution\n", gf_filter_get_name(filter), i+1 ));
116 }
117 }
118 }
119 gf_free(pidctx);
120 }
121 gf_list_del(stack->pids);
122 }
123
ut_filter_send_update(GF_Filter * filter,u32 nb_pck)124 static void ut_filter_send_update(GF_Filter *filter, u32 nb_pck)
125 {
126 GF_UnitTestFilter *stack = (GF_UnitTestFilter *) gf_filter_get_udta(filter);
127
128 if (stack->update && (nb_pck==stack->max_pck/2) ) {
129 char *sep, *fid;
130 char *cmd = gf_strdup(stack->update);
131 fid = cmd;
132 sep = strchr(cmd, ',');
133 if (sep) {
134 char *name, *val;
135 sep[0]=0;
136 sep+=1;
137 name=sep;
138 sep = strchr(name, ',');
139 if (sep) {
140 sep[0]=0;
141 val = sep+1;
142 } else {
143 val=NULL;
144 }
145 gf_filter_send_update(filter, fid, name, val, 0);
146 }
147 gf_free(cmd);
148 }
149 }
150
151
ut_filter_process_filter(GF_Filter * filter)152 static GF_Err ut_filter_process_filter(GF_Filter *filter)
153 {
154 u32 size, i, j, count, nb_loops;
155 u32 fwd;
156 GF_FilterPacket *pck_dst;
157 GF_UnitTestFilter *stack = (GF_UnitTestFilter *) gf_filter_get_udta(filter);
158
159 count = gf_list_count(stack->pids);
160 for (i=0; i<count; i++) {
161 PIDCtx *pidctx = gf_list_get(stack->pids, i);
162 GF_FilterPacket *pck = gf_filter_pid_get_packet(pidctx->src_pid);
163 if (!pck)
164 return GF_OK;
165
166 if ((stack-> max_out>=0) && (pidctx->nb_packets - pidctx->pck_del >= (u32) stack->max_out) ) {
167 GF_LOG(GF_LOG_DEBUG, GF_LOG_APP, ("TestSource: No packets to emit, waiting for destruction\n"));
168 return GF_OK;
169 }
170 }
171
172 //loop on each PID
173 for (i=0; i<count; i++) {
174 const u8 *data;
175 u32 pck_size;
176 u8 *data_ptr;
177 PIDCtx *pidctx = gf_list_get(stack->pids, i);
178 GF_FilterPacket *pck = gf_filter_pid_get_packet(pidctx->src_pid);
179 assert (pck);
180 assert(pidctx == gf_filter_pid_get_udta(pidctx->src_pid));
181
182 data = gf_filter_pck_get_data(pck, &size);
183 gf_sha1_update(pidctx->sha_ctx, (u8*)data, size);
184
185 nb_loops = stack->framing ? 3 : 1;
186 pck_size = stack->framing ? size/nb_loops : size;
187 data_ptr = (u8 *)data;
188
189 for (j=0; j<nb_loops; j++) {
190
191 //adjust last packet size
192 if ((j+1) == nb_loops) {
193 pck_size = size - j*pck_size;
194 }
195
196 fwd = stack->fwd;
197 if (fwd==3) fwd = pidctx->nb_packets % 3;
198
199 //shared memory
200 if (fwd==0) {
201 pck_dst = gf_filter_pck_new_shared(pidctx->dst_pid, data_ptr, pck_size, test_pck_del);
202 }
203 //copy memory
204 else if (fwd==1) {
205 u8 *data_dst;
206 pck_dst = gf_filter_pck_new_alloc(pidctx->dst_pid, pck_size, &data_dst);
207 if (pck_dst) {
208 memcpy(data_dst, data_ptr, pck_size);
209 }
210 }
211 //packet reference
212 else {
213 if (stack->framing) {
214 pck_dst = gf_filter_pck_new_ref(pidctx->dst_pid, data_ptr, pck_size, pck);
215 } else {
216 pck_dst = gf_filter_pck_new_ref(pidctx->dst_pid, NULL, 0, pck);
217 }
218 }
219
220
221 if (pck_dst) {
222 Bool is_start, is_end;
223 //get source packet framing
224 gf_filter_pck_get_framing(pck, &is_start, &is_end);
225 //adjust flags given our framing
226 if (is_start && j) is_start = GF_FALSE;
227 if (is_end && (j+1 < nb_loops) ) is_end = GF_FALSE;
228 if (stack->framing==2) is_start = GF_FALSE;
229 if (stack->framing==3) is_end = GF_FALSE;
230
231 gf_filter_pck_set_framing(pck_dst, is_start, is_end);
232
233 pidctx->nb_packets++;
234 //copy over src props to dst
235 gf_filter_pck_merge_properties(pck, pck_dst);
236 gf_filter_pck_send(pck_dst);
237 }
238 //move our data pointer
239 data_ptr += pck_size;
240
241 } //end framing loop
242
243 gf_filter_pid_drop_packet(pidctx->src_pid);
244
245 } //end PID loop
246
247 return GF_OK;
248
249 }
250
ut_source_pck_del(GF_Filter * filter,GF_FilterPid * pid,GF_FilterPacket * pck)251 static void ut_source_pck_del(GF_Filter *filter, GF_FilterPid *pid, GF_FilterPacket *pck)
252 {
253
254 }
255
ut_source_ifce_get_plane(struct _gf_filter_frame_interface * frame,u32 plane_idx,const u8 ** outPlane,u32 * outStride)256 static GF_Err ut_source_ifce_get_plane(struct _gf_filter_frame_interface *frame, u32 plane_idx, const u8 **outPlane, u32 *outStride)
257 {
258 PIDCtx *pctx = frame->user_data;
259 memset(pctx->ifce_data, 0, 10);
260 if (plane_idx) return GF_BAD_PARAM;
261 *outPlane = pctx->ifce_data;
262 *outStride = 5;
263 return GF_OK;
264 }
265
ut_filter_process_source(GF_Filter * filter)266 static GF_Err ut_filter_process_source(GF_Filter *filter)
267 {
268 GF_PropertyValue p;
269 GF_FilterPacket *pck;
270 u32 i, count, nb_eos;
271 GF_UnitTestFilter *stack = (GF_UnitTestFilter *) gf_filter_get_udta(filter);
272
273 nb_eos = 0;
274 count = gf_list_count(stack->pids);
275 for (i=0; i<count; i++) {
276 PIDCtx *pidctx=gf_list_get(stack->pids, i);
277
278 if (pidctx->nb_packets==stack->max_pck) {
279 if (stack->gsftest && pidctx->dst_pid) {
280 gf_filter_pid_remove(pidctx->dst_pid);
281 pidctx->dst_pid = NULL;
282 }
283 nb_eos++;
284 continue;
285 }
286
287 if ((stack->max_out>=0) && (pidctx->nb_packets - pidctx->pck_del >= (u32) stack->max_out) ) {
288 GF_LOG(GF_LOG_DEBUG, GF_LOG_APP, ("TestSource: No packets to emit, waiting for destruction\n"));
289 continue;
290 }
291 pidctx->nb_packets++;
292
293 if (stack->gsftest && pidctx->nb_packets==4) {
294 pidctx->frame_ifce.get_plane = ut_source_ifce_get_plane;
295 pidctx->frame_ifce.user_data = pidctx;
296 pck = gf_filter_pck_new_frame_interface(pidctx->dst_pid, &pidctx->frame_ifce, ut_source_pck_del);
297 } else if (stack->alloc) {
298 u8 *data;
299 pck = gf_filter_pck_new_alloc(pidctx->dst_pid, 10, &data);
300 memcpy(data, "PacketCopy", 10);
301 gf_sha1_update(pidctx->sha_ctx, "PacketCopy", 10);
302 } else {
303 pck = gf_filter_pck_new_shared(pidctx->dst_pid, "PacketShared", 12, test_pck_del);
304 gf_sha1_update(pidctx->sha_ctx, "PacketShared", 12);
305 }
306 GF_LOG(GF_LOG_DEBUG, GF_LOG_APP, ("TestSource: pck %d PacketShared\n", pidctx->nb_packets));
307
308 gf_filter_pck_set_cts(pck, pidctx->nb_packets);
309
310 p.type = GF_PROP_NAME;
311 p.value.string = "custom_value";
312 gf_filter_pck_set_property(pck, GF_4CC('c','u','s','t'), &p);
313
314 //try all our properties
315 if (pidctx->nb_packets==1) {
316 u32 val=1;
317 gf_filter_pck_set_property(pck, GF_4CC('c','u','s','1'), &PROP_BOOL(GF_TRUE) );
318 gf_filter_pck_set_property(pck, GF_4CC('c','u','s','2'), &PROP_SINT(-1));
319 gf_filter_pck_set_property(pck, GF_4CC('c','u','s','3'), &PROP_UINT(1));
320 gf_filter_pck_set_property(pck, GF_4CC('c','u','s','4'), &PROP_LONGSINT(-1));
321 gf_filter_pck_set_property(pck, GF_4CC('c','u','s','5'), &PROP_LONGUINT(1));
322 gf_filter_pck_set_property(pck, GF_4CC('c','u','s','6'), &PROP_FLOAT(1.0f));
323 gf_filter_pck_set_property(pck, GF_4CC('c','u','s','7'), &PROP_DOUBLE(1.0));
324 gf_filter_pck_set_property(pck, GF_4CC('c','u','s','8'), &PROP_FRAC_INT(1,1));
325 gf_filter_pck_set_property(pck, GF_4CC('c','u','s','8'), &PROP_FRAC64_INT(1,1));
326 gf_filter_pck_set_property(pck, GF_4CC('c','u','s','9'), &PROP_POINTER(pck));
327
328 if (stack->gsftest) {
329 gf_filter_pck_set_property(pck, GF_4CC('c','u','s','a'), &PROP_DATA(pidctx->ifce_data, 8));
330 gf_filter_pck_set_property(pck, GF_4CC('c','u','s','b'), &PROP_CONST_DATA(pidctx->ifce_data, 8));
331 } else {
332 gf_filter_pck_set_property(pck, GF_4CC('c','u','s','a'), &PROP_DATA((char *) pidctx, sizeof(pidctx)));
333 gf_filter_pck_set_property(pck, GF_4CC('c','u','s','b'), &PROP_CONST_DATA((char *) pidctx, sizeof(pidctx)));
334 }
335 gf_filter_pck_set_property(pck, GF_4CC('c','u','s','c'), &PROP_STRING("custom"));
336 gf_filter_pck_set_property(pck, GF_4CC('c','u','s','d'), &PROP_STRING("custom"));
337 memset(&p, 0, sizeof(GF_PropertyValue));
338 p.type = GF_PROP_VEC2;
339 gf_filter_pck_set_property(pck, GF_4CC('c','u','s','e'), &p);
340 p.type = GF_PROP_VEC2I;
341 gf_filter_pck_set_property(pck, GF_4CC('c','u','s','f'), &p);
342 p.type = GF_PROP_VEC3;
343 gf_filter_pck_set_property(pck, GF_4CC('c','u','s','g'), &p);
344 p.type = GF_PROP_VEC3I;
345 gf_filter_pck_set_property(pck, GF_4CC('c','u','s','h'), &p);
346 p.type = GF_PROP_VEC4;
347 gf_filter_pck_set_property(pck, GF_4CC('c','u','s','i'), &p);
348 p.type = GF_PROP_VEC4I;
349 gf_filter_pck_set_property(pck, GF_4CC('c','u','s','j'), &p);
350 p.type = GF_PROP_STRING_LIST;
351 p.value.string_list = gf_list_new();
352 gf_list_add(p.value.string_list, gf_strdup("custom"));
353 gf_filter_pck_set_property(pck, GF_4CC('c','u','s','k'), &p);
354 p.value.string_list = NULL;
355 p.type = GF_PROP_UINT_LIST;
356 p.value.uint_list.nb_items = 1;
357 p.value.uint_list.vals = &val;
358 gf_filter_pck_set_property(pck, GF_4CC('c','u','s','l'), &p);
359
360 gf_filter_pck_set_property_str(pck, "cusd", &PROP_BOOL(GF_TRUE) );
361 gf_filter_pck_set_property_dyn(pck, "cuse", &PROP_BOOL(GF_TRUE) );
362 }
363 if (stack->gsftest) {
364 gf_filter_pck_set_dts(pck, pidctx->nb_packets-1);
365 gf_filter_pck_set_cts(pck, pidctx->nb_packets-1);
366 gf_filter_pck_set_duration(pck, 1);
367 if (pidctx->nb_packets==2) {
368 gf_filter_pck_set_seek_flag(pck, GF_TRUE);
369 gf_filter_pck_set_carousel_version(pck, 1);
370 gf_filter_pck_set_interlaced(pck, GF_TRUE);
371 gf_filter_pck_set_sap(pck, GF_FILTER_SAP_3);
372 gf_filter_pck_set_dependency_flags(pck, 0xFF);
373 gf_filter_pck_set_property(pck, GF_PROP_PCK_SENDER_NTP, &PROP_LONGUINT(0) );
374 }
375 else if (pidctx->nb_packets==3) {
376 gf_filter_pck_set_sap(pck, GF_FILTER_SAP_4);
377 gf_filter_pck_set_roll_info(pck, 1);
378 gf_filter_pck_set_byte_offset(pck, 20);
379 }
380 }
381
382 ut_filter_send_update(filter, pidctx->nb_packets);
383
384 if (pidctx->nb_packets==stack->max_pck) {
385 if (pidctx->sha_ctx) {
386 u8 digest[GF_SHA1_DIGEST_SIZE];
387 gf_sha1_finish(pidctx->sha_ctx, digest);
388 pidctx->sha_ctx = NULL;
389 p.type = GF_PROP_DATA;
390 p.value.data.size = GF_SHA1_DIGEST_SIZE;
391 p.value.data.ptr = (char *) digest;
392 //with this we test both:
393 //- SHA of send data is correct at the receiver side
394 //- property update on a PID
395 gf_filter_pid_set_property(pidctx->dst_pid, GF_4CC('s','h','a','1'), &p);
396 }
397 }
398 //just for coverage: check keeping a reference to the packet
399 gf_filter_pck_ref(& pck);
400
401 gf_filter_pck_send(pck);
402
403 //and destroy the reference
404 gf_filter_pck_unref(pck);
405
406 }
407 if (nb_eos==count) return GF_EOS;
408 return GF_OK;
409 }
410
411
ut_filter_process_sink(GF_Filter * filter)412 static GF_Err ut_filter_process_sink(GF_Filter *filter)
413 {
414 u32 size, i, count, nb_eos;
415 const char *data;
416 GF_UnitTestFilter *stack = (GF_UnitTestFilter *) gf_filter_get_udta(filter);
417
418 count = gf_list_count(stack->pids);
419 nb_eos=0;
420
421 for (i=0; i<count; i++) {
422 PIDCtx *pidctx=gf_list_get(stack->pids, i);
423
424 GF_FilterPacket *pck = gf_filter_pid_get_packet(pidctx->src_pid);
425 if (!pck) {
426 if (gf_filter_pid_is_eos(pidctx->src_pid)) nb_eos++;
427 continue;
428 }
429
430 data = gf_filter_pck_get_data(pck, &size);
431
432 if (stack->cov && !pidctx->nb_packets) {
433 GF_PropertyValue p;
434 Bool old_strict = gf_log_set_strict_error(GF_FALSE);
435 gf_filter_pck_send(pck);
436 gf_filter_pck_set_property(pck, GF_4CC('c','u','s','t'), &p);
437 gf_filter_pck_merge_properties(pck, pck);
438 gf_filter_pck_set_framing(pck, GF_TRUE, GF_FALSE);
439 gf_log_set_strict_error(old_strict);
440 }
441
442 gf_sha1_update(pidctx->sha_ctx, (u8*)data, size);
443
444 pidctx->nb_packets++;
445 GF_LOG(GF_LOG_DEBUG, GF_LOG_APP, ("TestSink: Consuming packet %d bytes\n", size));
446
447 dump_properties(pck, pidctx->nb_packets);
448
449 gf_filter_pid_drop_packet(pidctx->src_pid);
450
451 } //end PID loop
452
453 if (nb_eos==count) return GF_EOS;
454
455 return GF_OK;
456 }
457
458
ut_filter_config_input(GF_Filter * filter,GF_FilterPid * pid,Bool is_remove)459 static GF_Err ut_filter_config_input(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
460 {
461 const GF_PropertyValue *format;
462 GF_PropertyValue p;
463 PIDCtx *pidctx;
464 u32 i, count;
465 GF_UnitTestFilter *stack = (GF_UnitTestFilter *) gf_filter_get_udta(filter);
466
467 if (stack->mode==UTF_MODE_SOURCE) {
468 GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("[UTFilter] Error: Attempt to connect PID on source filter\n"));
469 return GF_BAD_PARAM;
470 }
471 //for both filter and sink modes, check input format
472
473 count = gf_list_count(stack->pids);
474 for (i=0; i<count; i++) {
475 pidctx = gf_list_get(stack->pids, i);
476
477 //something is being reconfigured. We check we have the same custum arg, otherwise we do not support
478 if (pidctx->src_pid == pid) {
479 format = gf_filter_pid_get_property(pidctx->src_pid, GF_4CC('c','u','s','t') );
480 if (!format || !format->value.string || strcmp(format->value.string, stack->pid_att)) {
481 return GF_NOT_SUPPORTED;
482 }
483 //filter mode, set properties on output
484 if (stack->mode==UTF_MODE_FILTER) {
485 //this is not needed since copy_properties does that, used for coverage/tests
486 gf_filter_pid_reset_properties(pidctx->dst_pid);
487 gf_filter_pid_copy_properties(pidctx->dst_pid, pidctx->src_pid);
488 }
489 return GF_OK;
490 }
491 }
492
493 //check our functions
494 format = gf_filter_pid_get_property_str(pid, "custom1");
495 if (!format) {
496 GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("%s: expecting property string custom1 on PID\n", gf_filter_get_name(filter) ));
497 }
498 format = gf_filter_pid_get_property_str(pid, "custom2");
499 if (!format) {
500 GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("%s: expecting property string custom2 on PID\n", gf_filter_get_name(filter) ));
501 }
502
503 format = gf_filter_pid_get_property(pid, GF_4CC('c','u','s','t') );
504 if (!format || !format->value.string || strcmp(format->value.string, stack->pid_att)) {
505 return GF_NOT_SUPPORTED;
506 }
507
508 //new PID
509 GF_SAFEALLOC(pidctx, PIDCtx);
510 if (!pidctx) return GF_OUT_OF_MEM;
511 pidctx->src_pid = pid;
512 gf_list_add(stack->pids, pidctx);
513 assert(pidctx->src_pid);
514
515 //coverage mode
516 if (stack->cov) {
517 u8 *data;
518 Bool old_strict = gf_log_set_strict_error(GF_FALSE);
519 gf_filter_pid_set_property(pidctx->src_pid, GF_4CC('s','h','a','1'), format);
520 gf_filter_pid_reset_properties(pidctx->src_pid);
521 gf_filter_pck_new_alloc(pidctx->src_pid, 20, &data);
522 gf_filter_pck_new_shared(pidctx->src_pid, "foo", 3, NULL);
523 gf_filter_pck_new_ref(pidctx->src_pid, "foo", 3, NULL);
524 gf_log_set_strict_error(old_strict);
525 }
526
527 //filter mode, setup output
528 if (stack->mode==UTF_MODE_FILTER) {
529 pidctx->dst_pid = gf_filter_pid_new(filter);
530 p.type=GF_PROP_NAME;
531 p.value.string = (char *) stack->pid_att;
532 gf_filter_pid_copy_properties(pidctx->dst_pid, pidctx->src_pid);
533
534 if (stack->cov) {
535 Bool old_strict = gf_log_set_strict_error(GF_FALSE);
536 gf_filter_pid_copy_properties(pidctx->src_pid, pidctx->dst_pid);
537 gf_filter_pid_get_packet(pidctx->dst_pid);
538 gf_filter_pid_drop_packet(pidctx->dst_pid);
539 gf_filter_pid_drop_packet(pidctx->src_pid);
540 gf_log_set_strict_error(old_strict);
541 }
542
543 gf_filter_pid_set_property(pidctx->dst_pid, GF_4CC('c','u','s','t'), &p);
544
545 gf_filter_pid_set_udta(pidctx->dst_pid, pidctx);
546 gf_filter_pid_set_udta(pidctx->src_pid, pidctx);
547
548 gf_filter_pid_set_framing_mode(pidctx->src_pid, GF_TRUE);
549 pidctx->sha_ctx = gf_sha1_starts();
550 }
551 //sink mode, request full reconstruction of input blocks or not depending on framing mode
552 else {
553 GF_FilterEvent evt;
554 gf_filter_pid_set_framing_mode(pidctx->src_pid, stack->framing ? GF_FALSE : GF_TRUE);
555 pidctx->sha_ctx = gf_sha1_starts();
556 GF_FEVT_INIT(evt, GF_FEVT_PLAY, pid);
557 gf_filter_pid_send_event(pid, &evt);
558 }
559
560 return GF_OK;
561 }
562
563
ut_filter_config_source(GF_Filter * filter)564 static GF_Err ut_filter_config_source(GF_Filter *filter)
565 {
566 GF_PropertyValue p;
567 PIDCtx *pidctx;
568 u32 i;
569 GF_UnitTestFilter *stack = (GF_UnitTestFilter *) gf_filter_get_udta(filter);
570
571 for (i=0; i<stack->nb_pids; i++) {
572 //create a pid
573 GF_SAFEALLOC(pidctx, PIDCtx);
574 if (!pidctx) return GF_OUT_OF_MEM;
575 gf_list_add(stack->pids, pidctx);
576 pidctx->dst_pid = gf_filter_pid_new(filter);
577 gf_filter_pid_set_udta(pidctx->dst_pid, pidctx);
578
579 //set a custum property
580 p.type = GF_PROP_NAME;
581 p.value.string = (char *) stack->pid_att;
582 gf_filter_pid_set_property(pidctx->dst_pid, GF_4CC('c','u','s','t'), &p);
583
584 //for coverage
585 gf_filter_pid_set_property_str(pidctx->dst_pid, "custom1", &p);
586 gf_filter_pid_set_property_dyn(pidctx->dst_pid, "custom2", &p);
587
588 if (stack->cov) {
589 Bool old_strict = gf_log_set_strict_error(GF_FALSE);
590 gf_filter_pid_set_framing_mode(pidctx->dst_pid, GF_TRUE);
591 gf_log_set_strict_error(old_strict);
592 }
593
594 pidctx->sha_ctx = gf_sha1_starts();
595
596 if (stack->gsftest) {
597 gf_filter_pid_set_property(pidctx->dst_pid, GF_PROP_PID_STREAM_TYPE, &PROP_UINT(GF_STREAM_VISUAL) );
598 gf_filter_pid_set_property(pidctx->dst_pid, GF_PROP_PID_WIDTH, &PROP_UINT(5) );
599 gf_filter_pid_set_property(pidctx->dst_pid, GF_PROP_PID_HEIGHT, &PROP_UINT(2) );
600 gf_filter_pid_set_property(pidctx->dst_pid, GF_PROP_PID_FPS, &PROP_FRAC_INT(25,1) );
601 gf_filter_pid_set_property(pidctx->dst_pid, GF_PROP_PID_CODECID, &PROP_UINT(GF_CODECID_RAW) );
602 gf_filter_pid_set_property(pidctx->dst_pid, GF_PROP_PID_PIXFMT, &PROP_UINT(GF_PIXEL_GREYSCALE) );
603 gf_filter_pid_set_property_str(pidctx->dst_pid, "gsfdummy", &p);
604 gf_filter_pid_set_property(pidctx->dst_pid, GF_PROP_PID_TIMESCALE, &PROP_UINT(25) );
605 }
606
607 }
608 return GF_OK;
609 }
610
611
ut_filter_update_arg(GF_Filter * filter,const char * arg_name,const GF_PropertyValue * arg_val)612 static GF_Err ut_filter_update_arg(GF_Filter *filter, const char *arg_name, const GF_PropertyValue *arg_val)
613 {
614 return GF_OK;
615 }
616
utfilter_initialize(GF_Filter * filter)617 GF_Err utfilter_initialize(GF_Filter *filter)
618 {
619 GF_PropertyValue p;
620 GF_UnitTestFilter *stack = gf_filter_get_udta(filter);
621
622 stack->pids = gf_list_new();
623
624 if (stack->cov) {
625 Bool old_strict;
626 char szFmt[40];
627 s64 val;
628 u32 i;
629 GF_PropertyValue p2;
630 p = gf_props_parse_value(GF_PROP_BOOL, "prop", "true", NULL, 0);
631 if (p.value.boolean != GF_TRUE) {
632 GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("[UTFilter] Error parsing boolean value\n"));
633 }
634 p = gf_props_parse_value(GF_PROP_BOOL, "prop", "yes", NULL, 0);
635 if (p.value.boolean != GF_TRUE) {
636 GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("[UTFilter] Error parsing boolean value\n"));
637 }
638 p = gf_props_parse_value(GF_PROP_BOOL, "prop", "no", NULL, 0);
639 if (p.value.boolean != GF_FALSE) {
640 GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("[UTFilter] Error parsing boolean value\n"));
641 }
642 p = gf_props_parse_value(GF_PROP_BOOL, "prop", "false", NULL, 0);
643 if (p.value.boolean != GF_FALSE) {
644 GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("[UTFilter] Error parsing boolean value\n"));
645 }
646 p = gf_props_parse_value(GF_PROP_SINT, "prop", "-1", NULL, 0);
647 if (p.value.sint != -1) {
648 GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("[UTFilter] Error parsing sint value\n"));
649 }
650 p = gf_props_parse_value(GF_PROP_SINT, "prop", "-1k", NULL, 0);
651 if (p.value.sint != -1000) {
652 GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("[UTFilter] Error parsing sint value\n"));
653 }
654 p = gf_props_parse_value(GF_PROP_UINT, "prop", "1", NULL, 0);
655 if (p.value.uint != 1) {
656 GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("[UTFilter] Error parsing uint value\n"));
657 }
658 p = gf_props_parse_value(GF_PROP_UINT, "prop", "1m", NULL, 0);
659 if (p.value.uint != 1000000) {
660 GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("[UTFilter] Error parsing uint 1m value\n"));
661 }
662 p = gf_props_parse_value(GF_PROP_UINT, "prop", "0x10000000", NULL, 0);
663 if (p.value.uint != 0x10000000) {
664 GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("[UTFilter] Error parsing uint hex value\n"));
665 }
666 p = gf_props_parse_value(GF_PROP_UINT, "prop", "moof", NULL, 0);
667 if (p.value.uint != GF_4CC('m','o','o','f')) {
668 GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("[UTFilter] Error parsing uint 4CC value\n"));
669 }
670 val = 0xFFFFFFFF;
671 val *= 2;
672 sprintf(szFmt, ""LLD, -val);
673 p = gf_props_parse_value(GF_PROP_LSINT, "prop", szFmt, NULL, 0);
674 if (p.value.longsint != -val) {
675 GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("[UTFilter] Error parsing longsint value\n"));
676 }
677 p = gf_props_parse_value(GF_PROP_LSINT, "prop", "-1m", NULL, 0);
678 if (p.value.longsint != -1000000) {
679 GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("[UTFilter] Error parsing longsint value\n"));
680 }
681 sprintf(szFmt, ""LLU, val);
682 p = gf_props_parse_value(GF_PROP_LUINT, "prop", szFmt, NULL, 0);
683 if (p.value.longuint != val) {
684 GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("[UTFilter] Error parsing longuint value\n"));
685 }
686 p = gf_props_parse_value(GF_PROP_LUINT, "prop", "1k", NULL, 0);
687 if (p.value.longuint != 1000) {
688 GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("[UTFilter] Error parsing longuint value\n"));
689 }
690 p = gf_props_parse_value(GF_PROP_FLOAT, "prop", "1.0", NULL, 0);
691 if (p.value.fnumber != FIX_ONE) {
692 GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("[UTFilter] Error parsing float value\n"));
693 }
694 p = gf_props_parse_value(GF_PROP_DOUBLE, "prop", "1.0", NULL, 0);
695 if (p.value.number != 1.0) {
696 GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("[UTFilter] Error parsing double value\n"));
697 }
698 p = gf_props_parse_value(GF_PROP_DOUBLE, "prop", "1.0m", NULL, 0);
699 if (p.value.number != 1000000.0) {
700 GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("[UTFilter] Error parsing double value\n"));
701 }
702 p = gf_props_parse_value(GF_PROP_FRACTION, "prop", "1000/1", NULL, 0);
703 if ((p.value.frac.den != 1) || (p.value.frac.num != 1000)) {
704 GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("[UTFilter] Error parsing fraction value\n"));
705 }
706 p = gf_props_parse_value(GF_PROP_FRACTION, "prop", "1000", NULL, 0);
707 if ((p.value.frac.den != 1) || (p.value.frac.num != 1000)) {
708 GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("[UTFilter] Error parsing fraction value\n"));
709 }
710 p = gf_props_parse_value(GF_PROP_FRACTION, "prop", "1.001", NULL, 0);
711 if ((p.value.frac.den != 1000000) ) {
712 GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("[UTFilter] Error parsing fraction fp value\n"));
713 }
714 p = gf_props_parse_value(GF_PROP_STRING, "prop", "test", NULL, 0);
715 if (!p.value.string || strcmp(p.value.string, "test")) {
716 GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("[UTFilter] Error parsing fraction value\n"));
717 }
718 if (p.value.string) gf_free(p.value.string);
719
720 p = gf_props_parse_value(GF_PROP_FRACTION64, "prop", "1.001", NULL, 0);
721 if ((p.value.lfrac.den != 1000000) ) {
722 GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("[UTFilter] Error parsing fraction64 fp value\n"));
723 }
724 p = gf_props_parse_value(GF_PROP_VEC2I, "prop", "1x1", NULL, 0);
725 if ((p.value.vec2i.x != 1) || (p.value.vec2i.y != 1) ) {
726 GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("[UTFilter] Error parsing vec2i value\n"));
727 }
728 p = gf_props_parse_value(GF_PROP_VEC2, "prop", "1x1", NULL, 0);
729 if ((p.value.vec2.x != 1.0) || (p.value.vec2.y != 1.0) ) {
730 GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("[UTFilter] Error parsing vec2 value\n"));
731 }
732 p = gf_props_parse_value(GF_PROP_VEC3I, "prop", "1x1x1", NULL, 0);
733 if ((p.value.vec3i.x != 1) || (p.value.vec3i.y != 1) || (p.value.vec3i.z != 1)) {
734 GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("[UTFilter] Error parsing vec3i value\n"));
735 }
736 p = gf_props_parse_value(GF_PROP_VEC3, "prop", "1x1x1", NULL, 0);
737 if ((p.value.vec3.x != 1.0) || (p.value.vec3.y != 1.0) || (p.value.vec3.z != 1.0)) {
738 GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("[UTFilter] Error parsing vec3 value\n"));
739 }
740 p = gf_props_parse_value(GF_PROP_VEC4I, "prop", "1x1x1x1", NULL, 0);
741 if ((p.value.vec4i.x != 1) || (p.value.vec4i.y != 1) || (p.value.vec4i.z != 1) || (p.value.vec4i.w != 1)) {
742 GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("[UTFilter] Error parsing vec4i value\n"));
743 }
744 p = gf_props_parse_value(GF_PROP_VEC4, "prop", "1x1x1x1", NULL, 0);
745 if ((p.value.vec4.x != 1.0) || (p.value.vec4.y != 1.0) || (p.value.vec4.z != 1.0) || (p.value.vec4.w != 1.0)) {
746 GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("[UTFilter] Error parsing vec4 value\n"));
747 }
748 p = gf_props_parse_value(GF_PROP_PIXFMT, "prop", "rgb", NULL, 0);
749 if (p.value.uint != GF_PIXEL_RGB) {
750 GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("[UTFilter] Error parsing pixfmt value\n"));
751 }
752 p = gf_props_parse_value(GF_PROP_PCMFMT, "prop", "pcm", NULL, 0);
753 if (p.value.uint != GF_AUDIO_FMT_S16) {
754 GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("[UTFilter] Error parsing pcmfmt value\n"));
755 }
756
757 sprintf(szFmt, "%d@%p", (u32) sizeof(stack), stack);
758 p = gf_props_parse_value(GF_PROP_DATA, "prop", szFmt, NULL, 0);
759 if ((p.value.data.size != (u32) sizeof(stack)) || memcmp(p.value.data.ptr, (char *) stack, sizeof(stack))) {
760 GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("[UTFilter] Error parsing data value\n"));
761 }
762 p = gf_props_parse_value(GF_PROP_CONST_DATA, "prop", szFmt, NULL, 0);
763 if ((p.value.data.ptr != (u8 *) stack) || (p.value.data.size != (u32) sizeof(stack))) {
764 GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("[UTFilter] Error parsing data value\n"));
765 }
766 p = gf_props_parse_value(GF_PROP_CONST_DATA, "prop", "0xABCDEF", NULL, 0);
767 if (!p.value.data.ptr || (p.value.data.size != 3) || (p.value.data.ptr[0] != 0xAB) ) {
768 GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("[UTFilter] Error parsing data value\n"));
769 }
770 if (p.value.data.ptr) gf_free(p.value.data.ptr);
771
772 sprintf(szFmt, "%p", stack);
773 p = gf_props_parse_value(GF_PROP_POINTER, "prop", szFmt, NULL, 0);
774 if (p.value.ptr != stack) {
775 GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("[UTFilter] Error parsing data value\n"));
776 }
777
778 old_strict = gf_log_set_strict_error(GF_FALSE);
779 //negative tests
780 gf_props_parse_value(GF_PROP_STRING, "prop", "file@_no_exist", NULL, 0);
781 gf_props_parse_value(GF_PROP_STRING, "prop", "bxml@_no_exist", NULL, 0);
782 gf_props_parse_value(GF_PROP_DATA, "prop", "file@_no_exist", NULL, 0);
783 gf_props_parse_value(GF_PROP_DATA, "prop", "bxml@_no_exist", NULL, 0);
784 gf_props_parse_value(GF_PROP_BOOL, "prop", "", NULL, 0);
785 gf_props_parse_value(GF_PROP_SINT, "prop", "", NULL, 0);
786 gf_props_parse_value(GF_PROP_UINT, "prop", "", NULL, 0);
787 gf_props_parse_value(GF_PROP_LSINT, "prop", "", NULL, 0);
788 gf_props_parse_value(GF_PROP_LUINT, "prop", "", NULL, 0);
789 gf_props_parse_value(GF_PROP_FLOAT, "prop", "", NULL, 0);
790 gf_props_parse_value(GF_PROP_DOUBLE, "prop", "", NULL, 0);
791 gf_props_parse_value(GF_PROP_FRACTION, "prop", "", NULL, 0);
792 gf_props_parse_value(GF_PROP_FRACTION, "prop", "", NULL, 0);
793 gf_props_parse_value(GF_PROP_STRING, "prop", NULL, NULL, 0);
794 gf_props_parse_value(GF_PROP_DATA, "prop", "", NULL, 0);
795 gf_props_parse_value(GF_PROP_CONST_DATA, "prop", "", NULL, 0);
796 gf_props_parse_value(GF_PROP_POINTER, "prop", "", NULL, 0);
797 gf_props_parse_value(GF_PROP_BOOL, "prop", NULL, NULL, 0);
798 gf_props_parse_value(GF_PROP_SINT, "prop", NULL, NULL, 0);
799 gf_props_parse_value(GF_PROP_UINT, "prop", NULL, NULL, 0);
800 gf_props_parse_value(GF_PROP_LSINT, "prop", NULL, NULL, 0);
801 gf_props_parse_value(GF_PROP_LUINT, "prop", NULL, NULL, 0);
802 gf_props_parse_value(GF_PROP_FLOAT, "prop", NULL, NULL, 0);
803 gf_props_parse_value(GF_PROP_DOUBLE, "prop", NULL, NULL, 0);
804 gf_props_parse_value(GF_PROP_FRACTION, "prop", NULL, NULL, 0);
805 gf_props_parse_value(GF_PROP_FRACTION64, "prop", NULL, NULL, 0);
806 gf_props_parse_value(GF_PROP_VEC2I, "prop", NULL, NULL, 0);
807 gf_props_parse_value(GF_PROP_VEC2, "prop", NULL, NULL, 0);
808 gf_props_parse_value(GF_PROP_VEC3I, "prop", NULL, NULL, 0);
809 gf_props_parse_value(GF_PROP_VEC3, "prop", NULL, NULL, 0);
810 gf_props_parse_value(GF_PROP_VEC4I, "prop", NULL, NULL, 0);
811 gf_props_parse_value(GF_PROP_VEC4, "prop", NULL, NULL, 0);
812 gf_props_parse_value(GF_PROP_STRING, "prop", NULL, NULL, 0);
813 gf_props_parse_value(GF_PROP_DATA, "prop", NULL, NULL, 0);
814 gf_props_parse_value(GF_PROP_CONST_DATA, "prop", NULL, NULL, 0);
815 gf_props_parse_value(GF_PROP_POINTER, "prop", NULL, NULL, 0);
816 gf_props_parse_value(GF_PROP_UINT, "prop", "test", "foo|bar", 0);
817 gf_props_parse_value(100, "prop", "test", NULL, 0);
818
819 memset(&p, 0, sizeof(GF_PropertyValue));
820 p2=p;
821 for (i=GF_PROP_FORBIDEN; i<GF_PROP_LAST_DEFINED; i++) {
822 char dump[GF_PROP_DUMP_ARG_SIZE];
823 gf_props_get_type_name(i);
824 p.type = p2.type = i;
825 gf_props_equal(&p, &p2);
826 gf_props_dump_val(&p, dump, GF_FALSE, NULL);
827 }
828 p.type = GF_PROP_DATA;
829 p.value.data.size = 4;
830 p.value.data.ptr = "test";
831 p2 = p;
832 p2.value.data.ptr = NULL;
833 gf_props_equal(&p, &p2);
834 p2.value.data.size = 3;
835 p2.value.data.ptr = "test";
836 gf_props_equal(&p, &p2);
837 p2.value.data.size = 4;
838 gf_props_equal(&p, &p2);
839
840 p.type = GF_PROP_UINT_LIST;
841 i=0;
842 p.value.uint_list.nb_items=1;
843 p.value.uint_list.vals = &i;
844 p2 = p;
845 gf_props_equal(&p, &p2);
846
847
848 gf_log_set_strict_error(old_strict);
849 }
850
851 if (! strcmp( "UTSink", gf_filter_get_name(filter))) {
852 stack->mode=UTF_MODE_SINK;
853 gf_filter_set_max_extra_input_pids(filter, 10);
854 }
855 else if (! strcmp( "UTFilter", gf_filter_get_name(filter))) stack->mode=UTF_MODE_FILTER;
856 else {
857 stack->mode=UTF_MODE_SOURCE;
858 return ut_filter_config_source(filter);
859 }
860 return GF_OK;
861 }
862
863 #define OFFS(_n) #_n, offsetof(GF_UnitTestFilter, _n)
864 static const GF_FilterArgs UTFilterArgs[] =
865 {
866 { OFFS(pid_att), "set default value for PID `cust` attribute", GF_PROP_NAME, "UTSourceData", NULL, 0},
867 { OFFS(max_pck), "maximum number of packets to send in source mode", GF_PROP_UINT, "1000", NULL, 0},
868 { OFFS(nb_pids), "number of PIDs in source mode", GF_PROP_UINT, "1", "1-+I", 0},
869 { OFFS(max_out), "maximum number of shared packets not yet released in source/filter mode, no limit if -1", GF_PROP_SINT, "-1", NULL, GF_FS_ARG_UPDATE},
870 { OFFS(alloc), "use allocated memory packets in source mode", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_UPDATE},
871 { OFFS(fwd), "indicate packet forward mode for filter.\n"
872 "- shared: use shared memory (dangerous)\n"
873 "- copy: use copy\n"
874 "- ref: use references to source packet\n"
875 "- mix: change mode at each packet sent", GF_PROP_UINT, "shared", "shared|copy|ref|mix", GF_FS_ARG_UPDATE},
876 { OFFS(framing), "packet framing.\n"
877 "- none: disable packet split\n"
878 "- default: divide packets in 3 for filter mode and allows partial blocks for sink mode\n"
879 "- nostart: same as default but does not signal packet start flag\n"
880 "- noend: same as default but does not signal packet end flag"
881 "", GF_PROP_UINT, "none", "none|default|nostart|noend", GF_FS_ARG_UPDATE},
882 { OFFS(update), "send update message after half packet send. Update format is FID,argname,argval", GF_PROP_STRING, NULL, NULL, GF_FS_ARG_UPDATE},
883 { OFFS(cov), "dump options and exercise error cases for code coverage", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_UPDATE},
884 { OFFS(norecfg), "disable reconfig on input pid in filter/sink mode", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_UPDATE},
885 { OFFS(gsftest), "dispatch a fake single video pid with props and packet props for GSF testing", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_UPDATE},
886
887 { OFFS(dummy1), "dummy for coverage", GF_PROP_LSINT, "0", NULL, GF_FS_ARG_UPDATE},
888 { OFFS(dummy1), "dummy for coverage", GF_PROP_LUINT, "0", NULL, GF_FS_ARG_UPDATE},
889 { OFFS(dummy1), "dummy for coverage", GF_PROP_FLOAT, "0", NULL, GF_FS_ARG_UPDATE},
890 { OFFS(dummy1), "dummy for coverage", GF_PROP_DOUBLE, "0", NULL, GF_FS_ARG_UPDATE},
891 { OFFS(dummy1), "dummy for coverage", GF_PROP_FRACTION, "0", NULL, GF_FS_ARG_UPDATE},
892 { OFFS(dummy1), "dummy for coverage", GF_PROP_POINTER, "0", NULL, GF_FS_ARG_UPDATE},
893 { OFFS(dummy1), "dummy for coverage", GF_PROP_FRACTION64, "0", NULL, GF_FS_ARG_UPDATE},
894 { NULL }
895 };
896
897 #define UT_CAP_CODE GF_4CC('c','u','s','t')
898 static const GF_FilterCapability UTFilterCaps[] =
899 {
900 CAP_STRING(GF_CAPS_INPUT, UT_CAP_CODE, "UTSourceData"),
901 CAP_STRING(GF_CAPS_INPUT, UT_CAP_CODE, "UTFilterData"),
902 CAP_STRING(GF_CAPS_OUTPUT, UT_CAP_CODE, "UTSourceData"),
903 CAP_STRING(GF_CAPS_OUTPUT, UT_CAP_CODE, "UTFilterData"),
904 };
905
906 static const GF_FilterCapability UTSinkInputs[] =
907 {
908 CAP_STRING(GF_CAPS_INPUT, UT_CAP_CODE, "UTSourceData"),
909 };
910
911 static const GF_FilterCapability UTSink2Inputs[] =
912 {
913 CAP_STRING(GF_CAPS_INPUT, UT_CAP_CODE, "UTFilterData"),
914 };
915
916 static const GF_FilterCapability UTSourceOutputs[] =
917 {
918 CAP_STRING(GF_CAPS_OUTPUT, UT_CAP_CODE, "UTSourceData"),
919 };
920
921
922 const GF_FilterRegister UTFilterRegister = {
923 .name = "UTFilter",
924 GF_FS_SET_DESCRIPTION("Unit Test Filter")
925 GF_FS_SET_HELP("This filter is only used for unit testing of filter framework")
926 .private_size = sizeof(GF_UnitTestFilter),
927 .flags = GF_FS_REG_EXPLICIT_ONLY,
928 SETCAPS( UTFilterCaps),
929 .args = UTFilterArgs,
930 .initialize = utfilter_initialize,
931 .finalize = ut_filter_finalize,
932 .process = ut_filter_process_filter,
933 .configure_pid = ut_filter_config_input,
934 .update_arg = ut_filter_update_arg
935 };
936
937
938 const GF_FilterRegister UTSinkRegister = {
939 .name = "UTSink",
940 GF_FS_SET_DESCRIPTION("Unit Test Sink")
941 GF_FS_SET_HELP("This filter is only used for unit testing of filter framework")
942 .private_size = sizeof(GF_UnitTestFilter),
943 .flags = GF_FS_REG_EXPLICIT_ONLY,
944 SETCAPS(UTSinkInputs),
945 .args = UTFilterArgs,
946 .initialize = utfilter_initialize,
947 .finalize = ut_filter_finalize,
948 .process = ut_filter_process_sink,
949 .configure_pid = ut_filter_config_input,
950 .update_arg = ut_filter_update_arg
951 };
952
953 const GF_FilterRegister UTSink2Register = {
954 .name = "UTSink2",
955 GF_FS_SET_DESCRIPTION("Unit Test Sink2")
956 GF_FS_SET_HELP("This filter is only used for unit testing of filter framework")
957 .private_size = sizeof(GF_UnitTestFilter),
958 .flags = GF_FS_REG_EXPLICIT_ONLY,
959 SETCAPS(UTSink2Inputs),
960 .args = UTFilterArgs,
961 .initialize = utfilter_initialize,
962 .finalize = ut_filter_finalize,
963 .process = ut_filter_process_sink,
964 .configure_pid = ut_filter_config_input,
965 .update_arg = ut_filter_update_arg
966 };
967
968 const GF_FilterRegister UTSourceRegister = {
969 .name = "UTSource",
970 GF_FS_SET_DESCRIPTION("Unit Test Source")
971 GF_FS_SET_HELP("This filter is only used for unit testing of filter framework")
972 .private_size = sizeof(GF_UnitTestFilter),
973 .flags = GF_FS_REG_EXPLICIT_ONLY,
974 SETCAPS(UTSourceOutputs),
975 .args = UTFilterArgs,
976 .initialize = utfilter_initialize,
977 .finalize = ut_filter_finalize,
978 .process = ut_filter_process_source,
979 .update_arg = ut_filter_update_arg
980 };
981
982
ut_filter_register(GF_FilterSession * session,Bool load_meta_filters)983 const GF_FilterRegister *ut_filter_register(GF_FilterSession *session, Bool load_meta_filters)
984 {
985 return &UTFilterRegister;
986 }
ut_source_register(GF_FilterSession * session,Bool load_meta_filters)987 const GF_FilterRegister *ut_source_register(GF_FilterSession *session, Bool load_meta_filters)
988 {
989 return &UTSourceRegister;
990 }
ut_sink_register(GF_FilterSession * session,Bool load_meta_filters)991 const GF_FilterRegister *ut_sink_register(GF_FilterSession *session, Bool load_meta_filters)
992 {
993 return &UTSinkRegister;
994 }
ut_sink2_register(GF_FilterSession * session,Bool load_meta_filters)995 const GF_FilterRegister *ut_sink2_register(GF_FilterSession *session, Bool load_meta_filters)
996 {
997 return &UTSink2Register;
998 }
999
1000
1001
1002