[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