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 / generic stream to file filter
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/constants.h>
28 #include <gpac/bitstream.h>
29 
30 #include <gpac/internal/isomedia_dev.h>
31 
32 enum
33 {
34 	DECINFO_NO=0,
35 	DECINFO_FIRST,
36 	DECINFO_SAP,
37 	DECINFO_AUTO
38 };
39 
40 typedef struct
41 {
42 	//opts
43 	Bool exporter, frame, split;
44 	u32 sstart, send;
45 	u32 pfmt, afmt, decinfo;
46 	GF_Fraction dur;
47 
48 	//only one input pid declared
49 	GF_FilterPid *ipid;
50 	//only one output pid declared
51 	GF_FilterPid *opid;
52 
53 	u32 codecid;
54 	Bool is_mj2k;
55 	u32 sample_num;
56 
57 	const char *dcfg;
58 	u32 dcfg_size;
59 	Bool cfg_sent;
60 
61 	GF_Fraction64 duration;
62 	Bool first;
63 
64 	GF_BitStream *bs;
65 
66 	u32 target_pfmt, target_afmt;
67 	Bool is_bmp;
68 	u32 is_wav;
69 	u32 w, h, stride;
70 	u64 nb_bytes;
71 	Bool dash_mode;
72 
73 	u64 first_dts_plus_one;
74 } GF_GenDumpCtx;
75 
76 
writegen_configure_pid(GF_Filter * filter,GF_FilterPid * pid,Bool is_remove)77 GF_Err writegen_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
78 {
79 	u32 cid, chan, sr, w, h, stype, pf, sfmt, av1mode, nb_bps;
80 	const char *name, *mimetype;
81 	char szExt[GF_4CC_MSIZE], szCodecExt[30], *sep;
82 	const GF_PropertyValue *p;
83 	GF_GenDumpCtx *ctx = gf_filter_get_udta(filter);
84 
85 	if (is_remove) {
86 		ctx->ipid = NULL;
87 		gf_filter_pid_remove(ctx->opid);
88 		ctx->opid = NULL;
89 		return GF_OK;
90 	}
91 	if (! gf_filter_pid_check_caps(pid))
92 		return GF_NOT_SUPPORTED;
93 
94 	p = gf_filter_pid_get_property(pid, GF_PROP_PID_CODECID);
95 	if (!p) return GF_NOT_SUPPORTED;
96 	cid = p->value.uint;
97 
98 	ctx->codecid = cid;
99 	if (!ctx->opid) {
100 		ctx->opid = gf_filter_pid_new(filter);
101 		ctx->first = GF_TRUE;
102 	}
103 
104 	ctx->ipid = pid;
105 
106 	//copy properties at init or reconfig
107 	gf_filter_pid_copy_properties(ctx->opid, pid);
108 	gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DECODER_CONFIG, NULL);
109 
110 	p = gf_filter_pid_get_property(pid, GF_PROP_PID_STREAM_TYPE);
111 	stype = p ? p->value.uint : 0;
112 
113 	p = gf_filter_pid_get_property(pid, GF_PROP_PID_SAMPLE_RATE);
114 	sr = p ? p->value.uint : 0;
115 	p = gf_filter_pid_get_property(pid, GF_PROP_PID_NUM_CHANNELS);
116 	chan = p ? p->value.uint : 0;
117 	p = gf_filter_pid_get_property(pid, GF_PROP_PID_AUDIO_FORMAT);
118 	sfmt = p ? p->value.uint : GF_AUDIO_FMT_S16;
119 	p = gf_filter_pid_get_property(pid, GF_PROP_PID_AUDIO_BPS);
120 	nb_bps = p ? p->value.uint : 0;
121 
122 
123 	p = gf_filter_pid_get_property(pid, GF_PROP_PID_WIDTH);
124 	ctx->w = w = p ? p->value.uint : 0;
125 	p = gf_filter_pid_get_property(pid, GF_PROP_PID_HEIGHT);
126 	ctx->h = h = p ? p->value.uint : 0;
127 
128 	p = gf_filter_pid_get_property(pid, GF_PROP_PID_PIXFMT);
129 	pf = p ? p->value.uint : 0;
130 	if (!pf) pf = GF_PIXEL_YUV;
131 
132 	p = gf_filter_pid_get_property(pid, GF_PROP_PID_DECODER_CONFIG);
133 	if (p) {
134 		ctx->dcfg = p->value.data.ptr;
135 		ctx->dcfg_size = p->value.data.size;
136 	}
137 	p = gf_filter_pid_get_property(pid, GF_PROP_PID_DASH_MODE);
138 	ctx->dash_mode = (p && p->value.uint) ? GF_TRUE : GF_FALSE;
139 
140 	gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_STREAM_TYPE, &PROP_UINT(GF_STREAM_FILE) );
141 
142 	//special case for xml text, override to xml
143 	switch (cid) {
144 	case GF_CODECID_META_XML:
145 	case GF_CODECID_SUBS_XML:
146 		strcpy(szCodecExt, "xml");
147 		break;
148 	default:
149 		strncpy(szCodecExt, gf_codecid_file_ext(cid), 29);
150 		szCodecExt[29]=0;
151 		sep = strchr(szCodecExt, '|');
152 		if (sep) sep[0] = 0;
153 		break;
154 	}
155 	gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_FILE_EXT, &PROP_STRING(szCodecExt) );
156 
157 	mimetype = gf_codecid_mime(cid);
158 
159 	switch (cid) {
160 	case GF_CODECID_AAC_MPEG4:
161 	case GF_CODECID_AAC_MPEG2_MP:
162 	case GF_CODECID_AAC_MPEG2_LCP:
163 	case GF_CODECID_AAC_MPEG2_SSRP:
164 		p = gf_filter_pid_get_property(pid, GF_PROP_PID_UNFRAMED_LATM);
165 		if (p && p->value.boolean) {
166 			gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_FILE_EXT, &PROP_STRING("latm") );
167 		}
168 		break;
169 	case GF_CODECID_PNG:
170 	case GF_CODECID_JPEG:
171 		ctx->split = GF_TRUE;
172 		break;
173 	case GF_CODECID_J2K:
174 		ctx->split = GF_TRUE;
175 		ctx->is_mj2k = GF_TRUE;
176 		break;
177 	case GF_CODECID_AMR:
178 		gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_MIME, &PROP_STRING(mimetype) );
179 		ctx->dcfg = "#!AMR\n";
180 		ctx->dcfg_size = 6;
181 		ctx->decinfo = DECINFO_FIRST;
182 		break;
183 	case GF_CODECID_AMR_WB:
184 		gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_MIME, &PROP_STRING(mimetype) );
185 		ctx->dcfg = "#!AMR-WB\n";
186 		ctx->dcfg_size = 9;
187 		ctx->decinfo = DECINFO_FIRST;
188 		break;
189 	case GF_CODECID_SMV:
190 		gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_MIME, &PROP_STRING(mimetype) );
191 		ctx->dcfg = "#!SMV\n";
192 		ctx->dcfg_size = 6;
193 		ctx->decinfo = DECINFO_FIRST;
194 		break;
195 	case GF_CODECID_EVRC_PV:
196 	case GF_CODECID_EVRC:
197 		gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_MIME, &PROP_STRING(mimetype) );
198 		ctx->dcfg = "#!EVRC\n";
199 		ctx->dcfg_size = 7;
200 		ctx->decinfo = DECINFO_FIRST;
201 		break;
202 
203 	case GF_CODECID_FLAC:
204 		gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_MIME, &PROP_STRING(mimetype) );
205 		ctx->decinfo = DECINFO_FIRST;
206 		break;
207 
208 
209 	case GF_CODECID_SIMPLE_TEXT:
210 		if (!gf_filter_pid_get_property(pid, GF_PROP_PID_MIME))
211 			gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_MIME, &PROP_STRING(mimetype) );
212 		if (ctx->decinfo == DECINFO_AUTO)
213 			ctx->decinfo = DECINFO_FIRST;
214 		break;
215 	case GF_CODECID_META_TEXT:
216 		if (!gf_filter_pid_get_property(pid, GF_PROP_PID_MIME))
217 			gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_MIME, &PROP_STRING(mimetype) );
218 		if (ctx->decinfo == DECINFO_AUTO)
219 			ctx->decinfo = DECINFO_FIRST;
220 		break;
221 	case GF_CODECID_META_XML:
222 		if (!gf_filter_pid_get_property(pid, GF_PROP_PID_MIME))
223 			gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_MIME, &PROP_STRING(mimetype) );
224 		if (ctx->decinfo == DECINFO_AUTO)
225 			ctx->decinfo = DECINFO_FIRST;
226 		break;
227 	case GF_CODECID_SUBS_TEXT:
228 		if (!gf_filter_pid_get_property(pid, GF_PROP_PID_MIME))
229 			gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_MIME, &PROP_STRING(mimetype) );
230 		if (ctx->decinfo == DECINFO_AUTO)
231 			ctx->decinfo = DECINFO_FIRST;
232 		break;
233 	case GF_CODECID_SUBS_XML:
234 		if (!gf_filter_pid_get_property(pid, GF_PROP_PID_MIME))
235 			gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_MIME, &PROP_STRING(mimetype) );
236 
237 		if (!ctx->frame) {
238 			GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("Subtitles re-assembling is not supported yet\n"));
239 			return GF_NOT_SUPPORTED;
240 		}
241 		ctx->split = GF_TRUE;
242 		if (ctx->decinfo == DECINFO_AUTO)
243 			ctx->decinfo = DECINFO_FIRST;
244 		break;
245 
246 	case GF_CODECID_AV1:
247 		av1mode = 0;
248 		p = gf_filter_pid_get_property_str(ctx->ipid, "obu:mode");
249 		if (p) av1mode = p->value.uint;
250 		if (av1mode==1) {
251 			gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_FILE_EXT, &PROP_STRING("av1b") );
252 			gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_MIME, &PROP_STRING("video/x-av1b") );
253 		} else if (av1mode==2) {
254 			gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_FILE_EXT, &PROP_STRING("ivf") );
255 			gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_MIME, &PROP_STRING("video/x-ivf") );
256 		} else {
257 			gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_FILE_EXT, &PROP_STRING("obu") );
258 			gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_MIME, &PROP_STRING("video/x-av1") );
259 		}
260 		break;
261 	case GF_CODECID_RAW:
262 		ctx->dcfg = NULL;
263 		ctx->dcfg_size = 0;
264 		if (stype==GF_STREAM_VISUAL) {
265 			strcpy(szExt, gf_pixel_fmt_sname(ctx->target_pfmt ? ctx->target_pfmt : pf));
266 			p = gf_filter_pid_caps_query(ctx->opid, GF_PROP_PID_FILE_EXT);
267 			if (p) {
268 				strncpy(szExt, p->value.string, GF_4CC_MSIZE-1);
269 				szExt[GF_4CC_MSIZE-1] = 0;
270 				if (!strcmp(szExt, "bmp")) {
271 					ctx->is_bmp = GF_TRUE;
272 					//request BGR
273 					ctx->target_pfmt = GF_PIXEL_BGR;
274 					ctx->split = GF_TRUE;
275 				} else {
276 					ctx->target_pfmt = gf_pixel_fmt_parse(szExt);
277 					if (!ctx->target_pfmt) {
278 						GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("Cannot guess pixel format from extension type %s\n", szExt));
279 						return GF_NOT_SUPPORTED;
280 					}
281 					strcpy(szExt, gf_pixel_fmt_sname(ctx->target_pfmt));
282 				}
283 				//forcing pixel format regardless of extension
284 				if (ctx->pfmt) {
285 					if (pf != ctx->pfmt) {
286 						gf_filter_pid_negociate_property(ctx->ipid, GF_PROP_PID_PIXFMT, &PROP_UINT(ctx->pfmt));
287 						//make sure we reconfigure
288 						ctx->codecid = 0;
289 						pf = ctx->pfmt;
290 					}
291 				}
292 				//use extension to derive pixel format
293 				else if (pf != ctx->target_pfmt) {
294 					gf_filter_pid_negociate_property(ctx->ipid, GF_PROP_PID_PIXFMT, &PROP_UINT(ctx->target_pfmt));
295 					strcpy(szExt, gf_pixel_fmt_sname(ctx->target_pfmt));
296 					//make sure we reconfigure
297 					ctx->codecid = 0;
298 				}
299 			}
300 
301 			p = gf_filter_pid_get_property(pid, GF_PROP_PID_STRIDE);
302 			ctx->stride = p ? p->value.uint : 0;
303 
304 			if (!ctx->stride) {
305 				gf_pixel_get_size_info(ctx->target_pfmt, ctx->w, ctx->h, NULL, &ctx->stride, NULL, NULL, NULL);
306 			}
307 
308 		} else if (stype==GF_STREAM_AUDIO) {
309 			strcpy(szExt, gf_audio_fmt_sname(ctx->target_pfmt ? ctx->target_afmt : sfmt));
310 			p = gf_filter_pid_caps_query(ctx->opid, GF_PROP_PID_FILE_EXT);
311 			if (p) {
312 				strncpy(szExt, p->value.string, GF_4CC_MSIZE-1);
313 				szExt[GF_4CC_MSIZE-1] = 0;
314 				if (!strcmp(szExt, "wav")) {
315 					ctx->is_wav = GF_TRUE;
316 					//request PCMs16 ?
317 //					ctx->target_afmt = GF_AUDIO_FMT_S16;
318 					ctx->target_afmt = sfmt;
319 				} else {
320 					ctx->target_afmt = gf_audio_fmt_parse(szExt);
321 					strcpy(szExt, gf_audio_fmt_sname(ctx->target_afmt));
322 				}
323 				//forcing sample format regardless of extension
324 				if (ctx->afmt) {
325 					if (sfmt != ctx->afmt) {
326 						gf_filter_pid_negociate_property(ctx->ipid, GF_PROP_PID_AUDIO_FORMAT, &PROP_UINT(ctx->afmt));
327 						//make sure we reconfigure
328 						ctx->codecid = 0;
329 						sfmt = ctx->afmt;
330 					}
331 				}
332 				//use extension to derive sample format
333 				else if (sfmt != ctx->target_afmt) {
334 					gf_filter_pid_negociate_property(ctx->ipid, GF_PROP_PID_AUDIO_FORMAT, &PROP_UINT(ctx->target_afmt));
335 					strcpy(szExt, gf_audio_fmt_sname(ctx->target_afmt));
336 					//make sure we reconfigure
337 					ctx->codecid = 0;
338 				}
339 			}
340 
341 		} else {
342 			strcpy(szExt, gf_4cc_to_str(cid));
343 		}
344 		if (ctx->is_bmp) strcpy(szExt, "bmp");
345 		else if (ctx->is_wav) {
346 			gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DISABLE_PROGRESSIVE, &PROP_UINT(GF_PID_FILE_PATCH_REPLACE) );
347 			strcpy(szExt, "wav");
348 		} else if (!strlen(szExt)) strcpy(szExt, "raw");
349 
350 		gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_FILE_EXT, &PROP_STRING( szExt ) );
351 		gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_MIME, &PROP_STRING("application/octet-string") );
352 		if (!ctx->codecid) return GF_OK;
353 		break;
354 
355 	default:
356 		if (!strcmp(szCodecExt, "raw")) {
357 			strcpy(szExt, gf_4cc_to_str(cid));
358 			if (!strlen(szExt)) strcpy(szExt, "raw");
359 			gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_FILE_EXT, &PROP_STRING( szExt ) );
360 		} else {
361 			gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_FILE_EXT, &PROP_STRING( szCodecExt ) );
362 		}
363 		gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_MIME, &PROP_STRING(mimetype) );
364 		break;
365 	}
366 
367 	if (ctx->decinfo == DECINFO_AUTO)
368 		ctx->decinfo = DECINFO_NO;
369 
370 	name = gf_codecid_name(cid);
371 	if (ctx->exporter) {
372 		if (w && h) {
373 			if (cid==GF_CODECID_RAW) name = gf_pixel_fmt_name(pf);
374 			GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("Exporting %s - Size %dx%d\n", name, w, h));
375 		} else if (sr && chan) {
376 			if (cid==GF_CODECID_RAW) {
377 				GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("Exporting PCM %s SampleRate %d %d channels %d bits per sample\n", gf_audio_fmt_name(sfmt), sr, chan, gf_audio_fmt_bit_depth(sfmt) ));
378 			} else {
379 				if (!nb_bps)
380 					nb_bps = gf_audio_fmt_bit_depth(sfmt);
381 
382 				GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("Exporting %s - SampleRate %d %d channels %d bits per sample\n", name, sr, chan, nb_bps ));
383 			}
384 		} else {
385 			GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("Exporting %s\n", name));
386 		}
387 	}
388 
389 	//avoid creating a file when dumping individual samples
390 	if (ctx->split) {
391 		p = gf_filter_pid_get_property(pid, GF_PROP_PID_NB_FRAMES);
392 		if (!p || (p->value.uint>1))
393 			gf_filter_pid_set_property(ctx->opid, GF_PROP_PCK_FILENUM, &PROP_UINT(0) );
394 		else
395 			ctx->split = GF_FALSE;
396 	} else if (ctx->frame) {
397 		gf_filter_pid_set_property(ctx->opid, GF_PROP_PCK_FILENUM, &PROP_UINT(0) );
398 	}
399 
400 	p = gf_filter_pid_get_property(pid, GF_PROP_PID_DURATION);
401 	if (p) ctx->duration = p->value.lfrac;
402 
403 	gf_filter_pid_set_framing_mode(pid, GF_TRUE);
404 	return GF_OK;
405 }
406 
writegen_write_j2k(GF_GenDumpCtx * ctx,char * data,u32 data_size,GF_FilterPacket * in_pck)407 static GF_FilterPacket *writegen_write_j2k(GF_GenDumpCtx *ctx, char *data, u32 data_size, GF_FilterPacket *in_pck)
408 {
409 	u32 size;
410 	u8 *output;
411 	GF_FilterPacket *dst_pck;
412 	char sig[8];
413 	sig[0] = sig[1] = sig[2] = 0;
414 	sig[3] = 0xC;
415 	sig[4] = 'j';
416 	sig[5] = 'P';
417 	sig[6] = sig[7] = ' ';
418 
419 	if ((data_size>16) && !memcmp(data, sig, 8)) {
420 		return gf_filter_pck_new_ref(ctx->opid, NULL, 0, in_pck);
421 	}
422 
423 	size = data_size + 8*4 /*jP%20%20 + ftyp*/ + ctx->dcfg_size + 8;
424 
425 	dst_pck = gf_filter_pck_new_alloc(ctx->opid, size, &output);
426 
427 
428 	if (!ctx->bs) ctx->bs = gf_bs_new(output, size, GF_BITSTREAM_WRITE);
429 	else gf_bs_reassign_buffer(ctx->bs, output, size);
430 
431 	gf_bs_write_u32(ctx->bs, 12);
432 	gf_bs_write_u32(ctx->bs, GF_ISOM_BOX_TYPE_JP);
433 	gf_bs_write_u32(ctx->bs, 0x0D0A870A);
434 	gf_bs_write_u32(ctx->bs, 20);
435 	gf_bs_write_u32(ctx->bs, GF_ISOM_BOX_TYPE_FTYP);
436 	gf_bs_write_u32(ctx->bs, GF_ISOM_BRAND_JP2);
437 	gf_bs_write_u32(ctx->bs, 0);
438 	gf_bs_write_u32(ctx->bs, GF_ISOM_BRAND_JP2);
439 
440 	//todo, write colr and other info ?
441 	if (ctx->dcfg) {
442 		gf_bs_write_u32(ctx->bs, 8+ctx->dcfg_size);
443 		gf_bs_write_u32(ctx->bs, GF_ISOM_BOX_TYPE_JP2H);
444 		gf_bs_write_data(ctx->bs, ctx->dcfg, ctx->dcfg_size);
445 	}
446 	gf_bs_write_data(ctx->bs, data, data_size);
447 
448 	return dst_pck;
449 }
450 
451 #ifdef WIN32
452 #include <windows.h>
453 #else
454 typedef struct tagBITMAPFILEHEADER
455 {
456 	u16	bfType;
457 	u32	bfSize;
458 	u16	bfReserved1;
459 	u16	bfReserved2;
460 	u32 bfOffBits;
461 } BITMAPFILEHEADER;
462 
463 typedef struct tagBITMAPINFOHEADER {
464 	u32	biSize;
465 	s32	biWidth;
466 	s32	biHeight;
467 	u16	biPlanes;
468 	u16	biBitCount;
469 	u32	biCompression;
470 	u32	biSizeImage;
471 	s32	biXPelsPerMeter;
472 	s32	biYPelsPerMeter;
473 	u32	biClrUsed;
474 	u32	biClrImportant;
475 } BITMAPINFOHEADER;
476 
477 #define BI_RGB        0L
478 
479 #endif
480 
writegen_write_bmp(GF_GenDumpCtx * ctx,char * data,u32 data_size)481 static GF_FilterPacket *writegen_write_bmp(GF_GenDumpCtx *ctx, char *data, u32 data_size)
482 {
483 	u32 size;
484 	u8 *output;
485 	BITMAPFILEHEADER fh;
486 	BITMAPINFOHEADER fi;
487 	GF_FilterPacket *dst_pck;
488 	u32 i;
489 
490 	size = ctx->w*ctx->h*3 + 54; //14 + 40 = size of BMP file header and BMP file info;
491 	dst_pck = gf_filter_pck_new_alloc(ctx->opid, size, &output);
492 
493 	memset(&fh, 0, sizeof(fh));
494 	fh.bfType = 19778;
495 	fh.bfOffBits = 54;
496 
497 	if (!ctx->bs) ctx->bs = gf_bs_new(output, size, GF_BITSTREAM_WRITE);
498 	else gf_bs_reassign_buffer(ctx->bs, output, size);
499 
500 	gf_bs_write_data(ctx->bs, (const char *) &fh.bfType, 2);
501 	gf_bs_write_data(ctx->bs, (const char *) &fh.bfSize, 4);
502 	gf_bs_write_data(ctx->bs, (const char *) &fh.bfReserved1, 2);
503 	gf_bs_write_data(ctx->bs, (const char *) &fh.bfReserved2, 2);
504 	gf_bs_write_data(ctx->bs, (const char *) &fh.bfOffBits, 4);
505 
506 	memset(&fi, 0, sizeof(char)*40);
507 	fi.biSize = 40;
508 	fi.biWidth = ctx->w;
509 	fi.biHeight = ctx->h;
510 	fi.biPlanes = 1;
511 	fi.biBitCount = 24;
512 	fi.biCompression = BI_RGB;
513 	fi.biSizeImage = ctx->w * ctx->h * 3;
514 
515 	memcpy(output+14, &fi, sizeof(char)*40);
516 	//reverse lines
517 	output += sizeof(u8) * 54;
518 	for (i=ctx->h; i>0; i--) {
519 		u8 *ptr = data + (i-1)*ctx->stride;
520 		memcpy(output, ptr, sizeof(u8)*3*ctx->w);
521 		output += 3*ctx->w;
522 	}
523 	return dst_pck;
524 }
525 
writegen_write_wav_header(GF_GenDumpCtx * ctx)526 static void writegen_write_wav_header(GF_GenDumpCtx *ctx)
527 {
528 	u32 size;
529 	u8 *output;
530 	GF_FilterPacket *dst_pck;
531 	const GF_PropertyValue *p;
532 	u32 nb_ch, sample_rate, afmt, bps;
533 	const char chunkID[] = {'R', 'I', 'F', 'F'};
534 	const char format[] = {'W', 'A', 'V', 'E'};
535 	const char subchunk1ID[] = {'f', 'm', 't', ' '};
536 	const char subchunk2ID[] = {'d', 'a', 't', 'a'};
537 
538 	if (ctx->is_wav!=1) return;
539 	ctx->is_wav = 2;
540 
541 	p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_SAMPLE_RATE);
542 	if (!p) return;
543 	sample_rate = p->value.uint;
544 	p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_NUM_CHANNELS);
545 	if (!p) return;
546 	nb_ch = p->value.uint;
547 	p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_AUDIO_FORMAT);
548 	if (!p) return;
549 	afmt = p->value.uint;
550 
551 	bps = gf_audio_fmt_bit_depth(afmt);
552 
553 	size = 44;
554 	dst_pck = gf_filter_pck_new_alloc(ctx->opid, size, &output);
555 
556 	if (!ctx->bs) ctx->bs = gf_bs_new(output, size, GF_BITSTREAM_WRITE);
557 	else gf_bs_reassign_buffer(ctx->bs, output, size);
558 
559 	gf_bs_write_data(ctx->bs, chunkID, 4);
560 	gf_bs_write_u32_le(ctx->bs, (u32) ctx->nb_bytes + 36);
561 	gf_bs_write_data(ctx->bs, format, 4);
562 
563 	gf_bs_write_data(ctx->bs, subchunk1ID, 4);
564 	gf_bs_write_u32_le(ctx->bs, 16); //subchunk1 size
565 	gf_bs_write_u16_le(ctx->bs, 1); //audio format
566 	gf_bs_write_u16_le(ctx->bs, nb_ch);
567 	gf_bs_write_u32_le(ctx->bs, sample_rate);
568 	gf_bs_write_u32_le(ctx->bs, sample_rate * nb_ch * bps / 8); //byte rate
569 	gf_bs_write_u16_le(ctx->bs, nb_ch * bps / 8); // block align
570 	gf_bs_write_u16_le(ctx->bs, bps);
571 
572 	gf_bs_write_data(ctx->bs, subchunk2ID, 4);
573 	gf_bs_write_u32_le(ctx->bs, (u32) ctx->nb_bytes);
574 
575 	gf_filter_pck_set_framing(dst_pck, GF_FALSE, GF_FALSE);
576 	gf_filter_pck_set_byte_offset(dst_pck, 0);
577 	gf_filter_pck_set_seek_flag(dst_pck, GF_TRUE);
578 	gf_filter_pck_send(dst_pck);
579 }
580 
writegen_process(GF_Filter * filter)581 GF_Err writegen_process(GF_Filter *filter)
582 {
583 	GF_GenDumpCtx *ctx = gf_filter_get_udta(filter);
584 	GF_FilterPacket *pck, *dst_pck;
585 	char *data;
586 	u32 pck_size;
587 	Bool do_abort = GF_FALSE;
588 	Bool split = ctx->split;
589 	if (!ctx->ipid) return GF_EOS;
590 
591 	pck = gf_filter_pid_get_packet(ctx->ipid);
592 	if (!pck || !ctx->codecid) {
593 		if (gf_filter_pid_is_eos(ctx->ipid)) {
594 			if (ctx->is_wav) writegen_write_wav_header(ctx);
595 			gf_filter_pid_set_eos(ctx->opid);
596 			return GF_EOS;
597 		}
598 		return GF_OK;
599 	}
600 	ctx->sample_num++;
601 
602 	if (ctx->sstart) {
603 		if (ctx->sstart > ctx->sample_num) {
604 			gf_filter_pid_drop_packet(ctx->ipid);
605 			return GF_OK;
606 		}
607 		if ((ctx->sstart <= ctx->send) && (ctx->sample_num>ctx->send) ) {
608 			do_abort = GF_TRUE;
609 		}
610 	} else if (ctx->dur.num && ctx->dur.den) {
611 		u64 dts = gf_filter_pck_get_dts(pck);
612 		if (dts==GF_FILTER_NO_TS)
613 		dts = gf_filter_pck_get_cts(pck);
614 
615 		if (!ctx->first_dts_plus_one) {
616 			ctx->first_dts_plus_one = dts+1;
617 		} else {
618 			if (ctx->dur.den * (dts + 1 - ctx->first_dts_plus_one) > ctx->dur.num * gf_filter_pck_get_timescale(pck)) {
619 				do_abort = GF_TRUE;
620 			}
621 		}
622 	}
623 	if (do_abort) {
624 		GF_FilterEvent evt;
625 		gf_filter_pid_drop_packet(ctx->ipid);
626 		GF_FEVT_INIT(evt, GF_FEVT_STOP, ctx->ipid);
627 		gf_filter_pid_send_event(ctx->ipid, &evt);
628 		return GF_OK;
629 	}
630 
631 	//except in dash mode, force a new file if GF_PROP_PCK_FILENUM is set
632 	if (!ctx->dash_mode && (gf_filter_pck_get_property(pck, GF_PROP_PCK_FILENUM) != NULL)) {
633 		ctx->cfg_sent = GF_FALSE;
634 		ctx->first = GF_TRUE;
635 	}
636 
637 	if (ctx->frame) {
638 		split = GF_TRUE;
639 	} else if (ctx->dcfg_size && gf_filter_pck_get_sap(pck) && !ctx->is_mj2k && (ctx->decinfo!=DECINFO_NO) && !ctx->cfg_sent) {
640 		dst_pck = gf_filter_pck_new_shared(ctx->opid, ctx->dcfg, ctx->dcfg_size, NULL);
641 		gf_filter_pck_merge_properties(pck, dst_pck);
642 		gf_filter_pck_set_framing(dst_pck, ctx->first, GF_FALSE);
643 		ctx->first = GF_FALSE;
644 		gf_filter_pck_set_readonly(dst_pck);
645 		gf_filter_pck_send(dst_pck);
646 		if ((ctx->decinfo==DECINFO_FIRST) && !ctx->split) {
647 			ctx->dcfg_size = 0;
648 			ctx->dcfg = NULL;
649 		}
650 		ctx->cfg_sent = GF_TRUE;
651 		return GF_OK;
652 	}
653 	ctx->cfg_sent = GF_FALSE;
654 	data = (char *) gf_filter_pck_get_data(pck, &pck_size);
655 
656 	if (ctx->is_mj2k) {
657 		dst_pck = writegen_write_j2k(ctx, data, pck_size, pck);
658 	} else if (ctx->is_bmp) {
659 		dst_pck = writegen_write_bmp(ctx, data, pck_size);
660 	} else if (ctx->is_wav && ctx->first) {
661 		u8 * output;
662 		dst_pck = gf_filter_pck_new_alloc(ctx->opid, 44, &output);
663 		gf_filter_pck_merge_properties(pck, dst_pck);
664 		gf_filter_pck_set_byte_offset(dst_pck, GF_FILTER_NO_BO);
665 		gf_filter_pck_set_framing(dst_pck, GF_TRUE, GF_FALSE);
666 		gf_filter_pck_set_corrupted(dst_pck, GF_TRUE);
667 		ctx->first = GF_FALSE;
668 		gf_filter_pck_send(dst_pck);
669 		ctx->nb_bytes += 44;
670 		return GF_OK;
671 	} else {
672 		dst_pck = gf_filter_pck_new_ref(ctx->opid, NULL, 0, pck);
673 	}
674 	gf_filter_pck_merge_properties(pck, dst_pck);
675 	//don't keep byte offset
676 	gf_filter_pck_set_byte_offset(dst_pck, GF_FILTER_NO_BO);
677 
678 	if (split) {
679 		gf_filter_pck_set_property(dst_pck, GF_PROP_PCK_FILENUM, &PROP_UINT(ctx->sample_num) );
680 		gf_filter_pck_set_framing(dst_pck, GF_TRUE, GF_TRUE);
681 	} else {
682 		gf_filter_pck_set_framing(dst_pck, ctx->first, GF_FALSE);
683 		ctx->first = GF_FALSE;
684 	}
685 
686 	gf_filter_pck_send(dst_pck);
687 	gf_filter_pck_set_seek_flag(dst_pck, 0);
688 	ctx->nb_bytes += pck_size;
689 
690 	if (ctx->exporter) {
691 		u32 timescale = gf_filter_pck_get_timescale(pck);
692 		u64 ts = gf_filter_pck_get_dts(pck);
693 		if (ts==GF_FILTER_NO_TS)
694 			ts = gf_filter_pck_get_cts(pck);
695 		if (ts!=GF_FILTER_NO_TS) {
696 			ts += gf_filter_pck_get_duration(pck);
697 			ts *= ctx->duration.den;
698 			ts /= timescale;
699 			gf_set_progress("Exporting", ts, ctx->duration.num);
700 		}
701 	}
702 
703 	gf_filter_pid_drop_packet(ctx->ipid);
704 
705 	return GF_OK;
706 }
707 
708 /*
709 	We list capabilities per codec type, associating the codec type to the file extension. This allows,
710 	when matching to an output filter accepting a given file extension to match the codec type in write_gen caps, and
711 	setup the right filter chain
712 */
713 static GF_FilterCapability GenDumpCaps[] =
714 {
715 	//raw color dump YUV and RGB - keep it as first for field extension assignment
716 	//cf below
717 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
718 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_RAW),
719 	CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
720 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "gpac"),
721 	{0},
722 	//raw audio dump - keep it as second for field extension assignment
723 	//cf below
724 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
725 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_RAW),
726 	CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
727 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "gpac" ),
728 	{0},
729 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
730 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_RAW),
731 	CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
732 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "bmp"),
733 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "image/bmp"),
734 	{0},
735 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
736 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_RAW),
737 	CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
738 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "wav"),
739 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "audio/wav|audio/wave"),
740 	{0},
741 
742 	//we accept unframed AVC (annex B format)
743 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
744 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_AVC),
745 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_AVC_PS),
746 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_SVC),
747 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_MVC),
748 	CAP_BOOL(GF_CAPS_INPUT,GF_PROP_PID_UNFRAMED, GF_TRUE),
749 	CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
750 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "264|h264|avc|svc|mvc"),
751 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "video/avc|video/h264|video/svc|video/mvc"),
752 	{0},
753 
754 	//we accept unframed HEVC (annex B format)
755 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
756 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_HEVC),
757 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_LHVC),
758 	CAP_BOOL(GF_CAPS_INPUT,GF_PROP_PID_UNFRAMED, GF_TRUE),
759 	CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
760 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "265|h265|hvc|hevc|shvc|lhvc"),
761 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "video/hevc|video/lhvc|video/shvc|video/mhvc"),
762 	{0},
763 
764 	//we accept unframed OBU (without size field)
765 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
766 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_AV1),
767 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_VP8),
768 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_VP9),
769 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_VP10),
770 	CAP_BOOL(GF_CAPS_INPUT,GF_PROP_PID_UNFRAMED, GF_TRUE),
771 	CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
772 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "obu|av1|av1b|ivf"),
773 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "video/x-ivf|video/av1"),
774 	{0},
775 
776 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
777 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_MPEG4_PART2),
778 	CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
779 	CAP_BOOL(GF_CAPS_INPUT,GF_PROP_PID_UNFRAMED, GF_TRUE),
780 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "cmp|m4ve"),
781 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "video/mp4v-es"),
782 	{0},
783 
784 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
785 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_H263),
786 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_S263),
787 	CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
788 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "h263|263|s263"),
789 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "video/h263"),
790 	{0},
791 
792 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
793 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_MPEG1),
794 	CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
795 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "m1v"),
796 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "video/mpgv-es"),
797 	{0},
798 
799 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
800 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_MPEG2_422),
801 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_MPEG2_SNR),
802 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_MPEG2_HIGH),
803 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_MPEG2_MAIN),
804 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_MPEG2_SIMPLE),
805 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_MPEG2_SPATIAL),
806 	CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
807 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "m2v"),
808 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "video/mpgv-es"),
809 	{0},
810 
811 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
812 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_AP4H),
813 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_AP4X),
814 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_APCH),
815 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_APCO),
816 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_APCS),
817 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_APCN),
818 	CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
819 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "prores"),
820 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "video/prores"),
821 	{0},
822 
823 	//we accept unframed AAC + ADTS
824 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
825 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_AAC_MPEG4),
826 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_AAC_MPEG2_MP),
827 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_AAC_MPEG2_LCP),
828 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_AAC_MPEG2_SSRP),
829 	CAP_BOOL(GF_CAPS_INPUT,GF_PROP_PID_UNFRAMED, GF_TRUE),
830 	CAP_BOOL(GF_CAPS_INPUT_EXCLUDED,GF_PROP_PID_UNFRAMED_LATM, GF_TRUE),
831 	CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
832 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "aac|adts"),
833 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "audio/x-m4a|audio/aac|audio/aacp|audio/x-aac"),
834 	{0},
835 
836 	//we accept unframed AAC + LATM
837 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
838 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_AAC_MPEG4),
839 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_AAC_MPEG2_MP),
840 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_AAC_MPEG2_LCP),
841 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_AAC_MPEG2_SSRP),
842 	CAP_BOOL(GF_CAPS_INPUT,GF_PROP_PID_UNFRAMED_LATM, GF_TRUE),
843 	CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
844 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "latm"),
845 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "audio/aac+latm"),
846 	{0},
847 
848 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
849 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_PNG),
850 	CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
851 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "png"),
852 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "image/png"),
853 	{0},
854 
855 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
856 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_JPEG),
857 	CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
858 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "jpg|jpeg"),
859 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "image/jpg"),
860 	{0},
861 
862 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
863 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_J2K),
864 	CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
865 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "jp2|j2k"),
866 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "image/jp2"),
867 	{0},
868 
869 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
870 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_MPEG_AUDIO),
871 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_MPEG2_PART3),
872 	CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
873 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "mp3|mp1|mp2"),
874 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "audio/mp3|audio/x-mp3"),
875 	{0},
876 
877 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
878 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_AMR),
879 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_AMR_WB),
880 	CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
881 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "amr"),
882 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "audio/amr"),
883 	{0},
884 
885 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
886 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_SMV),
887 	CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
888 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "smv"),
889 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "audio/smv"),
890 	{0},
891 
892 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
893 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_EVRC_PV),
894 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_EVRC),
895 	CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
896 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "evc"),
897 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "audio/evrc"),
898 	{0},
899 
900 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
901 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_AC3),
902 	CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
903 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "ac3"),
904 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "audio/x-ac3|audio/ac3"),
905 	{0},
906 
907 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
908 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_EAC3),
909 	CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
910 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "eac3"),
911 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "audio/x-eac3|audio/eac3"),
912 	{0},
913 
914 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_SIMPLE_TEXT),
915 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_META_TEXT),
916 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_SUBS_TEXT),
917 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "txt"),
918 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "x-subtitle/srt|subtitle/srt|text/srt"),
919 	{0},
920 
921 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_META_XML),
922 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_SUBS_XML),
923 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "xml|txml|ttml"),
924 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "subtitle/ttml|text/ttml|application/xml+ttml"),
925 	{0},
926 
927 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
928 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_QCELP),
929 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "qcelp"),
930 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "audio/qcelp"),
931 	{0},
932 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
933 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_THEORA),
934 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "theo"),
935 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "video/x-theora"),
936 	{0},
937 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
938 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_VORBIS),
939 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "vorb"),
940 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "audio/x-vorbis"),
941 	{0},
942 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
943 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_SPEEX),
944 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "spx"),
945 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "audio/x-speex"),
946 	{0},
947 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
948 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_FLAC),
949 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "flac"),
950 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "audio/flac"),
951 	{0},
952 
953 	//anything else: only for explicit dump (filter loaded on purpose), otherwise don't load for filter link resolution
954 	CAP_UINT(GF_CAPS_OUTPUT_LOADED_FILTER, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
955 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "*"),
956 	CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "*"),
957 	//for the rest, we include everything, only specifies excluded ones from above and non-handled ones
958 	CAP_UINT(GF_CAPS_INPUT_EXCLUDED,  GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
959 
960 	CAP_UINT(GF_CAPS_INPUT_EXCLUDED,  GF_PROP_PID_CODECID, GF_CODECID_AVC),
961 	CAP_UINT(GF_CAPS_INPUT_EXCLUDED,  GF_PROP_PID_CODECID, GF_CODECID_AVC_PS),
962 	CAP_UINT(GF_CAPS_INPUT_EXCLUDED,  GF_PROP_PID_CODECID, GF_CODECID_SVC),
963 	CAP_UINT(GF_CAPS_INPUT_EXCLUDED,  GF_PROP_PID_CODECID, GF_CODECID_MVC),
964 	CAP_UINT(GF_CAPS_INPUT_EXCLUDED,  GF_PROP_PID_CODECID, GF_CODECID_HEVC),
965 	CAP_UINT(GF_CAPS_INPUT_EXCLUDED,  GF_PROP_PID_CODECID, GF_CODECID_LHVC),
966 	CAP_UINT(GF_CAPS_INPUT_EXCLUDED,  GF_PROP_PID_CODECID, GF_CODECID_MPEG4_PART2),
967 	CAP_UINT(GF_CAPS_INPUT_EXCLUDED,  GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
968 	CAP_UINT(GF_CAPS_INPUT_EXCLUDED,  GF_PROP_PID_CODECID, GF_CODECID_AAC_MPEG4),
969 	CAP_UINT(GF_CAPS_INPUT_EXCLUDED,  GF_PROP_PID_CODECID, GF_CODECID_AAC_MPEG2_MP),
970 	CAP_UINT(GF_CAPS_INPUT_EXCLUDED,  GF_PROP_PID_CODECID, GF_CODECID_AAC_MPEG2_LCP),
971 	CAP_UINT(GF_CAPS_INPUT_EXCLUDED,  GF_PROP_PID_CODECID, GF_CODECID_AAC_MPEG2_SSRP),
972 	CAP_UINT(GF_CAPS_INPUT_EXCLUDED,  GF_PROP_PID_CODECID, GF_CODECID_RAW),
973 
974 	//WebVTT needs rewrite
975 	CAP_UINT(GF_CAPS_INPUT_EXCLUDED,  GF_PROP_PID_CODECID, GF_CODECID_WEBVTT),
976 	//systems streams not dumpable to file
977 	CAP_UINT(GF_CAPS_INPUT_EXCLUDED,  GF_PROP_PID_CODECID, GF_CODECID_BIFS),
978 	CAP_UINT(GF_CAPS_INPUT_EXCLUDED,  GF_PROP_PID_CODECID, GF_CODECID_BIFS_V2),
979 	CAP_UINT(GF_CAPS_INPUT_EXCLUDED,  GF_PROP_PID_CODECID, GF_CODECID_OD_V1),
980 	CAP_UINT(GF_CAPS_INPUT_EXCLUDED,  GF_PROP_PID_CODECID, GF_CODECID_OD_V2),
981 	//this one need QCP
982 	CAP_UINT(GF_CAPS_INPUT_EXCLUDED,  GF_PROP_PID_CODECID, GF_CODECID_QCELP),
983 
984 	//other not supported (yet)
985 	CAP_UINT(GF_CAPS_INPUT_EXCLUDED,  GF_PROP_PID_CODECID, GF_CODECID_THEORA),
986 	CAP_UINT(GF_CAPS_INPUT_EXCLUDED,  GF_PROP_PID_CODECID, GF_CODECID_VORBIS)
987 };
988 
989 
990 #define OFFS(_n)	#_n, offsetof(GF_GenDumpCtx, _n)
991 static GF_FilterArgs GenDumpArgs[] =
992 {
993 	{ OFFS(exporter), "compatibility with old exporter, displays export results", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
994 	{ OFFS(pfmt), "pixel format for raw extract. If not set, derived from extension", GF_PROP_PIXFMT, "none", NULL, 0},
995 	{ OFFS(afmt), "audio format for raw extract. If not set, derived from extension", GF_PROP_PCMFMT, "none", NULL, 0},
996 	{ OFFS(decinfo), "decoder config insert mode\n"
997 	"- no: never inserted\n"
998 	"- first: inserted on first packet\n"
999 	"- sap: inserted at each SAP\n"
1000 	"- auto: selects between no and first based on media type", GF_PROP_UINT, "auto", "no|first|sap|auto", GF_FS_ARG_HINT_ADVANCED},
1001 	{ OFFS(split), "force one file per decoded frame.", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
1002 	{ OFFS(frame), "force single frame dump with no rewrite. In this mode, all codecids are supported", GF_PROP_BOOL, "false", NULL, 0},
1003 	{ OFFS(sstart), "start number of frame to forward. If 0, all samples are forwarded", GF_PROP_UINT, "0", NULL, 0},
1004 	{ OFFS(send), "end number of frame to forward. If less than start frame, all samples after start are forwarded", GF_PROP_UINT, "0", NULL, 0},
1005 	{ OFFS(dur), "duration of media to forward after first sample. If 0, all samples are forwarded", GF_PROP_FRACTION, "0", NULL, 0},
1006 	{0}
1007 };
1008 
1009 static GF_Err writegen_initialize(GF_Filter *filter);
1010 
writegen_finalize(GF_Filter * filter)1011 void writegen_finalize(GF_Filter *filter)
1012 {
1013 	GF_GenDumpCtx *ctx = gf_filter_get_udta(filter);
1014 	if (ctx->bs) gf_bs_del(ctx->bs);
1015 }
1016 
1017 GF_FilterRegister GenDumpRegister = {
1018 	.name = "writegen",
1019 	GF_FS_SET_DESCRIPTION("Stream to file")
1020 	GF_FS_SET_HELP("Generic single stream to file converter, used when extracting/converting PIDs.\n"
1021 	"The writegen filter should usually not be explicetly loaded without a source ID specified, since the filter would likely match any pid connection.")
1022 	.private_size = sizeof(GF_GenDumpCtx),
1023 	.args = GenDumpArgs,
1024 	.initialize = writegen_initialize,
1025 	.finalize = writegen_finalize,
1026 	SETCAPS(GenDumpCaps),
1027 	.configure_pid = writegen_configure_pid,
1028 	.process = writegen_process
1029 };
1030 
1031 static const GF_FilterCapability FrameDumpCaps[] =
1032 {
1033 	CAP_BOOL(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
1034 	CAP_UINT(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_CODECID, GF_CODECID_NONE),
1035 	CAP_UINT(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_STREAM_TYPE, GF_STREAM_UNKNOWN),
1036 	CAP_UINT(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
1037 	CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE)
1038 };
1039 
writegen_initialize(GF_Filter * filter)1040 static GF_Err writegen_initialize(GF_Filter *filter)
1041 {
1042 	GF_GenDumpCtx *ctx = gf_filter_get_udta(filter);
1043 	if (ctx->frame) {
1044 		return gf_filter_override_caps(filter, (const GF_FilterCapability *) FrameDumpCaps, sizeof(FrameDumpCaps) / sizeof(GF_FilterCapability));
1045 	}
1046 	return GF_OK;
1047 }
1048 
1049 
writegen_register(GF_FilterSession * session)1050 const GF_FilterRegister *writegen_register(GF_FilterSession *session)
1051 {
1052 
1053 	//assign runtime caps on first load
1054 	if (!strcmp(GenDumpCaps[3].val.value.string, "gpac")) {
1055 		GenDumpCaps[3].val.value.string = (char *) gf_pixel_fmt_all_shortnames();
1056 		GenDumpCaps[8].val.value.string = (char *) gf_audio_fmt_all_shortnames();
1057 		GenDumpArgs[1].min_max_enum = gf_pixel_fmt_all_names();
1058 		GenDumpArgs[2].min_max_enum = gf_audio_fmt_all_names();
1059 	}
1060 
1061 	return &GenDumpRegister;
1062 }
1063 
1064