1 /*
2 * GPAC - Multimedia Framework C SDK
3 *
4 * Authors: Jean Le Feuvre
5 * Copyright (c) Telecom ParisTech 2005-2020
6 * All rights reserved
7 *
8 * This file is part of GPAC / NHML demuxer 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/thread.h>
29 #include <gpac/list.h>
30 #include <gpac/bitstream.h>
31 #include <gpac/xml.h>
32 #include <gpac/network.h>
33 #include <gpac/isomedia.h>
34 #include <gpac/base_coding.h>
35
36 #ifndef GPAC_DISABLE_AV_PARSERS
37 #include <gpac/avparse.h>
38 #endif
39
40 typedef struct
41 {
42 //opts
43 Bool reframe;
44 Double index;
45
46 GF_FilterPid *ipid;
47 GF_FilterPid *opid;
48
49 Bool is_dims;
50
51 Double start_range;
52 u64 first_dts;
53
54 Bool is_playing;
55 GF_Fraction64 duration;
56 Bool in_seek;
57
58 u32 timescale;
59 u32 sample_num;
60
61 FILE *mdia;
62 char szMedia[GF_MAX_PATH];
63
64 GF_DOMParser *parser;
65 GF_XMLNode *root;
66 //0: not initialized, 1: OK, samples can be sent, 2: EOS, 3: error
67 u32 parsing_state;
68 u32 current_child_idx;
69 Bool has_sap;
70 u32 compress_type;
71 const char *src_url;
72 u64 last_dts;
73 u32 dts_inc;
74
75 u8 *samp_buffer;
76 u32 samp_buffer_alloc, samp_buffer_size;
77 char *zlib_buffer;
78 u32 zlib_buffer_alloc, zlib_buffer_size;
79 #ifndef GPAC_DISABLE_ZLIB
80 Bool use_dict;
81 char *dictionary;
82 #endif
83
84 u64 media_done;
85 Bool is_img;
86 u32 header_end;
87
88 GF_BitStream *bs_w;
89 GF_BitStream *bs_r;
90 } GF_NHMLDmxCtx;
91
92
nhmldmx_configure_pid(GF_Filter * filter,GF_FilterPid * pid,Bool is_remove)93 GF_Err nhmldmx_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
94 {
95 const GF_PropertyValue *p;
96 GF_NHMLDmxCtx *ctx = gf_filter_get_udta(filter);
97
98 if (is_remove) {
99 ctx->ipid = NULL;
100 //gf_filter_pid_remove(st->opid);
101
102 return GF_OK;
103 }
104 if (! gf_filter_pid_check_caps(pid))
105 return GF_NOT_SUPPORTED;
106
107 ctx->ipid = pid;
108 gf_filter_pid_set_framing_mode(pid, GF_TRUE);
109
110 p = gf_filter_pid_get_property(pid, GF_PROP_PID_MIME);
111 if (p && p->value.string && strstr(p->value.string, "dims")) ctx->is_dims = GF_TRUE;
112 else {
113 p = gf_filter_pid_get_property(pid, GF_PROP_PID_FILE_EXT);
114 if (p && p->value.string && strstr(p->value.string, "dims")) ctx->is_dims = GF_TRUE;
115 }
116
117 return GF_OK;
118 }
119
nhmldmx_process_event(GF_Filter * filter,const GF_FilterEvent * evt)120 static Bool nhmldmx_process_event(GF_Filter *filter, const GF_FilterEvent *evt)
121 {
122 u32 i=0;
123 u64 cur_dts = 0;
124 u64 byte_offset = 0;
125 u32 sample_num = 0;
126 GF_XMLNode *node;
127 GF_NHMLDmxCtx *ctx = gf_filter_get_udta(filter);
128
129 switch (evt->base.type) {
130 case GF_FEVT_PLAY:
131 if (ctx->is_playing && (ctx->start_range == evt->play.start_range)) {
132 return GF_TRUE;
133 }
134
135 ctx->start_range = evt->play.start_range;
136 ctx->current_child_idx = 0;
137 ctx->media_done = ctx->header_end;
138 ctx->is_playing = GF_TRUE;
139 //post a seek
140 ctx->in_seek = GF_TRUE;
141
142 //lcoate previous RAP sample
143 while ((node = (GF_XMLNode *) gf_list_enum(ctx->root->content, &i))) {
144 u32 j=0;
145 u64 dts=0;
146 u32 datalen=0;
147 Bool is_rap = ctx->has_sap ? GF_FALSE : GF_TRUE;
148 s32 cts_offset=0;
149 u64 sample_duration = 0;
150 GF_XMLAttribute *att;
151 if (node->type) continue;
152 if (stricmp(node->name, ctx->is_dims ? "DIMSUnit" : "NHNTSample") ) continue;
153
154 while ( (att = (GF_XMLAttribute *)gf_list_enum(node->attributes, &j))) {
155 if (!stricmp(att->name, "DTS") || !stricmp(att->name, "time")) {
156 u32 h, m, s, ms;
157 u64 dst_val;
158 if (strchr(att->value, ':') && sscanf(att->value, "%u:%u:%u.%u", &h, &m, &s, &ms) == 4) {
159 dts = (u64) ( (Double) ( ((h*3600.0 + m*60.0 + s)*1000 + ms) / 1000.0) * ctx->timescale );
160 } else if (sscanf(att->value, ""LLU, &dst_val)==1) {
161 dts = dst_val;
162 }
163 }
164 else if (!stricmp(att->name, "CTSOffset")) cts_offset = atoi(att->value);
165 else if (!stricmp(att->name, "duration") ) sscanf(att->value, ""LLU, &sample_duration);
166 else if (!stricmp(att->name, "isRAP") ) {
167 is_rap = (!stricmp(att->value, "yes")) ? GF_TRUE : GF_FALSE;
168 }
169 else if (!stricmp(att->name, "mediaOffset"))
170 byte_offset = (s64) atof(att->value) ;
171 else if (!stricmp(att->name, "dataLength"))
172 datalen = atoi(att->value);
173 }
174
175 dts += cts_offset;
176 if ((s64) dts < 0) dts = 0;
177
178 if (dts) cur_dts = dts;
179 if (sample_duration) cur_dts += sample_duration;
180 else if (ctx->dts_inc) cur_dts += ctx->dts_inc;
181
182 if (cur_dts >= ctx->timescale * evt->play.start_range) {
183 break;
184 }
185 if (is_rap) {
186 ctx->current_child_idx = i-1;
187 ctx->media_done = byte_offset;
188 ctx->sample_num = sample_num;
189 }
190 byte_offset += datalen;
191 sample_num++;
192 }
193
194 //cancel event
195 return GF_TRUE;
196
197 case GF_FEVT_STOP:
198 ctx->is_playing = GF_FALSE;
199 //don't cancel event
200 return GF_FALSE;
201
202 case GF_FEVT_SET_SPEED:
203 //cancel event
204 return GF_TRUE;
205 default:
206 break;
207 }
208 //by default don't cancel event - to rework once we have downloading in place
209 return GF_FALSE;
210 }
211
212
213 typedef struct
214 {
215 Bool from_is_start, from_is_end, to_is_start, to_is_end;
216 u64 from_pos, to_pos;
217 char *from_id, *to_id;
218 GF_List *id_stack;
219 GF_SAXParser *sax;
220 } XMLBreaker;
221
222
nhml_node_start(void * sax_cbck,const char * node_name,const char * name_space,const GF_XMLAttribute * attributes,u32 nb_attributes)223 static void nhml_node_start(void *sax_cbck, const char *node_name, const char *name_space, const GF_XMLAttribute *attributes, u32 nb_attributes)
224 {
225 XMLBreaker *breaker = (XMLBreaker *)sax_cbck;
226 char *node_id;
227 u32 i;
228 node_id = NULL;
229 for (i=0; i<nb_attributes; i++) {
230 GF_XMLAttribute *att = (GF_XMLAttribute *) &attributes[i];
231 if (stricmp(att->name, "DEF") && stricmp(att->name, "id")) continue;
232 node_id = gf_strdup(att->value);
233 break;
234 }
235 if (!node_id) {
236 node_id = gf_strdup("__nhml__none");
237 gf_list_add(breaker->id_stack, node_id);
238 return;
239 }
240 gf_list_add(breaker->id_stack, node_id);
241
242 if (breaker->from_is_start && breaker->from_id && !strcmp(breaker->from_id, node_id)) {
243 breaker->from_pos = gf_xml_sax_get_node_start_pos(breaker->sax);
244 breaker->from_is_start = GF_FALSE;
245 }
246 if (breaker->to_is_start && breaker->to_id && !strcmp(breaker->to_id, node_id)) {
247 breaker->to_pos = gf_xml_sax_get_node_start_pos(breaker->sax);
248 breaker->to_is_start = GF_FALSE;
249 }
250 if (!breaker->to_is_start && !breaker->from_is_start && !breaker->to_is_end && !breaker->from_is_end) {
251 gf_xml_sax_suspend(breaker->sax, GF_TRUE);
252 }
253
254 }
255
nhml_node_end(void * sax_cbck,const char * node_name,const char * name_space)256 static void nhml_node_end(void *sax_cbck, const char *node_name, const char *name_space)
257 {
258 XMLBreaker *breaker = (XMLBreaker *)sax_cbck;
259 char *node_id = (char *)gf_list_last(breaker->id_stack);
260 gf_list_rem_last(breaker->id_stack);
261 if (breaker->from_is_end && breaker->from_id && !strcmp(breaker->from_id, node_id)) {
262 breaker->from_pos = gf_xml_sax_get_node_end_pos(breaker->sax);
263 breaker->from_is_end = GF_FALSE;
264 }
265 if (breaker->to_is_end && breaker->to_id && !strcmp(breaker->to_id, node_id)) {
266 breaker->to_pos = gf_xml_sax_get_node_end_pos(breaker->sax);
267 breaker->to_is_end = GF_FALSE;
268 }
269 gf_free(node_id);
270 if (!breaker->to_is_start && !breaker->from_is_start && !breaker->to_is_end && !breaker->from_is_end) {
271 gf_xml_sax_suspend(breaker->sax, GF_TRUE);
272 }
273 }
274
275
nhml_sample_from_xml(GF_NHMLDmxCtx * ctx,char * xml_file,char * xmlFrom,char * xmlTo)276 static GF_Err nhml_sample_from_xml(GF_NHMLDmxCtx *ctx, char *xml_file, char *xmlFrom, char *xmlTo)
277 {
278 GF_Err e = GF_OK;
279 u32 read;
280 XMLBreaker breaker;
281 char *tmp;
282 FILE *xml;
283 u8 szBOM[3];
284 if (!xml_file || !xmlFrom || !xmlTo) return GF_BAD_PARAM;
285
286 memset(&breaker, 0, sizeof(XMLBreaker));
287
288 xml = gf_fopen(xml_file, "rb");
289 if (!xml) {
290 GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[NHMLDmx] import failure: file %s not found", xml_file ));
291 goto exit;
292 }
293 //we cannot use files with BOM since the XML position we get from the parser are offsets in the UTF-8 version of the XML.
294 //TODO: to support files with BOM we would need to serialize on the fly the callback from the sax parser
295 read = (u32) gf_fread(szBOM, 3, xml);
296 if (read==3) {
297 gf_fseek(xml, 0, SEEK_SET);
298 if ((szBOM[0]==0xFF) || (szBOM[0]==0xFE) || (szBOM[0]==0xEF)) {
299 GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[NHMLDmx] import failure: XML file %s uses unsupported BOM, please convert to plain UTF-8 or ANSI first", xml_file));
300 goto exit;
301 }
302 }
303
304
305 memset(&breaker, 0, sizeof(XMLBreaker));
306 breaker.id_stack = gf_list_new();
307
308 if (strstr(xmlFrom, ".start")) breaker.from_is_start = GF_TRUE;
309 else breaker.from_is_end = GF_TRUE;
310 tmp = strchr(xmlFrom, '.');
311 *tmp = 0;
312 if (stricmp(xmlFrom, "doc")) breaker.from_id = gf_strdup(xmlFrom);
313 /*doc start pos is 0, no need to look for it*/
314 else if (breaker.from_is_start) breaker.from_is_start = GF_FALSE;
315 *tmp = '.';
316
317 if (strstr(xmlTo, ".start")) breaker.to_is_start = GF_TRUE;
318 else breaker.to_is_end = GF_TRUE;
319 tmp = strchr(xmlTo, '.');
320 *tmp = 0;
321 if (stricmp(xmlTo, "doc")) breaker.to_id = gf_strdup(xmlTo);
322 /*doc end pos is file size, no need to look for it*/
323 else if (breaker.to_is_end) breaker.to_is_end = GF_FALSE;
324 *tmp = '.';
325
326 breaker.sax = gf_xml_sax_new(nhml_node_start, nhml_node_end, NULL, &breaker);
327 e = gf_xml_sax_parse_file(breaker.sax, xml_file, NULL);
328 gf_xml_sax_del(breaker.sax);
329 if (e<0) goto exit;
330
331 if (!breaker.to_id) {
332 breaker.to_pos = gf_fsize(xml);
333 }
334 if (breaker.to_pos < breaker.from_pos) {
335 GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[NHMLDmx] import failure: xmlFrom %s is located after xmlTo %s", xmlFrom, xmlTo));
336 goto exit;
337 }
338
339 assert(breaker.to_pos > breaker.from_pos);
340
341
342 ctx->samp_buffer_size = (u32) (breaker.to_pos - breaker.from_pos);
343 if (ctx->samp_buffer_alloc < ctx->samp_buffer_size) {
344 ctx->samp_buffer_alloc = ctx->samp_buffer_size;
345 ctx->samp_buffer = (char*)gf_realloc(ctx->samp_buffer, sizeof(char)*ctx->samp_buffer_alloc);
346 }
347 gf_fseek(xml, breaker.from_pos, SEEK_SET);
348 if (0 == gf_fread(ctx->samp_buffer, ctx->samp_buffer_size, xml)) {
349 GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[NHMLDmx] Failed to read samp->dataLength\n"));
350 }
351 e = GF_OK;
352
353 exit:
354 if (xml) gf_fclose(xml);
355 while (gf_list_count(breaker.id_stack)) {
356 char *id = (char *)gf_list_last(breaker.id_stack);
357 gf_list_rem_last(breaker.id_stack);
358 gf_free(id);
359 }
360 gf_list_del(breaker.id_stack);
361 if (breaker.from_id) gf_free(breaker.from_id);
362 if (breaker.to_id) gf_free(breaker.to_id);
363 return e;
364 }
365
366
367 #ifndef GPAC_DISABLE_ZLIB
368
369 /*since 0.2.2, we use zlib for xmt/x3d reading to handle gz files*/
370 #include <zlib.h>
371
372 #define ZLIB_COMPRESS_SAFE 4
373
compress_sample_data(GF_NHMLDmxCtx * ctx,u32 compress_type,char ** dict,u32 offset)374 static GF_Err compress_sample_data(GF_NHMLDmxCtx *ctx, u32 compress_type, char **dict, u32 offset)
375 {
376 z_stream stream;
377 int err;
378 u32 size;
379
380 if (!ctx) return GF_OK;
381
382 size = ctx->samp_buffer_size*ZLIB_COMPRESS_SAFE;
383 if (ctx->zlib_buffer_alloc < size) {
384 ctx->zlib_buffer_alloc = size;
385 ctx->zlib_buffer = gf_realloc(ctx->zlib_buffer, sizeof(char)*size);
386 }
387
388 stream.next_in = (Bytef*) ctx->samp_buffer + offset;
389 stream.avail_in = (uInt)ctx->samp_buffer_size - offset;
390 stream.next_out = ( Bytef*)ctx->zlib_buffer;
391 stream.avail_out = (uInt)size;
392 stream.zalloc = (alloc_func)NULL;
393 stream.zfree = (free_func)NULL;
394 stream.opaque = (voidpf)NULL;
395
396 if (compress_type==1) {
397 err = deflateInit(&stream, 9);
398 } else {
399 err = deflateInit2(&stream, 9, Z_DEFLATED, 16+MAX_WBITS, 8, Z_DEFAULT_STRATEGY);
400 }
401 if (err != Z_OK) {
402 return GF_IO_ERR;
403 }
404 if (dict && *dict) {
405 err = deflateSetDictionary(&stream, (Bytef *)*dict, (u32) strlen(*dict));
406 if (err != Z_OK) {
407 GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[NHMLDmx] Error assigning dictionary\n"));
408 deflateEnd(&stream);
409 return GF_IO_ERR;
410 }
411 }
412 err = deflate(&stream, Z_FINISH);
413 if (err != Z_STREAM_END) {
414 deflateEnd(&stream);
415 return GF_IO_ERR;
416 }
417 if (ctx->samp_buffer_size - offset < stream.total_out) {
418 GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[NHMLDmx] compressed data (%d) bigger than input data (%d)\n", (u32) stream.total_out, (u32) ctx->samp_buffer_size - offset));
419 }
420 if (dict) {
421 if (*dict) gf_free(*dict);
422 *dict = (char*)gf_malloc(sizeof(char) * ctx->samp_buffer_size);
423 memcpy(*dict, ctx->samp_buffer, ctx->samp_buffer_size);
424 }
425 if (ctx->samp_buffer_alloc < stream.total_out) {
426 ctx->samp_buffer_alloc = (u32) (stream.total_out*2);
427 ctx->samp_buffer = (char*)gf_realloc(ctx->samp_buffer, ctx->samp_buffer_alloc * sizeof(char));
428 }
429
430 memcpy(ctx->samp_buffer + offset, ctx->zlib_buffer, sizeof(char)*stream.total_out);
431 ctx->samp_buffer_size = (u32) (offset + stream.total_out);
432
433 deflateEnd(&stream);
434 return GF_OK;
435 }
436
437 #endif /*GPAC_DISABLE_ZLIB*/
438
439 #define NHML_SCAN_INT(_fmt, _value) \
440 {\
441 if (strstr(att->value, "0x")) { u32 __i; sscanf(att->value+2, "%x", &__i); _value = __i; }\
442 else if (strstr(att->value, "0X")) { u32 __i; sscanf(att->value+2, "%X", &__i); _value = __i; }\
443 else sscanf(att->value, _fmt, &_value); \
444 }\
445
446
nhmldmx_init_parsing(GF_Filter * filter,GF_NHMLDmxCtx * ctx)447 static GF_Err nhmldmx_init_parsing(GF_Filter *filter, GF_NHMLDmxCtx *ctx)
448 {
449 GF_Err e;
450 Bool inRootOD;
451 u32 i, tkID, mtype, streamType, codecid, specInfoSize, par_den, par_num;
452 GF_XMLAttribute *att;
453 u32 width, height, codec_tag, sample_rate, nb_channels, version, revision, vendor_code, temporal_quality, spatial_quality, h_res, v_res, bit_depth, bits_per_sample;
454
455 u32 dims_profile, dims_level, dims_pathComponents, dims_fullRequestHost, dims_streamType, dims_containsRedundant;
456 char *textEncoding, *contentEncoding, *dims_content_script_types, *mime_type, *xml_schema_loc, *xmlns;
457 FILE *nhml;
458 const GF_PropertyValue *p;
459 char *auxiliary_mime_types = NULL;
460 char *ext, szName[1000], szInfo[GF_MAX_PATH], szXmlFrom[1000], szXmlHeaderEnd[1000];
461 u8 *specInfo;
462 char compressor_name[100];
463 GF_XMLNode *node;
464 FILE *finfo;
465 u64 media_size, last_dts;
466 char *szRootName, *szSampleName, *szImpName;
467
468 szRootName = ctx->is_dims ? "DIMSStream" : "NHNTStream";
469 szSampleName = ctx->is_dims ? "DIMSUnit" : "NHNTSample";
470 szImpName = ctx->is_dims ? "DIMS" : "NHML";
471
472 p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_FILEPATH);
473 if (!p) {
474 gf_filter_pid_drop_packet(ctx->ipid);
475 return GF_NOT_SUPPORTED;
476 }
477 ctx->src_url = p->value.string;
478 nhml = gf_fopen(ctx->src_url, "rt");
479 if (!nhml) {
480 GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[NHMLDmx] Cannot find %s file %s", szImpName, ctx->src_url));
481 return GF_URL_ERROR;
482 }
483
484 szName[0] = 0;
485 if (!strncmp(ctx->src_url, "gfio://", 7)) {
486 char *base = gf_file_basename( gf_fileio_translate_url(ctx->src_url) );
487 if (base) strcpy(szName, base);
488 } else {
489 strcpy(szName, ctx->src_url);
490 }
491 ext = gf_file_ext_start(szName);
492 if (ext) ext[0] = 0;
493 strcpy(ctx->szMedia, szName);
494 strcpy(szInfo, szName);
495 strcat(ctx->szMedia, ".media");
496 strcat(szInfo, ".info");
497
498 ctx->parser = gf_xml_dom_new();
499 e = gf_xml_dom_parse(ctx->parser, p->value.string, NULL, NULL);
500 if (e) {
501 gf_fclose(nhml);
502 GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[NHMLDmx] Error parsing %s file: Line %d - %s", szImpName, gf_xml_dom_get_line(ctx->parser), gf_xml_dom_get_error(ctx->parser) ));
503 return GF_NON_COMPLIANT_BITSTREAM;
504 }
505 gf_fclose(nhml);
506
507 ctx->root = gf_xml_dom_get_root(ctx->parser);
508 if (!ctx->root) {
509 GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[NHMLDmx] Error parsing %s file - no root node found", szImpName ));
510 return GF_NON_COMPLIANT_BITSTREAM;
511 }
512
513 ctx->dts_inc = 0;
514 inRootOD = GF_FALSE;
515 ctx->compress_type = 0;
516 specInfo = NULL;
517
518 #ifndef GPAC_DISABLE_ZLIB
519 ctx->use_dict = GF_FALSE;
520 #endif
521
522 if (stricmp(ctx->root->name, szRootName)) {
523 GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[NHMLDmx] Error parsing %s file - \"%s\" root expected, got \"%s\"", szImpName, szRootName, ctx->root->name));
524 return GF_NON_COMPLIANT_BITSTREAM;
525 }
526
527 tkID = mtype = streamType = codecid = par_den = par_num = 0;
528 ctx->timescale = 1000;
529 i=0;
530 strcpy(szXmlHeaderEnd, "");
531 ctx->header_end = 0;
532
533 width = height = codec_tag = sample_rate = nb_channels = version = revision = vendor_code = temporal_quality = spatial_quality = h_res = v_res = bit_depth = bits_per_sample = 0;
534
535 dims_pathComponents = dims_fullRequestHost = 0;
536 textEncoding = contentEncoding = dims_content_script_types = mime_type = xml_schema_loc = xmlns = NULL;
537 dims_profile = dims_level = 255;
538 dims_streamType = GF_TRUE;
539 dims_containsRedundant = 1;
540
541 while ((att = (GF_XMLAttribute *)gf_list_enum(ctx->root->attributes, &i))) {
542 if (!stricmp(att->name, "streamType")) {
543 NHML_SCAN_INT("%u", streamType)
544 } else if (!stricmp(att->name, "mediaType") && (strlen(att->value)==4)) {
545 mtype = GF_4CC(att->value[0], att->value[1], att->value[2], att->value[3]);
546 } else if (!stricmp(att->name, "mediaSubType") && (strlen(att->value)==4)) {
547 codec_tag = GF_4CC(att->value[0], att->value[1], att->value[2], att->value[3]);
548 } else if (!stricmp(att->name, "objectTypeIndication")) {
549 NHML_SCAN_INT("%u", codecid)
550 } else if (!stricmp(att->name, "codecID") && (strlen(att->value)==4)) {
551 codecid = GF_4CC(att->value[0], att->value[1], att->value[2], att->value[3]);
552 } else if (!stricmp(att->name, "timeScale")) {
553 NHML_SCAN_INT("%u", ctx->timescale)
554 } else if (!stricmp(att->name, "width")) {
555 NHML_SCAN_INT("%u", width)
556 } else if (!stricmp(att->name, "height")) {
557 NHML_SCAN_INT("%u", height)
558 } else if (!stricmp(att->name, "parNum")) {
559 NHML_SCAN_INT("%u", par_num)
560 } else if (!stricmp(att->name, "parDen")) {
561 NHML_SCAN_INT("%u", par_den)
562 } else if (!stricmp(att->name, "sampleRate")) {
563 NHML_SCAN_INT("%u", sample_rate)
564 } else if (!stricmp(att->name, "numChannels")) {
565 NHML_SCAN_INT("%u", nb_channels)
566 } else if (!stricmp(att->name, "baseMediaFile")) {
567 char *url = gf_url_concatenate(ctx->src_url, att->value);
568 strcpy(ctx->szMedia, url ? url : att->value);
569 if (url) gf_free(url);
570 } else if (!stricmp(att->name, "specificInfoFile")) {
571 char *url = gf_url_concatenate(ctx->src_url, att->value);
572 strcpy(szInfo, url ? url : att->value);
573 if (url) gf_free(url);
574 } else if (!stricmp(att->name, "headerEnd")) {
575 NHML_SCAN_INT("%u", ctx->header_end)
576 } else if (!stricmp(att->name, "trackID")) {
577 NHML_SCAN_INT("%u", tkID)
578 } else if (!stricmp(att->name, "inRootOD")) {
579 inRootOD = (!stricmp(att->value, "yes") );
580 } else if (!stricmp(att->name, "DTS_increment")) {
581 NHML_SCAN_INT("%u", ctx->dts_inc)
582 } else if (!stricmp(att->name, "gzipSamples")) {
583 if (!stricmp(att->value, "yes") || !stricmp(att->value, "gzip"))
584 ctx->compress_type = 2;
585 else if (!stricmp(att->value, "deflate"))
586 ctx->compress_type = 1;
587 } else if (!stricmp(att->name, "auxiliaryMimeTypes")) {
588 auxiliary_mime_types = gf_strdup(att->name);
589 }
590 #ifndef GPAC_DISABLE_ZLIB
591 else if (!stricmp(att->name, "gzipDictionary")) {
592 u32 d_size;
593 if (stricmp(att->value, "self")) {
594 char *url = gf_url_concatenate(ctx->src_url, att->value);
595
596 e = gf_file_load_data(url ? url : att->value, (u8 **) &ctx->dictionary, &d_size);
597
598 if (url) gf_free(url);
599 if (e) {
600 GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[NHMLDmx] Cannot open dictionary file %s: %s", att->value, gf_error_to_string(e) ));
601 continue;
602 }
603 }
604 ctx->use_dict = GF_TRUE;
605 }
606 #endif
607 /*unknown desc related*/
608 else if (!stricmp(att->name, "compressorName")) {
609 strncpy(compressor_name, att->value, 99);
610 compressor_name[99]=0;
611 } else if (!stricmp(att->name, "codecVersion")) {
612 NHML_SCAN_INT("%u", version)
613 } else if (!stricmp(att->name, "codecRevision")) {
614 NHML_SCAN_INT("%u", revision)
615 } else if (!stricmp(att->name, "codecVendor") && (strlen(att->value)==4)) {
616 vendor_code = GF_4CC(att->value[0], att->value[1], att->value[2], att->value[3]);
617 } else if (!stricmp(att->name, "temporalQuality")) {
618 NHML_SCAN_INT("%u", temporal_quality)
619 } else if (!stricmp(att->name, "spatialQuality")) {
620 NHML_SCAN_INT("%u", spatial_quality)
621 } else if (!stricmp(att->name, "horizontalResolution")) {
622 NHML_SCAN_INT("%u", h_res)
623 } else if (!stricmp(att->name, "verticalResolution")) {
624 NHML_SCAN_INT("%u", v_res)
625 } else if (!stricmp(att->name, "bitDepth")) {
626 NHML_SCAN_INT("%u", bit_depth)
627 } else if (!stricmp(att->name, "bitsPerSample")) {
628 NHML_SCAN_INT("%u", bits_per_sample)
629 }
630 /*DIMS stuff*/
631 else if (!stricmp(att->name, "profile")) {
632 NHML_SCAN_INT("%u", dims_profile)
633 } else if (!stricmp(att->name, "level")) {
634 NHML_SCAN_INT("%u", dims_level)
635 } else if (!stricmp(att->name, "pathComponents")) {
636 NHML_SCAN_INT("%u", dims_pathComponents)
637 } else if (!stricmp(att->name, "useFullRequestHost") && !stricmp(att->value, "yes")) {
638 dims_fullRequestHost = GF_TRUE;
639 } else if (!stricmp(att->name, "stream_type") && !stricmp(att->value, "secondary")) {
640 dims_streamType = GF_FALSE;
641 } else if (!stricmp(att->name, "contains_redundant")) {
642 if (!stricmp(att->value, "main")) {
643 dims_containsRedundant = 1;
644 } else if (!stricmp(att->value, "redundant")) {
645 dims_containsRedundant = 2;
646 } else if (!stricmp(att->value, "main+redundant")) {
647 dims_containsRedundant = 3;
648 }
649 } else if (!stricmp(att->name, "text_encoding") || !stricmp(att->name, "encoding")) {
650 textEncoding = att->value;
651 } else if (!stricmp(att->name, "content_encoding")) {
652 if (!strcmp(att->value, "deflate")) {
653 contentEncoding = att->value;
654 ctx->compress_type = 1;
655 }
656 else if (!strcmp(att->value, "gzip")) {
657 contentEncoding = att->value;
658 ctx->compress_type = 2;
659 }
660 } else if (!stricmp(att->name, "content_script_types")) {
661 dims_content_script_types = att->value;
662 } else if (!stricmp(att->name, "mime_type")) {
663 mime_type = att->value;
664 } else if (!stricmp(att->name, "media_namespace")) {
665 xmlns = att->value;
666 } else if (!stricmp(att->name, "media_schema_location")) {
667 xml_schema_loc = att->value;
668 } else if (!stricmp(att->name, "xml_namespace")) {
669 xmlns = att->value;
670 } else if (!stricmp(att->name, "xml_schema_location")) {
671 xml_schema_loc = att->value;
672 } else if (!stricmp(att->name, "xmlHeaderEnd")) {
673 strcpy(szXmlHeaderEnd, att->value);
674 }
675 }
676 if (sample_rate && !ctx->timescale) {
677 ctx->timescale = sample_rate;
678 }
679 if (!bits_per_sample) {
680 bits_per_sample = 16;
681 }
682
683 if (ctx->is_dims || (codec_tag==GF_ISOM_SUBTYPE_3GP_DIMS)) {
684 mtype = GF_ISOM_MEDIA_DIMS;
685 codec_tag=GF_ISOM_SUBTYPE_3GP_DIMS;
686 codecid = GF_CODECID_DIMS;
687 streamType = GF_STREAM_SCENE;
688 }
689 if (gf_file_exists_ex(ctx->szMedia, ctx->src_url))
690 ctx->mdia = gf_fopen_ex(ctx->szMedia, ctx->src_url, "rb");
691
692 specInfoSize = 0;
693 if (!streamType && !mtype && !codec_tag) {
694 GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[NHMLDmx] parsing %s file - StreamType or MediaType not specified", szImpName));
695 return GF_NON_COMPLIANT_BITSTREAM;
696 }
697
698 finfo = NULL;
699 if (gf_file_exists_ex(szInfo, ctx->src_url))
700 finfo = gf_fopen_ex(szInfo, ctx->src_url, "rb");
701
702 if (finfo) {
703 e = gf_file_load_data_filep(finfo, (u8 **)&specInfo, &specInfoSize);
704 gf_fclose(finfo);
705 if (e) return e;
706 } else if (ctx->header_end) {
707 /* for text based streams, the decoder specific info can be at the beginning of the file */
708 specInfoSize = ctx->header_end;
709 specInfo = (char*)gf_malloc(sizeof(char) * (specInfoSize+1));
710 specInfoSize = (u32) gf_fread(specInfo, specInfoSize, ctx->mdia);
711 specInfo[specInfoSize] = 0;
712 ctx->header_end = specInfoSize;
713 } else if (strlen(szXmlHeaderEnd)) {
714 /* for XML based streams, the decoder specific info can be up to some element in the file */
715 strcpy(szXmlFrom, "doc.start");
716 ctx->samp_buffer_size = 0;
717 e = nhml_sample_from_xml(ctx, ctx->szMedia, szXmlFrom, szXmlHeaderEnd);
718 if (e) {
719 GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[NHMLDmx] failed to load XML header: %s", gf_error_to_string(e) ));
720 return e;
721 }
722
723 specInfo = (char*)gf_malloc(sizeof(char) * (ctx->samp_buffer_size +1));
724 memcpy(specInfo, ctx->samp_buffer, ctx->samp_buffer_size);
725 specInfoSize = ctx->samp_buffer_size;
726 specInfo[specInfoSize] = 0;
727 }
728
729 i=0;
730 while ((node = (GF_XMLNode *) gf_list_enum(ctx->root->content, &i))) {
731 if (node->type) continue;
732 if (stricmp(node->name, "DecoderSpecificInfo") ) continue;
733
734 e = gf_xml_parse_bit_sequence(node, ctx->src_url, &specInfo, &specInfoSize);
735 if (e) {
736 if (specInfo) gf_free(specInfo);
737 return e;
738 }
739 break;
740 }
741
742 ctx->opid = gf_filter_pid_new(filter);
743 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_STREAM_TYPE, &PROP_UINT(streamType) );
744 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CODECID, &PROP_UINT(codecid) );
745 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_TIMESCALE, &PROP_UINT(ctx->timescale) );
746 if (ctx->reframe)
747 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_UNFRAMED, &PROP_UINT(GF_TRUE) );
748
749 #ifndef GPAC_DISABLE_AV_PARSERS
750 if (!width && !height && specInfo && (codecid==GF_CODECID_MPEG4_PART2)) {
751 GF_M4VDecSpecInfo dsi;
752 e = gf_m4v_get_config(specInfo, specInfoSize, &dsi);
753 if (!e) {
754 width = dsi.width;
755 height = dsi.height;
756 par_num = dsi.par_num;
757 par_den = dsi.par_den;
758 }
759 }
760 #endif
761
762 if (tkID) gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_ESID, &PROP_UINT(tkID) );
763 if (width) gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_WIDTH, &PROP_UINT(width) );
764 if (height) gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_HEIGHT, &PROP_UINT(height) );
765
766 if (par_den) gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_SAR, &PROP_FRAC_INT(par_num, par_den) );
767 switch (bits_per_sample) {
768 case 8:
769 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_AUDIO_FORMAT, &PROP_UINT(GF_AUDIO_FMT_U8) );
770 break;
771 case 16:
772 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_AUDIO_FORMAT, &PROP_UINT(GF_AUDIO_FMT_S16) );
773 break;
774 case 24:
775 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_AUDIO_FORMAT, &PROP_UINT(GF_AUDIO_FMT_S24) );
776 break;
777 case 32:
778 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_AUDIO_FORMAT, &PROP_UINT(GF_AUDIO_FMT_S32) );
779 break;
780 default:
781 GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[NHMLDmx] Unsupported audio bit depth %d\n", bits_per_sample));
782 break;
783 }
784
785 if (sample_rate) gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_SAMPLE_RATE, &PROP_UINT(sample_rate) );
786 if (nb_channels) gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_NUM_CHANNELS, &PROP_UINT(nb_channels) );
787 if (bit_depth) gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_BIT_DEPTH_Y, &PROP_UINT(bit_depth) );
788
789 if (ctx->is_dims) {
790 if (dims_profile) gf_filter_pid_set_property_str(ctx->opid, "dims:profile", &PROP_UINT(dims_profile) );
791 if (dims_level) gf_filter_pid_set_property_str(ctx->opid, "dims:level", &PROP_UINT(dims_level) );
792 if (dims_pathComponents) gf_filter_pid_set_property_str(ctx->opid, "dims:pathComponents", &PROP_UINT(dims_pathComponents) );
793 if (dims_fullRequestHost) gf_filter_pid_set_property_str(ctx->opid, "dims:fullRequestHost", &PROP_UINT(dims_fullRequestHost) );
794 if (dims_streamType) gf_filter_pid_set_property_str(ctx->opid, "dims:streamType", &PROP_BOOL(dims_streamType) );
795 if (dims_containsRedundant) gf_filter_pid_set_property_str(ctx->opid, "dims:redundant", &PROP_UINT(dims_containsRedundant) );
796 if (textEncoding) gf_filter_pid_set_property_str(ctx->opid, "meta:encoding", &PROP_STRING(textEncoding) );
797 if (contentEncoding) gf_filter_pid_set_property_str(ctx->opid, "meta:content_encoding", &PROP_STRING(contentEncoding) );
798 if (dims_content_script_types) gf_filter_pid_set_property_str(ctx->opid, "dims:scriptTypes", &PROP_STRING(dims_content_script_types) );
799 if (mime_type) gf_filter_pid_set_property_str(ctx->opid, "meta:mime", &PROP_STRING(mime_type) );
800 if (xml_schema_loc) gf_filter_pid_set_property_str(ctx->opid, "meta:schemaloc", &PROP_STRING(xml_schema_loc) );
801
802 } else if (mtype == GF_ISOM_MEDIA_MPEG_SUBT || mtype == GF_ISOM_MEDIA_SUBT || mtype == GF_ISOM_MEDIA_TEXT) {
803 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_STREAM_TYPE, &PROP_UINT(mtype) );
804 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CODECID, &PROP_UINT(codec_tag) );
805
806 if (codec_tag == GF_ISOM_SUBTYPE_STPP) {
807 if (xmlns) gf_filter_pid_set_property_str(ctx->opid, "meta:xmlns", &PROP_STRING(xmlns) );
808 if (xml_schema_loc) gf_filter_pid_set_property_str(ctx->opid, "meta:schemaloc", &PROP_STRING(xml_schema_loc) );
809 if (auxiliary_mime_types) gf_filter_pid_set_property_str(ctx->opid, "meta:aux_mimes", &PROP_STRING(auxiliary_mime_types) );
810
811 } else if (codec_tag == GF_ISOM_SUBTYPE_SBTT) {
812 if (mime_type) gf_filter_pid_set_property_str(ctx->opid, "meta:mime", &PROP_STRING(mime_type) );
813 if (textEncoding) gf_filter_pid_set_property_str(ctx->opid, "meta:encoding", &PROP_STRING(textEncoding) );
814 } else if (codec_tag == GF_ISOM_SUBTYPE_STXT) {
815 if (mime_type) gf_filter_pid_set_property_str(ctx->opid, "meta:mime", &PROP_STRING(mime_type) );
816 if (textEncoding) gf_filter_pid_set_property_str(ctx->opid, "meta:encoding", &PROP_STRING(textEncoding) );
817 if (contentEncoding) gf_filter_pid_set_property_str(ctx->opid, "meta:content_encoding", &PROP_STRING(contentEncoding) );
818 } else {
819 e = GF_NOT_SUPPORTED;
820 }
821 } else if (mtype == GF_ISOM_MEDIA_META) {
822 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_STREAM_TYPE, &PROP_UINT(mtype) );
823 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CODECID, &PROP_UINT(codec_tag) );
824
825 if (codec_tag == GF_ISOM_SUBTYPE_METX) {
826 if (xmlns) gf_filter_pid_set_property_str(ctx->opid, "meta:xmlns", &PROP_STRING(xmlns) );
827 if (xml_schema_loc) gf_filter_pid_set_property_str(ctx->opid, "meta:schemaloc", &PROP_STRING(xml_schema_loc) );
828 if (textEncoding) gf_filter_pid_set_property_str(ctx->opid, "meta:encoding", &PROP_STRING(textEncoding) );
829 } else if (codec_tag == GF_ISOM_SUBTYPE_METT) {
830 if (mime_type) gf_filter_pid_set_property_str(ctx->opid, "meta:mime", &PROP_STRING(mime_type) );
831 if (textEncoding) gf_filter_pid_set_property_str(ctx->opid, "meta:encoding", &PROP_STRING(textEncoding) );
832 } else {
833 e = GF_NOT_SUPPORTED;
834 }
835 } else if (!streamType) {
836 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_STREAM_TYPE, &PROP_UINT(mtype) );
837 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CODECID, &PROP_UINT(codec_tag) );
838
839 if (version) gf_filter_pid_set_property_str(ctx->opid, "gene:version", &PROP_UINT(version) );
840 if (revision) gf_filter_pid_set_property_str(ctx->opid, "gene:revision", &PROP_UINT(revision) );
841 if (vendor_code) gf_filter_pid_set_property_str(ctx->opid, "gene:vendor", &PROP_UINT(vendor_code) );
842 if (temporal_quality) gf_filter_pid_set_property_str(ctx->opid, "gene:temporal_quality", &PROP_UINT(temporal_quality) );
843 if (spatial_quality) gf_filter_pid_set_property_str(ctx->opid, "gene:spatial_quality", &PROP_UINT(spatial_quality) );
844 if (h_res) gf_filter_pid_set_property_str(ctx->opid, "gene:horizontal_res", &PROP_UINT(h_res) );
845 if (v_res) gf_filter_pid_set_property_str(ctx->opid, "gene:vertical_res", &PROP_UINT(v_res) );
846 }
847
848
849 if (specInfo) {
850 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DECODER_CONFIG, &PROP_DATA_NO_COPY(specInfo, specInfoSize) );
851 specInfo = NULL;
852 specInfoSize = 0;
853 }
854
855 if (inRootOD) gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_IN_IOD, &PROP_BOOL(GF_TRUE) );
856
857 ctx->media_done = 0;
858 ctx->current_child_idx = 0;
859 ctx->last_dts = GF_FILTER_NO_TS;
860
861 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_FILEPATH, & PROP_STRING(ctx->szMedia));
862
863 if (ctx->mdia) {
864 media_size = gf_fsize(ctx->mdia);
865 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DOWN_SIZE, & PROP_LONGUINT(media_size) );
866 }
867
868 if (specInfo) gf_free(specInfo);
869 if (auxiliary_mime_types) gf_free(auxiliary_mime_types);
870
871 //compute duration
872 ctx->duration.den = ctx->timescale;
873 ctx->duration.num = 0;
874 last_dts = 0;
875 i=0;
876 ctx->has_sap = GF_FALSE;
877 while ((node = (GF_XMLNode *) gf_list_enum(ctx->root->content, &i))) {
878 u32 j=0;
879 u64 dts=0;
880 s32 cts_offset=0;
881 u64 sample_duration = 0;
882 if (node->type) continue;
883 if (stricmp(node->name, szSampleName) ) continue;
884
885 while ( (att = (GF_XMLAttribute *)gf_list_enum(node->attributes, &j))) {
886 if (!stricmp(att->name, "DTS") || !stricmp(att->name, "time")) {
887 u32 h, m, s, ms;
888 u64 dst_val;
889 if (strchr(att->value, ':') && sscanf(att->value, "%u:%u:%u.%u", &h, &m, &s, &ms) == 4) {
890 dts = (u64) ( (Double) ( ((h*3600.0 + m*60.0 + s)*1000 + ms) / 1000.0) * ctx->timescale );
891 } else if (sscanf(att->value, ""LLU, &dst_val)==1) {
892 dts = dst_val;
893 }
894 }
895 else if (!stricmp(att->name, "CTSOffset")) cts_offset = atoi(att->value);
896 else if (!stricmp(att->name, "duration") ) sscanf(att->value, ""LLU, &sample_duration);
897 else if (!stricmp(att->name, "isRAP") ) ctx->has_sap = GF_TRUE;
898 }
899 last_dts = ctx->duration.num;
900 if (dts) ctx->duration.num = (u32) (dts + cts_offset);
901 if (sample_duration) {
902 last_dts = 0;
903 ctx->duration.num += (u32) sample_duration;
904 } else if (ctx->dts_inc) {
905 last_dts = 0;
906 ctx->duration.num += ctx->dts_inc;
907 }
908 }
909 if (last_dts) {
910 ctx->duration.num += (u32) (ctx->duration.num - last_dts);
911 }
912 //assume image, one sec (default for old arch)
913 if ((streamType==4) && !ctx->duration.num) {
914 ctx->is_img = GF_TRUE;
915 ctx->duration.num =ctx->duration.den;
916 }
917
918 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DURATION, & PROP_FRAC64(ctx->duration) );
919
920 return e;
921 }
922
nhml_get_bs(GF_BitStream ** bs,char * data,u32 size,u32 mode)923 void nhml_get_bs(GF_BitStream **bs, char *data, u32 size, u32 mode)
924 {
925 if (*bs) gf_bs_reassign_buffer(*bs, data, size);
926 else (*bs) = gf_bs_new(data, size, mode);
927 }
928
nhmldmx_send_sample(GF_Filter * filter,GF_NHMLDmxCtx * ctx)929 static GF_Err nhmldmx_send_sample(GF_Filter *filter, GF_NHMLDmxCtx *ctx)
930 {
931 GF_XMLNode *node, *childnode;
932 u64 sample_duration = 0;
933 char szMediaTemp[GF_MAX_PATH], szXmlFrom[1000], szXmlTo[1000];
934 char *szSubSampleName = ctx->is_dims ? "DIMSSubUnit" : "NHNTSubSample";
935
936 while ((node = (GF_XMLNode *) gf_list_enum(ctx->root->content, &ctx->current_child_idx))) {
937 u8 *data;
938 GF_FilterPacket *pck;
939 u32 j, dims_flags;
940 GF_FilterSAPType sap_type;
941 GF_XMLAttribute *att;
942 u64 dts=0;
943 GF_Err e=GF_OK;
944 s32 cts_offset;
945 u64 offset=0, byte_offset = GF_FILTER_NO_BO;
946 u32 nb_subsamples = 0;
947 Bool redundant_rap, append, has_subbs, first_subsample_is_first = GF_FALSE;
948 u32 compress_type;
949 char *base_data = NULL;
950 if (node->type) continue;
951 if (stricmp(node->name, ctx->is_dims ? "DIMSUnit" : "NHNTSample") ) continue;
952
953 strcpy(szMediaTemp, "");
954 strcpy(szXmlFrom, "");
955 strcpy(szXmlTo, "");
956
957 /*by default handle all samples as contiguous*/
958 ctx->samp_buffer_size = 0;
959 dims_flags = 0;
960 append = GF_FALSE;
961 compress_type = ctx->compress_type;
962 sample_duration = 0;
963 redundant_rap = 0;
964 sap_type = ctx->has_sap ? GF_FILTER_SAP_NONE : GF_FILTER_SAP_1;
965
966 cts_offset = 0;
967 if (ctx->last_dts != GF_FILTER_NO_TS)
968 dts = ctx->last_dts;
969 else
970 dts = 0;
971
972 ctx->sample_num++;
973
974
975 j=0;
976 while ( (att = (GF_XMLAttribute *)gf_list_enum(node->attributes, &j))) {
977 if (!stricmp(att->name, "DTS") || !stricmp(att->name, "time")) {
978 u32 h, m, s, ms;
979 u64 dst_val;
980 if (strchr(att->value, ':') && sscanf(att->value, "%u:%u:%u.%u", &h, &m, &s, &ms) == 4) {
981 dts = (u64) ( (Double) ( ((h*3600.0 + m*60.0 + s)*1000 + ms) / 1000.0) * ctx->timescale );
982 } else if (sscanf(att->value, ""LLU, &dst_val)==1) {
983 dts = dst_val;
984 }
985 }
986 else if (!stricmp(att->name, "CTSOffset")) cts_offset = atoi(att->value);
987 else if (!stricmp(att->name, "isRAP") ) {
988 sap_type = (!stricmp(att->value, "yes")) ? GF_FILTER_SAP_1 : GF_FILTER_SAP_NONE;
989 }
990 else if (!stricmp(att->name, "isSyncShadow")) redundant_rap = !stricmp(att->value, "yes") ? 1 : 0;
991 else if (!stricmp(att->name, "SAPType") ) sap_type = atoi(att->value);
992 else if (!stricmp(att->name, "mediaOffset")) offset = (s64) atof(att->value) ;
993 else if (!stricmp(att->name, "dataLength")) ctx->samp_buffer_size = atoi(att->value);
994 else if (!stricmp(att->name, "mediaFile")) {
995 if (!strncmp(att->value, "data:", 5)) {
996 char *base = strstr(att->value, "base64,");
997 if (!base) {
998 GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[NHMLDmx] Data encoding scheme not recognized in sample %d - skipping\n", ctx->sample_num));
999 } else {
1000 base_data = att->value;
1001 }
1002 } else {
1003 char *url = gf_url_concatenate(ctx->src_url, att->value);
1004 strcpy(szMediaTemp, url ? url : att->value);
1005 if (url) gf_free(url);
1006 }
1007 }
1008 else if (!stricmp(att->name, "xmlFrom")) strcpy(szXmlFrom, att->value);
1009 else if (!stricmp(att->name, "xmlTo")) strcpy(szXmlTo, att->value);
1010 /*DIMS flags*/
1011 else if (!stricmp(att->name, "is-Scene") && !stricmp(att->value, "yes"))
1012 dims_flags |= GF_DIMS_UNIT_S;
1013 else if (!stricmp(att->name, "is-RAP") && !stricmp(att->value, "yes")) {
1014 dims_flags |= GF_DIMS_UNIT_M;
1015 sap_type = GF_FILTER_SAP_1;
1016 }
1017 else if (!stricmp(att->name, "is-redundant") && !stricmp(att->value, "yes"))
1018 dims_flags |= GF_DIMS_UNIT_I;
1019 else if (!stricmp(att->name, "redundant-exit") && !stricmp(att->value, "yes"))
1020 dims_flags |= GF_DIMS_UNIT_D;
1021 else if (!stricmp(att->name, "priority") && !stricmp(att->value, "high"))
1022 dims_flags |= GF_DIMS_UNIT_P;
1023 else if (!stricmp(att->name, "compress") && !stricmp(att->value, "yes"))
1024 dims_flags |= GF_DIMS_UNIT_C;
1025 else if (!stricmp(att->name, "duration") )
1026 sscanf(att->value, ""LLU, &sample_duration);
1027 }
1028 if (sap_type==GF_FILTER_SAP_1)
1029 dims_flags |= GF_DIMS_UNIT_M;
1030
1031 if (ctx->is_dims)
1032 compress_type = (dims_flags & GF_DIMS_UNIT_C) ? 2 : 0 ;
1033
1034 if (ctx->is_img) sample_duration = ctx->duration.den;
1035
1036 has_subbs = GF_FALSE;
1037 j=0;
1038 while ((childnode = (GF_XMLNode *) gf_list_enum(node->content, &j))) {
1039 if (childnode->type) continue;
1040 if (!stricmp(childnode->name, "BS")) {
1041 has_subbs = GF_TRUE;
1042 break;
1043 }
1044 }
1045
1046 if (strlen(szXmlFrom) && strlen(szXmlTo)) {
1047 char *xml_file;
1048 if (strlen(szMediaTemp)) xml_file = szMediaTemp;
1049 else xml_file = ctx->szMedia;
1050 ctx->samp_buffer_size = 0;
1051 e = nhml_sample_from_xml(ctx, xml_file, szXmlFrom, szXmlTo);
1052 } else if (ctx->is_dims && !strlen(szMediaTemp)) {
1053
1054 char *content = gf_xml_dom_serialize(node, GF_TRUE);
1055
1056 ctx->samp_buffer_size = 3 + (u32) strlen(content);
1057 if (ctx->samp_buffer_alloc < ctx->samp_buffer_size) {
1058 ctx->samp_buffer_alloc = ctx->samp_buffer_size;
1059 ctx->samp_buffer = gf_realloc(ctx->samp_buffer, ctx->samp_buffer_size);
1060 }
1061 nhml_get_bs(&ctx->bs_w, ctx->samp_buffer, ctx->samp_buffer_size, GF_BITSTREAM_WRITE);
1062 gf_bs_write_u16(ctx->bs_w, ctx->samp_buffer_size - 2);
1063 gf_bs_write_u8(ctx->bs_w, (u8) dims_flags);
1064 gf_bs_write_data(ctx->bs_w, content, (ctx->samp_buffer_size - 3));
1065 gf_free(content);
1066
1067 /*same DIMS unit*/
1068 if (ctx->last_dts == dts)
1069 append = GF_TRUE;
1070
1071 } else if (has_subbs) {
1072 gf_bs_reassign_buffer(ctx->bs_w, ctx->samp_buffer, ctx->samp_buffer_alloc);
1073 gf_xml_parse_bit_sequence_bs(node, ctx->src_url, ctx->bs_w);
1074 gf_bs_get_content(ctx->bs_w, &ctx->samp_buffer, &ctx->samp_buffer_size);
1075 if (ctx->samp_buffer_size > ctx->samp_buffer_alloc)
1076 ctx->samp_buffer_alloc = ctx->samp_buffer_size;
1077
1078 } else if (base_data) {
1079 char *start = strchr(base_data, ',');
1080 if (start) {
1081 u32 len = (u32)strlen(start+1);
1082 if (len > ctx->samp_buffer_alloc) {
1083 ctx->samp_buffer_alloc = len;
1084 ctx->samp_buffer = gf_realloc(ctx->samp_buffer, sizeof(char)*ctx->samp_buffer_alloc);
1085 }
1086 ctx->samp_buffer_size = gf_base64_decode(start, len, ctx->samp_buffer, ctx->samp_buffer_alloc);
1087 }
1088 } else {
1089 Bool close = GF_FALSE;
1090 FILE *f = ctx->mdia;
1091
1092 j = 0;
1093 while ((childnode = (GF_XMLNode *)gf_list_enum(node->content, &j))) {
1094 if (childnode->type) continue;
1095 if (!stricmp(childnode->name, szSubSampleName)) {
1096 nb_subsamples++;
1097 }
1098 }
1099
1100 if (strlen(szMediaTemp)) {
1101 f = gf_fopen(szMediaTemp, "rb");
1102 if (!f) {
1103 GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[NHMLDmx] import failure in sample %d: file %s not found", ctx->sample_num, close ? szMediaTemp : ctx->szMedia));
1104 return GF_NON_COMPLIANT_BITSTREAM;
1105 }
1106 close = GF_TRUE;
1107 if (offset) gf_fseek(f, offset, SEEK_SET);
1108 //when using dedicated source files per samples, we don't allow for data reference yet
1109 } else {
1110 if (!offset) offset = ctx->media_done;
1111 byte_offset = offset;
1112 }
1113
1114 if (f) {
1115 if (!ctx->samp_buffer_size) {
1116 u64 ssize = gf_fsize(f);
1117 assert(ssize < 0x80000000);
1118 ctx->samp_buffer_size = (u32) ssize;
1119 }
1120 gf_fseek(f, offset, SEEK_SET);
1121
1122 if (ctx->is_dims) {
1123 u32 read;
1124 if (ctx->samp_buffer_size + 3 > ctx->samp_buffer_alloc) {
1125 ctx->samp_buffer_alloc = ctx->samp_buffer_size + 3;
1126 ctx->samp_buffer = (char*)gf_realloc(ctx->samp_buffer, sizeof(char) * ctx->samp_buffer_alloc);
1127 }
1128 nhml_get_bs(&ctx->bs_w, ctx->samp_buffer, ctx->samp_buffer_alloc, GF_BITSTREAM_WRITE);
1129 gf_bs_write_u16(ctx->bs_w, ctx->samp_buffer_size+1);
1130 gf_bs_write_u8(ctx->bs_w, (u8) dims_flags);
1131 read = (u32) gf_fread( ctx->samp_buffer + 3, ctx->samp_buffer_size, f);
1132 if (ctx->samp_buffer_size != read) {
1133 GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[NHMLDmx] Failed to fully read sample %d: dataLength %d read %d\n", ctx->sample_num, ctx->samp_buffer_size, read));
1134 }
1135 ctx->samp_buffer_size += 3;
1136
1137 /*same DIMS unit*/
1138 if (ctx->last_dts == dts)
1139 append = GF_TRUE;
1140 } else {
1141 u32 read;
1142 if (ctx->samp_buffer_alloc < ctx->samp_buffer_size) {
1143 ctx->samp_buffer_alloc = ctx->samp_buffer_size;
1144 ctx->samp_buffer = (char*)gf_realloc(ctx->samp_buffer, sizeof(char) * ctx->samp_buffer_alloc);
1145 }
1146 read = (u32) gf_fread(ctx->samp_buffer, ctx->samp_buffer_size, f);
1147 if (ctx->samp_buffer_size != read) {
1148 GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[NHMLDmx] Failed to fully read sample %d: dataLength %d read %d\n", ctx->sample_num, ctx->samp_buffer_size, read));
1149 }
1150 }
1151 if (close) gf_fclose(f);
1152 } else if (!nb_subsamples) {
1153 GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[NHMLDmx] No media file associated with sample %d!\n", ctx->sample_num));
1154 e = GF_URL_ERROR;
1155 }
1156 }
1157
1158 if (e) return e;
1159
1160 //override DIMS flags
1161 if (ctx->is_dims) {
1162 if (strstr(ctx->samp_buffer + 3, "svg ")) dims_flags |= GF_DIMS_UNIT_S;
1163 if (dims_flags & GF_DIMS_UNIT_S) dims_flags |= GF_DIMS_UNIT_P;
1164 ctx->samp_buffer[2] = dims_flags;
1165 }
1166
1167 if (compress_type) {
1168 #ifndef GPAC_DISABLE_ZLIB
1169 e = compress_sample_data(ctx, compress_type, ctx->use_dict ? &ctx->dictionary : NULL, ctx->is_dims ? 3 : 0);
1170 if (e) return e;
1171
1172 if (ctx->is_dims) {
1173 nhml_get_bs(&ctx->bs_w, ctx->samp_buffer, ctx->samp_buffer_size, GF_BITSTREAM_WRITE);
1174 gf_bs_write_u16(ctx->bs_w, ctx->samp_buffer_size-2);
1175 }
1176 #else
1177 GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[NHMLDmx] Error: your version of GPAC was compiled with no libz support. Abort."));
1178 return GF_NOT_SUPPORTED;
1179 #endif
1180 }
1181
1182 if (ctx->is_dims && (ctx->samp_buffer_size > 0xFFFF)) {
1183 GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[NHMLDmx] DIMS import failure: sample %d data is too long - maximum size allowed: 65532 bytes", ctx->sample_num));
1184 return GF_NON_COMPLIANT_BITSTREAM;
1185 }
1186 if (ctx->samp_buffer_size) {
1187 pck = gf_filter_pck_new_alloc(ctx->opid, ctx->samp_buffer_size, &data);
1188 memcpy(data, ctx->samp_buffer, ctx->samp_buffer_size);
1189 gf_filter_pck_set_framing(pck, append ? GF_FALSE : GF_TRUE, nb_subsamples ? GF_FALSE : GF_TRUE);
1190 if (!append) {
1191 gf_filter_pck_set_sap(pck, sap_type);
1192 gf_filter_pck_set_dts(pck, dts);
1193 gf_filter_pck_set_cts(pck, dts+cts_offset);
1194 if (redundant_rap && !ctx->is_dims) gf_filter_pck_set_dependency_flags(pck, 0x1);
1195
1196 if (sample_duration || ctx->dts_inc)
1197 gf_filter_pck_set_duration(pck, sample_duration ? (u32) sample_duration : ctx->dts_inc);
1198
1199 if (byte_offset != GF_FILTER_NO_BO)
1200 gf_filter_pck_set_byte_offset(pck, byte_offset);
1201
1202 if (ctx->in_seek) {
1203 if (dts+cts_offset >= ctx->start_range * ctx->timescale)
1204 ctx->in_seek = GF_FALSE;
1205 else
1206 gf_filter_pck_set_seek_flag(pck, GF_TRUE);
1207 }
1208 }
1209 gf_filter_pck_send(pck);
1210 } else {
1211 first_subsample_is_first = GF_TRUE;
1212 }
1213
1214 if (nb_subsamples) {
1215 if (ctx->samp_buffer_alloc<14*nb_subsamples) {
1216 ctx->samp_buffer_alloc = 14*nb_subsamples;
1217 ctx->samp_buffer = gf_realloc(ctx->samp_buffer, ctx->samp_buffer_alloc);
1218 }
1219 assert(ctx->samp_buffer);
1220 nhml_get_bs(&ctx->bs_w, ctx->samp_buffer, ctx->samp_buffer_alloc, GF_BITSTREAM_WRITE);
1221 }
1222
1223 j = 0;
1224 while (!append && nb_subsamples && (childnode = (GF_XMLNode *)gf_list_enum(node->content, &j))) {
1225 if (childnode->type) continue;
1226 if (!stricmp(childnode->name, szSubSampleName)) {
1227 u32 k = 0;
1228 while ((att = (GF_XMLAttribute *)gf_list_enum(childnode->attributes, &k))) {
1229 if (!stricmp(att->name, "mediaFile")) {
1230 u64 subsMediaFileSize = 0;
1231 FILE *f = NULL;
1232 char *sub_file_url = gf_url_concatenate(ctx->src_url, att->value);
1233 if (sub_file_url) {
1234 f = gf_fopen(sub_file_url, "rb");
1235 gf_free(sub_file_url);
1236 }
1237
1238 if (!f) {
1239 GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[NHMLDmx] Error: mediaFile \"%s\" not found for subsample in sample %d. Abort.\n", att->value, ctx->sample_num));
1240 return GF_URL_ERROR;
1241 }
1242 subsMediaFileSize = gf_fsize(f);
1243 assert(subsMediaFileSize < 0x80000000);
1244
1245 //send continuation frame
1246 pck = gf_filter_pck_new_alloc(ctx->opid, (u32) subsMediaFileSize, &data);
1247 subsMediaFileSize = (u32) gf_fread(data, (u32) subsMediaFileSize, f);
1248 gf_fclose(f);
1249
1250 nb_subsamples--;
1251 if (first_subsample_is_first) {
1252 gf_filter_pck_set_framing(pck, GF_TRUE, nb_subsamples ? GF_FALSE : GF_TRUE);
1253
1254 gf_filter_pck_set_sap(pck, sap_type);
1255 gf_filter_pck_set_dts(pck, dts);
1256 gf_filter_pck_set_cts(pck, dts+cts_offset);
1257 if (redundant_rap && !ctx->is_dims) gf_filter_pck_set_dependency_flags(pck, 0x1);
1258
1259 if (sample_duration || ctx->dts_inc)
1260 gf_filter_pck_set_duration(pck, sample_duration ? (u32) sample_duration : ctx->dts_inc);
1261
1262 if (ctx->in_seek) {
1263 if (dts+cts_offset >= ctx->start_range * ctx->timescale)
1264 ctx->in_seek = GF_FALSE;
1265 else
1266 gf_filter_pck_set_seek_flag(pck, GF_TRUE);
1267 }
1268
1269 first_subsample_is_first = GF_FALSE;
1270 } else {
1271 gf_filter_pck_set_framing(pck, GF_FALSE, nb_subsamples ? GF_FALSE : GF_TRUE);
1272 }
1273
1274
1275 gf_bs_write_u32(ctx->bs_w, 0); //flags
1276 gf_bs_write_u32(ctx->bs_w, (u32) subsMediaFileSize);
1277 gf_bs_write_u32(ctx->bs_w, 0); //reserved
1278 gf_bs_write_u8(ctx->bs_w, 0); //priority
1279 gf_bs_write_u8(ctx->bs_w, 0); //discardable
1280
1281 if (!nb_subsamples) {
1282 u32 subs_size = (u32) gf_bs_get_position(ctx->bs_w);
1283 gf_filter_pck_set_property(pck, GF_PROP_PCK_SUBS, &PROP_DATA(ctx->samp_buffer, subs_size) );
1284 }
1285
1286 gf_filter_pck_send(pck);
1287 }
1288 }
1289 }
1290 }
1291
1292 ctx->last_dts = dts;
1293
1294 if (sample_duration)
1295 ctx->last_dts += sample_duration;
1296 else
1297 ctx->last_dts += ctx->dts_inc;
1298 ctx->media_done += ctx->samp_buffer_size;
1299
1300 if (gf_filter_pid_would_block(ctx->opid))
1301 return GF_OK;
1302 }
1303 ctx->parsing_state = 2;
1304 return GF_OK;
1305 }
1306
nhmldmx_process(GF_Filter * filter)1307 GF_Err nhmldmx_process(GF_Filter *filter)
1308 {
1309 GF_NHMLDmxCtx *ctx = gf_filter_get_udta(filter);
1310 GF_FilterPacket *pck;
1311 GF_Err e;
1312 Bool start, end;
1313
1314 pck = gf_filter_pid_get_packet(ctx->ipid);
1315 if (pck) {
1316 gf_filter_pck_get_framing(pck, &start, &end);
1317 //for now we only work with complete files
1318 assert(end);
1319 }
1320
1321
1322 //need init ?
1323 switch (ctx->parsing_state) {
1324 case 0:
1325 e = nhmldmx_init_parsing(filter, ctx);
1326 if (e) {
1327 ctx->parsing_state = 3;
1328 return e;
1329 }
1330 ctx->parsing_state = 1;
1331 //fall-through
1332 case 1:
1333 if (!ctx->is_playing) return GF_OK;
1334
1335 e = nhmldmx_send_sample(filter, ctx);
1336 if (e) return e;
1337 break;
1338 case 2:
1339 default:
1340 if (pck) gf_filter_pid_drop_packet(ctx->ipid);
1341 if (ctx->opid) {
1342 gf_filter_pid_set_eos(ctx->opid);
1343 return GF_EOS;
1344 }
1345 break;
1346 }
1347 return GF_OK;
1348 }
1349
nhmldmx_initialize(GF_Filter * filter)1350 GF_Err nhmldmx_initialize(GF_Filter *filter)
1351 {
1352 // GF_NHMLDmxCtx *ctx = gf_filter_get_udta(filter);
1353 return GF_OK;
1354 }
1355
nhmldmx_finalize(GF_Filter * filter)1356 void nhmldmx_finalize(GF_Filter *filter)
1357 {
1358 GF_NHMLDmxCtx *ctx = gf_filter_get_udta(filter);
1359 if (ctx->mdia) gf_fclose(ctx->mdia);
1360 if (ctx->parser)
1361 gf_xml_dom_del(ctx->parser);
1362
1363 #ifndef GPAC_DISABLE_ZLIB
1364 if (ctx->dictionary) gf_free(ctx->dictionary);
1365 #endif
1366 if (ctx->bs_r) gf_bs_del(ctx->bs_r);
1367 if (ctx->bs_w) gf_bs_del(ctx->bs_w);
1368 if (ctx->samp_buffer) gf_free(ctx->samp_buffer);
1369 if (ctx->zlib_buffer) gf_free(ctx->zlib_buffer);
1370 }
1371
1372
1373 #define OFFS(_n) #_n, offsetof(GF_NHMLDmxCtx, _n)
1374 static const GF_FilterArgs GF_NHMLDmxArgs[] =
1375 {
1376 { OFFS(reframe), "force reparsing of referenced content", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
1377 { OFFS(index), "indexing window length", GF_PROP_DOUBLE, "1.0", NULL, 0},
1378 {0}
1379 };
1380
1381
1382 static const GF_FilterCapability NHMLDmxCaps[] =
1383 {
1384 CAP_UINT(GF_CAPS_INPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
1385 CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_FILE_EXT, "nhml|dims|dml"),
1386 CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_MIME, "application/x-nhml|application/dims"),
1387 CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
1388 CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
1389 CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_SCENE),
1390 };
1391
1392 GF_FilterRegister NHMLDmxRegister = {
1393 .name = "nhmlr",
1394 GF_FS_SET_DESCRIPTION("NHML parser")
1395 GF_FS_SET_HELP("This filter reads NHML files/data to produce a media PID and frames.\n"
1396 "NHML documentation is available at https://wiki.gpac.io/NHML-Format\n")
1397 .private_size = sizeof(GF_NHMLDmxCtx),
1398 .args = GF_NHMLDmxArgs,
1399 .initialize = nhmldmx_initialize,
1400 .finalize = nhmldmx_finalize,
1401 SETCAPS(NHMLDmxCaps),
1402 .configure_pid = nhmldmx_configure_pid,
1403 .process = nhmldmx_process,
1404 .process_event = nhmldmx_process_event
1405 };
1406
nhmldmx_register(GF_FilterSession * session)1407 const GF_FilterRegister *nhmldmx_register(GF_FilterSession *session)
1408 {
1409 return &NHMLDmxRegister;
1410 }
1411
1412