You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
687 lines
20 KiB
687 lines
20 KiB
14 years ago
|
/* Copyright (C) 2002-2003 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.
|
||
|
*/
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#if !defined WIN32 && !defined _WIN32
|
||
|
#include <unistd.h>
|
||
|
#include <getopt.h>
|
||
|
#endif
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
#include "speex.h"
|
||
|
#include "ogg/ogg.h"
|
||
|
|
||
|
#if defined WIN32 || defined _WIN32
|
||
|
#include <windows.h>
|
||
|
#include "getopt_win.h"
|
||
|
#include "wave_out.h"
|
||
|
/* We need the following two to set stdout to binary */
|
||
|
#include <io.h>
|
||
|
#include <fcntl.h>
|
||
|
#endif
|
||
|
#include <math.h>
|
||
|
|
||
|
#ifdef HAVE_SYS_SOUNDCARD_H
|
||
|
#include <sys/soundcard.h>
|
||
|
#include <sys/types.h>
|
||
|
#include <sys/stat.h>
|
||
|
#include <fcntl.h>
|
||
|
#include <sys/ioctl.h>
|
||
|
#endif
|
||
|
|
||
|
#include <string.h>
|
||
|
#include "wav_io.h"
|
||
|
#include "speex_header.h"
|
||
|
#include "speex_stereo.h"
|
||
|
#include "speex_callbacks.h"
|
||
|
#include "misc.h"
|
||
|
|
||
|
#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 (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;i<nb_fields;i++)
|
||
|
{
|
||
|
if (c+4>end)
|
||
|
{
|
||
|
fprintf (stderr, "Invalid/corrupted comments\n");
|
||
|
return;
|
||
|
}
|
||
|
len=readint(c, 0);
|
||
|
c+=4;
|
||
|
if (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 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);
|
||
|
#endif
|
||
|
fout=stdout;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
#if defined WIN32 || defined _WIN32
|
||
|
fout = fopen(outFile, "wb");
|
||
|
#else
|
||
|
fout = fopen(outFile, "w");
|
||
|
#endif
|
||
|
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()
|
||
|
{
|
||
|
printf ("speexdec (Speex decoder) version " VERSION " (compiled " __DATE__ ")\n");
|
||
|
printf ("Copyright (C) 2002-2003 Jean-Marc Valin\n");
|
||
|
}
|
||
|
|
||
|
void version_short()
|
||
|
{
|
||
|
printf ("speexdec version " VERSION "\n");
|
||
|
printf ("Copyright (C) 2002-2003 Jean-Marc Valin\n");
|
||
|
}
|
||
|
|
||
|
static void *process_header(ogg_packet *op, int enh_enabled, int *frame_size, int *rate, int *nframes, int forceMode, int *channels, SpeexStereoState *stereo, int *extra_headers)
|
||
|
{
|
||
|
void *st;
|
||
|
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)
|
||
|
{
|
||
|
fprintf (stderr, "Mode number %d does not (yet/any longer) exist in this version\n",
|
||
|
header->mode);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
modeID = header->mode;
|
||
|
if (forceMode!=-1)
|
||
|
modeID = forceMode;
|
||
|
mode = speex_mode_list[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);
|
||
|
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");
|
||
|
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");
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
st = speex_decoder_init(mode);
|
||
|
if (!st)
|
||
|
{
|
||
|
fprintf (stderr, "Decoder initialization failed.\n");
|
||
|
return NULL;
|
||
|
}
|
||
|
speex_decoder_ctl(st, SPEEX_SET_ENH, &enh_enabled);
|
||
|
speex_decoder_ctl(st, SPEEX_GET_FRAME_SIZE, frame_size);
|
||
|
|
||
|
if (!(*channels==1))
|
||
|
{
|
||
|
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 (!*rate)
|
||
|
*rate = header->rate;
|
||
|
/* Adjust rate if --force-* options are used */
|
||
|
if (forceMode!=-1)
|
||
|
{
|
||
|
if (header->mode < forceMode)
|
||
|
*rate <<= (forceMode - header->mode);
|
||
|
if (header->mode > forceMode)
|
||
|
*rate >>= (header->mode - forceMode);
|
||
|
}
|
||
|
|
||
|
speex_decoder_ctl(st, SPEEX_SET_SAMPLING_RATE, rate);
|
||
|
|
||
|
*nframes = header->frames_per_packet;
|
||
|
|
||
|
if (*channels==-1)
|
||
|
*channels = header->nb_channels;
|
||
|
|
||
|
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];
|
||
|
float output[MAX_FRAME_SIZE];
|
||
|
int frame_size=0;
|
||
|
void *st=NULL;
|
||
|
SpeexBits bits;
|
||
|
int packet_count=0;
|
||
|
int stream_init = 0;
|
||
|
struct option long_options[] =
|
||
|
{
|
||
|
{"help", 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;
|
||
|
int wav_format=0;
|
||
|
|
||
|
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,"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(inFile+strlen(inFile)-4,".WAV")==0);
|
||
|
/*Open input file*/
|
||
|
if (strcmp(inFile, "-")==0)
|
||
|
{
|
||
|
#if defined WIN32 || defined _WIN32
|
||
|
_setmode(_fileno(stdin), _O_BINARY);
|
||
|
#endif
|
||
|
fin=stdin;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
#if defined WIN32 || defined _WIN32
|
||
|
fin = fopen(inFile, "rb");
|
||
|
#else
|
||
|
fin = fopen(inFile, "r");
|
||
|
#endif
|
||
|
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)
|
||
|
{
|
||
|
if (stream_init == 0) {
|
||
|
ogg_stream_init(&os, ogg_page_serialno(&og));
|
||
|
stream_init = 1;
|
||
|
}
|
||
|
/*Add page to the bitstream*/
|
||
|
ogg_stream_pagein(&os, &og);
|
||
|
/*Extract all available packets*/
|
||
|
while (!eos && ogg_stream_packetout(&os, &op)==1)
|
||
|
{
|
||
|
/*If first packet, process as Speex header*/
|
||
|
if (packet_count==0)
|
||
|
{
|
||
|
st = process_header(&op, enh_enabled, &frame_size, &rate, &nframes, forceMode, &channels, &stereo, &extra_headers);
|
||
|
if (!nframes)
|
||
|
nframes=1;
|
||
|
if (!st)
|
||
|
exit(1);
|
||
|
fout = out_file_open(outFile, rate, &channels);
|
||
|
|
||
|
} else if (packet_count==1)
|
||
|
{
|
||
|
print_comments((char*)op.packet, op.bytes);
|
||
|
} else if (packet_count<=1+extra_headers)
|
||
|
{
|
||
|
/* Ignore extra headers */
|
||
|
} else {
|
||
|
|
||
|
int lost=0;
|
||
|
if (loss_percent>0 && 100*((float)rand())/RAND_MAX<loss_percent)
|
||
|
lost=1;
|
||
|
|
||
|
/*End of stream condition*/
|
||
|
if (op.e_o_s)
|
||
|
eos=1;
|
||
|
|
||
|
/*Copy Ogg packet to Speex bitstream*/
|
||
|
speex_bits_read_from(&bits, (char*)op.packet, op.bytes);
|
||
|
for (j=0;j!=nframes;j++)
|
||
|
{
|
||
|
int ret;
|
||
|
/*Decode frame*/
|
||
|
if (!lost)
|
||
|
ret = speex_decode(st, &bits, output);
|
||
|
else
|
||
|
ret = speex_decode(st, NULL, output);
|
||
|
|
||
|
if (ret==-1)
|
||
|
break;
|
||
|
if (ret==-2)
|
||
|
{
|
||
|
fprintf (stderr, "Decoding error: corrupted stream?\n");
|
||
|
break;
|
||
|
}
|
||
|
if (speex_bits_remaining(&bits)<0)
|
||
|
{
|
||
|
fprintf (stderr, "Decoding overflow: corrupted stream?\n");
|
||
|
break;
|
||
|
}
|
||
|
if (channels==2)
|
||
|
speex_decode_stereo(output, frame_size, &stereo);
|
||
|
|
||
|
if (print_bitrate) {
|
||
|
int tmp;
|
||
|
char ch=13;
|
||
|
speex_decoder_ctl(st, SPEEX_GET_BITRATE, &tmp);
|
||
|
fputc (ch, stderr);
|
||
|
fprintf (stderr, "Bitrate is use: %d bps ", tmp);
|
||
|
}
|
||
|
/*PCM saturation (just in case)*/
|
||
|
for (i=0;i<frame_size*channels;i++)
|
||
|
{
|
||
|
if (output[i]>32000.0)
|
||
|
output[i]=32000.0;
|
||
|
else if (output[i]<-32000.0)
|
||
|
output[i]=-32000.0;
|
||
|
}
|
||
|
/*Convert to short and save to output file*/
|
||
|
if (strlen(outFile)!=0)
|
||
|
{
|
||
|
for (i=0;i<frame_size*channels;i++)
|
||
|
out[i]=(short)le_short((short)floor(.5+output[i]));
|
||
|
} else {
|
||
|
for (i=0;i<frame_size*channels;i++)
|
||
|
out[i]=(short)floor(.5+output[i]);
|
||
|
}
|
||
|
#if defined WIN32 || defined _WIN32
|
||
|
if (strlen(outFile)==0)
|
||
|
WIN_Play_Samples (out, sizeof(short) * frame_size*channels);
|
||
|
else
|
||
|
#endif
|
||
|
fwrite(out, sizeof(short), frame_size*channels, fout);
|
||
|
|
||
|
audio_size+=sizeof(short)*frame_size*channels;
|
||
|
}
|
||
|
}
|
||
|
packet_count++;
|
||
|
}
|
||
|
}
|
||
|
if (feof(fin))
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
if (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;
|
||
|
}
|