summaryrefslogtreecommitdiffstats
path: root/dec_audio.c
diff options
context:
space:
mode:
authoratmos4 <atmos4@b3059339-0415-0410-9bf9-f77b7e298cf2>2001-09-01 19:44:49 +0000
committeratmos4 <atmos4@b3059339-0415-0410-9bf9-f77b7e298cf2>2001-09-01 19:44:49 +0000
commitaada0e47d273ab4ac42fcd44d01209aa092cf790 (patch)
tree445baeffb0414739c3e1d6a7a812032466f1b126 /dec_audio.c
parent5d0b354e7ad9c55f5e0939a0ef62b036f0b85b2e (diff)
downloadmpv-aada0e47d273ab4ac42fcd44d01209aa092cf790.tar.bz2
mpv-aada0e47d273ab4ac42fcd44d01209aa092cf790.tar.xz
OggVorbis support, ALPHA state!
git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@1829 b3059339-0415-0410-9bf9-f77b7e298cf2
Diffstat (limited to 'dec_audio.c')
-rw-r--r--dec_audio.c232
1 files changed, 231 insertions, 1 deletions
diff --git a/dec_audio.c b/dec_audio.c
index 7a2242ba44..16a3294355 100644
--- a/dec_audio.c
+++ b/dec_audio.c
@@ -37,6 +37,12 @@ int fakemono=0;
#include "loader/DirectShow/DS_AudioDec.h"
#endif
+#ifdef HAVE_OGGVORBIS
+/* XXX is math.h really needed? - atmos */
+#include <math.h>
+#include <vorbis/codec.h>
+#endif
+
extern int init_acm_audio_codec(sh_audio_t *sh_audio);
extern int acm_decode_audio(sh_audio_t *sh_audio, void* a_buffer,int minlen,int maxlen);
@@ -110,7 +116,7 @@ case AFM_DSHOW:
// Win32 DShow audio codec:
// printf("DShow_audio: channs=%d rate=%d\n",sh_audio->channels,sh_audio->samplerate);
if(DS_AudioDecoder_Open(sh_audio->codec->dll,&sh_audio->codec->guid,sh_audio->wf)){
- mp_msg(MSGT_DECAUDIO,MSGL_ERR,"ERROR: Could not load/initialize Win32/DirctShow AUDIO codec: %s\n",sh_audio->codec->dll);
+ mp_msg(MSGT_DECAUDIO,MSGL_ERR,"ERROR: Could not load/initialize Win32/DirectShow AUDIO codec: %s\n",sh_audio->codec->dll);
driver=0;
} else {
sh_audio->i_bps=sh_audio->wf->nAvgBytesPerSec;
@@ -125,6 +131,15 @@ case AFM_DSHOW:
}
#endif
break;
+case AFM_VORBIS:
+#ifndef HAVE_OGGVORBIS
+ mp_msg(MSGT_DECAUDIO,MSGL_ERR,"OggVorbis audio codec disabled -> force nosound :(\n");
+ driver=0;
+#else
+ /* OggVorbis audio via libvorbis, compatible with files created by nandub and zorannt codec */
+ sh_audio->audio_out_minsize=4096;
+#endif
+ break;
case AFM_PCM:
case AFM_DVDPCM:
case AFM_ALAW:
@@ -288,6 +303,126 @@ case AFM_MPEG: {
sh_audio->i_bps=MP3_bitrate*(1000/8);
break;
}
+#ifdef HAVE_OGGVORBIS
+case AFM_VORBIS: {
+ // OggVorbis Audio:
+#if 0 /* just here for reference - atmos */
+ ogg_sync_state oy; /* sync and verify incoming physical bitstream */
+ ogg_stream_state os; /* take physical pages, weld into a logical
+ stream of packets */
+ ogg_page og; /* one Ogg bitstream page. Vorbis packets are inside */
+ ogg_packet op; /* one raw packet of data for decode */
+
+ vorbis_info vi; /* struct that stores all the static vorbis bitstream
+ settings */
+ vorbis_comment vc; /* struct that stores all the bitstream user comments */
+ vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */
+ vorbis_block vb; /* local working space for packet->PCM decode */
+#else
+ /* nix, nada, rien, nothing, nem, nüx */
+#endif
+
+ uint32_t hdrsizes[3];/* stores vorbis header sizes from AVI audio header,
+ maybe use ogg_uint32_t */
+ //int i;
+ int ret;
+ char *buffer;
+ ogg_packet hdr;
+ //ov_struct_t *s=&sh_audio->ov;
+ sh_audio->ov=malloc(sizeof(ov_struct_t));
+ //s=&sh_audio->ov;
+
+ vorbis_info_init(&sh_audio->ov->vi);
+ vorbis_comment_init(&sh_audio->ov->vc);
+
+ printf("OggVorbis: cbsize: %i\n", sh_audio->wf->cbSize);
+ memcpy(hdrsizes, ((unsigned char*)sh_audio->wf)+2*sizeof(WAVEFORMATEX), 3*sizeof(uint32_t));
+ printf("OggVorbis: Read header sizes: initial: %i comment: %i codebook: %i\n", hdrsizes[0], hdrsizes[1], hdrsizes[2]);
+ /*for(i=12; i <= 40; i+=2) { // header bruteforce :)
+ memcpy(hdrsizes, ((unsigned char*)sh_audio->wf)+i, 3*sizeof(uint32_t));
+ printf("OggVorbis: Read header sizes (%i): %ld %ld %ld\n", i, hdrsizes[0], hdrsizes[1], hdrsizes[2]);
+ }*/
+
+ /* read headers */ // FIXME disable sound on errors here, we absolutely need this headers! - atmos
+ hdr.packet=NULL;
+ hdr.b_o_s = 1; /* beginning of stream for first packet */
+ hdr.bytes = hdrsizes[0];
+ hdr.packet = realloc(hdr.packet,hdr.bytes);
+ memcpy(hdr.packet,((unsigned char*)sh_audio->wf)+2*sizeof(WAVEFORMATEX)+3*sizeof(uint32_t),hdr.bytes);
+ if(vorbis_synthesis_headerin(&sh_audio->ov->vi,&sh_audio->ov->vc,&hdr)<0)
+ printf("OggVorbis: initial (identification) header broken!\n");
+ hdr.b_o_s = 0;
+ hdr.bytes = hdrsizes[1];
+ hdr.packet = realloc(hdr.packet,hdr.bytes);
+ memcpy(hdr.packet,((unsigned char*)sh_audio->wf)+2*sizeof(WAVEFORMATEX)+3*sizeof(uint32_t)+hdrsizes[0],hdr.bytes);
+ if(vorbis_synthesis_headerin(&sh_audio->ov->vi,&sh_audio->ov->vc,&hdr)<0)
+ printf("OggVorbis: comment header broken!\n");
+ hdr.bytes = hdrsizes[2];
+ hdr.packet = realloc(hdr.packet,hdr.bytes);
+ memcpy(hdr.packet,((unsigned char*)sh_audio->wf)+2*sizeof(WAVEFORMATEX)+3*sizeof(uint32_t)+hdrsizes[0]+hdrsizes[1],hdr.bytes);
+ if(vorbis_synthesis_headerin(&sh_audio->ov->vi,&sh_audio->ov->vc,&hdr)<0)
+ printf("OggVorbis: codebook header broken!\n");
+ hdr.bytes=0;
+ hdr.packet = realloc(hdr.packet,hdr.bytes); /* free */
+ /* done with the headers */
+
+
+ /* Throw the comments plus a few lines about the bitstream we're
+ decoding */
+ {
+ char **ptr=sh_audio->ov->vc.user_comments;
+ while(*ptr){
+ printf("OggVorbisComment: %s\n",*ptr);
+ ++ptr;
+ }
+ printf("OggVorbis: Bitstream is %d channel, %ldHz, %ldkbit/s %cBR\n",sh_audio->ov->vi.channels,sh_audio->ov->vi.rate,sh_audio->ov->vi.bitrate_nominal/1000, (sh_audio->ov->vi.bitrate_lower!=sh_audio->ov->vi.bitrate_nominal)||(sh_audio->ov->vi.bitrate_upper!=sh_audio->ov->vi.bitrate_nominal)?'V':'C');
+ printf("OggVorbis: Encoded by: %s\n",sh_audio->ov->vc.vendor);
+ }
+ sh_audio->channels=sh_audio->ov->vi.channels;
+ sh_audio->samplerate=sh_audio->ov->vi.rate;
+ sh_audio->i_bps=sh_audio->ov->vi.bitrate_nominal/8;
+
+// printf("[\n");
+ sh_audio->a_buffer_len=sh_audio->audio_out_minsize;///ov->vi.channels;
+// printf("]\n");
+
+ /* OK, got and parsed all three headers. Initialize the Vorbis
+ packet->PCM decoder. */
+ vorbis_synthesis_init(&sh_audio->ov->vd,&sh_audio->ov->vi); /* central decode state */
+ vorbis_block_init(&sh_audio->ov->vd,&sh_audio->ov->vb); /* local state for most of the decode
+ so multiple block decodes can
+ proceed in parallel. We could init
+ multiple vorbis_block structures
+ for vd here */
+ //printf("OggVorbis: synthesis and block init done.\n");
+ ogg_sync_init(&sh_audio->ov->oy); /* Now we can read pages */
+
+ while((ret = ogg_sync_pageout(&sh_audio->ov->oy,&sh_audio->ov->og))!=1) {
+ if(ret == -1)
+ printf("OggVorbis: Pageout: not properly synced, had to skip some bytes.\n");
+ else
+ if(ret == 0) {
+ printf("OggVorbis: Pageout: need more data to verify page, reading more data.\n");
+ /* submit a a_buffer_len block to libvorbis' Ogg layer */
+ buffer=ogg_sync_buffer(&sh_audio->ov->oy,sh_audio->a_buffer_len);
+ ogg_sync_wrote(&sh_audio->ov->oy,demux_read_data(sh_audio->ds,buffer,sh_audio->a_buffer_len));
+ }
+ }
+ printf("OggVorbis: Pageout: successfull.\n");
+ /* commenting out pagein to leave data (hopefully) to the decoder - atmos */
+ //ogg_stream_pagein(&sh_audio->ov->os,&sh_audio->ov->og); /* we can ignore any errors here
+ // as they'll also become apparent
+ // at packetout */
+
+ /* Get the serial number and set up the rest of decode. */
+ /* serialno first; use it to set up a logical stream */
+ ogg_stream_init(&sh_audio->ov->os,ogg_page_serialno(&sh_audio->ov->og));
+
+ printf("OggVorbis: Init OK!\n");
+
+ break;
+}
+#endif
}
if(!sh_audio->channels || !sh_audio->samplerate){
@@ -318,6 +453,101 @@ int decode_audio(sh_audio_t *sh_audio,unsigned char *buf,int minlen,int maxlen){
len=MP3_DecodeFrame(buf,-1);
// len=MP3_DecodeFrame(buf,3);
break;
+ case AFM_VORBIS: { // OggVorbis
+ /* note: good minlen would be 4k or 8k IMHO - atmos */
+ int ret;
+ char *buffer;
+ int bytes;
+ int samples;
+ float **pcm;
+ ogg_int16_t convbuffer[4096];
+ int convsize;
+ minlen=4096; // XXX hack, not neccessarily needed - atmos
+ convsize=minlen/sh_audio->ov->vi.channels;
+ while((ret = ogg_sync_pageout(&sh_audio->ov->oy,&sh_audio->ov->og))!=1) {
+ if(ret == -1)
+ printf("OggVorbis: Pageout: not properly synced, had to skip some bytes.\n");
+ else
+ if(ret == 0) {
+ //printf("OggVorbis: Pageout: need more data to verify page, reading more data.\n");
+ /* submit a minlen k block to libvorbis' Ogg layer */
+ buffer=ogg_sync_buffer(&sh_audio->ov->oy,minlen);
+ bytes=demux_read_data(sh_audio->ds,buffer,minlen);
+ ogg_sync_wrote(&sh_audio->ov->oy,bytes);
+ if(bytes==0)
+ printf("OggVorbis: 0Bytes written, possible End of Stream\n");
+ }
+ }
+ //printf("OggVorbis: Pageout: successfull, pagin in.\n");
+ if(ogg_stream_pagein(&sh_audio->ov->os,&sh_audio->ov->og)<0)
+ printf("OggVorbis: Pagein failed!\n");
+
+ ret=ogg_stream_packetout(&sh_audio->ov->os,&sh_audio->ov->op);
+ if(ret==0)
+ printf("OggVorbis: Packetout: need more data, FIXME!\n");
+ else
+ if(ret<0)
+ printf("OggVorbis: Packetout: missing or corrupt data, skipping packet!\n");
+ else {
+
+ /* we have a packet. Decode it */
+
+ if(vorbis_synthesis(&sh_audio->ov->vb,&sh_audio->ov->op)==0) /* test for success! */
+ vorbis_synthesis_blockin(&sh_audio->ov->vd,&sh_audio->ov->vb);
+
+ /* **pcm is a multichannel float vector. In stereo, for
+ example, pcm[0] is left, and pcm[1] is right. samples is
+ the size of each channel. Convert the float values
+ (-1.<=range<=1.) to whatever PCM format and write it out */
+
+ while((samples=vorbis_synthesis_pcmout(&sh_audio->ov->vd,&pcm))>0){
+ int i,j;
+ int clipflag=0;
+ int bout=(samples<convsize?samples:convsize);
+
+ /* convert floats to 16 bit signed ints (host order) and
+ interleave */
+ for(i=0;i<sh_audio->ov->vi.channels;i++){
+ ogg_int16_t *ptr=convbuffer+i;
+ float *mono=pcm[i];
+ for(j=0;j<bout;j++){
+#if 1
+ int val=mono[j]*32767.f;
+#else /* optional dither */
+ int val=mono[j]*32767.f+drand48()-0.5f;
+#endif
+ /* might as well guard against clipping */
+ if(val>32767){
+ val=32767;
+ clipflag=1;
+ }
+ if(val<-32768){
+ val=-32768;
+ clipflag=1;
+ }
+ *ptr=val;
+ ptr+=sh_audio->ov->vi.channels;
+ }
+ }
+
+ if(clipflag)
+ printf("Clipping in frame %ld\n",(long)(sh_audio->ov->vd.sequence));
+
+ //fwrite(convbuffer,2*sh_audio->ov->vi.channels,bout,stderr); //dump pcm to file for debugging
+ len=2*sh_audio->ov->vi.channels*bout;
+ memcpy(buf,convbuffer,len);
+
+ vorbis_synthesis_read(&sh_audio->ov->vd,bout); /* tell libvorbis how
+ many samples we
+ actually consumed */
+ }
+ if(ogg_page_eos(&sh_audio->ov->og))
+ printf("OggVorbis: End of Stream reached!\n"); // FIXME clearup decoder, notify mplayer - atmos
+
+ } // from else, packetout ok
+
+ break;
+ }
case AFM_PCM: // AVI PCM
len=demux_read_data(sh_audio->ds,buf,minlen);
break;