source: roaraudio/roard/codecfilter_vorbis.c @ 717:39021279ac6a

Last change on this file since 717:39021279ac6a was 717:39021279ac6a, checked in by phi, 16 years ago

minor fix

File size: 9.5 KB
Line 
1//codecfilter_vorbis.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2008
5 *
6 *  This file is part of roard a part of RoarAudio,
7 *  a cross-platform sound system for both, home and professional use.
8 *  See README for details.
9 *
10 *  This file is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU General Public License version 3
12 *  as published by the Free Software Foundation.
13 *
14 *  RoarAudio is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU General Public License for more details.
18 *
19 *  You should have received a copy of the GNU General Public License
20 *  along with this software; see the file COPYING.  If not, write to
21 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
22 *
23 */
24
25#include "roard.h"
26
27#ifdef ROAR_HAVE_LIBVORBISFILE
28
29int cf_vorbis_open(CODECFILTER_USERDATA_T * inst, int codec,
30                                            struct roar_stream_server * info,
31                                            struct roar_codecfilter   * filter) {
32 struct codecfilter_vorbis_inst * self = malloc(sizeof(struct codecfilter_vorbis_inst));
33 struct roar_stream * s = ROAR_STREAM(info);
34
35 if ( !self )
36  return -1;
37
38 self->current_section      = -1;
39 self->last_section         = -1;
40 self->opened               =  0;
41 self->got_it_running       =  0;
42 self->stream               = info;
43// self->outlen               = ROAR_OUTPUT_BUFFER_SAMPLES * s->info.channels * s->info.bits / 8; // optimal size
44#ifdef ROAR_HAVE_LIBVORBISENC
45 self->encoding             = 0;
46#endif
47
48 ROAR_DBG("cf_vorbis_open(*): info->id=%i", ROAR_STREAM(info)->id);
49
50 if ( (self->in = fdopen(s->fh, "r")) == NULL ) {
51  free((void*)self);
52  return -1;
53 }
54
55 *inst = (CODECFILTER_USERDATA_T) self;
56
57 s->info.codec = ROAR_CODEC_DEFAULT;
58 s->info.bits  = 16;
59
60 if ( s->dir == ROAR_DIR_PLAY ) {
61  return 0;
62 } else if ( s->dir == ROAR_DIR_MONITOR || s->dir == ROAR_DIR_OUTPUT ) {
63#ifdef ROAR_HAVE_LIBVORBISENC
64  // set up the encoder here
65
66  memset(&(self->encoder), 0, sizeof(self->encoder));
67
68  self->encoding = 1;
69
70  vorbis_info_init(&(self->encoder.vi));
71  vorbis_comment_init(&(self->encoder.vc));
72  vorbis_comment_add_tag(&(self->encoder.vc), "SERVER", "RoarAudio");
73  vorbis_comment_add_tag(&(self->encoder.vc), "ENCODER", "RoarAudio Vorbis codecfilter");
74
75  if( vorbis_encode_init_vbr(&(self->encoder.vi), (long) s->info.channels, (long) s->info.rate,
76                                                  self->encoder.v_base_quality) != 0 ) {
77   ROAR_ERR("cf_vorbis_open(*): Can not vorbis_encode_init_vbr(*)!");
78   vorbis_info_clear(&(self->encoder.vi)); // TODO: do we need to free vc also?
79   free(self);
80   return -1;
81  }
82
83  vorbis_analysis_init(&(self->encoder.vd), &(self->encoder.vi));
84  vorbis_block_init(&(self->encoder.vd), &(self->encoder.vb));
85
86                                     //  "RA"<<16 + PID<<8 + Stream ID
87  ogg_stream_init(&(self->encoder.os), 0x52410000 + ((getpid() & 0xff)<<8) + s->id);
88
89#else
90 free(self);
91 return -1;
92#endif
93 } else {
94  free(self);
95  return -1;
96 }
97
98 return 0;
99}
100
101int cf_vorbis_close(CODECFILTER_USERDATA_T   inst) {
102 struct codecfilter_vorbis_inst * self = (struct codecfilter_vorbis_inst *) inst;
103
104 if ( !inst )
105  return -1;
106
107 if ( self->got_it_running )
108  ov_clear(&(self->vf));
109
110#ifdef ROAR_HAVE_LIBVORBISENC
111 if ( self->encoding ) {
112  ogg_stream_clear(&(self->encoder.os));
113  vorbis_block_clear(&(self->encoder.vb));
114  vorbis_dsp_clear(&(self->encoder.vd));
115  vorbis_info_clear(&(self->encoder.vi));
116 }
117#endif
118
119 free(inst);
120 return 0;
121}
122
123int cf_vorbis_write(CODECFILTER_USERDATA_T   inst, char * buf, int len) {
124#ifdef ROAR_HAVE_LIBVORBISENC
125 struct codecfilter_vorbis_inst * self = (struct codecfilter_vorbis_inst *) inst;
126 struct roar_stream * s = ROAR_STREAM(self->stream);
127 ogg_packet header;
128 ogg_packet header_comm;
129 ogg_packet header_code;
130 float ** encbuf;
131 int i, c;
132 int chans;
133 int end;
134 int16_t * data = (int16_t *) buf;
135
136 if ( ! self->opened ) {
137  vorbis_analysis_headerout(&(self->encoder.vd), &(self->encoder.vc), &header, &header_comm, &header_code);
138
139  ogg_stream_packetin(&(self->encoder.os), &header);
140  ogg_stream_packetin(&(self->encoder.os), &header_comm);
141  ogg_stream_packetin(&(self->encoder.os), &header_code);
142
143  while (ogg_stream_flush(&(self->encoder.os), &(self->encoder.og))) {
144   if ( stream_vio_s_write(self->stream, self->encoder.og.header, self->encoder.og.header_len)
145                                                                 != self->encoder.og.header_len ||
146        stream_vio_s_write(self->stream, self->encoder.og.body,   self->encoder.og.body_len  )
147                                                                 != self->encoder.og.body_len     ) {
148    free(self); // TODO: do we need addional cleanup?
149    return -1;
150   }
151  }
152  self->opened = 1;
153 } else {
154  encbuf = vorbis_analysis_buffer(&(self->encoder.vd), len /* TODO: need to lookup the menaing of this */);
155  chans  = s->info.channels;
156  end    = len/(2*chans);
157
158  if ( chans == 1 ) { // use optimized code
159   for (i = 0; i < end; i++)
160    encbuf[0][i] = data[i]/32768.0;
161
162  } else if ( chans == 2 ) { // use optimized code
163   for (i = 0; i < end; i++) {
164    encbuf[0][i] = data[2*i  ]/32768.0;
165    encbuf[1][i] = data[2*i+1]/32768.0;
166   }
167  } else { // use generic multi channel code
168   for (i = 0; i < end; i++) {
169    for (c = 0; c < chans; c++) {
170     encbuf[c][i] = data[chans*i+c]/32768.0;
171    }
172   }
173  }
174
175  vorbis_analysis_wrote(&(self->encoder.vd), i);
176
177  while ( vorbis_analysis_blockout(&(self->encoder.vd), &(self->encoder.vb)) == 1 ) {
178   vorbis_analysis(&(self->encoder.vb), &(self->encoder.op));
179   vorbis_bitrate_addblock(&(self->encoder.vb));
180
181   while ( vorbis_bitrate_flushpacket(&(self->encoder.vd), &(self->encoder.op)) ) {
182    ogg_stream_packetin(&(self->encoder.os), &(self->encoder.op));
183
184    while( ogg_stream_pageout(&(self->encoder.os), &(self->encoder.og)) ) {
185     if (
186          stream_vio_s_write(self->stream, self->encoder.og.header, self->encoder.og.header_len) == -1 ||
187          stream_vio_s_write(self->stream, self->encoder.og.body,   self->encoder.og.body_len  ) == -1   ) {
188      return -1;
189     }
190    }
191   }
192  }
193 }
194
195  return len; // we assume every thing was written (at least into our dsp anaylises buffer
196#else
197 errno = ENOSYS;
198 return -1;
199#endif
200}
201int cf_vorbis_read(CODECFILTER_USERDATA_T   inst, char * buf, int len) {
202 struct codecfilter_vorbis_inst * self = (struct codecfilter_vorbis_inst *) inst;
203 long r;
204 long todo = len;
205 long done = 0;
206
207// printf("cf_vorbis_read(inst=%p, buf=%p, len=%i) = ?\n", inst, buf, len);
208
209 self->opened++;
210 if ( self->opened == 16 ) {
211  //printf("cf_vorbis_read(*): opening...\n");
212  if ( ov_open(self->in, &(self->vf), NULL, 0) < 0 ) {
213//   free((void*)self);
214   return 0;
215  }
216 }
217
218 if ( self->opened < 16 ) {
219  errno = EAGAIN;
220  return -1;
221 }
222
223
224 self->got_it_running = 1;
225
226 while (todo) {
227  r = ov_read(&(self->vf), buf+done, todo, 0, 2, 1, &(self->current_section));
228  if ( r < 1 ) {
229   break;
230  } else {
231   if ( self->last_section != self->current_section )
232    if ( cf_vorbis_update_stream(self) == -1 )
233     return 0;
234
235   self->last_section = self->current_section;
236   todo -= r;
237   done += r;
238  }
239 }
240
241 //printf("ov_read(*) = %i\n", done);
242
243 if ( done == 0 ) {
244  // do some EOF handling...
245  return 0;
246 } else {
247  return len;
248 }
249}
250
251int cf_vorbis_update_stream (struct codecfilter_vorbis_inst * self) {
252 vorbis_info *vi = ov_info(&(self->vf), -1);
253 char **ptr = ov_comment(&(self->vf), -1)->user_comments;
254 char key[ROAR_META_MAX_NAMELEN] = {0}, value[LIBROAR_BUFFER_MSGDATA] = {0};
255 struct roar_stream * s = ROAR_STREAM(self->stream);
256 int type;
257 int j, h = 0;
258 float rpg_track = 0, rpg_album = 0;
259 int meta_ok;
260
261 s->info.channels = vi->channels;
262 s->info.rate     = vi->rate;
263 s->info.bits     = 16;
264 s->info.codec    = ROAR_CODEC_DEFAULT;
265
266 stream_meta_clear(s->id);
267
268 while(*ptr){
269  meta_ok = 1;
270
271   for (j = 0; (*ptr)[j] != 0 && (*ptr)[j] != '='; j++) {
272    if ( j == ROAR_META_MAX_NAMELEN ) {
273     ROAR_ERR("cf_vorbis_update_stream(*): invalid meta data on stream %i: meta data key too long", s->id);
274     meta_ok = 0;
275     j = 0;
276     break;
277    }
278    key[j] = (*ptr)[j];
279   }
280   key[j] = 0;
281
282   if ( meta_ok ) {
283    for (j++, h = 0; (*ptr)[j] != 0 && (*ptr)[j] != '='; j++) {
284     if ( h == LIBROAR_BUFFER_MSGDATA ) {
285      ROAR_ERR("update_stream(*): invalid meta data on stream %i: meta data value for key '%s' too long", s->id, key);
286      meta_ok = 0;
287      h = 0;
288      break;
289     }
290     value[h++] = (*ptr)[j];
291    }
292    value[h]   = 0;
293   }
294
295   if ( meta_ok ) {
296    type = roar_meta_inttype(key);
297    if ( type != -1 )
298     stream_meta_set(s->id, type, "", value);
299
300    ROAR_DBG("cf_vorbis_update_stream(*): Meta %-16s: %s", key, value);
301
302    if ( strcmp(key, "REPLAYGAIN_TRACK_PEAK") == 0 ) {
303     rpg_track = 1/atof(value);
304/*
305    } else if ( strcmp(key, "REPLAYGAIN_TRACK_GAIN") == 0 ) {
306     rpg_track = powf(10, atof(value)/20);
307*/
308    } else if ( strcmp(key, "REPLAYGAIN_ALBUM_PEAK") == 0 ) {
309     rpg_album = 1/atof(value);
310/*
311    } else if ( strcmp(key, "REPLAYGAIN_ALBUM_GAIN") == 0 ) {
312     rpg_album = powf(10, atof(value)/20);
313*/
314    }
315   }
316
317   ptr++;
318 }
319
320 if ( rpg_album ) {
321  self->stream->mixer.rpg_div = 2718;  // = int(exp(1)*1000)
322  self->stream->mixer.rpg_mul = (float)rpg_album*2718;
323 } else if ( rpg_track ) {
324  self->stream->mixer.rpg_div = 2718;
325  self->stream->mixer.rpg_mul = (float)rpg_track*2718;
326 }
327
328 //printf("RPG: mul=%i, div=%i\n", self->stream->mixer.rpg_mul, self->stream->mixer.rpg_div);
329 return 0;
330}
331
332#endif
333
334//ll
Note: See TracBrowser for help on using the repository browser.