Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2017-2021
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 : #include <gpac/xml.h>
30 : #include <gpac/base_coding.h>
31 :
32 : #include <gpac/internal/isomedia_dev.h>
33 :
34 : enum
35 : {
36 : DECINFO_NO=0,
37 : DECINFO_FIRST,
38 : DECINFO_SAP,
39 : DECINFO_AUTO
40 : };
41 :
42 : typedef struct
43 : {
44 : //opts
45 : Bool exporter, frame, split, merge_region;
46 : u32 sstart, send;
47 : u32 pfmt, afmt, decinfo;
48 : GF_Fraction dur;
49 :
50 : //only one input pid declared
51 : GF_FilterPid *ipid;
52 : //only one output pid declared
53 : GF_FilterPid *opid;
54 :
55 : u32 codecid;
56 : Bool is_mj2k;
57 : u32 sample_num;
58 :
59 : const char *dcfg;
60 : u32 dcfg_size;
61 : Bool cfg_sent;
62 :
63 : GF_Fraction64 duration;
64 : Bool first;
65 :
66 : GF_BitStream *bs;
67 :
68 : u32 target_pfmt, target_afmt;
69 : Bool is_bmp;
70 : u32 is_wav;
71 : u32 w, h, stride;
72 : u64 nb_bytes;
73 : Bool dash_mode;
74 : Bool trunc_audio;
75 :
76 : u64 first_dts_plus_one;
77 :
78 : Bool ttml_agg;
79 : GF_XMLNode *ttml_root;
80 : } GF_GenDumpCtx;
81 :
82 :
83 1779 : GF_Err writegen_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
84 : {
85 : u32 cid, chan, sr, w, h, stype, pf, sfmt, av1mode, nb_bps;
86 : const char *name, *mimetype;
87 : char szExt[GF_4CC_MSIZE], szCodecExt[30], *sep;
88 : const GF_PropertyValue *p;
89 1779 : GF_GenDumpCtx *ctx = gf_filter_get_udta(filter);
90 :
91 1779 : if (is_remove) {
92 0 : ctx->ipid = NULL;
93 0 : if (ctx->opid) {
94 0 : gf_filter_pid_remove(ctx->opid);
95 0 : ctx->opid = NULL;
96 : }
97 : return GF_OK;
98 : }
99 1779 : if (! gf_filter_pid_check_caps(pid))
100 : return GF_NOT_SUPPORTED;
101 :
102 1778 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_CODECID);
103 1778 : if (!p) return GF_NOT_SUPPORTED;
104 1778 : cid = p->value.uint;
105 :
106 1778 : ctx->codecid = cid;
107 1778 : if (!ctx->opid) {
108 949 : ctx->opid = gf_filter_pid_new(filter);
109 949 : ctx->first = GF_TRUE;
110 : }
111 :
112 1778 : ctx->ipid = pid;
113 :
114 : //copy properties at init or reconfig
115 1778 : gf_filter_pid_copy_properties(ctx->opid, pid);
116 1778 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DECODER_CONFIG, NULL);
117 :
118 1778 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_STREAM_TYPE);
119 1778 : stype = p ? p->value.uint : 0;
120 :
121 1778 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_SAMPLE_RATE);
122 1778 : sr = p ? p->value.uint : 0;
123 1778 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_NUM_CHANNELS);
124 1778 : chan = p ? p->value.uint : 0;
125 1778 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_AUDIO_FORMAT);
126 1778 : sfmt = p ? p->value.uint : GF_AUDIO_FMT_S16;
127 1778 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_AUDIO_BPS);
128 1778 : nb_bps = p ? p->value.uint : 0;
129 :
130 :
131 1778 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_WIDTH);
132 1778 : ctx->w = w = p ? p->value.uint : 0;
133 1778 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_HEIGHT);
134 1778 : ctx->h = h = p ? p->value.uint : 0;
135 :
136 1778 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_PIXFMT);
137 1778 : pf = p ? p->value.uint : 0;
138 1527 : if (!pf) pf = GF_PIXEL_YUV;
139 :
140 1778 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_DECODER_CONFIG);
141 1778 : if (p) {
142 19 : ctx->dcfg = p->value.data.ptr;
143 19 : ctx->dcfg_size = p->value.data.size;
144 : }
145 1778 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_DASH_MODE);
146 1778 : ctx->dash_mode = (p && p->value.uint) ? GF_TRUE : GF_FALSE;
147 :
148 1778 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_STREAM_TYPE, &PROP_UINT(GF_STREAM_FILE) );
149 :
150 : //special case for xml text, override to xml
151 1778 : switch (cid) {
152 : case GF_CODECID_META_XML:
153 : case GF_CODECID_SUBS_XML:
154 : strcpy(szCodecExt, "xml");
155 : break;
156 1767 : default:
157 1767 : strncpy(szCodecExt, gf_codecid_file_ext(cid), 29);
158 1767 : szCodecExt[29]=0;
159 1767 : sep = strchr(szCodecExt, '|');
160 1767 : if (sep) sep[0] = 0;
161 : break;
162 : }
163 1778 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_FILE_EXT, &PROP_STRING(szCodecExt) );
164 :
165 1778 : mimetype = gf_codecid_mime(cid);
166 :
167 1778 : switch (cid) {
168 13 : case GF_CODECID_AAC_MPEG4:
169 : case GF_CODECID_AAC_MPEG2_MP:
170 : case GF_CODECID_AAC_MPEG2_LCP:
171 : case GF_CODECID_AAC_MPEG2_SSRP:
172 : //override extension to latm for aac if unframed latm data - NOT for usac
173 13 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_UNFRAMED_LATM);
174 13 : if (p && p->value.boolean) {
175 2 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_FILE_EXT, &PROP_STRING("latm") );
176 : }
177 : break;
178 40 : case GF_CODECID_PNG:
179 : case GF_CODECID_JPEG:
180 40 : ctx->split = GF_TRUE;
181 40 : break;
182 1 : case GF_CODECID_J2K:
183 1 : ctx->split = GF_TRUE;
184 1 : ctx->is_mj2k = GF_TRUE;
185 1 : break;
186 3 : case GF_CODECID_AMR:
187 3 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_MIME, &PROP_STRING(mimetype) );
188 3 : ctx->dcfg = "#!AMR\n";
189 3 : ctx->dcfg_size = 6;
190 3 : ctx->decinfo = DECINFO_FIRST;
191 3 : break;
192 2 : case GF_CODECID_AMR_WB:
193 2 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_MIME, &PROP_STRING(mimetype) );
194 2 : ctx->dcfg = "#!AMR-WB\n";
195 2 : ctx->dcfg_size = 9;
196 2 : ctx->decinfo = DECINFO_FIRST;
197 2 : break;
198 0 : case GF_CODECID_SMV:
199 0 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_MIME, &PROP_STRING(mimetype) );
200 0 : ctx->dcfg = "#!SMV\n";
201 0 : ctx->dcfg_size = 6;
202 0 : ctx->decinfo = DECINFO_FIRST;
203 0 : break;
204 0 : case GF_CODECID_EVRC_PV:
205 : case GF_CODECID_EVRC:
206 0 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_MIME, &PROP_STRING(mimetype) );
207 0 : ctx->dcfg = "#!EVRC\n";
208 0 : ctx->dcfg_size = 7;
209 0 : ctx->decinfo = DECINFO_FIRST;
210 0 : break;
211 :
212 1 : case GF_CODECID_FLAC:
213 1 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_MIME, &PROP_STRING(mimetype) );
214 1 : ctx->decinfo = DECINFO_FIRST;
215 1 : break;
216 :
217 :
218 18 : case GF_CODECID_SIMPLE_TEXT:
219 18 : if (!gf_filter_pid_get_property(pid, GF_PROP_PID_MIME))
220 18 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_MIME, &PROP_STRING(mimetype) );
221 18 : if (ctx->decinfo == DECINFO_AUTO)
222 18 : ctx->decinfo = DECINFO_FIRST;
223 : break;
224 0 : case GF_CODECID_META_TEXT:
225 0 : if (!gf_filter_pid_get_property(pid, GF_PROP_PID_MIME))
226 0 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_MIME, &PROP_STRING(mimetype) );
227 0 : if (ctx->decinfo == DECINFO_AUTO)
228 0 : ctx->decinfo = DECINFO_FIRST;
229 : break;
230 2 : case GF_CODECID_META_XML:
231 2 : if (!gf_filter_pid_get_property(pid, GF_PROP_PID_MIME))
232 2 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_MIME, &PROP_STRING(mimetype) );
233 2 : if (ctx->decinfo == DECINFO_AUTO)
234 2 : ctx->decinfo = DECINFO_FIRST;
235 : break;
236 0 : case GF_CODECID_SUBS_TEXT:
237 0 : if (!gf_filter_pid_get_property(pid, GF_PROP_PID_MIME))
238 0 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_MIME, &PROP_STRING(mimetype) );
239 0 : if (ctx->decinfo == DECINFO_AUTO)
240 0 : ctx->decinfo = DECINFO_FIRST;
241 : break;
242 9 : case GF_CODECID_SUBS_XML:
243 9 : if (!gf_filter_pid_get_property(pid, GF_PROP_PID_MIME))
244 9 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_MIME, &PROP_STRING(mimetype) );
245 :
246 9 : if (!ctx->frame) {
247 7 : ctx->ttml_agg = GF_TRUE;
248 : } else {
249 2 : ctx->split = GF_TRUE;
250 : }
251 9 : if (ctx->decinfo == DECINFO_AUTO)
252 9 : ctx->decinfo = DECINFO_FIRST;
253 : break;
254 :
255 4 : case GF_CODECID_AV1:
256 : av1mode = 0;
257 4 : p = gf_filter_pid_get_property_str(ctx->ipid, "obu:mode");
258 4 : if (p) av1mode = p->value.uint;
259 4 : if (av1mode==1) {
260 2 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_FILE_EXT, &PROP_STRING("av1b") );
261 2 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_MIME, &PROP_STRING("video/x-av1b") );
262 2 : } else if (av1mode==2) {
263 1 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_FILE_EXT, &PROP_STRING("ivf") );
264 1 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_MIME, &PROP_STRING("video/x-ivf") );
265 : } else {
266 1 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_FILE_EXT, &PROP_STRING("obu") );
267 1 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_MIME, &PROP_STRING("video/x-av1") );
268 : }
269 : break;
270 1592 : case GF_CODECID_RAW:
271 1592 : ctx->dcfg = NULL;
272 1592 : ctx->dcfg_size = 0;
273 1592 : if (stype==GF_STREAM_VISUAL) {
274 1487 : strcpy(szExt, gf_pixel_fmt_sname(ctx->target_pfmt ? ctx->target_pfmt : pf));
275 1487 : p = gf_filter_pid_caps_query(ctx->opid, GF_PROP_PID_FILE_EXT);
276 1487 : if (p) {
277 1487 : strncpy(szExt, p->value.string, GF_4CC_MSIZE-1);
278 1487 : szExt[GF_4CC_MSIZE-1] = 0;
279 1487 : if (!strcmp(szExt, "bmp")) {
280 3 : ctx->is_bmp = GF_TRUE;
281 : //request BGR
282 3 : ctx->target_pfmt = GF_PIXEL_BGR;
283 3 : ctx->split = GF_TRUE;
284 : } else {
285 1484 : ctx->target_pfmt = gf_pixel_fmt_parse(szExt);
286 1484 : if (!ctx->target_pfmt) {
287 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("Cannot guess pixel format from extension type %s\n", szExt));
288 : return GF_NOT_SUPPORTED;
289 : }
290 1484 : strcpy(szExt, gf_pixel_fmt_sname(ctx->target_pfmt));
291 : }
292 : //forcing pixel format regardless of extension
293 1487 : if (ctx->pfmt) {
294 15 : if (pf != ctx->pfmt) {
295 0 : gf_filter_pid_negociate_property(ctx->ipid, GF_PROP_PID_PIXFMT, &PROP_UINT(ctx->pfmt));
296 : //make sure we reconfigure
297 0 : ctx->codecid = 0;
298 0 : pf = ctx->pfmt;
299 : }
300 : }
301 : //use extension to derive pixel format
302 1472 : else if (pf != ctx->target_pfmt) {
303 80 : gf_filter_pid_negociate_property(ctx->ipid, GF_PROP_PID_PIXFMT, &PROP_UINT(ctx->target_pfmt));
304 80 : strcpy(szExt, gf_pixel_fmt_sname(ctx->target_pfmt));
305 : //make sure we reconfigure
306 80 : ctx->codecid = 0;
307 : }
308 : }
309 :
310 1487 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_STRIDE);
311 1487 : ctx->stride = p ? p->value.uint : 0;
312 :
313 1487 : if (!ctx->stride) {
314 151 : gf_pixel_get_size_info(ctx->target_pfmt ? ctx->target_pfmt : pf, ctx->w, ctx->h, NULL, &ctx->stride, NULL, NULL, NULL);
315 : }
316 :
317 105 : } else if (stype==GF_STREAM_AUDIO) {
318 105 : strcpy(szExt, gf_audio_fmt_sname(ctx->target_afmt ? ctx->target_afmt : sfmt));
319 105 : p = gf_filter_pid_caps_query(ctx->opid, GF_PROP_PID_FILE_EXT);
320 105 : if (p) {
321 105 : strncpy(szExt, p->value.string, GF_4CC_MSIZE-1);
322 105 : szExt[GF_4CC_MSIZE-1] = 0;
323 105 : if (!strcmp(szExt, "wav")) {
324 2 : ctx->is_wav = GF_TRUE;
325 : //request PCMs16 ?
326 : // ctx->target_afmt = GF_AUDIO_FMT_S16;
327 2 : ctx->target_afmt = sfmt;
328 : } else {
329 103 : ctx->target_afmt = gf_audio_fmt_parse(szExt);
330 103 : strcpy(szExt, gf_audio_fmt_sname(ctx->target_afmt));
331 : }
332 : //forcing sample format regardless of extension
333 105 : if (ctx->afmt) {
334 0 : if (sfmt != ctx->afmt) {
335 0 : gf_filter_pid_negociate_property(ctx->ipid, GF_PROP_PID_AUDIO_FORMAT, &PROP_UINT(ctx->afmt));
336 : //make sure we reconfigure
337 0 : ctx->codecid = 0;
338 0 : sfmt = ctx->afmt;
339 : }
340 : }
341 : //use extension to derive sample format
342 105 : else if (sfmt != ctx->target_afmt) {
343 31 : gf_filter_pid_negociate_property(ctx->ipid, GF_PROP_PID_AUDIO_FORMAT, &PROP_UINT(ctx->target_afmt));
344 31 : strcpy(szExt, gf_audio_fmt_sname(ctx->target_afmt));
345 : //make sure we reconfigure
346 31 : ctx->codecid = 0;
347 : }
348 105 : if (ctx->dur.num && ctx->dur.den && !gf_audio_fmt_is_planar(ctx->target_afmt ? ctx->target_afmt : ctx->afmt))
349 29 : ctx->trunc_audio = GF_TRUE;
350 : }
351 :
352 : } else {
353 0 : strcpy(szExt, gf_4cc_to_str(cid));
354 : }
355 1592 : if (ctx->is_bmp) strcpy(szExt, "bmp");
356 1589 : else if (ctx->is_wav) {
357 2 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DISABLE_PROGRESSIVE, &PROP_UINT(GF_PID_FILE_PATCH_REPLACE) );
358 : strcpy(szExt, "wav");
359 1587 : } else if (!strlen(szExt)) strcpy(szExt, "raw");
360 :
361 1592 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_FILE_EXT, &PROP_STRING( szExt ) );
362 1592 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_MIME, &PROP_STRING("application/octet-string") );
363 1592 : if (!ctx->codecid) return GF_OK;
364 : break;
365 :
366 93 : default:
367 93 : if (!strcmp(szCodecExt, "raw")) {
368 0 : strcpy(szExt, gf_4cc_to_str(cid));
369 0 : if (!strlen(szExt)) strcpy(szExt, "raw");
370 0 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_FILE_EXT, &PROP_STRING( szExt ) );
371 : } else {
372 93 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_FILE_EXT, &PROP_STRING( szCodecExt ) );
373 : }
374 93 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_MIME, &PROP_STRING(mimetype) );
375 93 : break;
376 : }
377 :
378 1667 : if (ctx->decinfo == DECINFO_AUTO)
379 916 : ctx->decinfo = DECINFO_NO;
380 :
381 1667 : name = gf_codecid_name(cid);
382 1667 : if (ctx->exporter) {
383 26 : if (w && h) {
384 11 : if (cid==GF_CODECID_RAW) name = gf_pixel_fmt_name(pf);
385 11 : GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("Exporting %s - Size %dx%d\n", name, w, h));
386 15 : } else if (sr && chan) {
387 1 : if (cid==GF_CODECID_RAW) {
388 0 : 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) ));
389 : } else {
390 1 : if (!nb_bps)
391 1 : nb_bps = gf_audio_fmt_bit_depth(sfmt);
392 :
393 1 : GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("Exporting %s - SampleRate %d %d channels %d bits per sample\n", name, sr, chan, nb_bps ));
394 : }
395 : } else {
396 14 : GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("Exporting %s\n", name));
397 : }
398 : }
399 :
400 : //avoid creating a file when dumping individual samples
401 1667 : if (ctx->split) {
402 45 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_NB_FRAMES);
403 45 : if (!p || (p->value.uint>1))
404 25 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PCK_FILENUM, &PROP_UINT(0) );
405 : else
406 20 : ctx->split = GF_FALSE;
407 1622 : } else if (ctx->frame) {
408 12 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PCK_FILENUM, &PROP_UINT(0) );
409 : }
410 :
411 1667 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_DURATION);
412 1667 : if (p) ctx->duration = p->value.lfrac;
413 :
414 1667 : gf_filter_pid_set_framing_mode(pid, GF_TRUE);
415 1667 : return GF_OK;
416 : }
417 :
418 1 : static GF_FilterPacket *writegen_write_j2k(GF_GenDumpCtx *ctx, char *data, u32 data_size, GF_FilterPacket *in_pck)
419 : {
420 : u32 size;
421 : u8 *output;
422 : GF_FilterPacket *dst_pck;
423 : char sig[8];
424 1 : sig[0] = sig[1] = sig[2] = 0;
425 1 : sig[3] = 0xC;
426 1 : sig[4] = 'j';
427 1 : sig[5] = 'P';
428 1 : sig[6] = sig[7] = ' ';
429 :
430 1 : if ((data_size>16) && !memcmp(data, sig, 8)) {
431 0 : return gf_filter_pck_new_ref(ctx->opid, 0, 0, in_pck);
432 : }
433 :
434 1 : size = data_size + 8*4 /*jP%20%20 + ftyp*/ + ctx->dcfg_size + 8;
435 :
436 1 : dst_pck = gf_filter_pck_new_alloc(ctx->opid, size, &output);
437 1 : if (!dst_pck) return NULL;
438 :
439 :
440 1 : if (!ctx->bs) ctx->bs = gf_bs_new(output, size, GF_BITSTREAM_WRITE);
441 0 : else gf_bs_reassign_buffer(ctx->bs, output, size);
442 :
443 1 : gf_bs_write_u32(ctx->bs, 12);
444 1 : gf_bs_write_u32(ctx->bs, GF_ISOM_BOX_TYPE_JP);
445 1 : gf_bs_write_u32(ctx->bs, 0x0D0A870A);
446 1 : gf_bs_write_u32(ctx->bs, 20);
447 1 : gf_bs_write_u32(ctx->bs, GF_ISOM_BOX_TYPE_FTYP);
448 1 : gf_bs_write_u32(ctx->bs, GF_ISOM_BRAND_JP2);
449 1 : gf_bs_write_u32(ctx->bs, 0);
450 1 : gf_bs_write_u32(ctx->bs, GF_ISOM_BRAND_JP2);
451 :
452 : //todo, write colr and other info ?
453 1 : if (ctx->dcfg) {
454 1 : gf_bs_write_u32(ctx->bs, 8+ctx->dcfg_size);
455 1 : gf_bs_write_u32(ctx->bs, GF_ISOM_BOX_TYPE_JP2H);
456 1 : gf_bs_write_data(ctx->bs, ctx->dcfg, ctx->dcfg_size);
457 : }
458 1 : gf_bs_write_data(ctx->bs, data, data_size);
459 :
460 1 : return dst_pck;
461 : }
462 :
463 : #ifdef WIN32
464 : #include <windows.h>
465 : #else
466 : typedef struct tagBITMAPFILEHEADER
467 : {
468 : u16 bfType;
469 : u32 bfSize;
470 : u16 bfReserved1;
471 : u16 bfReserved2;
472 : u32 bfOffBits;
473 : } BITMAPFILEHEADER;
474 :
475 : typedef struct tagBITMAPINFOHEADER {
476 : u32 biSize;
477 : s32 biWidth;
478 : s32 biHeight;
479 : u16 biPlanes;
480 : u16 biBitCount;
481 : u32 biCompression;
482 : u32 biSizeImage;
483 : s32 biXPelsPerMeter;
484 : s32 biYPelsPerMeter;
485 : u32 biClrUsed;
486 : u32 biClrImportant;
487 : } BITMAPINFOHEADER;
488 :
489 : #define BI_RGB 0L
490 :
491 : #endif
492 :
493 1 : static GF_FilterPacket *writegen_write_bmp(GF_GenDumpCtx *ctx, char *data, u32 data_size)
494 : {
495 : u32 size;
496 : u8 *output;
497 : BITMAPFILEHEADER fh;
498 : BITMAPINFOHEADER fi;
499 : GF_FilterPacket *dst_pck;
500 : u32 i;
501 :
502 1 : size = ctx->w*ctx->h*3 + 54; //14 + 40 = size of BMP file header and BMP file info;
503 1 : dst_pck = gf_filter_pck_new_alloc(ctx->opid, size, &output);
504 1 : if (!dst_pck) return NULL;
505 :
506 : memset(&fh, 0, sizeof(fh));
507 1 : fh.bfType = 19778;
508 1 : fh.bfOffBits = 54;
509 :
510 1 : if (!ctx->bs) ctx->bs = gf_bs_new(output, size, GF_BITSTREAM_WRITE);
511 0 : else gf_bs_reassign_buffer(ctx->bs, output, size);
512 :
513 1 : gf_bs_write_data(ctx->bs, (const char *) &fh.bfType, 2);
514 1 : gf_bs_write_data(ctx->bs, (const char *) &fh.bfSize, 4);
515 1 : gf_bs_write_data(ctx->bs, (const char *) &fh.bfReserved1, 2);
516 1 : gf_bs_write_data(ctx->bs, (const char *) &fh.bfReserved2, 2);
517 1 : gf_bs_write_data(ctx->bs, (const char *) &fh.bfOffBits, 4);
518 :
519 : memset(&fi, 0, sizeof(char)*40);
520 1 : fi.biSize = 40;
521 1 : fi.biWidth = ctx->w;
522 1 : fi.biHeight = ctx->h;
523 1 : fi.biPlanes = 1;
524 1 : fi.biBitCount = 24;
525 : fi.biCompression = BI_RGB;
526 1 : fi.biSizeImage = ctx->w * ctx->h * 3;
527 :
528 1 : memcpy(output+14, &fi, sizeof(char)*40);
529 : //reverse lines
530 1 : output += sizeof(u8) * 54;
531 130 : for (i=ctx->h; i>0; i--) {
532 128 : u8 *ptr = data + (i-1)*ctx->stride;
533 128 : memcpy(output, ptr, sizeof(u8)*3*ctx->w);
534 128 : output += 3*ctx->w;
535 : }
536 : return dst_pck;
537 : }
538 :
539 1 : static void writegen_write_wav_header(GF_GenDumpCtx *ctx)
540 : {
541 : u32 size;
542 : u8 *output;
543 : GF_FilterPacket *dst_pck;
544 : const GF_PropertyValue *p;
545 : u32 nb_ch, sample_rate, afmt, bps;
546 1 : const char chunkID[] = {'R', 'I', 'F', 'F'};
547 1 : const char format[] = {'W', 'A', 'V', 'E'};
548 1 : const char subchunk1ID[] = {'f', 'm', 't', ' '};
549 1 : const char subchunk2ID[] = {'d', 'a', 't', 'a'};
550 :
551 1 : if (ctx->is_wav!=1) return;
552 1 : ctx->is_wav = 2;
553 :
554 1 : p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_SAMPLE_RATE);
555 1 : if (!p) return;
556 1 : sample_rate = p->value.uint;
557 1 : p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_NUM_CHANNELS);
558 1 : if (!p) return;
559 1 : nb_ch = p->value.uint;
560 1 : p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_AUDIO_FORMAT);
561 1 : if (!p) return;
562 1 : afmt = p->value.uint;
563 :
564 1 : bps = gf_audio_fmt_bit_depth(afmt);
565 :
566 : size = 44;
567 1 : dst_pck = gf_filter_pck_new_alloc(ctx->opid, size, &output);
568 1 : if (!dst_pck) return;
569 :
570 1 : if (!ctx->bs) ctx->bs = gf_bs_new(output, size, GF_BITSTREAM_WRITE);
571 0 : else gf_bs_reassign_buffer(ctx->bs, output, size);
572 :
573 1 : gf_bs_write_data(ctx->bs, chunkID, 4);
574 1 : gf_bs_write_u32_le(ctx->bs, (u32) ctx->nb_bytes + 36);
575 1 : gf_bs_write_data(ctx->bs, format, 4);
576 :
577 1 : gf_bs_write_data(ctx->bs, subchunk1ID, 4);
578 1 : gf_bs_write_u32_le(ctx->bs, 16); //subchunk1 size
579 1 : gf_bs_write_u16_le(ctx->bs, 1); //audio format
580 1 : gf_bs_write_u16_le(ctx->bs, nb_ch);
581 1 : gf_bs_write_u32_le(ctx->bs, sample_rate);
582 1 : gf_bs_write_u32_le(ctx->bs, sample_rate * nb_ch * bps / 8); //byte rate
583 1 : gf_bs_write_u16_le(ctx->bs, nb_ch * bps / 8); // block align
584 1 : gf_bs_write_u16_le(ctx->bs, bps);
585 :
586 1 : gf_bs_write_data(ctx->bs, subchunk2ID, 4);
587 1 : gf_bs_write_u32_le(ctx->bs, (u32) ctx->nb_bytes);
588 :
589 1 : gf_filter_pck_set_framing(dst_pck, GF_FALSE, GF_FALSE);
590 1 : gf_filter_pck_set_byte_offset(dst_pck, 0);
591 1 : gf_filter_pck_set_seek_flag(dst_pck, GF_TRUE);
592 1 : gf_filter_pck_send(dst_pck);
593 : }
594 :
595 :
596 12 : static GF_XMLAttribute *ttml_get_attr(GF_XMLNode *node, char *name)
597 : {
598 12 : u32 i=0;
599 : GF_XMLAttribute *att;
600 26 : while (node && (att = gf_list_enum(node->attributes, &i)) ) {
601 14 : if (!strcmp(att->name, name)) return att;
602 : }
603 : return NULL;
604 : }
605 40 : static GF_XMLNode *ttml_locate_div(GF_XMLNode *body, const char *region_name, u32 div_idx)
606 : {
607 40 : u32 i=0, loc_div_idx=0;
608 : GF_XMLNode *div;
609 120 : while ( (div = gf_list_enum(body->content, &i)) ) {
610 80 : if (div->type) continue;
611 40 : if (strcmp(div->name, "div")) continue;
612 :
613 40 : if (!region_name) {
614 40 : if (div_idx==loc_div_idx) return div;
615 0 : loc_div_idx++;
616 : } else {
617 0 : GF_XMLAttribute *att = ttml_get_attr(div, "region");
618 0 : if (att && att->value && !strcmp(att->value, region_name))
619 : return div;
620 : }
621 : }
622 0 : if (region_name) {
623 0 : return ttml_locate_div(body, NULL, div_idx);
624 : }
625 : return NULL;
626 : }
627 :
628 84 : static GF_XMLNode *ttml_get_body(GF_XMLNode *root)
629 : {
630 84 : u32 i=0;
631 : GF_XMLNode *child;
632 412 : while (root && (child = gf_list_enum(root->content, &i)) ) {
633 324 : if (child->type) continue;
634 160 : if (!strcmp(child->name, "body")) return child;
635 : }
636 : return NULL;
637 : }
638 :
639 206 : static Bool ttml_same_attr(GF_XMLNode *n1, GF_XMLNode *n2)
640 : {
641 206 : u32 i=0;
642 : GF_XMLAttribute *att1;
643 206 : while ( (att1 = gf_list_enum(n1->attributes, &i))) {
644 : Bool found = GF_FALSE;
645 206 : u32 j=0;
646 : GF_XMLAttribute *att2;
647 1023 : while ( (att2 = gf_list_enum(n2->attributes, &j))) {
648 817 : if (!strcmp(att1->name, att2->name) && !strcmp(att1->value, att2->value)) {
649 : found = GF_TRUE;
650 : break;
651 : }
652 : }
653 206 : if (!found) return GF_FALSE;
654 : }
655 : return GF_TRUE;
656 : }
657 :
658 69 : static GF_Err ttml_embed_data(GF_XMLNode *node, u8 *aux_data, u32 aux_data_size, u8 *subs_data, u32 subs_data_size)
659 : {
660 69 : u32 i=0;
661 : GF_XMLNode *child;
662 : u32 subs_idx=0;
663 : GF_XMLAttribute *att;
664 : Bool is_source = GF_FALSE;
665 : Bool has_src_att = GF_FALSE;
666 69 : if (!node || node->type) return GF_BAD_PARAM;
667 :
668 69 : if (!strcmp(node->name, "source")) {
669 : is_source = GF_TRUE;
670 : }
671 :
672 187 : while ((att = gf_list_enum(node->attributes, &i))) {
673 : char *sep, *fext;
674 126 : if (strcmp(att->name, "src")) continue;
675 : has_src_att = GF_TRUE;
676 9 : if (strncmp(att->value, "urn:", 4)) continue;
677 8 : sep = strrchr(att->value, ':');
678 8 : if (!sep) continue;
679 8 : sep++;
680 8 : fext = gf_file_ext_start(sep);
681 8 : if (fext) fext[0] = 0;
682 8 : subs_idx = atoi(sep);
683 8 : if (fext) fext[0] = '.';
684 8 : if (!subs_idx || ((subs_idx-1) * 14 > subs_data_size)) {
685 : subs_idx = 0;
686 0 : continue;
687 : }
688 : break;
689 : }
690 69 : if (subs_idx) {
691 : GF_XMLNode *data;
692 : u32 subs_offset = 0;
693 : u32 subs_size = 0;
694 : u32 idx = 1;
695 : //fetch subsample info
696 10 : for (i=0; i<subs_data_size; i+=14) {
697 10 : u32 a_subs_size = subs_data[i+4];
698 10 : a_subs_size <<= 8;
699 10 : a_subs_size |= subs_data[i+5];
700 10 : a_subs_size <<= 8;
701 10 : a_subs_size |= subs_data[i+6];
702 10 : a_subs_size <<= 8;
703 10 : a_subs_size |= subs_data[i+7];
704 10 : if (idx==subs_idx) {
705 : subs_size = a_subs_size;
706 : break;
707 : }
708 2 : subs_offset += a_subs_size;
709 2 : idx++;
710 : }
711 8 : if (!subs_size || (subs_offset + subs_size > aux_data_size)) {
712 0 : if (!subs_size) {
713 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("No subsample with index %u in sample\n", subs_idx));
714 : } else {
715 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("Corrupted subsample %u info, size %u offset %u but sample size %u\n", subs_idx, subs_size, subs_offset, aux_data_size));
716 : }
717 : return GF_NON_COMPLIANT_BITSTREAM;
718 : }
719 :
720 : //remove src attribute
721 8 : gf_list_del_item(node->attributes, att);
722 8 : if (att->name) gf_free(att->name);
723 8 : if (att->value) gf_free(att->value);
724 8 : gf_free(att);
725 :
726 : //create a source node
727 8 : if (!is_source) {
728 : GF_XMLNode *s;
729 4 : GF_SAFEALLOC(s, GF_XMLNode);
730 4 : if (!s) return GF_OUT_OF_MEM;
731 4 : s->attributes = gf_list_new();
732 4 : s->content = gf_list_new();
733 4 : s->name = gf_strdup("source");
734 4 : gf_list_add(node->content, s);
735 4 : if (!s->name || !s->content || !s->attributes) return GF_OUT_OF_MEM;
736 : //move @type to source
737 4 : att = ttml_get_attr(node, "type");
738 4 : if (att) {
739 4 : gf_list_del_item(node->attributes, att);
740 4 : gf_list_add(s->attributes, att);
741 : }
742 : node = s;
743 : }
744 :
745 : //create a data node
746 8 : GF_SAFEALLOC(data, GF_XMLNode);
747 8 : if (!data) return GF_OUT_OF_MEM;
748 8 : data->attributes = gf_list_new();
749 8 : data->content = gf_list_new();
750 8 : data->name = gf_strdup("data");
751 8 : gf_list_add(node->content, data);
752 8 : if (!data->name || !data->content || !data->attributes) return GF_OUT_OF_MEM;
753 : //move @type to data
754 8 : att = ttml_get_attr(node, "type");
755 8 : if (att) {
756 8 : gf_list_del_item(node->attributes, att);
757 8 : gf_list_add(data->attributes, att);
758 : }
759 : //base64 encode in a child
760 8 : GF_SAFEALLOC(node, GF_XMLNode)
761 8 : if (!node) return GF_OUT_OF_MEM;
762 8 : node->type = GF_XML_TEXT_TYPE;
763 8 : node->name = gf_malloc(sizeof(u8) * subs_size * 2);
764 8 : if (!node->name) {
765 0 : gf_free(node);
766 0 : return GF_OUT_OF_MEM;
767 : }
768 8 : subs_size = gf_base64_encode(aux_data + subs_offset, subs_size, (u8*) node->name, subs_size * 2);
769 8 : node->name[subs_size] = 0;
770 8 : return gf_list_add(data->content, node);
771 : }
772 : //src was present but not an embedded data, do not recurse
773 61 : if (has_src_att) return GF_OK;
774 :
775 60 : i=0;
776 294 : while ((child = gf_list_enum(node->content, &i))) {
777 174 : if (child->type) continue;
778 63 : ttml_embed_data(child, aux_data, aux_data_size, subs_data, subs_data_size);
779 : }
780 : return GF_OK;
781 : }
782 :
783 49 : static GF_Err writegen_push_ttml(GF_GenDumpCtx *ctx, char *data, u32 data_size, GF_FilterPacket *in_pck)
784 : {
785 49 : const GF_PropertyValue *subs = gf_filter_pck_get_property(in_pck, GF_PROP_PCK_SUBS);
786 : char *ttml_text = NULL;
787 : GF_Err e = GF_OK;
788 : u32 ttml_text_size;
789 : GF_DOMParser *dom;
790 : u32 txt_size, nb_children;
791 : u32 i, k, div_idx;
792 : GF_XMLNode *root_pck, *p_global, *p_pck, *body_pck, *body_global;
793 :
794 49 : if (subs) {
795 6 : if (subs->value.data.size < 14)
796 : return GF_NON_COMPLIANT_BITSTREAM;
797 6 : txt_size = subs->value.data.ptr[4];
798 6 : txt_size <<= 8;
799 6 : txt_size |= subs->value.data.ptr[5];
800 6 : txt_size <<= 8;
801 6 : txt_size |= subs->value.data.ptr[6];
802 6 : txt_size <<= 8;
803 6 : txt_size |= subs->value.data.ptr[7];
804 6 : if (txt_size>data_size)
805 : return GF_NON_COMPLIANT_BITSTREAM;
806 : } else {
807 : txt_size = data_size;
808 : }
809 49 : ttml_text_size = txt_size + 2;
810 49 : ttml_text = gf_malloc(sizeof(char) * ttml_text_size);
811 49 : if (!ttml_text) return GF_OUT_OF_MEM;
812 :
813 49 : memcpy(ttml_text, data, txt_size);
814 49 : ttml_text[txt_size] = 0;
815 49 : ttml_text[txt_size+1] = 0;
816 :
817 49 : dom = gf_xml_dom_new();
818 49 : if (!dom) return GF_OUT_OF_MEM;
819 49 : e = gf_xml_dom_parse_string(dom, ttml_text);
820 49 : if (e) {
821 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[XML] Invalid TTML doc: %s\n\tXML text was:\n%s", gf_xml_dom_get_error(dom), ttml_text));
822 : goto exit;
823 : }
824 49 : root_pck = gf_xml_dom_get_root(dom);
825 :
826 : //subsamples, replace all data embedded as subsample with base64 encoding
827 49 : if (subs && root_pck) {
828 6 : e = ttml_embed_data(root_pck, data+txt_size, data_size-txt_size, subs->value.data.ptr+14, subs->value.data.size-14);
829 6 : if (e) goto exit;
830 : }
831 :
832 49 : if (!ctx->ttml_root) {
833 7 : ctx->ttml_root = gf_xml_dom_detach_root(dom);
834 : goto exit;
835 : }
836 :
837 :
838 42 : body_pck = ttml_get_body(root_pck);
839 42 : body_global = ttml_get_body(ctx->ttml_root);
840 : div_idx = 0;
841 42 : nb_children = body_pck ? gf_list_count(body_pck->content) : 0;
842 120 : for (k=0; k<nb_children; k++) {
843 : GF_XMLAttribute *div_reg = NULL;
844 : GF_XMLNode *div_global, *div_pck;
845 120 : div_pck = gf_list_get(body_pck->content, k);
846 120 : if (div_pck->type) continue;
847 40 : if (strcmp(div_pck->name, "div")) continue;
848 :
849 40 : if (ctx->merge_region)
850 0 : div_reg = ttml_get_attr(div_pck, "region");
851 :
852 : //merge input doc
853 0 : div_global = ttml_locate_div(body_global, div_reg ? div_reg->value : NULL, div_idx);
854 :
855 40 : if (!div_global) {
856 0 : gf_list_rem(body_pck->content, k);
857 0 : gf_list_insert(body_global->content, div_pck, div_idx+1);
858 : div_idx++;
859 0 : continue;
860 : }
861 40 : div_idx++;
862 :
863 40 : i=0;
864 160 : while ( (p_pck = gf_list_enum(div_pck->content, &i)) ) {
865 : s32 idx;
866 : GF_XMLNode *txt;
867 120 : u32 j=0;
868 : Bool found = GF_FALSE;
869 200 : if (p_pck->type) continue;
870 40 : if (strcmp(p_pck->name, "p")) continue;
871 492 : while ( (p_global = gf_list_enum(div_global->content, &j)) ) {
872 452 : if (p_global->type) continue;
873 206 : if (strcmp(p_global->name, "p")) continue;
874 :
875 206 : if (ttml_same_attr(p_pck, p_global)) {
876 : found = GF_TRUE;
877 : break;
878 : }
879 : }
880 40 : if (found) continue;
881 :
882 : //insert this p - if last entry in global div is text, insert before
883 40 : txt = gf_list_last(div_global->content);
884 40 : if (txt && txt->type) {
885 40 : idx = gf_list_count(div_global->content) - 1;
886 : } else {
887 0 : idx = gf_list_count(div_global->content);
888 : }
889 :
890 40 : i--;
891 40 : gf_list_rem(div_pck->content, i);
892 40 : if (i) {
893 40 : txt = gf_list_get(div_pck->content, i-1);
894 40 : if (txt->type) {
895 40 : i--;
896 40 : gf_list_rem(div_pck->content, i);
897 40 : gf_list_insert(div_global->content, txt, idx);
898 40 : idx++;
899 : }
900 : }
901 40 : gf_list_insert(div_global->content, p_pck, idx);
902 :
903 : }
904 : }
905 :
906 49 : exit:
907 49 : if (ttml_text) gf_free(ttml_text);
908 49 : gf_xml_dom_del(dom);
909 : return e;
910 : }
911 :
912 7 : static GF_Err writegen_flush_ttml(GF_GenDumpCtx *ctx)
913 : {
914 : char *data;
915 : u8 *output;
916 : u32 size;
917 : GF_FilterPacket *pck;
918 7 : if (!ctx->ttml_root) return GF_OK;
919 :
920 7 : if (ctx->merge_region) {
921 : u32 i, count;
922 0 : GF_XMLNode *body_global = ttml_get_body(ctx->ttml_root);
923 0 : count = body_global ? gf_list_count(body_global->content) : 0;
924 0 : for (i=0; i<count; i++) {
925 : GF_XMLNode *child;
926 0 : GF_XMLNode *div = gf_list_get(body_global->content, i);
927 0 : if (div->type) continue;
928 0 : if (strcmp(div->name, "div")) continue;
929 0 : if (gf_list_count(div->content) > 1) continue;;
930 :
931 0 : child = gf_list_get(div->content, 0);
932 0 : if (child && !child->type) continue;;
933 :
934 0 : gf_list_rem(body_global->content, i);
935 0 : i--;
936 0 : count--;
937 0 : gf_xml_dom_node_del(div);
938 : }
939 : }
940 :
941 7 : data = gf_xml_dom_serialize_root(ctx->ttml_root, GF_FALSE, GF_FALSE);
942 7 : if (!data) return GF_OK;
943 7 : size = (u32) strlen(data);
944 7 : pck = gf_filter_pck_new_alloc(ctx->opid, size, &output);
945 7 : if (!pck) return GF_OUT_OF_MEM;
946 :
947 7 : memcpy(output, data, size);
948 7 : gf_free(data);
949 7 : gf_filter_pck_set_framing(pck, GF_TRUE, GF_TRUE);
950 7 : gf_xml_dom_node_del(ctx->ttml_root);
951 7 : ctx->ttml_root = NULL;
952 7 : return gf_filter_pck_send(pck);
953 : }
954 :
955 121890 : GF_Err writegen_process(GF_Filter *filter)
956 : {
957 121890 : GF_GenDumpCtx *ctx = gf_filter_get_udta(filter);
958 : GF_FilterPacket *pck, *dst_pck = NULL;
959 : char *data;
960 : u32 pck_size;
961 : Bool do_abort = GF_FALSE;
962 121890 : Bool split = ctx->split;
963 121890 : if (!ctx->ipid) return GF_EOS;
964 :
965 121890 : pck = gf_filter_pid_get_packet(ctx->ipid);
966 121890 : if (!pck || !ctx->codecid) {
967 42588 : if (gf_filter_pid_is_eos(ctx->ipid)) {
968 942 : if (ctx->is_wav) writegen_write_wav_header(ctx);
969 941 : else if (ctx->ttml_agg) writegen_flush_ttml(ctx);
970 942 : gf_filter_pid_set_eos(ctx->opid);
971 942 : return GF_EOS;
972 : }
973 : return GF_OK;
974 : }
975 79302 : ctx->sample_num++;
976 :
977 79302 : if (ctx->sstart) {
978 725 : if (ctx->sstart > ctx->sample_num) {
979 84 : gf_filter_pid_drop_packet(ctx->ipid);
980 84 : return GF_OK;
981 : }
982 641 : if ((ctx->sstart <= ctx->send) && (ctx->sample_num>ctx->send) ) {
983 : do_abort = GF_TRUE;
984 : }
985 78577 : } else if (ctx->dur.num && ctx->dur.den) {
986 23940 : u64 dts = gf_filter_pck_get_dts(pck);
987 23940 : if (dts==GF_FILTER_NO_TS)
988 17 : dts = gf_filter_pck_get_cts(pck);
989 :
990 23940 : if (!ctx->first_dts_plus_one) {
991 403 : ctx->first_dts_plus_one = dts+1;
992 : } else {
993 23537 : if (ctx->dur.den * (dts + 1 - ctx->first_dts_plus_one) > ctx->dur.num * gf_filter_pck_get_timescale(pck)) {
994 : do_abort = GF_TRUE;
995 : }
996 : }
997 : }
998 : if (do_abort) {
999 : GF_FilterEvent evt;
1000 365 : gf_filter_pid_drop_packet(ctx->ipid);
1001 365 : GF_FEVT_INIT(evt, GF_FEVT_STOP, ctx->ipid);
1002 365 : gf_filter_pid_send_event(ctx->ipid, &evt);
1003 : return GF_OK;
1004 : }
1005 :
1006 : //except in dash mode, force a new file if GF_PROP_PCK_FILENUM is set
1007 78853 : if (!ctx->dash_mode && (gf_filter_pck_get_property(pck, GF_PROP_PCK_FILENUM) != NULL)) {
1008 0 : ctx->cfg_sent = GF_FALSE;
1009 0 : ctx->first = GF_TRUE;
1010 : }
1011 :
1012 78853 : if (ctx->frame) {
1013 : split = GF_TRUE;
1014 78624 : } else if (ctx->dcfg_size && gf_filter_pck_get_sap(pck) && !ctx->is_mj2k && (ctx->decinfo!=DECINFO_NO) && !ctx->cfg_sent) {
1015 6 : dst_pck = gf_filter_pck_new_shared(ctx->opid, ctx->dcfg, ctx->dcfg_size, NULL);
1016 6 : if (!dst_pck) return GF_OUT_OF_MEM;
1017 :
1018 6 : gf_filter_pck_merge_properties(pck, dst_pck);
1019 6 : gf_filter_pck_set_framing(dst_pck, ctx->first, GF_FALSE);
1020 6 : ctx->first = GF_FALSE;
1021 6 : gf_filter_pck_set_readonly(dst_pck);
1022 6 : gf_filter_pck_send(dst_pck);
1023 6 : if ((ctx->decinfo==DECINFO_FIRST) && !ctx->split) {
1024 6 : ctx->dcfg_size = 0;
1025 6 : ctx->dcfg = NULL;
1026 : }
1027 6 : ctx->cfg_sent = GF_TRUE;
1028 6 : return GF_OK;
1029 : }
1030 78847 : ctx->cfg_sent = GF_FALSE;
1031 78847 : data = (char *) gf_filter_pck_get_data(pck, &pck_size);
1032 :
1033 78847 : if (ctx->is_mj2k) {
1034 1 : dst_pck = writegen_write_j2k(ctx, data, pck_size, pck);
1035 78846 : } else if (ctx->is_bmp) {
1036 1 : dst_pck = writegen_write_bmp(ctx, data, pck_size);
1037 78845 : } else if (ctx->is_wav && ctx->first) {
1038 : u8 * output;
1039 1 : dst_pck = gf_filter_pck_new_alloc(ctx->opid, 44, &output);
1040 1 : if (!dst_pck) return GF_OUT_OF_MEM;
1041 :
1042 1 : gf_filter_pck_merge_properties(pck, dst_pck);
1043 1 : gf_filter_pck_set_byte_offset(dst_pck, GF_FILTER_NO_BO);
1044 1 : gf_filter_pck_set_framing(dst_pck, GF_TRUE, GF_FALSE);
1045 1 : gf_filter_pck_set_corrupted(dst_pck, GF_TRUE);
1046 1 : ctx->first = GF_FALSE;
1047 1 : gf_filter_pck_send(dst_pck);
1048 1 : ctx->nb_bytes += 44;
1049 1 : return GF_OK;
1050 78844 : } else if (ctx->ttml_agg) {
1051 49 : GF_Err e = writegen_push_ttml(ctx, data, pck_size, pck);
1052 49 : ctx->first = GF_FALSE;
1053 49 : if (e) {
1054 0 : gf_filter_pid_drop_packet(ctx->ipid);
1055 0 : return e;
1056 : }
1057 : goto no_output;
1058 78795 : } else if (ctx->trunc_audio) {
1059 2375 : u64 dts = gf_filter_pck_get_dts(pck);
1060 2375 : if (dts==GF_FILTER_NO_TS)
1061 14 : dts = gf_filter_pck_get_cts(pck);
1062 :
1063 2375 : if (!ctx->first_dts_plus_one) {
1064 14 : ctx->first_dts_plus_one = dts+1;
1065 : } else {
1066 2361 : u32 timescale = gf_filter_pck_get_timescale(pck);
1067 2361 : u32 dur = gf_filter_pck_get_duration(pck);
1068 2361 : if (ctx->dur.den * (dts + dur + 1 - ctx->first_dts_plus_one) > ctx->dur.num * timescale) {
1069 : u32 bpp;
1070 : u8 *odata;
1071 : const GF_PropertyValue *p;
1072 7 : dur = ctx->dur.num * timescale / ctx->dur.den;
1073 7 : dur -= (u32) (dts + 1 - ctx->first_dts_plus_one);
1074 :
1075 7 : bpp = gf_audio_fmt_bit_depth(ctx->target_afmt);
1076 7 : p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_NUM_CHANNELS);
1077 7 : if (p) bpp *= p->value.uint;
1078 7 : bpp/= 8;
1079 :
1080 7 : p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_SAMPLE_RATE);
1081 7 : if (p && (p->value.uint != timescale)) {
1082 0 : dur *= p->value.uint;
1083 0 : dur /= timescale;
1084 : }
1085 : assert(pck_size >= bpp * dur);
1086 7 : pck_size = bpp * dur;
1087 :
1088 7 : dst_pck = gf_filter_pck_new_alloc(ctx->opid, pck_size, &odata);
1089 7 : if (dst_pck)
1090 7 : memcpy(odata, data, pck_size);
1091 : }
1092 : }
1093 :
1094 7 : if (!dst_pck) {
1095 2368 : dst_pck = gf_filter_pck_new_ref(ctx->opid, 0, 0, pck);
1096 : }
1097 :
1098 : } else {
1099 76420 : dst_pck = gf_filter_pck_new_ref(ctx->opid, 0, 0, pck);
1100 : }
1101 78797 : if (!dst_pck) return GF_OUT_OF_MEM;
1102 :
1103 78797 : gf_filter_pck_merge_properties(pck, dst_pck);
1104 : //don't keep byte offset
1105 78797 : gf_filter_pck_set_byte_offset(dst_pck, GF_FILTER_NO_BO);
1106 :
1107 78797 : if (split) {
1108 252 : gf_filter_pck_set_property(dst_pck, GF_PROP_PCK_FILENUM, &PROP_UINT(ctx->sample_num) );
1109 252 : gf_filter_pck_set_framing(dst_pck, GF_TRUE, GF_TRUE);
1110 : } else {
1111 78545 : gf_filter_pck_set_framing(dst_pck, ctx->first, GF_FALSE);
1112 78545 : ctx->first = GF_FALSE;
1113 : }
1114 :
1115 78797 : gf_filter_pck_set_seek_flag(dst_pck, 0);
1116 78797 : gf_filter_pck_send(dst_pck);
1117 78797 : ctx->nb_bytes += pck_size;
1118 :
1119 78846 : no_output:
1120 78846 : if (ctx->exporter) {
1121 1155 : u32 timescale = gf_filter_pck_get_timescale(pck);
1122 1155 : u64 ts = gf_filter_pck_get_dts(pck);
1123 1155 : if (ts==GF_FILTER_NO_TS)
1124 0 : ts = gf_filter_pck_get_cts(pck);
1125 1155 : if (ts!=GF_FILTER_NO_TS) {
1126 1155 : ts += gf_filter_pck_get_duration(pck);
1127 1155 : ts *= ctx->duration.den;
1128 1155 : ts /= timescale;
1129 1155 : gf_set_progress("Exporting", ts, ctx->duration.num);
1130 : }
1131 : }
1132 :
1133 78846 : gf_filter_pid_drop_packet(ctx->ipid);
1134 :
1135 78846 : return GF_OK;
1136 : }
1137 :
1138 : /*
1139 : We list capabilities per codec type, associating the codec type to the file extension. This allows,
1140 : when matching to an output filter accepting a given file extension to match the codec type in write_gen caps, and
1141 : setup the right filter chain
1142 : */
1143 : static GF_FilterCapability GenDumpCaps[] =
1144 : {
1145 : //raw color dump YUV and RGB - keep it as first for field extension assignment
1146 : //cf below
1147 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
1148 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_RAW),
1149 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
1150 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "gpac"),
1151 : {0},
1152 : //raw audio dump - keep it as second for field extension assignment
1153 : //cf below
1154 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
1155 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_RAW),
1156 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
1157 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "gpac" ),
1158 : {0},
1159 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
1160 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_RAW),
1161 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
1162 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "bmp"),
1163 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "image/bmp"),
1164 : {0},
1165 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
1166 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_RAW),
1167 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
1168 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "wav"),
1169 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "audio/wav|audio/wave"),
1170 : {0},
1171 :
1172 : //we accept unframed AVC (annex B format)
1173 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
1174 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_AVC),
1175 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_AVC_PS),
1176 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_SVC),
1177 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_MVC),
1178 : CAP_BOOL(GF_CAPS_INPUT,GF_PROP_PID_UNFRAMED, GF_TRUE),
1179 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
1180 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "264|h264|avc|svc|mvc"),
1181 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "video/avc|video/h264|video/svc|video/mvc"),
1182 : {0},
1183 :
1184 : //we accept unframed HEVC (annex B format)
1185 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
1186 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_HEVC),
1187 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_LHVC),
1188 : CAP_BOOL(GF_CAPS_INPUT,GF_PROP_PID_UNFRAMED, GF_TRUE),
1189 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
1190 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "265|h265|hvc|hevc|shvc|lhvc"),
1191 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "video/hevc|video/lhvc|video/shvc|video/mhvc"),
1192 : {0},
1193 :
1194 : //we accept unframed OBU (without size field)
1195 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
1196 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_AV1),
1197 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_VP8),
1198 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_VP9),
1199 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_VP10),
1200 : CAP_BOOL(GF_CAPS_INPUT,GF_PROP_PID_UNFRAMED, GF_TRUE),
1201 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
1202 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "obu|av1|av1b|ivf"),
1203 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "video/x-ivf|video/av1"),
1204 : {0},
1205 :
1206 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
1207 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_MPEG4_PART2),
1208 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
1209 : CAP_BOOL(GF_CAPS_INPUT,GF_PROP_PID_UNFRAMED, GF_TRUE),
1210 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "cmp|m4ve|m4v"),
1211 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "video/mp4v-es"),
1212 : {0},
1213 :
1214 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
1215 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_H263),
1216 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_S263),
1217 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
1218 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "h263|263|s263"),
1219 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "video/h263"),
1220 : {0},
1221 :
1222 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
1223 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_MPEG1),
1224 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
1225 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "m1v"),
1226 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "video/mpgv-es"),
1227 : {0},
1228 :
1229 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
1230 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_MPEG2_422),
1231 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_MPEG2_SNR),
1232 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_MPEG2_HIGH),
1233 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_MPEG2_MAIN),
1234 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_MPEG2_SIMPLE),
1235 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_MPEG2_SPATIAL),
1236 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
1237 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "m2v"),
1238 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "video/mpgv-es"),
1239 : {0},
1240 :
1241 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
1242 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_AP4H),
1243 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_AP4X),
1244 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_APCH),
1245 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_APCO),
1246 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_APCS),
1247 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_APCN),
1248 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
1249 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "prores"),
1250 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "video/prores"),
1251 : {0},
1252 :
1253 : //we accept unframed AAC + ADTS
1254 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
1255 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_AAC_MPEG4),
1256 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_AAC_MPEG2_MP),
1257 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_AAC_MPEG2_LCP),
1258 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_AAC_MPEG2_SSRP),
1259 : CAP_BOOL(GF_CAPS_INPUT,GF_PROP_PID_UNFRAMED, GF_TRUE),
1260 : CAP_BOOL(GF_CAPS_INPUT_EXCLUDED,GF_PROP_PID_UNFRAMED_LATM, GF_TRUE),
1261 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
1262 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "aac|adts"),
1263 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "audio/x-m4a|audio/aac|audio/aacp|audio/x-aac"),
1264 : {0},
1265 :
1266 : //we accept unframed AAC + LATM
1267 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
1268 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_AAC_MPEG4),
1269 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_AAC_MPEG2_MP),
1270 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_AAC_MPEG2_LCP),
1271 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_AAC_MPEG2_SSRP),
1272 : CAP_BOOL(GF_CAPS_INPUT,GF_PROP_PID_UNFRAMED_LATM, GF_TRUE),
1273 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
1274 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "latm"),
1275 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "audio/aac+latm"),
1276 : {0},
1277 :
1278 : //we accept unframed USAC + LATM
1279 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
1280 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_USAC),
1281 : CAP_BOOL(GF_CAPS_INPUT,GF_PROP_PID_UNFRAMED_LATM, GF_TRUE),
1282 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
1283 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "usac|xheaac|latm"),
1284 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "audio/xheaac+latm"),
1285 : {0},
1286 :
1287 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
1288 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_PNG),
1289 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
1290 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "png"),
1291 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "image/png"),
1292 : {0},
1293 :
1294 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
1295 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_JPEG),
1296 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
1297 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "jpg|jpeg"),
1298 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "image/jpg"),
1299 : {0},
1300 :
1301 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
1302 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_J2K),
1303 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
1304 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "jp2|j2k"),
1305 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "image/jp2"),
1306 : {0},
1307 :
1308 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
1309 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_V210),
1310 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
1311 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "v210"),
1312 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "video/x-raw-v210"),
1313 : {0},
1314 :
1315 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
1316 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_MPEG_AUDIO),
1317 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_MPEG2_PART3),
1318 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
1319 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "mp3|mp1|mp2"),
1320 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "audio/mp3|audio/x-mp3"),
1321 : {0},
1322 :
1323 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
1324 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_AMR),
1325 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_AMR_WB),
1326 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
1327 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "amr"),
1328 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "audio/amr"),
1329 : {0},
1330 :
1331 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
1332 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_SMV),
1333 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
1334 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "smv"),
1335 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "audio/smv"),
1336 : {0},
1337 :
1338 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
1339 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_EVRC_PV),
1340 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_EVRC),
1341 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
1342 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "evc"),
1343 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "audio/evrc"),
1344 : {0},
1345 :
1346 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
1347 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_AC3),
1348 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
1349 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "ac3"),
1350 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "audio/x-ac3|audio/ac3"),
1351 : {0},
1352 :
1353 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
1354 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_EAC3),
1355 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
1356 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "eac3"),
1357 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "audio/x-eac3|audio/eac3"),
1358 : {0},
1359 :
1360 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_SIMPLE_TEXT),
1361 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_META_TEXT),
1362 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_SUBS_TEXT),
1363 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "txt"),
1364 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "x-subtitle/srt|subtitle/srt|text/srt"),
1365 : {0},
1366 :
1367 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_META_XML),
1368 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_SUBS_XML),
1369 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "xml|txml|ttml"),
1370 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "subtitle/ttml|text/ttml|application/xml+ttml"),
1371 : {0},
1372 :
1373 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
1374 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_QCELP),
1375 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "qcelp"),
1376 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "audio/qcelp"),
1377 : {0},
1378 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
1379 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_THEORA),
1380 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "theo"),
1381 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "video/x-theora"),
1382 : {0},
1383 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
1384 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_VORBIS),
1385 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "vorb"),
1386 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "audio/x-vorbis"),
1387 : {0},
1388 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
1389 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_SPEEX),
1390 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "spx"),
1391 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "audio/x-speex"),
1392 : {0},
1393 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
1394 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_FLAC),
1395 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "flac"),
1396 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "audio/flac"),
1397 : {0},
1398 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
1399 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_MPHA),
1400 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_MHAS),
1401 : CAP_BOOL(GF_CAPS_INPUT,GF_PROP_PID_UNFRAMED, GF_TRUE),
1402 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "mhas"),
1403 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "audio/mpegh"),
1404 : {0},
1405 :
1406 : //we accept unframed VVC (annex B format)
1407 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
1408 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_VVC),
1409 : CAP_BOOL(GF_CAPS_INPUT,GF_PROP_PID_UNFRAMED, GF_TRUE),
1410 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
1411 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "266|h266|vvc|lvvc"),
1412 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "video/vvc|video/lvvc"),
1413 : {0},
1414 :
1415 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
1416 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_TRUEHD),
1417 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
1418 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "mlp"),
1419 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "audio/truehd"),
1420 : {0},
1421 :
1422 :
1423 : //anything else: only for explicit dump (filter loaded on purpose), otherwise don't load for filter link resolution
1424 : CAP_UINT(GF_CAPS_OUTPUT_LOADED_FILTER, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
1425 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "*"),
1426 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "*"),
1427 : //for the rest, we include everything, only specifies excluded ones from above and non-handled ones
1428 : CAP_UINT(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
1429 :
1430 : CAP_UINT(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_CODECID, GF_CODECID_AVC),
1431 : CAP_UINT(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_CODECID, GF_CODECID_AVC_PS),
1432 : CAP_UINT(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_CODECID, GF_CODECID_SVC),
1433 : CAP_UINT(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_CODECID, GF_CODECID_MVC),
1434 : CAP_UINT(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_CODECID, GF_CODECID_HEVC),
1435 : CAP_UINT(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_CODECID, GF_CODECID_LHVC),
1436 : CAP_UINT(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_CODECID, GF_CODECID_MPEG4_PART2),
1437 : CAP_UINT(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_CODECID, GF_CODECID_VVC),
1438 :
1439 : CAP_UINT(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_CODECID, GF_CODECID_MPEG2_PART3),
1440 : CAP_UINT(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_CODECID, GF_CODECID_MPEG_AUDIO),
1441 : CAP_UINT(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_CODECID, GF_CODECID_AAC_MPEG4),
1442 : CAP_UINT(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_CODECID, GF_CODECID_AAC_MPEG2_MP),
1443 : CAP_UINT(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_CODECID, GF_CODECID_AAC_MPEG2_LCP),
1444 : CAP_UINT(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_CODECID, GF_CODECID_AAC_MPEG2_SSRP),
1445 : // CAP_UINT(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_CODECID, GF_CODECID_RAW),
1446 :
1447 : //WebVTT needs rewrite
1448 : CAP_UINT(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_CODECID, GF_CODECID_WEBVTT),
1449 : //systems streams not dumpable to file
1450 : CAP_UINT(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_CODECID, GF_CODECID_BIFS),
1451 : CAP_UINT(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_CODECID, GF_CODECID_BIFS_V2),
1452 : CAP_UINT(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_CODECID, GF_CODECID_OD_V1),
1453 : CAP_UINT(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_CODECID, GF_CODECID_OD_V2),
1454 : //this one need QCP
1455 : CAP_UINT(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_CODECID, GF_CODECID_QCELP),
1456 :
1457 : //other not supported (yet)
1458 : CAP_UINT(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_CODECID, GF_CODECID_THEORA),
1459 : CAP_UINT(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_CODECID, GF_CODECID_VORBIS)
1460 : };
1461 :
1462 :
1463 : #define OFFS(_n) #_n, offsetof(GF_GenDumpCtx, _n)
1464 : static GF_FilterArgs GenDumpArgs[] =
1465 : {
1466 : { OFFS(exporter), "compatibility with old exporter, displays export results", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
1467 : { OFFS(pfmt), "pixel format for raw extract. If not set, derived from extension", GF_PROP_PIXFMT, "none", NULL, 0},
1468 : { OFFS(afmt), "audio format for raw extract. If not set, derived from extension", GF_PROP_PCMFMT, "none", NULL, 0},
1469 : { OFFS(decinfo), "decoder config insert mode\n"
1470 : "- no: never inserted\n"
1471 : "- first: inserted on first packet\n"
1472 : "- sap: inserted at each SAP\n"
1473 : "- auto: selects between no and first based on media type", GF_PROP_UINT, "auto", "no|first|sap|auto", GF_FS_ARG_HINT_ADVANCED},
1474 : { OFFS(split), "force one file per decoded frame", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
1475 : { OFFS(frame), "force single frame dump with no rewrite. In this mode, all codecids are supported", GF_PROP_BOOL, "false", NULL, 0},
1476 : { OFFS(sstart), "start number of frame to forward. If 0, all samples are forwarded", GF_PROP_UINT, "0", NULL, 0},
1477 : { 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},
1478 : { OFFS(dur), "duration of media to forward after first sample. If 0, all samples are forwarded", GF_PROP_FRACTION, "0", NULL, 0},
1479 : { OFFS(merge_region), "merge TTML regions with same ID while reassembling TTML doc", GF_PROP_BOOL, "false", NULL, 0},
1480 : {0}
1481 : };
1482 :
1483 : static GF_Err writegen_initialize(GF_Filter *filter);
1484 :
1485 951 : void writegen_finalize(GF_Filter *filter)
1486 : {
1487 951 : GF_GenDumpCtx *ctx = gf_filter_get_udta(filter);
1488 951 : if (ctx->bs) gf_bs_del(ctx->bs);
1489 951 : if (ctx->ttml_root)
1490 0 : gf_xml_dom_node_del(ctx->ttml_root);
1491 951 : }
1492 :
1493 : GF_FilterRegister GenDumpRegister = {
1494 : .name = "writegen",
1495 : GF_FS_SET_DESCRIPTION("Stream to file")
1496 : GF_FS_SET_HELP("Generic single stream to file converter, used when extracting/converting PIDs.\n"
1497 : "The writegen filter should usually not be explicetly loaded without a source ID specified, since the filter would likely match any pid connection.")
1498 : .private_size = sizeof(GF_GenDumpCtx),
1499 : .args = GenDumpArgs,
1500 : .initialize = writegen_initialize,
1501 : .finalize = writegen_finalize,
1502 : SETCAPS(GenDumpCaps),
1503 : .configure_pid = writegen_configure_pid,
1504 : .process = writegen_process
1505 : };
1506 :
1507 : static const GF_FilterCapability FrameDumpCaps[] =
1508 : {
1509 : CAP_BOOL(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
1510 : CAP_UINT(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_CODECID, GF_CODECID_NONE),
1511 : CAP_UINT(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_STREAM_TYPE, GF_STREAM_UNKNOWN),
1512 : CAP_UINT(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
1513 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE)
1514 : };
1515 :
1516 951 : static GF_Err writegen_initialize(GF_Filter *filter)
1517 : {
1518 951 : GF_GenDumpCtx *ctx = gf_filter_get_udta(filter);
1519 951 : if (ctx->frame) {
1520 14 : return gf_filter_override_caps(filter, (const GF_FilterCapability *) FrameDumpCaps, sizeof(FrameDumpCaps) / sizeof(GF_FilterCapability));
1521 : }
1522 : return GF_OK;
1523 : }
1524 :
1525 :
1526 2877 : const GF_FilterRegister *writegen_register(GF_FilterSession *session)
1527 : {
1528 :
1529 : //assign runtime caps on first load
1530 2877 : if (!strcmp(GenDumpCaps[3].val.value.string, "gpac")) {
1531 2740 : GenDumpCaps[3].val.value.string = (char *) gf_pixel_fmt_all_shortnames();
1532 2740 : GenDumpCaps[8].val.value.string = (char *) gf_audio_fmt_all_shortnames();
1533 2740 : GenDumpArgs[1].min_max_enum = gf_pixel_fmt_all_names();
1534 2740 : GenDumpArgs[2].min_max_enum = gf_audio_fmt_all_names();
1535 : }
1536 :
1537 2877 : return &GenDumpRegister;
1538 : }
1539 :
|