mirror of
https://github.com/mpv-player/mpv
synced 2025-02-17 04:58:06 +00:00
OggVorbis support, ALPHA state!
git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@1829 b3059339-0415-0410-9bf9-f77b7e298cf2
This commit is contained in:
parent
5d0b354e7a
commit
aada0e47d2
@ -205,6 +205,7 @@ static short get_driver(char *s,int audioflag)
|
||||
"dshow",
|
||||
"dvdpcm",
|
||||
"hwac3",
|
||||
"libvorbis",
|
||||
NULL
|
||||
};
|
||||
static char *videodrv[] = {
|
||||
|
@ -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
|
||||
|
232
dec_audio.c
232
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;
|
||||
|
@ -546,3 +546,15 @@ audiocodec hwac3
|
||||
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"
|
||||
|
||||
|
21
stheader.h
21
stheader.h
@ -7,6 +7,24 @@ typedef struct {
|
||||
} 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 @@ typedef struct {
|
||||
// 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 {
|
||||
|
Loading…
Reference in New Issue
Block a user