LCOV - code coverage report
Current view: top level - filters - dmx_nhml.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 597 755 79.1 %
Date: 2021-04-29 23:48:07 Functions: 13 13 100.0 %

          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             : 

Generated by: LCOV version 1.13