LCOV - code coverage report
Current view: top level - filters - in_file.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 205 290 70.7 %
Date: 2021-04-29 23:48:07 Functions: 7 7 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 / generic FILE input 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             : 
      27             : #include <gpac/filters.h>
      28             : #include <gpac/constants.h>
      29             : 
      30             : enum{
      31             :         FILE_RAND_NONE=0,
      32             :         FILE_RAND_ANY,
      33             :         FILE_RAND_SC_ANY,
      34             :         FILE_RAND_SC_AVC,
      35             :         FILE_RAND_SC_HEVC,
      36             :         FILE_RAND_SC_AV1
      37             : };
      38             : 
      39             : typedef struct
      40             : {
      41             :         //options
      42             :         char *src;
      43             :         char *ext, *mime;
      44             :         u32 block_size;
      45             :         GF_Fraction64 range;
      46             : 
      47             :         //only one output pid declared
      48             :         GF_FilterPid *pid;
      49             : 
      50             :         FILE *file;
      51             :         u64 file_size;
      52             :         u64 file_pos, end_pos;
      53             :         Bool is_end, pck_out;
      54             :         Bool is_null;
      55             :         Bool full_file_only;
      56             :         Bool do_reconfigure;
      57             :         char *block;
      58             :         u32 is_random;
      59             :         Bool cached_set;
      60             :         Bool no_failure;
      61             : } GF_FileInCtx;
      62             : 
      63             : 
      64        5353 : static GF_Err filein_initialize(GF_Filter *filter)
      65             : {
      66        5353 :         GF_FileInCtx *ctx = (GF_FileInCtx *) gf_filter_get_udta(filter);
      67             :         FILE *old_file = NULL;
      68             :         char *ext_start = NULL;
      69             :         char *frag_par = NULL;
      70             :         char *cgi_par = NULL;
      71             :         char *src, *path;
      72             :         const char *prev_url=NULL;
      73             : 
      74        5353 :         if (!ctx || !ctx->src) return GF_BAD_PARAM;
      75             : 
      76        5353 :         if (!strcmp(ctx->src, "null")) {
      77           1 :                 ctx->pid = gf_filter_pid_new(filter);
      78           1 :                 gf_filter_pid_set_property(ctx->pid, GF_PROP_PID_STREAM_TYPE, &PROP_UINT(GF_STREAM_FILE));
      79           1 :                 gf_filter_pid_set_eos(ctx->pid);
      80           1 :                 ctx->is_end = GF_TRUE;
      81           1 :                 return GF_OK;
      82             :         }
      83        5352 :         if (!strcmp(ctx->src, "rand") || !strcmp(ctx->src, "randsc")) {
      84           0 :                 gf_rand_init(GF_FALSE);
      85           0 :                 ctx->is_random = FILE_RAND_ANY;
      86           0 :                 if (!strcmp(ctx->src, "randsc")) {
      87           0 :                         ctx->is_random = FILE_RAND_SC_ANY;
      88           0 :                         if (ctx->mime) {
      89           0 :                                 if (!strcmp(ctx->mime, "video/avc")) ctx->is_random = FILE_RAND_SC_AVC;
      90           0 :                                 if (!strcmp(ctx->mime, "video/hevc")) ctx->is_random = FILE_RAND_SC_HEVC;
      91           0 :                                 if (!strcmp(ctx->mime, "video/av1")) ctx->is_random = FILE_RAND_SC_AV1;
      92             :                         }
      93             :                 }
      94             : 
      95           0 :                 if (!ctx->block_size) ctx->block_size = 5000;
      96           0 :                 while (ctx->block_size % 4) ctx->block_size++;
      97           0 :                 ctx->block = gf_malloc(ctx->block_size +1);
      98           0 :                 return GF_OK;
      99             :         }
     100             : 
     101             : 
     102             : 
     103        5352 :         if (strnicmp(ctx->src, "file:/", 6) && strnicmp(ctx->src, "gfio:/", 6) && strstr(ctx->src, "://"))  {
     104           0 :                 gf_filter_setup_failure(filter, GF_NOT_SUPPORTED);
     105           0 :                 return GF_NOT_SUPPORTED;
     106             :         }
     107        5352 :         path = strstr(ctx->src, "://");
     108        5352 :         if (path) path += 3;
     109        5352 :         if (path && strstr(path, "://")) {
     110           0 :                 ctx->is_end = GF_TRUE;
     111           0 :                 return gf_filter_pid_raw_new(filter, path, path, NULL, NULL, NULL, 0, GF_TRUE, &ctx->pid);
     112             :         }
     113             : 
     114             :         //local file
     115             : 
     116             :         //strip any fragment identifer
     117        5352 :         ext_start = gf_file_ext_start(ctx->src);
     118        5352 :         frag_par = strchr(ext_start ? ext_start : ctx->src, '#');
     119        5352 :         if (frag_par) frag_par[0] = 0;
     120        5352 :         cgi_par = strchr(ctx->src, '?');
     121        5352 :         if (cgi_par) cgi_par[0] = 0;
     122             : 
     123        5352 :         src = (char *) ctx->src;
     124        5352 :         if (!strnicmp(ctx->src, "file://", 7)) src += 7;
     125        5352 :         else if (!strnicmp(ctx->src, "file:", 5)) src += 5;
     126             : 
     127             :         //for gfio, do not close file until we open the new one
     128        5352 :         if (ctx->do_reconfigure) {
     129        2564 :                 old_file = ctx->file;
     130        2564 :                 ctx->file = NULL;
     131        2564 :                 if (gf_fileio_check(old_file))
     132           3 :                         prev_url = gf_fileio_url((GF_FileIO *)old_file);
     133             :         }
     134             : 
     135        5352 :         if (!ctx->file) {
     136        5352 :                 ctx->file = gf_fopen_ex(src, prev_url, "rb");
     137             :         }
     138             : 
     139        5352 :         if (old_file) {
     140        2558 :                 gf_fclose(old_file);
     141             :         }
     142             : 
     143        5352 :         if (!ctx->file) {
     144           8 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[FileIn] Failed to open %s\n", src));
     145             : 
     146           8 :                 if (frag_par) frag_par[0] = '#';
     147           8 :                 if (cgi_par) cgi_par[0] = '?';
     148             : 
     149           8 :                 if (ctx->no_failure) {
     150           7 :                         gf_filter_notification_failure(filter, GF_URL_ERROR, GF_FALSE);
     151           7 :                         ctx->is_end = GF_TRUE;
     152           7 :                         return GF_OK;
     153             :                 }
     154             : 
     155           1 :                 gf_filter_setup_failure(filter, GF_URL_ERROR);
     156             : #ifdef GPAC_ENABLE_COVERAGE
     157           1 :                 if (gf_sys_is_cov_mode() && !strcmp(src, "blob"))
     158             :                         return GF_OK;
     159             : #endif
     160           0 :                 return GF_URL_ERROR;
     161             :         }
     162        5344 :         GF_LOG(GF_LOG_INFO, GF_LOG_MMIO, ("[FileIn] opening %s\n", src));
     163        5344 :         ctx->file_size = gf_fsize(ctx->file);
     164             : 
     165        5344 :         ctx->cached_set = GF_FALSE;
     166        5344 :         ctx->full_file_only = GF_FALSE;
     167             : 
     168        5344 :         if (ctx->do_reconfigure && gf_fileio_check(ctx->file)) {
     169           2 :                 GF_FileIO *gfio = (GF_FileIO *)ctx->file;
     170           2 :                 gf_free(ctx->src);
     171           2 :                 ctx->src = gf_strdup(gf_fileio_url(gfio));
     172             :         }
     173             : 
     174             : 
     175        5344 :         ctx->file_pos = ctx->range.num;
     176        5344 :         if (ctx->range.den) {
     177         306 :                 ctx->end_pos = ctx->range.den;
     178         306 :                 if (ctx->end_pos>ctx->file_size) {
     179           0 :                         ctx->range.den = ctx->end_pos = ctx->file_size;
     180             :                 }
     181             :         }
     182        5344 :         gf_fseek(ctx->file, ctx->file_pos, SEEK_SET);
     183        5344 :         ctx->is_end = GF_FALSE;
     184             : 
     185        5344 :         if (frag_par) frag_par[0] = '#';
     186        5344 :         if (cgi_par) cgi_par[0] = '?';
     187             : 
     188        5344 :         if (!ctx->block) {
     189        2787 :                 if (!ctx->block_size) {
     190        2787 :                         if (ctx->file_size>500000000) ctx->block_size = 1000000;
     191        2787 :                         else ctx->block_size = 5000;
     192             :                 }
     193        2787 :                 ctx->block = gf_malloc(ctx->block_size +1);
     194             :         }
     195             :         return GF_OK;
     196             : }
     197             : 
     198        2784 : static void filein_finalize(GF_Filter *filter)
     199             : {
     200        2784 :         GF_FileInCtx *ctx = (GF_FileInCtx *) gf_filter_get_udta(filter);
     201             : 
     202        2784 :         if (ctx->file) gf_fclose(ctx->file);
     203        2784 :         if (ctx->block) gf_free(ctx->block);
     204        2784 : }
     205             : 
     206        2936 : static GF_FilterProbeScore filein_probe_url(const char *url, const char *mime_type)
     207             : {
     208             :         char *ext_start = NULL;
     209             :         char *frag_par = NULL;
     210             :         char *cgi_par = NULL;
     211             :         char *src = (char *) url;
     212             :         Bool res;
     213             : 
     214        2936 :         if (!strcmp(url, "-") || !strcmp(url, "stdin")) return GF_FPROBE_NOT_SUPPORTED;
     215             : 
     216        2934 :         if (!strnicmp(url, "file://", 7)) src += 7;
     217        2934 :         else if (!strnicmp(url, "file:", 5)) src += 5;
     218             : 
     219        2934 :         if (!strcmp(url, "null")) return GF_FPROBE_SUPPORTED;
     220        2933 :         if (!strcmp(url, "rand")) return GF_FPROBE_SUPPORTED;
     221        2933 :         if (!strcmp(url, "randsc")) return GF_FPROBE_SUPPORTED;
     222        2933 :         if (!strncmp(src, "isobmff://", 10)) return GF_FPROBE_SUPPORTED;
     223        2933 :         if (!strncmp(url, "gfio://", 7)) {
     224           4 :                 GF_FileIO *gfio = gf_fileio_from_url(url);
     225           4 :                 if (gfio && gf_fileio_read_mode(gfio))
     226             :                         return GF_FPROBE_SUPPORTED;
     227             :                 return GF_FPROBE_NOT_SUPPORTED;
     228             :         }
     229        2929 :         if (strstr(src, "://"))
     230             :                 return GF_FPROBE_NOT_SUPPORTED;
     231             : 
     232             : 
     233             :         //strip any fragment identifer
     234        2782 :         ext_start = gf_file_ext_start(url);
     235        2782 :         frag_par = strchr(ext_start ? ext_start : url, '#');
     236        2782 :         if (frag_par) frag_par[0] = 0;
     237        2782 :         cgi_par = strchr(url, '?');
     238        2782 :         if (cgi_par) cgi_par[0] = 0;
     239             : 
     240        2782 :         res = gf_file_exists(src);
     241             : 
     242        2782 :         if (frag_par) frag_par[0] = '#';
     243        2782 :         if (cgi_par) cgi_par[0] = '?';
     244             : 
     245        2782 :         return res ? GF_FPROBE_SUPPORTED : GF_FPROBE_NOT_SUPPORTED;
     246             : }
     247             : 
     248        5381 : static Bool filein_process_event(GF_Filter *filter, const GF_FilterEvent *evt)
     249             : {
     250        5381 :         GF_FileInCtx *ctx = (GF_FileInCtx *) gf_filter_get_udta(filter);
     251             : 
     252        5381 :         if (evt->base.on_pid && (evt->base.on_pid != ctx->pid))
     253             :                 return GF_FALSE;
     254             : 
     255        5381 :         switch (evt->base.type) {
     256         588 :         case GF_FEVT_PLAY:
     257             :         case GF_FEVT_PLAY_HINT:
     258         588 :                 ctx->full_file_only = evt->play.full_file_only;
     259         588 :                 return GF_TRUE;
     260         512 :         case GF_FEVT_STOP:
     261             :                 //stop sending data
     262         512 :                 ctx->is_end = GF_TRUE;
     263         512 :                 gf_filter_pid_set_eos(ctx->pid);
     264         512 :                 return GF_TRUE;
     265         448 :         case GF_FEVT_SOURCE_SEEK:
     266         448 :                 if (ctx->is_random)
     267             :                         return GF_TRUE;
     268         448 :                 if (ctx->file_size && (evt->seek.start_offset >= ctx->file_size)) {
     269           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[FileIn] Seek request outside of file %s range ("LLU" vs size "LLU")\n", ctx->src, evt->seek.start_offset, ctx->file_size));
     270             :                         return GF_TRUE;
     271             :                 }
     272             : 
     273         448 :                 GF_LOG(GF_LOG_INFO, GF_LOG_MMIO, ("[FileIn] Asked to seek source to range "LLU"-"LLU"\n", evt->seek.start_offset, evt->seek.end_offset));
     274         448 :                 ctx->is_end = GF_FALSE;
     275             : 
     276         448 :                 if (gf_fileio_check(ctx->file)) {
     277           0 :                         ctx->cached_set = GF_FALSE;
     278             :                 }
     279             : 
     280         448 :                 if (ctx->file) {
     281         448 :                         int res = gf_fseek(ctx->file, evt->seek.start_offset, SEEK_SET);
     282         448 :                         if (res) {
     283           0 :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[FileIn] Seek on file failed: %d\n", res));
     284             :                                 return GF_TRUE;
     285             :                         }
     286             :                 }
     287             : 
     288         448 :                 ctx->file_pos = evt->seek.start_offset;
     289         448 :                 ctx->end_pos = evt->seek.end_offset;
     290         448 :                 if (ctx->end_pos>ctx->file_size) ctx->end_pos = ctx->file_size;
     291         448 :                 ctx->range.num = evt->seek.start_offset;
     292         448 :                 ctx->range.den = ctx->end_pos;
     293         448 :                 if (evt->seek.hint_block_size > ctx->block_size) {
     294         280 :                         ctx->block_size = evt->seek.hint_block_size;
     295         280 :                         ctx->block = gf_realloc(ctx->block, ctx->block_size+1);
     296             :                 }
     297             :                 return GF_TRUE;
     298        2564 :         case GF_FEVT_SOURCE_SWITCH:
     299        2564 :                 if (ctx->is_random)
     300             :                         return GF_TRUE;
     301        2564 :                 GF_LOG(GF_LOG_INFO, GF_LOG_MMIO, ("[FileIn] Asked to switch source to %s (range "LLU"-"LLU")\n", evt->seek.source_switch ? evt->seek.source_switch : "self", evt->seek.start_offset, evt->seek.end_offset));
     302             :                 assert(ctx->is_end);
     303        2564 :                 ctx->range.num = evt->seek.start_offset;
     304        2564 :                 ctx->range.den = evt->seek.end_offset;
     305        2564 :                 if (evt->seek.source_switch) {
     306        2564 :                         if (strcmp(evt->seek.source_switch, ctx->src)) {
     307        2270 :                                 gf_free(ctx->src);
     308        2270 :                                 ctx->src = gf_strdup(evt->seek.source_switch);
     309             :                         }
     310        2564 :                         ctx->do_reconfigure = GF_TRUE;
     311             :                 }
     312             :                 //don't send a setup failure on source switch (this would destroy ourselves which we don't want in DASH)
     313        2564 :                 ctx->no_failure = GF_TRUE;
     314        2564 :                 filein_initialize(filter);
     315        2564 :                 gf_filter_post_process_task(filter);
     316        2564 :                 break;
     317           0 :         case GF_FEVT_FILE_DELETE:
     318           0 :                 if (ctx->is_end && !strcmp(evt->file_del.url, "__gpac_self__")) {
     319           0 :                         if (ctx->file) {
     320           0 :                                 gf_fclose(ctx->file);
     321           0 :                                 ctx->file = NULL;
     322             :                         }
     323           0 :                         gf_file_delete(ctx->src);
     324             :                 }
     325             :                 break;
     326             : 
     327             :         default:
     328             :                 break;
     329             :         }
     330             :         return GF_FALSE;
     331             : }
     332             : 
     333             : 
     334      230313 : static void filein_pck_destructor(GF_Filter *filter, GF_FilterPid *pid, GF_FilterPacket *pck)
     335             : {
     336      230313 :         GF_FileInCtx *ctx = (GF_FileInCtx *) gf_filter_get_udta(filter);
     337      230313 :         ctx->pck_out = GF_FALSE;
     338             :         //ready to process again
     339      230313 :         gf_filter_post_process_task(filter);
     340      230313 : }
     341             : 
     342      239149 : static GF_Err filein_process(GF_Filter *filter)
     343             : {
     344             :         GF_Err e;
     345             :         u32 nb_read, to_read;
     346             :         u64 lto_read;
     347             :         GF_FilterPacket *pck;
     348      239149 :         GF_FileInCtx *ctx = (GF_FileInCtx *) gf_filter_get_udta(filter);
     349             : 
     350      239149 :         if (ctx->is_end)
     351             :                 return GF_EOS;
     352             : 
     353             :         //until packet is released we return EOS (no processing), and ask for processing again upon release
     354      234622 :         if (ctx->pck_out)
     355             :                 return GF_EOS;
     356      230317 :         if (ctx->pid && gf_filter_pid_would_block(ctx->pid)) {
     357             :                 return GF_OK;
     358             :         }
     359             : 
     360      230317 :         if (ctx->full_file_only && ctx->pid && !ctx->do_reconfigure && ctx->cached_set) {
     361         419 :                 pck = gf_filter_pck_new_shared(ctx->pid, ctx->block, 0, filein_pck_destructor);
     362         419 :                 if (!pck) return GF_OUT_OF_MEM;
     363             : 
     364         419 :                 ctx->is_end = GF_TRUE;
     365         419 :                 gf_filter_pck_set_framing(pck, ctx->file_pos ? GF_FALSE : GF_TRUE, ctx->is_end);
     366         419 :                 gf_filter_pck_set_sap(pck, GF_FILTER_SAP_1);
     367         419 :                 ctx->pck_out = GF_TRUE;
     368         419 :                 gf_filter_pck_send(pck);
     369         419 :                 gf_filter_pid_set_eos(ctx->pid);
     370             : 
     371         419 :                 if (ctx->file_size && gf_filter_reporting_enabled(filter)) {
     372             :                         char szStatus[1024], *szSrc;
     373           0 :                         szSrc = gf_file_basename(ctx->src);
     374             : 
     375           0 :                         sprintf(szStatus, "%s: EOS (dispatch canceled after "LLD" b, file size "LLD" b)", szSrc, (s64) ctx->file_pos, (s64) ctx->file_size);
     376           0 :                         gf_filter_update_status(filter, 10000, szStatus);
     377             :                 }
     378             :                 return GF_OK;
     379             :         }
     380      229898 :         if (ctx->is_random) {
     381             :                 u32 i;
     382           0 :                 if (ctx->is_random>=FILE_RAND_SC_ANY) {
     383           0 :                         for (i=0; i<ctx->block_size; i+= 4) {
     384           0 :                                 u32 val = gf_rand();
     385             : 
     386           0 :                                 if (i+4>=ctx->block_size) {
     387           0 :                                         * ((u32 *) (ctx->block + i)) = val;
     388           0 :                                         continue;
     389             :                                 }
     390           0 :                                 if (val % 100) {
     391           0 :                                         * ((u32 *) (ctx->block + i)) = val;
     392           0 :                                         continue;
     393             :                                 }
     394           0 :                                 if (ctx->is_random==FILE_RAND_SC_AVC) {
     395           0 :                                         u32 rand_high = val>>24;
     396           0 :                                         * ((u32 *) (ctx->block + i)) = 0x00000001;
     397             :                                         i += 4;
     398           0 :                                         val &= 0x00FFFFFF;
     399           0 :                                         rand_high = rand_high%31;
     400           0 :                                         rand_high <<= 24;
     401           0 :                                         val |= rand_high;
     402           0 :                                         * ((u32 *) (ctx->block + i)) = val;
     403           0 :                                 } else if (ctx->is_random==FILE_RAND_SC_HEVC) {
     404           0 :                                         u32 rand_high = val>>16;
     405           0 :                                         * ((u32 *) (ctx->block + i)) = 0x00000001;
     406             :                                         i += 4;
     407           0 :                                         val &= 0x0000FFFF;
     408           0 :                                         rand_high = rand_high % 63;
     409             :                                         rand_high <<= 8;
     410             :                                         rand_high |= 1; //end of layerid (=0) and temporal sublayer (=1)
     411           0 :                                         rand_high <<= 16;
     412           0 :                                         val |= rand_high;
     413           0 :                                         * ((u32 *) (ctx->block + i)) = val;
     414             :                                 }
     415             :                                 else {
     416           0 :                                         val &= 0x000001FF;
     417           0 :                                         * ((u32 *) (ctx->block + i)) = val;
     418             :                                 }
     419             :                         }
     420             :                 } else {
     421           0 :                         for (i=0; i<ctx->block_size; i+= 4) {
     422           0 :                                 * ((u32 *) (ctx->block + i)) = gf_rand();
     423             :                         }
     424             :                 }
     425           0 :                 ctx->block[ctx->block_size]=0;
     426             : 
     427           0 :                 if (!ctx->pid) {
     428           0 :                         e = gf_filter_pid_raw_new(filter, ctx->src, ctx->src, ctx->mime, ctx->ext, ctx->block, ctx->block_size, GF_TRUE,  &ctx->pid);
     429           0 :                         if (e) return e;
     430             :                 }
     431           0 :                 pck = gf_filter_pck_new_shared(ctx->pid, ctx->block, ctx->block_size, filein_pck_destructor);
     432           0 :                 if (!pck) return GF_OUT_OF_MEM;
     433             : 
     434           0 :                 gf_filter_pck_set_framing(pck, ctx->file_pos ? GF_FALSE : GF_TRUE, GF_FALSE);
     435           0 :                 gf_filter_pck_set_sap(pck, GF_FILTER_SAP_1);
     436           0 :                 ctx->file_pos += ctx->block_size;
     437             : 
     438           0 :                 ctx->pck_out = GF_TRUE;
     439           0 :                 gf_filter_pck_send(pck);
     440           0 :                 return GF_OK;
     441             :         }
     442             : 
     443             :         //compute size to read as u64 (large file)
     444      229898 :         if (ctx->end_pos > ctx->file_pos)
     445        4379 :                 lto_read = ctx->end_pos - ctx->file_pos;
     446      225519 :         else if (ctx->file_size)
     447      225519 :                 lto_read = ctx->file_size - ctx->file_pos;
     448             :         else
     449           0 :                 lto_read = ctx->block_size;
     450             : 
     451             :         //and clamp based on blocksize as u32
     452      229898 :         if (lto_read > (u64) ctx->block_size)
     453             :                 to_read = (u64) ctx->block_size;
     454             :         else
     455        5050 :                 to_read = (u32) lto_read;
     456             : 
     457      229898 :         nb_read = (u32) gf_fread(ctx->block, to_read, ctx->file);
     458      229898 :         if (!nb_read)
     459           0 :                 ctx->file_size = ctx->file_pos;
     460             : 
     461      229898 :         ctx->block[nb_read] = 0;
     462      229898 :         if (!ctx->pid || ctx->do_reconfigure) {
     463             :                 //quick hack for ID3v2: if detected, increase block size to have the full id3v2 + some frames in the initial block
     464             :                 //to avoid relying on file extension for demux
     465        5340 :                 if (!ctx->pid && (nb_read>10)
     466        2783 :                         && (ctx->block[0] == 'I' && ctx->block[1] == 'D' && ctx->block[2] == '3')
     467             :                 ) {
     468           1 :                         u32 tag_size = ((ctx->block[9] & 0x7f) + ((ctx->block[8] & 0x7f) << 7) + ((ctx->block[7] & 0x7f) << 14) + ((ctx->block[6] & 0x7f) << 21));
     469           1 :                         if (tag_size > nb_read) {
     470           0 :                                 u32 probe_size = tag_size + ctx->block_size;
     471           0 :                                 if (probe_size>ctx->file_size)
     472           0 :                                         probe_size = (u32) ctx->file_size;
     473             : 
     474           0 :                                 ctx->block_size = probe_size;
     475           0 :                                 ctx->block = gf_realloc(ctx->block, ctx->block_size+1);
     476           0 :                                 nb_read += (u32) gf_fread(ctx->block + nb_read, probe_size-nb_read, ctx->file);
     477             :                         }
     478             :                 }
     479             : 
     480        5340 :                 ctx->do_reconfigure = GF_FALSE;
     481        5340 :                 e = gf_filter_pid_raw_new(filter, ctx->src, ctx->src, ctx->mime, ctx->ext, ctx->block, nb_read, GF_TRUE, &ctx->pid);
     482        5340 :                 if (e) return e;
     483             : 
     484        5340 :                 if (!gf_fileio_check(ctx->file)) {
     485        5334 :                         gf_filter_pid_set_property(ctx->pid, GF_PROP_PID_FILE_CACHED, &PROP_BOOL(GF_TRUE) );
     486             : 
     487        5334 :                         gf_filter_pid_set_property(ctx->pid, GF_PROP_PID_DOWN_SIZE, ctx->file_size ? &PROP_LONGUINT(ctx->file_size) : NULL);
     488             : 
     489        5334 :                         ctx->cached_set = GF_TRUE;
     490             :                 }
     491             : 
     492        5340 :                 if (ctx->range.num || ctx->range.den)
     493         306 :                         gf_filter_pid_set_property(ctx->pid, GF_PROP_PID_FILE_RANGE, &PROP_FRAC64(ctx->range) );
     494             :         }
     495             : 
     496             :         //GFIO wrapper, gets stats and update
     497      229898 :         if (!ctx->cached_set) {
     498             :                 u64 bdone, btotal;
     499             :                 Bool fcached;
     500             :                 u32 bytes_per_sec;
     501           6 :                 if (gf_fileio_get_stats((GF_FileIO *)ctx->file, &bdone, &btotal, &fcached, &bytes_per_sec)) {
     502           6 :                         if (fcached) {
     503           6 :                                 gf_filter_pid_set_property(ctx->pid, GF_PROP_PID_FILE_CACHED, &PROP_BOOL(fcached) );
     504           6 :                                 ctx->cached_set = GF_TRUE;
     505             :                         }
     506             : 
     507           6 :                         gf_filter_pid_set_info(ctx->pid, GF_PROP_PID_DOWN_SIZE, &PROP_LONGUINT(btotal) );
     508           6 :                         gf_filter_pid_set_info(ctx->pid, GF_PROP_PID_DOWN_BYTES, &PROP_LONGUINT(bdone) );
     509           6 :                         gf_filter_pid_set_info(ctx->pid, GF_PROP_PID_DOWN_RATE, &PROP_UINT(bytes_per_sec*8) );
     510             :                 }
     511             :         }
     512             : 
     513      229898 :         pck = gf_filter_pck_new_shared(ctx->pid, ctx->block, nb_read, filein_pck_destructor);
     514      229898 :         if (!pck) return GF_OUT_OF_MEM;
     515             : 
     516      229898 :         gf_filter_pck_set_byte_offset(pck, ctx->file_pos);
     517             : 
     518      229898 :         if (ctx->file_size && (ctx->file_pos + nb_read == ctx->file_size)) {
     519        4744 :                 ctx->is_end = GF_TRUE;
     520        4744 :                 gf_filter_pid_set_info(ctx->pid, GF_PROP_PID_DOWN_BYTES, &PROP_LONGUINT(ctx->file_size) );
     521             :         } else {
     522      225154 :                 if (nb_read < to_read) {
     523             :                         Bool is_eof;
     524           0 :                         GF_LOG(GF_LOG_WARNING, GF_LOG_MMIO, ("[FileIn] Asked to read %d but got only %d\n", to_read, nb_read));
     525             : 
     526           0 :                         is_eof = gf_feof(ctx->file);
     527             : 
     528           0 :                         if (is_eof) {
     529           0 :                                 gf_filter_pid_set_info(ctx->pid, GF_PROP_PID_DOWN_BYTES, &PROP_LONGUINT(ctx->file_size) );
     530           0 :                                 ctx->is_end = GF_TRUE;
     531           0 :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[FileIn] IO error EOF found after reading %d bytes but file %s size is %d\n", ctx->file_pos+nb_read, ctx->src, ctx->file_size));
     532             :                         }
     533             :                 } else {
     534      225154 :                         gf_filter_pid_set_info(ctx->pid, GF_PROP_PID_DOWN_BYTES, &PROP_LONGUINT(ctx->file_pos) );
     535             :                 }
     536             :         }
     537      229898 :         gf_filter_pck_set_framing(pck, ctx->file_pos ? GF_FALSE : GF_TRUE, ctx->is_end);
     538      229898 :         gf_filter_pck_set_sap(pck, GF_FILTER_SAP_1);
     539      229898 :         ctx->file_pos += nb_read;
     540             : 
     541      229898 :         ctx->pck_out = GF_TRUE;
     542      229898 :         gf_filter_pck_send(pck);
     543             : 
     544      229898 :         if (ctx->file_size && gf_filter_reporting_enabled(filter)) {
     545             :                 char szStatus[1024], *szSrc;
     546          35 :                 szSrc = gf_file_basename(ctx->src);
     547             : 
     548          35 :                 sprintf(szStatus, "%s: % 16"LLD_SUF" /% 16"LLD_SUF" (%02.02f)", szSrc, (s64) ctx->file_pos, (s64) ctx->file_size, ((Double)ctx->file_pos*100.0)/ctx->file_size);
     549          35 :                 gf_filter_update_status(filter, (u32) (ctx->file_pos*10000/ctx->file_size), szStatus);
     550             :         }
     551             : 
     552      229898 :         if (ctx->is_end) {
     553        4744 :                 gf_filter_pid_set_eos(ctx->pid);
     554        4744 :                 return GF_EOS;
     555             :         }
     556      225154 :         return ctx->pck_out ? GF_EOS : GF_OK;
     557             : }
     558             : 
     559             : 
     560             : 
     561             : #define OFFS(_n)        #_n, offsetof(GF_FileInCtx, _n)
     562             : 
     563             : static const GF_FilterArgs FileInArgs[] =
     564             : {
     565             :         { OFFS(src), "location of source file", GF_PROP_NAME, NULL, NULL, 0},
     566             :         { OFFS(block_size), "block size used to read file. 0 means 5000 if file less than 500m, 1M otherwise", GF_PROP_UINT, "0", NULL, GF_FS_ARG_HINT_ADVANCED},
     567             :         { OFFS(range), "byte range", GF_PROP_FRACTION64, "0-0", NULL, 0},
     568             :         { OFFS(ext), "override file extension", GF_PROP_NAME, NULL, NULL, 0},
     569             :         { OFFS(mime), "set file mime type", GF_PROP_NAME, NULL, NULL, 0},
     570             :         {0}
     571             : };
     572             : 
     573             : static const GF_FilterCapability FileInCaps[] =
     574             : {
     575             :         CAP_UINT(GF_CAPS_OUTPUT,  GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
     576             : };
     577             : 
     578             : GF_FilterRegister FileInRegister = {
     579             :         .name = "fin",
     580             :         GF_FS_SET_DESCRIPTION("File input")
     581             :         GF_FS_SET_HELP("This filter dispatch raw blocks from input file into a filter chain.\n"
     582             :         "Block size can be adjusted using [-block_size]().\n"
     583             :         "Content format can be forced through [-mime]() and file extension can be changed through [-ext]().\n"
     584             :         "Note: Unless disabled at session level (see [-no-probe](CORE) ), file extensions are usually ignored and format probing is done on the first data block.\n"
     585             :         "The special file name `null` is used for creating a file with no data, needed by some filters such as [dasher](dasher).\n"
     586             :         "The special file name `rand` is used to generate random data.\n"
     587             :         "The special file name `randsc` is used to generate random data with fake start-codes (0x000001).\n"
     588             :         "\n"
     589             :         "The filter handles both files and GF_FileIO objects as input URL.\n"
     590             :         )
     591             :         .private_size = sizeof(GF_FileInCtx),
     592             :         .args = FileInArgs,
     593             :         .initialize = filein_initialize,
     594             :         SETCAPS(FileInCaps),
     595             :         .finalize = filein_finalize,
     596             :         .process = filein_process,
     597             :         .process_event = filein_process_event,
     598             :         .probe_url = filein_probe_url
     599             : };
     600             : 
     601             : 
     602        2877 : const GF_FilterRegister *filein_register(GF_FilterSession *session)
     603             : {
     604        2877 :         return &FileInRegister;
     605             : }
     606             : 

Generated by: LCOV version 1.13