changeset 1828:60afe3421c04

OggVorbis support, ALPHA state!
author atmos4
date Sat, 01 Sep 2001 19:44:49 +0000
parents 9d62dcf8c7c5
children a4156c8cdd57
files codec-cfg.c codec-cfg.h dec_audio.c etc/codecs.conf stheader.h
diffstat 5 files changed, 266 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/codec-cfg.c	Sat Sep 01 19:43:41 2001 +0000
+++ b/codec-cfg.c	Sat Sep 01 19:44:49 2001 +0000
@@ -205,6 +205,7 @@
 		"dshow",
 		"dvdpcm",
 		"hwac3",
+		"libvorbis",
 		NULL
 	};
 	static char *videodrv[] = {
--- a/codec-cfg.h	Sat Sep 01 19:43:41 2001 +0000
+++ b/codec-cfg.h	Sat Sep 01 19:44:49 2001 +0000
@@ -27,6 +27,7 @@
 #define AFM_DSHOW 7
 #define AFM_DVDPCM 8
 #define AFM_HWAC3 9
+#define AFM_VORBIS 10
 
 #define VFM_MPEG 1
 #define VFM_VFW 2
--- a/dec_audio.c	Sat Sep 01 19:43:41 2001 +0000
+++ b/dec_audio.c	Sat Sep 01 19:44:49 2001 +0000
@@ -37,6 +37,12 @@
 #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 @@
   // 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 @@
   }
 #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 @@
   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 @@
         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;
--- a/etc/codecs.conf	Sat Sep 01 19:43:41 2001 +0000
+++ b/etc/codecs.conf	Sat Sep 01 19:44:49 2001 +0000
@@ -546,3 +546,15 @@
   driver hwac3
   dll "ac3-iec958.c"
 
+audiocodec vorbis
+  info "OggVorbis Audio Decoder"
+  status working
+  comment "OggVorbis driver using libvorbis"
+  format 0xFFFE
+  driver libvorbis
+  dll "libvorbis"
+  flags seekable
+; acm codec doesn't work, haven't tried zorannt dshow codec
+;  driver acm
+;  dll "vorbis.acm"
+
--- a/stheader.h	Sat Sep 01 19:43:41 2001 +0000
+++ b/stheader.h	Sat Sep 01 19:44:49 2001 +0000
@@ -7,6 +7,24 @@
 } codecinfo_t;
 */
 
+#ifdef HAVE_OGGVORBIS
+#include <math.h>
+#include <vorbis/codec.h>
+typedef struct {
+  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 */
+} ov_struct_t;
+#endif
+
 typedef struct {
   demux_stream_t *ds;
   unsigned int format;
@@ -40,6 +58,9 @@
 //  ac3_frame_t *ac3_frame;
   void* ac3_frame;
   int pcm_bswap;
+#ifdef HAVE_OGGVORBIS
+  ov_struct_t *ov; // should be assigned on init
+#endif
 } sh_audio_t;
 
 typedef struct {