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