Mercurial > mplayer.hg
view libmpcodecs/ad_realaud.c @ 7743:a280cc3087ea
All right: The patch adresses two issues which I found, when I analyzed
the input from some DVDs with known subtitle-dropouts:
1. The packet-size at the beginning of the packet, which is used to
check, whether we got all fragments, is sometimes one byte too long. It
seems to be always padded to an even number, while the actual size can
be odd.
2. The original algorythm used to assemble the fragments relies on the
timestamps to check, whether a new packet begins. This has proven to be
unrelieable on some disks. So instead, I use the timestamp only to
check, whether it's been too long (defined as 0,01sec) since the last
fragment, which is probably indicating a broken packet, and normaly
starting a new packet when the last one has been finished.
patch by Christof Buergi <christof@buergi.lugs.ch>
author | arpi |
---|---|
date | Tue, 15 Oct 2002 00:47:17 +0000 |
parents | f296ff05bcd0 |
children | 18f8233094da |
line wrap: on
line source
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include "config.h" #ifdef USE_REALCODECS #include <stddef.h> #include <dlfcn.h> #include "ad_internal.h" static ad_info_t info = { "RealAudio decoder", "realaud", "A'rpi", "Florian Schneider", "binary real audio codecs" }; LIBAD_EXTERN(realaud) static void *handle=NULL; void *__builtin_new(unsigned long size) { return malloc(size); } #if defined(__FreeBSD__) || defined(__NetBSD__) void *__ctype_b=NULL; #endif static unsigned long (*raCloseCodec)(void*); static unsigned long (*raDecode)(void*, char*,unsigned long,char*,unsigned int*,long); static unsigned long (*raFlush)(unsigned long,unsigned long,unsigned long); static unsigned long (*raFreeDecoder)(void*); static void* (*raGetFlavorProperty)(void*,unsigned long,unsigned long,int*); //static unsigned long (*raGetNumberOfFlavors2)(void); static unsigned long (*raInitDecoder)(void*, void*); static unsigned long (*raOpenCodec2)(void*); static unsigned long (*raSetFlavor)(void*,unsigned long); //static void (*raSetDLLAccessPath)(unsigned long); static void (*raSetPwd)(char*,char*); typedef struct { int samplerate; short bits; short channels; int unk1; int unk2; int packetsize; int unk3; void* unk4; } ra_init_t; static int preinit(sh_audio_t *sh){ // let's check if the driver is available, return 0 if not. // (you should do that if you use external lib(s) which is optional) unsigned int result; int len=0; void* prop; char path[4096]; sprintf(path, REALCODEC_PATH "/%s", sh->codec->dll); handle = dlopen (path, RTLD_LAZY); if(!handle){ mp_msg(MSGT_DECAUDIO,MSGL_WARN,"Cannot open dll: %s\n",dlerror()); return 0; } raCloseCodec = dlsym(handle, "RACloseCodec"); raDecode = dlsym(handle, "RADecode"); raFlush = dlsym(handle, "RAFlush"); raFreeDecoder = dlsym(handle, "RAFreeDecoder"); raGetFlavorProperty = dlsym(handle, "RAGetFlavorProperty"); raOpenCodec2 = dlsym(handle, "RAOpenCodec2"); raInitDecoder = dlsym(handle, "RAInitDecoder"); raSetFlavor = dlsym(handle, "RASetFlavor"); // raSetDLLAccessPath = dlsym(handle, "SetDLLAccessPath"); raSetPwd = dlsym(handle, "RASetPwd"); // optional, used by SIPR if(!raCloseCodec || !raDecode || !raFlush || !raFreeDecoder || !raGetFlavorProperty || !raOpenCodec2 || !raSetFlavor || /*!raSetDLLAccessPath ||*/ !raInitDecoder){ mp_msg(MSGT_DECAUDIO,MSGL_WARN,"Cannot resolve symbols - incompatible dll\n"); return 0; } result=raOpenCodec2(&sh->context); if(result){ mp_msg(MSGT_DECAUDIO,MSGL_WARN,"Decoder open failed, error code: 0x%X\n",result); return 0; } sh->samplerate=sh->wf->nSamplesPerSec; sh->samplesize=sh->wf->wBitsPerSample/8; sh->channels=sh->wf->nChannels; { ra_init_t init_data={ sh->wf->nSamplesPerSec,sh->wf->wBitsPerSample,sh->wf->nChannels, 100, // ??? ((short*)(sh->wf+1))[0], // subpacket size sh->wf->nBlockAlign, 16, // ?? ((char*)(sh->wf+1))+6+8 }; result=raInitDecoder(sh->context,&init_data); if(result){ mp_msg(MSGT_DECAUDIO,MSGL_WARN,"Decoder init failed, error code: 0x%X\n",result); return 0; } } if(raSetPwd){ // used by 'SIPR' raSetPwd(sh->context,"Ardubancel Quazanga"); // set password... lol. } result=raSetFlavor(sh->context,((short*)(sh->wf+1))[2]); if(result){ mp_msg(MSGT_DECAUDIO,MSGL_WARN,"Decoder flavor setup failed, error code: 0x%X\n",result); return 0; } prop=raGetFlavorProperty(sh->context,((short*)(sh->wf+1))[2],0,&len); mp_msg(MSGT_DECAUDIO,MSGL_INFO,"Audio codec: [%d] %s\n",((short*)(sh->wf+1))[2],prop); prop=raGetFlavorProperty(sh->context,((short*)(sh->wf+1))[2],1,&len); sh->i_bps=((*((int*)prop))+4)/8; mp_msg(MSGT_DECAUDIO,MSGL_INFO,"Audio bitrate: %5.3f kbit/s (%d bps) \n",(*((int*)prop))*0.001f,sh->i_bps); // prop=raGetFlavorProperty(sh->context,((short*)(sh->wf+1))[2],0x13,&len); // mp_msg(MSGT_DECAUDIO,MSGL_INFO,"Samples/block?: %d \n",(*((int*)prop))); sh->audio_out_minsize=128000; // no idea how to get... :( sh->audio_in_minsize=((short*)(sh->wf+1))[1]*sh->wf->nBlockAlign; return 1; // return values: 1=OK 0=ERROR } static int init(sh_audio_t *sh_audio){ // initialize the decoder, set tables etc... // you can store HANDLE or private struct pointer at sh->context // you can access WAVEFORMATEX header at sh->wf // set sample format/rate parameters if you didn't do it in preinit() yet. return 1; // return values: 1=OK 0=ERROR } static void uninit(sh_audio_t *sh){ // uninit the decoder etc... // again: you don't have to free() a_in_buffer here! it's done by the core. } static unsigned char sipr_swaps[38][2]={ {0,63},{1,22},{2,44},{3,90},{5,81},{7,31},{8,86},{9,58},{10,36},{12,68}, {13,39},{14,73},{15,53},{16,69},{17,57},{19,88},{20,34},{21,71},{24,46}, {25,94},{26,54},{28,75},{29,50},{32,70},{33,92},{35,74},{38,85},{40,56}, {42,87},{43,65},{45,59},{48,79},{49,93},{51,89},{55,95},{61,76},{67,83}, {77,80} }; static int decode_audio(sh_audio_t *sh,unsigned char *buf,int minlen,int maxlen){ int result; int len=-1; int sps=((short*)(sh->wf+1))[0]; int w=sh->wf->nBlockAlign; // 5 int h=((short*)(sh->wf+1))[1]; // printf("bs=%d sps=%d w=%d h=%d \n",sh->wf->nBlockAlign,sps,w,h); #if 1 if(sh->a_in_buffer_len<=0){ // fill the buffer! if(!sps){ // 'sipr' way int j,n; int bs=h*w*2/96; // nibbles per subpacket unsigned char *p=sh->a_in_buffer; demux_read_data(sh->ds, p, h*w); for(n=0;n<38;n++){ int i=bs*sipr_swaps[n][0]; int o=bs*sipr_swaps[n][1]; // swap nibbles of block 'i' with 'o' TODO: optimize for(j=0;j<bs;j++){ int x=(i&1) ? (p[(i>>1)]>>4) : (p[(i>>1)]&15); int y=(o&1) ? (p[(o>>1)]>>4) : (p[(o>>1)]&15); if(o&1) p[(o>>1)]=(p[(o>>1)]&0x0F)|(x<<4); else p[(o>>1)]=(p[(o>>1)]&0xF0)|x; if(i&1) p[(i>>1)]=(p[(i>>1)]&0x0F)|(y<<4); else p[(i>>1)]=(p[(i>>1)]&0xF0)|y; ++i;++o; } } sh->a_in_buffer_size= sh->a_in_buffer_len=w*h; } else { // 'cook' way int x,y; w/=sps; for(y=0;y<h;y++) for(x=0;x<w;x++){ demux_read_data(sh->ds, sh->a_in_buffer+sps*(h*x+((h+1)/2)*(y&1)+(y>>1)), sps); } sh->a_in_buffer_size= sh->a_in_buffer_len=w*h*sps; } } #else if(sh->a_in_buffer_len<=0){ // fill the buffer! demux_read_data(sh->ds, sh->a_in_buffer, sh->wf->nBlockAlign); sh->a_in_buffer_size= sh->a_in_buffer_len=sh->wf->nBlockAlign; } #endif result=raDecode(sh->context, sh->a_in_buffer+sh->a_in_buffer_size-sh->a_in_buffer_len, sh->wf->nBlockAlign, buf, &len, -1); sh->a_in_buffer_len-=sh->wf->nBlockAlign; // printf("radecode: %d bytes, res=0x%X \n",len,result); return len; // return value: number of _bytes_ written to output buffer, // or -1 for EOF (or uncorrectable error) } static int control(sh_audio_t *sh,int cmd,void* arg, ...){ // various optional functions you MAY implement: switch(cmd){ case ADCTRL_RESYNC_STREAM: // it is called once after seeking, to resync. // Note: sh_audio->a_in_buffer_len=0; is done _before_ this call! return CONTROL_TRUE; case ADCTRL_SKIP_FRAME: // it is called to skip (jump over) small amount (1/10 sec or 1 frame) // of audio data - used to sync audio to video after seeking // if you don't return CONTROL_TRUE, it will defaults to: // ds_fill_buffer(sh_audio->ds); // skip 1 demux packet return CONTROL_TRUE; } return CONTROL_UNKNOWN; } #endif