[xiph-commits] r7428 - in icecast/trunk/ices0: . src

brendan at motherfish-iii.xiph.org brendan
Thu Aug 5 19:04:50 PDT 2004


Author: brendan
Date: Thu Aug  5 19:04:50 2004
New Revision: 7428

Added:
icecast/trunk/ices0/src/in_flac.c
icecast/trunk/ices0/src/in_flac.h
Modified:
icecast/trunk/ices0/configure.ac
icecast/trunk/ices0/src/Makefile.am
icecast/trunk/ices0/src/icestypes.h
icecast/trunk/ices0/src/setup.c
icecast/trunk/ices0/src/stream.c
Log:
Couldn't sleep, so I wrote a FLAC plugin.


Modified: icecast/trunk/ices0/configure.ac
===================================================================
--- icecast/trunk/ices0/configure.ac	2004-07-31 08:11:05 UTC (rev 7427)
+++ icecast/trunk/ices0/configure.ac	2004-07-31 09:11:47 UTC (rev 7428)
@@ -342,6 +342,52 @@
fi
fi

+AC_ARG_WITH(flac,
+  [[  --with-flac[=DIR]     support for FLAC transcoding using libFLAC [in DIR]]])
+
+if test "$have_LAME" != "yes"
+then
+  if test -n "$with_flac" -a "$with_flac" != "no"
+  then
+    AC_MSG_ERROR([FLAC transcoding cannot be enabled without LAME])
+  elif test "$with_flac" != "no"
+  then
+    AC_MSG_RESULT([FLAC transcoding is disabled because LAME is not enabled])
+    with_flac="no"
+  fi
+fi
+
+have_flac="no"
+if test "$with_flac" != "no"
+then
+  if test -n "$with_flac" -a "$with_flac" != "yes"
+  then
+    CPPFLAGS="$CPPFLAGS -I$with_flac/include"
+    LDFLAGS="$LDFLAGS -L$with_flac/lib"
+  fi
+
+  AC_CHECK_HEADER(faad.h, have_flac="maybe")
+  if test "$have_flac" != "no"
+  then
+    AC_CHECK_LIB(FLAC, FLAC__stream_decoder_new, [
+      LIBS="$LIBS -lFLAC"
+      AC_DEFINE(HAVE_LIBFLAC, 1, [Define if you have libFLAC])
+      ICES_OBJECTS="$ICES_OBJECTS in_flac.o"
+      have_flac="yes"
+    ],[have_flac="no"])
+  fi
+fi
+
+if test "$with_flac" != "no" -a "$have_flac" != "yes"
+then
+  if test -n "$with_flac"
+  then
+    AC_MSG_ERROR([Could not find libFLAC])
+  else
+    AC_MSG_RESULT([Could not find libFLAC, FLAC transcoding disabled])
+  fi
+fi
+
dnl -- and finish up --

LIBS="$LIBS $LIBM $LIBDL"
@@ -359,3 +405,4 @@
AC_MSG_RESULT([  LAME    : $have_LAME])
AC_MSG_RESULT([  Vorbis  : $have_vorbis])
AC_MSG_RESULT([  MP4     : $have_faad])
+AC_MSG_RESULT([  FLAC    : $have_flac])

Modified: icecast/trunk/ices0/src/Makefile.am
===================================================================
--- icecast/trunk/ices0/src/Makefile.am	2004-07-31 08:11:05 UTC (rev 7427)
+++ icecast/trunk/ices0/src/Makefile.am	2004-07-31 09:11:47 UTC (rev 7428)
@@ -5,13 +5,13 @@
bin_PROGRAMS = ices

noinst_HEADERS = icestypes.h definitions.h setup.h log.h stream.h util.h \
-	cue.h metadata.h in_vorbis.h mp3.h in_mp4.h id3.h signals.h reencode.h \
-	ices_config.h
+	cue.h metadata.h in_vorbis.h mp3.h in_mp4.h in_flac.h id3.h signals.h \
+	reencode.h ices_config.h

ices_SOURCES = ices.c log.c setup.c stream.c util.c mp3.c cue.c metadata.c \
id3.c signals.c crossfade.c

-EXTRA_ices_SOURCES = ices_config.c reencode.c in_vorbis.c in_mp4.c
+EXTRA_ices_SOURCES = ices_config.c reencode.c in_vorbis.c in_mp4.c in_flac.c

ices_LDADD = $(ICES_OBJECTS) playlist/libplaylist.a
ices_DEPENDENCIES = $(ices_LDADD)

Modified: icecast/trunk/ices0/src/icestypes.h
===================================================================
--- icecast/trunk/ices0/src/icestypes.h	2004-07-31 08:11:05 UTC (rev 7427)
+++ icecast/trunk/ices0/src/icestypes.h	2004-07-31 09:11:47 UTC (rev 7428)
@@ -79,7 +79,8 @@
typedef enum {
ICES_INPUT_VORBIS,
ICES_INPUT_MP3,
-  ICES_INPUT_MP4
+  ICES_INPUT_MP4,
+  ICES_INPUT_FLAC
} input_type_t;

typedef struct _input_stream_t {

Added: icecast/trunk/ices0/src/in_flac.c
===================================================================
--- icecast/trunk/ices0/src/in_flac.c	2004-07-31 08:11:05 UTC (rev 7427)
+++ icecast/trunk/ices0/src/in_flac.c	2004-07-31 09:11:47 UTC (rev 7428)
@@ -0,0 +1,279 @@
+/* in_flac.c
+ * Plugin to read FLAC files as PCM
+ *
+ * Copyright (c) 2004 Brendan Cully <brendan at xiph.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * $Id$
+ */
+
+#include "config.h"
+#include "in_flac.h"
+#include "metadata.h"
+
+#include <FLAC/stream_decoder.h>
+
+/* -- data structures -- */
+typedef struct {
+  FLAC__StreamDecoder* decoder;
+  unsigned char parsed;
+  /* read buffer */
+  char *buf;
+  size_t len;
+  /* write buffer */
+  int16_t *left;
+  int16_t *right;
+  size_t olen;
+} flac_in_t;
+
+/* -- static prototypes -- */
+static int ices_flac_readpcm (input_stream_t* self, size_t len,
+			      int16_t* left, int16_t* right);
+static int ices_flac_close (input_stream_t* self);
+
+/* -- FLAC callbacks -- */
+static FLAC__StreamDecoderReadStatus
+flac_read_cb(const FLAC__StreamDecoder* decoder, FLAC__byte buffer[],
+	     unsigned* bytes, void* client_data);
+static FLAC__StreamDecoderWriteStatus
+flac_write_cb(const FLAC__StreamDecoder* decoder, const FLAC__Frame* frame,
+	      const FLAC__int32* const buffer[], void* client_data);
+static void
+flac_metadata_cb(const FLAC__StreamDecoder* decoder,
+		 const FLAC__StreamMetadata* metadata, void* client_data);
+static void
+flac_error_cb(const FLAC__StreamDecoder* decoder,
+	      FLAC__StreamDecoderErrorStatus status, void* client_data);
+
+/* try to open a FLAC file for decoding. Returns:
+ *   0: success
+ *   1: not a FLAC file
+ *  -1: error opening
+ */
+int
+ices_flac_open (input_stream_t* self, char* buf, size_t len)
+{
+  flac_in_t* flac_data;
+  FLAC__StreamDecoder* decoder;
+
+  if (!(decoder = FLAC__stream_decoder_new())) {
+    ices_log_error("ices_flac_open: Error allocating FLAC decoder");
+    return -1;
+  }
+
+  FLAC__stream_decoder_set_read_callback(decoder, flac_read_cb);
+  FLAC__stream_decoder_set_write_callback(decoder, flac_write_cb);
+  FLAC__stream_decoder_set_metadata_callback(decoder, flac_metadata_cb);
+  FLAC__stream_decoder_set_error_callback(decoder, flac_error_cb);
+
+  FLAC__stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+  if (!(flac_data = (flac_in_t*)malloc (sizeof (flac_in_t)))) {
+    ices_log_error ("Malloc failed in ices_flac_open");
+    goto errDecoder;
+  }
+  FLAC__stream_decoder_set_client_data(decoder, self);
+
+  flac_data->decoder = decoder;
+  flac_data->parsed = 0;
+  flac_data->buf = buf;
+  flac_data->len = len;
+
+  self->data = flac_data;
+
+  switch (FLAC__stream_decoder_init(decoder)) {
+  case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA:
+    break;
+  case FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR:
+    ices_log_error("Could not allocate memory during FLAC decoder init");
+    goto errData;
+  default:
+    ices_log_error("Unexpected error during FLAC decoder init");
+    goto errData;
+  }
+
+  if (!FLAC__stream_decoder_process_single(decoder)) {
+    ices_log_error("Could not find FLAC metadata header");
+    free(flac_data);
+    FLAC__stream_decoder_delete(decoder);
+    return 1;;
+  }
+  if (!flac_data->parsed) {
+    ices_log_error("Could not find FLAC metadata header in prebuffer");
+    goto errData;
+  }
+
+  self->type = ICES_INPUT_FLAC;
+
+  self->read = NULL;
+  self->readpcm = ices_flac_readpcm;
+  self->close = ices_flac_close;
+
+  if (!FLAC__stream_decoder_process_until_end_of_metadata(decoder)) {
+    ices_log_error("Error seeking past FLAC metadata");
+    goto errData;
+  }
+
+  return 0;
+
+errData:
+  free(flac_data);
+errDecoder:
+  FLAC__stream_decoder_delete(decoder);
+
+  return -1;
+}
+
+static int
+ices_flac_readpcm (input_stream_t* self, size_t olen, int16_t* left,
+		   int16_t* right)
+{
+  flac_in_t* flac_data = (flac_in_t*)self->data;
+
+  flac_data->left = left;
+  flac_data->right = right;
+  flac_data->olen = olen;
+  if (!FLAC__stream_decoder_process_single(flac_data->decoder)) {
+    switch (FLAC__stream_decoder_get_state(flac_data->decoder)) {
+    case FLAC__STREAM_DECODER_END_OF_STREAM:
+      return 0;
+    default:
+      ices_log_error("Error reading FLAC stream");
+    }
+  }
+  if (FLAC__stream_decoder_get_state(flac_data->decoder) == FLAC__STREAM_DECODER_END_OF_STREAM)
+    return 0;
+
+  return flac_data->olen;
+}
+
+static int
+ices_flac_close (input_stream_t* self)
+{
+  flac_in_t* flac_data = (flac_in_t*) self->data;
+
+  FLAC__stream_decoder_finish(flac_data->decoder);
+  FLAC__stream_decoder_delete(flac_data->decoder);
+  free (flac_data);
+
+  return 0;
+}
+
+/* -- callbacks -- */
+static FLAC__StreamDecoderReadStatus
+flac_read_cb(const FLAC__StreamDecoder* decoder, FLAC__byte buffer[],
+	     unsigned* bytes, void* client_data)
+{
+  input_stream_t* self = (input_stream_t*)client_data;
+  flac_in_t* flac_data = (flac_in_t*)self->data;
+  ssize_t len;
+  char errbuf[128];
+
+  if (!flac_data->len) {
+    if (!flac_data->parsed) {
+      *bytes = 0;
+      return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+    }
+    if ((len = read(self->fd, buffer, *bytes)) > 0)
+      return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+    if (!len)
+      return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+    ices_log_error("Error reading FLAC stream: %s", ices_util_strerror(errno, errbuf, sizeof(errbuf)));
+    return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+  }
+
+  if (flac_data->len < *bytes)
+    *bytes = flac_data->len;
+  memcpy(buffer, flac_data->buf, *bytes);
+  flac_data->len -= *bytes;
+
+  return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+}
+
+static FLAC__StreamDecoderWriteStatus
+flac_write_cb(const FLAC__StreamDecoder* decoder, const FLAC__Frame* frame,
+	      const FLAC__int32* const buffer[], void* client_data)
+{
+  input_stream_t* self = (input_stream_t*)client_data;
+  flac_in_t* flac_data = (flac_in_t*)self->data;
+  int i;
+
+  for (i = 0; i < frame->header.blocksize; i++) {
+    flac_data->left[i] = buffer[0][i];
+    if (self->channels > 1)
+      flac_data->right[i] = buffer[1][i];
+  }
+  if (self->channels == 1)
+    memcpy(flac_data->right, flac_data->left, frame->header.blocksize << 1);
+
+  flac_data->olen = frame->header.blocksize;
+
+  return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+static void
+flac_metadata_cb(const FLAC__StreamDecoder* decoder,
+		 const FLAC__StreamMetadata* metadata, void* client_data)
+{
+  input_stream_t* self = (input_stream_t*)client_data;
+  flac_in_t* flac_data = (flac_in_t*)self->data;
+  FLAC__StreamMetadata_VorbisComment_Entry* comment;
+  char* artist = NULL;
+  char* title = NULL;
+  int i;
+
+  switch(metadata->type) {
+  case FLAC__METADATA_TYPE_STREAMINFO:
+    self->samplerate = metadata->data.stream_info.sample_rate;
+    self->channels = metadata->data.stream_info.channels;
+    flac_data->parsed = 1;
+    ices_log_debug("Found FLAC file, %d Hz, %d channels, %d bits", self->samplerate, self->channels, metadata->data.stream_info.bits_per_sample);
+    break;
+  case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+    for (i = 0; i < metadata->data.vorbis_comment.num_comments; i++) {
+      comment = metadata->data.vorbis_comment.comments + i;
+
+      if (!strncasecmp("artist", comment->entry, 6))
+	artist = comment->entry + 7;
+      else if (!strncasecmp("title", comment->entry, 5))
+	title = comment->entry + 6;
+
+      ices_metadata_set(artist, title);
+    }
+    break;
+  default:
+    ices_log_debug("Ignoring unknown FLAC metadata type");
+  }
+}
+
+static void
+flac_error_cb(const FLAC__StreamDecoder* decoder,
+	      FLAC__StreamDecoderErrorStatus status, void* client_data)
+{
+  switch (status) {
+  case FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC:
+    ices_log_error("FLAC lost sync");
+    break;
+  case FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER:
+    ices_log_error("Bad header in FLAC stream");
+    break;
+  case FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH:
+    ices_log_error("Bad CRC for FLAC frame");
+    break;
+  default:
+    ices_log_error("Unspecified error decoding FLAC stream");
+  }
+}


Property changes on: icecast/trunk/ices0/src/in_flac.c
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native

Added: icecast/trunk/ices0/src/in_flac.h
===================================================================
--- icecast/trunk/ices0/src/in_flac.h	2004-07-31 08:11:05 UTC (rev 7427)
+++ icecast/trunk/ices0/src/in_flac.h	2004-07-31 09:11:47 UTC (rev 7428)
@@ -0,0 +1,30 @@
+/* in_flac.h
+ * ices input plugin to read FLAC files as PCM
+ *
+ * Copyright (c) 2004 Brendan Cully <brendan at xiph.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * $Id$
+ */
+
+#ifndef IN_FLAC_H
+#define IN_FLAC_H
+
+#include "definitions.h"
+
+int ices_flac_open (input_stream_t* self, char* buf, size_t len);
+
+#endif


Property changes on: icecast/trunk/ices0/src/in_flac.h
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native

Modified: icecast/trunk/ices0/src/setup.c
===================================================================
--- icecast/trunk/ices0/src/setup.c	2004-07-31 08:11:05 UTC (rev 7427)
+++ icecast/trunk/ices0/src/setup.c	2004-07-31 09:11:47 UTC (rev 7428)
@@ -592,6 +592,9 @@
#ifdef HAVE_LIBVORBISFILE
"Vorbis "
#endif
+#ifdef HAVE_LIBFLAC
+  "FLAC "
+#endif
#ifdef HAVE_LIBFAAD
"MP4"
#endif

Modified: icecast/trunk/ices0/src/stream.c
===================================================================
--- icecast/trunk/ices0/src/stream.c	2004-07-31 08:11:05 UTC (rev 7427)
+++ icecast/trunk/ices0/src/stream.c	2004-07-31 09:11:47 UTC (rev 7428)
@@ -29,6 +29,9 @@
#ifdef HAVE_LIBFAAD
#include "in_mp4.h"
#endif
+#ifdef HAVE_LIBFLAC
+#include "in_flac.h"
+#endif

#ifdef TIME_WITH_SYS_TIME
#  include <sys/time.h>
@@ -356,14 +359,23 @@
return -1;
}

-  #ifdef HAVE_LIBFAAD
+#ifdef HAVE_LIBFLAC
+  if (!(rc = ices_flac_open (source, buf, len)))
+    return 0;
+  if (rc < 0) {
+    close(fd);
+    return -1;
+  }
+#endif
+
+#ifdef HAVE_LIBFAAD
if (!(rc = ices_mp4_open (source, buf, len)))
return 0;
if (rc < 0) {
close(fd);
return -1;
}
-  #endif
+#endif

if (!(rc = ices_mp3_open (source, buf, len)))
return 0;



More information about the commits mailing list