mirror of
https://github.com/badaix/snapcast.git
synced 2025-05-13 17:16:42 +02:00
experimental FLAC support
This commit is contained in:
parent
176ed8abc0
commit
d99c3cb9a0
10 changed files with 289 additions and 35 deletions
|
@ -1,9 +1,9 @@
|
||||||
VERSION = 0.1
|
VERSION = 0.1
|
||||||
CC = /usr/bin/g++
|
CC = /usr/bin/g++
|
||||||
CFLAGS = -std=gnu++0x -static-libgcc -static-libstdc++ -Wall -Wno-unused-function -O3 -D_REENTRANT -DVERSION=\"$(VERSION)\" -I..
|
CFLAGS = -std=gnu++0x -static-libgcc -static-libstdc++ -Wall -Wno-unused-function -O3 -D_REENTRANT -DVERSION=\"$(VERSION)\" -I..
|
||||||
LDFLAGS = -lrt -lpthread -lboost_system -lboost_program_options -lasound -logg -lvorbis -lvorbisenc
|
LDFLAGS = -lrt -lpthread -lboost_system -lboost_program_options -lasound -logg -lvorbis -lvorbisenc -lFLAC
|
||||||
|
|
||||||
OBJ = snapClient.o stream.o alsaPlayer.o clientConnection.o timeProvider.o oggDecoder.o pcmDecoder.o controller.o ../message/pcmChunk.o ../common/log.o ../message/sampleFormat.o
|
OBJ = snapClient.o stream.o alsaPlayer.o clientConnection.o timeProvider.o oggDecoder.o pcmDecoder.o flacDecoder.o controller.o ../message/pcmChunk.o ../common/log.o ../message/sampleFormat.o
|
||||||
BIN = snapclient
|
BIN = snapclient
|
||||||
|
|
||||||
all: client
|
all: client
|
||||||
|
|
|
@ -97,7 +97,7 @@ void Player::start()
|
||||||
snd_pcm_sw_params(pcm_handle_, swparams);
|
snd_pcm_sw_params(pcm_handle_, swparams);
|
||||||
|
|
||||||
active_ = true;
|
active_ = true;
|
||||||
playerThread_ = new thread(&Player::worker, this);
|
playerThread_ = thread(&Player::worker, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -108,12 +108,10 @@ Player::~Player()
|
||||||
|
|
||||||
|
|
||||||
void Player::stop() {
|
void Player::stop() {
|
||||||
active_ = false;
|
if (active_)
|
||||||
if (playerThread_ != NULL)
|
|
||||||
{
|
{
|
||||||
playerThread_->join();
|
active_ = false;
|
||||||
delete playerThread_;
|
playerThread_.join();
|
||||||
playerThread_ = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pcm_handle_ != NULL)
|
if (pcm_handle_ != NULL)
|
||||||
|
|
|
@ -26,7 +26,7 @@ private:
|
||||||
char *buff_;
|
char *buff_;
|
||||||
std::atomic<bool> active_;
|
std::atomic<bool> active_;
|
||||||
Stream* stream_;
|
Stream* stream_;
|
||||||
std::thread* playerThread_;
|
std::thread playerThread_;
|
||||||
PcmDevice pcmDevice_;
|
PcmDevice pcmDevice_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include "oggDecoder.h"
|
#include "oggDecoder.h"
|
||||||
#include "pcmDecoder.h"
|
#include "pcmDecoder.h"
|
||||||
|
#include "flacDecoder.h"
|
||||||
#include "alsaPlayer.h"
|
#include "alsaPlayer.h"
|
||||||
#include "timeProvider.h"
|
#include "timeProvider.h"
|
||||||
#include "common/log.h"
|
#include "common/log.h"
|
||||||
|
@ -99,6 +100,8 @@ void Controller::worker()
|
||||||
decoder_ = new OggDecoder();
|
decoder_ = new OggDecoder();
|
||||||
else if (headerChunk->codec == "pcm")
|
else if (headerChunk->codec == "pcm")
|
||||||
decoder_ = new PcmDecoder();
|
decoder_ = new PcmDecoder();
|
||||||
|
else if (headerChunk->codec == "flac")
|
||||||
|
decoder_ = new FlacDecoder();
|
||||||
decoder_->setHeader(headerChunk.get());
|
decoder_->setHeader(headerChunk.get());
|
||||||
|
|
||||||
msg::Request timeReq(kTime);
|
msg::Request timeReq(kTime);
|
||||||
|
@ -149,8 +152,8 @@ void Controller::worker()
|
||||||
delete decoder_;
|
delete decoder_;
|
||||||
decoder_ = NULL;
|
decoder_ = NULL;
|
||||||
logO << "done" << endl;
|
logO << "done" << endl;
|
||||||
if (active_)
|
for (size_t n=0; (n<10) && active_; ++n)
|
||||||
usleep(500*1000);
|
usleep(100*1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logD << "Thread stopped\n";
|
logD << "Thread stopped\n";
|
||||||
|
|
187
client/flacDecoder.cpp
Normal file
187
client/flacDecoder.cpp
Normal file
|
@ -0,0 +1,187 @@
|
||||||
|
#include "flacDecoder.h"
|
||||||
|
#include <iostream>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cmath>
|
||||||
|
#include <FLAC/stream_decoder.h>
|
||||||
|
#include "common/log.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
|
||||||
|
static FLAC__StreamDecoderReadStatus read_callback(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data);
|
||||||
|
static FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);
|
||||||
|
static void metadata_callback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data);
|
||||||
|
static void error_callback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
|
||||||
|
|
||||||
|
static FLAC__uint64 total_samples = 0;
|
||||||
|
static unsigned sample_rate = 0;
|
||||||
|
static unsigned channels = 0;
|
||||||
|
static unsigned bps = 0;
|
||||||
|
static msg::Header* flacHeader = NULL;
|
||||||
|
static msg::PcmChunk* flacChunk = NULL;
|
||||||
|
static FLAC__StreamDecoder *decoder = 0;
|
||||||
|
|
||||||
|
|
||||||
|
FlacDecoder::FlacDecoder() : Decoder()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FlacDecoder::~FlacDecoder()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool FlacDecoder::decode(msg::PcmChunk* chunk)
|
||||||
|
{
|
||||||
|
flacChunk = chunk;
|
||||||
|
//logO << "Decode start: " << chunk->payloadSize << endl;
|
||||||
|
// flacChunk->payload = (char*)realloc(flacChunk->payload, chunk->payloadSize);
|
||||||
|
// memcpy(flacChunk->payload, chunk->payload, chunk->payloadSize);
|
||||||
|
// flacChunk->payloadSize = chunk->payloadSize;
|
||||||
|
FLAC__stream_decoder_process_single(decoder);
|
||||||
|
FLAC__stream_decoder_process_single(decoder);
|
||||||
|
//logO << "Decode end\n" << endl;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool FlacDecoder::setHeader(msg::Header* chunk)
|
||||||
|
{
|
||||||
|
flacHeader = chunk;
|
||||||
|
FLAC__bool ok = true;
|
||||||
|
FLAC__StreamDecoderInitStatus init_status;
|
||||||
|
|
||||||
|
if((decoder = FLAC__stream_decoder_new()) == NULL) {
|
||||||
|
fprintf(stderr, "ERROR: allocating decoder\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// (void)FLAC__stream_decoder_set_md5_checking(decoder, true);
|
||||||
|
|
||||||
|
init_status = FLAC__stream_decoder_init_stream(decoder, read_callback, NULL, NULL, NULL, NULL, write_callback, metadata_callback, error_callback, this);
|
||||||
|
|
||||||
|
// init_status = FLAC__stream_decoder_init_file(decoder, argv[1], write_callback, metadata_callback, error_callback, fout);
|
||||||
|
if(init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
|
||||||
|
fprintf(stderr, "ERROR: initializing decoder: %s\n", FLAC__StreamDecoderInitStatusString[init_status]);
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
|
// FLAC__stream_decoder_process_until_end_of_stream(decoder);
|
||||||
|
FLAC__stream_decoder_process_until_end_of_metadata(decoder);
|
||||||
|
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FLAC__StreamDecoderReadStatus read_callback(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
|
||||||
|
{
|
||||||
|
if (flacHeader != NULL)
|
||||||
|
{
|
||||||
|
*bytes = flacHeader->payloadSize;
|
||||||
|
memcpy(buffer, flacHeader->payload, *bytes);
|
||||||
|
flacHeader = NULL;
|
||||||
|
}
|
||||||
|
else if (flacChunk != NULL)
|
||||||
|
{
|
||||||
|
//logO << "Read: " << *bytes << "\t" << flacChunk->payloadSize << "\n";
|
||||||
|
if (*bytes > flacChunk->payloadSize)
|
||||||
|
*bytes = flacChunk->payloadSize;
|
||||||
|
|
||||||
|
if (flacChunk->payloadSize == 0)
|
||||||
|
return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
|
||||||
|
|
||||||
|
memcpy(buffer, flacChunk->payload, *bytes);
|
||||||
|
memmove(flacChunk->payload, flacChunk->payload + *bytes, flacChunk->payloadSize - *bytes);
|
||||||
|
flacChunk->payloadSize = flacChunk->payloadSize - *bytes;
|
||||||
|
flacChunk->payload = (char*)realloc(flacChunk->payload, flacChunk->payloadSize);
|
||||||
|
//logO << "Read end\n";
|
||||||
|
// return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
|
||||||
|
}
|
||||||
|
return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
|
||||||
|
{
|
||||||
|
//logO << "Write start\n";
|
||||||
|
(void)decoder;
|
||||||
|
|
||||||
|
if(channels != 2 || bps != 16) {
|
||||||
|
fprintf(stderr, "ERROR: this example only supports 16bit stereo streams\n");
|
||||||
|
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
|
||||||
|
}
|
||||||
|
if(frame->header.channels != 2) {
|
||||||
|
fprintf(stderr, "ERROR: This frame contains %d channels (should be 2)\n", frame->header.channels);
|
||||||
|
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
|
||||||
|
}
|
||||||
|
if(buffer [0] == NULL) {
|
||||||
|
fprintf(stderr, "ERROR: buffer [0] is NULL\n");
|
||||||
|
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
|
||||||
|
}
|
||||||
|
if(buffer [1] == NULL) {
|
||||||
|
fprintf(stderr, "ERROR: buffer [1] is NULL\n");
|
||||||
|
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flacChunk != NULL)
|
||||||
|
{
|
||||||
|
size_t bytes = frame->header.blocksize * 4;
|
||||||
|
//logO << "blocksize: " << frame->header.blocksize << "\tframe_number: " << frame->header.number.frame_number << "\tsample_number: " << frame->header.number.sample_number << "\n";
|
||||||
|
//logO << "Write: " << bytes << "\n";
|
||||||
|
//flacChunk->payloadSize = 0;
|
||||||
|
flacChunk->payload = (char*)realloc(flacChunk->payload, flacChunk->payloadSize + bytes);
|
||||||
|
for(size_t i = 0; i < frame->header.blocksize; i++)
|
||||||
|
{
|
||||||
|
memcpy(flacChunk->payload + flacChunk->payloadSize + 4*i, (char*)(buffer[0] + i), 2);
|
||||||
|
memcpy(flacChunk->payload + flacChunk->payloadSize + 4*i+2, (char*)(buffer[1] + i), 2);
|
||||||
|
//logO << 4*i+2 << "\t" << bytes << "\n";
|
||||||
|
}
|
||||||
|
flacChunk->payloadSize += bytes;
|
||||||
|
//logO << "Write end: " << flacChunk->payloadSize << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/* write decoded PCM samples */
|
||||||
|
/* for(i = 0; i < frame->header.blocksize; i++) {
|
||||||
|
if(
|
||||||
|
!write_little_endian_int16(f, (FLAC__int16)buffer[0][i]) || // left channel
|
||||||
|
!write_little_endian_int16(f, (FLAC__int16)buffer[1][i]) // right channel
|
||||||
|
) {
|
||||||
|
fprintf(stderr, "ERROR: write error\n");
|
||||||
|
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void metadata_callback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
|
||||||
|
{
|
||||||
|
(void)decoder, (void)client_data;
|
||||||
|
|
||||||
|
/* print some stats */
|
||||||
|
if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
|
||||||
|
/* save for later */
|
||||||
|
total_samples = metadata->data.stream_info.total_samples;
|
||||||
|
sample_rate = metadata->data.stream_info.sample_rate;
|
||||||
|
channels = metadata->data.stream_info.channels;
|
||||||
|
bps = metadata->data.stream_info.bits_per_sample;
|
||||||
|
|
||||||
|
logO << "sample rate : " << sample_rate << "Hz\n";
|
||||||
|
logO << "channels : " << channels << "\n";
|
||||||
|
logO << "bits per sample: " << bps << "\n";
|
||||||
|
logO << "total samples : " << total_samples << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void error_callback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
|
||||||
|
{
|
||||||
|
(void)decoder, (void)client_data;
|
||||||
|
fprintf(stderr, "Got error callback: %s\n", FLAC__StreamDecoderErrorStatusString[status]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
18
client/flacDecoder.h
Normal file
18
client/flacDecoder.h
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#ifndef FLAC_DECODER_H
|
||||||
|
#define FLAC_DECODER_H
|
||||||
|
#include "decoder.h"
|
||||||
|
|
||||||
|
|
||||||
|
class FlacDecoder : public Decoder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FlacDecoder();
|
||||||
|
virtual ~FlacDecoder();
|
||||||
|
virtual bool decode(msg::PcmChunk* chunk);
|
||||||
|
virtual bool setHeader(msg::Header* chunk);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
VERSION = 0.1
|
VERSION = 0.1
|
||||||
CC = /usr/bin/g++
|
CC = /usr/bin/g++
|
||||||
CFLAGS = -std=gnu++0x -Wall -Wno-unused-function -O3 -D_REENTRANT -DVERSION=\"$(VERSION)\" -I..
|
CFLAGS = -std=gnu++0x -Wall -Wno-unused-function -O3 -D_REENTRANT -DVERSION=\"$(VERSION)\" -I..
|
||||||
LDFLAGS = -lrt -lpthread -lboost_system -lboost_program_options -lvorbis -lvorbisenc -logg
|
LDFLAGS = -lrt -lpthread -lboost_system -lboost_program_options -lvorbis -lvorbisenc -logg -lFLAC
|
||||||
|
|
||||||
OBJ = snapServer.o controlServer.o pcmEncoder.o oggEncoder.o serverSession.o ../common/log.o ../message/pcmChunk.o ../message/sampleFormat.o
|
OBJ = snapServer.o controlServer.o flacEncoder.o pcmEncoder.o oggEncoder.o serverSession.o ../common/log.o ../message/pcmChunk.o ../message/sampleFormat.o
|
||||||
BIN = snapserver
|
BIN = snapserver
|
||||||
|
|
||||||
all: server
|
all: server
|
||||||
|
|
|
@ -5,28 +5,75 @@
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
|
||||||
FlacEncoder::FlacEncoder(const msg::SampleFormat& format) : Encoder(format)
|
FlacEncoder::FlacEncoder(const msg::SampleFormat& format) : Encoder(format), encoder(0)
|
||||||
{
|
{
|
||||||
headerChunk = new HeaderMessage("flac");
|
initEncoder();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define READSIZE 16384
|
||||||
|
|
||||||
|
static FLAC__int32 pcm[READSIZE/*samples*/ * 2/*channels*/];
|
||||||
|
size_t encodedSamples = 0;
|
||||||
|
static msg::PcmChunk* encodedChunk;
|
||||||
|
|
||||||
|
|
||||||
|
msg::Header* FlacEncoder::getHeaderChunk()
|
||||||
|
{
|
||||||
|
return headerChunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
double FlacEncoder::encode(msg::PcmChunk* chunk)
|
double FlacEncoder::encode(msg::PcmChunk* chunk)
|
||||||
{
|
{
|
||||||
return chunk->duration<chronos::msec>().count();
|
logD << "payload: " << chunk->payloadSize << "\tsamples: " << chunk->payloadSize/4 << "\n";
|
||||||
|
int samples = chunk->payloadSize / 4;
|
||||||
|
for(int i=0; i<samples*2/*channels*/; i++)
|
||||||
|
{
|
||||||
|
pcm[i] = (FLAC__int32)(((FLAC__int16)(FLAC__int8)chunk->payload[2*i+1] << 8) | (FLAC__int16)(0x00ff&chunk->payload[2*i]));
|
||||||
|
}
|
||||||
|
FLAC__stream_encoder_process_interleaved(encoder, pcm, samples);
|
||||||
|
|
||||||
|
double res = encodedSamples / ((double)sampleFormat.rate / 1000.);
|
||||||
|
if (encodedSamples > 0)
|
||||||
|
{
|
||||||
|
logD << "encoded: " << chunk->payloadSize << "\tsamples: " << encodedSamples << "\tres: " << res << "\n";
|
||||||
|
encodedSamples = 0;
|
||||||
|
chunk->payloadSize = encodedChunk->payloadSize;
|
||||||
|
chunk->payload = (char*)realloc(chunk->payload, encodedChunk->payloadSize);
|
||||||
|
memcpy(chunk->payload, encodedChunk->payload, encodedChunk->payloadSize);
|
||||||
|
encodedChunk->payloadSize = 0;
|
||||||
|
encodedChunk->payload = (char*)realloc(encodedChunk->payload, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define READSIZE 1024
|
return res;//chunk->duration<chronos::msec>().count();
|
||||||
|
}
|
||||||
static unsigned total_samples = 0; /* can use a 32-bit number due to WAVE size limitations */
|
|
||||||
static FLAC__byte buffer[READSIZE/*samples*/ * 2/*bytes_per_sample*/ * 2/*channels*/]; /* we read the WAVE data into here */
|
|
||||||
static FLAC__int32 pcm[READSIZE/*samples*/ * 2/*channels*/];
|
|
||||||
|
|
||||||
|
|
||||||
|
FLAC__StreamEncoderWriteStatus write_callback(const FLAC__StreamEncoder *encoder,
|
||||||
static void write_callback(const FLAC__StreamEncoder *encoder, const unsigned char*, long unsigned int bytes, unsigned int samples, unsigned int current_frame, void *client_data)
|
const FLAC__byte buffer[],
|
||||||
|
size_t bytes,
|
||||||
|
unsigned samples,
|
||||||
|
unsigned current_frame,
|
||||||
|
void *client_data)
|
||||||
{
|
{
|
||||||
cout << "write_callback: " << bytes << ", " << samples << ", " << current_frame << "\n";
|
logD << "write_callback: " << bytes << ", " << samples << ", " << current_frame << "\n";
|
||||||
|
FlacEncoder* flacEncoder = (FlacEncoder*)client_data;
|
||||||
|
if ((current_frame == 0) && (bytes > 0) && (samples == 0))
|
||||||
|
{
|
||||||
|
msg::Header* headerChunk = flacEncoder->getHeaderChunk();
|
||||||
|
headerChunk->payload = (char*)realloc(headerChunk->payload, headerChunk->payloadSize + bytes);
|
||||||
|
memcpy(headerChunk->payload + headerChunk->payloadSize, buffer, bytes);
|
||||||
|
headerChunk->payloadSize += bytes;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
encodedChunk->payload = (char*)realloc(encodedChunk->payload, encodedChunk->payloadSize + bytes);
|
||||||
|
memcpy(encodedChunk->payload + encodedChunk->payloadSize, buffer, bytes);
|
||||||
|
encodedChunk->payloadSize += bytes;
|
||||||
|
encodedSamples += samples;
|
||||||
|
}
|
||||||
|
return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -35,8 +82,9 @@ static void write_callback(const FLAC__StreamEncoder *encoder, const unsigned ch
|
||||||
|
|
||||||
void FlacEncoder::initEncoder()
|
void FlacEncoder::initEncoder()
|
||||||
{
|
{
|
||||||
|
encodedChunk = new msg::PcmChunk();
|
||||||
|
headerChunk = new msg::Header("flac");
|
||||||
FLAC__bool ok = true;
|
FLAC__bool ok = true;
|
||||||
FLAC__StreamEncoder *encoder = 0;
|
|
||||||
FLAC__StreamEncoderInitStatus init_status;
|
FLAC__StreamEncoderInitStatus init_status;
|
||||||
FLAC__StreamMetadata *metadata[2];
|
FLAC__StreamMetadata *metadata[2];
|
||||||
FLAC__StreamMetadata_VorbisComment_Entry entry;
|
FLAC__StreamMetadata_VorbisComment_Entry entry;
|
||||||
|
@ -48,11 +96,10 @@ void FlacEncoder::initEncoder()
|
||||||
}
|
}
|
||||||
|
|
||||||
ok &= FLAC__stream_encoder_set_verify(encoder, true);
|
ok &= FLAC__stream_encoder_set_verify(encoder, true);
|
||||||
ok &= FLAC__stream_encoder_set_compression_level(encoder, 5);
|
ok &= FLAC__stream_encoder_set_compression_level(encoder, 8);
|
||||||
ok &= FLAC__stream_encoder_set_channels(encoder, sampleFormat.channels);
|
ok &= FLAC__stream_encoder_set_channels(encoder, sampleFormat.channels);
|
||||||
ok &= FLAC__stream_encoder_set_bits_per_sample(encoder, sampleFormat.bits);
|
ok &= FLAC__stream_encoder_set_bits_per_sample(encoder, sampleFormat.bits);
|
||||||
ok &= FLAC__stream_encoder_set_sample_rate(encoder, sampleFormat.rate);
|
ok &= FLAC__stream_encoder_set_sample_rate(encoder, sampleFormat.rate);
|
||||||
ok &= FLAC__stream_encoder_set_total_samples_estimate(encoder, 0);
|
|
||||||
|
|
||||||
// now add some metadata; we'll add some tags and a padding block
|
// now add some metadata; we'll add some tags and a padding block
|
||||||
if(ok) {
|
if(ok) {
|
||||||
|
@ -76,7 +123,7 @@ void FlacEncoder::initEncoder()
|
||||||
|
|
||||||
// initialize encoder
|
// initialize encoder
|
||||||
if(ok) {
|
if(ok) {
|
||||||
init_status = FLAC__stream_encoder_init_stream(encoder, write_callback, NULL, NULL, NULL, NULL);
|
init_status = FLAC__stream_encoder_init_stream(encoder, write_callback, NULL, NULL, NULL, this);
|
||||||
if(init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) {
|
if(init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) {
|
||||||
fprintf(stderr, "ERROR: initializing encoder: %s\n", FLAC__StreamEncoderInitStatusString[init_status]);
|
fprintf(stderr, "ERROR: initializing encoder: %s\n", FLAC__StreamEncoderInitStatusString[init_status]);
|
||||||
ok = false;
|
ok = false;
|
||||||
|
@ -122,12 +169,13 @@ void FlacEncoder::initEncoder()
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
void progress_callback(const FLAC__StreamEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate, void *client_data)
|
void progress_callback(const FLAC__StreamEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate, void *client_data)
|
||||||
{
|
{
|
||||||
(void)encoder, (void)client_data;
|
(void)encoder, (void)client_data;
|
||||||
fprintf(stderr, "wrote %d bytes, %d, %u samples, %u/%u frames\n", bytes_written, samples_written, total_samples, frames_written, total_frames_estimate);
|
fprintf(stderr, "wrote %d bytes, %d, %u samples, %u/%u frames\n", bytes_written, samples_written, total_samples, frames_written, total_frames_estimate);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -14,9 +14,11 @@ class FlacEncoder : public Encoder
|
||||||
public:
|
public:
|
||||||
FlacEncoder(const msg::SampleFormat& format);
|
FlacEncoder(const msg::SampleFormat& format);
|
||||||
virtual double encode(msg::PcmChunk* chunk);
|
virtual double encode(msg::PcmChunk* chunk);
|
||||||
|
msg::Header* getHeaderChunk();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void initEncoder();
|
void initEncoder();
|
||||||
|
FLAC__StreamEncoder *encoder;
|
||||||
// virtual void progress_callback(FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate);
|
// virtual void progress_callback(FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "message/message.h"
|
#include "message/message.h"
|
||||||
#include "pcmEncoder.h"
|
#include "pcmEncoder.h"
|
||||||
#include "oggEncoder.h"
|
#include "oggEncoder.h"
|
||||||
|
#include "flacEncoder.h"
|
||||||
#include "controlServer.h"
|
#include "controlServer.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -92,10 +93,7 @@ int main(int argc, char* argv[])
|
||||||
else if (codec == "pcm")
|
else if (codec == "pcm")
|
||||||
encoder.reset(new PcmEncoder(sampleFormat));
|
encoder.reset(new PcmEncoder(sampleFormat));
|
||||||
else if (codec == "flac")
|
else if (codec == "flac")
|
||||||
{
|
encoder.reset(new FlacEncoder(sampleFormat));
|
||||||
logO << "Not yet supported\n";
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
logO << "unknown codec: " << codec << "\n";
|
logO << "unknown codec: " << codec << "\n";
|
||||||
|
@ -144,8 +142,8 @@ int main(int argc, char* argv[])
|
||||||
controlServer->send(chunk);
|
controlServer->send(chunk);
|
||||||
//logD << chunk->tv_sec << ", " << chunk->tv_usec / 1000 << "\n";
|
//logD << chunk->tv_sec << ", " << chunk->tv_usec / 1000 << "\n";
|
||||||
// addUs(tvChunk, 1000*chunk->getDuration());
|
// addUs(tvChunk, 1000*chunk->getDuration());
|
||||||
chronos::addUs(tvChunk, chunkDuration * 1000);
|
|
||||||
nextTick += duration;
|
nextTick += duration;
|
||||||
|
chronos::addUs(tvChunk, chunkDuration * 1000);
|
||||||
long currentTick = chronos::getTickCount();
|
long currentTick = chronos::getTickCount();
|
||||||
if (nextTick > currentTick)
|
if (nextTick > currentTick)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue