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