Fixed the default int32 type which was wrong on amd64 (and added testcase).
Also, added an Ogg encoder (doesn't work quite yet).
This commit is contained in:
parent
eaab4b7121
commit
2fecbdf084
9 changed files with 1318 additions and 7 deletions
|
@ -15,9 +15,9 @@ lib_LTLIBRARIES = libcelt.la
|
||||||
|
|
||||||
# Sources for compilation in the library
|
# Sources for compilation in the library
|
||||||
libcelt_la_SOURCES = bands.c bitrdec.c bitree.c bitrenc.c celt.c cwrs.c \
|
libcelt_la_SOURCES = bands.c bitrdec.c bitree.c bitrenc.c celt.c cwrs.c \
|
||||||
ecintrin.h entcode.c entdec.c entenc.c fftwrap.c laplace.c mdct.c \
|
ecintrin.h entcode.c entdec.c entenc.c fftwrap.c header.c laplace.c mdct.c modes.c \
|
||||||
modes.c pitch.c psy.c quant_bands.c quant_pitch.c rangedec.c \
|
pitch.c psy.c quant_bands.c quant_pitch.c rangedec.c rangeenc.c rate.c \
|
||||||
rangeenc.c rate.c smallft.c vq.c
|
smallft.c vq.c
|
||||||
|
|
||||||
#noinst_HEADERS =
|
#noinst_HEADERS =
|
||||||
|
|
||||||
|
|
|
@ -158,8 +158,8 @@
|
||||||
/* Give up, take a reasonable guess */
|
/* Give up, take a reasonable guess */
|
||||||
typedef short celt_int16_t;
|
typedef short celt_int16_t;
|
||||||
typedef unsigned short celt_uint16_t;
|
typedef unsigned short celt_uint16_t;
|
||||||
typedef long celt_int32_t;
|
typedef int celt_int32_t;
|
||||||
typedef unsigned long celt_uint32_t;
|
typedef unsigned int celt_uint32_t;
|
||||||
typedef long long celt_int64_t;
|
typedef long long celt_int64_t;
|
||||||
typedef unsigned long long celt_uint64_t;
|
typedef unsigned long long celt_uint64_t;
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
INCLUDES = -I$(top_srcdir)/libcelt
|
INCLUDES = -I$(top_srcdir)/libcelt
|
||||||
METASOURCES = AUTO
|
METASOURCES = AUTO
|
||||||
|
|
||||||
TESTS = ectest cwrs32-test cwrs64-test
|
TESTS = type-test ectest cwrs32-test cwrs64-test
|
||||||
|
|
||||||
bin_PROGRAMS = ectest cwrs32-test cwrs64-test
|
bin_PROGRAMS = type-test ectest cwrs32-test cwrs64-test
|
||||||
|
|
||||||
|
ectest_SOURCES = type-test.c
|
||||||
|
ectest_LDADD = $(top_builddir)/libcelt/libcelt.la
|
||||||
|
|
||||||
ectest_SOURCES = ectest.c
|
ectest_SOURCES = ectest.c
|
||||||
ectest_LDADD = $(top_builddir)/libcelt/libcelt.la
|
ectest_LDADD = $(top_builddir)/libcelt/libcelt.la
|
||||||
|
|
24
tests/type-test.c
Normal file
24
tests/type-test.c
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#include "celt_types.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
celt_int16_t i = 1;
|
||||||
|
i <<= 14;
|
||||||
|
if (i>>14 != 1)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "celt_int16_t isn't 16 bits\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (sizeof(celt_int16_t)*2 != sizeof(celt_int32_t))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "16*2 != 32\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (sizeof(celt_int32_t)*2 != sizeof(celt_int64_t))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "32*2 != 64\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
720
tools/celtenc.c
Normal file
720
tools/celtenc.c
Normal file
|
@ -0,0 +1,720 @@
|
||||||
|
/* Copyright (C) 2002-2008 Jean-Marc Valin
|
||||||
|
File: celtenc.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 <stdio.h>
|
||||||
|
#if !defined WIN32 && !defined _WIN32
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_GETOPT_H
|
||||||
|
#include <getopt.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef HAVE_GETOPT_LONG
|
||||||
|
#include "getopt_win.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include "celt.h"
|
||||||
|
#include "celt_header.h"
|
||||||
|
#include <ogg/ogg.h>
|
||||||
|
#include "wav_io.h"
|
||||||
|
|
||||||
|
#if defined WIN32 || defined _WIN32
|
||||||
|
/* We need the following two to set stdout to binary */
|
||||||
|
#include <io.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "skeleton.h"
|
||||||
|
|
||||||
|
|
||||||
|
void comment_init(char **comments, int* length, char *vendor_string);
|
||||||
|
void comment_add(char **comments, int* length, char *tag, char *val);
|
||||||
|
|
||||||
|
|
||||||
|
/*Write an Ogg page to a file pointer*/
|
||||||
|
int oe_write_page(ogg_page *page, FILE *fp)
|
||||||
|
{
|
||||||
|
int written;
|
||||||
|
written = fwrite(page->header,1,page->header_len, fp);
|
||||||
|
written += fwrite(page->body,1,page->body_len, fp);
|
||||||
|
|
||||||
|
return written;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MAX_FRAME_SIZE 2000
|
||||||
|
#define MAX_FRAME_BYTES 2000
|
||||||
|
|
||||||
|
/* Convert input audio bits, endians and channels */
|
||||||
|
static int read_samples(FILE *fin,int frame_size, int bits, int channels, int lsb, short * input, char *buff, celt_int32_t *size)
|
||||||
|
{
|
||||||
|
unsigned char in[MAX_FRAME_BYTES*2];
|
||||||
|
int i;
|
||||||
|
short *s;
|
||||||
|
int nb_read;
|
||||||
|
|
||||||
|
if (size && *size<=0)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*Read input audio*/
|
||||||
|
if (size)
|
||||||
|
*size -= bits/8*channels*frame_size;
|
||||||
|
if (buff)
|
||||||
|
{
|
||||||
|
for (i=0;i<12;i++)
|
||||||
|
in[i]=buff[i];
|
||||||
|
nb_read = fread(in+12,1,bits/8*channels*frame_size-12, fin) + 12;
|
||||||
|
if (size)
|
||||||
|
*size += 12;
|
||||||
|
} else {
|
||||||
|
nb_read = fread(in,1,bits/8*channels* frame_size, fin);
|
||||||
|
}
|
||||||
|
nb_read /= bits/8*channels;
|
||||||
|
|
||||||
|
/*fprintf (stderr, "%d\n", nb_read);*/
|
||||||
|
if (nb_read==0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
s=(short*)in;
|
||||||
|
if(bits==8)
|
||||||
|
{
|
||||||
|
/* Convert 8->16 bits */
|
||||||
|
for(i=frame_size*channels-1;i>=0;i--)
|
||||||
|
{
|
||||||
|
s[i]=(in[i]<<8)^0x8000;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
/* convert to our endian format */
|
||||||
|
for(i=0;i<frame_size*channels;i++)
|
||||||
|
{
|
||||||
|
if(lsb)
|
||||||
|
s[i]=le_short(s[i]);
|
||||||
|
else
|
||||||
|
s[i]=be_short(s[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME: This is probably redundent now */
|
||||||
|
/* copy to float input buffer */
|
||||||
|
for (i=0;i<frame_size*channels;i++)
|
||||||
|
{
|
||||||
|
input[i]=(short)s[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i=nb_read*channels;i<frame_size*channels;i++)
|
||||||
|
{
|
||||||
|
input[i]=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return nb_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_fishead_packet (ogg_stream_state *os) {
|
||||||
|
|
||||||
|
fishead_packet fp;
|
||||||
|
|
||||||
|
memset(&fp, 0, sizeof(fp));
|
||||||
|
fp.ptime_n = 0;
|
||||||
|
fp.ptime_d = 1000;
|
||||||
|
fp.btime_n = 0;
|
||||||
|
fp.btime_d = 1000;
|
||||||
|
|
||||||
|
add_fishead_to_stream(os, &fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Adds the fishead packets in the skeleton output stream along with the e_o_s packet
|
||||||
|
*/
|
||||||
|
void add_fisbone_packet (ogg_stream_state *os, celt_int32_t serialno, CELTHeader *header) {
|
||||||
|
|
||||||
|
fisbone_packet fp;
|
||||||
|
|
||||||
|
memset(&fp, 0, sizeof(fp));
|
||||||
|
fp.serial_no = serialno;
|
||||||
|
fp.nr_header_packet = 2 + header->extra_headers;
|
||||||
|
fp.granule_rate_n = header->sample_rate;
|
||||||
|
fp.granule_rate_d = 1;
|
||||||
|
fp.start_granule = 0;
|
||||||
|
fp.preroll = 3;
|
||||||
|
fp.granule_shift = 0;
|
||||||
|
|
||||||
|
add_message_header_field(&fp, "Content-Type", "audio/x-celt");
|
||||||
|
|
||||||
|
add_fisbone_to_stream(os, &fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void version()
|
||||||
|
{
|
||||||
|
printf ("celtenc (CELT encoder)\n");
|
||||||
|
printf ("Copyright (C) 2008 Jean-Marc Valin\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void version_short()
|
||||||
|
{
|
||||||
|
printf ("celtenc (CELT encoder)\n");
|
||||||
|
printf ("Copyright (C) 2008 Jean-Marc Valin\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void usage()
|
||||||
|
{
|
||||||
|
printf ("Usage: celtenc [options] input_file output_file\n");
|
||||||
|
printf ("\n");
|
||||||
|
printf ("Encodes input_file using Speex. It can read the WAV or raw files.\n");
|
||||||
|
printf ("\n");
|
||||||
|
printf ("input_file can be:\n");
|
||||||
|
printf (" filename.wav wav file\n");
|
||||||
|
printf (" filename.* Raw PCM file (any extension other than .wav)\n");
|
||||||
|
printf (" - stdin\n");
|
||||||
|
printf ("\n");
|
||||||
|
printf ("output_file can be:\n");
|
||||||
|
printf (" filename.oga compressed file\n");
|
||||||
|
printf (" - stdout\n");
|
||||||
|
printf ("\n");
|
||||||
|
printf ("Options:\n");
|
||||||
|
printf (" --bitrate n Encoding bit-rate (use bit-rate n or lower)\n");
|
||||||
|
printf (" --skeleton Outputs ogg skeleton metadata (may cause incompatibilities)\n");
|
||||||
|
printf (" --comment Add the given string as an extra comment. This may be\n");
|
||||||
|
printf (" used multiple times\n");
|
||||||
|
printf (" --author Author of this track\n");
|
||||||
|
printf (" --title Title for this track\n");
|
||||||
|
printf (" -h, --help This help\n");
|
||||||
|
printf (" -v, --version Version information\n");
|
||||||
|
printf (" -V Verbose mode (show bit-rate)\n");
|
||||||
|
printf ("Raw input options:\n");
|
||||||
|
printf (" --rate n Sampling rate for raw input\n");
|
||||||
|
printf (" --stereo Consider raw input as stereo\n");
|
||||||
|
printf (" --le Raw input is little-endian\n");
|
||||||
|
printf (" --be Raw input is big-endian\n");
|
||||||
|
printf (" --8bit Raw input is 8-bit unsigned\n");
|
||||||
|
printf (" --16bit Raw input is 16-bit signed\n");
|
||||||
|
printf ("Default raw PCM input is 16-bit, little-endian, mono\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");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int nb_samples, total_samples=0, nb_encoded;
|
||||||
|
int c;
|
||||||
|
int option_index = 0;
|
||||||
|
char *inFile, *outFile;
|
||||||
|
FILE *fin, *fout;
|
||||||
|
short input[MAX_FRAME_SIZE];
|
||||||
|
celt_int32_t frame_size;
|
||||||
|
int quiet=0;
|
||||||
|
int nbBytes;
|
||||||
|
const CELTMode *mode=celt_mono;
|
||||||
|
int modeID = -1;
|
||||||
|
void *st;
|
||||||
|
char bits[MAX_FRAME_BYTES];
|
||||||
|
int with_skeleton = 0;
|
||||||
|
struct option long_options[] =
|
||||||
|
{
|
||||||
|
{"bitrate", required_argument, NULL, 0},
|
||||||
|
{"skeleton",no_argument,NULL, 0},
|
||||||
|
{"help", no_argument, NULL, 0},
|
||||||
|
{"quiet", no_argument, NULL, 0},
|
||||||
|
{"le", no_argument, NULL, 0},
|
||||||
|
{"be", no_argument, NULL, 0},
|
||||||
|
{"8bit", no_argument, NULL, 0},
|
||||||
|
{"16bit", no_argument, NULL, 0},
|
||||||
|
{"stereo", no_argument, NULL, 0},
|
||||||
|
{"rate", required_argument, NULL, 0},
|
||||||
|
{"version", no_argument, NULL, 0},
|
||||||
|
{"version-short", no_argument, NULL, 0},
|
||||||
|
{"comment", required_argument, NULL, 0},
|
||||||
|
{"author", required_argument, NULL, 0},
|
||||||
|
{"title", required_argument, NULL, 0},
|
||||||
|
{0, 0, 0, 0}
|
||||||
|
};
|
||||||
|
int print_bitrate=0;
|
||||||
|
celt_int32_t rate=0;
|
||||||
|
celt_int32_t size;
|
||||||
|
int chan=1;
|
||||||
|
int fmt=16;
|
||||||
|
int lsb=1;
|
||||||
|
ogg_stream_state os;
|
||||||
|
ogg_stream_state so; /* ogg stream for skeleton bitstream */
|
||||||
|
ogg_page og;
|
||||||
|
ogg_packet op;
|
||||||
|
int bytes_written=0, ret, result;
|
||||||
|
int id=-1;
|
||||||
|
CELTHeader header;
|
||||||
|
celt_int32_t complexity=3;
|
||||||
|
char vendor_string[64];
|
||||||
|
char *comments;
|
||||||
|
int comments_length;
|
||||||
|
int close_in=0, close_out=0;
|
||||||
|
int eos=0;
|
||||||
|
celt_int32_t bitrate=0;
|
||||||
|
double cumul_bits=0, enc_frames=0;
|
||||||
|
char first_bytes[12];
|
||||||
|
int wave_input=0;
|
||||||
|
celt_int32_t tmp;
|
||||||
|
celt_int32_t lookahead = 0;
|
||||||
|
int bytes_per_packet=48;
|
||||||
|
|
||||||
|
snprintf(vendor_string, sizeof(vendor_string), "Encoded with CELT\n");
|
||||||
|
|
||||||
|
comment_init(&comments, &comments_length, vendor_string);
|
||||||
|
|
||||||
|
/*Process command-line 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,"bitrate")==0)
|
||||||
|
{
|
||||||
|
bitrate = atoi (optarg);
|
||||||
|
} else if (strcmp(long_options[option_index].name,"skeleton")==0)
|
||||||
|
{
|
||||||
|
with_skeleton=1;
|
||||||
|
} else 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,"le")==0)
|
||||||
|
{
|
||||||
|
lsb=1;
|
||||||
|
} else if (strcmp(long_options[option_index].name,"be")==0)
|
||||||
|
{
|
||||||
|
lsb=0;
|
||||||
|
} else if (strcmp(long_options[option_index].name,"8bit")==0)
|
||||||
|
{
|
||||||
|
fmt=8;
|
||||||
|
} else if (strcmp(long_options[option_index].name,"16bit")==0)
|
||||||
|
{
|
||||||
|
fmt=16;
|
||||||
|
} else if (strcmp(long_options[option_index].name,"stereo")==0)
|
||||||
|
{
|
||||||
|
chan=2;
|
||||||
|
mode = celt_stereo;
|
||||||
|
} else if (strcmp(long_options[option_index].name,"rate")==0)
|
||||||
|
{
|
||||||
|
rate=atoi (optarg);
|
||||||
|
} else if (strcmp(long_options[option_index].name,"comment")==0)
|
||||||
|
{
|
||||||
|
if (!strchr(optarg, '='))
|
||||||
|
{
|
||||||
|
fprintf (stderr, "Invalid comment: %s\n", optarg);
|
||||||
|
fprintf (stderr, "Comments must be of the form name=value\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
comment_add(&comments, &comments_length, NULL, optarg);
|
||||||
|
} else if (strcmp(long_options[option_index].name,"author")==0)
|
||||||
|
{
|
||||||
|
comment_add(&comments, &comments_length, "author=", optarg);
|
||||||
|
} else if (strcmp(long_options[option_index].name,"title")==0)
|
||||||
|
{
|
||||||
|
comment_add(&comments, &comments_length, "title=", 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)
|
||||||
|
{
|
||||||
|
usage();
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
inFile=argv[optind];
|
||||||
|
outFile=argv[optind+1];
|
||||||
|
|
||||||
|
/*Initialize Ogg stream struct*/
|
||||||
|
srand(time(NULL));
|
||||||
|
if (ogg_stream_init(&os, rand())==-1)
|
||||||
|
{
|
||||||
|
fprintf(stderr,"Error: stream init failed\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (with_skeleton && ogg_stream_init(&so, rand())==-1)
|
||||||
|
{
|
||||||
|
fprintf(stderr,"Error: stream init failed\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(inFile, "-")==0)
|
||||||
|
{
|
||||||
|
#if defined WIN32 || defined _WIN32
|
||||||
|
_setmode(_fileno(stdin), _O_BINARY);
|
||||||
|
#elif defined OS2
|
||||||
|
_fsetmode(stdin,"b");
|
||||||
|
#endif
|
||||||
|
fin=stdin;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fin = fopen(inFile, "rb");
|
||||||
|
if (!fin)
|
||||||
|
{
|
||||||
|
perror(inFile);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
close_in=1;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
fread(first_bytes, 1, 12, fin);
|
||||||
|
if (strncmp(first_bytes,"RIFF",4)==0 && strncmp(first_bytes,"RIFF",4)==0)
|
||||||
|
{
|
||||||
|
if (read_wav_header(fin, &rate, &chan, &fmt, &size)==-1)
|
||||||
|
exit(1);
|
||||||
|
wave_input=1;
|
||||||
|
lsb=1; /* CHECK: exists big-endian .wav ?? */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
celt_mode_info(mode, CELT_GET_FRAME_SIZE, &frame_size);
|
||||||
|
celt_init_header(&header, rate, 1, mode);
|
||||||
|
header.nb_channels = chan;
|
||||||
|
|
||||||
|
{
|
||||||
|
char *st_string="mono";
|
||||||
|
if (chan==2)
|
||||||
|
st_string="stereo";
|
||||||
|
if (!quiet)
|
||||||
|
fprintf (stderr, "Encoding %d Hz audio using %s\n",
|
||||||
|
header.sample_rate, st_string);
|
||||||
|
}
|
||||||
|
/*fprintf (stderr, "Encoding %d Hz audio at %d bps using %s mode\n",
|
||||||
|
header.rate, mode->bitrate, mode->modeName);*/
|
||||||
|
|
||||||
|
/*Initialize Speex encoder*/
|
||||||
|
st = celt_encoder_new(mode);
|
||||||
|
|
||||||
|
if (strcmp(outFile,"-")==0)
|
||||||
|
{
|
||||||
|
#if defined WIN32 || defined _WIN32
|
||||||
|
_setmode(_fileno(stdout), _O_BINARY);
|
||||||
|
#endif
|
||||||
|
fout=stdout;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fout = fopen(outFile, "wb");
|
||||||
|
if (!fout)
|
||||||
|
{
|
||||||
|
perror(outFile);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
close_out=1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (with_skeleton) {
|
||||||
|
fprintf (stderr, "Warning: Enabling skeleton output may cause some decoders to fail.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* first packet should be the skeleton header. */
|
||||||
|
if (with_skeleton) {
|
||||||
|
add_fishead_packet(&so);
|
||||||
|
if ((ret = flush_ogg_stream_to_file(&so, fout))) {
|
||||||
|
fprintf (stderr,"Error: failed skeleton (fishead) header to output stream\n");
|
||||||
|
exit(1);
|
||||||
|
} else
|
||||||
|
bytes_written += ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Write header*/
|
||||||
|
{
|
||||||
|
char header_data[100];
|
||||||
|
int packet_size = celt_header_to_packet(&header, header_data, 100);
|
||||||
|
op.packet = header_data;
|
||||||
|
op.bytes = packet_size;
|
||||||
|
fprintf(stderr, "header size is %d\n", op.bytes);
|
||||||
|
op.b_o_s = 1;
|
||||||
|
op.e_o_s = 0;
|
||||||
|
op.granulepos = 0;
|
||||||
|
op.packetno = 0;
|
||||||
|
ogg_stream_packetin(&os, &op);
|
||||||
|
|
||||||
|
while((result = ogg_stream_flush(&os, &og)))
|
||||||
|
{
|
||||||
|
if(!result) break;
|
||||||
|
ret = oe_write_page(&og, fout);
|
||||||
|
if(ret != og.header_len + og.body_len)
|
||||||
|
{
|
||||||
|
fprintf (stderr,"Error: failed writing header to output stream\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
bytes_written += ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
op.packet = (unsigned char *)comments;
|
||||||
|
op.bytes = comments_length;
|
||||||
|
op.b_o_s = 0;
|
||||||
|
op.e_o_s = 0;
|
||||||
|
op.granulepos = 0;
|
||||||
|
op.packetno = 1;
|
||||||
|
ogg_stream_packetin(&os, &op);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fisbone packet should be write after all bos pages */
|
||||||
|
if (with_skeleton) {
|
||||||
|
add_fisbone_packet(&so, os.serialno, &header);
|
||||||
|
if ((ret = flush_ogg_stream_to_file(&so, fout))) {
|
||||||
|
fprintf (stderr,"Error: failed writing skeleton (fisbone )header to output stream\n");
|
||||||
|
exit(1);
|
||||||
|
} else
|
||||||
|
bytes_written += ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* writing the rest of the speex header packets */
|
||||||
|
while((result = ogg_stream_flush(&os, &og)))
|
||||||
|
{
|
||||||
|
if(!result) break;
|
||||||
|
ret = oe_write_page(&og, fout);
|
||||||
|
if(ret != og.header_len + og.body_len)
|
||||||
|
{
|
||||||
|
fprintf (stderr,"Error: failed writing header to output stream\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
bytes_written += ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(comments);
|
||||||
|
|
||||||
|
/* write the skeleton eos packet */
|
||||||
|
if (with_skeleton) {
|
||||||
|
add_eos_packet_to_stream(&so);
|
||||||
|
if ((ret = flush_ogg_stream_to_file(&so, fout))) {
|
||||||
|
fprintf (stderr,"Error: failed writing skeleton header to output stream\n");
|
||||||
|
exit(1);
|
||||||
|
} else
|
||||||
|
bytes_written += ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!wave_input)
|
||||||
|
{
|
||||||
|
nb_samples = read_samples(fin,frame_size,fmt,chan,lsb,input, first_bytes, NULL);
|
||||||
|
} else {
|
||||||
|
nb_samples = read_samples(fin,frame_size,fmt,chan,lsb,input, NULL, &size);
|
||||||
|
}
|
||||||
|
if (nb_samples==0)
|
||||||
|
eos=1;
|
||||||
|
total_samples += nb_samples;
|
||||||
|
nb_encoded = -lookahead;
|
||||||
|
/*Main encoding loop (one frame per iteration)*/
|
||||||
|
while (!eos || total_samples>nb_encoded)
|
||||||
|
{
|
||||||
|
id++;
|
||||||
|
/*Encode current frame*/
|
||||||
|
|
||||||
|
nbBytes = celt_encode(st, input, bits, bytes_per_packet);
|
||||||
|
|
||||||
|
nb_encoded += frame_size;
|
||||||
|
|
||||||
|
if (wave_input)
|
||||||
|
{
|
||||||
|
nb_samples = read_samples(fin,frame_size,fmt,chan,lsb,input, NULL, &size);
|
||||||
|
} else {
|
||||||
|
nb_samples = read_samples(fin,frame_size,fmt,chan,lsb,input, NULL, NULL);
|
||||||
|
}
|
||||||
|
if (nb_samples==0)
|
||||||
|
{
|
||||||
|
eos=1;
|
||||||
|
}
|
||||||
|
if (eos && total_samples<=nb_encoded)
|
||||||
|
op.e_o_s = 1;
|
||||||
|
else
|
||||||
|
op.e_o_s = 0;
|
||||||
|
total_samples += nb_samples;
|
||||||
|
|
||||||
|
op.packet = (unsigned char *)bits;
|
||||||
|
op.bytes = nbBytes;
|
||||||
|
op.b_o_s = 0;
|
||||||
|
/*Is this redundent?*/
|
||||||
|
if (eos && total_samples<=nb_encoded)
|
||||||
|
op.e_o_s = 1;
|
||||||
|
else
|
||||||
|
op.e_o_s = 0;
|
||||||
|
op.granulepos = (id+1)*frame_size-lookahead;
|
||||||
|
if (op.granulepos>total_samples)
|
||||||
|
op.granulepos = total_samples;
|
||||||
|
/*printf ("granulepos: %d %d %d %d %d %d\n", (int)op.granulepos, id, nframes, lookahead, 5, 6);*/
|
||||||
|
op.packetno = 2+id;
|
||||||
|
ogg_stream_packetin(&os, &op);
|
||||||
|
|
||||||
|
/*Write all new pages (most likely 0 or 1)*/
|
||||||
|
while (ogg_stream_pageout(&os,&og))
|
||||||
|
{
|
||||||
|
ret = oe_write_page(&og, fout);
|
||||||
|
if(ret != og.header_len + og.body_len)
|
||||||
|
{
|
||||||
|
fprintf (stderr,"Error: failed writing header to output stream\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
bytes_written += ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*Flush all pages left to be written*/
|
||||||
|
while (ogg_stream_flush(&os, &og))
|
||||||
|
{
|
||||||
|
ret = oe_write_page(&og, fout);
|
||||||
|
if(ret != og.header_len + og.body_len)
|
||||||
|
{
|
||||||
|
fprintf (stderr,"Error: failed writing header to output stream\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
bytes_written += ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
celt_encoder_destroy(st);
|
||||||
|
ogg_stream_clear(&os);
|
||||||
|
|
||||||
|
if (close_in)
|
||||||
|
fclose(fin);
|
||||||
|
if (close_out)
|
||||||
|
fclose(fout);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Comments will be stored in the Vorbis style.
|
||||||
|
It is describled in the "Structure" section of
|
||||||
|
http://www.xiph.org/ogg/vorbis/doc/v-comment.html
|
||||||
|
|
||||||
|
The comment header is decoded as follows:
|
||||||
|
1) [vendor_length] = read an unsigned integer of 32 bits
|
||||||
|
2) [vendor_string] = read a UTF-8 vector as [vendor_length] octets
|
||||||
|
3) [user_comment_list_length] = read an unsigned integer of 32 bits
|
||||||
|
4) iterate [user_comment_list_length] times {
|
||||||
|
5) [length] = read an unsigned integer of 32 bits
|
||||||
|
6) this iteration's user comment = read a UTF-8 vector as [length] octets
|
||||||
|
}
|
||||||
|
7) [framing_bit] = read a single bit as boolean
|
||||||
|
8) if ( [framing_bit] unset or end of packet ) then ERROR
|
||||||
|
9) done.
|
||||||
|
|
||||||
|
If you have troubles, please write to ymnk@jcraft.com.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define readint(buf, base) (((buf[base+3]<<24)&0xff000000)| \
|
||||||
|
((buf[base+2]<<16)&0xff0000)| \
|
||||||
|
((buf[base+1]<<8)&0xff00)| \
|
||||||
|
(buf[base]&0xff))
|
||||||
|
#define writeint(buf, base, val) do{ buf[base+3]=((val)>>24)&0xff; \
|
||||||
|
buf[base+2]=((val)>>16)&0xff; \
|
||||||
|
buf[base+1]=((val)>>8)&0xff; \
|
||||||
|
buf[base]=(val)&0xff; \
|
||||||
|
}while(0)
|
||||||
|
|
||||||
|
void comment_init(char **comments, int* length, char *vendor_string)
|
||||||
|
{
|
||||||
|
int vendor_length=strlen(vendor_string);
|
||||||
|
int user_comment_list_length=0;
|
||||||
|
int len=4+vendor_length+4;
|
||||||
|
char *p=(char*)malloc(len);
|
||||||
|
if(p==NULL){
|
||||||
|
fprintf (stderr, "malloc failed in comment_init()\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
writeint(p, 0, vendor_length);
|
||||||
|
memcpy(p+4, vendor_string, vendor_length);
|
||||||
|
writeint(p, 4+vendor_length, user_comment_list_length);
|
||||||
|
*length=len;
|
||||||
|
*comments=p;
|
||||||
|
}
|
||||||
|
void comment_add(char **comments, int* length, char *tag, char *val)
|
||||||
|
{
|
||||||
|
char* p=*comments;
|
||||||
|
int vendor_length=readint(p, 0);
|
||||||
|
int user_comment_list_length=readint(p, 4+vendor_length);
|
||||||
|
int tag_len=(tag?strlen(tag):0);
|
||||||
|
int val_len=strlen(val);
|
||||||
|
int len=(*length)+4+tag_len+val_len;
|
||||||
|
|
||||||
|
p=(char*)realloc(p, len);
|
||||||
|
if(p==NULL){
|
||||||
|
fprintf (stderr, "realloc failed in comment_add()\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
writeint(p, *length, tag_len+val_len); /* length of comment */
|
||||||
|
if(tag) memcpy(p+*length+4, tag, tag_len); /* comment */
|
||||||
|
memcpy(p+*length+4+tag_len, val, val_len); /* comment */
|
||||||
|
writeint(p, 4+vendor_length, user_comment_list_length+1);
|
||||||
|
|
||||||
|
*comments=p;
|
||||||
|
*length=len;
|
||||||
|
}
|
||||||
|
#undef readint
|
||||||
|
#undef writeint
|
188
tools/skeleton.c
Normal file
188
tools/skeleton.c
Normal file
|
@ -0,0 +1,188 @@
|
||||||
|
/*
|
||||||
|
* skeleton.c
|
||||||
|
* author: Tahseen Mohammad
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <ogg/ogg.h>
|
||||||
|
|
||||||
|
#include "skeleton.h"
|
||||||
|
|
||||||
|
/* write an ogg_page to a file pointer */
|
||||||
|
int write_ogg_page_to_file(ogg_page *og, FILE *out) {
|
||||||
|
int written;
|
||||||
|
|
||||||
|
written = fwrite(og->header,1, og->header_len, out);
|
||||||
|
written += fwrite(og->body,1, og->body_len, out);
|
||||||
|
|
||||||
|
return written;
|
||||||
|
}
|
||||||
|
|
||||||
|
int add_message_header_field(fisbone_packet *fp,
|
||||||
|
char *header_key,
|
||||||
|
char *header_value) {
|
||||||
|
|
||||||
|
/* size of both key and value + ': ' + CRLF */
|
||||||
|
int this_message_size = strlen(header_key) + strlen(header_value) + 4;
|
||||||
|
if (fp->message_header_fields == NULL) {
|
||||||
|
fp->message_header_fields = _ogg_calloc(this_message_size, sizeof(char));
|
||||||
|
} else {
|
||||||
|
int new_size = (fp->current_header_size + this_message_size) * sizeof(char);
|
||||||
|
fp->message_header_fields = _ogg_realloc(fp->message_header_fields, new_size);
|
||||||
|
}
|
||||||
|
snprintf(fp->message_header_fields + fp->current_header_size,
|
||||||
|
this_message_size+1,
|
||||||
|
"%s: %s\r\n",
|
||||||
|
header_key,
|
||||||
|
header_value);
|
||||||
|
fp->current_header_size += this_message_size;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create a ogg_packet from a fishead_packet structure */
|
||||||
|
ogg_packet ogg_from_fishead(fishead_packet *fp) {
|
||||||
|
|
||||||
|
ogg_packet op;
|
||||||
|
|
||||||
|
memset(&op, 0, sizeof(op));
|
||||||
|
op.packet = _ogg_calloc(FISHEAD_SIZE, sizeof(unsigned char));
|
||||||
|
memset(op.packet, 0, FISHEAD_SIZE);
|
||||||
|
|
||||||
|
memcpy (op.packet, FISHEAD_IDENTIFIER, 8); /* identifier */
|
||||||
|
*((ogg_uint16_t*)(op.packet+8)) = SKELETON_VERSION_MAJOR; /* version major */
|
||||||
|
*((ogg_uint16_t*)(op.packet+10)) = SKELETON_VERSION_MINOR; /* version minor */
|
||||||
|
*((ogg_int64_t*)(op.packet+12)) = (ogg_int64_t)fp->ptime_n; /* presentationtime numerator */
|
||||||
|
*((ogg_int64_t*)(op.packet+20)) = (ogg_int64_t)fp->ptime_d; /* presentationtime denominator */
|
||||||
|
*((ogg_int64_t*)(op.packet+28)) = (ogg_int64_t)fp->btime_n; /* basetime numerator */
|
||||||
|
*((ogg_int64_t*)(op.packet+36)) = (ogg_int64_t)fp->btime_d; /* basetime denominator */
|
||||||
|
/* TODO: UTC time, set to zero for now */
|
||||||
|
|
||||||
|
op.b_o_s = 1; /* its the first packet of the stream */
|
||||||
|
op.e_o_s = 0; /* its not the last packet of the stream */
|
||||||
|
op.bytes = FISHEAD_SIZE; /* length of the packet in bytes */
|
||||||
|
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create a ogg_packet from a fisbone_packet structure.
|
||||||
|
* call this method after the fisbone_packet is filled and all message header fields are added
|
||||||
|
* by calling add_message_header_field method.
|
||||||
|
*/
|
||||||
|
ogg_packet ogg_from_fisbone(fisbone_packet *fp) {
|
||||||
|
|
||||||
|
ogg_packet op;
|
||||||
|
int packet_size = FISBONE_SIZE + fp->current_header_size;
|
||||||
|
|
||||||
|
memset (&op, 0, sizeof (op));
|
||||||
|
op.packet = _ogg_calloc (packet_size, sizeof(unsigned char));
|
||||||
|
memset (op.packet, 0, packet_size);
|
||||||
|
memcpy (op.packet, FISBONE_IDENTIFIER, 8); /* identifier */
|
||||||
|
*((ogg_uint32_t*)(op.packet+8)) = FISBONE_MESSAGE_HEADER_OFFSET; /* offset of the message header fields */
|
||||||
|
*((ogg_uint32_t*)(op.packet+12)) = fp->serial_no; /* serialno of the respective stream */
|
||||||
|
*((ogg_uint32_t*)(op.packet+16)) = fp->nr_header_packet; /* number of header packets */
|
||||||
|
*((ogg_int64_t*)(op.packet+20)) = fp->granule_rate_n; /* granulrate numerator */
|
||||||
|
*((ogg_int64_t*)(op.packet+28)) = fp->granule_rate_d; /* granulrate denominator */
|
||||||
|
*((ogg_int64_t*)(op.packet+36)) = fp->start_granule; /* start granule */
|
||||||
|
*((ogg_uint32_t*)(op.packet+44)) = fp->preroll; /* preroll, for theora its 0 */
|
||||||
|
*(op.packet+48) = fp->granule_shift; /* granule shift */
|
||||||
|
memcpy((op.packet+FISBONE_SIZE), fp->message_header_fields, fp->current_header_size);
|
||||||
|
|
||||||
|
op.b_o_s = 0;
|
||||||
|
op.e_o_s = 0;
|
||||||
|
op.bytes = packet_size; /* size of the packet in bytes */
|
||||||
|
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fills up a fishead_packet from a fishead ogg_packet of a skeleton bistream */
|
||||||
|
fishead_packet fishead_from_ogg(ogg_packet *op) {
|
||||||
|
|
||||||
|
fishead_packet fp;
|
||||||
|
|
||||||
|
if (memcmp(op->packet, FISHEAD_IDENTIFIER, 8))
|
||||||
|
; /* invalid packet what do we do? */
|
||||||
|
|
||||||
|
fp.version_major = *((ogg_uint16_t*)(op->packet+8)); /* version major */
|
||||||
|
fp.version_minor = *((ogg_uint16_t*)(op->packet+10)); /* version minor */
|
||||||
|
fp.ptime_n = *((ogg_int64_t*)(op->packet+12)); /* presentationtime numerator */
|
||||||
|
fp.ptime_d = *((ogg_int64_t*)(op->packet+20)); /* presentationtime denominator */
|
||||||
|
fp.btime_n = *((ogg_int64_t*)(op->packet+28)); /* basetime numerator */
|
||||||
|
fp.btime_d = *((ogg_int64_t*)(op->packet+36)); /* basetime denominator */
|
||||||
|
memcpy(fp.UTC, op->packet+44, 20);
|
||||||
|
|
||||||
|
return fp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fills up a fisbone_packet from a fisbone ogg_packet of a skeleton bitstream */
|
||||||
|
fisbone_packet fisbone_from_ogg(ogg_packet *op) {
|
||||||
|
|
||||||
|
fisbone_packet fp;
|
||||||
|
|
||||||
|
if (memcmp(op->packet, FISBONE_IDENTIFIER, 8))
|
||||||
|
; /* invalid value, what do we do? */
|
||||||
|
fp.serial_no = *((ogg_uint32_t*)(op->packet+12)); /* serialno of the stream represented by this fisbone packet */
|
||||||
|
fp.nr_header_packet = *((ogg_uint32_t*)(op->packet+16)); /* number of header packets */
|
||||||
|
fp.granule_rate_n = *((ogg_int64_t*)(op->packet+20)); /* granulrate numerator */
|
||||||
|
fp.granule_rate_d = *((ogg_int64_t*)(op->packet+28)); /* granulrate denominator */
|
||||||
|
fp.start_granule = *((ogg_int64_t*)(op->packet+36)); /* start granule */
|
||||||
|
fp.preroll = *((ogg_uint32_t*)(op->packet+44)); /* preroll, for theora its 0 */
|
||||||
|
fp.granule_shift = *(op->packet+48); /* granule shift */
|
||||||
|
fp.current_header_size = op->bytes - FISBONE_SIZE;
|
||||||
|
fp.message_header_fields = _ogg_calloc(fp.current_header_size+1, sizeof(char));
|
||||||
|
memcpy(fp.message_header_fields, op->packet+FISBONE_SIZE, fp.current_header_size);
|
||||||
|
|
||||||
|
return fp;
|
||||||
|
}
|
||||||
|
|
||||||
|
int add_fishead_to_stream(ogg_stream_state *os, fishead_packet *fp) {
|
||||||
|
|
||||||
|
ogg_packet op;
|
||||||
|
|
||||||
|
op = ogg_from_fishead(fp);
|
||||||
|
ogg_stream_packetin(os, &op);
|
||||||
|
_ogg_free(op.packet);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int add_fisbone_to_stream(ogg_stream_state *os, fisbone_packet *fp) {
|
||||||
|
|
||||||
|
ogg_packet op;
|
||||||
|
|
||||||
|
op = ogg_from_fisbone(fp);
|
||||||
|
ogg_stream_packetin(os, &op);
|
||||||
|
_ogg_free(op.packet);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int add_eos_packet_to_stream(ogg_stream_state *os) {
|
||||||
|
|
||||||
|
ogg_packet op;
|
||||||
|
|
||||||
|
memset (&op, 0, sizeof(op));
|
||||||
|
op.e_o_s = 1;
|
||||||
|
ogg_stream_packetin(os, &op);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int flush_ogg_stream_to_file(ogg_stream_state *os, FILE *out) {
|
||||||
|
|
||||||
|
ogg_page og;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
while((result = ogg_stream_flush(os, &og)))
|
||||||
|
{
|
||||||
|
if(!result) break;
|
||||||
|
result = write_ogg_page_to_file(&og, out);
|
||||||
|
if(result != og.header_len + og.body_len)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
78
tools/skeleton.h
Normal file
78
tools/skeleton.h
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
/*
|
||||||
|
* skeleton.h
|
||||||
|
* author: Tahseen Mohammad
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _SKELETON_H
|
||||||
|
#define _SKELETON_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#define snprintf _snprintf
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <ogg/ogg.h>
|
||||||
|
|
||||||
|
#define SKELETON_VERSION_MAJOR 3
|
||||||
|
#define SKELETON_VERSION_MINOR 0
|
||||||
|
#define FISHEAD_IDENTIFIER "fishead\0"
|
||||||
|
#define FISBONE_IDENTIFIER "fisbone\0"
|
||||||
|
#define FISHEAD_SIZE 64
|
||||||
|
#define FISBONE_SIZE 52
|
||||||
|
#define FISBONE_MESSAGE_HEADER_OFFSET 44
|
||||||
|
|
||||||
|
/* fishead_packet holds a fishead header packet. */
|
||||||
|
typedef struct {
|
||||||
|
ogg_uint16_t version_major; /* skeleton version major */
|
||||||
|
ogg_uint16_t version_minor; /* skeleton version minor */
|
||||||
|
/* Start time of the presentation
|
||||||
|
* For a new stream presentationtime & basetime is same. */
|
||||||
|
ogg_int64_t ptime_n; /* presentation time numerator */
|
||||||
|
ogg_int64_t ptime_d; /* presentation time denominator */
|
||||||
|
ogg_int64_t btime_n; /* basetime numerator */
|
||||||
|
ogg_int64_t btime_d; /* basetime denominator */
|
||||||
|
/* will holds the time of origin of the stream, a 20 bit field. */
|
||||||
|
unsigned char UTC[20];
|
||||||
|
} fishead_packet;
|
||||||
|
|
||||||
|
/* fisbone_packet holds a fisbone header packet. */
|
||||||
|
typedef struct {
|
||||||
|
ogg_uint32_t serial_no; /* serial no of the corresponding stream */
|
||||||
|
ogg_uint32_t nr_header_packet; /* number of header packets */
|
||||||
|
/* granule rate is the temporal resolution of the logical bitstream */
|
||||||
|
ogg_int64_t granule_rate_n; /* granule rate numerator */
|
||||||
|
ogg_int64_t granule_rate_d; /* granule rate denominator */
|
||||||
|
ogg_int64_t start_granule; /* start granule value */
|
||||||
|
ogg_uint32_t preroll; /* preroll */
|
||||||
|
unsigned char granule_shift; /* 1 byte value holding the granule shift */
|
||||||
|
char *message_header_fields; /* holds all the message header fields */
|
||||||
|
/* current total size of the message header fields, for realloc purpose, initially zero */
|
||||||
|
ogg_uint32_t current_header_size;
|
||||||
|
} fisbone_packet;
|
||||||
|
|
||||||
|
extern int write_ogg_page_to_file(ogg_page *og, FILE *out);
|
||||||
|
extern int add_message_header_field(fisbone_packet *fp, char *header_key, char *header_value);
|
||||||
|
/* remember to deallocate the returned ogg_packet properly */
|
||||||
|
extern ogg_packet ogg_from_fishead(fishead_packet *fp);
|
||||||
|
extern ogg_packet ogg_from_fisbone(fisbone_packet *fp);
|
||||||
|
extern fishead_packet fishead_from_ogg(ogg_packet *op);
|
||||||
|
extern fisbone_packet fisbone_from_ogg(ogg_packet *op);
|
||||||
|
extern int add_fishead_to_stream(ogg_stream_state *os, fishead_packet *fp);
|
||||||
|
extern int add_fisbone_to_stream(ogg_stream_state *os, fisbone_packet *fp);
|
||||||
|
extern int add_eos_packet_to_stream(ogg_stream_state *os);
|
||||||
|
extern int flush_ogg_stream_to_file(ogg_stream_state *os, FILE *out);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _SKELETON_H */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
232
tools/wav_io.c
Normal file
232
tools/wav_io.c
Normal file
|
@ -0,0 +1,232 @@
|
||||||
|
/* Copyright (C) 2002 Jean-Marc Valin
|
||||||
|
File: wav_io.c
|
||||||
|
Routines to handle wav (RIFF) headers
|
||||||
|
|
||||||
|
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 <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "celt_types.h"
|
||||||
|
#include "wav_io.h"
|
||||||
|
|
||||||
|
|
||||||
|
int read_wav_header(FILE *file, int *rate, int *channels, int *format, celt_int32_t *size)
|
||||||
|
{
|
||||||
|
char ch[5];
|
||||||
|
celt_int32_t itmp;
|
||||||
|
celt_int16_t stmp;
|
||||||
|
celt_int32_t bpersec;
|
||||||
|
celt_int16_t balign;
|
||||||
|
int skip_bytes;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
ch[4]=0;
|
||||||
|
#if 0
|
||||||
|
fread(ch, 1, 4, file);
|
||||||
|
if (strcmp(ch, "RIFF")!=0)
|
||||||
|
{
|
||||||
|
fseek(file, 0, SEEK_SET);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fread(&itmp, 4, 1, file);
|
||||||
|
*size = le_int(itmp-36);
|
||||||
|
|
||||||
|
fread(ch, 1, 4, file);
|
||||||
|
if (strcmp(ch, "WAVE")!=0)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "RIFF file is not a WAVE file\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
fread(ch, 1, 4, file);
|
||||||
|
while (strcmp(ch, "fmt ")!=0)
|
||||||
|
{
|
||||||
|
fread(&itmp, 4, 1, file);
|
||||||
|
itmp = le_int(itmp);
|
||||||
|
/*fprintf (stderr, "skip=%d\n", itmp);*/
|
||||||
|
/*strange way of seeking, but it works even for pipes*/
|
||||||
|
for (i=0;i<itmp;i++)
|
||||||
|
fgetc(file);
|
||||||
|
/*fseek(file, itmp, SEEK_CUR);*/
|
||||||
|
fread(ch, 1, 4, file);
|
||||||
|
if (feof(file))
|
||||||
|
{
|
||||||
|
fprintf (stderr, "Corrupted WAVE file: no \"fmt \"\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*if (strcmp(ch, "fmt ")!=0)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "Corrupted WAVE file: no \"fmt \"\n");
|
||||||
|
return -1;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
fread(&itmp, 4, 1, file);
|
||||||
|
itmp = le_int(itmp);
|
||||||
|
skip_bytes=itmp-16;
|
||||||
|
/*fprintf (stderr, "skip=%d\n", skip_bytes);*/
|
||||||
|
|
||||||
|
fread(&stmp, 2, 1, file);
|
||||||
|
stmp = le_short(stmp);
|
||||||
|
if (stmp!=1)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "Only PCM encoding is supported\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fread(&stmp, 2, 1, file);
|
||||||
|
stmp = le_short(stmp);
|
||||||
|
*channels = stmp;
|
||||||
|
|
||||||
|
if (stmp>2)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "Only mono and (intensity) stereo supported\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fread(&itmp, 4, 1, file);
|
||||||
|
itmp = le_int(itmp);
|
||||||
|
*rate = itmp;
|
||||||
|
if (*rate != 8000 && *rate != 16000 && *rate != 11025 && *rate != 22050 && *rate != 32000 && *rate != 44100 && *rate != 48000)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "Only 8 kHz (narrowband) and 16 kHz (wideband) supported (plus 11.025 kHz and 22.05 kHz, but your mileage may vary)\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fread(&itmp, 4, 1, file);
|
||||||
|
bpersec = le_int(itmp);
|
||||||
|
|
||||||
|
fread(&stmp, 2, 1, file);
|
||||||
|
balign = le_short(stmp);
|
||||||
|
|
||||||
|
fread(&stmp, 2, 1, file);
|
||||||
|
stmp = le_short(stmp);
|
||||||
|
if (stmp!=16 && stmp!=8)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "Only 8/16-bit linear supported\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
*format=stmp;
|
||||||
|
|
||||||
|
if (bpersec!=*rate**channels*stmp/8)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "Corrupted header: ByteRate mismatch\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (balign!=*channels*stmp/8)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "Corrupted header: BlockAlign mismatch\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*strange way of seeking, but it works even for pipes*/
|
||||||
|
if (skip_bytes>0)
|
||||||
|
for (i=0;i<skip_bytes;i++)
|
||||||
|
fgetc(file);
|
||||||
|
|
||||||
|
/*fseek(file, skip_bytes, SEEK_CUR);*/
|
||||||
|
|
||||||
|
fread(ch, 1, 4, file);
|
||||||
|
while (strcmp(ch, "data")!=0)
|
||||||
|
{
|
||||||
|
fread(&itmp, 4, 1, file);
|
||||||
|
itmp = le_int(itmp);
|
||||||
|
/*strange way of seeking, but it works even for pipes*/
|
||||||
|
for (i=0;i<itmp;i++)
|
||||||
|
fgetc(file);
|
||||||
|
/*fseek(file, itmp, SEEK_CUR);*/
|
||||||
|
fread(ch, 1, 4, file);
|
||||||
|
if (feof(file))
|
||||||
|
{
|
||||||
|
fprintf (stderr, "Corrupted WAVE file: no \"data\"\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Ignore this for now*/
|
||||||
|
fread(&itmp, 4, 1, file);
|
||||||
|
itmp = le_int(itmp);
|
||||||
|
|
||||||
|
*size=itmp;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void write_wav_header(FILE *file, int rate, int channels, int format, int size)
|
||||||
|
{
|
||||||
|
char ch[5];
|
||||||
|
celt_int32_t itmp;
|
||||||
|
celt_int16_t stmp;
|
||||||
|
|
||||||
|
ch[4]=0;
|
||||||
|
|
||||||
|
fprintf (file, "RIFF");
|
||||||
|
|
||||||
|
itmp = 0x7fffffff;
|
||||||
|
fwrite(&itmp, 4, 1, file);
|
||||||
|
|
||||||
|
fprintf (file, "WAVEfmt ");
|
||||||
|
|
||||||
|
itmp = le_int(16);
|
||||||
|
fwrite(&itmp, 4, 1, file);
|
||||||
|
|
||||||
|
stmp = le_short(1);
|
||||||
|
fwrite(&stmp, 2, 1, file);
|
||||||
|
|
||||||
|
stmp = le_short(channels);
|
||||||
|
fwrite(&stmp, 2, 1, file);
|
||||||
|
|
||||||
|
itmp = le_int(rate);
|
||||||
|
fwrite(&itmp, 4, 1, file);
|
||||||
|
|
||||||
|
itmp = le_int(rate*channels*2);
|
||||||
|
fwrite(&itmp, 4, 1, file);
|
||||||
|
|
||||||
|
stmp = le_short(2*channels);
|
||||||
|
fwrite(&stmp, 2, 1, file);
|
||||||
|
|
||||||
|
stmp = le_short(16);
|
||||||
|
fwrite(&stmp, 2, 1, file);
|
||||||
|
|
||||||
|
fprintf (file, "data");
|
||||||
|
|
||||||
|
itmp = le_int(0x7fffffff);
|
||||||
|
fwrite(&itmp, 4, 1, file);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
66
tools/wav_io.h
Normal file
66
tools/wav_io.h
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
/* Copyright (C) 2002 Jean-Marc Valin
|
||||||
|
File: wav_io.h
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef WAV_IO_H
|
||||||
|
#define WAV_IO_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "celt_types.h"
|
||||||
|
|
||||||
|
#if !defined(__LITTLE_ENDIAN__) && ( defined(WORDS_BIGENDIAN) || defined(__BIG_ENDIAN__) )
|
||||||
|
#define le_short(s) ((short) ((unsigned short) (s) << 8) | ((unsigned short) (s) >> 8))
|
||||||
|
#define be_short(s) ((short) (s))
|
||||||
|
#else
|
||||||
|
#define le_short(s) ((short) (s))
|
||||||
|
#define be_short(s) ((short) ((unsigned short) (s) << 8) | ((unsigned short) (s) >> 8))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Convert little endian */
|
||||||
|
static inline celt_int32_t le_int(celt_int32_t i)
|
||||||
|
{
|
||||||
|
#if !defined(__LITTLE_ENDIAN__) && ( defined(WORDS_BIGENDIAN) || defined(__BIG_ENDIAN__) )
|
||||||
|
celt_uint32_t ui, ret;
|
||||||
|
ui = i;
|
||||||
|
ret = ui>>24;
|
||||||
|
ret |= (ui>>8)&0x0000ff00;
|
||||||
|
ret |= (ui<<8)&0x00ff0000;
|
||||||
|
ret |= (ui<<24);
|
||||||
|
return ret;
|
||||||
|
#else
|
||||||
|
return i;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int read_wav_header(FILE *file, int *rate, int *channels, int *format, celt_int32_t *size);
|
||||||
|
|
||||||
|
void write_wav_header(FILE *file, int rate, int channels, int format, int size);
|
||||||
|
|
||||||
|
#endif
|
Loading…
Add table
Add a link
Reference in a new issue