LCOV - code coverage report
Current view: top level - filters - reframe_qcp.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 278 353 78.8 %
Date: 2021-04-29 23:48:07 Functions: 8 8 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             : #include <gpac/bitstream.h>
      29             : #include <gpac/internal/media_dev.h>
      30             : 
      31             : typedef struct
      32             : {
      33             :         u64 pos;
      34             :         Double duration;
      35             : } QCPIdx;
      36             : 
      37             : typedef struct
      38             : {
      39             :         //filter args
      40             :         Double index;
      41             : 
      42             :         //only one input pid declared
      43             :         GF_FilterPid *ipid;
      44             :         //only one output pid declared
      45             :         GF_FilterPid *opid;
      46             : 
      47             :         u32 codecid, sample_rate, block_size;
      48             :         Bool done;
      49             : 
      50             :         u64 cts;
      51             :         GF_Fraction64 duration;
      52             :         Double start_range;
      53             : 
      54             :         Bool in_seek;
      55             :         u32 timescale;
      56             :         Bool is_playing;
      57             :         Bool is_file;
      58             :         Bool initial_play_done, file_loaded;
      59             : 
      60             :         u32 data_chunk_offset, data_chunk_size, data_chunk_remain;
      61             :         u32 resume_from;
      62             :         u32 remaining;
      63             :         u32 skip_bytes;
      64             :         u32 vrat_rate_flag, pck_size, rate_table_count;
      65             :         QCPRateTable rate_table[8];
      66             : 
      67             :         Bool hdr_processed;
      68             : 
      69             :         char *buffer;
      70             :         u32 buffer_alloc, buffer_size;
      71             : 
      72             :         GF_BitStream *bs;
      73             : 
      74             : 
      75             :         QCPIdx *indexes;
      76             :         u32 index_alloc_size, index_size;
      77             : } GF_QCPDmxCtx;
      78             : 
      79             : 
      80             : 
      81             : 
      82          14 : GF_Err qcpdmx_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
      83             : {
      84          14 :         GF_QCPDmxCtx *ctx = gf_filter_get_udta(filter);
      85             : 
      86          14 :         if (is_remove) {
      87           0 :                 ctx->ipid = NULL;
      88           0 :                 if (ctx->opid) {
      89           0 :                         gf_filter_pid_remove(ctx->opid);
      90           0 :                         ctx->opid = NULL;
      91             :                 }
      92             :                 return GF_OK;
      93             :         }
      94          14 :         if (! gf_filter_pid_check_caps(pid))
      95             :                 return GF_NOT_SUPPORTED;
      96             : 
      97          14 :         ctx->ipid = pid;
      98          14 :         return GF_OK;
      99             : }
     100             : 
     101             : static GF_Err qcpdmx_process_header(GF_Filter *filter, GF_QCPDmxCtx *ctx, char *data, u32 size, GF_BitStream *file_bs);
     102             : 
     103       16298 : static void qcpdmx_check_dur(GF_Filter *filter, GF_QCPDmxCtx *ctx)
     104             : {
     105             :         FILE *stream;
     106             :         GF_BitStream *bs;
     107             :         u32 i, chunk_size;
     108             :         GF_Err e;
     109             :         u32 data_chunk_size = 0;
     110             :         u64 duration, cur_dur;
     111             :         char magic[4];
     112             :         const GF_PropertyValue *p;
     113       32595 :         if (!ctx->opid || ctx->timescale || ctx->file_loaded) return;
     114             : 
     115           7 :         if (ctx->index<=0) {
     116           6 :                 ctx->file_loaded = GF_TRUE;
     117           6 :                 return;
     118             :         }
     119             : 
     120           1 :         p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_FILEPATH);
     121           1 :         if (!p || !p->value.string || !strncmp(p->value.string, "gmem://", 7)) {
     122           0 :                 ctx->is_file = GF_FALSE;
     123           0 :                 ctx->file_loaded = GF_TRUE;
     124           0 :                 return;
     125             :         }
     126           1 :         ctx->is_file = GF_TRUE;
     127             : 
     128           1 :         stream = gf_fopen(p->value.string, "rb");
     129           1 :         if (!stream) return;
     130             : 
     131           1 :         ctx->codecid = 0;
     132           1 :         ctx->sample_rate = 8000;
     133           1 :         ctx->block_size = 160;
     134             : 
     135           1 :         bs = gf_bs_from_file(stream, GF_BITSTREAM_READ);
     136           1 :         if (!ctx->hdr_processed ) {
     137           0 :                 e = qcpdmx_process_header(filter, ctx, NULL, 0, bs);
     138           0 :                 if (e) {
     139           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[QCPDmx] Header parsed error %s\n", gf_error_to_string(e) ));
     140             :                 }
     141             :         } else {
     142           1 :                 gf_bs_skip_bytes(bs, 170);
     143             :         }
     144           2 :         while (gf_bs_available(bs) ) {
     145           2 :                 gf_bs_read_data(bs, magic, 4);
     146           2 :                 chunk_size = gf_bs_read_u32_le(bs);
     147             : 
     148           2 :                 if (strncmp(magic, "data", 4)) {
     149           1 :                         gf_bs_skip_bytes(bs, chunk_size);
     150           1 :                         if (chunk_size%2) gf_bs_skip_bytes(bs, 1);
     151           1 :                         continue;
     152             :                 }
     153             :                 data_chunk_size = chunk_size;
     154             :                 break;
     155             :         }
     156           1 :         if (!data_chunk_size) {
     157           0 :                 gf_bs_del(bs);
     158           0 :                 gf_fclose(stream);
     159           0 :                 return;
     160             :         }
     161             : 
     162           1 :         ctx->index_size = 0;
     163           1 :         ctx->data_chunk_offset = (u32) gf_ftell(stream);
     164           1 :         ctx->data_chunk_size = data_chunk_size;
     165             : 
     166             :         duration = 0;
     167             :         cur_dur = 0;
     168         951 :         while (data_chunk_size) {
     169             :                 u32 idx, size=0;
     170             :                 u64 pos;
     171         949 :                 pos = gf_ftell(stream);
     172             :                 /*get frame rate idx*/
     173         949 :                 if (ctx->vrat_rate_flag) {
     174         949 :                         idx = gf_fgetc(stream);
     175             :                         chunk_size-=1;
     176        4069 :                         for (i=0; i<ctx->rate_table_count; i++) {
     177        3612 :                                 if (ctx->rate_table[i].rate_idx==idx) {
     178         492 :                                         size = ctx->rate_table[i].pck_size;
     179         492 :                                         break;
     180             :                                 }
     181             :                         }
     182         949 :                         gf_fseek(stream, size, SEEK_CUR);
     183         949 :                         size++;
     184             :                 } else {
     185           0 :                         size = ctx->pck_size;
     186           0 :                         gf_fseek(stream, size, SEEK_CUR);
     187             :                 }
     188         949 :                 data_chunk_size-= size;
     189             :                 
     190         949 :                 duration += ctx->block_size;
     191         949 :                 cur_dur += ctx->block_size;
     192         949 :                 if (cur_dur > ctx->index * ctx->sample_rate) {
     193          18 :                         if (!ctx->index_alloc_size) ctx->index_alloc_size = 10;
     194          17 :                         else if (ctx->index_alloc_size == ctx->index_size) ctx->index_alloc_size *= 2;
     195          18 :                         ctx->indexes = gf_realloc(ctx->indexes, sizeof(QCPIdx)*ctx->index_alloc_size);
     196          18 :                         ctx->indexes[ctx->index_size].pos = pos;
     197          18 :                         ctx->indexes[ctx->index_size].duration = (Double) duration;
     198          18 :                         ctx->indexes[ctx->index_size].duration /= ctx->sample_rate;
     199          18 :                         ctx->index_size ++;
     200             :                         cur_dur = 0;
     201             :                 }
     202             :         }
     203           1 :         gf_bs_del(bs);
     204           1 :         gf_fclose(stream);
     205             : 
     206           1 :         if (!ctx->duration.num || (ctx->duration.num  * ctx->sample_rate != duration * ctx->duration.den)) {
     207           1 :                 ctx->duration.num = (s32) duration;
     208           1 :                 ctx->duration.den = ctx->sample_rate;
     209             : 
     210           1 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DURATION, & PROP_FRAC64(ctx->duration));
     211           1 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_PLAYBACK_MODE, &PROP_UINT(GF_PLAYBACK_MODE_FASTFORWARD ) );
     212             :         }
     213             : 
     214           1 :         p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_FILE_CACHED);
     215           1 :         if (p && p->value.boolean) ctx->file_loaded = GF_TRUE;
     216           1 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CAN_DATAREF, & PROP_BOOL(GF_TRUE ) );
     217             : }
     218             : 
     219       16286 : static Bool qcpdmx_process_event(GF_Filter *filter, const GF_FilterEvent *evt)
     220             : {
     221             :         u32 i;
     222             :         u64 file_pos = 0;
     223             :         GF_FilterEvent fevt;
     224       16286 :         GF_QCPDmxCtx *ctx = gf_filter_get_udta(filter);
     225             : 
     226       16286 :         switch (evt->base.type) {
     227           7 :         case GF_FEVT_PLAY:
     228           7 :                 if (!ctx->is_playing) {
     229           7 :                         ctx->is_playing = GF_TRUE;
     230           7 :                         ctx->cts = 0;
     231           7 :                         ctx->remaining = 0;
     232             :                 }
     233           7 :                 if (! ctx->is_file) {
     234             :                         return GF_FALSE;
     235             :                 }
     236           1 :                 qcpdmx_check_dur(filter, ctx);
     237             : 
     238           1 :                 ctx->start_range = evt->play.start_range;
     239           1 :                 ctx->in_seek = GF_TRUE;
     240           1 :                 if (ctx->start_range) {
     241           0 :                         for (i=1; i<ctx->index_size; i++) {
     242           0 :                                 if (ctx->indexes[i].duration>ctx->start_range) {
     243           0 :                                         ctx->cts = (u64) (ctx->indexes[i-1].duration * ctx->sample_rate);
     244           0 :                                         file_pos = ctx->indexes[i-1].pos;
     245           0 :                                         break;
     246             :                                 }
     247             :                         }
     248             :                 }
     249           1 :                 if (!ctx->initial_play_done) {
     250           1 :                         ctx->initial_play_done = GF_TRUE;
     251             :                         //seek will not change the current source state, don't send a seek
     252           1 :                         if (!file_pos) {
     253             :                                 return GF_TRUE;
     254             :                         }
     255             :                 }
     256           0 :                 if (!file_pos) {
     257           0 :                         file_pos = ctx->data_chunk_offset;
     258           0 :                         ctx->data_chunk_remain = ctx->data_chunk_size;
     259             :                 }
     260             : 
     261             :                 //post a seek
     262           0 :                 GF_FEVT_INIT(fevt, GF_FEVT_SOURCE_SEEK, ctx->ipid);
     263           0 :                 fevt.seek.start_offset = file_pos;
     264           0 :                 gf_filter_pid_send_event(ctx->ipid, &fevt);
     265             : 
     266             :                 //cancel event
     267           0 :                 return GF_TRUE;
     268             : 
     269           4 :         case GF_FEVT_STOP:
     270           4 :                 ctx->is_playing = GF_FALSE;
     271             :                 //don't cancel event
     272           4 :                 return GF_FALSE;
     273             : 
     274             :         case GF_FEVT_SET_SPEED:
     275             :                 //cancel event
     276             :                 return GF_TRUE;
     277             :         default:
     278             :                 break;
     279             :         }
     280             :         //by default don't cancel event - to rework once we have downloading in place
     281       16275 :         return GF_FALSE;
     282             : }
     283             : 
     284             : /*QCP codec GUIDs*/
     285             : static const char *QCP_QCELP_GUID_1 = "\x41\x6D\x7F\x5E\x15\xB1\xD0\x11\xBA\x91\x00\x80\x5F\xB4\xB9\x7E";
     286             : static const char *QCP_QCELP_GUID_2 = "\x42\x6D\x7F\x5E\x15\xB1\xD0\x11\xBA\x91\x00\x80\x5F\xB4\xB9\x7E";
     287             : static const char *QCP_EVRC_GUID = "\x8D\xD4\x89\xE6\x76\x90\xB5\x46\x91\xEF\x73\x6A\x51\x00\xCE\xB4";
     288             : static const char *QCP_SMV_GUID = "\x75\x2B\x7C\x8D\x97\xA7\x46\xED\x98\x5E\xD5\x3C\x8C\xC7\x5F\x84";
     289             : 
     290           7 : static GF_Err qcpdmx_process_header(GF_Filter *filter, GF_QCPDmxCtx *ctx, char *data, u32 size, GF_BitStream *file_bs)
     291             : {
     292             :         char magic[12], GUID[17], name[81], fmt[162];
     293             :         u32 riff_size, chunk_size, i, avg_bps;
     294             :         Bool has_pad;
     295             :         const GF_PropertyValue *p;
     296             :         GF_BitStream *bs;
     297             : 
     298           7 :         bs = file_bs ? file_bs : gf_bs_new(data, size, GF_BITSTREAM_READ);
     299             : 
     300           7 :         gf_bs_read_data(bs, magic, 4);
     301           7 :         if (strnicmp(magic, "RIFF", 4)) {
     302           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[QCPDmx] Broken file: RIFF header not found\n"));
     303           0 :                 if (!file_bs) gf_bs_del(bs);
     304             :                 return GF_NON_COMPLIANT_BITSTREAM;
     305             :         }
     306           7 :         riff_size = gf_bs_read_u32_le(bs);
     307           7 :         gf_bs_read_data(bs, fmt, 162);
     308           7 :         gf_bs_seek(bs, 8);
     309           7 :         gf_bs_read_data(bs, magic, 4);
     310           7 :         if (strnicmp(magic, "QLCM", 4)) {
     311           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[QCPDmx] Broken file: QLCM header not found\n"));
     312           0 :                 if (!file_bs) gf_bs_del(bs);
     313             :                 return GF_NON_COMPLIANT_BITSTREAM;
     314             :         }
     315           7 :         p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_DOWN_SIZE);
     316           7 :         if (p && p->value.longuint != riff_size+8) {
     317           0 :                 GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[QCPDmx] Broken file:  RIFF-Size %d got %d\n", p->value.uint - 8, riff_size));
     318             :         }
     319             :         /*fmt*/
     320           7 :         gf_bs_read_data(bs, magic, 4);
     321           7 :         if (strnicmp(magic, "fmt ", 4)) {
     322           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[QCPDmx] Broken file: FMT not found\n"));
     323           0 :                 if (!file_bs) gf_bs_del(bs);
     324             :                 return GF_NON_COMPLIANT_BITSTREAM;
     325             :         }
     326           7 :         chunk_size = gf_bs_read_u32_le(bs);
     327           7 :         has_pad = (chunk_size%2) ? GF_TRUE : GF_FALSE;
     328           7 :         /*major = */gf_bs_read_u8(bs);
     329           7 :         /*minor = */gf_bs_read_u8(bs);
     330             :         chunk_size -= 2;
     331             :         /*codec info*/
     332           7 :         gf_bs_read_data(bs, GUID, 16);
     333           7 :         GUID[16]=0;
     334           7 :         /*version = */gf_bs_read_u16_le(bs);
     335             :         chunk_size -= 18;
     336           7 :         gf_bs_read_data(bs, name, 80);
     337           7 :         name[80]=0;
     338             :         chunk_size -= 80;
     339           7 :         avg_bps = gf_bs_read_u16_le(bs);
     340           7 :         ctx->pck_size = gf_bs_read_u16_le(bs);
     341           7 :         ctx->block_size = gf_bs_read_u16_le(bs);
     342           7 :         ctx->sample_rate = gf_bs_read_u16_le(bs);
     343           7 :         /*bps = */gf_bs_read_u16_le(bs);
     344           7 :         ctx->rate_table_count = gf_bs_read_u32_le(bs);
     345             :         chunk_size -= 14;
     346             :         /*skip var rate*/
     347          63 :         for (i=0; i<8; i++) {
     348          56 :                 ctx->rate_table[i].pck_size = gf_bs_read_u8(bs);
     349          56 :                 ctx->rate_table[i].rate_idx = gf_bs_read_u8(bs);
     350             :         }
     351             :         chunk_size -= 16;
     352           7 :         gf_bs_skip_bytes(bs, 5*4);/*reserved*/
     353           7 :         chunk_size -= 20;
     354           7 :         gf_bs_skip_bytes(bs, chunk_size);
     355           7 :         if (has_pad) gf_bs_read_u8(bs);
     356             : 
     357           7 :         if (!strncmp(GUID, QCP_QCELP_GUID_1, 16) || !strncmp(GUID, QCP_QCELP_GUID_2, 16)) {
     358           5 :                 ctx->codecid = GF_CODECID_QCELP;
     359           2 :         } else if (!strncmp(GUID, QCP_EVRC_GUID, 16)) {
     360           2 :                 ctx->codecid = GF_CODECID_EVRC;
     361           0 :         } else if (!strncmp(GUID, QCP_SMV_GUID, 16)) {
     362           0 :                 ctx->codecid = GF_CODECID_SMV;
     363             :         } else {
     364           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[QCPDmx] Unsupported codec GUID %s\n", GUID));
     365           0 :                 if (!file_bs) gf_bs_del(bs);
     366             :                 return GF_NON_COMPLIANT_BITSTREAM;
     367             :         }
     368             :         /*vrat*/
     369           7 :         gf_bs_read_data(bs, magic, 4);
     370           7 :         if (strnicmp(magic, "vrat", 4)) {
     371           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[QCPDmx] Broken file: VRAT not found\n"));
     372           0 :                 if (!file_bs) gf_bs_del(bs);
     373             :                 return GF_NON_COMPLIANT_BITSTREAM;
     374             :         }
     375           7 :         chunk_size = gf_bs_read_u32_le(bs);
     376           7 :         has_pad = (chunk_size%2) ? GF_TRUE : GF_FALSE;
     377           7 :         ctx->vrat_rate_flag = gf_bs_read_u32_le(bs);
     378           7 :         /*size_in_packet =*/gf_bs_read_u32_le(bs);
     379           7 :         chunk_size -= 8;
     380           7 :         gf_bs_skip_bytes(bs, chunk_size);
     381           7 :         if (has_pad) gf_bs_read_u8(bs);
     382             : 
     383           7 :         if (file_bs) return GF_OK;
     384             : 
     385           7 :         gf_bs_del(bs);
     386             : 
     387             : 
     388           7 :         ctx->opid = gf_filter_pid_new(filter);
     389           7 :         gf_filter_pid_copy_properties(ctx->opid, ctx->ipid);
     390           7 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_STREAM_TYPE, & PROP_UINT( GF_STREAM_AUDIO));
     391           7 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_TIMESCALE, & PROP_UINT(ctx->sample_rate));
     392           7 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_SAMPLE_RATE, & PROP_UINT(ctx->sample_rate));
     393           7 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_NUM_CHANNELS, & PROP_UINT(1) );
     394           7 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CODECID, & PROP_UINT(ctx->codecid ) );
     395           7 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_SAMPLES_PER_FRAME, & PROP_UINT(ctx->block_size ) );
     396           7 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_BITRATE, & PROP_UINT(avg_bps));
     397           7 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_FRAME_SIZE, & PROP_UINT(ctx->pck_size));
     398             : 
     399           7 :         qcpdmx_check_dur(filter, ctx);
     400             : 
     401           7 :         return GF_OK;
     402             : 
     403             : }
     404             : 
     405       16290 : GF_Err qcpdmx_process(GF_Filter *filter)
     406             : {
     407       16290 :         GF_QCPDmxCtx *ctx = gf_filter_get_udta(filter);
     408             :         GF_FilterPacket *pck;
     409             :         u64 byte_offset;
     410             :         u8 *data, *output;
     411             :         u8 *start;
     412             :         u32 pck_size, remain;
     413             :         GF_Err e;
     414             :         //update duration
     415       16290 :         qcpdmx_check_dur(filter, ctx);
     416             : 
     417       16290 :         if (ctx->done) return GF_EOS;
     418             : 
     419       16290 :         if (ctx->opid && !ctx->is_playing)
     420             :                 return GF_OK;
     421             : 
     422       16275 :         pck = gf_filter_pid_get_packet(ctx->ipid);
     423       16275 :         if (!pck) {
     424           0 :                 if (gf_filter_pid_is_eos(ctx->ipid)) {
     425           0 :                         if (ctx->opid)
     426           0 :                                 gf_filter_pid_set_eos(ctx->opid);
     427             :                         assert(ctx->remaining == 0);
     428             :                         return GF_EOS;
     429             :                 }
     430             :                 return GF_OK;
     431             :         }
     432             : 
     433       16275 :         data = (char *) gf_filter_pck_get_data(pck, &pck_size);
     434       16275 :         byte_offset = gf_filter_pck_get_byte_offset(pck);
     435             : 
     436             :         start = data;
     437       16275 :         remain = pck_size;
     438             : 
     439             :         //flush not previously dispatched data
     440       16275 :         if (ctx->remaining) {
     441             :                 u32 to_send = ctx->remaining;
     442          28 :                 if (ctx->remaining > pck_size) {
     443             :                         to_send = pck_size;
     444           0 :                         ctx->remaining -= pck_size;
     445             :                 } else {
     446          28 :                         ctx->remaining = 0;
     447             :                 }
     448          28 :                 if (! ctx->in_seek) {
     449          28 :                         GF_FilterPacket *dst_pck = gf_filter_pck_new_alloc(ctx->opid, to_send, &output);
     450          28 :                         if (!dst_pck) return GF_OUT_OF_MEM;
     451          28 :                         memcpy(output, data, to_send);
     452             : 
     453          28 :                         gf_filter_pck_set_cts(dst_pck, ctx->cts);
     454          28 :                         gf_filter_pck_set_sap(dst_pck, GF_FILTER_SAP_1);
     455          28 :                         gf_filter_pck_set_framing(dst_pck, GF_FALSE, ctx->remaining ? GF_FALSE : GF_TRUE);
     456          28 :                         if (byte_offset != GF_FILTER_NO_BO) {
     457          28 :                                 gf_filter_pck_set_byte_offset(dst_pck, byte_offset);
     458             :                         }
     459          28 :                         gf_filter_pck_send(dst_pck);
     460             :                 }
     461             :                 assert (ctx->data_chunk_remain >= to_send);
     462          28 :                 ctx->data_chunk_remain -= to_send;
     463             : 
     464          28 :                 if (ctx->remaining) {
     465           0 :                         gf_filter_pid_drop_packet(ctx->ipid);
     466           0 :                         return GF_OK;
     467             :                 }
     468          28 :                 ctx->cts += ctx->block_size;
     469          28 :                 start += to_send;
     470          28 :                 remain -= to_send;
     471             : 
     472          28 :                 if (!ctx->data_chunk_remain) {
     473           0 :                         ctx->done = GF_TRUE;
     474           0 :                         if (ctx->opid)
     475           0 :                                 gf_filter_pid_set_eos(ctx->opid);
     476             :                         return GF_EOS;
     477             :                 }
     478             :         }
     479             : 
     480       16275 :         if (ctx->resume_from) {
     481       16236 :                 start += ctx->resume_from;
     482       16236 :                 remain -= ctx->resume_from;
     483       16236 :                 ctx->resume_from = 0;
     484             :         }
     485             : 
     486             : 
     487       17471 :         while (remain) {
     488             :                 u32 i, chunk_size=0;
     489             :                 u32 idx = 0;
     490             :                 u32 size = 0;
     491             :                 u64 b_offset;
     492             :                 u8 *pck_data;
     493             :                 Bool has_pad;
     494             : 
     495       17467 :                 if (!ctx->hdr_processed) {
     496           7 :                         if (ctx->buffer_size + remain < 170) {
     497           0 :                                 if (ctx->buffer_alloc < ctx->buffer_size + remain) {
     498           0 :                                         ctx->buffer_alloc = ctx->buffer_size + remain;
     499           0 :                                         ctx->buffer = gf_realloc(ctx->buffer, ctx->buffer_alloc);
     500             :                                 }
     501           0 :                                 memcpy(ctx->buffer + ctx->buffer_size, start, remain);
     502           0 :                                 ctx->buffer_size += remain;
     503           0 :                                 gf_filter_pid_drop_packet(ctx->ipid);
     504           0 :                                 return GF_OK;
     505             :                         }
     506           7 :                         ctx->hdr_processed = GF_TRUE;
     507           7 :                         if (ctx->buffer_size) {
     508           0 :                                 e = qcpdmx_process_header(filter, ctx, ctx->buffer, ctx->buffer_size, NULL);
     509             :                         } else {
     510           7 :                                 e = qcpdmx_process_header(filter, ctx, start, remain, NULL);
     511             :                         }
     512           7 :                         start += 170 - ctx->buffer_size;
     513           7 :                         remain -= 170 - ctx->buffer_size;
     514           7 :                         ctx->buffer_size = 0;
     515             : 
     516           7 :                         if (e) {
     517           0 :                                 gf_filter_setup_failure(filter, e);
     518           0 :                                 ctx->done = GF_TRUE;
     519           0 :                                 gf_filter_pid_drop_packet(ctx->ipid);
     520           0 :                                 return GF_EOS;
     521             :                         }
     522          21 :                         continue;
     523             :                 }
     524             :                 //skip current chunk
     525       17460 :                 if (ctx->skip_bytes) {
     526           7 :                         if (remain<ctx->skip_bytes) {
     527           0 :                                 ctx->skip_bytes -= remain;
     528           0 :                                 gf_filter_pid_drop_packet(ctx->ipid);
     529           0 :                                 return GF_OK;
     530             :                         }
     531           7 :                         start += ctx->skip_bytes;
     532           7 :                         remain -= ctx->skip_bytes;
     533           7 :                         ctx->skip_bytes = 0;
     534             :                 }
     535             : 
     536             :                 //load chunk tag
     537       17460 :                 if (!ctx->data_chunk_remain) {
     538             :                         char magic[4];
     539             :                         //load chunk
     540          14 :                         if (remain<8) {
     541           0 :                                 if (ctx->buffer_alloc < ctx->buffer_size + 8) {
     542           0 :                                         ctx->buffer_alloc = ctx->buffer_size + 8;
     543           0 :                                         ctx->buffer = gf_realloc(ctx->buffer, ctx->buffer_alloc);
     544             :                                 }
     545           0 :                                 memcpy(ctx->buffer + ctx->buffer_size, start, remain);
     546           0 :                                 ctx->buffer_size += remain;
     547           0 :                                 gf_filter_pid_drop_packet(ctx->ipid);
     548           0 :                                 return GF_OK;
     549             :                         }
     550          14 :                         if (!ctx->buffer_size) {
     551          14 :                                 if (!ctx->bs) {
     552           7 :                                         ctx->bs = gf_bs_new((u8 *) start, remain, GF_BITSTREAM_READ);
     553             :                                 } else {
     554           7 :                                         gf_bs_reassign_buffer(ctx->bs, start, remain);
     555             :                                 }
     556             :                         } else {
     557           0 :                                 if (!ctx->bs) {
     558           0 :                                         ctx->bs = gf_bs_new((u8 *) ctx->buffer, ctx->buffer_size, GF_BITSTREAM_READ);
     559             :                                 } else {
     560           0 :                                         gf_bs_reassign_buffer(ctx->bs, ctx->buffer, ctx->buffer_size);
     561             :                                 }
     562             :                         }
     563             : 
     564          14 :                         gf_bs_read_data(ctx->bs, magic, 4);
     565          14 :                         chunk_size = gf_bs_read_u32_le(ctx->bs);
     566          14 :                         has_pad = (chunk_size%2) ? GF_TRUE : GF_FALSE;
     567          14 :                         start += 8-ctx->buffer_size;
     568          14 :                         remain -= 8-ctx->buffer_size;
     569          14 :                         ctx->buffer_size = 0;
     570             : 
     571             :                         //wait until we reach data chunk
     572          14 :                         if (strnicmp(magic, "data", 4)) {
     573           7 :                                 ctx->skip_bytes = chunk_size;
     574           7 :                                 if (has_pad) ctx->skip_bytes++;
     575           7 :                                 continue;
     576             :                         } else {
     577           7 :                                 ctx->data_chunk_size = ctx->data_chunk_remain = chunk_size;
     578             :                         }
     579             :                 }
     580             : 
     581             :                 //we are in the data chunk
     582       17453 :                 if (!ctx->is_playing) {
     583           7 :                         ctx->resume_from = (u32) ( (char *)start -  (char *)data);
     584           7 :                         return GF_OK;
     585             :                 }
     586             : 
     587       17446 :                 b_offset = gf_filter_pck_get_byte_offset(pck);
     588       17446 :                 if (b_offset != GF_FILTER_NO_BO) {
     589       17446 :                         b_offset += (start - (u8 *) data);
     590             :                 }
     591             :                 /*get frame rate idx*/
     592       17446 :                 if (ctx->vrat_rate_flag) {
     593       17446 :                         idx = start[0];
     594             :                         //chunk_size-=1;
     595       33888 :                         for (i=0; i<ctx->rate_table_count; i++) {
     596       33888 :                                 if (ctx->rate_table[i].rate_idx==idx) {
     597       17446 :                                         size = ctx->rate_table[i].pck_size;
     598       17446 :                                         break;
     599             :                                 }
     600             :                         }
     601       17446 :                         size++;
     602             :                 } else {
     603           0 :                         size = ctx->pck_size;
     604             :                 }
     605             : 
     606       17446 :                 if (size > remain) {
     607          32 :                         ctx->remaining = size - remain;
     608             :                         size = remain;
     609             :                 } else {
     610       17414 :                         ctx->remaining = 0;
     611             :                 }
     612             : 
     613       17446 :                 if (ctx->in_seek) {
     614           1 :                         u64 nb_samples_at_seek = (u64) (ctx->start_range * ctx->sample_rate);
     615           1 :                         if (ctx->cts + ctx->block_size >= nb_samples_at_seek) {
     616             :                                 //u32 samples_to_discard = (ctx->cts + ctx->block_size ) - nb_samples_at_seek;
     617           1 :                                 ctx->in_seek = GF_FALSE;
     618             :                         }
     619             :                 }
     620             : 
     621       17446 :                 if (!ctx->in_seek) {
     622       17446 :                         GF_FilterPacket *dst_pck = gf_filter_pck_new_alloc(ctx->opid, size, &pck_data);
     623       17446 :                         if (!dst_pck) return GF_OUT_OF_MEM;
     624       17446 :                         memcpy(pck_data, start, size);
     625             : 
     626       17446 :                         gf_filter_pck_set_framing(dst_pck, GF_TRUE, ctx->remaining ? GF_FALSE : GF_TRUE);
     627       17446 :                         gf_filter_pck_set_cts(dst_pck, ctx->cts);
     628       17446 :                         gf_filter_pck_set_sap(dst_pck, GF_FILTER_SAP_1);
     629       17446 :                         gf_filter_pck_set_duration(dst_pck, ctx->block_size);
     630       17446 :                         if (b_offset != GF_FILTER_NO_BO)
     631       17446 :                                 gf_filter_pck_set_byte_offset(dst_pck, b_offset);
     632             : 
     633       17446 :                         gf_filter_pck_send(dst_pck);
     634             :                 }
     635             : 
     636             :                 assert (ctx->data_chunk_remain >= size);
     637       17446 :                 ctx->data_chunk_remain -= size;
     638       17446 :                 if (!ctx->data_chunk_remain) {
     639           3 :                         ctx->done = GF_TRUE;
     640           3 :                         if (ctx->opid)
     641           3 :                                 gf_filter_pid_set_eos(ctx->opid);
     642          35 :                         break;
     643             :                 }
     644             : 
     645       17443 :                 if (ctx->remaining) break;
     646       17411 :                 ctx->cts += ctx->block_size;
     647       17411 :                 start += size;
     648       17411 :                 remain -= size;
     649             : 
     650             : 
     651             :                 //don't demux too much of input, abort when we would block. This avoid dispatching
     652             :                 //a huge number of frames in a single call
     653       17411 :                 if (gf_filter_pid_would_block(ctx->opid)) {
     654       16229 :                         ctx->resume_from = (u32) ((char *)start -  (char *)data);
     655       16229 :                         return GF_OK;
     656             :                 }
     657             :         }
     658          39 :         gf_filter_pid_drop_packet(ctx->ipid);
     659             : 
     660          39 :         return GF_OK;
     661             : }
     662             : 
     663           7 : static void qcpdmx_finalize(GF_Filter *filter)
     664             : {
     665           7 :         GF_QCPDmxCtx *ctx = gf_filter_get_udta(filter);
     666           7 :         if (ctx->indexes) gf_free(ctx->indexes);
     667           7 :         if (ctx->bs) gf_bs_del(ctx->bs);
     668           7 :         if (ctx->buffer) gf_free(ctx->buffer);
     669           7 : }
     670             : 
     671        3072 : static const char *qcpdmx_probe_data(const u8 *data, u32 size, GF_FilterProbeScore *score)
     672             : {
     673             :         char magic[5];
     674             :         Bool is_qcp = GF_TRUE;
     675        3072 :         GF_BitStream *bs = gf_bs_new(data, size, GF_BITSTREAM_READ);
     676             : 
     677        3072 :         magic[4] = 0;
     678        3072 :         gf_bs_read_data(bs, magic, 4);
     679        3072 :         if (strnicmp(magic, "RIFF", 4)) {
     680             :                 is_qcp = GF_FALSE;
     681             :         } else {
     682          18 :                 /*riff_size = */gf_bs_read_u32_le(bs);
     683          18 :                 gf_bs_read_data(bs, magic, 4);
     684          18 :                 if (strnicmp(magic, "QLCM", 4)) {
     685             :                         is_qcp = GF_FALSE;
     686             :                 }
     687             :         }
     688        3072 :         gf_bs_del(bs);
     689        3072 :         if (!is_qcp) return NULL;
     690           7 :         *score = GF_FPROBE_SUPPORTED;
     691           7 :         return "audio/qcp";
     692             : }
     693             : 
     694             : static const GF_FilterCapability QCPDmxCaps[] =
     695             : {
     696             :         CAP_UINT(GF_CAPS_INPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
     697             :         CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_FILE_EXT, "qcp"),
     698             :         CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_MIME, "audio/qcp"),
     699             :         CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
     700             :         CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_QCELP),
     701             :         CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_SMV),
     702             :         CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_EVRC),
     703             :         CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_EVRC_PV),
     704             :         CAP_BOOL(GF_CAPS_OUTPUT_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
     705             : };
     706             : 
     707             : 
     708             : #define OFFS(_n)        #_n, offsetof(GF_QCPDmxCtx, _n)
     709             : static const GF_FilterArgs QCPDmxArgs[] =
     710             : {
     711             :         { OFFS(index), "indexing window length", GF_PROP_DOUBLE, "1.0", NULL, 0},
     712             :         {0}
     713             : };
     714             : 
     715             : 
     716             : GF_FilterRegister QCPDmxRegister = {
     717             :         .name = "rfqcp",
     718             :         GF_FS_SET_DESCRIPTION("QCP reframer")
     719             :         GF_FS_SET_HELP("This filter parses QCP files/data and outputs corresponding audio PID and frames.")
     720             :         .private_size = sizeof(GF_QCPDmxCtx),
     721             :         .args = QCPDmxArgs,
     722             :         .finalize = qcpdmx_finalize,
     723             :         SETCAPS(QCPDmxCaps),
     724             :         .configure_pid = qcpdmx_configure_pid,
     725             :         .process = qcpdmx_process,
     726             :         .probe_data = qcpdmx_probe_data,
     727             :         .process_event = qcpdmx_process_event
     728             : };
     729             : 
     730             : 
     731        2877 : const GF_FilterRegister *qcpdmx_register(GF_FilterSession *session)
     732             : {
     733        2877 :         return &QCPDmxRegister;
     734             : }
     735             : 

Generated by: LCOV version 1.13