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 / NHML 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/base_coding.h>
30 :
31 : #include <gpac/internal/isomedia_dev.h>
32 :
33 : #ifndef GPAC_DISABLE_ZLIB
34 : #include <zlib.h>
35 : #endif
36 :
37 : typedef struct
38 : {
39 : //opts
40 : const char *name;
41 : Bool exporter, dims, pckp, nhmlonly, chksum;
42 : FILE *filep;
43 :
44 :
45 : //only one input pid declared
46 : GF_FilterPid *ipid;
47 : //only one output pid declared
48 : GF_FilterPid *opid_nhml, *opid_mdia, *opid_info;
49 :
50 : u32 codecid;
51 : u32 streamtype;
52 : u32 oti;
53 : u32 chan, sr, bps, w, h;
54 : const char *dcfg;
55 : u32 dcfg_size;
56 : char *media_file, *info_file;
57 : const char *szRootName;
58 :
59 : GF_Fraction64 duration;
60 : Bool first;
61 : Bool uncompress, is_dims, is_stpp;
62 :
63 : GF_BitStream *bs_w, *bs_r;
64 : u8 *nhml_buffer;
65 : u32 nhml_buffer_size;
66 : char *b64_buffer;
67 : u32 b64_buffer_size;
68 : u64 mdia_pos;
69 : u32 pck_num;
70 :
71 : Bool side_streams_config;
72 : } GF_NHMLDumpCtx;
73 :
74 12 : GF_Err nhmldump_config_side_stream(GF_Filter *filter, GF_NHMLDumpCtx *ctx)
75 : {
76 : char *mime=NULL, *name;
77 : char fileName[GF_MAX_PATH+1];
78 : const GF_PropertyValue *p;
79 : GF_FileIO *gfio = NULL;
80 :
81 12 : if (ctx->name) {
82 : strncpy(fileName, ctx->name, GF_MAX_PATH);
83 12 : fileName[GF_MAX_PATH] = 0;
84 : } else {
85 0 : char *url = gf_filter_pid_get_destination(ctx->opid_nhml);
86 0 : if (url) {
87 0 : if (!strncmp(url, "gfio://", 7)) {
88 0 : gfio = gf_fileio_from_url(url);
89 0 : strncpy(fileName, gf_fileio_translate_url(url), GF_MAX_PATH);
90 : } else {
91 : strncpy(fileName, url, GF_MAX_PATH);
92 : }
93 0 : fileName[GF_MAX_PATH] = 0;
94 0 : gf_free(url);
95 : } else {
96 : strcpy(fileName, "dump");
97 : }
98 : }
99 12 : name = gf_file_ext_start(fileName);
100 12 : if (name) {
101 0 : name[0] = 0;
102 : }
103 :
104 12 : if (!ctx->opid_mdia && !ctx->nhmlonly)
105 12 : ctx->opid_mdia = gf_filter_pid_new(filter);
106 :
107 12 : p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_DECODER_CONFIG);
108 12 : if (p) {
109 3 : ctx->dcfg = p->value.data.ptr;
110 3 : ctx->dcfg_size = p->value.data.size;
111 :
112 3 : if (!ctx->opid_info && !ctx->nhmlonly) {
113 3 : ctx->opid_info = gf_filter_pid_new(filter);
114 : }
115 :
116 9 : } else if (ctx->opid_info) {
117 0 : gf_filter_pid_remove(ctx->opid_info);
118 0 : ctx->opid_info = NULL;
119 : }
120 12 : if (ctx->info_file) gf_free(ctx->info_file);
121 12 : ctx->info_file = NULL;
122 :
123 12 : if (ctx->opid_mdia) {
124 : GF_Err e;
125 : char *res_name;
126 12 : gf_filter_pid_set_property(ctx->opid_mdia, GF_PROP_PID_STREAM_TYPE, &PROP_UINT(GF_STREAM_FILE) );
127 12 : gf_filter_pid_set_property(ctx->opid_mdia, GF_PROP_PID_MIME, &PROP_STRING(mime) );
128 :
129 12 : name = gf_file_ext_start(fileName);
130 12 : if (name) name[0] = 0;
131 : strcat(fileName, ".media");
132 12 : if (gfio) {
133 0 : res_name = (char *) gf_fileio_factory(gfio, gf_file_basename(fileName) );
134 : } else {
135 : res_name = fileName;
136 : }
137 12 : if (!ctx->exporter) {
138 0 : gf_filter_pid_set_property(ctx->opid_mdia, GF_PROP_PID_OUTPATH, &PROP_STRING(res_name) );
139 : }
140 :
141 12 : if (ctx->media_file) gf_free(ctx->media_file);
142 12 : ctx->media_file = gf_strdup(fileName);
143 12 : gf_filter_pid_set_property(ctx->opid_mdia, GF_PROP_PID_FILE_EXT, &PROP_STRING("media") );
144 :
145 12 : if (!ctx->exporter) {
146 0 : GF_Filter *o_media = gf_filter_connect_destination(filter, res_name, &e);
147 0 : if (o_media) gf_filter_set_source(o_media, filter, NULL);
148 : }
149 : }
150 :
151 12 : if (ctx->opid_info) {
152 : char *res_name;
153 : GF_Err e;
154 3 : gf_filter_pid_set_property(ctx->opid_info, GF_PROP_PID_STREAM_TYPE, &PROP_UINT(GF_STREAM_FILE) );
155 3 : gf_filter_pid_set_property(ctx->opid_info, GF_PROP_PID_MIME, &PROP_STRING(mime) );
156 :
157 3 : name = gf_file_ext_start(fileName);
158 3 : if (name) name[0] = 0;
159 : strcat(fileName, ".info");
160 3 : if (gfio) {
161 0 : res_name = (char *) gf_fileio_factory(gfio, gf_file_basename(fileName) );
162 : } else {
163 : res_name = fileName;
164 : }
165 3 : if (!ctx->exporter) {
166 0 : gf_filter_pid_set_property(ctx->opid_info, GF_PROP_PID_OUTPATH, &PROP_STRING(res_name) );
167 : }
168 :
169 3 : if (ctx->info_file) gf_free(ctx->info_file);
170 3 : ctx->info_file = gf_strdup(fileName);
171 3 : gf_filter_pid_set_property(ctx->opid_info, GF_PROP_PID_FILE_EXT, &PROP_STRING("info") );
172 :
173 3 : if (!ctx->exporter) {
174 0 : GF_Filter *o_info = gf_filter_connect_destination(filter, res_name, &e);
175 0 : if (o_info) gf_filter_set_source(o_info, filter, NULL);
176 : }
177 : }
178 :
179 12 : if (ctx->opid_mdia)
180 12 : gf_filter_pid_set_name(ctx->opid_mdia, "media");
181 12 : if (ctx->opid_info)
182 3 : gf_filter_pid_set_name(ctx->opid_info, "info");
183 :
184 12 : ctx->side_streams_config = GF_TRUE;
185 12 : return GF_OK;
186 : }
187 :
188 13 : GF_Err nhmldump_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
189 : {
190 : u32 cid;
191 : char *mime=NULL, *name;
192 : const GF_PropertyValue *p;
193 13 : GF_NHMLDumpCtx *ctx = gf_filter_get_udta(filter);
194 :
195 13 : if (is_remove) {
196 0 : ctx->ipid = NULL;
197 0 : if (ctx->opid_nhml) {
198 0 : gf_filter_pid_remove(ctx->opid_nhml);
199 0 : ctx->opid_nhml = NULL;
200 : }
201 0 : if (ctx->opid_mdia) {
202 0 : gf_filter_pid_remove(ctx->opid_mdia);
203 0 : ctx->opid_mdia = NULL;
204 : }
205 0 : if (ctx->opid_info) {
206 0 : gf_filter_pid_remove(ctx->opid_info);
207 0 : ctx->opid_info = NULL;
208 : }
209 : return GF_OK;
210 : }
211 13 : if (! gf_filter_pid_check_caps(pid))
212 : return GF_NOT_SUPPORTED;
213 :
214 13 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_CODECID);
215 13 : if (!p) return GF_NOT_SUPPORTED;
216 13 : cid = p->value.uint;
217 :
218 13 : if (ctx->codecid == cid) {
219 : return GF_OK;
220 : }
221 13 : ctx->codecid = cid;
222 :
223 13 : if (ctx->codecid<GF_CODECID_LAST_MPEG4_MAPPING) {
224 1 : ctx->oti = ctx->codecid;
225 : } else {
226 12 : ctx->oti = gf_codecid_oti(ctx->codecid);
227 : }
228 :
229 13 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_STREAM_TYPE);
230 13 : ctx->streamtype = p ? p->value.uint : GF_STREAM_UNKNOWN;
231 :
232 13 : if (!ctx->opid_nhml && !ctx->filep)
233 13 : ctx->opid_nhml = gf_filter_pid_new(filter);
234 :
235 13 : ctx->side_streams_config = GF_FALSE;
236 13 : if (ctx->nhmlonly)
237 0 : ctx->side_streams_config = GF_TRUE;
238 :
239 13 : ctx->is_dims = GF_FALSE;
240 13 : if ((ctx->codecid == GF_CODECID_DIMS) && ctx->dims) {
241 1 : if (ctx->opid_mdia) {
242 0 : gf_filter_pid_remove(ctx->opid_mdia);
243 0 : ctx->opid_mdia = NULL;
244 : }
245 1 : ctx->is_dims = GF_TRUE;
246 1 : ctx->side_streams_config = GF_TRUE;
247 : }
248 :
249 : //file pointer set, we act as a sink, send play
250 13 : if (!ctx->ipid && ctx->filep) {
251 : GF_FilterEvent evt;
252 0 : GF_FEVT_INIT(evt, GF_FEVT_PLAY, pid);
253 0 : gf_filter_pid_send_event(pid, &evt);
254 : }
255 13 : ctx->ipid = pid;
256 :
257 :
258 13 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_SAMPLE_RATE);
259 13 : ctx->sr = p ? p->value.uint : 0;
260 13 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_NUM_CHANNELS);
261 13 : ctx->chan = p ? p->value.uint : 0;
262 13 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_AUDIO_FORMAT);
263 13 : ctx->bps = p ? gf_audio_fmt_bit_depth(p->value.uint) : 16;
264 13 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_WIDTH);
265 13 : ctx->w = p ? p->value.uint : 0;
266 13 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_HEIGHT);
267 13 : ctx->h = p ? p->value.uint : 0;
268 :
269 13 : name = (char*) gf_codecid_name(ctx->codecid);
270 13 : if (ctx->exporter) {
271 13 : if (ctx->w && ctx->h) {
272 4 : GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("Exporting %s - Size %dx%d\n", name, ctx->w, ctx->h));
273 9 : } else if (ctx->sr && ctx->chan) {
274 0 : GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("Exporting %s - SampleRate %d %d channels %d bits per sample\n", name, ctx->sr, ctx->chan, ctx->bps));
275 : } else {
276 9 : GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("Exporting %s\n", name));
277 : }
278 : }
279 :
280 13 : if (ctx->opid_nhml) {
281 : char *ext;
282 13 : mime = ctx->dims ? "application/dims" : "application/x-nhml";
283 13 : ext = ctx->dims ? "dims" : "nhml";
284 :
285 13 : if (ctx->name) {
286 : char fileName[GF_MAX_PATH+1];
287 : strncpy(fileName, ctx->name, GF_MAX_PATH);
288 13 : fileName[GF_MAX_PATH] = 0;
289 13 : name = gf_file_ext_start(fileName);
290 13 : if (name) {
291 0 : name[0] = 0;
292 0 : gf_filter_pid_set_property(ctx->opid_nhml, GF_PROP_PID_OUTPATH, &PROP_STRING(ctx->name) );
293 : } else {
294 : strcat(fileName, ".nhml");
295 13 : gf_filter_pid_set_property(ctx->opid_nhml, GF_PROP_PID_OUTPATH, &PROP_STRING(fileName) );
296 : }
297 : }
298 :
299 13 : gf_filter_pid_set_property(ctx->opid_nhml, GF_PROP_PID_STREAM_TYPE, &PROP_UINT(GF_STREAM_FILE) );
300 13 : gf_filter_pid_set_property(ctx->opid_nhml, GF_PROP_PID_MIME, &PROP_STRING(mime) );
301 13 : gf_filter_pid_set_property(ctx->opid_nhml, GF_PROP_PID_FILE_EXT, &PROP_STRING(ext) );
302 : }
303 :
304 :
305 13 : ctx->first = GF_TRUE;
306 13 : ctx->is_stpp = (cid==GF_CODECID_SUBS_XML) ? GF_TRUE : GF_FALSE;
307 :
308 13 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_DURATION);
309 13 : if (p) ctx->duration = p->value.lfrac;
310 :
311 :
312 13 : if (ctx->opid_nhml)
313 13 : gf_filter_pid_set_name(ctx->opid_nhml, "nhml");
314 :
315 13 : gf_filter_pid_set_framing_mode(pid, GF_TRUE);
316 :
317 13 : return GF_OK;
318 : }
319 :
320 : #define NHML_PRINT_4CC(_code, _pname, _name) \
321 : if (_code) p = gf_filter_pid_get_property(ctx->ipid, _code); \
322 : else p = gf_filter_pid_get_property_str(ctx->ipid, _pname); \
323 : if (p) { \
324 : sprintf(nhml, "%s=\"%s\" ", _name, gf_4cc_to_str(p->value.uint)); \
325 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml)); \
326 : }
327 :
328 : #define NHML_PRINT_UINT(_code, _pname, _name) \
329 : if (_code) p = gf_filter_pid_get_property(ctx->ipid, _code); \
330 : else p = gf_filter_pid_get_property_str(ctx->ipid, _pname); \
331 : if (p) { \
332 : sprintf(nhml, "%s=\"%d\" ", _name, p->value.uint); \
333 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml)); \
334 : }
335 :
336 : #define NHML_PRINT_STRING(_code, _pname, _name) \
337 : if (_code) p = gf_filter_pid_get_property(ctx->ipid, _code); \
338 : else p = gf_filter_pid_get_property_str(ctx->ipid, _pname); \
339 : if (p) { \
340 : sprintf(nhml, "%s=\"%s\" ", _name, p->value.string); \
341 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml)); \
342 : }
343 :
344 :
345 :
346 13 : static void nhmldump_send_header(GF_NHMLDumpCtx *ctx)
347 : {
348 : GF_FilterPacket *dst_pck;
349 : char nhml[1024];
350 : u32 size;
351 : u8 *output;
352 : const GF_PropertyValue *p;
353 :
354 13 : ctx->szRootName = "NHNTStream";
355 13 : if (ctx->dims) {
356 1 : ctx->szRootName = "DIMSStream";
357 : }
358 :
359 13 : if (!ctx->filep) {
360 : sprintf(nhml, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n");
361 13 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
362 : }
363 :
364 : /*write header*/
365 13 : sprintf(nhml, "<%s version=\"1.0\" ", ctx->szRootName);
366 13 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
367 :
368 :
369 26 : NHML_PRINT_UINT(GF_PROP_PID_ID, NULL, "trackID")
370 26 : NHML_PRINT_UINT(GF_PROP_PID_TIMESCALE, NULL, "timeScale")
371 :
372 13 : p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_IN_IOD);
373 13 : if (p && p->value.boolean) {
374 : sprintf(nhml, "inRootOD=\"yes\" ");
375 0 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
376 : }
377 :
378 13 : if (ctx->oti && (ctx->oti<GF_CODECID_LAST_MPEG4_MAPPING)) {
379 1 : sprintf(nhml, "streamType=\"%d\" objectTypeIndication=\"%d\" ", ctx->streamtype, ctx->oti);
380 1 : gf_bs_write_data(ctx->bs_w, nhml, (u32)strlen(nhml));
381 : } else {
382 12 : p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_SUBTYPE);
383 12 : if (p) {
384 12 : sprintf(nhml, "%s=\"%s\" ", "mediaType", gf_4cc_to_str(p->value.uint));
385 12 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
386 :
387 24 : NHML_PRINT_4CC(GF_PROP_PID_ISOM_SUBTYPE, "mediaSubType", "mediaSubType")
388 : } else {
389 0 : NHML_PRINT_4CC(GF_PROP_PID_CODECID, NULL, "codecID")
390 : }
391 : }
392 :
393 13 : if (ctx->w && ctx->h) {
394 : //compatibility with old arch, we might want to remove this
395 4 : switch (ctx->streamtype) {
396 0 : case GF_STREAM_VISUAL:
397 : case GF_STREAM_SCENE:
398 : sprintf(nhml, "width=\"%d\" height=\"%d\" ", ctx->w, ctx->h);
399 0 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
400 0 : break;
401 : default:
402 : break;
403 : }
404 : }
405 9 : else if (ctx->sr && ctx->chan) {
406 : sprintf(nhml, "sampleRate=\"%d\" numChannels=\"%d\" ", ctx->sr, ctx->chan);
407 0 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
408 0 : p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_AUDIO_FORMAT);
409 0 : if (p) {
410 0 : sprintf(nhml, "bitsPerSample=\"%d\" ", gf_audio_fmt_bit_depth(p->value.uint));
411 0 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
412 : }
413 : }
414 :
415 13 : NHML_PRINT_4CC(0, "codec_vendor", "codecVendor")
416 13 : NHML_PRINT_UINT(0, "codec_version", "codecVersion")
417 13 : NHML_PRINT_UINT(0, "codec_revision", "codecRevision")
418 13 : NHML_PRINT_STRING(0, "compressor_name", "compressorName")
419 13 : NHML_PRINT_UINT(0, "temporal_quality", "temporalQuality")
420 13 : NHML_PRINT_UINT(0, "spatial_quality", "spatialQuality")
421 13 : NHML_PRINT_UINT(0, "hres", "horizontalResolution")
422 13 : NHML_PRINT_UINT(0, "vres", "verticalResolution")
423 13 : NHML_PRINT_UINT(GF_PROP_PID_BIT_DEPTH_Y, NULL, "bitDepth")
424 :
425 15 : NHML_PRINT_STRING(0, "meta:xmlns", "xml_namespace")
426 15 : NHML_PRINT_STRING(0, "meta:schemaloc", "xml_schema_location")
427 22 : NHML_PRINT_STRING(0, "meta:mime", "mime_type")
428 :
429 13 : NHML_PRINT_STRING(0, "meta:config", "config")
430 13 : NHML_PRINT_STRING(0, "meta:aux_mimes", "aux_mime_type")
431 :
432 13 : if (ctx->codecid == GF_CODECID_DIMS) {
433 1 : if (gf_filter_pid_get_property_str(ctx->ipid, "meta:xmlns")==NULL) {
434 : sprintf(nhml, "xmlns=\"http://www.3gpp.org/richmedia\" ");
435 1 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
436 : }
437 :
438 2 : NHML_PRINT_UINT(0, "dims:profile", "profile")
439 2 : NHML_PRINT_UINT(0, "dims:level", "level")
440 2 : NHML_PRINT_UINT(0, "dims:pathComponents", "pathComponents")
441 :
442 1 : p = gf_filter_pid_get_property_str(ctx->ipid, "dims:fullRequestHost");
443 1 : if (p) {
444 1 : sprintf(nhml, "useFullRequestHost=\"%s\" ", p->value.boolean ? "yes" : "no");
445 1 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
446 : }
447 1 : p = gf_filter_pid_get_property_str(ctx->ipid, "dims:streamType");
448 1 : if (p) {
449 1 : sprintf(nhml, "stream_type=\"%s\" ", p->value.boolean ? "primary" : "secondary");
450 1 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
451 : }
452 1 : p = gf_filter_pid_get_property_str(ctx->ipid, "dims:redundant");
453 1 : if (p) {
454 1 : sprintf(nhml, "contains_redundant=\"%s\" ", (p->value.uint==1) ? "main" : ((p->value.uint==1) ? "redundant" : "main+redundant") );
455 1 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
456 : }
457 1 : NHML_PRINT_UINT(0, "dims:scriptTypes", "scriptTypes")
458 : }
459 :
460 : //send DCD
461 13 : if (ctx->opid_info) {
462 3 : sprintf(nhml, "specificInfoFile=\"%s\" ", gf_file_basename(ctx->info_file) );
463 3 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
464 :
465 3 : dst_pck = gf_filter_pck_new_shared(ctx->opid_info, ctx->dcfg, ctx->dcfg_size, NULL);
466 3 : if (dst_pck) {
467 3 : gf_filter_pck_set_framing(dst_pck, GF_TRUE, GF_TRUE);
468 3 : gf_filter_pck_set_readonly(dst_pck);
469 3 : gf_filter_pck_send(dst_pck);
470 : }
471 : }
472 :
473 18 : NHML_PRINT_STRING(0, "meta:encoding", "encoding")
474 13 : NHML_PRINT_STRING(0, "meta:contentEncoding", "content_encoding")
475 13 : ctx->uncompress = GF_FALSE;
476 13 : if (p) {
477 0 : if (!strcmp(p->value.string, "deflate")) ctx->uncompress = GF_TRUE;
478 : else {
479 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[NHMLMx] content_encoding %s not supported\n", p->value.string ));
480 : }
481 : }
482 :
483 13 : if (ctx->opid_mdia) {
484 12 : sprintf(nhml, "baseMediaFile=\"%s\" ", gf_file_basename(ctx->media_file) );
485 12 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
486 : }
487 : sprintf(nhml, ">\n");
488 13 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
489 :
490 13 : gf_bs_get_content_no_truncate(ctx->bs_w, &ctx->nhml_buffer, &size, &ctx->nhml_buffer_size);
491 :
492 13 : if (ctx->filep) {
493 0 : gf_fwrite(ctx->nhml_buffer, size, ctx->filep);
494 0 : return;
495 : }
496 :
497 13 : dst_pck = gf_filter_pck_new_alloc(ctx->opid_nhml, size, &output);
498 13 : if (!dst_pck) return;
499 :
500 13 : memcpy(output, ctx->nhml_buffer, size);
501 13 : gf_filter_pck_set_framing(dst_pck, GF_TRUE, GF_FALSE);
502 13 : gf_filter_pck_send(dst_pck);
503 : }
504 :
505 1 : static void nhmldump_send_dims(GF_NHMLDumpCtx *ctx, char *data, u32 data_size, GF_FilterPacket *pck)
506 : {
507 : char nhml[1024];
508 : u32 size;
509 : u8 *output;
510 : GF_FilterPacket *dst_pck;
511 1 : u64 dts = gf_filter_pck_get_dts(pck);
512 1 : u64 cts = gf_filter_pck_get_cts(pck);
513 :
514 1 : if (dts==GF_FILTER_NO_TS) dts = cts;
515 1 : if (cts==GF_FILTER_NO_TS) cts = dts;
516 :
517 1 : if (!ctx->bs_r) ctx->bs_r = gf_bs_new(data, data_size, GF_BITSTREAM_READ);
518 0 : else gf_bs_reassign_buffer(ctx->bs_r, data, data_size);
519 :
520 2 : while (gf_bs_available(ctx->bs_r)) {
521 1 : u64 pos = gf_bs_get_position(ctx->bs_r);
522 1 : size = gf_bs_read_u16(ctx->bs_r);
523 1 : u8 flags = gf_bs_read_u8(ctx->bs_r);
524 : u8 prev;
525 :
526 1 : if (pos+size+2 > data_size)
527 : break;
528 :
529 :
530 : prev = 0;
531 1 : if (pos+2+size<data_size) {
532 0 : prev = data[pos+2+size];
533 0 : data[pos+2+size] = 0;
534 : }
535 :
536 : sprintf(nhml, "<DIMSUnit time=\""LLU"\"", cts);
537 1 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
538 :
539 : /*DIMS flags*/
540 1 : if (flags & GF_DIMS_UNIT_S) {
541 : sprintf(nhml, " is-Scene=\"yes\"");
542 1 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
543 : }
544 1 : if (flags & GF_DIMS_UNIT_M) {
545 : sprintf(nhml, " is-RAP=\"yes\"");
546 1 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
547 : }
548 1 : if (flags & GF_DIMS_UNIT_I) {
549 : sprintf(nhml, " is-redundant=\"yes\"");
550 0 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
551 : }
552 1 : if (flags & GF_DIMS_UNIT_D) {
553 : sprintf(nhml, " redundant-exit=\"yes\"");
554 0 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
555 : }
556 1 : if (flags & GF_DIMS_UNIT_P) {
557 : sprintf(nhml, " priority=\"high\"");
558 1 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
559 : }
560 1 : if (flags & GF_DIMS_UNIT_C) {
561 : sprintf(nhml, " compressed=\"yes\"");
562 0 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
563 : }
564 : sprintf(nhml, ">");
565 1 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
566 1 : if (ctx->uncompress && (flags & GF_DIMS_UNIT_C)) {
567 : #ifndef GPAC_DISABLE_ZLIB
568 : char svg_data[2049];
569 : int err;
570 : u32 done = 0;
571 : z_stream d_stream;
572 0 : d_stream.zalloc = (alloc_func)0;
573 0 : d_stream.zfree = (free_func)0;
574 0 : d_stream.opaque = (voidpf)0;
575 0 : d_stream.next_in = (Bytef*) data+pos+3;
576 0 : d_stream.avail_in = size-1;
577 0 : d_stream.next_out = (Bytef*)svg_data;
578 0 : d_stream.avail_out = 2048;
579 :
580 0 : err = inflateInit(&d_stream);
581 0 : if (err == Z_OK) {
582 0 : while ((s32) d_stream.total_in < size-1) {
583 0 : err = inflate(&d_stream, Z_NO_FLUSH);
584 0 : if (err < Z_OK) break;
585 0 : svg_data[d_stream.total_out - done] = 0;
586 0 : gf_bs_write_data(ctx->bs_w, svg_data, (u32) strlen(svg_data));
587 :
588 0 : if (err== Z_STREAM_END) break;
589 0 : done = (u32) d_stream.total_out;
590 0 : d_stream.avail_out = 2048;
591 0 : d_stream.next_out = (Bytef*)svg_data;
592 : }
593 0 : inflateEnd(&d_stream);
594 : }
595 : #else
596 : GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("Error: your version of GPAC was compiled with no libz support."));
597 : gf_bs_del(ctx->bs_r);
598 : if (prev)
599 : data[pos+2+size] = prev;
600 : return;
601 : #endif
602 : } else {
603 1 : gf_bs_write_data(ctx->bs_w, data+pos+3, size-1);
604 : }
605 : sprintf(nhml, "</DIMSUnit>\n");
606 1 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
607 :
608 1 : if (prev)
609 0 : data[pos+2+size] = prev;
610 1 : gf_bs_skip_bytes(ctx->bs_r, size-1);
611 : }
612 :
613 1 : gf_bs_get_content_no_truncate(ctx->bs_w, &ctx->nhml_buffer, &size, &ctx->nhml_buffer_size);
614 :
615 1 : if (ctx->filep) {
616 0 : gf_fwrite(ctx->nhml_buffer, size, ctx->filep);
617 0 : return;
618 : }
619 :
620 1 : dst_pck = gf_filter_pck_new_alloc(ctx->opid_nhml, size, &output);
621 1 : if (!dst_pck) return;
622 :
623 1 : memcpy(output, ctx->nhml_buffer, size);
624 1 : gf_filter_pck_set_framing(dst_pck, GF_FALSE, GF_FALSE);
625 1 : gf_filter_pck_send(dst_pck);
626 : }
627 :
628 :
629 502 : static void nhmldump_pck_property(GF_NHMLDumpCtx *ctx, u32 p4cc, const char *pname, const GF_PropertyValue *att)
630 : {
631 : u32 i;
632 : char nhml[1024];
633 : char pval[GF_PROP_DUMP_ARG_SIZE];
634 502 : if (!pname) pname = gf_props_4cc_get_name(p4cc);
635 :
636 502 : sprintf(nhml, "%s=\"", pname ? pname : gf_4cc_to_str(p4cc));
637 502 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
638 :
639 502 : switch (att->type) {
640 : case GF_PROP_DATA:
641 : case GF_PROP_CONST_DATA:
642 : case GF_PROP_DATA_NO_COPY:
643 : sprintf(nhml, "0x");
644 502 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
645 12048 : for (i=0; i<att->value.data.size; i++) {
646 12048 : sprintf(nhml, "%02X", (unsigned char) att->value.data.ptr[i]);
647 12048 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
648 : }
649 502 : nhml[0] = 0;
650 : break;
651 0 : default:
652 0 : sprintf(nhml, "%s", gf_props_dump_val(att, pval, GF_PROP_DUMP_DATA_NONE, NULL) );
653 : break;
654 : }
655 502 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
656 : sprintf(nhml, "\"");
657 502 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
658 502 : }
659 :
660 544 : static void nhmldump_send_frame(GF_NHMLDumpCtx *ctx, char *data, u32 data_size, GF_FilterPacket *pck)
661 : {
662 : GF_FilterPacket *dst_pck;
663 : char nhml[1024];
664 : const GF_PropertyValue *p;
665 : u32 size;
666 : u8 *output;
667 544 : GF_FilterSAPType sap = gf_filter_pck_get_sap(pck);
668 544 : u64 dts = gf_filter_pck_get_dts(pck);
669 544 : u64 cts = gf_filter_pck_get_cts(pck);
670 :
671 544 : if (dts==GF_FILTER_NO_TS) dts = cts;
672 544 : if (cts==GF_FILTER_NO_TS) cts = dts;
673 :
674 544 : ctx->pck_num++;
675 : sprintf(nhml, "<NHNTSample number=\"%d\" DTS=\""LLU"\" dataLength=\"%d\" ", ctx->pck_num, dts, data_size);
676 544 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
677 544 : if (ctx->pckp || (cts != dts) ) {
678 502 : sprintf(nhml, "CTSOffset=\"%d\" ", (s32) ((s64)cts - (s64)dts));
679 502 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
680 : }
681 544 : if (sap==GF_FILTER_SAP_1) {
682 : sprintf(nhml, "isRAP=\"yes\" ");
683 45 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
684 499 : } else if (sap) {
685 : sprintf(nhml, "SAPType=\"%d\" ", sap);
686 0 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
687 499 : } else if (ctx->pckp) {
688 : sprintf(nhml, "isRAP=\"no\" ");
689 481 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
690 : if ((sap==GF_FILTER_SAP_4) || (sap==GF_FILTER_SAP_4_PROL)) {
691 : s32 roll = gf_filter_pck_get_roll_info(pck);
692 : sprintf(nhml, "SAPType=\"4\" %s=\"%d\" ", (sap==GF_FILTER_SAP_4_PROL) ? "prol" : "roll", roll);
693 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
694 : }
695 : }
696 :
697 544 : if (ctx->pckp) {
698 : u64 bo;
699 : u32 duration, idx;
700 502 : sprintf(nhml, "mediaOffset=\""LLU"\" ", ctx->mdia_pos);
701 502 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
702 :
703 502 : bo = gf_filter_pck_get_byte_offset(pck);
704 502 : if (bo!=GF_FILTER_NO_BO) {
705 : sprintf(nhml, "sourceByteOffset=\""LLU"\" ", bo);
706 0 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
707 : }
708 502 : duration = gf_filter_pck_get_duration(pck);
709 502 : if (duration) {
710 : sprintf(nhml, "duration=\"%d\" ", duration);
711 502 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
712 : }
713 502 : idx = gf_filter_pck_get_carousel_version(pck);
714 502 : if (idx) {
715 : sprintf(nhml, "carouselVersion=\"%d\" ", idx);
716 0 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
717 : }
718 502 : idx = 0;
719 : while (1) {
720 : u32 prop_4cc;
721 : const char *prop_name;
722 1004 : p = gf_filter_pck_enum_properties(pck, &idx, &prop_4cc, &prop_name);
723 1004 : if (!p) break;
724 502 : if (prop_4cc == GF_PROP_PCK_SUBS) continue;
725 502 : nhmldump_pck_property(ctx, prop_4cc, prop_name, p);
726 : }
727 : }
728 :
729 544 : if (ctx->chksum) {
730 0 : if (ctx->chksum==1) {
731 0 : u32 crc = gf_crc_32(data, data_size);
732 : sprintf(nhml, "crc=\"%08X\" ", crc);
733 0 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
734 : } else {
735 : u32 j;
736 : u8 hash[GF_SHA1_DIGEST_SIZE];
737 0 : gf_sha1_csum(data, data_size, hash);
738 : sprintf(nhml, "sha1=\"");
739 0 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
740 0 : for (j=0; j<20; j++) {
741 0 : sprintf(nhml, "%02X", hash[j]);
742 0 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
743 : }
744 : sprintf(nhml, "\" ");
745 0 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
746 : }
747 : }
748 :
749 : sprintf(nhml, ">\n");
750 544 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
751 :
752 544 : p = gf_filter_pck_get_property(pck, GF_PROP_PCK_SUBS);
753 544 : if (p) {
754 : u32 offset_in_sample = 0;
755 : Bool first_subs = GF_TRUE;
756 0 : if (!ctx->bs_r) ctx->bs_r = gf_bs_new(p->value.data.ptr, p->value.data.size, GF_BITSTREAM_READ);
757 0 : else gf_bs_reassign_buffer(ctx->bs_r, p->value.data.ptr, p->value.data.size);
758 :
759 : //(data) binary blob containing N [(u32)flags(u32)size(u32)reserved(u8)priority(u8) discardable]
760 0 : while (gf_bs_available(ctx->bs_r)) {
761 0 : u32 s_flags = gf_bs_read_u32(ctx->bs_r);
762 0 : u32 s_size = gf_bs_read_u32(ctx->bs_r);
763 0 : u32 s_res = gf_bs_read_u32(ctx->bs_r);
764 0 : u8 s_prio = gf_bs_read_u8(ctx->bs_r);
765 0 : u8 s_discard = gf_bs_read_u8(ctx->bs_r);
766 :
767 :
768 0 : if (offset_in_sample + s_size > data_size) {
769 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("Wrong subsample info: sample size %d vs subsample offset+size %dn", data_size, offset_in_sample + s_size));
770 : break;
771 : }
772 :
773 0 : if (ctx->is_stpp && ctx->nhmlonly) {
774 0 : if (first_subs) {
775 : sprintf(nhml, "<NHNTSubSample>\n");
776 0 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
777 :
778 0 : gf_bs_write_data(ctx->bs_w, data, s_size);
779 :
780 : sprintf(nhml, "</NHNTSubSample>\n");
781 0 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
782 : } else {
783 : u32 d_size;
784 0 : if (ctx->b64_buffer_size<2*s_size) {
785 0 : ctx->b64_buffer_size = 2 * s_size;
786 0 : ctx->b64_buffer = gf_realloc(ctx->b64_buffer, ctx->b64_buffer_size);
787 : }
788 0 : d_size = gf_base64_encode(data + offset_in_sample, s_size, ctx->b64_buffer, ctx->b64_buffer_size);
789 0 : ctx->b64_buffer[d_size] = 0;
790 : sprintf(nhml, "<NHNTSubSample data=\"data:application/octet-string;base64,");
791 0 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
792 0 : gf_bs_write_data(ctx->bs_w, ctx->b64_buffer, d_size);
793 : sprintf(nhml, "\">\n");
794 0 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
795 : }
796 : } else {
797 0 : sprintf(nhml, "<NHNTSubSample size=\"%d\" flags=\"%d\" reserved=\"%d\" priority=\"%d\" discard=\"%d\" />\n", s_size, s_flags, s_res, s_prio, s_discard);
798 0 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
799 : }
800 : first_subs = GF_FALSE;
801 : }
802 544 : } else if (ctx->is_stpp && ctx->nhmlonly) {
803 : sprintf(nhml, "<NHNTSubSample><![CDATA[\n");
804 0 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
805 0 : gf_bs_write_data(ctx->bs_w, data, data_size);
806 : sprintf(nhml, "]]></NHNTSubSample>\n");
807 0 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
808 : }
809 : sprintf(nhml, "</NHNTSample>\n");
810 544 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
811 :
812 544 : gf_bs_get_content_no_truncate(ctx->bs_w, &ctx->nhml_buffer, &size, &ctx->nhml_buffer_size);
813 :
814 544 : if (ctx->filep) {
815 0 : gf_fwrite(ctx->nhml_buffer, size, ctx->filep);
816 0 : return;
817 : }
818 :
819 544 : dst_pck = gf_filter_pck_new_alloc(ctx->opid_nhml, size, &output);
820 544 : if (dst_pck) {
821 544 : memcpy(output, ctx->nhml_buffer, size);
822 544 : gf_filter_pck_set_framing(dst_pck, GF_FALSE, GF_FALSE);
823 544 : gf_filter_pck_send(dst_pck);
824 : }
825 :
826 544 : ctx->mdia_pos += data_size;
827 :
828 544 : if (ctx->opid_mdia) {
829 : //send the complete data packet
830 544 : dst_pck = gf_filter_pck_new_ref(ctx->opid_mdia, 0, data_size, pck);
831 544 : if (!dst_pck) return;
832 :
833 544 : gf_filter_pck_merge_properties(pck, dst_pck);
834 : //keep byte offset ?
835 : // gf_filter_pck_set_byte_offset(dst_pck, GF_FILTER_NO_BO);
836 :
837 544 : gf_filter_pck_set_framing(dst_pck, ctx->first, GF_FALSE);
838 544 : gf_filter_pck_send(dst_pck);
839 : }
840 : }
841 :
842 :
843 570 : GF_Err nhmldump_process(GF_Filter *filter)
844 : {
845 570 : GF_NHMLDumpCtx *ctx = gf_filter_get_udta(filter);
846 : GF_FilterPacket *pck;
847 : char *data;
848 : u32 pck_size;
849 :
850 570 : if (!ctx->side_streams_config) {
851 12 : return nhmldump_config_side_stream(filter, ctx);
852 : }
853 :
854 558 : pck = gf_filter_pid_get_packet(ctx->ipid);
855 558 : if (!pck) {
856 13 : if (gf_filter_pid_is_eos(ctx->ipid)) {
857 13 : if (ctx->bs_w && ctx->szRootName) {
858 : char nhml[1024];
859 : u32 size;
860 13 : gf_bs_reassign_buffer(ctx->bs_w, ctx->nhml_buffer, ctx->nhml_buffer_size);
861 13 : sprintf(nhml, "</%s>\n", ctx->szRootName);
862 13 : gf_bs_write_data(ctx->bs_w, nhml, (u32) strlen(nhml));
863 :
864 13 : gf_bs_get_content_no_truncate(ctx->bs_w, &ctx->nhml_buffer, &size, &ctx->nhml_buffer_size);
865 :
866 13 : if (ctx->filep) {
867 0 : gf_fwrite(ctx->nhml_buffer, size, ctx->filep);
868 : } else {
869 : GF_FilterPacket *dst_pck;
870 : u8 *output;
871 13 : dst_pck = gf_filter_pck_new_alloc(ctx->opid_nhml, size, &output);
872 13 : if (dst_pck) {
873 13 : memcpy(output, ctx->nhml_buffer, size);
874 13 : gf_filter_pck_set_framing(dst_pck, GF_FALSE, GF_TRUE);
875 13 : gf_filter_pck_send(dst_pck);
876 : }
877 : }
878 13 : ctx->szRootName = NULL;
879 : }
880 13 : if (ctx->opid_nhml) gf_filter_pid_set_eos(ctx->opid_nhml);
881 13 : if (ctx->opid_mdia) gf_filter_pid_set_eos(ctx->opid_mdia);
882 13 : if (ctx->opid_info) gf_filter_pid_set_eos(ctx->opid_info);
883 : return GF_EOS;
884 : }
885 : return GF_OK;
886 : }
887 :
888 545 : if (!ctx->bs_w) ctx->bs_w = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
889 532 : else gf_bs_reassign_buffer(ctx->bs_w, ctx->nhml_buffer, ctx->nhml_buffer_size);
890 :
891 545 : if (ctx->first) {
892 13 : nhmldump_send_header(ctx);
893 13 : gf_bs_reassign_buffer(ctx->bs_w, ctx->nhml_buffer, ctx->nhml_buffer_size);
894 : }
895 :
896 : //get media data
897 545 : data = (char *) gf_filter_pck_get_data(pck, &pck_size);
898 :
899 : //send data
900 545 : if (ctx->is_dims) {
901 1 : nhmldump_send_dims(ctx, data, pck_size, pck);
902 : } else {
903 544 : nhmldump_send_frame(ctx, data, pck_size, pck);
904 : }
905 545 : ctx->first = GF_FALSE;
906 :
907 :
908 545 : if (ctx->exporter) {
909 545 : u32 timescale = gf_filter_pck_get_timescale(pck);
910 545 : u64 ts = gf_filter_pck_get_cts(pck);
911 545 : gf_set_progress("Exporting", ts*ctx->duration.den, ctx->duration.num*timescale);
912 : }
913 :
914 545 : gf_filter_pid_drop_packet(ctx->ipid);
915 :
916 545 : return GF_OK;
917 : }
918 :
919 13 : static GF_Err nhmldump_initialize(GF_Filter *filter)
920 : {
921 13 : return GF_OK;
922 : }
923 :
924 13 : static void nhmldump_finalize(GF_Filter *filter)
925 : {
926 13 : GF_NHMLDumpCtx *ctx = gf_filter_get_udta(filter);
927 13 : if (ctx->bs_r) gf_bs_del(ctx->bs_r);
928 13 : if (ctx->bs_w) gf_bs_del(ctx->bs_w);
929 13 : if (ctx->nhml_buffer) gf_free(ctx->nhml_buffer);
930 13 : if (ctx->b64_buffer) gf_free(ctx->b64_buffer);
931 13 : if (ctx->info_file) gf_free(ctx->info_file);
932 13 : if (ctx->media_file) gf_free(ctx->media_file);
933 13 : }
934 :
935 : static const GF_FilterCapability NHMLDumpCaps[] =
936 : {
937 : CAP_UINT(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
938 : CAP_UINT(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_CODECID, GF_CODECID_NONE),
939 : CAP_BOOL(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
940 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
941 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_FILE_EXT, "nhml|dims|dml"),
942 : CAP_STRING(GF_CAPS_OUTPUT, GF_PROP_PID_MIME, "application/x-nhml|application/dims"),
943 : };
944 :
945 : #define OFFS(_n) #_n, offsetof(GF_NHMLDumpCtx, _n)
946 : static const GF_FilterArgs NHMLDumpArgs[] =
947 : {
948 : { OFFS(exporter), "compatibility with old exporter, displays export results", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
949 : { OFFS(dims), "use DIMS mode", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
950 : { OFFS(name), "set output name of files produced (needed media/info files referred to from XML", GF_PROP_STRING, NULL, NULL, 0},
951 : { OFFS(nhmlonly), "only dump NHML info, not media", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
952 : { OFFS(pckp), "full NHML dump", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
953 : { OFFS(chksum), "insert frame checksum\n"
954 : "- none: no checksum\n"
955 : "- crc: CRC32 checksum\n"
956 : "- sha1: SHA1 checksum"
957 : "", GF_PROP_UINT, "none", "none|crc|sha1", GF_FS_ARG_HINT_ADVANCED},
958 : { OFFS(filep), "dump directly to the given FILE pointer (used by MP4Box)", GF_PROP_POINTER, NULL, NULL, GF_FS_ARG_HINT_HIDE},
959 : {0}
960 : };
961 :
962 :
963 : GF_FilterRegister NHMLDumpRegister = {
964 : .name = "nhmlw",
965 : GF_FS_SET_DESCRIPTION("NHML writer")
966 : GF_FS_SET_HELP("This filter converts a single stream to an NHML output file.\n"
967 : "NHML documentation is available at https://wiki.gpac.io/NHML-Format\n")
968 : .private_size = sizeof(GF_NHMLDumpCtx),
969 : .args = NHMLDumpArgs,
970 : .initialize = nhmldump_initialize,
971 : .finalize = nhmldump_finalize,
972 : SETCAPS(NHMLDumpCaps),
973 : .configure_pid = nhmldump_configure_pid,
974 : .process = nhmldump_process
975 : };
976 :
977 2877 : const GF_FilterRegister *nhmldump_register(GF_FilterSession *session)
978 : {
979 2877 : return &NHMLDumpRegister;
980 : }
981 :
|