[xiph-commits] r3341 - in libfishsound/branches/1.0-stable: .
include/fishsound src/examples src/libfishsound src/tests
conrad at svn.annodex.net
conrad at svn.annodex.net
Fri Jan 11 18:15:37 PST 2008
Author: conrad
Date: 2008-01-11 18:15:34 -0800 (Fri, 11 Jan 2008)
New Revision: 3341
Added:
libfishsound/branches/1.0-stable/src/libfishsound/flac.c
Modified:
libfishsound/branches/1.0-stable/config.h.in
libfishsound/branches/1.0-stable/configure.ac
libfishsound/branches/1.0-stable/include/fishsound/constants.h
libfishsound/branches/1.0-stable/src/examples/fishsound-decenc.c
libfishsound/branches/1.0-stable/src/examples/fishsound-encode.c
libfishsound/branches/1.0-stable/src/examples/fishsound-identify.c
libfishsound/branches/1.0-stable/src/libfishsound/Makefile.am
libfishsound/branches/1.0-stable/src/libfishsound/fishsound.c
libfishsound/branches/1.0-stable/src/libfishsound/private.h
libfishsound/branches/1.0-stable/src/tests/encdec-audio.c
Log:
Merge in changes from branches/1.0-stable-flac r3282:3340
Modified: libfishsound/branches/1.0-stable/config.h.in
===================================================================
--- libfishsound/branches/1.0-stable/config.h.in 2008-01-11 14:05:03 UTC (rev 3340)
+++ libfishsound/branches/1.0-stable/config.h.in 2008-01-12 02:15:34 UTC (rev 3341)
@@ -12,6 +12,9 @@
/* Define to 1 if you have the <dlfcn.h> header file. */
#undef HAVE_DLFCN_H
+/* Define to 1 if you have libFLAC */
+#undef HAVE_FLAC
+
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
Modified: libfishsound/branches/1.0-stable/configure.ac
===================================================================
--- libfishsound/branches/1.0-stable/configure.ac 2008-01-11 14:05:03 UTC (rev 3340)
+++ libfishsound/branches/1.0-stable/configure.ac 2008-01-12 02:15:34 UTC (rev 3341)
@@ -244,6 +244,37 @@
AM_CONDITIONAL(HAVE_SPEEX, [test "x$HAVE_SPEEX" = "xyes"])
dnl
+dnl Detect flac
+dnl
+
+HAVE_FLAC=no
+FLAC_SUPPORT=no
+
+ac_enable_flac=yes
+AC_ARG_ENABLE(flac,
+ [ --disable-flac enable building of Flac codec support ],
+ [ ac_enable_flac=no ], [ ac_enable_flac=yes] )
+
+if test "x${ac_enable_flac}" = xyes ; then
+ AC_CHECK_LIB(FLAC, FLAC__stream_decoder_init, HAVE_FLAC="maybe", , [-lm -logg])
+ if test "x$HAVE_FLAC" = xmaybe; then
+ AC_CHECK_HEADER(FLAC/all.h, HAVE_FLAC="yes", HAVE_FLAC="no")
+ fi
+ if test "x$HAVE_FLAC" = xyes ; then
+ AC_DEFINE(HAVE_FLAC, [1], [Define to 1 if you have libFLAC])
+ FLAC_LIBS="-lFLAC -logg -lm"
+ AC_SUBST(FLAC_LIBS)
+ FLAC_SUPPORT="yes"
+ else
+ AC_DEFINE(HAVE_FLAC, [0], [Define to 1 if you have libFLAC])
+ fi
+else
+ AC_DEFINE(HAVE_FLAC, [0], [Define to 1 if you have libFLAC])
+ FLAC_SUPPORT="disabled"
+fi
+AM_CONDITIONAL(HAVE_FLAC, [test "x$HAVE_FLAC" = "xyes"])
+
+dnl
dnl Check codec disabling sanity
dnl
if test "x${ac_enable_vorbis}" = xno && test "x${ac_enable_speex}" = xno ; then
@@ -358,6 +389,17 @@
])
fi
+if test "x$HAVE_FLAC" != xyes ; then
+ AC_MSG_RESULT(
+[*** libFLAC, available from http://flac.sourceforge.net/])
+fi
+if test "x$HAVE_FLAC" = xmaybe ; then
+ AC_MSG_RESULT(
+[ Development files missing: The libFLAC library binary seems to be
+ installed, but building of a test program failed.
+])
+fi
+
AC_MSG_RESULT(
[*** If you install the required libraries from source, you
*** need to inform the dynamic linker of their location. If
@@ -438,6 +480,7 @@
Vorbis support: .............. $VORBIS_SUPPORT
Speex support: ............... $SPEEX_SUPPORT
+ Flac support: ................ $FLAC_SUPPORT
Example programs (./src/examples):
Modified: libfishsound/branches/1.0-stable/include/fishsound/constants.h
===================================================================
--- libfishsound/branches/1.0-stable/include/fishsound/constants.h 2008-01-11 14:05:03 UTC (rev 3340)
+++ libfishsound/branches/1.0-stable/include/fishsound/constants.h 2008-01-12 02:15:34 UTC (rev 3341)
@@ -55,7 +55,10 @@
FISH_SOUND_VORBIS = 0x01,
/** Speex */
- FISH_SOUND_SPEEX = 0x02
+ FISH_SOUND_SPEEX = 0x02,
+
+ /** Flac */
+ FISH_SOUND_FLAC = 0x03
} FishSoundCodecID;
/** Decode callback return values */
Modified: libfishsound/branches/1.0-stable/src/examples/fishsound-decenc.c
===================================================================
--- libfishsound/branches/1.0-stable/src/examples/fishsound-decenc.c 2008-01-11 14:05:03 UTC (rev 3340)
+++ libfishsound/branches/1.0-stable/src/examples/fishsound-decenc.c 2008-01-12 02:15:34 UTC (rev 3341)
@@ -66,6 +66,7 @@
printf ("Options:\n");
printf (" --vorbis Use Vorbis as the output codec\n");
printf (" --speex Use Speex as the output codec\n");
+ printf (" --flac Use Flac as the output codec\n");
printf (" --interleave Use interleaved PCM internally\n");
exit (1);
}
@@ -224,6 +225,8 @@
format = FISH_SOUND_VORBIS;
} else if (!strcmp (argv[i], "--speex")) {
format = FISH_SOUND_SPEEX;
+ } else if (!strcmp (argv[i], "--flac")) {
+ format = FISH_SOUND_FLAC;
} else if (!strcmp (argv[i], "--interleave")) {
interleave = 1;
} else if (!strcmp (argv[i], "--help") || !strcmp (argv[i], "-h")) {
@@ -255,6 +258,15 @@
}
}
+ if (format == FISH_SOUND_FLAC) {
+ if (HAVE_FLAC) {
+ printf ("Using Flac as the output codec\n");
+ } else {
+ fprintf (stderr, "Error: Flac support disabled\n");
+ exit (1);
+ }
+ }
+
ed = fs_encdec_new (infilename, outfilename, format, interleave, blocksize);
while ((n = oggz_read (ed->oggz_in, 1024)) > 0)
Modified: libfishsound/branches/1.0-stable/src/examples/fishsound-encode.c
===================================================================
--- libfishsound/branches/1.0-stable/src/examples/fishsound-encode.c 2008-01-11 14:05:03 UTC (rev 3340)
+++ libfishsound/branches/1.0-stable/src/examples/fishsound-encode.c 2008-01-12 02:15:34 UTC (rev 3341)
@@ -42,6 +42,8 @@
#include <fishsound/fishsound.h>
#include <sndfile.h>
+#define ENCODE_BLOCK_SIZE (1152)
+
long serialno;
int b_o_s = 1;
@@ -56,7 +58,7 @@
op.bytes = bytes;
op.b_o_s = b_o_s;
op.e_o_s = 0;
- op.granulepos = 0; /* frameno */
+ op.granulepos = fish_sound_get_frameno (fsound);
op.packetno = -1;
err = oggz_write_feed (oggz, &op, serialno, 0, NULL);
@@ -107,6 +109,8 @@
ext = strrchr (outfilename, '.');
if (ext && !strncasecmp (ext, ".spx", 4))
format = FISH_SOUND_SPEEX;
+ else if (ext && !strncasecmp (ext, ".flc", 4))
+ format = FISH_SOUND_FLAC;
else
format = FISH_SOUND_VORBIS;
@@ -119,13 +123,13 @@
fish_sound_set_interleave (fsound, 1);
- while (sf_readf_float (sndfile, pcm, 1024) > 0) {
- fish_sound_encode (fsound, (float **)pcm, 1024);
- while ((n = oggz_write (oggz, 1024)) > 0);
+ while (sf_readf_float (sndfile, pcm, ENCODE_BLOCK_SIZE) > 0) {
+ fish_sound_encode (fsound, (float **)pcm, ENCODE_BLOCK_SIZE);
+ oggz_run (oggz);
}
fish_sound_flush (fsound);
- while ((n = oggz_write (oggz, 1024)) > 0);
+ oggz_run (oggz);
oggz_close (oggz);
Modified: libfishsound/branches/1.0-stable/src/examples/fishsound-identify.c
===================================================================
--- libfishsound/branches/1.0-stable/src/examples/fishsound-identify.c 2008-01-11 14:05:03 UTC (rev 3340)
+++ libfishsound/branches/1.0-stable/src/examples/fishsound-identify.c 2008-01-12 02:15:34 UTC (rev 3341)
@@ -52,6 +52,7 @@
switch (format) {
case FISH_SOUND_VORBIS: printf ("Vorbis\n"); break;
case FISH_SOUND_SPEEX: printf ("Speex\n"); break;
+ case FISH_SOUND_FLAC: printf ("Flac\n"); break;
default: printf ("Unknown\n");
}
Modified: libfishsound/branches/1.0-stable/src/libfishsound/Makefile.am
===================================================================
--- libfishsound/branches/1.0-stable/src/libfishsound/Makefile.am 2008-01-11 14:05:03 UTC (rev 3340)
+++ libfishsound/branches/1.0-stable/src/libfishsound/Makefile.am 2008-01-12 02:15:34 UTC (rev 3341)
@@ -22,7 +22,8 @@
comments.c \
speex.c \
vorbis.c \
+ flac.c \
fs_vector.c
libfishsound_la_LDFLAGS = -version-info @SHARED_VERSION_INFO@ @SHLIB_VERSION_ARG@
-libfishsound_la_LIBADD = $(VORBIS_LIBS) $(SPEEX_LIBS)
+libfishsound_la_LIBADD = $(VORBIS_LIBS) $(SPEEX_LIBS) $(FLAC_LIBS)
Modified: libfishsound/branches/1.0-stable/src/libfishsound/fishsound.c
===================================================================
--- libfishsound/branches/1.0-stable/src/libfishsound/fishsound.c 2008-01-11 14:05:03 UTC (rev 3340)
+++ libfishsound/branches/1.0-stable/src/libfishsound/fishsound.c 2008-01-12 02:15:34 UTC (rev 3341)
@@ -50,6 +50,9 @@
fish_sound_speex_identify (buf, bytes) != FISH_SOUND_UNKNOWN)
return FISH_SOUND_SPEEX;
+ if (fish_sound_flac_identify (buf, bytes) != FISH_SOUND_UNKNOWN)
+ return FISH_SOUND_FLAC;
+
return FISH_SOUND_UNKNOWN;
}
@@ -60,7 +63,9 @@
fsound->codec = fish_sound_vorbis_codec ();
} else if (format == FISH_SOUND_SPEEX) {
fsound->codec = fish_sound_speex_codec ();
- } else {
+ } else if (format == FISH_SOUND_FLAC) {
+ fsound->codec = fish_sound_flac_codec ();
+ } else {
return -1;
}
@@ -91,6 +96,9 @@
if (!HAVE_SPEEX) {
if (fsinfo->format == FISH_SOUND_SPEEX) return NULL;
}
+ if (!HAVE_FLAC) {
+ if (fsinfo->format == FISH_SOUND_FLAC) return NULL;
+ }
}
} else if (mode != FISH_SOUND_DECODE) {
return NULL;
Copied: libfishsound/branches/1.0-stable/src/libfishsound/flac.c (from rev 3340, libfishsound/branches/1.0-stable-flac/src/libfishsound/flac.c)
===================================================================
--- libfishsound/branches/1.0-stable/src/libfishsound/flac.c (rev 0)
+++ libfishsound/branches/1.0-stable/src/libfishsound/flac.c 2008-01-12 02:15:34 UTC (rev 3341)
@@ -0,0 +1,625 @@
+/*
+ Copyright (C) 2007 Annodex Association
+
+ 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 Annodex Association 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 ASSOCIATION 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.
+*/
+
+/* Original patches by Tobias Gehrig, 2005
+ * http://www.annodex.net/software/libfishsound/libfishsound-flac/
+ *
+ * The Ogg FLAC mapping is documented in:
+ * http://flac.sourceforge.net/ogg_mapping.html
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "private.h"
+#include "convert.h"
+
+/*#define DEBUG*/
+
+#if HAVE_FLAC
+
+#include "FLAC/all.h"
+
+#define BITS_PER_SAMPLE 24
+
+typedef struct _FishSoundFlacInfo {
+ FLAC__StreamDecoder *fsd;
+ FLAC__StreamEncoder *fse;
+ unsigned char * buffer;
+ char header;
+ long bufferlength;
+ unsigned long packetno;
+ struct {
+ unsigned char major, minor;
+ } version;
+ unsigned short header_packets;
+ void * ipcm;
+ float * pcm_out[8]; /* non-interleaved pcm, output (decode only);
+ * FLAC does max 8 channels */
+} FishSoundFlacInfo;
+
+int
+fish_sound_flac_identify (unsigned char * buf, long bytes)
+{
+ if (bytes < 8) return FISH_SOUND_UNKNOWN;
+ if (buf[0] != 0x7f) return FISH_SOUND_UNKNOWN;
+ if (!strncmp ((char *)buf+1, "FLAC", 4)) {
+#ifdef DEBUG
+ printf("fish_sound_flac_identify: flac found\n");
+#endif
+ /* if only a short buffer was passed, do a weak identify */
+ if (bytes == 8) return FISH_SOUND_FLAC;
+
+ /* otherwise, look for the fLaC header preceding STREAMINFO */
+ if (!strncmp ((char *)buf+9, "fLaC", 4)) {
+ return FISH_SOUND_FLAC;
+ }
+ }
+
+ return FISH_SOUND_UNKNOWN;
+}
+
+static int
+fs_flac_command (FishSound * fsound, int command, void * data, int datasize)
+{
+ return 0;
+}
+
+#if FS_DECODE
+static FLAC__StreamDecoderReadStatus
+fs_flac_read_callback(const FLAC__StreamDecoder *decoder,
+ FLAC__byte buffer[], unsigned *bytes,
+ void *client_data)
+{
+ FishSound* fsound = (FishSound*)client_data;
+ FishSoundFlacInfo* fi = (FishSoundFlacInfo *)fsound->codec_data;
+#ifdef DEBUG
+ printf("fs_flac_read_callback: IN\n");
+#endif
+ if (fi->bufferlength > *bytes) {
+#ifdef DEBUG
+ printf("fs_flac_read_callback: too much data\n");
+#endif
+ return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+ } else if (fi->bufferlength < 1) {
+#ifdef DEBUG
+ printf("fs_flac_read_callback: no data, %ld\n",fi->bufferlength);
+#endif
+ return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+ }
+
+ memcpy(buffer, fi->buffer, fi->bufferlength);
+ *bytes = fi->bufferlength;
+ fi->bufferlength = 0;
+ return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+}
+
+static FLAC__StreamDecoderWriteStatus
+fs_flac_write_callback(const FLAC__StreamDecoder *decoder,
+ const FLAC__Frame *frame,
+ const FLAC__int32 * const buffer[],
+ void *client_data)
+{
+ FishSound* fsound = (FishSound*)client_data;
+ FishSoundFlacInfo* fi = (FishSoundFlacInfo *)fsound->codec_data;
+ int i, j, channels, blocksize, offset;
+
+ channels = frame->header.channels;
+ blocksize = frame->header.blocksize;
+
+#ifdef DEBUG
+ printf("fs_flac_write_callback: IN, blocksize %d\n", blocksize);
+#endif
+
+ fsound->frameno += blocksize;
+
+ if (fsound->callback.decoded_float) {
+ float norm = 1.0 / ((1 << (frame->header.bits_per_sample - 1)));
+
+ if (fsound->interleave) {
+ FishSoundDecoded_FloatIlv dfi;
+ float* retpcm;
+
+ fi->ipcm = realloc(fi->ipcm, sizeof(float) * channels * blocksize);
+ retpcm = (float*) fi->ipcm;
+ for (i = 0; i < blocksize; i++) {
+ offset = i * channels;
+ for (j = 0; j < channels; j++)
+ retpcm[offset + j] = buffer[j][i] * norm;
+ }
+ dfi = (FishSoundDecoded_FloatIlv)fsound->callback.decoded_float_ilv;
+ dfi (fsound, (float **)retpcm, blocksize, fsound->user_data);
+ } else {
+ FishSoundDecoded_Float df;
+ FLAC__int32 * s = (FLAC__int32 *)buffer; /* de-interleave source */
+ float *d; /* de-interleave dest */
+
+ for (j = 0; j < channels; j++) {
+ fi->pcm_out[j] = realloc(fi->pcm_out[j], sizeof(float) * blocksize);
+ }
+ for (i = 0; i < blocksize; i++)
+ for (j = 0; j < channels; j++) {
+ d = fi->pcm_out[j];
+ d[i] = s[i*channels + j] * norm;
+ }
+ df = (FishSoundDecoded_Float)fsound->callback.decoded_float;
+ df (fsound, fi->pcm_out, blocksize, fsound->user_data);
+ }
+ }
+ return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+static void
+fs_flac_meta_callback(const FLAC__StreamDecoder *decoder,
+ const FLAC__StreamMetadata *metadata,
+ void *client_data)
+{
+ FishSound* fsound = (FishSound*)client_data;
+ /* FishSoundFlacInfo* fi = (FishSoundFlacInfo *)fsound->codec_data; */
+#ifdef DEBUG
+ printf("fs_flac_meta_callback: IN\n");
+#endif
+ switch (metadata->type) {
+ case FLAC__METADATA_TYPE_STREAMINFO:
+#ifdef DEBUG
+ printf("fs_flac_meta_callback: channels %d, samplerate %d\n",
+ metadata->data.stream_info.channels,
+ metadata->data.stream_info.sample_rate);
+#endif
+ fsound->info.channels = metadata->data.stream_info.channels;
+ fsound->info.samplerate = metadata->data.stream_info.sample_rate;
+ break;
+ default:
+#ifdef DEBUG
+ printf("fs_flac_meta_callback: not yet implemented type\n");
+#endif
+ break;
+ }
+}
+
+static void
+fs_flac_error_callback(const FLAC__StreamDecoder *decoder,
+ FLAC__StreamDecoderErrorStatus status,
+ void *client_data)
+{
+#ifdef DEBUG
+ printf("fs_flac_error_callback: IN\n");
+#endif
+ fprintf(stderr, "FLAC ERROR: %s\n", FLAC__StreamDecoderErrorStatusString[status]);
+}
+#endif
+#if FS_DECODE
+static void*
+fs_flac_decode_header (FishSound * fsound, unsigned char *buf, long bytes)
+{
+ FishSoundFlacInfo *fi = fsound->codec_data;
+ if (buf[0] != 0x7f) return NULL;
+ if (strncmp((char *)buf+1, "FLAC", 4) != 0) return NULL;
+ fi->version.major = buf[5];
+ fi->version.minor = buf[6];
+#ifdef DEBUG
+ printf("fs_flac_decode_header : Flac Ogg Mapping Version: %d.%d\n",
+ fi->version.major, fi->version.minor);
+#endif
+ fi->header_packets = buf[7] << 8 | buf[8];
+#ifdef DEBUG
+ printf("fs_flac_decode_header: Number of Header packets: %d\n",
+ fi->header_packets);
+#endif
+
+ if ((fi->fsd = FLAC__stream_decoder_new()) == NULL) {
+#ifdef DEBUG
+ printf ("fs_flac_decode_header: unable to create new stream_decoder\n");
+#endif
+ return NULL;
+ }
+
+ FLAC__stream_decoder_set_read_callback(fi->fsd, fs_flac_read_callback);
+ FLAC__stream_decoder_set_write_callback(fi->fsd, fs_flac_write_callback);
+ FLAC__stream_decoder_set_metadata_callback(fi->fsd, fs_flac_meta_callback);
+ FLAC__stream_decoder_set_error_callback(fi->fsd, fs_flac_error_callback);
+ FLAC__stream_decoder_set_client_data(fi->fsd, fsound);
+
+ if (FLAC__stream_decoder_init(fi->fsd) != FLAC__STREAM_DECODER_SEARCH_FOR_METADATA)
+ return NULL;
+
+ return fi->fsd;
+}
+
+static long
+fs_flac_decode (FishSound * fsound, unsigned char * buf, long bytes)
+{
+ FishSoundFlacInfo *fi = fsound->codec_data;
+
+#ifdef DEBUG
+ printf("fs_flac_decode: IN, fi->packetno = %ld\n", fi->packetno);
+#endif
+
+ if (fi->packetno == 0) {
+ if (fs_flac_decode_header (fsound, buf, bytes) == NULL) {
+#ifdef DEBUG
+ printf("fs_flac_decode: Error reading header\n");
+#endif
+ return -1;
+ }
+ fi->buffer = fs_malloc(sizeof(unsigned char)*bytes);
+ memcpy(fi->buffer, buf+9, bytes-9);
+ fi->bufferlength = bytes-9;
+ }
+ else if (fi->packetno <= fi->header_packets){
+ unsigned char* tmp = fs_malloc(sizeof(unsigned char)*(fi->bufferlength+bytes));
+#ifdef DEBUG
+ printf("fs_flac_decode: handling header (fi->header_packets = %d)\n",
+ fi->header_packets);
+#endif
+
+#if 0
+ if (fi->packetno == 1) fish_sound_comments_decode (fsound, buf, bytes);
+#endif
+
+ memcpy(tmp, fi->buffer, fi->bufferlength);
+ memcpy(tmp+fi->bufferlength, buf, bytes);
+ fi->bufferlength += bytes;
+ fs_free(fi->buffer);
+ fi->buffer = tmp;
+ if (fi->packetno == fi->header_packets) {
+ FLAC__stream_decoder_process_until_end_of_metadata(fi->fsd);
+ fs_free(fi->buffer);
+ }
+ } else {
+ fi->buffer = buf;
+ fi->bufferlength = bytes;
+ FLAC__stream_decoder_process_single(fi->fsd);
+ }
+ fi->packetno++;
+
+ return 0;
+}
+#else /* !FS_DECODE */
+
+#define fs_flac_decode NULL
+
+#endif
+
+
+#if FS_ENCODE
+static FLAC__StreamEncoderWriteStatus
+fs_flac_enc_write_callback(const FLAC__StreamEncoder *encoder,
+ const FLAC__byte buffer[], unsigned bytes,
+ unsigned samples, unsigned current_frame,
+ void *client_data)
+{
+ FishSound* fsound = (FishSound*)client_data;
+ FishSoundFlacInfo *fi = fsound->codec_data;
+#ifdef DEBUG
+ printf("fs_flac_enc_write_callback: IN\n");
+ printf("fs_flac_enc_write_callback: bytes: %d, samples: %d\n", bytes, samples);
+#endif
+ if (fsound->callback.encoded) {
+ FishSoundEncoded encoded = (FishSoundEncoded) fsound->callback.encoded;
+ if (fi->packetno == 0 && fi->header <= 1) {
+ if (fi->header == 0) {
+ /* libFLAC has called us with data containing the normal fLaC header
+ * and a STREAMINFO block. Prepend the FLAC Ogg mapping header,
+ * as described in http://flac.sourceforge.net/ogg_mapping.html.
+ */
+#ifdef DEBUG
+ printf("fs_flac_enc_write_callback: generating FLAC header packet: "
+ "%c%c%c%c\n", buffer[0], buffer[1], buffer[2], buffer[3]);
+#endif
+ fi->buffer = (unsigned char*)malloc(sizeof(unsigned char)*(bytes+9));
+ fi->buffer[0] = 0x7f;
+ fi->buffer[1] = 0x46; /* 'F' */
+ fi->buffer[2] = 0x4c; /* 'L' */
+ fi->buffer[3] = 0x41; /* 'A' */
+ fi->buffer[4] = 0x43; /* 'C' */
+ fi->buffer[5] = 1; /* Version major generated by this file */
+ fi->buffer[6] = 0; /* Version minor generated by this file */
+ fi->buffer[7] = 0; /* MSB(be): Nr. other non-audio header packets */
+ fi->buffer[8] = 1; /* LSB(be): Nr. other non-audio header packets */
+ memcpy (fi->buffer+9, buffer, bytes); /* fLaC header ++ STREAMINFO */
+ fi->bufferlength = bytes+9;
+ fi->header++;
+ } else {
+ /* Make a temporary copy of the metadata header to pass to the user
+ * callback.
+ */
+ unsigned char* tmp = (unsigned char*)malloc(sizeof(unsigned char)*(bytes+fi->bufferlength));
+ memcpy (tmp, fi->buffer, fi->bufferlength);
+ memcpy (tmp+fi->bufferlength, buffer, bytes);
+ fs_free(fi->buffer);
+ fi->buffer = tmp;
+ fi->bufferlength += bytes;
+ fi->header++;
+ encoded (fsound, (unsigned char *)fi->buffer, (long)fi->bufferlength,
+ fsound->user_data);
+ }
+ } else {
+ fsound->frameno += samples;
+ encoded (fsound, (unsigned char *)buffer, (long)bytes,
+ fsound->user_data);
+ }
+ }
+
+ return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
+}
+
+static void
+fs_flac_enc_meta_callback(const FLAC__StreamEncoder *encoder,
+ const FLAC__StreamMetadata *metadata,
+ void *client_data)
+{
+ /* FishSound* fsound = (FishSound*)client_data; */
+ /* FishSoundFlacInfo* fi = (FishSoundFlacInfo *)fsound->codec_data; */
+#ifdef DEBUG
+ printf("fs_flac_enc_meta_callback: IN\n");
+#endif
+ switch (metadata->type) {
+ case FLAC__METADATA_TYPE_STREAMINFO:
+#ifdef DEBUG
+ printf("fs_flac_enc_meta_callback: channels %d, samplerate %d\n",
+ metadata->data.stream_info.channels,
+ metadata->data.stream_info.sample_rate);
+#endif
+ /*
+ fsound->info.channels = metadata->data.stream_info.channels;
+ fsound->info.samplerate = metadata->data.stream_info.sample_rate;
+ */
+ break;
+ default:
+#ifdef DEBUG
+ printf("fs_flac_enc_meta_callback: metadata type not yet implemented\n");
+#endif
+ break;
+ }
+
+ return;
+}
+
+static FishSound *
+fs_flac_enc_headers (FishSound * fsound)
+{
+ FishSoundFlacInfo *fi = fsound->codec_data;
+ fi->fse = FLAC__stream_encoder_new();
+ FLAC__stream_encoder_set_channels(fi->fse, fsound->info.channels);
+ FLAC__stream_encoder_set_sample_rate(fi->fse, fsound->info.samplerate);
+ FLAC__stream_encoder_set_bits_per_sample(fi->fse, BITS_PER_SAMPLE);
+ FLAC__stream_encoder_set_write_callback(fi->fse, fs_flac_enc_write_callback);
+ FLAC__stream_encoder_set_metadata_callback(fi->fse, fs_flac_enc_meta_callback);
+ FLAC__stream_encoder_set_client_data(fi->fse, fsound);
+ /* FLAC__stream_encoder_set_total_samples_estimate(fi->fse, ...);*/
+ if (FLAC__stream_encoder_init(fi->fse) != FLAC__STREAM_ENCODER_OK)
+ return NULL;
+ return fsound;
+}
+
+static long
+fs_flac_encode_f (FishSound * fsound, float * pcm[], long frames)
+{
+ FishSoundFlacInfo *fi = fsound->codec_data;
+ FLAC__int32 *buffer;
+ float * p, norm = (1 << (BITS_PER_SAMPLE - 1));
+ long i;
+ int j, channels = fsound->info.channels;
+
+#ifdef DEBUG
+ printf("fs_flac_encode_f: IN, frames = %ld\n", frames);
+#endif
+
+ fi->ipcm = realloc(fi->ipcm, sizeof(FLAC__int32) * channels * frames);
+ buffer = (FLAC__int32*) fi->ipcm;
+ for (i = 0; i < frames; i++) {
+ for (j = 0; j < channels; j++) {
+ p = pcm[j];
+ buffer[i*channels + j] = (FLAC__int32) (p[i] * norm);
+ }
+ }
+
+ if (fi->packetno == 0)
+ fs_flac_enc_headers (fsound);
+
+ /* We could have used FLAC__stream_encoder_process() and a more direct
+ * conversion loop above, rather than converting and interleaving. */
+ FLAC__stream_encoder_process_interleaved(fi->fse, buffer, frames);
+
+ fi->packetno++;
+
+ return frames;
+}
+
+static long
+fs_flac_encode_f_ilv (FishSound * fsound, float ** pcm, long frames)
+{
+ FishSoundFlacInfo *fi = fsound->codec_data;
+ FLAC__int32 *buffer;
+ float * p = (float*)pcm, norm = (1 << (BITS_PER_SAMPLE - 1));
+ long i, length = frames * fsound->info.channels;
+
+#ifdef DEBUG
+ printf("fs_flac_encode_f_ilv: IN, frames = %ld\n", frames);
+#endif
+
+ fi->ipcm = realloc(fi->ipcm, sizeof(FLAC__int32)*fsound->info.channels*frames);
+ buffer = (FLAC__int32*) fi->ipcm;
+ for (i=0; i<length; i++)
+ buffer[i] = p[i] * norm;
+
+ if (fi->packetno == 0)
+ fs_flac_enc_headers (fsound);
+
+ FLAC__stream_encoder_process_interleaved(fi->fse, buffer, frames);
+
+ fi->packetno++;
+
+ return frames;
+}
+#else /* ! FS_ENCODE */
+
+#define fs_flac_encode_f NULL
+#define fs_flac_encode_f_ilv NULL
+
+#endif /* ! FS_ENCODE */
+
+
+static FishSound *
+fs_flac_delete (FishSound * fsound)
+{
+ FishSoundFlacInfo * fi = (FishSoundFlacInfo *)fsound->codec_data;
+ int i;
+
+#ifdef DEBUG
+ printf("fs_flac_delete: IN\n");
+#endif
+
+ if (fsound->mode == FISH_SOUND_DECODE) {
+ FLAC__stream_decoder_finish(fi->fsd);
+ FLAC__stream_decoder_delete(fi->fsd);
+ } else if (fsound->mode == FISH_SOUND_ENCODE) {
+ FLAC__stream_encoder_finish(fi->fse);
+ FLAC__stream_encoder_delete(fi->fse);
+ if (fi->buffer) fs_free(fi->buffer);
+ }
+
+ if (fi->ipcm) fs_free(fi->ipcm);
+ for (i = 0; i < 8; i++) {
+ if (fi->pcm_out[i]) fs_free (fi->pcm_out[i]);
+ }
+
+ fs_free (fi);
+ fsound->codec_data = NULL;
+
+ return fsound;
+}
+
+static int
+fs_flac_update (FishSound * fsound, int interleave)
+{
+ return 0;
+}
+
+static int
+fs_flac_reset (FishSound * fsound)
+{
+ /*FishSoundFlacInfo * fi = (FishSoundFlacInfo *)fsound->codec_data;*/
+#if 0
+ if (fsound->mode == FISH_SOUND_DECODE) {
+ FLAC__stream_decoder_reset(fi->fsd);
+ } else if (fsound->mode == FISH_SOUND_ENCODE) {
+ }
+#endif
+ return 0;
+}
+
+static long
+fs_flac_flush (FishSound * fsound)
+{
+ FishSoundFlacInfo * fi = (FishSoundFlacInfo *)fsound->codec_data;
+
+#ifdef DEBUG
+ printf("fs_flac_flush: IN (%s)\n",
+ fsound->mode == FISH_SOUND_DECODE ? "decode" : "encode");
+#endif
+
+ if (fsound->mode == FISH_SOUND_DECODE) {
+ FLAC__stream_decoder_finish(fi->fsd);
+ } else if (fsound->mode == FISH_SOUND_ENCODE) {
+ FLAC__stream_encoder_finish(fi->fse);
+ }
+
+ return 0;
+}
+
+static FishSound *
+fs_flac_init (FishSound * fsound)
+{
+ FishSoundFlacInfo *fi;
+ int i;
+
+ fi = fs_malloc (sizeof (FishSoundFlacInfo));
+ if (fi == NULL) return NULL;
+ fi->packetno = 0;
+ fi->header = 0;
+ fi->header_packets = 0;
+ fi->fsd = NULL;
+ fi->fse = NULL;
+
+ fi->ipcm = NULL;
+ for (i = 0; i < 8; i++) {
+ fi->pcm_out[i] = NULL;
+ }
+
+ fsound->codec_data = fi;
+
+ return fsound;
+}
+
+FishSoundCodec *
+fish_sound_flac_codec (void)
+{
+ FishSoundCodec * codec;
+
+ codec = (FishSoundCodec *) fs_malloc (sizeof (FishSoundCodec));
+
+ codec->format.format = FISH_SOUND_FLAC;
+ codec->format.name = "Flac (Xiph.Org)";
+ codec->format.extension = "ogg";
+
+ codec->init = fs_flac_init;
+ codec->del = fs_flac_delete;
+ codec->reset = fs_flac_reset;
+ codec->update = fs_flac_update;
+ codec->command = fs_flac_command;
+ codec->decode = fs_flac_decode;
+ codec->encode_f = fs_flac_encode_f;
+ codec->encode_f_ilv = fs_flac_encode_f_ilv;
+ codec->flush = fs_flac_flush;
+
+ return codec;
+}
+
+#else /* !HAVE_FLAC */
+
+int
+fish_sound_flac_identify (unsigned char * buf, long bytes)
+{
+ return FISH_SOUND_UNKNOWN;
+}
+
+FishSoundCodec *
+fish_sound_flac_codec (void)
+{
+ return NULL;
+}
+
+#endif
Modified: libfishsound/branches/1.0-stable/src/libfishsound/private.h
===================================================================
--- libfishsound/branches/1.0-stable/src/libfishsound/private.h 2008-01-11 14:05:03 UTC (rev 3340)
+++ libfishsound/branches/1.0-stable/src/libfishsound/private.h 2008-01-12 02:15:34 UTC (rev 3341)
@@ -100,7 +100,7 @@
union FishSoundCallback {
FishSoundDecoded_Float decoded_float;
FishSoundDecoded_FloatIlv decoded_float_ilv;
- FishSoundEncoded * encoded;
+ FishSoundEncoded encoded;
};
struct _FishSound {
@@ -160,6 +160,9 @@
int fish_sound_speex_identify (unsigned char * buf, long bytes);
FishSoundCodec * fish_sound_speex_codec (void);
+int fish_sound_flac_identify (unsigned char * buf, long bytes);
+FishSoundCodec * fish_sound_flac_codec (void);
+
/* comments */
int fish_sound_comments_init (FishSound * fsound);
int fish_sound_comments_free (FishSound * fsound);
Modified: libfishsound/branches/1.0-stable/src/tests/encdec-audio.c
===================================================================
--- libfishsound/branches/1.0-stable/src/tests/encdec-audio.c 2008-01-11 14:05:03 UTC (rev 3340)
+++ libfishsound/branches/1.0-stable/src/tests/encdec-audio.c 2008-01-12 02:15:34 UTC (rev 3341)
@@ -53,6 +53,7 @@
printf (" --nasty Run with large test parameters\n");
printf (" --disable-vorbis Disable testing of Vorbis codec\n");
printf (" --disable-speex Disable testing of Speex codec\n");
+ printf (" --disable-flac Disable testing of Flac codec\n");
printf (" --disable-interleave Disable testing of interleave\n");
printf (" --disable-non-interleave Disable testing of non-interleave\n");
exit (1);
@@ -61,7 +62,7 @@
/* For one-time tests, configure these by commandline args */
static int * test_blocksizes, * test_samplerates, * test_channels;
static int iter = DEFAULT_ITER;
-static int test_vorbis = HAVE_VORBIS, test_speex = HAVE_SPEEX;
+static int test_vorbis = HAVE_VORBIS, test_speex = HAVE_SPEEX, test_flac = HAVE_FLAC;
static int test_interleave = 1, test_non_interleave = 1;
static int nasty_blocksizes[] = {128, 256, 512, 1024, 2048, 4096, 0};
@@ -97,7 +98,7 @@
static int
decoded_float_ilv (FishSound * fsound, float * pcm[], long frames,
- void * user_data)
+ void * user_data)
{
FS_EncDec * ed = (FS_EncDec *) user_data;
@@ -132,7 +133,7 @@
static FS_EncDec *
fs_encdec_new (int samplerate, int channels, int format, int interleave,
- int blocksize)
+ int blocksize)
{
FS_EncDec * ed;
FishSoundInfo fsinfo;
@@ -199,7 +200,7 @@
static int
fs_encdec_test (int samplerate, int channels, int format, int interleave,
- int blocksize)
+ int blocksize)
{
FS_EncDec * ed;
char msg[128];
@@ -207,11 +208,11 @@
long expected_frames;
snprintf (msg, 128,
- "+ %2d channel %6d Hz %s, %d frame buffer (%s)",
- channels, samplerate,
- format == FISH_SOUND_VORBIS ? "Vorbis" : "Speex",
- blocksize,
- interleave ? "interleave" : "non-interleave");
+ "+ %2d channel %6d Hz %s, %d frame buffer (%s)",
+ channels, samplerate,
+ format == FISH_SOUND_VORBIS ? "Vorbis" : (format == FISH_SOUND_FLAC ? "Flac" : "Speex"),
+ blocksize,
+ interleave ? "interleave" : "non-interleave");
INFO (msg);
ed = fs_encdec_new (samplerate, channels, format, interleave, blocksize);
@@ -219,12 +220,13 @@
for (i = 0; i < iter; i++) {
ed->actual_frames_in += blocksize;
fish_sound_prepare_truncation (ed->encoder, ed->actual_frames_in,
- (i == (iter - 1)));
+ (i == (iter - 1)));
fish_sound_encode (ed->encoder, ed->pcm, blocksize);
ed->reported_frames_in = fish_sound_get_frameno (ed->encoder);
}
fish_sound_flush (ed->encoder);
+ fish_sound_flush (ed->decoder);
ed->reported_frames_in = fish_sound_get_frameno (ed->encoder);
expected_frames = ed->actual_frames_in;
@@ -234,8 +236,8 @@
if (ed->actual_frames_out != expected_frames) {
snprintf (msg, 128,
- "%ld frames encoded, %ld frames decoded",
- ed->actual_frames_in, ed->actual_frames_out);
+ "%ld frames encoded, %ld frames decoded",
+ ed->actual_frames_in, ed->actual_frames_out);
if (ed->actual_frames_out < ed->actual_frames_in) {
FAIL (msg);
} else {
@@ -250,8 +252,8 @@
if (ed->reported_frames_out != expected_frames) {
snprintf (msg, 128,
- "%ld frames reported in, %ld frames reported out",
- ed->reported_frames_in, ed->reported_frames_out);
+ "%ld frames reported in, %ld frames reported out",
+ ed->reported_frames_in, ed->reported_frames_out);
WARN (msg);
}
@@ -277,6 +279,8 @@
test_vorbis = 0;
} else if (!strcmp (argv[i], "--disable-speex")) {
test_speex = 0;
+ } else if (!strcmp (argv[i], "--disable-flac")) {
+ test_flac = 0;
} else if (!strcmp (argv[i], "--disable-interleave")) {
test_interleave = 0;
} else if (!strcmp (argv[i], "--disable-non-interleave")) {
@@ -295,6 +299,7 @@
if (!test_vorbis) INFO ("* DISABLED testing of Vorbis");
if (!test_speex) INFO ("* DISABLED testing of Speex");
+ if (!test_flac) INFO ("* DISABLED testing of Flac");
if (!test_interleave) INFO ("* DISABLED testing of INTERLEAVE");
if (!test_non_interleave) INFO ("* DISABLED testing of NON-INTERLEAVE");
}
@@ -314,41 +319,56 @@
for (s = 0; test_samplerates[s]; s++) {
for (c = 0; test_channels[c]; c++) {
- if (test_non_interleave) {
- /* Test VORBIS */
- if (test_vorbis) {
- fs_encdec_test (test_samplerates[s], test_channels[c],
- FISH_SOUND_VORBIS, 0, test_blocksizes[b]);
- }
-
- /* Test SPEEX */
- if (test_speex) {
- if (test_channels[c] <= 2) {
- fs_encdec_test (test_samplerates[s], test_channels[c],
- FISH_SOUND_SPEEX, 0, test_blocksizes[b]);
-
- }
- }
- }
+ if (test_non_interleave) {
+ /* Test VORBIS */
+ if (test_vorbis) {
+ fs_encdec_test (test_samplerates[s], test_channels[c],
+ FISH_SOUND_VORBIS, 0, test_blocksizes[b]);
+ }
+
+ /* Test SPEEX */
+ if (test_speex) {
+ if (test_channels[c] <= 2) {
+ fs_encdec_test (test_samplerates[s], test_channels[c],
+ FISH_SOUND_SPEEX, 0, test_blocksizes[b]);
+ }
+ }
- if (test_interleave) {
- /* Test VORBIS */
- if (test_vorbis) {
- fs_encdec_test (test_samplerates[s], test_channels[c],
- FISH_SOUND_VORBIS, 1, test_blocksizes[b]);
- }
-
- /* Test SPEEX */
- if (test_speex) {
- if (test_channels[c] <= 2) {
- fs_encdec_test (test_samplerates[s], test_channels[c],
- FISH_SOUND_SPEEX, 1, test_blocksizes[b]);
-
- }
- }
- }
+ /* Test FLAC */
+ if (test_flac) {
+ if (test_channels[c] <= 8) {
+ fs_encdec_test (test_samplerates[s], test_channels[c],
+ FISH_SOUND_FLAC, 0, test_blocksizes[b]);
+
+ }
+ }
+ }
+ if (test_interleave) {
+ /* Test VORBIS */
+ if (test_vorbis) {
+ fs_encdec_test (test_samplerates[s], test_channels[c],
+ FISH_SOUND_VORBIS, 1, test_blocksizes[b]);
+ }
+
+ /* Test SPEEX */
+ if (test_speex) {
+ if (test_channels[c] <= 2) {
+ fs_encdec_test (test_samplerates[s], test_channels[c],
+ FISH_SOUND_SPEEX, 1, test_blocksizes[b]);
+ }
+ }
+ /* Test FLAC */
+ if (test_flac) {
+ if (test_channels[c] <= 8) {
+ fs_encdec_test (test_samplerates[s], test_channels[c],
+ FISH_SOUND_FLAC, 1, test_blocksizes[b]);
+
+ }
+ }
+ }
+
}
}
}
More information about the commits
mailing list