/* Audio File Library Copyright (C) 2013 Michael Pruett This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "config.h" #include "FLAC.h" #include "Compiler.h" #include "FileModule.h" #include "Features.h" #include "Track.h" #include "byteorder.h" #if ENABLE(FLAC) #include #include #include #include #include class FLACDecoder : public FileModule { public: static FLACDecoder *create(Track *track, File *file, bool canSeek, bool headerless, AFframecount *chunkFrames); virtual ~FLACDecoder(); virtual const char *name() const OVERRIDE { return "flac_decompress"; } virtual void describe() OVERRIDE; virtual void runPull() OVERRIDE; virtual void reset1() OVERRIDE; virtual void reset2() OVERRIDE; virtual bool handlesSeeking() const OVERRIDE { return true; } private: FLACDecoder(Track *track, File *file, bool canSeek); FLAC__StreamDecoder *m_decoder; std::vector m_buffer; int m_bufferedFrames, m_bufferedOffset; void convertAndInterleave(int offset, int frameCount); static FLAC__StreamDecoderReadStatus readCallback(const FLAC__StreamDecoder *, FLAC__byte buffer[], size_t *bytes, void *clientData) { FLACDecoder *flac = static_cast(clientData); ssize_t result = flac->read(buffer, *bytes); if (result > 0) { *bytes = result; return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; } *bytes = 0; return FLAC__STREAM_DECODER_READ_STATUS_ABORT; } static FLAC__StreamDecoderSeekStatus seekCallback(const FLAC__StreamDecoder *, FLAC__uint64 absoluteByteOffset, void *clientData) { FLACDecoder *flac = static_cast(clientData); if (flac->seek(absoluteByteOffset) < 0) return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR; return FLAC__STREAM_DECODER_SEEK_STATUS_OK; } static FLAC__StreamDecoderTellStatus tellCallback(const FLAC__StreamDecoder *, FLAC__uint64 *absoluteByteOffset, void *clientData) { FLACDecoder *flac = static_cast(clientData); off_t result = flac->tell(); if (result < 0) return FLAC__STREAM_DECODER_TELL_STATUS_ERROR; *absoluteByteOffset = static_cast(result); return FLAC__STREAM_DECODER_TELL_STATUS_OK; } static FLAC__StreamDecoderLengthStatus lengthCallback(const FLAC__StreamDecoder *, FLAC__uint64 *length, void *clientData) { FLACDecoder *flac = static_cast(clientData); off_t result = flac->length(); if (result < 0) return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR; *length = result; return FLAC__STREAM_DECODER_LENGTH_STATUS_OK; } static FLAC__bool eofCallback(const FLAC__StreamDecoder *, void *clientData) { FLACDecoder *flac = static_cast(clientData); return flac->tell() == flac->length(); } static FLAC__StreamDecoderWriteStatus writeCallback(const FLAC__StreamDecoder *, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *clientData) { FLACDecoder *flac = static_cast(clientData); flac->didDecodeFrame(frame, buffer); return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; } static void metadataCallback(const FLAC__StreamDecoder *, const FLAC__StreamMetadata *metadata, void *clientData) { } static void errorCallback(const FLAC__StreamDecoder *, FLAC__StreamDecoderErrorStatus status, void *clientData) { _af_error(AF_BAD_CODEC_CONFIG, "FLAC decoding error %d", status); } void didDecodeFrame(const FLAC__Frame *frame, const FLAC__int32 * const buffer[]) { m_bufferedFrames = frame->header.blocksize; m_bufferedOffset = 0; for (unsigned c=0; cheader.channels; c++) memcpy(m_buffer[c], buffer[c], frame->header.blocksize * sizeof (int32_t)); m_track->nextfframe += frame->header.blocksize; } }; FLACDecoder *FLACDecoder::create(Track *track, File *file, bool canSeek, bool headerless, AFframecount *chunkFrames) { return new FLACDecoder(track, file, canSeek); } FLACDecoder::FLACDecoder(Track *track, File *file, bool canSeek) : FileModule(Decompress, track, file, canSeek), m_decoder(NULL), m_bufferedFrames(0), m_bufferedOffset(0) { m_decoder = FLAC__stream_decoder_new(); if (FLAC__stream_decoder_init_stream(m_decoder, readCallback, seekCallback, tellCallback, lengthCallback, eofCallback, writeCallback, metadataCallback, errorCallback, this) != FLAC__STREAM_DECODER_INIT_STATUS_OK) { _af_error(AF_BAD_CODEC_CONFIG, "could not initialize FLAC decoder"); return; } m_buffer.resize(m_track->f.channelCount); for (int c=0; cf.channelCount; c++) m_buffer[c] = new int32_t[FLAC__MAX_BLOCK_SIZE]; } FLACDecoder::~FLACDecoder() { if (m_decoder) { FLAC__stream_decoder_delete(m_decoder); m_decoder = NULL; } for (size_t i=0; if.byteOrder = _AF_BYTEORDER_NATIVE; m_outChunk->f.compressionType = AF_COMPRESSION_NONE; m_outChunk->f.compressionParams = AU_NULL_PVLIST; } void FLACDecoder::convertAndInterleave(int offset, int frameCount) { int channelCount = m_outChunk->f.channelCount; if (m_track->f.sampleWidth == 16) { int16_t *out = static_cast(m_outChunk->buffer); for (int i=0; if.sampleWidth == 24) { uint8_t *out = static_cast(m_outChunk->buffer); for (int i=0; i> 16) & 0xff; c1 = (in >> 8) & 0xff; c2 = in & 0xff; #else c2 = (in >> 16) & 0xff; c1 = (in >> 8) & 0xff; c0 = in & 0xff; #endif int outIndex = (offset+i) * channelCount + c; out[3*outIndex] = c0; out[3*outIndex+1] = c1; out[3*outIndex+2] = c2; } } } m_bufferedOffset += frameCount; } void FLACDecoder::runPull() { int framesToRead = m_outChunk->frameCount; int offset = 0; while (framesToRead > 0) { int bufferedFramesToRead = std::min(framesToRead, m_bufferedFrames - m_bufferedOffset); convertAndInterleave(offset, bufferedFramesToRead); offset += bufferedFramesToRead; framesToRead -= bufferedFramesToRead; if (framesToRead > 0) { if (!FLAC__stream_decoder_process_single(m_decoder)) break; if (FLAC__stream_decoder_get_state(m_decoder) >= FLAC__STREAM_DECODER_END_OF_STREAM) break; } } } void FLACDecoder::reset1() { } void FLACDecoder::reset2() { if (!FLAC__stream_decoder_seek_absolute(m_decoder, m_track->nextfframe)) { _af_error(AF_BAD_CODEC_CONFIG, "could not seek to frame %jd", static_cast(m_track->nextfframe)); } } class FLACEncoder : public FileModule { public: static FLACEncoder *create(Track *track, File *file, bool canSeek, bool headerless, AFframecount *chunkFrames); virtual ~FLACEncoder(); virtual const char *name() const OVERRIDE { return "flac_compress"; } virtual void describe() OVERRIDE; virtual void runPush() OVERRIDE; virtual void sync1() OVERRIDE; virtual void sync2() OVERRIDE; virtual bool handlesSeeking() const OVERRIDE { return true; } private: FLAC__StreamEncoder *m_encoder; FLAC__int32 *m_buffer; FLACEncoder(Track *track, File *file, bool canSeek); void convert16To32(); void convert24To32(); static FLAC__StreamEncoderSeekStatus seekCallback(const FLAC__StreamEncoder *, FLAC__uint64 absoluteByteOffset, void *clientData) { FLACEncoder *flac = static_cast(clientData); off_t result = flac->seek(absoluteByteOffset); if (result < 0) return FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR; return FLAC__STREAM_ENCODER_SEEK_STATUS_OK; } static FLAC__StreamEncoderTellStatus tellCallback(const FLAC__StreamEncoder *, FLAC__uint64 *absoluteByteOffset, void *clientData) { FLACEncoder *flac = static_cast(clientData); off_t offset = flac->tell(); if (offset < 0) return FLAC__STREAM_ENCODER_TELL_STATUS_ERROR; *absoluteByteOffset = static_cast(offset); return FLAC__STREAM_ENCODER_TELL_STATUS_OK; } static FLAC__StreamEncoderWriteStatus writeCallback(const FLAC__StreamEncoder *, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned currentFrame, void *clientData) { FLACEncoder *flac = static_cast(clientData); ssize_t result = flac->write(buffer, bytes); if (result == static_cast(bytes)) return FLAC__STREAM_ENCODER_WRITE_STATUS_OK; return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; } }; FLACEncoder::FLACEncoder(Track *track, File *file, bool canSeek) : FileModule(Compress, track, file, canSeek), m_encoder(NULL), m_buffer(NULL) { m_encoder = FLAC__stream_encoder_new(); if (!m_encoder) { _af_error(AF_BAD_CODEC_CONFIG, "could not create encoder"); return; } if (!FLAC__stream_encoder_set_channels(m_encoder, m_track->f.channelCount)) { _af_error(AF_BAD_CODEC_CONFIG, "could not set channel count"); return; } if (!FLAC__stream_encoder_set_sample_rate(m_encoder, m_track->f.sampleRate)) { _af_error(AF_BAD_CODEC_CONFIG, "could not set sample rate"); return; } if (!FLAC__stream_encoder_set_bits_per_sample(m_encoder, m_track->f.sampleWidth)) { _af_error(AF_BAD_CODEC_CONFIG, "could not set sample width"); return; } if (FLAC__stream_encoder_init_stream(m_encoder, writeCallback, seekCallback, tellCallback, NULL, this) != FLAC__STREAM_ENCODER_INIT_STATUS_OK) { _af_error(AF_BAD_CODEC_CONFIG, "could not initialize FLAC encoder"); return; } m_buffer = new int32_t[FLAC__MAX_BLOCK_SIZE * m_track->f.channelCount]; } FLACEncoder::~FLACEncoder() { if (m_encoder) { FLAC__stream_encoder_delete(m_encoder); m_encoder = NULL; } delete [] m_buffer; } FLACEncoder *FLACEncoder::create(Track *track, File *file, bool canSeek, bool headerless, AFframecount *chunkFrames) { return new FLACEncoder(track, file, canSeek); } void FLACEncoder::describe() { m_outChunk->f.byteOrder = _AF_BYTEORDER_NATIVE; m_outChunk->f.compressionType = AF_COMPRESSION_FLAC; } void FLACEncoder::runPush() { if (m_track->f.sampleWidth == 16) convert16To32(); else if (m_track->f.sampleWidth == 24) convert24To32(); if (!FLAC__stream_encoder_process_interleaved(m_encoder, m_buffer, m_inChunk->frameCount)) { _af_error(AF_BAD_CODEC_CONFIG, "could not encode data into FLAC stream"); } m_track->nextfframe += m_inChunk->frameCount; m_track->totalfframes = m_track->nextfframe; } void FLACEncoder::sync1() { } void FLACEncoder::sync2() { if (!FLAC__stream_encoder_finish(m_encoder)) { _af_error(AF_BAD_CODEC_CONFIG, "could not finish encoding"); } } void FLACEncoder::convert16To32() { int channelCount = m_track->f.channelCount; const int16_t *src = static_cast(m_inChunk->buffer); for (unsigned i=0; iframeCount; i++) for (int c=0; cf.channelCount; const uint8_t *src = static_cast(m_inChunk->buffer); for (unsigned i=0; iframeCount; i++) for (int c=0; c> 8; } } bool _af_flac_format_ok(AudioFormat *f) { if (f->channelCount > static_cast(FLAC__MAX_CHANNELS)) { _af_error(AF_BAD_COMPRESSION, "FLAC compression supports a maximum of 8 channels"); return false; } if (f->sampleFormat != AF_SAMPFMT_TWOSCOMP || (f->sampleWidth != 16 && f->sampleWidth != 24)) { _af_error(AF_BAD_COMPRESSION, "FLAC compression requires 16- or 24-bit signed integer format"); return false; } if (f->byteOrder != _AF_BYTEORDER_NATIVE) { _af_error(AF_BAD_COMPRESSION, "FLAC compression requires native byte order"); return false; } return true; } #else bool _af_flac_format_ok(AudioFormat *) { return false; } #endif FileModule *_af_flac_init_compress(Track *track, File *file, bool canSeek, bool headerless, AFframecount *chunkFrames) { #if ENABLE(FLAC) return FLACEncoder::create(track, file, canSeek, headerless, chunkFrames); #else return NULL; #endif } FileModule *_af_flac_init_decompress(Track *track, File *file, bool canSeek, bool headerless, AFframecount *chunkFrames) { #if ENABLE(FLAC) return FLACDecoder::create(track, file, canSeek, headerless, chunkFrames); #else return NULL; #endif }