diff options
-rw-r--r-- | src/libreal/audio_decoder.c | 595 |
1 files changed, 453 insertions, 142 deletions
diff --git a/src/libreal/audio_decoder.c b/src/libreal/audio_decoder.c index c075d521c..8dd5e70a9 100644 --- a/src/libreal/audio_decoder.c +++ b/src/libreal/audio_decoder.c @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: audio_decoder.c,v 1.2 2002/11/23 00:00:55 guenter Exp $ + * $Id: audio_decoder.c,v 1.3 2002/11/25 00:14:39 guenter Exp $ * * thin layer to use real binary-only codecs in xine * @@ -45,18 +45,8 @@ typedef struct { video_decoder_class_t decoder_class; - void *ra_handle; - - unsigned long (*raCloseCodec)(void*); - unsigned long (*raDecode)(void*, char*,unsigned long,char*,unsigned int*,long); - unsigned long (*raFlush)(unsigned long,unsigned long,unsigned long); - unsigned long (*raFreeDecoder)(void*); - void* (*raGetFlavorProperty)(void*,unsigned long,unsigned long,int*); - unsigned long (*raInitDecoder)(void*, void*); - unsigned long (*raOpenCodec2)(void*); - unsigned long (*raSetFlavor)(void*,unsigned long); - void (*raSetDLLAccessPath)(char*); - void (*raSetPwd)(char*,char*); + + char *real_codec_path; } real_class_t; @@ -67,6 +57,31 @@ typedef struct realdec_decoder_s { xine_stream_t *stream; + void *ra_handle; + + unsigned long (*raCloseCodec)(void*); + unsigned long (*raDecode)(void*, char*,unsigned long,char*,unsigned int*,long); + unsigned long (*raFlush)(unsigned long,unsigned long,unsigned long); + unsigned long (*raFreeDecoder)(void*); + void* (*raGetFlavorProperty)(void*,unsigned long,unsigned long,int*); + unsigned long (*raInitDecoder)(void*, void*); + unsigned long (*raOpenCodec2)(void*); + unsigned long (*raSetFlavor)(void*,unsigned long); + void (*raSetDLLAccessPath)(char*); + void (*raSetPwd)(char*,char*); + + void *context; + + int sps, w, h; + int block_align; + + uint8_t *frame_buffer; + uint8_t *frame_reordered; + int frame_size; + int frame_num_bytes; + + int sample_size; + } realdec_decoder_t; typedef struct { @@ -74,10 +89,10 @@ typedef struct { short bits; short channels; int unk1; - int unk2; - int packetsize; - int unk3; - void *unk4; + int subpacket_size; + int coded_frame_size; + int codec_data_length; + void *extras; } ra_init_t; static void hexdump (char *buf, int length) { @@ -95,14 +110,14 @@ static void hexdump (char *buf, int length) { } printf ("\n"); - printf ("libareal: complete hexdump of package follows:\nlibareal: "); + printf ("libareal: complete hexdump of package follows:\nlibareal 0x0000: "); for (i = 0; i < length; i++) { unsigned char c = buf[i]; printf ("%02x", c); if ((i % 16) == 15) - printf ("\nlibareal: "); + printf ("\nlibareal 0x%04x: ", i+1); if ((i % 2) == 1) printf (" "); @@ -111,78 +126,219 @@ static void hexdump (char *buf, int length) { printf ("\n"); } -static void realdec_decode_data (video_decoder_t *this_gen, buf_element_t *buf) { - realdec_decoder_t *this = (realdec_decoder_t *) this_gen; - real_class_t *cls = this->cls; +void *__builtin_new(unsigned long size) { + return malloc(size); +} -#ifdef LOG - printf ("libareal: decode_data, flags=0x%08x ...\n", buf->decoder_flags); -#endif +static int load_syms_linux (realdec_decoder_t *this, char *codec_name) { - if (buf->decoder_flags & BUF_FLAG_PREVIEW) { + char path[1024]; - /* real_find_sequence_header (&this->real, buf->content, buf->content + buf->size);*/ + sprintf (path, "%s/%s", this->cls->real_codec_path, codec_name); - } else if (buf->decoder_flags & BUF_FLAG_HEADER) { + printf ("libareal: (audio) opening shared obj '%s'\n", path); + this->ra_handle = dlopen (path, RTLD_LAZY); + + if (!this->ra_handle) { + printf ("libareal: error: %s\n", dlerror()); + return 0; + } + + this->raCloseCodec = dlsym (this->ra_handle, "RACloseCodec"); + this->raDecode = dlsym (this->ra_handle, "RADecode"); + this->raFlush = dlsym (this->ra_handle, "RAFlush"); + this->raFreeDecoder = dlsym (this->ra_handle, "RAFreeDecoder"); + this->raGetFlavorProperty = dlsym (this->ra_handle, "RAGetFlavorProperty"); + this->raOpenCodec2 = dlsym (this->ra_handle, "RAOpenCodec2"); + this->raInitDecoder = dlsym (this->ra_handle, "RAInitDecoder"); + this->raSetFlavor = dlsym (this->ra_handle, "RASetFlavor"); + this->raSetDLLAccessPath = dlsym (this->ra_handle, "SetDLLAccessPath"); + this->raSetPwd = dlsym (this->ra_handle, "RASetPwd"); /* optional, used by SIPR */ + + printf ("libareal: codec loaded, symbols resolved\n"); + + if (!this->raCloseCodec || !this->raDecode || !this->raFlush || !this->raFreeDecoder || + !this->raGetFlavorProperty || !this->raOpenCodec2 || !this->raSetFlavor || + /*!raSetDLLAccessPath ||*/ !this->raInitDecoder){ + printf ("libareal: (audio) Cannot resolve symbols - incompatible dll: %s\n", + path); + return 0; + } - int version ; - int samples_per_sec, bits_per_sample, num_channels; - int subpacket_size, coded_frame_size, codec_data_length, extras; + printf ("libareal: raSetDLLAccessPath\n"); - version = BE_16 (buf->content); + if (this->raSetDLLAccessPath){ - printf ("libareal: header buffer detected, header version %d\n", version); + char path[1024]; -#if 0 - subpacket_size = BE_16 (buf->content+40); - coded_frame_size = BE_32 (buf->content+20); - codec_data_length= - - if (version == 4) { - samples_per_sec = BE_16 (buf->content+44); - bits_per_sample = BE_16 (buf->content+48); - num_channels = BE_16 (buf->content+50); - } else { - samples_per_sec = BE_16 (buf->content+50); - bits_per_sample = BE_16 (buf->content+54); - num_channels = BE_16 (buf->content+56); + sprintf(path, "DT_Codecs=%s", this->cls->real_codec_path); + if (path[strlen(path)-1]!='/'){ + path[strlen(path)+1]=0; + path[strlen(path)]='/'; } + path[strlen(path)+1]=0; - printf ("libareal: %d samples/sec, %d bits/sample, %d channels\n", - samples_per_sec, bits_per_sample, num_channels); - - sh->samplerate = sh->wf->nSamplesPerSec; - sh->samplesize = sh->wf->wBitsPerSample/8; - sh->channels = sh->wf->nChannels; - - { - ra_init_t init_data={ - samples_per_sec, - bits_per_sample, - num_channels, - 100, /* ??? */ - ((short*)(sh->wf+1))[0], /* subpacket size */ - ((short*)(sh->wf+1))[3], /* coded frame size */ - ((short*)(sh->wf+1))[4], /* codec data length */ - ((char*)(sh->wf+1))+10 /* extras */ - }; - 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 (cls->raSetPwd) { - /* used by 'SIPR' */ - cls->raSetPwd (this->context, "Ardubancel Quazanga"); /* set password... lol. */ - } + printf ("libareal: path=%s\n", path); + + this->raSetDLLAccessPath(path); + } + + printf ("libareal: audio decoder loaded successfully\n"); + + return 1; +} + +static int init_codec (realdec_decoder_t *this, buf_element_t *buf) { + + int version, result ; + int samples_per_sec, bits_per_sample, num_channels; + int subpacket_size, coded_frame_size, codec_data_length; + int coded_frame_size2, data_len, flavor; + int mode; + void *extras; - result=raSetFlavor(sh->context,((short*)(sh->wf+1))[2]); + /* + * extract header data + */ + + version = BE_16 (buf->content); + + printf ("libareal: header buffer detected, header version %d\n", version); + + hexdump (buf->content, buf->size); + + flavor = BE_16 (buf->content+18); + coded_frame_size = BE_32 (buf->content+20); + codec_data_length= BE_16 (buf->content+36); + coded_frame_size2= BE_16 (buf->content+38); + subpacket_size = BE_16 (buf->content+40); + + this->sps = subpacket_size; + this->w = coded_frame_size2; + this->h = codec_data_length; + + if (version == 4) { + samples_per_sec = BE_16 (buf->content+44); + bits_per_sample = BE_16 (buf->content+48); + num_channels = BE_16 (buf->content+50); + /* FIXME: */ + data_len = BE_32 (buf->content+0x39); + extras = buf->content+0x44; + } else { + samples_per_sec = BE_16 (buf->content+50); + bits_per_sample = BE_16 (buf->content+54); + num_channels = BE_16 (buf->content+56); + data_len = BE_32 (buf->content+0x46); + extras = buf->content+0x4a; + } + + this->block_align= coded_frame_size2; + + printf ("libareal: 0x%04x 0x%04x 0x%04x 0x%04x data_len 0x%04x\n", + subpacket_size, coded_frame_size, codec_data_length, + coded_frame_size2, data_len); + + + printf ("libareal: %d samples/sec, %d bits/sample, %d channels\n", + samples_per_sec, bits_per_sample, num_channels); + + /* load codec, resolv symbols */ + + printf ("libareal: loading codec...\n"); + + switch (buf->type) { + case BUF_AUDIO_COOK: + if (!load_syms_linux (this, "cook.so.6.0")) + return 0; + + break; + + case BUF_AUDIO_ATRK: + if (!load_syms_linux (this, "atrc.so.6.0")) + return 0; + this->block_align = 384; + break; + + case BUF_AUDIO_14_4: + if (!load_syms_linux (this, "14_4.so.6.0")) + return 0; + break; + + case BUF_AUDIO_28_8: + if (!load_syms_linux (this, "28_8.so.6.0")) + return 0; + break; + + case BUF_AUDIO_SIPRO: + if (!load_syms_linux (this, "sipr.so.6.0")) + return 0; + this->block_align = 19; + break; + + default: + printf ("libareal: error, i don't handle buf type 0x%08x\n", + buf->type); + abort(); + } + + /* + * init codec + */ + + result = this->raOpenCodec2 (&this->context); + if (result) { + printf ("libareal: error in raOpenCodec2: %d\n", result); + return 0; + } + + { + ra_init_t init_data={ + samples_per_sec, + bits_per_sample, + num_channels, + 100, /* ??? */ + subpacket_size, /* subpacket size */ + coded_frame_size, /* coded frame size */ + data_len, /* codec data length */ + extras /* extras */ + }; + + + printf ("libareal: init_data:\n"); + hexdump (&init_data, sizeof (ra_init_t)); + printf ("libareal: extras :\n"); + hexdump (init_data.extras, data_len); + + + result = this->raInitDecoder (this->context, &init_data); if(result){ - mp_msg(MSGT_DECAUDIO,MSGL_WARN,"Decoder flavor setup failed, error code: 0x%X\n",result); + printf ("libareal: decoder init failed, error code: 0x%x\n", + result); return 0; } + } + + printf ("libareal: raInitDecoder done.\n"); + + if (this->raSetPwd){ + /* used by 'SIPR' */ + this->raSetPwd (this->context, "Ardubancel Quazanga"); /* set password... lol. */ + printf ("libareal: password set\n"); + } + + printf ("libareal: set flavor %d\n", flavor); + + result = this->raSetFlavor (this->context, flavor); + if (result){ + printf ("libareal: decoder flavor setup failed, error code: 0x%x\n", + result); + return 0; + } + + printf ("libareal: set flavor %d done\n", flavor); + + +#if 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); @@ -199,19 +355,203 @@ static void realdec_decode_data (video_decoder_t *this_gen, buf_element_t *buf) #endif + /* + * alloc buffers for data reordering + */ + + if (this->sps) { + + this->frame_size = this->w/this->sps*this->h*this->sps; + this->frame_buffer = xine_xmalloc (this->frame_size); + this->frame_reordered = xine_xmalloc (this->frame_size); + this->frame_num_bytes = 0; + + } else { + + printf ("libareal: data reordering for sps==0 not implemented\n"); + abort(); + + } + + /* + * open audio output + */ + + switch (num_channels) { + case 1: + mode = AO_CAP_MODE_MONO; + break; + case 2: + mode = AO_CAP_MODE_STEREO; + break; + default: + printf ("libareal: oups, real can do more than 2 channels ?\n"); + abort(); + } + + this->stream->audio_out->open(this->stream->audio_out, + this->stream, + bits_per_sample, + samples_per_sec, + mode) ; + + this->sample_size = num_channels * (bits_per_sample>>3); + printf ("libareal: 1 sample is %d bytes\n", this->sample_size); + + return 1; +} + +static void realdec_decode_data (video_decoder_t *this_gen, buf_element_t *buf) { + realdec_decoder_t *this = (realdec_decoder_t *) this_gen; + +#ifdef LOG + printf ("libareal: decode_data, flags=0x%08x ...\n", buf->decoder_flags); +#endif + + if (buf->decoder_flags & BUF_FLAG_PREVIEW) { + + /* real_find_sequence_header (&this->real, buf->content, buf->content + buf->size);*/ + + } else if (buf->decoder_flags & BUF_FLAG_HEADER) { + + init_codec (this, buf) ; + } else { - printf ("libareal: content buffer detected\n"); + int size; + + printf ("libareal: content buffer detected, %d bytes\n", buf->size); + + size = buf->size; + + while (size) { + + int needed; + + needed = this->frame_size - this->frame_num_bytes; + + if (needed>size) { + + memcpy (this->frame_buffer+this->frame_num_bytes, buf->content, size); + this->frame_num_bytes += size; + + printf ("libareal: buffering %d/%d bytes\n", this->frame_num_bytes, this->frame_size); + + size = 0; + + } else { + + int result; + int len =-1; + int n; + int sps = this->sps; + int w = this->w; + int h = this->h; + audio_buffer_t *audio_buffer; + + printf ("libareal: buffering %d bytes\n", needed); + memcpy (this->frame_buffer+this->frame_num_bytes, buf->content, needed); + + size -= needed; + this->frame_num_bytes = 0; + + printf ("libareal: frame completed. reordering...\n"); + + printf ("libareal: bs=%d sps=%d w=%d h=%d \n",/*sh->wf->nBlockAlign*/-1,sps,w,h); + + if (!sps) { + + printf ("libareal: sipr reordering not implemented yet\n"); + abort(); + +#if 0 + int j,n; + int bs=h*w*2/96; // nibbles per subpacket + unsigned char *p=sh->a_in_buffer; + + /* 'sipr' way */ + 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; +#endif + + } else { + int x, y; + uint8_t *s; + + /* 'cook' way */ + + w /= sps; s = this->frame_buffer; + + for (y=0; y<h; y++) + + for (x=0; x<w; x++) { + + printf ("libareal: x=%d, y=%d, off %d\n", + x, y, sps*(h*x+((h+1)/2)*(y&1)+(y>>1))); + + memcpy (this->frame_reordered+sps*(h*x+((h+1)/2)*(y&1)+(y>>1)), + s, sps); + s+=sps; + + /* 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; + */ + } + + hexdump (this->frame_reordered, buf->size); + + n = 0; + while (n<this->frame_size) { + + audio_buffer = this->stream->audio_out->get_buffer (this->stream->audio_out); + + result = this->raDecode (this->context, + this->frame_reordered+n, + this->block_align, + audio_buffer->mem, &len, -1); + + printf ("libareal: raDecode result %d, len=%d\n", result, len); + + audio_buffer->vpts = 0; /* FIXME */ + audio_buffer->num_frames = len/this->sample_size;; + + this->stream->audio_out->put_buffer (this->stream->audio_out, + audio_buffer, this->stream); + n+=this->block_align; + } + } + } } + #ifdef LOG printf ("libareal: decode_data...done\n"); #endif } static void realdec_flush (video_decoder_t *this_gen) { - realdec_decoder_t *this = (realdec_decoder_t *) this_gen; + /* realdec_decoder_t *this = (realdec_decoder_t *) this_gen; */ #ifdef LOG printf ("libareal: flush\n"); @@ -220,12 +560,12 @@ static void realdec_flush (video_decoder_t *this_gen) { } static void realdec_reset (video_decoder_t *this_gen) { - realdec_decoder_t *this = (realdec_decoder_t *) this_gen; + /* realdec_decoder_t *this = (realdec_decoder_t *) this_gen; */ } static void realdec_discontinuity (video_decoder_t *this_gen) { - realdec_decoder_t *this = (realdec_decoder_t *) this_gen; + /* realdec_decoder_t *this = (realdec_decoder_t *) this_gen; */ } @@ -237,6 +577,9 @@ static void realdec_dispose (video_decoder_t *this_gen) { printf ("libareal: close\n"); #endif + if (this->ra_handle) + dlclose (this->ra_handle); + free (this); } @@ -294,80 +637,48 @@ void __pure_virtual(void) { * real audio codec loader */ -#define REALCODEC_PATH "/opt/RealPlayer8/Codecs" - -static int load_syms_linux (real_class_t *cls, char *path) { - - printf ("libareal: (audio) opening shared obj '%s'\n", path); - cls->ra_handle = dlopen (path, RTLD_LAZY); - - if (!cls->ra_handle) { - printf ("libareal: error: %s\n", dlerror()); - return 0; - } +static void codec_path_cb (void *data, xine_cfg_entry_t *cfg) { + real_class_t *this = (real_class_t *) data; - cls->raCloseCodec = dlsym (cls->ra_handle, "RACloseCodec"); - cls->raDecode = dlsym (cls->ra_handle, "RADecode"); - cls->raFlush = dlsym (cls->ra_handle, "RAFlush"); - cls->raFreeDecoder = dlsym (cls->ra_handle, "RAFreeDecoder"); - cls->raGetFlavorProperty = dlsym (cls->ra_handle, "RAGetFlavorProperty"); - cls->raOpenCodec2 = dlsym (cls->ra_handle, "RAOpenCodec2"); - cls->raInitDecoder = dlsym (cls->ra_handle, "RAInitDecoder"); - cls->raSetFlavor = dlsym (cls->ra_handle, "RASetFlavor"); - cls->raSetDLLAccessPath = dlsym (cls->ra_handle, "SetDLLAccessPath"); - cls->raSetPwd = dlsym (cls->ra_handle, "RASetPwd"); /* optional, used by SIPR */ - - printf ("libareal: codec loaded, symbols resolved\n"); - - if (!cls->raCloseCodec || !cls->raDecode || !cls->raFlush || !cls->raFreeDecoder || - !cls->raGetFlavorProperty || !cls->raOpenCodec2 || !cls->raSetFlavor || - /*!raSetDLLAccessPath ||*/ !cls->raInitDecoder){ - printf ("libareal: (audio) Cannot resolve symbols - incompatible dll: %s\n", - path); - return 0; - } - - printf ("libareal: raSetDLLAccessPath\n"); - - if (cls->raSetDLLAccessPath){ - - char path[1024]; - - sprintf(path, "DT_Codecs=" REALCODEC_PATH); - if(path[strlen(path)-1]!='/'){ - path[strlen(path)+1]=0; - path[strlen(path)]='/'; - } - path[strlen(path)+1]=0; - - printf ("libareal: path=%s\n", path); - - cls->raSetDLLAccessPath(path); - } - - printf ("libareal: audio decoder loaded successfully\n"); - - return 1; + this->real_codec_path = cfg->str_value; } static void *init_class (xine_t *xine, void *data) { - real_class_t *this; + real_class_t *this; + config_values_t *config = xine->config; this = (real_class_t *) xine_xmalloc (sizeof (real_class_t)); - if (!load_syms_linux (this, "/usr/local/RealPlayer8/Codecs/sipr.so.6.0")) { - if (!load_syms_linux (this, "/opt/RealPlayer8/Codecs/sipr.so.6.0")) { - free (this); - return NULL; - } - } - this->decoder_class.open_plugin = open_plugin; this->decoder_class.get_identifier = get_identifier; this->decoder_class.get_description = get_description; this->decoder_class.dispose = dispose_class; + this->real_codec_path = config->register_string (config, "codec.real_codecs_path", + "unknown", + _("path to real player codecs, if installed"), + NULL, 10, codec_path_cb, (void *)this); + + if (!strcmp (this->real_codec_path, "unknown")) { + + struct stat s; + + /* try some auto-detection */ + + if (!stat ("/usr/local/RealPlayer8/Codecs/drv3.so.6.0", &s)) + config->update_string (config, "codec.real_codecs_path", + "/usr/local/RealPlayer8/Codecs"); + if (!stat ("/usr/RealPlayer8/Codecs/drv3.so.6.0", &s)) + config->update_string (config, "codec.real_codecs_path", + "/usr/RealPlayer8/Codecs"); + if (!stat ("/opt/RealPlayer8/Codecs/drv3.so.6.0", &s)) + config->update_string (config, "codec.real_codecs_path", + "/opt/RealPlayer8/Codecs"); + } + + printf ("libareal: real codec path : %s\n", this->real_codec_path); + return this; } |