LCOV - code coverage report
Current view: top level - filters - dec_mad.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 121 157 77.1 %
Date: 2021-04-29 23:48:07 Functions: 5 5 100.0 %

          Line data    Source code
       1             : /*
       2             :  *                      GPAC - Multimedia Framework C SDK
       3             :  *
       4             :  *                      Authors: Jean Le Feuvre
       5             :  *                      Copyright (c) Telecom ParisTech 2005-2021
       6             :  *                                      All rights reserved
       7             :  *
       8             :  *  This file is part of GPAC / MP3 libmad decoder filter
       9             :  *
      10             :  *  GPAC is free software; you can redistribute it and/or modify
      11             :  *  it under the terms of the GNU Lesser General Public License as published by
      12             :  *  the Free Software Foundation; either version 2, or (at your option)
      13             :  *  any later version.
      14             :  *
      15             :  *  GPAC is distributed in the hope that it will be useful,
      16             :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18             :  *  GNU Lesser General Public License for more details.
      19             :  *
      20             :  *  You should have received a copy of the GNU Lesser General Public
      21             :  *  License along with this library; see the file COPYING.  If not, write to
      22             :  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
      23             :  *
      24             :  */
      25             : 
      26             : 
      27             : #include <gpac/filters.h>
      28             : 
      29             : #ifdef GPAC_HAS_MAD
      30             : 
      31             : #include <gpac/constants.h>
      32             : 
      33             : #if defined(_WIN32_WCE) || defined(_WIN64) || defined(__SYMBIAN32__)
      34             : #ifndef FPM_DEFAULT
      35             : #ifdef GPAC_64_BITS
      36             : #define FPM_64BIT
      37             : #else
      38             : #define FPM_DEFAULT
      39             : #endif
      40             : #endif
      41             : #endif
      42             : 
      43             : #include <mad.h>
      44             : 
      45             : #if !defined(__GNUC__)
      46             : # if defined(_WIN32_WCE) || defined (WIN32)
      47             : #  pragma comment(lib, "libmad")
      48             : # endif
      49             : #endif
      50             : 
      51             : 
      52             : typedef struct
      53             : {
      54             :         GF_FilterPid *ipid, *opid;
      55             :         
      56             :         Bool configured;
      57             : 
      58             :         u32 sample_rate, num_samples, num_channels;
      59             :         u32 timescale;
      60             :         u64 last_cts;
      61             : 
      62             :         unsigned char *buffer;
      63             :         u32 len;
      64             : 
      65             :         struct mad_frame frame;
      66             :         struct mad_stream stream;
      67             :         struct mad_synth synth;
      68             : 
      69             :         Bool flush_done;
      70             :         u32 last_pck_dur;
      71             :         s64 delay;
      72             : 
      73             : } GF_MADCtx;
      74             : 
      75          19 : static void maddec_copy_props(GF_MADCtx *ctx)
      76             : {
      77             :         //copy properties at init or reconfig
      78          19 :         gf_filter_pid_copy_properties(ctx->opid, ctx->ipid);
      79          19 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CODECID, &PROP_UINT(GF_CODECID_RAW) );
      80          19 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_AUDIO_FORMAT, &PROP_UINT(GF_AUDIO_FMT_S16) );
      81             : 
      82          19 :         if (ctx->sample_rate)
      83          19 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_SAMPLE_RATE, &PROP_UINT(ctx->sample_rate) );
      84             : 
      85          19 :         if (ctx->num_channels) {
      86          19 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_NUM_CHANNELS, &PROP_UINT(ctx->num_channels) );
      87          19 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CHANNEL_LAYOUT, &PROP_LONGUINT((ctx->num_channels==1) ? GF_AUDIO_CH_FRONT_CENTER : GF_AUDIO_CH_FRONT_LEFT | GF_AUDIO_CH_FRONT_RIGHT) );
      88             :         }
      89             : 
      90          19 :         if (!ctx->delay)
      91          19 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DELAY, NULL);
      92          19 : }
      93             : 
      94          19 : static GF_Err maddec_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
      95             : {
      96             :         const GF_PropertyValue *p;
      97          19 :         GF_MADCtx *ctx = gf_filter_get_udta(filter);
      98             : 
      99          19 :         if (is_remove) {
     100           0 :                 if (ctx->opid) {
     101           0 :                         gf_filter_pid_remove(ctx->opid);
     102           0 :                         ctx->opid = NULL;
     103             :                 }
     104           0 :                 ctx->ipid = NULL;
     105           0 :                 return GF_OK;
     106             :         }
     107          19 :         if (! gf_filter_pid_check_caps(pid))
     108             :                 return GF_NOT_SUPPORTED;
     109             : 
     110             : 
     111          19 :         if (ctx->configured) {
     112           0 :                 p = gf_filter_pid_get_property(pid, GF_PROP_PID_NO_PRIMING);
     113             :                 //no re-prime, skip if same config
     114           0 :                 if (p && p->value.boolean) {
     115           0 :                         p = gf_filter_pid_get_property(pid, GF_PROP_PID_SAMPLE_RATE);
     116           0 :                         u32 sr = p ? p->value.uint : 0;
     117           0 :                         p = gf_filter_pid_get_property(pid, GF_PROP_PID_NUM_CHANNELS);
     118           0 :                         u32 ch = p ? p->value.uint : 0;
     119           0 :                         if ((ctx->sample_rate==sr) && (ctx->num_channels==ch)) {
     120           0 :                                 maddec_copy_props(ctx);
     121           0 :                                 return GF_OK;
     122             :                         }
     123             :                 }
     124             : 
     125           0 :                 mad_stream_finish(&ctx->stream);
     126           0 :                 mad_frame_finish(&ctx->frame);
     127             :                 mad_synth_finish(&ctx->synth);
     128             :         }
     129          19 :         mad_stream_init(&ctx->stream);
     130          19 :         mad_frame_init(&ctx->frame);
     131          19 :         mad_synth_init(&ctx->synth);
     132          19 :         ctx->configured = GF_TRUE;
     133             : 
     134             :         /*we need a frame to init, so use default values*/
     135          19 :         ctx->num_samples = 1152;
     136          19 :         ctx->num_channels = 0;
     137          19 :         ctx->sample_rate = 0;
     138          19 :         ctx->ipid = pid;
     139             : 
     140          19 :         if (!ctx->opid) {
     141          19 :                 ctx->opid = gf_filter_pid_new(filter);
     142             :         }
     143             : 
     144          19 :         p = gf_filter_pid_get_property(pid, GF_PROP_PID_SAMPLE_RATE);
     145          19 :         if (p) ctx->sample_rate = p->value.uint;
     146          19 :         p = gf_filter_pid_get_property(pid, GF_PROP_PID_NUM_CHANNELS);
     147          19 :         if (p) ctx->num_channels = p->value.uint;
     148             : 
     149          19 :         if (!ctx->buffer) {
     150          19 :                 ctx->buffer = (unsigned char*)gf_malloc(sizeof(char) * 2*MAD_BUFFER_MDLEN);
     151             :         }
     152             : 
     153          19 :         gf_filter_set_name(filter, "dec_mad:MAD " MAD_VERSION);
     154          19 :         p = gf_filter_pid_get_property(pid, GF_PROP_PID_DELAY);
     155          19 :         ctx->delay = p ? p->value.longsint : 0;
     156             : 
     157          19 :         gf_filter_pid_set_framing_mode(pid, GF_TRUE);
     158             : 
     159          19 :         maddec_copy_props(ctx);
     160             : 
     161          19 :         return GF_OK;
     162             : }
     163             : 
     164          19 : static void maddec_finalize(GF_Filter *filter)
     165             : {
     166          19 :         GF_MADCtx *ctx = gf_filter_get_udta(filter);
     167             : 
     168          19 :         if (ctx->buffer) gf_free(ctx->buffer);
     169             : 
     170          19 :         if (ctx->configured) {
     171          19 :                 mad_stream_finish(&ctx->stream);
     172          19 :                 mad_frame_finish(&ctx->frame);
     173             :                 mad_synth_finish(&ctx->synth);
     174             :         }
     175          19 : }
     176             : 
     177             : /*from miniMad.c*/
     178             : #define MAD_SCALE(ret, s_chan)  \
     179             :         chan = s_chan;                          \
     180             :         chan += (1L << (MAD_F_FRACBITS - 16));            \
     181             :         if (chan >= MAD_F_ONE)                                       \
     182             :                 chan = MAD_F_ONE - 1;                                   \
     183             :         else if (chan < -MAD_F_ONE)                          \
     184             :                 chan = -MAD_F_ONE;                              \
     185             :         ret = chan >> (MAD_F_FRACBITS + 1 - 16);          \
     186             :  
     187        8483 : static GF_Err maddec_process(GF_Filter *filter)
     188             : {
     189             :         mad_fixed_t *left_ch, *right_ch, chan;
     190             :         u8 *ptr;
     191             :         u8 *data;
     192             :         u32 num, samples_to_trash, in_size; //, outSize=0;
     193        8483 :         GF_MADCtx *ctx = gf_filter_get_udta(filter);
     194             :         GF_FilterPacket *dst_pck;
     195        8483 :         GF_FilterPacket *pck = gf_filter_pid_get_packet(ctx->ipid);
     196             : 
     197        8483 :         if (!pck) {
     198        2704 :                 if (gf_filter_pid_is_eos(ctx->ipid)) {
     199          38 :                         if (ctx->flush_done) {
     200          28 :                                 gf_filter_pid_set_eos(ctx->opid);
     201          28 :                                 return GF_EOS;
     202             :                         }
     203          10 :                         ctx->flush_done = GF_TRUE;
     204          10 :                         memset(ctx->buffer + ctx->len, 0, MAD_BUFFER_GUARD);
     205          10 :                         ctx->len += MAD_BUFFER_GUARD;
     206             :                 } else {
     207             :                         return GF_OK;
     208             :                 }
     209             :         } else {
     210        5779 :                 data = (char *) gf_filter_pck_get_data(pck, &in_size);
     211             : 
     212        5779 :                 if (ctx->len + in_size > 2*MAD_BUFFER_MDLEN) {
     213           0 :                         GF_LOG(GF_LOG_WARNING, GF_LOG_CODEC, ("[MAD] MAD buffer overflow, truncating\n"));
     214           0 :                         in_size = 2*MAD_BUFFER_MDLEN - ctx->len;
     215             :                 }
     216             : 
     217        5779 :                 memcpy(ctx->buffer + ctx->len, data, in_size);
     218        5779 :                 ctx->len += in_size;
     219        5779 :                 ctx->last_pck_dur = gf_filter_pck_get_duration(pck);
     220             :         }
     221             : 
     222        5789 : mad_resync:
     223        5793 :         mad_stream_buffer(&ctx->stream, ctx->buffer, ctx->len);
     224             : 
     225        5793 :         if (mad_frame_decode(&ctx->frame, &ctx->stream) == -1) {
     226          27 :                 if (!pck) return GF_OK;
     227             : 
     228          27 :                 if (ctx->stream.error==MAD_ERROR_BUFLEN) {
     229             :                         if (pck) {
     230          23 :                                 ctx->last_cts = gf_filter_pck_get_cts(pck);
     231          23 :                                 ctx->timescale = gf_filter_pck_get_timescale(pck);
     232          23 :                                 gf_filter_pid_drop_packet(ctx->ipid);
     233             :                         }
     234          23 :                         return GF_OK;
     235             :                 }
     236           4 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[MAD] Decoding failed error %s (%d)\n", mad_stream_errorstr(&ctx->stream), ctx->stream.error ) );
     237           4 :                 if (ctx->len==in_size) {
     238           0 :                         if (pck) gf_filter_pid_drop_packet(ctx->ipid);
     239           0 :                         return GF_NON_COMPLIANT_BITSTREAM;
     240             :                 }
     241             :                 //try resynchro
     242           4 :                 memcpy(ctx->buffer, data, in_size);
     243           4 :                 ctx->len = in_size;
     244           4 :                 goto mad_resync;
     245             :         }
     246             : 
     247        5766 :         mad_synth_frame(&ctx->synth, &ctx->frame);
     248             : 
     249        5766 :         if ((ctx->sample_rate != ctx->synth.pcm.samplerate) || (ctx->num_channels != ctx->synth.pcm.channels) || (ctx->num_samples != ctx->synth.pcm.length)) {
     250          19 :                 ctx->sample_rate = ctx->synth.pcm.samplerate;
     251          19 :                 ctx->num_channels = (u8) ctx->synth.pcm.channels;
     252          19 :                 ctx->num_samples = ctx->synth.pcm.length;
     253             : 
     254          19 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_SAMPLE_RATE, &PROP_UINT(ctx->sample_rate) );
     255          19 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_NUM_CHANNELS, &PROP_UINT(ctx->num_channels) );
     256          19 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CHANNEL_LAYOUT, &PROP_LONGUINT((ctx->num_channels==1) ? GF_AUDIO_CH_FRONT_CENTER : GF_AUDIO_CH_FRONT_LEFT | GF_AUDIO_CH_FRONT_RIGHT) );
     257             :         }
     258             : 
     259        5766 :         if (ctx->stream.next_frame) {
     260        5766 :                 ctx->len = (u32) (&ctx->buffer[ctx->len] - ctx->stream.next_frame);
     261        5766 :                 memmove(ctx->buffer, ctx->stream.next_frame, ctx->len);
     262             :         }
     263             : 
     264        5766 :         num = ctx->synth.pcm.length;
     265             : 
     266             :         samples_to_trash = 0;
     267        5766 :         if (ctx->delay<0) {
     268           0 :                 if ((s64) ctx->last_cts + ctx->delay < 0) {
     269           0 :                         s32 dur = num;
     270           0 :                         if (ctx->timescale != ctx->sample_rate) {
     271           0 :                                 dur *= ctx->sample_rate;
     272           0 :                                 dur /= ctx->timescale;
     273             :                         }
     274           0 :                         if (dur + ctx->delay < 0) {
     275             :                                 num = 0;
     276           0 :                                 ctx->delay += dur;
     277             :                         } else {
     278           0 :                                 samples_to_trash = (u32) -ctx->delay;
     279             :                         }
     280           0 :                         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DELAY, NULL);
     281             :                 } else {
     282           0 :                         ctx->delay = 0;
     283             :                 }
     284             :         }
     285             : 
     286        5766 :         if (!pck && ctx->last_pck_dur) {
     287             :                 u32 dur = ctx->last_pck_dur;
     288          10 :                 if (ctx->timescale != ctx->sample_rate) {
     289           0 :                         dur *= ctx->sample_rate;
     290           0 :                         dur /= ctx->timescale;
     291             :                 }
     292          10 :                 if (dur < num) {
     293             :                         num = dur;
     294             :                 }
     295             :         }
     296             : 
     297        5766 :         left_ch = ctx->synth.pcm.samples[0] + samples_to_trash;
     298        5766 :         right_ch = ctx->synth.pcm.samples[1] + samples_to_trash;
     299             : 
     300        5766 :         dst_pck = gf_filter_pck_new_alloc(ctx->opid, (num - samples_to_trash) * 2 * ctx->num_channels, &ptr);
     301        5766 :         if (!dst_pck) return GF_OUT_OF_MEM;
     302             : 
     303        5766 :         if (pck) {
     304        5756 :                 ctx->last_cts = gf_filter_pck_get_cts(pck);
     305        5756 :                 ctx->timescale = gf_filter_pck_get_timescale(pck);
     306        5756 :                 gf_filter_pck_merge_properties(pck, dst_pck);
     307             : 
     308        5756 :                 gf_filter_pid_drop_packet(ctx->ipid);
     309             :         }
     310        5766 :         gf_filter_pck_set_cts(dst_pck, ctx->last_cts);
     311        5766 :         if (ctx->timescale != ctx->sample_rate) {
     312           0 :                 u64 dur = num * ctx->timescale;
     313           0 :                 dur /= ctx->sample_rate;
     314           0 :                 gf_filter_pck_set_duration(dst_pck, (u32) dur);
     315           0 :                 ctx->last_cts += dur;
     316             :         } else {
     317        5766 :                 gf_filter_pck_set_duration(dst_pck, num);
     318        5766 :                 ctx->last_cts += num;
     319             :         }
     320             : 
     321             : 
     322     3326982 :         while (num-- > samples_to_trash) {
     323             :                 s32 rs;
     324     3321216 :                 MAD_SCALE(rs, (*left_ch++) );
     325             : 
     326     3321216 :                 *ptr = (rs >> 0) & 0xff;
     327     3321216 :                 ptr++;
     328     3321216 :                 *ptr = (rs >> 8) & 0xff;
     329     3321216 :                 ptr++;
     330             :                 //outSize += 2;
     331             : 
     332     3321216 :                 if (ctx->num_channels == 2) {
     333     3321216 :                         MAD_SCALE(rs, (*right_ch++) );
     334     3321216 :                         *ptr = (rs >> 0) & 0xff;
     335     3321216 :                         ptr++;
     336     3321216 :                         *ptr = (rs >> 8) & 0xff;
     337     3321216 :                         ptr++;
     338             :                         //outSize += 2;
     339             :                 }
     340             :         }
     341        5766 :         gf_filter_pck_send(dst_pck);
     342        5766 :         return GF_OK;
     343             : }
     344             : 
     345             : 
     346             : static const GF_FilterCapability MADCaps[] =
     347             : {
     348             :         CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
     349             :         CAP_BOOL(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
     350             :         CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_MPEG2_PART3),
     351             :         CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_MPEG_AUDIO),
     352             :         CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
     353             :         CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_RAW),
     354             : };
     355             : 
     356             : GF_FilterRegister MADRegister = {
     357             :         .name = "maddec",
     358             :         GF_FS_SET_DESCRIPTION("MAD decoder")
     359             :         GF_FS_SET_HELP("This filter decodes MPEG 1/2 audio streams through libmad library.")
     360             :         .private_size = sizeof(GF_MADCtx),
     361             :         .priority = 1,
     362             :         SETCAPS(MADCaps),
     363             :         .finalize = maddec_finalize,
     364             :         .configure_pid = maddec_configure_pid,
     365             :         .process = maddec_process,
     366             : };
     367             : 
     368             : #endif
     369             : 
     370        2877 : const GF_FilterRegister *maddec_register(GF_FilterSession *session)
     371             : {
     372             : #ifdef GPAC_HAS_MAD
     373        2877 :         return &MADRegister;
     374             : #else
     375             :         return NULL;
     376             : #endif
     377             : }
     378             : 

Generated by: LCOV version 1.13