Child: [166a14] (diff)

Download this file

flacencoder.cpp    155 lines (127 with data), 5.3 kB

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/* Copyright (C) 2015-2018 J.F.Dockes
* 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.
*/
#include "flacencoder.h"
#include "audioutil.h"
#include "log.h"
#include <string.h>
#ifdef DEBUG_ENCODER
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#endif
using namespace std;
FlacEncoder::FlacEncoder(AudioReader* audioReader, OhmSenderDriver *ohmSender)
: AudioEncoder(audioReader, ohmSender, true, "FLAC")
{
LOGDEB("New FLAC encoder\n");
m_encoder = FLAC__stream_encoder_new();
if (m_encoder == nullptr)
LOGERR("FlacEncoder: Failed to construct stream encoder\n");
FLAC__bool ok = true;
ok &= FLAC__stream_encoder_set_compression_level(m_encoder, 0);
ok &= FLAC__stream_encoder_set_channels(m_encoder,
m_audioReader->numChannels());
ok &= FLAC__stream_encoder_set_bits_per_sample(m_encoder,
m_audioReader->bitsPerSample());
ok &= FLAC__stream_encoder_set_sample_rate(m_encoder,
m_audioReader->sampleRate());
if (!ok)
LOGERR("FlacEncoder: Failed to set parameters for stream encoder\n");
#ifdef DEBUG_ENCODER
dumpfd = open("/tmp/mpd2dump.flac", O_WRONLY|O_CREAT|O_TRUNC, 0666);
#endif
}
FlacEncoder::~FlacEncoder()
{
LOGDEB("Delete FLAC encoder\n");
FLAC__stream_encoder_delete(m_encoder);
#ifdef DEBUG_ENCODER
if (dumpfd > 0)
close(dumpfd);
#endif
}
void FlacEncoder::start()
{
LOGDEB("Start FLAC encoder\n");
FLAC__StreamEncoderInitStatus init_status;
init_status = FLAC__stream_encoder_init_stream(m_encoder,
writeCallback, nullptr, nullptr, nullptr, this);
if (init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK)
LOGERR("FlacEncoder: Failed to init stream for stream encoder: "
<< string(FLAC__StreamEncoderInitStatusString[init_status])
<< endl);
}
int FlacEncoder::encode(const unsigned char *buffer, unsigned num_bytes,
bool halt)
{
if (num_bytes == 0) {
LOGDEB("FlacEncoder: Sending an empty audio message with halt="
<< halt << endl);
m_ohmSender->SendAudio((const TByte*)buffer, 0, halt, 0);
return 0;
}
m_halt = halt;
unsigned samples_left = num_bytes / 2; // each sample takes 2 bytes
// (16 bits per sample)
while (samples_left > 0) {
unsigned samples = samples_left > SAMPLES_BUF_SIZE ? SAMPLES_BUF_SIZE
: samples_left;
// convert the packed little-endian 16-bit PCM samples into an
// interleaved FLAC__int32 buffer for libFLAC
for (unsigned i = 0; i < samples; i++) {
// inefficient but simple and works on big- or little-endian
// machines.
m_samplesBuf[i] = (FLAC__int32)
(((FLAC__int16)(FLAC__int8)buffer[2*i+1] << 8)
| (FLAC__int16)buffer[2*i]);
}
// feed samples to encoder
if (!FLAC__stream_encoder_process_interleaved(m_encoder, m_samplesBuf,
samples / 2)) {
return 0;
}
samples_left -= samples;
buffer += samples * 2; // skip processed samples
}
return num_bytes; // consumed everything
}
void FlacEncoder::finish()
{
LOGDEB("Finish FLAC encoder\n");
FLAC__stream_encoder_finish(m_encoder);
}
FLAC__StreamEncoderWriteStatus FlacEncoder::writeCallback(
const FLAC__StreamEncoder *encoder,
const FLAC__byte buffer[], // An array of encoded data.
size_t bytes, // The byte length of buffer.
unsigned samples, // The number of samples encoded by buffer
// 0 has a special meaning.
unsigned current_frame, // The number of the current frame being
// encoded.
void *client_data)
{
FlacEncoder *enc = reinterpret_cast<FlacEncoder*>(client_data);
//LOGDEB("writeCallback: " << bytes << ", " << samples << ", "
// << current_frame << ", " << enc->m_halt << endl);
if (samples > 0)
enc->m_ohmSender->SendAudio(buffer, bytes, enc->m_halt, samples);
#ifdef DEBUG_ENCODER
if (enc->dumpfd > 0)
write(enc->dumpfd, buffer, bytes);
#endif
return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
}