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