source: roaraudio/roard/codecfilter_vorbis.c @ 3811:49db840fb4f4

Last change on this file since 3811:49db840fb4f4 was 3811:49db840fb4f4, checked in by phi, 14 years ago

fixed some copyright statements

File size: 14.9 KB
RevLine 
[204]1//codecfilter_vorbis.c:
2
[668]3/*
[3811]4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2008-2010
[668]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
[3517]21 *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
22 *  Boston, MA 02110-1301, USA.
[668]23 *
24 */
25
[1185]26#define ROAR_REQUIRE_LIBVORBISFILE
27
[204]28#include "roard.h"
29
[362]30#ifdef ROAR_HAVE_LIBVORBISFILE
31
[2107]32#define FIFAC ((float)((uint64_t)1<<(ROAR_VORBIS_BITS-1)))
33
[741]34int _g_cf_vorbis_vfvio_return_err (void) {
35 return -1;
36}
37
38ov_callbacks _g_cf_vorbis_vfvio = {
39  .read_func  = cf_vorbis_vfvio_read,
[743]40  .seek_func  = (int    (*)(void *, ogg_int64_t, int      )) _g_cf_vorbis_vfvio_return_err,
41  .close_func = (int    (*)(void *                        )) _g_cf_vorbis_vfvio_return_err,
42  .tell_func  = (long   (*)(void *                        )) _g_cf_vorbis_vfvio_return_err
[741]43};
44
45size_t cf_vorbis_vfvio_read (void *ptr, size_t size, size_t nmemb, void *datasource) {
46 ssize_t r;
[746]47
[741]48 r = stream_vio_s_read(ROAR_STREAM_SERVER(datasource), ptr, size*nmemb);
49
[745]50 ROAR_DBG("cf_vorbis_vfvio_read(ptr=%p, size=%lu, nmemb=%lu, datasource=%p): r=%i", ptr, size, nmemb, datasource, r);
[741]51
52 if ( r == -1 )
53  return 0;
54
55 if ( r > 0 )
56  errno = 0;
[744]57
58 r /= size;
[741]59 
[745]60 ROAR_DBG("cf_vorbis_vfvio_read(ptr=%p, size=%lu, nmemb=%lu, datasource=%p) = %i", ptr, size, nmemb, datasource, r);
[744]61 return r;
[741]62}
63
[205]64int cf_vorbis_open(CODECFILTER_USERDATA_T * inst, int codec,
65                                            struct roar_stream_server * info,
66                                            struct roar_codecfilter   * filter) {
67 struct codecfilter_vorbis_inst * self = malloc(sizeof(struct codecfilter_vorbis_inst));
[569]68 struct roar_stream * s = ROAR_STREAM(info);
[205]69
70 if ( !self )
71  return -1;
72
73 self->current_section      = -1;
74 self->last_section         = -1;
[382]75 self->opened               =  0;
76 self->got_it_running       =  0;
[205]77 self->stream               = info;
78// self->outlen               = ROAR_OUTPUT_BUFFER_SAMPLES * s->info.channels * s->info.bits / 8; // optimal size
[569]79#ifdef ROAR_HAVE_LIBVORBISENC
[1226]80 self->encoding               = 0;
81 self->encoder.v_base_quality = 0.3;
[1238]82 self->encoder.srn            = -1;
[569]83#endif
[205]84
[486]85 ROAR_DBG("cf_vorbis_open(*): info->id=%i", ROAR_STREAM(info)->id);
86
[205]87 *inst = (CODECFILTER_USERDATA_T) self;
88
[569]89 s->info.codec = ROAR_CODEC_DEFAULT;
90 s->info.bits  = 16;
91
92 if ( s->dir == ROAR_DIR_PLAY ) {
93  return 0;
[634]94 } else if ( s->dir == ROAR_DIR_MONITOR || s->dir == ROAR_DIR_OUTPUT ) {
[569]95#ifdef ROAR_HAVE_LIBVORBISENC
96  // set up the encoder here
[2087]97// this is delayed to the write function
98/*
[1226]99 if ( cf_vorbis_encode_start(self) == -1 ) {
100  free(self);
101  return -1;
102 }
[2087]103*/
[2107]104 s->info.bits  = ROAR_VORBIS_BITS;
[569]105#else
106 free(self);
107 return -1;
108#endif
109 } else {
110  free(self);
111  return -1;
112 }
[206]113
114 return 0;
[205]115}
116
117int cf_vorbis_close(CODECFILTER_USERDATA_T   inst) {
118 struct codecfilter_vorbis_inst * self = (struct codecfilter_vorbis_inst *) inst;
119
120 if ( !inst )
121  return -1;
122
[382]123 if ( self->got_it_running )
124  ov_clear(&(self->vf));
[205]125
[569]126#ifdef ROAR_HAVE_LIBVORBISENC
127 if ( self->encoding ) {
[1226]128  cf_vorbis_encode_end(self);
[569]129 }
130#endif
131
[205]132 free(inst);
[206]133 return 0;
[205]134}
135
[582]136int cf_vorbis_write(CODECFILTER_USERDATA_T   inst, char * buf, int len) {
137#ifdef ROAR_HAVE_LIBVORBISENC
138 struct codecfilter_vorbis_inst * self = (struct codecfilter_vorbis_inst *) inst;
139 struct roar_stream * s = ROAR_STREAM(self->stream);
140 ogg_packet header;
141 ogg_packet header_comm;
142 ogg_packet header_code;
[586]143 float ** encbuf;
144 int i, c;
145 int chans;
146 int end;
[2816]147 int sid;
148 void * prethrubuf;
[2107]149#if ROAR_VORBIS_BITS == 8
150 int8_t  * data = (int8_t  *) buf;
151#elif ROAR_VORBIS_BITS == 16
[586]152 int16_t * data = (int16_t *) buf;
[2107]153#elif ROAR_VORBIS_BITS == 32
154 int32_t * data = (int32_t *) buf;
155#else
156#error value of ROAR_VORBIS_BITS not supported
157#endif
[582]158
[584]159 if ( ! self->opened ) {
[2087]160  if ( !self->encoding ) {
161   if ( cf_vorbis_encode_start(self) == -1 ) {
162    return -1;
163   }
164  }
165
[2816]166  sid = ROAR_STREAM(self->stream)->id;
167
[582]168  vorbis_analysis_headerout(&(self->encoder.vd), &(self->encoder.vc), &header, &header_comm, &header_code);
169
170  ogg_stream_packetin(&(self->encoder.os), &header);
171  ogg_stream_packetin(&(self->encoder.os), &header_comm);
172  ogg_stream_packetin(&(self->encoder.os), &header_code);
173
[2816]174  stream_prethru_destroy(sid);
175
[582]176  while (ogg_stream_flush(&(self->encoder.os), &(self->encoder.og))) {
[598]177   if ( stream_vio_s_write(self->stream, self->encoder.og.header, self->encoder.og.header_len)
178                                                                 != self->encoder.og.header_len ||
179        stream_vio_s_write(self->stream, self->encoder.og.body,   self->encoder.og.body_len  )
180                                                                 != self->encoder.og.body_len     ) {
[582]181    free(self); // TODO: do we need addional cleanup?
182    return -1;
183   }
[2816]184   // we ignore errors at the moment...
185   if ( stream_prethru_add_data(sid, &prethrubuf, self->encoder.og.header_len + self->encoder.og.body_len) != -1 ) {
186    memcpy(prethrubuf,                               self->encoder.og.header, self->encoder.og.header_len);
187    memcpy(prethrubuf + self->encoder.og.header_len, self->encoder.og.body,   self->encoder.og.body_len  );
188   }
[582]189  }
[584]190  self->opened = 1;
[586]191 } else {
192  encbuf = vorbis_analysis_buffer(&(self->encoder.vd), len /* TODO: need to lookup the menaing of this */);
193  chans  = s->info.channels;
[2107]194  end    = len*8/(ROAR_VORBIS_BITS*chans);
[586]195
196  if ( chans == 1 ) { // use optimized code
197   for (i = 0; i < end; i++)
[2107]198    encbuf[0][i] = data[i]/FIFAC;
[586]199
200  } else if ( chans == 2 ) { // use optimized code
201   for (i = 0; i < end; i++) {
[2107]202    encbuf[0][i] = data[2*i  ]/FIFAC;
203    encbuf[1][i] = data[2*i+1]/FIFAC;
[586]204   }
205  } else { // use generic multi channel code
206   for (i = 0; i < end; i++) {
207    for (c = 0; c < chans; c++) {
[2107]208     encbuf[c][i] = data[chans*i+c]/FIFAC;
[586]209    }
210   }
211  }
[587]212
213  vorbis_analysis_wrote(&(self->encoder.vd), i);
214
[1238]215  if ( cf_vorbis_encode_flushout(self) == -1 )
216   return -1;
[584]217 }
[582]218
219  return len; // we assume every thing was written (at least into our dsp anaylises buffer
220#else
221 errno = ENOSYS;
222 return -1;
223#endif
224}
[205]225int cf_vorbis_read(CODECFILTER_USERDATA_T   inst, char * buf, int len) {
226 struct codecfilter_vorbis_inst * self = (struct codecfilter_vorbis_inst *) inst;
227 long r;
[206]228 long todo = len;
229 long done = 0;
[205]230
[206]231// printf("cf_vorbis_read(inst=%p, buf=%p, len=%i) = ?\n", inst, buf, len);
232
233 self->opened++;
234 if ( self->opened == 16 ) {
[744]235
[206]236  //printf("cf_vorbis_read(*): opening...\n");
[741]237  if ( ov_open_callbacks((void*)self->stream, &(self->vf), NULL, 0, _g_cf_vorbis_vfvio) < 0 ) {
[206]238   return 0;
[205]239  }
[742]240  errno = EAGAIN;
241  return -1;
[205]242 }
[206]243
244 if ( self->opened < 16 ) {
[541]245  errno = EAGAIN;
[206]246  return -1;
247 }
[205]248
[382]249
250 self->got_it_running = 1;
251
[206]252 while (todo) {
253  r = ov_read(&(self->vf), buf+done, todo, 0, 2, 1, &(self->current_section));
[744]254  if ( r == OV_HOLE ) {
[745]255   ROAR_DBG("cf_vorbis_read(*): Hole in stream");
[744]256  } else if ( r < 1 ) {
[206]257   break;
258  } else {
[207]259   if ( self->last_section != self->current_section )
260    if ( cf_vorbis_update_stream(self) == -1 )
261     return 0;
262
263   self->last_section = self->current_section;
[206]264   todo -= r;
265   done += r;
266  }
267 }
[205]268
[744]269//printf("ov_read(*) = %i\n", done);
[206]270
271 if ( done == 0 ) {
[205]272  // do some EOF handling...
[206]273  return 0;
[205]274 } else {
[206]275  return len;
[205]276 }
277}
278
[207]279int cf_vorbis_update_stream (struct codecfilter_vorbis_inst * self) {
[1493]280#ifdef ROAR_SUPPORT_META
[207]281 vorbis_info *vi = ov_info(&(self->vf), -1);
282 char **ptr = ov_comment(&(self->vf), -1)->user_comments;
[716]283 char key[ROAR_META_MAX_NAMELEN] = {0}, value[LIBROAR_BUFFER_MSGDATA] = {0};
[583]284 struct roar_stream * s = ROAR_STREAM(self->stream);
[207]285 int type;
286 int j, h = 0;
[222]287 float rpg_track = 0, rpg_album = 0;
[716]288 int meta_ok;
[207]289
290 s->info.channels = vi->channels;
291 s->info.rate     = vi->rate;
292 s->info.bits     = 16;
293 s->info.codec    = ROAR_CODEC_DEFAULT;
294
295 stream_meta_clear(s->id);
296
297 while(*ptr){
[716]298  meta_ok = 1;
[207]299
[716]300   for (j = 0; (*ptr)[j] != 0 && (*ptr)[j] != '='; j++) {
301    if ( j == ROAR_META_MAX_NAMELEN ) {
302     ROAR_ERR("cf_vorbis_update_stream(*): invalid meta data on stream %i: meta data key too long", s->id);
303     meta_ok = 0;
304     j = 0;
305     break;
306    }
307    key[j] = (*ptr)[j];
308   }
309   key[j] = 0;
[222]310
[716]311   if ( meta_ok ) {
312    for (j++, h = 0; (*ptr)[j] != 0 && (*ptr)[j] != '='; j++) {
313     if ( h == LIBROAR_BUFFER_MSGDATA ) {
314      ROAR_ERR("update_stream(*): invalid meta data on stream %i: meta data value for key '%s' too long", s->id, key);
[717]315      meta_ok = 0;
[716]316      h = 0;
317      break;
318     }
319     value[h++] = (*ptr)[j];
320    }
321    value[h]   = 0;
[222]322   }
323
[716]324   if ( meta_ok ) {
325    type = roar_meta_inttype(key);
326    if ( type != -1 )
327     stream_meta_set(s->id, type, "", value);
328
329    ROAR_DBG("cf_vorbis_update_stream(*): Meta %-16s: %s", key, value);
330
331    if ( strcmp(key, "REPLAYGAIN_TRACK_PEAK") == 0 ) {
332     rpg_track = 1/atof(value);
333/*
334    } else if ( strcmp(key, "REPLAYGAIN_TRACK_GAIN") == 0 ) {
335     rpg_track = powf(10, atof(value)/20);
336*/
337    } else if ( strcmp(key, "REPLAYGAIN_ALBUM_PEAK") == 0 ) {
338     rpg_album = 1/atof(value);
339/*
340    } else if ( strcmp(key, "REPLAYGAIN_ALBUM_GAIN") == 0 ) {
341     rpg_album = powf(10, atof(value)/20);
342*/
343    }
344   }
345
346   ptr++;
[207]347 }
348
[222]349 if ( rpg_album ) {
350  self->stream->mixer.rpg_div = 2718;  // = int(exp(1)*1000)
351  self->stream->mixer.rpg_mul = (float)rpg_album*2718;
352 } else if ( rpg_track ) {
353  self->stream->mixer.rpg_div = 2718;
354  self->stream->mixer.rpg_mul = (float)rpg_track*2718;
355 }
356
[1041]357 stream_meta_finalize(s->id);
[1493]358#endif
[223]359 //printf("RPG: mul=%i, div=%i\n", self->stream->mixer.rpg_mul, self->stream->mixer.rpg_div);
[207]360 return 0;
361}
362
[1226]363int cf_vorbis_encode_start  (struct codecfilter_vorbis_inst * self) {
364#ifdef ROAR_HAVE_LIBVORBISENC
[1238]365 int srn = self->encoder.srn; // this value is allrady inited...
[1493]366#ifdef ROAR_SUPPORT_META
[1238]367 int len = 0;
368 int i;
369 int types[ROAR_META_MAX_PER_STREAM];
[1493]370#endif
[1238]371 int sid = ROAR_STREAM(self->stream)->id;
[2087]372 float v_base_quality = self->encoder.v_base_quality;
[1238]373 char val[LIBROAR_BUFFER_MSGDATA];
374
375  val[LIBROAR_BUFFER_MSGDATA-1] = 0;
376
[1226]377  memset(&(self->encoder), 0, sizeof(self->encoder));
378
379  self->encoding = 1;
[2087]380  self->encoder.srn = srn + 1;
381  self->encoder.v_base_quality = v_base_quality;
[1226]382
383  vorbis_info_init(&(self->encoder.vi));
384  vorbis_comment_init(&(self->encoder.vc));
385  vorbis_comment_add_tag(&(self->encoder.vc), "SERVER", "RoarAudio");
386  vorbis_comment_add_tag(&(self->encoder.vc), "ENCODER", "RoarAudio Vorbis codecfilter");
387
[1493]388#ifdef ROAR_SUPPORT_META
[1238]389  if ( (len = stream_meta_list(sid, types, ROAR_META_MAX_PER_STREAM)) != -1 ) {
390   for (i = 0; i < len; i++) {
391//int stream_meta_get     (int id, int type, char * name, char * val, size_t len);
392    if ( stream_meta_get(sid, types[i], NULL, val, LIBROAR_BUFFER_MSGDATA-1) == 0 )
393     vorbis_comment_add_tag(&(self->encoder.vc), roar_meta_strtype(types[i]), val);
394   }
395  }
[1493]396#endif
[1238]397
[2087]398  ROAR_DBG("cf_vorbis_encode_start(*): q=%f", v_base_quality);
399
[1226]400  if( vorbis_encode_init_vbr(&(self->encoder.vi), (long) ROAR_STREAM(self->stream)->info.channels,
401                                                  (long) ROAR_STREAM(self->stream)->info.rate,
[2087]402                                                  v_base_quality) != 0 ) {
[1226]403   ROAR_ERR("cf_vorbis_encode_start(*): Can not vorbis_encode_init_vbr(*)!");
404   vorbis_info_clear(&(self->encoder.vi)); // TODO: do we need to free vc also?
405   return -1;
406  }
407
408  vorbis_analysis_init(&(self->encoder.vd), &(self->encoder.vi));
409  vorbis_block_init(&(self->encoder.vd), &(self->encoder.vb));
[362]410
[1239]411  ROAR_DBG("cf_vorbis_encode_start(*): srn=%i", self->encoder.srn);
[1226]412                                     //  "RA"<<16 + PID<<8 + Stream ID
[1238]413  ogg_stream_init(&(self->encoder.os),
[1239]414                   (((0x5241 + self->encoder.srn) & 0xffff)<<16) +
415                   ( (getpid()                    & 0x00ff)<< 8) +
416                   (  sid                         & 0x00ff));
[1226]417 return 0;
418#else
419 return -1;
420#endif
421}
422
423int cf_vorbis_encode_end    (struct codecfilter_vorbis_inst * self) {
424#ifdef ROAR_HAVE_LIBVORBISENC
425 if ( self->encoding ) {
[1238]426  // try to flush up to an EOS page...
427  vorbis_analysis_buffer(&(self->encoder.vd), 2*ROAR_MAX_CHANNELS);
428  vorbis_analysis_wrote(&(self->encoder.vd), 0);
429  cf_vorbis_encode_flushout(self);
430
431  // clean up...
[1226]432  ogg_stream_clear(&(self->encoder.os));
433  vorbis_block_clear(&(self->encoder.vb));
434  vorbis_dsp_clear(&(self->encoder.vd));
435  vorbis_info_clear(&(self->encoder.vi));
436  self->opened = 0;
437 }
438
439 return 0;
440#else
441 return -1;
442#endif
443}
444
[1238]445int cf_vorbis_encode_flushout(struct codecfilter_vorbis_inst * self) {
446#ifdef ROAR_HAVE_LIBVORBISENC
447 while ( vorbis_analysis_blockout(&(self->encoder.vd), &(self->encoder.vb)) == 1 ) {
448  vorbis_analysis(&(self->encoder.vb), &(self->encoder.op));
449  vorbis_bitrate_addblock(&(self->encoder.vb));
450
451  while ( vorbis_bitrate_flushpacket(&(self->encoder.vd), &(self->encoder.op)) ) {
452   ogg_stream_packetin(&(self->encoder.os), &(self->encoder.op));
453
454   while( ogg_stream_pageout(&(self->encoder.os), &(self->encoder.og)) ) {
455    if (
456         stream_vio_s_write(self->stream, self->encoder.og.header, self->encoder.og.header_len) == -1 ||
457         stream_vio_s_write(self->stream, self->encoder.og.body,   self->encoder.og.body_len  ) == -1   ) {
458     return -1;
459    }
460   }
461  }
462 }
463
464 return 0;
465#else
466 return -1;
467#endif
468}
469
470int cf_vorbis_ctl(CODECFILTER_USERDATA_T   inst, int cmd, void * data) {
471 struct codecfilter_vorbis_inst * self = (struct codecfilter_vorbis_inst *) inst;
[2084]472 int_least32_t type = cmd & ROAR_STREAM_CTL_TYPEMASK;
473
474 cmd -= type;
[1238]475
476 switch (cmd) {
477  case ROAR_CODECFILTER_CTL2CMD(ROAR_CODECFILTER_CTL_META_UPDATE):
[2084]478    if ( type != ROAR_STREAM_CTL_TYPE_VOID )
479     return -1;
480
[1239]481    ROAR_DBG("cf_vorbis_ctl(*): stoping stream...");
[1238]482    if ( cf_vorbis_encode_end(self) == -1 )
483     return -1;
[1239]484    ROAR_DBG("cf_vorbis_ctl(*): restarting stream...");
[1238]485    if ( cf_vorbis_encode_start(self) == -1 )
486     return -1;
487
488    return 0;
489   break;
[2084]490  case ROAR_CODECFILTER_CTL2CMD(ROAR_CODECFILTER_CTL_SET_Q):
491    if ( type != ROAR_STREAM_CTL_TYPE_FLOAT )
492     return -1;
493
[2087]494    ROAR_DBG("cf_vorbis_ctl(*): setting quality to q=%f", *(float*)data);
495
496    self->encoder.v_base_quality = *(float*)data / 10;
[2084]497
498    if ( self->encoding ) {
499     ROAR_DBG("cf_vorbis_ctl(*): we are allready encoding, restart...");
500     ROAR_DBG("cf_vorbis_ctl(*): stoping stream...");
501     if ( cf_vorbis_encode_end(self) == -1 )
502      return -1;
503     ROAR_DBG("cf_vorbis_ctl(*): restarting stream...");
504     if ( cf_vorbis_encode_start(self) == -1 )
505      return -1;
506    }
507
508    return 0;
509   break;
[1238]510  default:
[2087]511    ROAR_DBG("cf_vorbis_ctl(*): Unknown command: cmd=0x%.8x, type=0x%.8x, pcmd=0x%.8x",
512                    cmd, type, ROAR_CODECFILTER_CTL2CMD(cmd));
[1238]513    return -1;
514 }
515
516 return -1;
517}
518
[1226]519#endif
[204]520//ll
Note: See TracBrowser for help on using the repository browser.