1 /***************************************************************************
2                           audiocodec_ogg.cpp  -  description
3                              -------------------
4     begin                : Thu May 23 2002
5     copyright            : (C) 2002 by mean
6     email                : fixounet@free.fr
7 
8     Strongly inspired by mplayer ogg vorbis decoder
9     (ripp off should be more appropriate)
10 
11     We expect the first packet as extraData. It contains needed info such
12     as frequency/channels etc...
13 
14     How to deal with comment and codebook ?
15     Mmmmm
16 
17  ***************************************************************************/
18 
19 
20 /***************************************************************************
21  *                                                                         *
22  *   This program is free software; you can redistribute it and/or modify  *
23  *   it under the terms of the GNU General Public License as published by  *
24  *   the Free Software Foundation; either version 2 of the License, or     *
25  *   (at your option) any later version.                                   *
26  *                                                                         *
27  ***************************************************************************/
28 #include <vorbis/codec.h>
29 
30 #include "ADM_default.h"
31 #include "ADM_ad_plugin.h"
32 #include "ADM_ad_vorbis.h"
33 #include "ADM_coreUtils.h"
34 #include "ADM_audioXiphUtils.h"
35 
36 
37 /**
38  * \class ADM_vorbis
39  */
40 class ADM_vorbis : public     ADM_Audiocodec
41 {
42     protected:
43         oggVorbis           _context;
44 
45     public:
46                             ADM_vorbis(uint32_t fourcc, WAVHeader *info, uint32_t l, uint8_t *d);
47         virtual             ~ADM_vorbis();
48         virtual    uint8_t run(uint8_t *inptr, uint32_t nbIn, float *outptr, uint32_t *nbOut);
isCompressed(void)49         virtual    uint8_t isCompressed(void) {return 1;}
isDecompressable(void)50         virtual    uint8_t isDecompressable(void) {return 1;}
51         virtual    bool    resetAfterSeek(void) ;
52 };
53 
54 // Supported formats + declare our plugin
55 //*******************************************************
56 static  ad_supportedFormat Formats[]={
57         {WAV_OGG_VORBIS,AD_MEDIUM_QUAL},
58 };
59 DECLARE_AUDIO_DECODER(ADM_vorbis,                        // Class
60             0,0,1,                                                 // Major, minor,patch
61             Formats,                                             // Supported formats
62             "libVorbis decoder plugin for avidemux (c) Mean\n");     // Desc
63 //********************************************************
64 
65 
~ADM_vorbis()66  ADM_vorbis::~ADM_vorbis()
67  {
68     if(_init)
69     {
70         vorbis_block_clear(&(_context.vblock));
71         vorbis_info_clear(&(_context.vinfo));
72     }
73     _init=false;
74  }
75  /**
76   *
77   * @param name
78   * @param pack
79   */
printPacket(const char * name,ogg_packet * pack)80  static void printPacket(const char *name, ogg_packet *pack)
81  {
82      ADM_warning(" sending %s packet of size %d\n",name,pack->bytes);
83      mixDump(pack->packet,pack->bytes);
84  }
85  /**
86   *
87   * @param name
88   * @param error
89   */
printError(const char * name,int error)90  static void printError(const char *name, int error)
91  {
92      ADM_warning(" Error %d when processing %s\n",error,name);
93 
94 #define VERR(x) case x: ADM_warning(#x"\n")     ;break;
95 
96      switch(error)
97      {
98 VERR(OV_EREAD)
99 VERR(OV_EFAULT     )
100 VERR(OV_EIMPL      )
101 VERR(OV_EINVAL     )
102 VERR(OV_ENOTVORBIS )
103 VERR(OV_EBADHEADER )
104 VERR(OV_EVERSION   )
105 VERR(OV_ENOTAUDIO  )
106 VERR(OV_EBADPACKET )
107 VERR(OV_EBADLINK   )
108 VERR(OV_ENOSEEK    )
109 
110          default: ADM_warning("Unknown error\n");
111                   break;
112      }
113 
114  }
115  /**
116   *
117   * @param fcc
118   * @param info
119   * @param extra
120   * @param extraData
121   */
ADM_vorbis(uint32_t fcc,WAVHeader * info,uint32_t extra,uint8_t * extraData)122  ADM_vorbis::ADM_vorbis(uint32_t fcc, WAVHeader *info, uint32_t extra, uint8_t *extraData)
123      : ADM_Audiocodec(fcc,*info)
124  {
125  ogg_packet packet;
126  vorbis_comment comment;
127  oggVorbis *vrbis;
128  uint8_t *hdr,*cmt,*code;
129  uint32_t size_hdr,size_cmt, size_code;
130  uint32_t *ptr;
131  int error;
132 #define MANAGE_ERROR(st,er) {if(er<0) {printError(st,er); return ;}}
133      _init=0;
134      ADM_info("Trying to initialize vorbis codec with %d bytes of header data\n",(int)extra);
135 
136      _init=false;
137     memset(&(_context),0,sizeof(_context));
138 
139     uint8_t *packets[3];
140     int     packetsLen[3];
141 
142     if(!ADMXiph::admExtraData2packets(extraData,extra,packets,packetsLen))
143     {
144         return ;
145     }
146 
147     // init everything
148     vorbis_info_init(&(_context.vinfo));
149     vorbis_comment_init(&(_context.vcomment));
150 
151 
152      // Feed header passed as extraData
153     packet.bytes=packetsLen[0];
154     packet.packet=packets[0];
155     packet.b_o_s=1; // yes, it is a new stream
156     printPacket("1st packet",&packet);
157     error=vorbis_synthesis_headerin(&(_context.vinfo),&comment,&packet);
158     MANAGE_ERROR("1st packet",error);
159     // update some info in header this is the only place to get them
160     // especially frequency.
161 /*
162     info->channels=STRUCT->vinfo.channels;
163     info->frequency=STRUCT->vinfo.rate;
164 */
165     info->byterate=_context.vinfo.bitrate_nominal>>3;
166 
167     if(!info->byterate)
168     {
169         ADM_warning("Mmm, no nominal bitrate...\n");
170         info->byterate=16000;
171     }
172     // now unpack comment
173     packet.bytes=packetsLen[1];
174     packet.packet=packets[1];
175     packet.b_o_s=0; // Not new
176     printPacket("2nd packet",&packet);
177 
178     error=vorbis_synthesis_headerin(&(_context.vinfo),&comment,&packet);
179     MANAGE_ERROR("2nd packet",error);
180 
181     // and codebook
182     packet.bytes=packetsLen[2];
183     packet.packet=packets[2];
184     packet.b_o_s=0; // Not new
185     printPacket("3rd packet",&packet);
186 
187     error=vorbis_synthesis_headerin(&(_context.vinfo),&comment,&packet);
188     MANAGE_ERROR("3rd packet",error);
189 
190     vorbis_comment_clear(&comment);
191     vorbis_synthesis_init(&(_context.vdsp),&(_context.vinfo));
192     vorbis_block_init(&(_context.vdsp),&(_context.vblock));
193     ADM_info("Vorbis init successfull\n");
194     _context.ampscale=1;
195     _init=1;
196   CHANNEL_TYPE *p_ch_type = channelMapping;
197 #define DOIT(y) *(p_ch_type++)=ADM_CH_##y;
198     switch(_context.vinfo.channels)
199     {
200     case 1:
201     case 2:
202     {
203         DOIT(FRONT_LEFT);
204         DOIT(FRONT_RIGHT);
205         break;
206     }
207     default:
208     case 5:
209     {
210         DOIT(FRONT_LEFT);
211         DOIT(FRONT_CENTER);
212         DOIT(FRONT_RIGHT);
213 
214 
215         DOIT(REAR_LEFT);
216         DOIT(REAR_RIGHT);
217         DOIT(LFE);
218         break;
219     }
220     }
221  }
222  /**
223   *
224   * @param inptr
225   * @param nbIn
226   * @param outptr
227   * @param nbOut
228   * @return
229   */
230 
run(uint8_t * inptr,uint32_t nbIn,float * outptr,uint32_t * nbOut)231  uint8_t ADM_vorbis::run(uint8_t *inptr, uint32_t nbIn, float *outptr, uint32_t *nbOut)
232 {
233 ogg_packet packet;
234 float **sample_pcm;
235 int    nb_synth;
236 
237     *nbOut=0;
238     if(!_init) return 0;
239     packet.b_o_s=0;
240     packet.e_o_s=0;
241     packet.bytes=nbIn;
242     packet.packet=inptr;
243         packet.granulepos=-1;
244     if(!vorbis_synthesis(&(_context.vblock),&packet))
245     {
246           vorbis_synthesis_blockin(&(_context.vdsp),&(_context.vblock));
247      }
248      nb_synth=vorbis_synthesis_pcmout(&(_context.vdsp),&sample_pcm);
249      if(nb_synth<0)
250      {
251          printf("error decoding vorbis %d\n",nb_synth);
252         return 0;
253      }
254 
255      for (uint32_t samp = 0; samp < nb_synth; samp++)
256          for (uint8_t chan = 0; chan < _context.vinfo.channels; chan++)
257             *outptr++ = sample_pcm[chan][samp] * _context.ampscale;
258 
259      *nbOut = _context.vinfo.channels * nb_synth;
260 
261     // Puge them
262      vorbis_synthesis_read(&_context.vdsp,nb_synth);
263      //printf("This round : in %d bytes, out %d bytes synthetized:%d\n",nbIn,*nbOut,nb_synth);
264     return 1;
265 
266 }
267 /**
268     \fn resetAfterSeek
269     \brief  Try to flush the buffer
270             unsuccessfully :(
271 
272 */
resetAfterSeek(void)273   bool    ADM_vorbis::resetAfterSeek(void)
274   {
275   float **sample_pcm;
276   ogg_packet packet;
277 
278     ADM_info("Vorbis-Resetting\n");
279     vorbis_synthesis_pcmout(&(_context.vdsp),&sample_pcm);
280     vorbis_synthesis_restart(&(_context.vdsp));
281     return true;
282   }
283 
284 
285