LCOV - code coverage report
Current view: top level - filters - dec_vorbis.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 106 127 83.5 %
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 2000-2021
       6             :  *                                      All rights reserved
       7             :  *
       8             :  *  This file is part of GPAC / XIPH Vorbis 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             : #include <gpac/constants.h>
      29             : #include <gpac/bitstream.h>
      30             : 
      31             : #ifdef GPAC_HAS_VORBIS
      32             : 
      33             : #include <vorbis/codec.h>
      34             : 
      35             : #if !defined(__GNUC__)
      36             : # if defined(_WIN32_WCE) || defined (WIN32)
      37             : #  pragma comment(lib, "libvorbis_static")
      38             : # endif
      39             : #endif
      40             : 
      41             : typedef struct
      42             : {
      43             :         GF_FilterPid *ipid, *opid;
      44             :         u32 cfg_crc, sample_rate, nb_chan, timescale;
      45             :         u64 last_cts;
      46             : 
      47             :         vorbis_info vi;
      48             :         vorbis_dsp_state vd;
      49             :         vorbis_block vb;
      50             :         vorbis_comment vc;
      51             :         ogg_packet op;
      52             : 
      53             :         Bool has_reconfigured;
      54             : } GF_VorbisDecCtx;
      55             : 
      56           1 : static GF_Err vorbisdec_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
      57             : {
      58             :         const GF_PropertyValue *p;
      59             :         ogg_packet oggpacket;
      60             :         GF_BitStream *bs;
      61           1 :         GF_VorbisDecCtx *ctx = gf_filter_get_udta(filter);
      62             : 
      63             : 
      64           1 :         if (is_remove) {
      65           0 :                 if (ctx->opid) {
      66           0 :                         gf_filter_pid_remove(ctx->opid);
      67           0 :                         ctx->opid = NULL;
      68             :                 }
      69           0 :                 ctx->ipid = NULL;
      70           0 :                 return GF_OK;
      71             :         }
      72           1 :         if (! gf_filter_pid_check_caps(pid))
      73             :                 return GF_NOT_SUPPORTED;
      74             : 
      75           1 :         p = gf_filter_pid_get_property(pid, GF_PROP_PID_DECODER_CONFIG);
      76           1 :         if (p && p->value.data.ptr && p->value.data.size) {
      77             :                 u32 ex_crc;
      78           1 :                 if (strncmp(&p->value.data.ptr[3], "vorbis", 6)) return GF_NON_COMPLIANT_BITSTREAM;
      79           1 :                 ex_crc = gf_crc_32(p->value.data.ptr, p->value.data.size);
      80           1 :                 if (ctx->cfg_crc == ex_crc) return GF_OK;
      81           1 :                 ctx->cfg_crc = ex_crc;
      82             :         } else {
      83           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[XVID] Reconfiguring without DSI not yet supported\n"));
      84             :                 return GF_NOT_SUPPORTED;
      85             :         }
      86           1 :         if (!ctx->opid) {
      87           1 :                 ctx->opid = gf_filter_pid_new(filter);
      88             :         }
      89             : 
      90             :         //copy properties at init or reconfig
      91           1 :         gf_filter_pid_copy_properties(ctx->opid, pid);
      92           1 :         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CODECID, &PROP_UINT(GF_CODECID_RAW) );
      93             : 
      94           1 :         if (ctx->ipid) {
      95           0 :                 vorbis_block_clear(&ctx->vb);
      96           0 :                 vorbis_dsp_clear(&ctx->vd);
      97           0 :                 vorbis_info_clear(&ctx->vi);
      98           0 :                 vorbis_comment_clear(&ctx->vc);
      99             :         }
     100           1 :         ctx->ipid = pid;
     101           1 :         gf_filter_pid_set_framing_mode(ctx->ipid, GF_TRUE);
     102             : 
     103           1 :         vorbis_info_init(&ctx->vi);
     104           1 :         vorbis_comment_init(&ctx->vc);
     105             : 
     106           1 :         oggpacket.granulepos = -1;
     107           1 :         oggpacket.b_o_s = 1;
     108           1 :         oggpacket.e_o_s = 0;
     109           1 :         oggpacket.packetno = 0;
     110             : 
     111           1 :         bs = gf_bs_new(p->value.data.ptr, p->value.data.size, GF_BITSTREAM_READ);
     112           1 :         while (gf_bs_available(bs)) {
     113             :                 GF_Err e = GF_OK;
     114           3 :                 oggpacket.bytes = gf_bs_read_u16(bs);
     115           3 :                 oggpacket.packet = gf_malloc(sizeof(char) * oggpacket.bytes);
     116           3 :                 gf_bs_read_data(bs, oggpacket.packet, oggpacket.bytes);
     117           3 :                 if (vorbis_synthesis_headerin(&ctx->vi, &ctx->vc, &oggpacket) < 0 ) {
     118             :                         e = GF_NON_COMPLIANT_BITSTREAM;
     119             :                 }
     120           3 :                 gf_free(oggpacket.packet);
     121           3 :                 if (e) {
     122           0 :                         gf_bs_del(bs);
     123           0 :                         return e;
     124             :                 }
     125             :         }
     126           1 :         vorbis_synthesis_init(&ctx->vd, &ctx->vi);
     127           1 :         vorbis_block_init(&ctx->vd, &ctx->vb);
     128           1 :         gf_bs_del(bs);
     129             : 
     130           1 :         return GF_OK;
     131             : }
     132             : 
     133          19 : static GFINLINE void vorbis_to_intern(u32 samples, Float **pcm, char *buf, u32 channels)
     134             : {
     135             :         u32 i, j;
     136             :         s32 val;
     137             :         ogg_int16_t *data = (ogg_int16_t*)buf ;
     138             : 
     139          38 :         for (i=0 ; i<channels ; i++) {
     140             :                 Float *mono;
     141             :                 ogg_int16_t *ptr;
     142          19 :                 ptr = &data[i];
     143          19 :                 if (!ptr) break;
     144             :                 
     145          19 :                 if (channels>2) {
     146             :                         /*center is third in gpac*/
     147           0 :                         if (i==1) ptr = &data[2];
     148             :                         /*right is 2nd in gpac*/
     149           0 :                         else if (i==2) ptr = &data[1];
     150             :                         /*LFE is 4th in gpac*/
     151           0 :                         if ((channels==6) && (i>3)) {
     152           0 :                                 if (i==6) ptr = &data[4];   /*LFE*/
     153           0 :                                 else ptr = &data[i+1];      /*back l/r*/
     154             :                         }
     155             :                 }
     156             : 
     157          19 :                 mono = pcm[i];
     158       18131 :                 for (j=0; j<samples; j++) {
     159       18112 :                         val = (s32) (mono[j] * 32767.f);
     160       18112 :                         if (val > 32767) val = 32767;
     161       18112 :                         if (val < -32768) val = -32768;
     162       18112 :                         (*ptr) = val;
     163       18112 :                         ptr += channels;
     164             :                 }
     165             :         }
     166          19 : }
     167             : 
     168          21 : static GF_Err vorbisdec_process(GF_Filter *filter)
     169             : {
     170             :         ogg_packet op;
     171          21 :         u8 *buffer=NULL;
     172             :         Float **pcm;
     173             :         u32 samples, total_samples, total_bytes, size;
     174          21 :         GF_VorbisDecCtx *ctx = gf_filter_get_udta(filter);
     175             :         GF_FilterPacket *pck, *dst_pck=NULL;
     176             : 
     177          21 :         pck = gf_filter_pid_get_packet(ctx->ipid);
     178          21 :         if (!pck) {
     179           1 :                 if (!gf_filter_pid_is_eos(ctx->ipid)) {
     180             :                         return GF_OK;
     181             :                 }
     182             :         }
     183          21 :         op.granulepos = -1;
     184          21 :         op.b_o_s = 0;
     185          21 :         op.e_o_s = 0;
     186          21 :         op.packetno = 0;
     187             : 
     188          21 :         if (pck) {
     189             :                 u32 psize;
     190          20 :                 op.packet = (u8 *) gf_filter_pck_get_data(pck, &psize);
     191          20 :                 op.bytes = psize;
     192             :         } else {
     193           1 :                 op.packet = NULL;
     194           1 :                 op.bytes = 0;
     195             :         }
     196             : 
     197          21 :         if (vorbis_synthesis(&ctx->vb, &op) == 0)
     198          20 :                 vorbis_synthesis_blockin(&ctx->vd, &ctx->vb) ;
     199             : 
     200          21 :         if ( (ctx->vi.channels != ctx->nb_chan) || (ctx->vi.rate != ctx->sample_rate) ) {
     201             :                 u64 chan_mask = 0;
     202           1 :                 ctx->nb_chan = ctx->vi.channels;
     203           1 :                 ctx->sample_rate = ctx->vi.rate;
     204           1 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_SAMPLE_RATE, &PROP_UINT(ctx->sample_rate) );
     205           1 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_NUM_CHANNELS, &PROP_UINT(ctx->nb_chan) );
     206           1 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_AUDIO_FORMAT, &PROP_UINT(GF_AUDIO_FMT_S16) );
     207             : 
     208           1 :                 switch (ctx->vi.channels) {
     209             :                 case 1:
     210             :                         chan_mask = GF_AUDIO_CH_FRONT_CENTER;
     211             :                         break;
     212             :                 case 2:
     213             :                         chan_mask = GF_AUDIO_CH_FRONT_LEFT | GF_AUDIO_CH_FRONT_RIGHT;
     214             :                         break;
     215             :                 case 3:
     216             :                         chan_mask = GF_AUDIO_CH_FRONT_LEFT | GF_AUDIO_CH_FRONT_RIGHT | GF_AUDIO_CH_FRONT_CENTER;
     217             :                         break;
     218             :                 case 4:
     219             :                         chan_mask = GF_AUDIO_CH_FRONT_LEFT | GF_AUDIO_CH_FRONT_RIGHT | GF_AUDIO_CH_SURROUND_LEFT | GF_AUDIO_CH_SURROUND_RIGHT;
     220             :                         break;
     221             :                 case 5:
     222             :                         chan_mask = GF_AUDIO_CH_FRONT_LEFT | GF_AUDIO_CH_FRONT_RIGHT | GF_AUDIO_CH_FRONT_CENTER | GF_AUDIO_CH_SURROUND_LEFT | GF_AUDIO_CH_SURROUND_RIGHT;
     223             :                         break;
     224             :                 case 6:
     225             :                         chan_mask = GF_AUDIO_CH_FRONT_LEFT | GF_AUDIO_CH_FRONT_RIGHT | GF_AUDIO_CH_FRONT_CENTER | GF_AUDIO_CH_SURROUND_LEFT | GF_AUDIO_CH_SURROUND_RIGHT | GF_AUDIO_CH_LFE;
     226             :                         break;
     227             :                 }
     228           1 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CHANNEL_LAYOUT, &PROP_LONGUINT(chan_mask) );
     229             : 
     230             :         }
     231          21 :         size = (ctx->vd.pcm_current - ctx->vd.pcm_returned) * 2 * ctx->vi.channels;
     232          21 :         if (size) {
     233          19 :                 dst_pck = gf_filter_pck_new_alloc(ctx->opid, size, &buffer);
     234          19 :                 if (!dst_pck) return GF_OUT_OF_MEM;
     235             :         }
     236             : 
     237          21 :         if (pck && dst_pck) gf_filter_pck_merge_properties(pck, dst_pck);
     238             : 
     239             :         /*trust vorbis max block info*/
     240             :         total_samples = 0;
     241             :         total_bytes = 0;
     242          40 :         while ((samples = vorbis_synthesis_pcmout(&ctx->vd, &pcm)) > 0) {
     243          19 :                 vorbis_to_intern(samples, pcm, (char*) buffer + total_bytes, ctx->vi.channels);
     244          19 :                 total_bytes += samples * 2 * ctx->vi.channels;
     245          19 :                 total_samples += samples;
     246          19 :                 vorbis_synthesis_read(&ctx->vd, samples);
     247             :         }
     248          21 :         if (!size) {
     249           2 :                 if (pck) return GF_OK;
     250           1 :                 gf_filter_pid_set_eos(ctx->opid);
     251           1 :                 return GF_EOS;
     252             :         }
     253             : 
     254          19 :         if (pck) {
     255          19 :                 ctx->last_cts = gf_filter_pck_get_cts(pck);
     256          19 :                 ctx->timescale = gf_filter_pck_get_timescale(pck);
     257          19 :                 gf_filter_pid_drop_packet(ctx->ipid);
     258             :         }
     259          19 :         gf_filter_pck_set_cts(dst_pck, ctx->last_cts);
     260             : 
     261          19 :         if (ctx->timescale != ctx->sample_rate) {
     262           0 :                 u64 dur = total_samples * ctx->timescale;
     263           0 :                 dur /= ctx->sample_rate;
     264           0 :                 gf_filter_pck_set_duration(dst_pck, (u32) dur);
     265           0 :                 ctx->last_cts += dur;
     266             :         } else {
     267          19 :                 gf_filter_pck_set_duration(dst_pck, total_samples);
     268          19 :                 ctx->last_cts += total_samples;
     269             :         }
     270             : 
     271             :         assert(size == total_bytes);
     272          19 :         gf_filter_pck_send(dst_pck);
     273          19 :         return GF_OK;
     274             : }
     275             : 
     276           1 : static void vorbisdec_finalize(GF_Filter *filter)
     277             : {
     278           1 :         GF_VorbisDecCtx *ctx = gf_filter_get_udta(filter);
     279             : 
     280           1 :         vorbis_block_clear(&ctx->vb);
     281           1 :         vorbis_dsp_clear(&ctx->vd);
     282           1 :         vorbis_info_clear(&ctx->vi);
     283           1 :         vorbis_comment_clear(&ctx->vc);
     284           1 : }
     285             : 
     286             : static const GF_FilterCapability VorbisDecCaps[] =
     287             : {
     288             :         CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
     289             :         CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_VORBIS),
     290             :         CAP_BOOL(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
     291             :         CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
     292             :         CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_RAW),
     293             : };
     294             : 
     295             : GF_FilterRegister VorbisDecRegister = {
     296             :         .name = "vorbisdec",
     297             :         GF_FS_SET_DESCRIPTION("Vorbis decoder")
     298             :         GF_FS_SET_HELP("This filter decodes Vorbis streams through libvorbis library.")
     299             :         .private_size = sizeof(GF_VorbisDecCtx),
     300             :         .priority = 1,
     301             :         SETCAPS(VorbisDecCaps),
     302             :         .finalize = vorbisdec_finalize,
     303             :         .configure_pid = vorbisdec_configure_pid,
     304             :         .process = vorbisdec_process,
     305             : };
     306             : 
     307             : #endif
     308             : 
     309        2877 : const GF_FilterRegister *vorbisdec_register(GF_FilterSession *session)
     310             : {
     311             : #ifdef GPAC_HAS_VORBIS
     312        2877 :         return &VorbisDecRegister;
     313             : #else
     314             :         return NULL;
     315             : #endif
     316             : }
     317             : 
     318             : 

Generated by: LCOV version 1.13