LCOV - code coverage report
Current view: top level - filters - write_nhml.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 333 456 73.0 %
Date: 2021-04-29 23:48:07 Functions: 10 10 100.0 %

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

Generated by: LCOV version 1.13