8000 Added experimental FLAC encoding support. by bramton · Pull Request #191 · rafael2k/darkice · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Added experimental FLAC encoding support. #191

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion darkice/trunk/configure.in
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,19 @@ AS_CASE([$with_opus],
AS_IF(test -n "$OPUS_LIBS",
AC_DEFINE(HAVE_OPUS_LIB, 1, [build with Ogg Opus library]))

dnl-----------------------------------------------------------------------------
dnl link the ogg / FLAC libraries if requested
dnl-----------------------------------------------------------------------------
AC_ARG_WITH(flac,
AS_HELP_STRING([--with-flac], [use Ogg FLAC for encoding flac streams @<:@check@:>@]),
[], with_flac=check)
AS_CASE([$with_flac],
check, [PKG_CHECK_MODULES(FLAC, [ogg flac], [], true)],
yes, [PKG_CHECK_MODULES(FLAC, [ogg flac])],
AC_MSG_RESULT([building without Ogg FLAC]))
AS_IF(test -n "$FLAC_LIBS",
AC_DEFINE(HAVE_FLAC_LIB, 1, [build with Ogg FLAC library]))

dnl-----------------------------------------------------------------------------
dnl link the faac library if requested
dnl-----------------------------------------------------------------------------
Expand Down Expand Up @@ -172,10 +185,11 @@ dnl-----------------------------------------------------------------------------
if test -z "x${LAME_LIBS}" \
-a -z "${VORBIS_LIBS}" \
-a -z "${OPUS_LIBS}" \
-a -z "${FLAC_LIBS}" \
-a -z "${FAAC_LIBS}" \
-a -z "${AACPLUS_LIBS}" \
-a -z "${TWOLAME_LIBS}" ; then
AC_MSG_ERROR([neither lame, Ogg Vorbis, opus, faac, aac+ nor twolame configured])
AC_MSG_ERROR([neither lame, Ogg Vorbis, opus, FLAC, faac, aac+ nor twolame configured])
fi


Expand Down
20 changes: 15 additions & 5 deletions darkice/trunk/man/darkice.1
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
.TH darkice 1 "November 20, 2007" "DarkIce" "DarkIce live audio streamer"
.TH darkice 1 "April 3, 2024" "DarkIce" "DarkIce live audio streamer"
.SH NAME
darkice \- an icecast / shoutcast live audio streamer
.SH SYNOPSIS
.B darkice
[options] -c config.file
.SH DESCRIPTION
.PP
DarkIce as a live audio streamer. It records audio from an audio interface (e.g. sound card), encodes it and sends it to a streaming server.
DarkIce as a live audio streamer. It records audio from an audio interface
(e.g. sound card), encodes it and sends it to a streaming server.

DarkIce can record from:

* OSS audio devices
Expand All @@ -21,6 +23,7 @@ DarkIce can encode in the following formats:
* mp2 - using the twolame library
* Ogg Vorbis
* Ogg Opus
* Ogg FLAC
* AAC - using the faac library
* AAC HEv2 - using the libaacplus (3GPP reference code)

Expand Down Expand Up @@ -64,13 +67,20 @@ Defaults to 1.
Prints the help page and exits.


.SH NOTES
When using the FLAC encoder with an icecast streamer, make sure to increase the
.I <queue-size>
setting.


.SH BUGS
.PP
Lots of bugs.
.PP



.SH "SEE ALSO"
darkice.cfg(5)
darkice.cfg(5), icecast(1)


.SH AUTHOR
Expand Down Expand Up @@ -116,7 +126,7 @@ Developed with contributions by

.SH LINKS
Project homepage:
.I http://code.google.com/p/darkice/
.I http://www.darkice.org/

.B IceCast
homepage:
Expand Down
13 changes: 10 additions & 3 deletions darkice/trunk/man/darkice.cfg.5
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.TH darkice.cfg 5 "February 25, 2007" "DarkIce" "DarkIce live audio streamer"
.TH darkice.cfg 5 "April 3, 2024" "DarkIce" "DarkIce live audio streamer"
.SH NAME
darkice.cfg \- configuration file for darkice
.SH DESCRIPTION
Expand Down Expand Up @@ -210,6 +210,12 @@ Highpass filter setting for the lame encoder, in Hz. Frequencies below
the specified value will be cut.
If not set or set to 0, the encoder's default behaviour is used.
If set to -1, the filter is disabled.
.TP
.I compression
Compression level of the FLAC encoder.
An integer value between 0 (fast, least compression)
and 8 (slow, most compression).
If not set, the encoder's default value (5) is used.

.PP
.B [icecast2-x]
Expand All @@ -236,7 +242,8 @@ Required values:
.I format
Format of the stream sent to the
.B IceCast2
server. Supported formats are 'vorbis', 'opus', 'mp3', 'mp2', 'aac' and 'aacp'.
server. Supported formats are 'vorbis', 'opus', 'flac', 'mp3', 'mp2', 'aac'
and 'aacp'.
.TP
.I bitrateMode
The bit rate mode of the encoding, either "cbr", "abr" or "vbr",
Expand Down Expand Up @@ -665,7 +672,7 @@ Akos Maroy

.SH LINKS
Project homepage:
.I http://code.google.com/p/darkice/
.I http://darkice.org/

.B IceCast
homepage:
Expand Down
30 changes: 30 additions & 0 deletions darkice/trunk/src/DarkIce.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@
#include "OpusLibEncoder.h"
#endif

#ifdef HAVE_FLAC_LIB
#include "FlacLibEncoder.h"
#endif

#ifdef HAVE_FAAC_LIB
#include "FaacEncoder.h"
#endif
Expand Down Expand Up @@ -467,6 +471,7 @@ DarkIce :: configIceCast2 ( const Config & config,
bool isPublic = false;
int lowpass = 0;
int highpass = 0;
unsigned int compression = 0;
const char * localDumpName = 0;
FileSink * localDumpFile = 0;
bool fileAddDate = false;
Expand All @@ -479,6 +484,8 @@ DarkIce :: configIceCast2 ( const Config & config,
format = IceCast2::oggVorbis;
} else if ( Util::strEq( str, "opus") ) {
format = IceCast2::oggOpus;
} else if ( Util::strEq( str, "flac") ) {
format = IceCast2::oggFlac;
} else if ( Util::strEq( str, "mp3") ) {
format = IceCast2::mp3;
} else if ( Util::strEq( str, "mp2") ) {
Expand Down Expand Up @@ -553,6 +560,8 @@ DarkIce :: configIceCast2 ( const Config & config,
lowpass = str ? Util::strToL( str) : 0;
str = cs->get( "highpass");
highpass = str ? Util::strToL( str) : 0;
str = cs->get( "compression");
compression = str ? Util::strToL( str) : 5;
str = cs->get( "fileAddDate");
fileAddDate = str ? (Util::strEq( str, "yes") ? true : false) : false;
fileDateFormat = cs->get( "fileDateFormat");
Expand Down Expand Up @@ -672,6 +681,27 @@ DarkIce :: configIceCast2 ( const Config & config,
#endif // HAVE_OPUS_LIB
break;

case IceCast2::oggFlac:
#ifndef HAVE_FLAC_LIB
throw Exception( __FILE__, __LINE__,
"DarkIce not compiled with Ogg FLAC support, "
"thus can't Ogg FLAC stream: ",
stream);
#else

audioOuts[u].encoder = new FlacLibEncoder(
audioOut,
dsp.get(),
bitrateMode,
bitrate,
quality,
sampleRate,
dsp->getChannel(),
compression);

#endif // HAVE_FLAC_LIB
break;

case IceCast2::mp2:
#ifndef HAVE_TWOLAME_LIB
throw Exception( __FILE__, __LINE__,
Expand Down
204 changes: 204 additions & 0 deletions darkice/trunk/src/FlacLibEncoder.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
/* ============================================================ include files */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

// compile only if configured for Ogg / FLAC
#ifdef HAVE_FLAC_LIB

#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include <cstring>
#include <cstdlib>

#include "Exception.h"
#include "Util.h"
#include "FlacLibEncoder.h"
#include "CastSink.h"

/* =================================================== local data structures */


/* ================================================ local constants & macros */

/*------------------------------------------------------------------------------
* File identity
*----------------------------------------------------------------------------*/
static const char fileid[] = "$Id$";


/* =============================================== local function prototypes */


/* ============================================================= module code */

/*------------------------------------------------------------------------------
* Initialize the encoder
*----------------------------------------------------------------------------*/
void
FlacLibEncoder :: init ( unsigned int compression )

{

this->compression = compression;

if ( getInBitsPerSample() != 16 ) {
throw Exception( __FILE__, __LINE__,
"only 16 bits per sample supported at the moment",
getInBitsPerSample() );
}

if ( getInChannel() != 2 ) {
throw Exception( __FILE__, __LINE__,
"only two channels supported at the moment",
getInChannel() );
}

if ( getOutSampleRate() != getInSampleRate() ) {
throw Exception( __FILE__, __LINE__,
"resampling not supported at the moment");
}

if ( compression < 0 || compression > 8 ) {
throw Exception( __FILE__, __LINE__,
"unsupported compression level for the encoder",
compression );
}

encoderOpen = false;
}


/*------------------------------------------------------------------------------
* Start an encoding session
*----------------------------------------------------------------------------*/
bool
FlacLibEncoder :: open ( void )

{
if ( isOpen() ) {
close();
}

// open the underlying sink
if ( !getSink()->open() ) {
throw Exception( __FILE__, __LINE__,
"FLAC lib opening underlying sink error");
}

se = FLAC__stream_encoder_new();
if (!se) {
throw Exception( __FILE__, __LINE__,
"FLAC encoder creation error");
}
FLAC__stream_encoder_set_channels(se, getInChannel());
FLAC__stream_encoder_set_ogg_serial_number(se, rand());
FLAC__stream_encoder_set_bits_per_sample(se, getInBitsPerSample());
FLAC__stream_encoder_set_sample_rate(se, getInSampleRate());
FLAC__stream_encoder_set_compression_level(se, this->compression);

FLAC__StreamEncoderInitStatus status;
status = FLAC__stream_encoder_init_ogg_stream(se, NULL,
FlacLibEncoder::encoder_cb,
NULL, NULL, NULL, this);
if (status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) {
throw Exception( __FILE__, __LINE__,
"FLAC encoder initialisation failed");
}

encoderOpen = true;

return true;
}

/*------------------------------------------------------------------------------
* Callback function for the FLAC encoder
*----------------------------------------------------------------------------*/
FLAC__StreamEncoderWriteStatus
FlacLibEncoder :: encoder_cb (const FLAC__StreamEncoder *encoder,
const FLAC__byte buffer[],
size_t len,
uint32_t samples,
uint32_t current_frame,
void *flacencoder ) {
FlacLibEncoder *fle = (FlacLibEncoder*)flacencoder;
unsigned int written = fle->getSink()->write(buffer, len);
// Write callback is called twice; once for the page header, once for the
// page body. When page header is written, samples is 0.
if (samples != 0) {
fle->written = written;
}
return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
}

/*------------------------------------------------------------------------------
* Write data to the encoder
*----------------------------------------------------------------------------*/
unsigned int
FlacLibEncoder :: write ( const void * buf,
unsigned int len )
{
if ( !isOpen() || len == 0 ) {
return 0;
}
this->written = 0;

unsigned int bitsPerSample = getInBitsPerSample();
unsigned char *b = (unsigned char*)buf;
const uint32_t samples = len>>1;
const uint32_t samples_per_channel = samples/getInChannel();
FLAC__int32 *buffer = new FLAC__int32[samples];

Util::conv<FLAC__int32>(bitsPerSample, b, len, buffer, isInBigEndian());

if (!FLAC__stream_encoder_process_interleaved(se, buffer,
samples_per_channel)) {
const char *err = FLAC__stream_encoder_get_resolved_state_string(se);
size_t needed = snprintf(NULL, 0, "FLAC encoder error: %s", err) + 1;
char *msg = (char *)malloc(needed);
snprintf(msg, needed, "FLAC encoder error: %s", err);
throw Exception( __FILE__, __LINE__, msg);
}

delete[] buffer;
return this->written;
}

/*------------------------------------------------------------------------------
* Close the encoding session
*----------------------------------------------------------------------------*/
void
FlacLibEncoder :: close ( void )

{
if ( isOpen() ) {

FLAC__stream_encoder_finish(se);
getSink()->flush();
FLAC__stream_encoder_delete(se);
se = NULL;

encoderOpen = false;

getSink()->close();
}
}

/*------------------------------------------------------------------------------
* Flush the data from the encoder
*----------------------------------------------------------------------------*/
void
FlacLibEncoder :: flush ( void )

{
if ( !isOpen() ) {
return;
}

getSink()->flush();
}

#endif // HAVE_FLAC_LIB
Loading
0