X-Git-Url: http://4ch.mooo.com/gitweb/?a=blobdiff_plain;f=src%2Flib%2Fdl%2Fext%2Fspeex%2Fspeexdec.c;fp=src%2Flib%2Fdl%2Fext%2Fspeex%2Fspeexdec.c;h=b8bddc7118cd3cfd815c9ef99b9a8f11ff5ac59c;hb=10d8a0d8b1b72502f34c2ac1bd3a5c2d87849080;hp=0000000000000000000000000000000000000000;hpb=bc10e84da5198561bb96cf8eb459f59b8b0739ec;p=16.git diff --git a/src/lib/dl/ext/speex/speexdec.c b/src/lib/dl/ext/speex/speexdec.c new file mode 100755 index 00000000..b8bddc71 --- /dev/null +++ b/src/lib/dl/ext/speex/speexdec.c @@ -0,0 +1,808 @@ +/* Copyright (C) 2002-2006 Jean-Marc Valin + File: speexdec.c + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#if !defined WIN32 && !defined _WIN32 +#include +#endif +#ifdef HAVE_GETOPT_H +#include "getopt.h" +#endif +#ifndef HAVE_GETOPT_LONG +#include "getopt_win.h" +#endif +#include +#include + +#include +#include + +#if defined WIN32 || defined _WIN32 +#include "wave_out.h" +/* We need the following two to set stdout to binary */ +#include +#include +#endif +#include + +#ifdef __MINGW32__ +#include "wave_out.c" +#endif + +#ifdef HAVE_SYS_SOUNDCARD_H +#include +#include +#include +#include +#include + +#elif defined HAVE_SYS_AUDIOIO_H +#include +#include +#include +#include +#ifndef AUDIO_ENCODING_SLINEAR +#define AUDIO_ENCODING_SLINEAR AUDIO_ENCODING_LINEAR /* Solaris */ +#endif + +#endif + +#include +#include "wav_io.h" +#include +#include +#include + +#define MAX_FRAME_SIZE 2000 + +#define readint(buf, base) (((buf[base+3]<<24)&0xff000000)| \ + ((buf[base+2]<<16)&0xff0000)| \ + ((buf[base+1]<<8)&0xff00)| \ + (buf[base]&0xff)) + +static void print_comments(char *comments, int length) +{ + char *c=comments; + int len, i, nb_fields; + char *end; + + if (length<8) + { + fprintf (stderr, "Invalid/corrupted comments\n"); + return; + } + end = c+length; + len=readint(c, 0); + c+=4; + if (len < 0 || c+len>end) + { + fprintf (stderr, "Invalid/corrupted comments\n"); + return; + } + fwrite(c, 1, len, stderr); + c+=len; + fprintf (stderr, "\n"); + if (c+4>end) + { + fprintf (stderr, "Invalid/corrupted comments\n"); + return; + } + nb_fields=readint(c, 0); + c+=4; + for (i=0;iend) + { + fprintf (stderr, "Invalid/corrupted comments\n"); + return; + } + len=readint(c, 0); + c+=4; + if (len < 0 || c+len>end) + { + fprintf (stderr, "Invalid/corrupted comments\n"); + return; + } + fwrite(c, 1, len, stderr); + c+=len; + fprintf (stderr, "\n"); + } +} + +FILE *out_file_open(char *outFile, int rate, int *channels) +{ + FILE *fout=NULL; + /*Open output file*/ + if (strlen(outFile)==0) + { +#if defined HAVE_SYS_SOUNDCARD_H + int audio_fd, format, stereo; + audio_fd=open("/dev/dsp", O_WRONLY); + if (audio_fd<0) + { + perror("Cannot open /dev/dsp"); + exit(1); + } + + format=AFMT_S16_NE; + if (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &format)==-1) + { + perror("SNDCTL_DSP_SETFMT"); + close(audio_fd); + exit(1); + } + + stereo=0; + if (*channels==2) + stereo=1; + if (ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo)==-1) + { + perror("SNDCTL_DSP_STEREO"); + close(audio_fd); + exit(1); + } + if (stereo!=0) + { + if (*channels==1) + fprintf (stderr, "Cannot set mono mode, will decode in stereo\n"); + *channels=2; + } + + if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &rate)==-1) + { + perror("SNDCTL_DSP_SPEED"); + close(audio_fd); + exit(1); + } + fout = fdopen(audio_fd, "w"); +#elif defined HAVE_SYS_AUDIOIO_H + audio_info_t info; + int audio_fd; + + audio_fd = open("/dev/audio", O_WRONLY); + if (audio_fd<0) + { + perror("Cannot open /dev/audio"); + exit(1); + } + + AUDIO_INITINFO(&info); +#ifdef AUMODE_PLAY /* NetBSD/OpenBSD */ + info.mode = AUMODE_PLAY; +#endif + info.play.encoding = AUDIO_ENCODING_SLINEAR; + info.play.precision = 16; + info.play.sample_rate = rate; + info.play.channels = *channels; + + if (ioctl(audio_fd, AUDIO_SETINFO, &info) < 0) + { + perror ("AUDIO_SETINFO"); + exit(1); + } + fout = fdopen(audio_fd, "w"); +#elif defined WIN32 || defined _WIN32 + { + unsigned int speex_channels = *channels; + if (Set_WIN_Params (INVALID_FILEDESC, rate, SAMPLE_SIZE, speex_channels)) + { + fprintf (stderr, "Can't access %s\n", "WAVE OUT"); + exit(1); + } + } +#else + fprintf (stderr, "No soundcard support\n"); + exit(1); +#endif + } else { + if (strcmp(outFile,"-")==0) + { +#if defined WIN32 || defined _WIN32 + _setmode(_fileno(stdout), _O_BINARY); +#elif defined OS2 + _fsetmode(stdout,"b"); +#endif + fout=stdout; + } + else + { + fout = fopen(outFile, "wb"); + if (!fout) + { + perror(outFile); + exit(1); + } + if (strcmp(outFile+strlen(outFile)-4,".wav")==0 || strcmp(outFile+strlen(outFile)-4,".WAV")==0) + write_wav_header(fout, rate, *channels, 0, 0); + } + } + return fout; +} + +void usage() +{ + printf ("Usage: speexdec [options] input_file.spx [output_file]\n"); + printf ("\n"); + printf ("Decodes a Speex file and produce a WAV file or raw file\n"); + printf ("\n"); + printf ("input_file can be:\n"); + printf (" filename.spx regular Speex file\n"); + printf (" - stdin\n"); + printf ("\n"); + printf ("output_file can be:\n"); + printf (" filename.wav Wav file\n"); + printf (" filename.* Raw PCM file (any extension other that .wav)\n"); + printf (" - stdout\n"); + printf (" (nothing) Will be played to soundcard\n"); + printf ("\n"); + printf ("Options:\n"); + printf (" --enh Enable perceptual enhancement (default)\n"); + printf (" --no-enh Disable perceptual enhancement\n"); + printf (" --force-nb Force decoding in narrowband\n"); + printf (" --force-wb Force decoding in wideband\n"); + printf (" --force-uwb Force decoding in ultra-wideband\n"); + printf (" --mono Force decoding in mono\n"); + printf (" --stereo Force decoding in stereo\n"); + printf (" --rate n Force decoding at sampling rate n Hz\n"); + printf (" --packet-loss n Simulate n %% random packet loss\n"); + printf (" -V Verbose mode (show bit-rate)\n"); + printf (" -h, --help This help\n"); + printf (" -v, --version Version information\n"); + printf (" --pf Deprecated, use --enh instead\n"); + printf (" --no-pf Deprecated, use --no-enh instead\n"); + printf ("\n"); + printf ("More information is available from the Speex site: http://www.speex.org\n"); + printf ("\n"); + printf ("Please report bugs to the mailing list `speex-dev@xiph.org'.\n"); +} + +void version() +{ + const char* speex_version; + speex_lib_ctl(SPEEX_LIB_GET_VERSION_STRING, (void*)&speex_version); + printf ("speexdec (Speex decoder) version %s (compiled " __DATE__ ")\n", speex_version); + printf ("Copyright (C) 2002-2006 Jean-Marc Valin\n"); +} + +void version_short() +{ + const char* speex_version; + speex_lib_ctl(SPEEX_LIB_GET_VERSION_STRING, (void*)&speex_version); + printf ("speexdec version %s\n", speex_version); + printf ("Copyright (C) 2002-2006 Jean-Marc Valin\n"); +} + +static void *process_header(ogg_packet *op, spx_int32_t enh_enabled, spx_int32_t *frame_size, int *granule_frame_size, spx_int32_t *rate, int *nframes, int forceMode, int *channels, SpeexStereoState *stereo, int *extra_headers, int quiet) +{ + void *st; + const SpeexMode *mode; + SpeexHeader *header; + int modeID; + SpeexCallback callback; + + header = speex_packet_to_header((char*)op->packet, op->bytes); + if (!header) + { + fprintf (stderr, "Cannot read header\n"); + return NULL; + } + if (header->mode >= SPEEX_NB_MODES || header->mode<0) + { + fprintf (stderr, "Mode number %d does not (yet/any longer) exist in this version\n", + header->mode); + free(header); + return NULL; + } + + modeID = header->mode; + if (forceMode!=-1) + modeID = forceMode; + + mode = speex_lib_get_mode (modeID); + + if (header->speex_version_id > 1) + { + fprintf (stderr, "This file was encoded with Speex bit-stream version %d, which I don't know how to decode\n", header->speex_version_id); + free(header); + return NULL; + } + + if (mode->bitstream_version < header->mode_bitstream_version) + { + fprintf (stderr, "The file was encoded with a newer version of Speex. You need to upgrade in order to play it.\n"); + free(header); + return NULL; + } + if (mode->bitstream_version > header->mode_bitstream_version) + { + fprintf (stderr, "The file was encoded with an older version of Speex. You would need to downgrade the version in order to play it.\n"); + free(header); + return NULL; + } + + st = speex_decoder_init(mode); + if (!st) + { + fprintf (stderr, "Decoder initialization failed.\n"); + free(header); + return NULL; + } + speex_decoder_ctl(st, SPEEX_SET_ENH, &enh_enabled); + speex_decoder_ctl(st, SPEEX_GET_FRAME_SIZE, frame_size); + *granule_frame_size = *frame_size; + + if (!*rate) + *rate = header->rate; + /* Adjust rate if --force-* options are used */ + if (forceMode!=-1) + { + if (header->mode < forceMode) + { + *rate <<= (forceMode - header->mode); + *granule_frame_size >>= (forceMode - header->mode); + } + if (header->mode > forceMode) + { + *rate >>= (header->mode - forceMode); + *granule_frame_size <<= (header->mode - forceMode); + } + } + + + speex_decoder_ctl(st, SPEEX_SET_SAMPLING_RATE, rate); + + *nframes = header->frames_per_packet; + + if (*channels==-1) + *channels = header->nb_channels; + + if (!(*channels==1)) + { + *channels = 2; + callback.callback_id = SPEEX_INBAND_STEREO; + callback.func = speex_std_stereo_request_handler; + callback.data = stereo; + speex_decoder_ctl(st, SPEEX_SET_HANDLER, &callback); + } + + if (!quiet) + { + fprintf (stderr, "Decoding %d Hz audio using %s mode", + *rate, mode->modeName); + + if (*channels==1) + fprintf (stderr, " (mono"); + else + fprintf (stderr, " (stereo"); + + if (header->vbr) + fprintf (stderr, ", VBR)\n"); + else + fprintf(stderr, ")\n"); + /*fprintf (stderr, "Decoding %d Hz audio at %d bps using %s mode\n", + *rate, mode->bitrate, mode->modeName);*/ + } + + *extra_headers = header->extra_headers; + + free(header); + return st; +} + +int main(int argc, char **argv) +{ + int c; + int option_index = 0; + char *inFile, *outFile; + FILE *fin, *fout=NULL; + short out[MAX_FRAME_SIZE]; + short output[MAX_FRAME_SIZE]; + int frame_size=0, granule_frame_size=0; + void *st=NULL; + SpeexBits bits; + int packet_count=0; + int stream_init = 0; + int quiet = 0; + ogg_int64_t page_granule=0, last_granule=0; + int skip_samples=0, page_nb_packets; + struct option long_options[] = + { + {"help", no_argument, NULL, 0}, + {"quiet", no_argument, NULL, 0}, + {"version", no_argument, NULL, 0}, + {"version-short", no_argument, NULL, 0}, + {"enh", no_argument, NULL, 0}, + {"no-enh", no_argument, NULL, 0}, + {"pf", no_argument, NULL, 0}, + {"no-pf", no_argument, NULL, 0}, + {"force-nb", no_argument, NULL, 0}, + {"force-wb", no_argument, NULL, 0}, + {"force-uwb", no_argument, NULL, 0}, + {"rate", required_argument, NULL, 0}, + {"mono", no_argument, NULL, 0}, + {"stereo", no_argument, NULL, 0}, + {"packet-loss", required_argument, NULL, 0}, + {0, 0, 0, 0} + }; + ogg_sync_state oy; + ogg_page og; + ogg_packet op; + ogg_stream_state os; + int enh_enabled; + int nframes=2; + int print_bitrate=0; + int close_in=0; + int eos=0; + int forceMode=-1; + int audio_size=0; + float loss_percent=-1; + SpeexStereoState stereo = SPEEX_STEREO_STATE_INIT; + int channels=-1; + int rate=0; + int extra_headers=0; + int wav_format=0; + int lookahead; + int speex_serialno = -1; + + enh_enabled = 1; + + /*Process options*/ + while(1) + { + c = getopt_long (argc, argv, "hvV", + long_options, &option_index); + if (c==-1) + break; + + switch(c) + { + case 0: + if (strcmp(long_options[option_index].name,"help")==0) + { + usage(); + exit(0); + } else if (strcmp(long_options[option_index].name,"quiet")==0) + { + quiet = 1; + } else if (strcmp(long_options[option_index].name,"version")==0) + { + version(); + exit(0); + } else if (strcmp(long_options[option_index].name,"version-short")==0) + { + version_short(); + exit(0); + } else if (strcmp(long_options[option_index].name,"enh")==0) + { + enh_enabled=1; + } else if (strcmp(long_options[option_index].name,"no-enh")==0) + { + enh_enabled=0; + } else if (strcmp(long_options[option_index].name,"pf")==0) + { + fprintf (stderr, "--pf is deprecated, use --enh instead\n"); + enh_enabled=1; + } else if (strcmp(long_options[option_index].name,"no-pf")==0) + { + fprintf (stderr, "--no-pf is deprecated, use --no-enh instead\n"); + enh_enabled=0; + } else if (strcmp(long_options[option_index].name,"force-nb")==0) + { + forceMode=0; + } else if (strcmp(long_options[option_index].name,"force-wb")==0) + { + forceMode=1; + } else if (strcmp(long_options[option_index].name,"force-uwb")==0) + { + forceMode=2; + } else if (strcmp(long_options[option_index].name,"mono")==0) + { + channels=1; + } else if (strcmp(long_options[option_index].name,"stereo")==0) + { + channels=2; + } else if (strcmp(long_options[option_index].name,"rate")==0) + { + rate=atoi (optarg); + } else if (strcmp(long_options[option_index].name,"packet-loss")==0) + { + loss_percent = atof(optarg); + } + break; + case 'h': + usage(); + exit(0); + break; + case 'v': + version(); + exit(0); + break; + case 'V': + print_bitrate=1; + break; + case '?': + usage(); + exit(1); + break; + } + } + if (argc-optind!=2 && argc-optind!=1) + { + usage(); + exit(1); + } + inFile=argv[optind]; + + if (argc-optind==2) + outFile=argv[optind+1]; + else + outFile = ""; + wav_format = strlen(outFile)>=4 && ( + strcmp(outFile+strlen(outFile)-4,".wav")==0 + || strcmp(outFile+strlen(outFile)-4,".WAV")==0); + /*Open input file*/ + if (strcmp(inFile, "-")==0) + { +#if defined WIN32 || defined _WIN32 + _setmode(_fileno(stdin), _O_BINARY); +#endif + fin=stdin; + } + else + { + fin = fopen(inFile, "rb"); + if (!fin) + { + perror(inFile); + exit(1); + } + close_in=1; + } + + + /*Init Ogg data struct*/ + ogg_sync_init(&oy); + + speex_bits_init(&bits); + /*Main decoding loop*/ + + while (1) + { + char *data; + int i, j, nb_read; + /*Get the ogg buffer for writing*/ + data = ogg_sync_buffer(&oy, 200); + /*Read bitstream from input file*/ + nb_read = fread(data, sizeof(char), 200, fin); + ogg_sync_wrote(&oy, nb_read); + + /*Loop for all complete pages we got (most likely only one)*/ + while (ogg_sync_pageout(&oy, &og)==1) + { + int packet_no; + if (stream_init == 0) { + ogg_stream_init(&os, ogg_page_serialno(&og)); + stream_init = 1; + } + if (ogg_page_serialno(&og) != os.serialno) { + /* so all streams are read. */ + ogg_stream_reset_serialno(&os, ogg_page_serialno(&og)); + } + /*Add page to the bitstream*/ + ogg_stream_pagein(&os, &og); + page_granule = ogg_page_granulepos(&og); + page_nb_packets = ogg_page_packets(&og); + if (page_granule>0 && frame_size) + { + /* FIXME: shift the granule values if --force-* is specified */ + skip_samples = frame_size*(page_nb_packets*granule_frame_size*nframes - (page_granule-last_granule))/granule_frame_size; + if (ogg_page_eos(&og)) + skip_samples = -skip_samples; + /*else if (!ogg_page_bos(&og)) + skip_samples = 0;*/ + } else + { + skip_samples = 0; + } + /*printf ("page granulepos: %d %d %d\n", skip_samples, page_nb_packets, (int)page_granule);*/ + last_granule = page_granule; + /*Extract all available packets*/ + packet_no=0; + while (!eos && ogg_stream_packetout(&os, &op) == 1) + { + if (op.bytes>=5 && !memcmp(op.packet, "Speex", 5)) { + speex_serialno = os.serialno; + } + if (speex_serialno == -1 || os.serialno != speex_serialno) + break; + /*If first packet, process as Speex header*/ + if (packet_count==0) + { + st = process_header(&op, enh_enabled, &frame_size, &granule_frame_size, &rate, &nframes, forceMode, &channels, &stereo, &extra_headers, quiet); + if (!st) + exit(1); + speex_decoder_ctl(st, SPEEX_GET_LOOKAHEAD, &lookahead); + if (!nframes) + nframes=1; + fout = out_file_open(outFile, rate, &channels); + + } else if (packet_count==1) + { + if (!quiet) + print_comments((char*)op.packet, op.bytes); + } else if (packet_count<=1+extra_headers) + { + /* Ignore extra headers */ + } else { + int lost=0; + packet_no++; + if (loss_percent>0 && 100*((float)rand())/RAND_MAX 0) + { + /*printf ("chopping first packet\n");*/ + new_frame_size -= skip_samples+lookahead; + frame_offset = skip_samples+lookahead; + } + if (packet_no == page_nb_packets && skip_samples < 0) + { + int packet_length = nframes*frame_size+skip_samples+lookahead; + new_frame_size = packet_length - j*frame_size; + if (new_frame_size<0) + new_frame_size = 0; + if (new_frame_size>frame_size) + new_frame_size = frame_size; + /*printf ("chopping end: %d %d %d\n", new_frame_size, packet_length, packet_no);*/ + } + if (new_frame_size>0) + { +#if defined WIN32 || defined _WIN32 + if (strlen(outFile)==0) + WIN_Play_Samples (out+frame_offset*channels, sizeof(short) * new_frame_size*channels); + else +#endif + fwrite(out+frame_offset*channels, sizeof(short), new_frame_size*channels, fout); + + audio_size+=sizeof(short)*new_frame_size*channels; + } + } + } + } + packet_count++; + } + } + if (feof(fin)) + break; + + } + + if (fout && wav_format) + { + if (fseek(fout,4,SEEK_SET)==0) + { + int tmp; + tmp = le_int(audio_size+36); + fwrite(&tmp,4,1,fout); + if (fseek(fout,32,SEEK_CUR)==0) + { + tmp = le_int(audio_size); + fwrite(&tmp,4,1,fout); + } else + { + fprintf (stderr, "First seek worked, second didn't\n"); + } + } else { + fprintf (stderr, "Cannot seek on wave file, size will be incorrect\n"); + } + } + + if (st) + speex_decoder_destroy(st); + else + { + fprintf (stderr, "This doesn't look like a Speex file\n"); + } + speex_bits_destroy(&bits); + if (stream_init) + ogg_stream_clear(&os); + ogg_sync_clear(&oy); + +#if defined WIN32 || defined _WIN32 + if (strlen(outFile)==0) + WIN_Audio_close (); +#endif + + if (close_in) + fclose(fin); + if (fout != NULL) + fclose(fout); + + return 0; +}