LCOV - code coverage report
Current view: top level - filters - reframe_flac.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 237 295 80.3 %
Date: 2021-04-29 23:48:07 Functions: 10 11 90.9 %

          Line data    Source code
       1             : /*
       2             :  *                      GPAC - Multimedia Framework C SDK
       3             :  *
       4             :  *                      Authors: Jean Le Feuvre
       5             :  *                      Copyright (c) Telecom ParisTech 2019-2021
       6             :  *                                      All rights reserved
       7             :  *
       8             :  *  This file is part of GPAC / FLAC 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/avparse.h>
      27             : #include <gpac/constants.h>
      28             : #include <gpac/filters.h>
      29             : 
      30             : typedef struct
      31             : {
      32             :         u64 pos;
      33             :         Double duration;
      34             : } FLACIdx;
      35             : 
      36             : typedef struct
      37             : {
      38             :         u32 block_size;
      39             :         u32 sample_rate;
      40             : } FLACHeader;
      41             : 
      42             : typedef struct
      43             : {
      44             :         //filter args
      45             :         Double index;
      46             : 
      47             :         //only one input pid declared
      48             :         GF_FilterPid *ipid;
      49             :         //only one output pid declared
      50             :         GF_FilterPid *opid;
      51             : 
      52             :         GF_BitStream *bs;
      53             :         u64 file_pos, cts, prev_cts;
      54             : 
      55             :         GF_Fraction64 duration;
      56             :         Double start_range;
      57             :         Bool in_seek;
      58             :         u32 timescale;
      59             :         Bool is_playing;
      60             :         Bool is_file;
      61             :         Bool initial_play_done, file_loaded;
      62             :         Bool in_error;
      63             : 
      64             :         Bool initialized;
      65             :         u32 sample_rate, nb_channels, bits_per_sample, block_size;
      66             : 
      67             :         u8 *flac_buffer;
      68             :         u32 flac_buffer_size, flac_buffer_alloc, resume_from;
      69             :         u64 byte_offset;
      70             : 
      71             :         GF_FilterPacket *src_pck;
      72             : 
      73             :         Bool recompute_cts;
      74             :         FLACIdx *indexes;
      75             :         u32 index_alloc_size, index_size;
      76             :         u32 bitrate;
      77             : } GF_FLACDmxCtx;
      78             : 
      79             : 
      80             : 
      81             : 
      82           4 : GF_Err flac_dmx_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
      83             : {
      84             :         const GF_PropertyValue *p;
      85           4 :         GF_FLACDmxCtx *ctx = gf_filter_get_udta(filter);
      86             : 
      87           4 :         if (is_remove) {
      88           0 :                 ctx->ipid = NULL;
      89           0 :                 if (ctx->opid) {
      90           0 :                         gf_filter_pid_remove(ctx->opid);
      91           0 :                         ctx->opid = NULL;
      92             :                 }
      93             :                 return GF_OK;
      94             :         }
      95           4 :         if (! gf_filter_pid_check_caps(pid))
      96             :                 return GF_NOT_SUPPORTED;
      97             : 
      98           4 :         ctx->ipid = pid;
      99           4 :         p = gf_filter_pid_get_property(pid, GF_PROP_PID_TIMESCALE);
     100           4 :         if (p) ctx->timescale = p->value.uint;
     101             : 
     102           4 :         p = gf_filter_pid_get_property_str(pid, "nocts");
     103           4 :         if (p && p->value.boolean) ctx->recompute_cts = GF_TRUE;
     104           4 :         else ctx->recompute_cts = GF_FALSE;
     105             : 
     106           4 :         if (ctx->timescale && !ctx->opid) {
     107           0 :                 ctx->opid = gf_filter_pid_new(filter);
     108           0 :                 gf_filter_pid_copy_properties(ctx->opid, ctx->ipid);
     109           0 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_UNFRAMED, NULL);
     110             :         }
     111             :         return GF_OK;
     112             : }
     113             : 
     114          13 : static void flac_dmx_check_dur(GF_Filter *filter, GF_FLACDmxCtx *ctx)
     115             : {
     116             :         u64 rate;
     117             :         FILE *stream;
     118             :         const GF_PropertyValue *p;
     119          13 :         if (!ctx->opid || ctx->timescale || ctx->file_loaded) return;
     120             : 
     121           4 :         if (ctx->index<=0) {
     122           3 :                 ctx->file_loaded = GF_TRUE;
     123             :                 return;
     124             :         }
     125             : 
     126           1 :         p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_FILEPATH);
     127           1 :         if (!p || !p->value.string || !strncmp(p->value.string, "gmem://", 7)) {
     128           0 :                 ctx->is_file = GF_FALSE;
     129           0 :                 ctx->file_loaded = GF_TRUE;
     130             :                 return;
     131             :         }
     132           1 :         ctx->is_file = GF_TRUE;
     133             : 
     134           1 :         stream = gf_fopen(p->value.string, "rb");
     135           1 :         if (!stream) return;
     136           1 :         gf_fseek(stream, 0, SEEK_END);
     137             : 
     138           1 :         rate = gf_ftell(stream);
     139           1 :         gf_fclose(stream);
     140           1 :         if (ctx->duration.num && !gf_sys_is_test_mode() ) {
     141           0 :                 rate *= 8 * ctx->duration.den;
     142           0 :                 rate /= ctx->duration.num;
     143           0 :                 ctx->bitrate = (u32) rate;
     144             :         }
     145             : 
     146           1 :         p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_FILE_CACHED);
     147           1 :         if (p && p->value.boolean) ctx->file_loaded = GF_TRUE;
     148           1 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CAN_DATAREF, & PROP_BOOL(GF_TRUE ) );
     149             : }
     150             : 
     151           4 : static void flac_dmx_check_pid(GF_Filter *filter, GF_FLACDmxCtx *ctx, u8 *dsi, u32 dsi_size)
     152             : {
     153           4 :         if (!ctx->opid) {
     154           4 :                 ctx->opid = gf_filter_pid_new(filter);
     155           4 :                 flac_dmx_check_dur(filter, ctx);
     156             :         }
     157             :         //copy properties at init or reconfig
     158           4 :         gf_filter_pid_copy_properties(ctx->opid, ctx->ipid);
     159           4 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_STREAM_TYPE, & PROP_UINT( GF_STREAM_AUDIO));
     160           4 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_UNFRAMED, NULL );
     161           4 :         if (ctx->is_file && ctx->index) {
     162           1 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_PLAYBACK_MODE, & PROP_UINT(GF_PLAYBACK_MODE_FASTFORWARD) );
     163             :         }
     164           4 :         if (ctx->duration.num)
     165           4 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DURATION, & PROP_FRAC64(ctx->duration));
     166             : 
     167           4 :         if (!ctx->timescale) gf_filter_pid_set_name(ctx->opid, "audio");
     168             : 
     169           4 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DECODER_CONFIG, & PROP_DATA( dsi, dsi_size ) );
     170             : 
     171           4 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CODECID, & PROP_UINT( GF_CODECID_FLAC ) );
     172           4 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_TIMESCALE, & PROP_UINT(ctx->timescale ? ctx->timescale : ctx->sample_rate));
     173           4 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_SAMPLE_RATE, & PROP_UINT(ctx->sample_rate));
     174           4 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_NUM_CHANNELS, & PROP_UINT(ctx->nb_channels) );
     175           4 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_SAMPLES_PER_FRAME, & PROP_UINT(ctx->block_size) );
     176             : 
     177           4 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_AUDIO_BPS, & PROP_UINT(ctx->bits_per_sample) );
     178             : 
     179           4 :         if (ctx->bitrate) {
     180           0 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_BITRATE, & PROP_UINT(ctx->bitrate));
     181             :         }
     182             : 
     183           4 : }
     184             : 
     185         412 : static Bool flac_dmx_process_event(GF_Filter *filter, const GF_FilterEvent *evt)
     186             : {
     187             :         u32 i;
     188             :         GF_FilterEvent fevt;
     189         412 :         GF_FLACDmxCtx *ctx = gf_filter_get_udta(filter);
     190             : 
     191         412 :         if (evt->base.on_pid != ctx->opid) return GF_TRUE;
     192             : 
     193           6 :         switch (evt->base.type) {
     194           4 :         case GF_FEVT_PLAY:
     195           4 :                 if (!ctx->is_playing) {
     196           4 :                         ctx->is_playing = GF_TRUE;
     197             :                 }
     198           4 :                 if (! ctx->is_file) {
     199           3 :                         if (evt->play.start_range || ctx->initial_play_done) {
     200           0 :                                 ctx->flac_buffer_size = 0;
     201           0 :                                 ctx->resume_from = 0;
     202             :                         }
     203           3 :                         ctx->initial_play_done = GF_TRUE;
     204           3 :                         return GF_FALSE;
     205             :                 }
     206           1 :                 flac_dmx_check_dur(filter, ctx);
     207             : 
     208           1 :                 ctx->start_range = evt->play.start_range;
     209           1 :                 ctx->in_seek = GF_TRUE;
     210           1 :                 ctx->file_pos = 0;
     211           1 :                 if (ctx->start_range) {
     212           0 :                         for (i=1; i<ctx->index_size; i++) {
     213           0 :                                 if (ctx->indexes[i].duration>ctx->start_range) {
     214           0 :                                         ctx->cts = (u64) (ctx->indexes[i-1].duration * ctx->sample_rate);
     215           0 :                                         ctx->file_pos = ctx->indexes[i-1].pos;
     216           0 :                                         break;
     217             :                                 }
     218             :                         }
     219             :                 }
     220           1 :                 if (!ctx->initial_play_done) {
     221           1 :                         ctx->initial_play_done = GF_TRUE;
     222             :                         //seek will not change the current source state, don't send a seek
     223           1 :                         if (!ctx->file_pos)
     224             :                                 return GF_TRUE;
     225             :                 }
     226           0 :                 ctx->flac_buffer_size = 0;
     227           0 :                 ctx->resume_from = 0;
     228             :                 //post a seek
     229           0 :                 GF_FEVT_INIT(fevt, GF_FEVT_SOURCE_SEEK, ctx->ipid);
     230           0 :                 fevt.seek.start_offset = ctx->file_pos;
     231           0 :                 gf_filter_pid_send_event(ctx->ipid, &fevt);
     232             : 
     233             :                 //cancel event
     234           0 :                 return GF_TRUE;
     235             : 
     236           2 :         case GF_FEVT_STOP:
     237           2 :                 ctx->is_playing = GF_FALSE;
     238           2 :                 if (ctx->src_pck) gf_filter_pck_unref(ctx->src_pck);
     239           2 :                 ctx->src_pck = NULL;
     240             :                 //don't cancel event
     241           2 :                 return GF_FALSE;
     242             : 
     243             :         case GF_FEVT_SET_SPEED:
     244             :                 //cancel event
     245             :                 return GF_TRUE;
     246             :         default:
     247             :                 break;
     248             :         }
     249             :         //by default don't cancel event - to rework once we have downloading in place
     250           0 :         return GF_FALSE;
     251             : }
     252             : 
     253             : static GFINLINE void flac_dmx_update_cts(GF_FLACDmxCtx *ctx, u32 nb_samp)
     254             : {
     255         154 :         if (ctx->timescale) {
     256           0 :                 u64 inc = nb_samp;
     257           0 :                 inc *= ctx->timescale;
     258           0 :                 inc /= ctx->sample_rate;
     259           0 :                 ctx->cts += inc;
     260             :         } else {
     261         154 :                 ctx->cts += nb_samp;
     262             :         }
     263             : }
     264             : 
     265             : 
     266             : u8 const flac_dmx_crc8_table[256] = {
     267             :         0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15,
     268             :         0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
     269             :         0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65,
     270             :         0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,
     271             :         0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5,
     272             :         0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,
     273             :         0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85,
     274             :         0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,
     275             :         0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2,
     276             :         0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,
     277             :         0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2,
     278             :         0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,
     279             :         0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32,
     280             :         0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,
     281             :         0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42,
     282             :         0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,
     283             :         0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C,
     284             :         0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,
     285             :         0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC,
     286             :         0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,
     287             :         0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C,
     288             :         0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,
     289             :         0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C,
     290             :         0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
     291             :         0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B,
     292             :         0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,
     293             :         0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B,
     294             :         0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,
     295             :         0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB,
     296             :         0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
     297             :         0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB,
     298             :         0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3
     299             : };
     300             : 
     301           0 : u8 flac_dmx_crc8(u8 *data, u32 len)
     302             : {
     303             :         u8 crc = 0;
     304        2624 :         while (len--)
     305        2198 :                 crc = flac_dmx_crc8_table[crc ^ *data++];
     306           0 :         return crc;
     307             : }
     308             : 
     309             : static u32 flac_dmx_block_sizes[] =
     310             : {
     311             :         0, 192, 576, 1152, 2304, 4608, 0, 0, 256, 512, 1024, 2048, 4096, 8192, 16384,  32768
     312             : };
     313             : static u32 flac_dmx_samplerates[] =
     314             : {
     315             :         0, 88200, 176400, 192000, 8000, 16000, 22050, 24000, 32000, 44100, 48000, 96000
     316             : };
     317             : 
     318         554 : static Bool flac_parse_header(GF_FLACDmxCtx *ctx, char *data, u32 size, FLACHeader *hdr)
     319             : {
     320             :         u32 block_size, sample_rate, res, top, pos, crc, crc_hdr;
     321             : 
     322         554 :         gf_bs_reassign_buffer(ctx->bs, data, size);
     323         554 :         gf_bs_read_int(ctx->bs, 15);
     324         554 :         /*block_strategy = */gf_bs_read_int(ctx->bs, 1);
     325         554 :         block_size = gf_bs_read_int(ctx->bs, 4);
     326         554 :         sample_rate = gf_bs_read_int(ctx->bs, 4);
     327         554 :         /*u32 channel_layout = */gf_bs_read_int(ctx->bs, 4);
     328         554 :         /*u32 bps = */gf_bs_read_int(ctx->bs, 3);
     329         554 :         gf_bs_read_int(ctx->bs, 1);
     330             : 
     331         554 :         res = gf_bs_read_u8(ctx->bs);
     332         554 :         top = (res & 128) >> 1;
     333         554 :         if ((res & 0xC0) == 0x80 || (res >= 0xFE)) return GF_FALSE;
     334         508 :         while (res & top) {
     335          82 :                 s32 tmp = gf_bs_read_u8(ctx->bs);
     336          82 :                 tmp -= 128;
     337          82 :                 if(tmp>>6)
     338             :                         return GF_FALSE;
     339          36 :                 res = (res<<6) + tmp;
     340          36 :                 top <<= 5;
     341             :         }
     342             :         //res &= (top << 1) - 1;
     343             : 
     344         426 :         if (block_size==6) block_size = 1 + gf_bs_read_int(ctx->bs, 8);
     345         420 :         else if (block_size==7) block_size = 1 + gf_bs_read_int(ctx->bs, 16);
     346             :         else {
     347         410 :                 block_size = flac_dmx_block_sizes[block_size];
     348             :         }
     349             : 
     350             : #if 0
     351             :         if (bps==0) bps = ctx->bits_per_sample;
     352             :         else if (bps==1) bps = 8;
     353             :         else if (bps==2) bps = 12;
     354             :         else if (bps==4) bps = 16;
     355             :         else if (bps==5) bps = 20;
     356             :         else if (bps==6) bps = 24;
     357             : #endif
     358             : 
     359         426 :         if (sample_rate==0) sample_rate = ctx->sample_rate;
     360         420 :         else if ((sample_rate&0xC)==0xC) {
     361          17 :                 if (sample_rate==0xC) sample_rate = gf_bs_read_u8(ctx->bs);
     362          13 :                 else if (sample_rate==0xD) sample_rate = gf_bs_read_u16(ctx->bs);
     363          13 :                 else if (sample_rate==0xE) sample_rate = 10*gf_bs_read_u16(ctx->bs);
     364             :         } else {
     365         403 :                 sample_rate = flac_dmx_samplerates[sample_rate];
     366             :         }
     367             : 
     368         426 :         pos = (u32) gf_bs_get_position(ctx->bs);
     369             : 
     370         426 :         crc = gf_bs_read_u8(ctx->bs);
     371         426 :         crc_hdr = flac_dmx_crc8(data, pos);
     372             : 
     373         426 :         if (crc != crc_hdr) {
     374             :                 return GF_FALSE;
     375             :         }
     376         310 :         hdr->sample_rate = sample_rate;
     377         310 :         hdr->block_size = block_size;
     378             :         return GF_TRUE;
     379             : }
     380             : 
     381         426 : GF_Err flac_dmx_process(GF_Filter *filter)
     382             : {
     383         426 :         GF_FLACDmxCtx *ctx = gf_filter_get_udta(filter);
     384             :         GF_FilterPacket *pck, *dst_pck;
     385             :         u8 *output;
     386             :         u8 *start;
     387             :         Bool final_flush=GF_FALSE;
     388             :         u32 pck_size, remain, prev_pck_size;
     389             :         u64 cts = GF_FILTER_NO_TS;
     390             :         FLACHeader hdr;
     391             : 
     392         426 :         if (ctx->in_error)
     393             :                 return GF_NON_COMPLIANT_BITSTREAM;
     394             : 
     395             :         //always reparse duration
     396         426 :         if (!ctx->duration.num)
     397           8 :                 flac_dmx_check_dur(filter, ctx);
     398             : 
     399         426 :         if (ctx->opid && !ctx->is_playing)
     400             :                 return GF_OK;
     401             : 
     402         410 :         pck = gf_filter_pid_get_packet(ctx->ipid);
     403         410 :         if (!pck) {
     404           4 :                 if (gf_filter_pid_is_eos(ctx->ipid)) {
     405           4 :                         if (!ctx->flac_buffer_size) {
     406           2 :                                 if (ctx->opid)
     407           2 :                                         gf_filter_pid_set_eos(ctx->opid);
     408           2 :                                 if (ctx->src_pck) gf_filter_pck_unref(ctx->src_pck);
     409           2 :                                 ctx->src_pck = NULL;
     410           2 :                                 return GF_EOS;
     411             :                         }
     412             :                         final_flush = GF_TRUE;
     413             :                 } else {
     414             :                         return GF_OK;
     415             :                 }
     416             :         }
     417             : 
     418         408 :         prev_pck_size = ctx->flac_buffer_size;
     419         408 :         if (pck && !ctx->resume_from) {
     420         406 :                 u8 *data = (u8 *) gf_filter_pck_get_data(pck, &pck_size);
     421             : 
     422         406 :                 if (ctx->byte_offset != GF_FILTER_NO_BO) {
     423         406 :                         u64 byte_offset = gf_filter_pck_get_byte_offset(pck);
     424         406 :                         if (!ctx->flac_buffer_size) {
     425           4 :                                 ctx->byte_offset = byte_offset;
     426         402 :                         } else if (ctx->byte_offset + ctx->flac_buffer_size != byte_offset) {
     427         154 :                                 ctx->byte_offset = GF_FILTER_NO_BO;
     428         154 :                                 if ((byte_offset != GF_FILTER_NO_BO) && (byte_offset>ctx->flac_buffer_size) ) {
     429         154 :                                         ctx->byte_offset = byte_offset - ctx->flac_buffer_size;
     430             :                                 }
     431             :                         }
     432             :                 }
     433             : 
     434         406 :                 if (ctx->flac_buffer_size + pck_size > ctx->flac_buffer_alloc) {
     435          33 :                         ctx->flac_buffer_alloc = ctx->flac_buffer_size + pck_size;
     436          33 :                         ctx->flac_buffer = gf_realloc(ctx->flac_buffer, ctx->flac_buffer_alloc);
     437             :                 }
     438         406 :                 memcpy(ctx->flac_buffer + ctx->flac_buffer_size, data, pck_size);
     439         406 :                 ctx->flac_buffer_size += pck_size;
     440             :         }
     441             : 
     442             :         //input pid sets some timescale - we flushed pending data , update cts
     443         408 :         if (ctx->timescale && pck) {
     444           0 :                 cts = gf_filter_pck_get_cts(pck);
     445             :         }
     446             : 
     447           0 :         if (cts == GF_FILTER_NO_TS) {
     448             :                 //avoids updating cts
     449             :                 prev_pck_size = 0;
     450             :         }
     451             : 
     452         408 :         remain = ctx->flac_buffer_size;
     453         408 :         start = ctx->flac_buffer;
     454             : 
     455         408 :         if (ctx->resume_from) {
     456           0 :                 start += ctx->resume_from - 1;
     457           0 :                 remain -= ctx->resume_from - 1;
     458           0 :                 ctx->resume_from = 0;
     459             :         }
     460             : 
     461         562 :         while (remain>2) {
     462             :                 u32 next_frame=0, nb_samp;
     463         560 :                 u32 cur_size = remain-2;
     464         560 :                 u8 *cur_buf = start+2;
     465             :                 u8 *hdr_start = NULL;
     466             : 
     467         560 :                 if (final_flush) {
     468             :                         next_frame = remain;
     469             :                 } else {
     470       15752 :                         while (cur_size) {
     471             :                                 //wait till we have a frame header
     472       15750 :                                 hdr_start = memchr(cur_buf, 0xFF, cur_size);
     473       15750 :                                 if (!hdr_start) break;
     474       15350 :                                 next_frame = (u32) (hdr_start-start);
     475       15350 :                                 if (next_frame == remain)
     476             :                                         break;
     477             : 
     478       15350 :                                 if ((hdr_start[1]&0xFC) == 0xF8) {
     479         400 :                                         if (flac_parse_header(ctx, hdr_start, (u32) remain - next_frame, &hdr))
     480             :                                                 break;
     481             :                                 }
     482       15194 :                                 cur_buf = hdr_start+1;
     483       15194 :                                 cur_size = (u32) (cur_buf - start);
     484             :                                 assert(cur_size<=remain);
     485       15194 :                                 cur_size = remain - cur_size;
     486             :                                 hdr_start = NULL;
     487             :                         }
     488         558 :                         if (!hdr_start) break;
     489         156 :                         if (next_frame == remain)
     490             :                                 break;
     491             :                 }
     492             : 
     493             : 
     494         158 :                 if (!ctx->initialized) {
     495             :                         u32 size = next_frame;
     496             :                         u32 dsi_end = 0;
     497             :                         //we have a header
     498           4 :                         gf_bs_reassign_buffer(ctx->bs, ctx->flac_buffer, size);
     499           4 :                         u32 magic = gf_bs_read_u32(ctx->bs);
     500           4 :                         if (magic != GF_4CC('f','L','a','C')) {
     501           0 :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[FLACDmx] invalid FLAC magic\n"));
     502           0 :                                 ctx->in_error = GF_TRUE;
     503           0 :                                 ctx->flac_buffer_size = 0;
     504           0 :                                 if (pck)
     505           0 :                                         gf_filter_pid_drop_packet(ctx->ipid);
     506             :                                 return GF_NON_COMPLIANT_BITSTREAM;
     507             :                         }
     508          12 :                         while (gf_bs_available(ctx->bs)) {
     509          12 :                                 Bool last = gf_bs_read_int(ctx->bs, 1);
     510          12 :                                 u32 type = gf_bs_read_int(ctx->bs, 7);
     511          12 :                                 u32 len = gf_bs_read_int(ctx->bs, 24);
     512             : 
     513          12 :                                 if (type==0) {
     514           4 :                                         u16 min_block_size = gf_bs_read_u16(ctx->bs);
     515           4 :                                         u16 max_block_size = gf_bs_read_u16(ctx->bs);
     516           4 :                                         /*u32 min_frame_size = */gf_bs_read_u24(ctx->bs);
     517           4 :                                         /*u32 max_frame_size = */gf_bs_read_u24(ctx->bs);
     518           4 :                                         ctx->sample_rate = gf_bs_read_int(ctx->bs, 20);
     519           4 :                                         ctx->nb_channels = 1 + gf_bs_read_int(ctx->bs, 3);
     520           4 :                                         ctx->bits_per_sample = 1 + gf_bs_read_int(ctx->bs, 5);
     521           4 :                                         if (min_block_size==max_block_size) ctx->block_size = min_block_size;
     522           0 :                                         else ctx->block_size = 0;
     523             : 
     524           4 :                                         ctx->duration.num = gf_bs_read_long_int(ctx->bs, 36);
     525           4 :                                         ctx->duration.den = ctx->sample_rate;
     526             :                                         //ignore the rest
     527           4 :                                         gf_bs_skip_bytes(ctx->bs, 16);
     528           4 :                                         dsi_end = (u32) gf_bs_get_position(ctx->bs);
     529             : 
     530             :                                 } else {
     531             :                                         //ignore the rest for now
     532             :                                         //TODO: expose metadata, pictures and co
     533           8 :                                         gf_bs_skip_bytes(ctx->bs, len);
     534             :                                 }
     535          12 :                                 if (last) break;
     536             :                         }
     537           4 :                         if (!dsi_end) {
     538           0 :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[FLACDmx] invalid FLAC header\n"));
     539           0 :                                 ctx->in_error = GF_TRUE;
     540           0 :                                 ctx->flac_buffer_size = 0;
     541           0 :                                 if (pck)
     542           0 :                                         gf_filter_pid_drop_packet(ctx->ipid);
     543             :                                 return GF_NON_COMPLIANT_BITSTREAM;
     544             :                         }
     545           4 :                         flac_dmx_check_pid(filter, ctx, ctx->flac_buffer+4, dsi_end-4);
     546           4 :                         remain -= size;
     547           4 :                         start += size;
     548           4 :                         ctx->initialized = GF_TRUE;
     549           4 :                         if (!ctx->is_playing) break;
     550           0 :                         continue;
     551             :                 }
     552             : 
     553             :                 //we have a next frame, check we are synchronize
     554         154 :                 if ((start[0] != 0xFF) && ((start[1]&0xFC) != 0xF8)) {
     555           0 :                         GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[FLACDmx] invalid frame, dropping %d bytes and resyncing\n", next_frame));
     556           0 :                         start += next_frame;
     557           0 :                         remain -= next_frame;
     558           0 :                         continue;
     559             :                 }
     560             : 
     561         154 :                 flac_parse_header(ctx,start, next_frame, &hdr);
     562         154 :                 if (hdr.sample_rate != ctx->sample_rate) {
     563           0 :                         ctx->sample_rate = hdr.sample_rate;
     564           0 :                         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_SAMPLE_RATE, & PROP_UINT(ctx->sample_rate));
     565             :                 }
     566             : 
     567         154 :                 nb_samp = hdr.block_size;
     568             : 
     569         154 :                 if (ctx->in_seek) {
     570           1 :                         u64 nb_samples_at_seek = (u64) (ctx->start_range * ctx->sample_rate);
     571           1 :                         if (ctx->cts + nb_samp >= nb_samples_at_seek) {
     572             :                                 //u32 samples_to_discard = (ctx->cts + nb_samp ) - nb_samples_at_seek;
     573           1 :                                 ctx->in_seek = GF_FALSE;
     574             :                         }
     575             :                 }
     576             : 
     577         154 :                 if (ctx->timescale && !prev_pck_size && (cts != GF_FILTER_NO_TS) ) {
     578           0 :                         ctx->cts = cts;
     579             :                         cts = GF_FILTER_NO_TS;
     580             :                 }
     581             : 
     582         154 :                 if (!ctx->in_seek) {
     583         154 :                         dst_pck = gf_filter_pck_new_alloc(ctx->opid, next_frame, &output);
     584         154 :                         if (!dst_pck) return GF_OUT_OF_MEM;
     585         154 :                         memcpy(output, start, next_frame);
     586             : 
     587         154 :                         gf_filter_pck_set_cts(dst_pck, ctx->cts);
     588         154 :                         if (!ctx->timescale || (ctx->timescale==ctx->sample_rate) )
     589         154 :                                 gf_filter_pck_set_duration(dst_pck, nb_samp);
     590             :                         else {
     591           0 :                                 gf_filter_pck_set_duration(dst_pck, (nb_samp * ctx->timescale) / ctx->sample_rate);
     592             :                         }
     593         154 :                         gf_filter_pck_set_sap(dst_pck, GF_FILTER_SAP_1);
     594         154 :                         gf_filter_pck_set_framing(dst_pck, GF_TRUE, GF_TRUE);
     595             : 
     596         154 :                         if (ctx->byte_offset != GF_FILTER_NO_BO) {
     597         154 :                                 gf_filter_pck_set_byte_offset(dst_pck, ctx->byte_offset);
     598             :                         }
     599         154 :                         gf_filter_pck_send(dst_pck);
     600             :                 }
     601             :                 flac_dmx_update_cts(ctx, nb_samp);
     602             : 
     603             :                 assert (start[0] == 0xFF);
     604             :                 assert((start[1]&0xFC) == 0xF8);
     605             : 
     606         154 :                 start += next_frame;
     607             :                 assert(remain >= next_frame);
     608         154 :                 remain -= next_frame;
     609             : 
     610             :         }
     611             : 
     612         408 :         if (!pck) {
     613           2 :                 ctx->flac_buffer_size = 0;
     614           2 :                 return flac_dmx_process(filter);
     615             :         } else {
     616         406 :                 if (remain < ctx->flac_buffer_size) {
     617         156 :                         memmove(ctx->flac_buffer, start, remain);
     618             :                 }
     619         406 :                 ctx->flac_buffer_size = remain;
     620         406 :                 gf_filter_pid_drop_packet(ctx->ipid);
     621             :         }
     622         406 :         return GF_OK;
     623             : }
     624             : 
     625           4 : static GF_Err flac_dmx_initialize(GF_Filter *filter)
     626             : {
     627           4 :         GF_FLACDmxCtx *ctx = gf_filter_get_udta(filter);
     628           4 :         ctx->bs = gf_bs_new((u8 *)ctx, 1, GF_BITSTREAM_READ);
     629           4 :         return GF_OK;
     630             : }
     631           4 : static void flac_dmx_finalize(GF_Filter *filter)
     632             : {
     633           4 :         GF_FLACDmxCtx *ctx = gf_filter_get_udta(filter);
     634           4 :         if (ctx->bs) gf_bs_del(ctx->bs);
     635           4 :         if (ctx->indexes) gf_free(ctx->indexes);
     636           4 :         if (ctx->flac_buffer) gf_free(ctx->flac_buffer);
     637           4 :         if (ctx->src_pck) gf_filter_pck_unref(ctx->src_pck);
     638           4 : }
     639             : 
     640             : 
     641        3065 : static const char *flac_dmx_probe_data(const u8 *data, u32 size, GF_FilterProbeScore *score)
     642             : {
     643        3065 :         if ((size>4) && !strncmp(data, "fLaC", 4)) {
     644           4 :                 *score = GF_FPROBE_SUPPORTED;
     645           4 :                 return "audio/flac";
     646             :         }
     647             :         return NULL;
     648             : }
     649             : 
     650             : static const GF_FilterCapability FLACDmxCaps[] =
     651             : {
     652             :         CAP_UINT(GF_CAPS_INPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
     653             :         CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_FILE_EXT, "flac"),
     654             :         CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_MIME, "audio/flac"),
     655             :         CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
     656             :         CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_FLAC),
     657             :         CAP_BOOL(GF_CAPS_OUTPUT_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
     658             :         {0},
     659             :         CAP_UINT(GF_CAPS_INPUT_OUTPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
     660             :         CAP_BOOL(GF_CAPS_INPUT,GF_PROP_PID_UNFRAMED, GF_TRUE),
     661             :         CAP_UINT(GF_CAPS_INPUT_OUTPUT,GF_PROP_PID_CODECID, GF_CODECID_FLAC),
     662             :         CAP_BOOL(GF_CAPS_OUTPUT_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
     663             : };
     664             : 
     665             : 
     666             : 
     667             : #define OFFS(_n)        #_n, offsetof(GF_FLACDmxCtx, _n)
     668             : static const GF_FilterArgs FLACDmxArgs[] =
     669             : {
     670             :         { OFFS(index), "indexing window length", GF_PROP_DOUBLE, "1.0", NULL, 0},
     671             :         {0}
     672             : };
     673             : 
     674             : 
     675             : GF_FilterRegister FLACDmxRegister = {
     676             :         .name = "rfflac",
     677             :         GF_FS_SET_DESCRIPTION("FLAC reframer")
     678             :         GF_FS_SET_HELP("This filter parses FLAC files/data and outputs corresponding audio PID and frames.")
     679             :         .private_size = sizeof(GF_FLACDmxCtx),
     680             :         .args = FLACDmxArgs,
     681             :         .finalize = flac_dmx_finalize,
     682             :         .initialize = flac_dmx_initialize,
     683             :         SETCAPS(FLACDmxCaps),
     684             :         .configure_pid = flac_dmx_configure_pid,
     685             :         .process = flac_dmx_process,
     686             :         .probe_data = flac_dmx_probe_data,
     687             :         .process_event = flac_dmx_process_event
     688             : };
     689             : 
     690             : 
     691        2877 : const GF_FilterRegister *flac_dmx_register(GF_FilterSession *session)
     692             : {
     693        2877 :         return &FLACDmxRegister;
     694             : }

Generated by: LCOV version 1.13