LCOV - code coverage report
Current view: top level - filters - reframe_amr.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 223 289 77.2 %
Date: 2021-04-29 23:48:07 Functions: 9 9 100.0 %

          Line data    Source code
       1             : /*
       2             :  *                      GPAC - Multimedia Framework C SDK
       3             :  *
       4             :  *                      Authors: Jean Le Feuvre
       5             :  *                      Copyright (c) Telecom ParisTech 2000-2021
       6             :  *                                      All rights reserved
       7             :  *
       8             :  *  This file is part of GPAC / AMR&EVRC&SMV reframer 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             : 
      29             : typedef struct
      30             : {
      31             :         u64 pos;
      32             :         Double duration;
      33             : } AMRIdx;
      34             : 
      35             : typedef struct
      36             : {
      37             :         //filter args
      38             :         Double index;
      39             : 
      40             :         //only one input pid declared
      41             :         GF_FilterPid *ipid;
      42             :         //only one output pid declared
      43             :         GF_FilterPid *opid;
      44             : 
      45             :         u32 start_offset;
      46             :         u32 codecid, sample_rate, block_size;
      47             : 
      48             :         u32 bitrate;
      49             :         u64 file_pos, cts;
      50             : 
      51             :         u16 amr_mode_set;
      52             : 
      53             :         GF_Fraction64 duration;
      54             :         Double start_range;
      55             :         Bool in_seek;
      56             :         u32 timescale;
      57             :         Bool is_playing;
      58             :         Bool is_file;
      59             :         Bool initial_play_done, file_loaded;
      60             :         Bool skip_magic;
      61             : 
      62             :         u32 hdr;
      63             :         u32 resume_from;
      64             :         u32 remaining;
      65             : 
      66             :         AMRIdx *indexes;
      67             :         u32 index_alloc_size, index_size;
      68             : } GF_AMRDmxCtx;
      69             : 
      70             : 
      71             : 
      72             : 
      73           9 : GF_Err amrdmx_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
      74             : {
      75             :         const GF_PropertyValue *p;
      76           9 :         GF_AMRDmxCtx *ctx = gf_filter_get_udta(filter);
      77             : 
      78           9 :         if (is_remove) {
      79           0 :                 ctx->ipid = NULL;
      80           0 :                 if (ctx->opid) {
      81           0 :                         gf_filter_pid_remove(ctx->opid);
      82           0 :                         ctx->opid = NULL;
      83             :                 }
      84             :                 return GF_OK;
      85             :         }
      86           9 :         if (! gf_filter_pid_check_caps(pid))
      87             :                 return GF_NOT_SUPPORTED;
      88             : 
      89           9 :         ctx->ipid = pid;
      90           9 :         p = gf_filter_pid_get_property(pid, GF_PROP_PID_TIMESCALE);
      91           9 :         if (p) ctx->timescale = p->value.uint;
      92             : 
      93           9 :         ctx->start_offset = 6;
      94           9 :         ctx->sample_rate = 8000;
      95           9 :         ctx->block_size = 160;
      96             : 
      97           9 :         p = gf_filter_pid_get_property(pid, GF_PROP_PID_CODECID);
      98           9 :         if (p) {
      99           0 :                 if (ctx->codecid && (ctx->codecid != p->value.uint)) {
     100             :                         return GF_NOT_SUPPORTED;
     101             :                 }
     102           0 :                 ctx->codecid = p->value.uint;
     103           0 :                 if (ctx->codecid == GF_CODECID_AMR_WB) {
     104           0 :                         ctx->sample_rate = 16000;
     105           0 :                         ctx->block_size = 320;
     106             :                 }
     107           0 :                 ctx->skip_magic = GF_FALSE;
     108           0 :                 if (!ctx->opid) {
     109           0 :                         ctx->opid = gf_filter_pid_new(filter);
     110           0 :                         gf_filter_pid_copy_properties(ctx->opid, ctx->ipid);
     111           0 :                         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_UNFRAMED, NULL);
     112             :                 }
     113             :         }
     114             :         return GF_OK;
     115             : }
     116             : 
     117       42890 : static void amrdmx_check_dur(GF_Filter *filter, GF_AMRDmxCtx *ctx)
     118             : {
     119             :         FILE *stream;
     120             :         u32 i;
     121             :         u64 duration, cur_dur, rate;
     122             :         char magic[20];
     123             :         const GF_PropertyValue *p;
     124       85778 :         if (!ctx->opid || ctx->timescale || ctx->file_loaded) return;
     125             : 
     126           9 :         if (ctx->index<=0) {
     127           7 :                 ctx->file_loaded = GF_TRUE;
     128             :                 return;
     129             :         }
     130             :         
     131           2 :         p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_FILEPATH);
     132           2 :         if (!p || !p->value.string || !strncmp(p->value.string, "gmem://", 7)) {
     133           0 :                 ctx->is_file = GF_FALSE;
     134           0 :                 ctx->file_loaded = GF_TRUE;
     135             :                 return;
     136             :         }
     137           2 :         ctx->is_file = GF_TRUE;
     138             : 
     139           2 :         stream = gf_fopen(p->value.string, "rb");
     140           2 :         if (!stream) return;
     141             : 
     142           2 :         ctx->codecid = GF_CODECID_NONE;
     143           2 :         ctx->start_offset = 6;
     144           2 :         ctx->sample_rate = 8000;
     145           2 :         ctx->block_size = 160;
     146           2 :         i = (u32) gf_fread(magic, 20, stream);
     147           2 :         if (i != 20) return;
     148             : 
     149           2 :         if (!strnicmp(magic, "#!AMR\n", 6)) {
     150           1 :                 gf_fseek(stream, 6, SEEK_SET);
     151           1 :                 ctx->codecid = GF_CODECID_AMR;
     152             :         }
     153           1 :         else if (!strnicmp(magic, "#!EVRC\n", 7)) {
     154           0 :                 gf_fseek(stream, 7, SEEK_SET);
     155           0 :                 ctx->start_offset = 7;
     156           0 :                 ctx->codecid = GF_CODECID_EVRC;
     157             :         }
     158           1 :         else if (!strnicmp(magic, "#!SMV\n", 6)) {
     159           0 :                 gf_fseek(stream, 6, SEEK_SET);
     160           0 :                 ctx->codecid = GF_CODECID_SMV;
     161             :         }
     162           1 :         else if (!strnicmp(magic, "#!AMR-WB\n", 9)) {
     163           1 :                 ctx->codecid = GF_CODECID_AMR_WB;
     164           1 :                 ctx->start_offset = 9;
     165           1 :                 ctx->sample_rate = 16000;
     166           1 :                 ctx->block_size = 320;
     167           1 :                 gf_fseek(stream, 9, SEEK_SET);
     168             :         }
     169             :         else if (!strnicmp(magic, "#!AMR_MC1.0\n", 12)) return;
     170             :         else if (!strnicmp(magic, "#!AMR-WB_MC1.0\n", 15)) return;
     171             :         else return;
     172             : 
     173           2 :         ctx->index_size = 0;
     174             : 
     175             :         cur_dur = 0;
     176             :         duration = 0;
     177       21370 :         while (!gf_feof(stream)) {
     178             :                 u32 size=0;
     179             :                 u64 pos;
     180             :                 u8 toc, ft;
     181       21368 :                 toc = gf_fgetc(stream);
     182             : 
     183       21368 :                 switch (ctx->codecid) {
     184        1498 :                 case GF_CODECID_AMR:
     185        1498 :                         ft = (toc >> 3) & 0x0F;
     186        1498 :                         size = (u32)GF_AMR_FRAME_SIZE[ft];
     187             :                         break;
     188       19870 :                 case GF_CODECID_AMR_WB:
     189       19870 :                         ft = (toc >> 3) & 0x0F;
     190       19870 :                         size = (u32)GF_AMR_WB_FRAME_SIZE[ft];
     191             :                         break;
     192             :                 default:
     193           0 :                         for (i=0; i<GF_SMV_EVRC_RATE_TO_SIZE_NB; i++) {
     194           0 :                                 if (GF_SMV_EVRC_RATE_TO_SIZE[2*i]==toc) {
     195             :                                         /*remove rate_type byte*/
     196           0 :                                         size = (u32)GF_SMV_EVRC_RATE_TO_SIZE[2*i+1] - 1;
     197             :                                         break;
     198             :                                 }
     199             :                         }
     200             :                         break;
     201             :                 }
     202       21368 :                 duration += ctx->block_size;
     203       21368 :                 cur_dur += ctx->block_size;
     204       21368 :                 pos = gf_ftell(stream);
     205       21368 :                 if (cur_dur > ctx->index * ctx->sample_rate) {
     206         418 :                         if (!ctx->index_alloc_size) ctx->index_alloc_size = 10;
     207         416 :                         else if (ctx->index_alloc_size == ctx->index_size) ctx->index_alloc_size *= 2;
     208         418 :                         ctx->indexes = gf_realloc(ctx->indexes, sizeof(AMRIdx)*ctx->index_alloc_size);
     209         418 :                         ctx->indexes[ctx->index_size].pos = pos - 1;
     210         418 :                         ctx->indexes[ctx->index_size].duration = (Double) duration;
     211         418 :                         ctx->indexes[ctx->index_size].duration /= ctx->sample_rate;
     212         418 :                         ctx->index_size ++;
     213             :                         cur_dur = 0;
     214             :                 }
     215       21368 :                 if (size) gf_fseek(stream, size, SEEK_CUR);
     216             :         }
     217           2 :         rate = gf_ftell(stream);
     218           2 :         gf_fclose(stream);
     219             : 
     220           2 :         if (!ctx->duration.num || (ctx->duration.num  * ctx->sample_rate != duration * ctx->duration.den)) {
     221           2 :                 ctx->duration.num = (u32) duration;
     222           2 :                 ctx->duration.den = ctx->sample_rate;
     223             : 
     224           2 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DURATION, & PROP_FRAC64(ctx->duration));
     225             : 
     226           2 :                 if (duration && !gf_sys_is_test_mode() ) {
     227           0 :                         rate *= 8 * ctx->duration.den;
     228           0 :                         rate /= ctx->duration.num;
     229           0 :                         ctx->bitrate = (u32) rate;
     230             :                 }
     231             :         }
     232             : 
     233           2 :         p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_FILE_CACHED);
     234           2 :         if (p && p->value.boolean) ctx->file_loaded = GF_TRUE;
     235           2 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CAN_DATAREF, & PROP_BOOL(GF_TRUE ) );
     236             : }
     237             : 
     238       43376 : static void amrdmx_check_pid(GF_Filter *filter, GF_AMRDmxCtx *ctx, u16 amr_mode_set)
     239             : {
     240       43376 :         if (ctx->opid) {
     241       43367 :                 if (ctx->amr_mode_set != amr_mode_set) {
     242           9 :                         ctx->amr_mode_set = amr_mode_set;
     243           9 :                         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_AMR_MODE_SET, & PROP_UINT( amr_mode_set));
     244             :                 }
     245             :                 return;
     246             :         }
     247             : 
     248           9 :         ctx->opid = gf_filter_pid_new(filter);
     249           9 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_STREAM_TYPE, & PROP_UINT( GF_STREAM_AUDIO));
     250             : 
     251           9 :         amrdmx_check_dur(filter, ctx);
     252             : 
     253           9 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_TIMESCALE, & PROP_UINT(ctx->sample_rate));
     254           9 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_SAMPLE_RATE, & PROP_UINT(ctx->sample_rate));
     255           9 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_NUM_CHANNELS, & PROP_UINT(1) );
     256           9 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CODECID, & PROP_UINT(ctx->codecid ) );
     257           9 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_SAMPLES_PER_FRAME, & PROP_UINT(ctx->block_size ) );
     258           9 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_AMR_MODE_SET, & PROP_UINT(ctx->amr_mode_set));
     259             : 
     260           9 :         if (ctx->bitrate) {
     261           0 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_BITRATE, & PROP_UINT(ctx->bitrate));
     262             :         }
     263             : 
     264           9 :         if (ctx->is_file && ctx->index) {
     265           2 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_PLAYBACK_MODE, & PROP_UINT(GF_PLAYBACK_MODE_FASTFORWARD) );
     266             :         }
     267             : }
     268             : 
     269       42867 : static Bool amrdmx_process_event(GF_Filter *filter, const GF_FilterEvent *evt)
     270             : {
     271             :         u32 i;
     272             :         GF_FilterEvent fevt;
     273       42867 :         GF_AMRDmxCtx *ctx = gf_filter_get_udta(filter);
     274             : 
     275       42867 :         switch (evt->base.type) {
     276           9 :         case GF_FEVT_PLAY:
     277           9 :                 if (!ctx->is_playing) {
     278           9 :                         ctx->is_playing = GF_TRUE;
     279           9 :                         ctx->cts = 0;
     280           9 :                         ctx->remaining = 0;
     281             :                 }
     282           9 :                 if (! ctx->is_file) {
     283             :                         return GF_FALSE;
     284             :                 }
     285           2 :                 amrdmx_check_dur(filter, ctx);
     286             : 
     287           2 :                 ctx->start_range = evt->play.start_range;
     288           2 :                 ctx->in_seek = GF_TRUE;
     289           2 :                 ctx->file_pos = 0;
     290           2 :                 if (ctx->start_range) {
     291           0 :                         for (i=1; i<ctx->index_size; i++) {
     292           0 :                                 if (ctx->indexes[i].duration>ctx->start_range) {
     293           0 :                                         ctx->cts = (u64) (ctx->indexes[i-1].duration * ctx->sample_rate);
     294           0 :                                         ctx->file_pos = ctx->indexes[i-1].pos;
     295           0 :                                         break;
     296             :                                 }
     297             :                         }
     298             :                 }
     299           2 :                 if (!ctx->initial_play_done) {
     300           2 :                         ctx->initial_play_done = GF_TRUE;
     301             :                         //seek will not change the current source state, don't send a seek
     302           2 :                         if (!ctx->file_pos) {
     303           2 :                                 ctx->skip_magic = GF_TRUE;
     304           2 :                                 return GF_TRUE;
     305             :                         }
     306             :                 }
     307             :                 //post a seek
     308           0 :                 GF_FEVT_INIT(fevt, GF_FEVT_SOURCE_SEEK, ctx->ipid);
     309           0 :                 if (!ctx->file_pos)
     310           0 :                         ctx->skip_magic = GF_TRUE;
     311           0 :                 fevt.seek.start_offset = ctx->file_pos;
     312           0 :                 gf_filter_pid_send_event(ctx->ipid, &fevt);
     313             : 
     314             :                 //cancel event
     315           0 :                 return GF_TRUE;
     316             : 
     317           5 :         case GF_FEVT_STOP:
     318           5 :                 ctx->is_playing = GF_FALSE;
     319             :                 //don't cancel event
     320           5 :                 return GF_FALSE;
     321             : 
     322             :         case GF_FEVT_SET_SPEED:
     323             :                 //cancel event
     324             :                 return GF_TRUE;
     325             :         default:
     326             :                 break;
     327             :         }
     328             :         //by default don't cancel event - to rework once we have downloading in place
     329       42853 :         return GF_FALSE;
     330             : }
     331             : 
     332             : static GFINLINE void amrdmx_update_cts(GF_AMRDmxCtx *ctx)
     333             : {
     334       43362 :         if (ctx->timescale) {
     335           0 :                 u64 inc = ctx->block_size;
     336           0 :                 inc *= ctx->timescale;
     337           0 :                 inc /= ctx->sample_rate;
     338           0 :                 ctx->cts += inc;
     339             :         } else {
     340       43362 :                 ctx->cts += ctx->block_size;
     341             :         }
     342             : }
     343             : 
     344       42879 : GF_Err amrdmx_process(GF_Filter *filter)
     345             : {
     346       42879 :         GF_AMRDmxCtx *ctx = gf_filter_get_udta(filter);
     347             :         GF_FilterPacket *pck, *dst_pck;
     348             :         u64 byte_offset;
     349             :         u8 *data, *output;
     350             :         u8 *start;
     351             :         u32 pck_size, remain;
     352             : 
     353             :         //update duration
     354       42879 :         amrdmx_check_dur(filter, ctx);
     355             : 
     356       42879 :         if (ctx->opid && !ctx->is_playing)
     357             :                 return GF_OK;
     358             : 
     359       42857 :         pck = gf_filter_pid_get_packet(ctx->ipid);
     360       42857 :         if (!pck) {
     361           4 :                 if (gf_filter_pid_is_eos(ctx->ipid)) {
     362           4 :                         if (ctx->opid)
     363           4 :                                 gf_filter_pid_set_eos(ctx->opid);
     364             :                         assert(ctx->remaining == 0);
     365             :                         return GF_EOS;
     366             :                 }
     367             :                 return GF_OK;
     368             :         }
     369             : 
     370       42853 :         data = (char *) gf_filter_pck_get_data(pck, &pck_size);
     371       42853 :         byte_offset = gf_filter_pck_get_byte_offset(pck);
     372             : 
     373             :         start = data;
     374       42853 :         remain = pck_size;
     375             : 
     376             :         //flush not previously dispatched data
     377       42853 :         if (ctx->remaining) {
     378             :                 u32 to_send = ctx->remaining;
     379         494 :                 if (ctx->remaining > pck_size) {
     380             :                         to_send = pck_size;
     381           0 :                         ctx->remaining -= pck_size;
     382             :                 } else {
     383         494 :                         ctx->remaining = 0;
     384             :                 }
     385         494 :                 if (! ctx->in_seek) {
     386         494 :                         dst_pck = gf_filter_pck_new_alloc(ctx->opid, to_send, &output);
     387         494 :                         if (!dst_pck) return GF_OUT_OF_MEM;
     388         494 :                         memcpy(output, data, to_send);
     389             : 
     390         494 :                         gf_filter_pck_set_cts(dst_pck, ctx->cts);
     391         494 :                         gf_filter_pck_set_sap(dst_pck, GF_FILTER_SAP_1);
     392         494 :                         gf_filter_pck_set_framing(dst_pck, GF_FALSE, ctx->remaining ? GF_FALSE : GF_TRUE);
     393         494 :                         if (byte_offset != GF_FILTER_NO_BO) {
     394         494 :                                 gf_filter_pck_set_byte_offset(dst_pck, byte_offset);
     395             :                         }
     396         494 :                         gf_filter_pck_send(dst_pck);
     397             :                 }
     398             : 
     399         494 :                 if (ctx->remaining) {
     400           0 :                         gf_filter_pid_drop_packet(ctx->ipid);
     401           0 :                         return GF_OK;
     402             :                 }
     403             :                 amrdmx_update_cts(ctx);
     404         494 :                 start += to_send;
     405         494 :                 remain -= to_send;
     406             :         }
     407             : 
     408             :         //input pid sets some timescale - we flushed pending data , update cts
     409       42853 :         if (ctx->timescale) {
     410           0 :                 u64 cts = gf_filter_pck_get_cts(pck);
     411           0 :                 if (cts != GF_FILTER_NO_TS)
     412           0 :                         ctx->cts = cts;
     413             :         }
     414       42853 :         if (ctx->skip_magic) {
     415             : 
     416          18 :                 if (!strnicmp(start, "#!AMR\n", 6)) {
     417          10 :                         ctx->start_offset = 6;
     418          10 :                         ctx->codecid = GF_CODECID_AMR;
     419             :                 }
     420           8 :                 else if (!strnicmp(start, "#!EVRC\n", 7)) {
     421           0 :                         ctx->start_offset = 7;
     422           0 :                         ctx->codecid = GF_CODECID_EVRC;
     423             :                 }
     424           8 :                 else if (!strnicmp(start, "#!SMV\n", 6)) {
     425           0 :                         ctx->start_offset = 6;
     426           0 :                         ctx->codecid = GF_CODECID_SMV;
     427             :                 }
     428           8 :                 else if (!strnicmp(start, "#!AMR-WB\n", 9)) {
     429           8 :                         ctx->codecid = GF_CODECID_AMR_WB;
     430           8 :                         ctx->start_offset = 9;
     431           8 :                         ctx->sample_rate = 16000;
     432           8 :                         ctx->block_size = 320;
     433             :                 }
     434          18 :                 start += ctx->start_offset;
     435          18 :                 remain -= ctx->start_offset;
     436             :         }
     437       42853 :         if (ctx->resume_from) {
     438       42333 :                 start += ctx->resume_from;
     439       42333 :                 remain -= ctx->resume_from;
     440       42333 :                 ctx->resume_from = 0;
     441             :         }
     442             : 
     443             : 
     444       43388 :         while (remain) {
     445             :                 u8 toc, ft;
     446       43376 :                 u16 amr_mode_set = ctx->amr_mode_set;
     447             :                 u32 size=0, i;
     448             : 
     449       43376 :                 toc = start[0];
     450       43376 :                 if (!toc) {
     451           0 :                         GF_LOG(GF_LOG_INFO, GF_LOG_MEDIA, ("[AMRDmx] Could not find TOC word in packet, dropping\n"));
     452             :                         break;
     453             :                 }
     454       43376 :                 switch (ctx->codecid) {
     455        3470 :                 case GF_CODECID_AMR:
     456        3470 :                         ft = (toc >> 3) & 0x0F;
     457             : 
     458             :                         /*update mode set (same mechanism for both AMR and AMR-WB*/
     459        3470 :                         amr_mode_set |= (1<<ft);
     460        3470 :                         size = (u32)GF_AMR_FRAME_SIZE[ft];
     461        3470 :                         break;
     462       39906 :                 case GF_CODECID_AMR_WB:
     463       39906 :                         ft = (toc >> 3) & 0x0F;
     464       39906 :                         size = (u32)GF_AMR_WB_FRAME_SIZE[ft];
     465             : 
     466             :                         /*update mode set (same mechanism for both AMR and AMR-WB*/
     467       39906 :                         amr_mode_set |= (1<<ft);
     468       39906 :                         break;
     469             :                 case GF_CODECID_NONE:
     470             :                         size=0;
     471             :                         break;
     472             :                 default:
     473           0 :                         for (i=0; i<GF_SMV_EVRC_RATE_TO_SIZE_NB; i++) {
     474           0 :                                 if (GF_SMV_EVRC_RATE_TO_SIZE[2*i]==toc) {
     475             :                                         /*remove rate_type byte*/
     476           0 :                                         size = (u32)GF_SMV_EVRC_RATE_TO_SIZE[2*i+1] - 1;
     477           0 :                                         break;
     478             :                                 }
     479             :                         }
     480             :                         break;
     481             :                 }
     482             : 
     483       43376 :                 if (!size) {
     484           0 :                         GF_LOG(GF_LOG_INFO, GF_LOG_MEDIA, ("[AMRDmx] Broken TOC, trying resync\n"));
     485           0 :                         start++;
     486           0 :                         remain--;
     487           0 :                         continue;
     488             :                 }
     489             :                 //ready to send packet
     490       43376 :                 amrdmx_check_pid(filter, ctx, amr_mode_set);
     491             : 
     492       43376 :                 if (!ctx->is_playing) return GF_OK;
     493       43367 :                 size++;
     494       43367 :                 if (size > remain) {
     495         499 :                         ctx->remaining = size - remain;
     496             :                         size = remain;
     497             :                 }
     498             : 
     499       43367 :                 if (ctx->in_seek) {
     500           2 :                         u64 nb_samples_at_seek = (u64) (ctx->start_range * ctx->sample_rate);
     501           2 :                         if (ctx->cts + ctx->block_size >= nb_samples_at_seek) {
     502             :                                 //u32 samples_to_discard = (ctx->cts + ctx->block_size ) - nb_samples_at_seek;
     503           2 :                                 ctx->in_seek = GF_FALSE;
     504             :                         }
     505             :                 }
     506       43367 :                 if (!ctx->in_seek) {
     507       43367 :                         dst_pck = gf_filter_pck_new_alloc(ctx->opid, size, &output);
     508       43367 :                         if (!dst_pck) return GF_OUT_OF_MEM;
     509             : 
     510       43367 :                         memcpy(output, start, size);
     511             : 
     512       43367 :                         gf_filter_pck_set_cts(dst_pck, ctx->cts);
     513       43367 :                         gf_filter_pck_set_sap(dst_pck, GF_FILTER_SAP_1);
     514       43367 :                         gf_filter_pck_set_duration(dst_pck, ctx->block_size);
     515       43367 :                         gf_filter_pck_set_framing(dst_pck, GF_TRUE, ctx->remaining ? GF_FALSE : GF_TRUE);
     516             : 
     517       43367 :                         if (byte_offset != GF_FILTER_NO_BO) {
     518             :                                 u64 boffset = byte_offset;
     519       43367 :                                 boffset += start - data;
     520       43367 :                                 gf_filter_pck_set_byte_offset(dst_pck, boffset);
     521             :                         }
     522             : 
     523       43367 :                         gf_filter_pck_send(dst_pck);
     524             :                 }
     525       43367 :                 start += size;
     526       43367 :                 remain -= size;
     527             : 
     528       43367 :                 ctx->skip_magic = 0;
     529       43367 :                 if (ctx->remaining) break;
     530             :                 amrdmx_update_cts(ctx);
     531             : 
     532             :                 //don't demux too much of input, abort when we would block. This avoid dispatching
     533             :                 //a huge number of frames in a single call
     534       42868 :                 if (gf_filter_pid_would_block(ctx->opid)) {
     535       42333 :                         ctx->resume_from = (u32) ( (char *)start -  (char *)data);
     536       42333 :                         return GF_OK;
     537             :                 }
     538             :         }
     539         511 :         gf_filter_pid_drop_packet(ctx->ipid);
     540             : 
     541         511 :         return GF_OK;
     542             : }
     543             : 
     544           9 : static GF_Err amrdmx_initialize(GF_Filter *filter)
     545             : {
     546           9 :         GF_AMRDmxCtx *ctx = gf_filter_get_udta(filter);
     547           9 :         ctx->skip_magic = GF_TRUE;
     548           9 :         return GF_OK;
     549             : }
     550             : 
     551           9 : static void amrdmx_finalize(GF_Filter *filter)
     552             : {
     553           9 :         GF_AMRDmxCtx *ctx = gf_filter_get_udta(filter);
     554           9 :         if (ctx->indexes) gf_free(ctx->indexes);
     555           9 : }
     556             : 
     557        3074 : static const char * amrdmx_probe_data(const u8 *data, u32 size, GF_FilterProbeScore *score)
     558             : {
     559        3074 :         if (!strnicmp(data, "#!AMR\n", 6)) {
     560           5 :                 *score = GF_FPROBE_SUPPORTED;
     561           5 :                 return "audio/amr";
     562             :         }
     563        3069 :         else if (!strnicmp(data, "#!AMR-WB\n", 9)) {
     564           4 :                 *score = GF_FPROBE_SUPPORTED;
     565           4 :                 return "audio/amr";
     566             :         }
     567        3065 :         else if (!strnicmp(data, "#!EVRC\n", 7)) {
     568           0 :                 *score = GF_FPROBE_SUPPORTED;
     569           0 :                 return "audio/evrc";
     570             :         }
     571        3065 :         else if (!strnicmp(data, "#!SMV\n", 6)) {
     572           0 :                 *score = GF_FPROBE_SUPPORTED;
     573           0 :                 return "audio/smv";
     574             :         }
     575             :         return NULL;
     576             : }
     577             : 
     578             : static const GF_FilterCapability AMRDmxCaps[] =
     579             : {
     580             :         CAP_UINT(GF_CAPS_INPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
     581             :         CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_FILE_EXT, "amr|awb|evc|smv"),
     582             :         CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_MIME, "audio/amr|audio/evrc|audio/smv"),
     583             :         CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
     584             :         CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_AMR),
     585             :         CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_AMR_WB),
     586             :         CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_SMV),
     587             :         CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_EVRC),
     588             :         CAP_BOOL(GF_CAPS_OUTPUT_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
     589             : };
     590             : 
     591             : #define OFFS(_n)        #_n, offsetof(GF_AMRDmxCtx, _n)
     592             : static const GF_FilterArgs AMRDmxArgs[] =
     593             : {
     594             :         { OFFS(index), "indexing window length", GF_PROP_DOUBLE, "1.0", NULL, 0},
     595             :         {0}
     596             : };
     597             : 
     598             : 
     599             : GF_FilterRegister AMRDmxRegister = {
     600             :         .name = "rfamr",
     601             :         GF_FS_SET_DESCRIPTION("AMR/EVRC reframer")
     602             :         GF_FS_SET_HELP("This filter parses AMR, AMR Wideband, EVRC and SMV files/data and outputs corresponding audio PID and frames.")
     603             :         .private_size = sizeof(GF_AMRDmxCtx),
     604             :         .args = AMRDmxArgs,
     605             :         .initialize = amrdmx_initialize,
     606             :         .finalize = amrdmx_finalize,
     607             :         SETCAPS(AMRDmxCaps),
     608             :         .configure_pid = amrdmx_configure_pid,
     609             :         .process = amrdmx_process,
     610             :         .probe_data = amrdmx_probe_data,
     611             :         .process_event = amrdmx_process_event
     612             : };
     613             : 
     614             : 
     615        2877 : const GF_FilterRegister *amrdmx_register(GF_FilterSession *session)
     616             : {
     617        2877 :         return &AMRDmxRegister;
     618             : }
     619             : 

Generated by: LCOV version 1.13