MythTV  master
audiooutputdigitalencoder.cpp
Go to the documentation of this file.
1 // Std C headers
2 #include <cstdio>
3 #include <cstring>
4 #include <unistd.h>
5 
6 // libav headers
7 extern "C" {
8 #include "libavutil/mem.h" // for av_free
9 #include "libavcodec/avcodec.h"
10 }
11 
12 // MythTV headers
13 #include "libmythbase/compat.h"
16 
18 #include "audiooutpututil.h"
19 
20 #define LOC QString("DEnc: ")
21 
23  : m_outbuf(static_cast<uint8_t*>(av_mallocz(OUTBUFSIZE)))
24 {
25  if (m_outbuf)
26  {
28  }
29  m_inbuf = static_cast<uint8_t*>(av_mallocz(INBUFSIZE));
30  if (m_inbuf)
31  {
33  }
34  m_framebuf = static_cast<uint8_t*>(av_mallocz(INBUFSIZE));
35 }
36 
38 {
39  Reset();
40  if (m_outbuf)
41  {
42  av_freep(reinterpret_cast<void*>(&m_outbuf));
43  m_outSize = 0;
44  }
45  if (m_inbuf)
46  {
47  av_freep(reinterpret_cast<void*>(&m_inbuf));
48  m_inSize = 0;
49  }
50  if (m_framebuf)
51  {
52  av_freep(reinterpret_cast<void*>(&m_framebuf));
53  }
54 }
55 
57 {
58  if (m_avContext)
59  avcodec_free_context(&m_avContext);
60 
61  av_frame_free(&m_frame);
62 
63  delete m_spdifEnc;
64  m_spdifEnc = nullptr;
65 
66  clear();
67 }
68 
70  size_t old_size, size_t new_size)
71 {
72  if (!ptr)
73  return ptr;
74 
75  // av_realloc doesn't maintain 16 bytes alignment
76  void *new_ptr = av_malloc(new_size);
77  if (!new_ptr)
78  {
79  av_free(ptr);
80  return new_ptr;
81  }
82  memcpy(new_ptr, ptr, old_size);
83  av_free(ptr);
84  return new_ptr;
85 }
86 
87 // Encode can use either ac3 (floating point) or ac3_fixed (fixed point)
88 // To use ac3_fixed define AC3_FIXED 1
89 
90 #define AC3_FIXED 0 // NOLINT(cppcoreguidelines-macro-usage)
91 #if AC3_FIXED
92 static constexpr const char* CODECNAME { "ac3_fixed" };
93 static constexpr AVSampleFormat FFMPEG_SAMPLE_FORMAT { AV_SAMPLE_FMT_S32P };
94 static constexpr AudioFormat MYTH_SAMPLE_FORMAT { FORMAT_S32 };
95 #else
96 static constexpr const char* CODECNAME { "ac3" };
97 static constexpr AVSampleFormat FFMPEG_SAMPLE_FORMAT { AV_SAMPLE_FMT_FLTP };
99 #define MYTH_USE_FLOAT 1 // NOLINT(cppcoreguidelines-macro-usage)
100 #endif
101 
103  AVCodecID codec_id, int bitrate, int samplerate, int channels)
104 {
105  LOG(VB_AUDIO, LOG_INFO, LOC +
106  QString("Init codecid=%1, br=%2, sr=%3, ch=%4")
107  .arg(avcodec_get_name(codec_id)) .arg(bitrate)
108  .arg(samplerate) .arg(channels));
109 
110  if (!(m_inbuf || m_framebuf || m_outbuf))
111  {
112  LOG(VB_GENERAL, LOG_ERR, LOC + "Memory allocation failed");
113  return false;
114  }
115 
116  // Clear digital encoder from all existing content
117  Reset();
118 
119  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Using codec %1 to encode audio").arg(CODECNAME));
120  const AVCodec *codec = avcodec_find_encoder_by_name(CODECNAME);
121  if (!codec)
122  {
123  LOG(VB_GENERAL, LOG_ERR, LOC + "Could not find codec");
124  return false;
125  }
126 
127  m_avContext = avcodec_alloc_context3(codec);
128 
129  m_avContext->bit_rate = bitrate;
130  m_avContext->sample_rate = samplerate;
131  av_channel_layout_default(&(m_avContext->ch_layout), channels);
132  m_avContext->sample_fmt = FFMPEG_SAMPLE_FORMAT;
133 
134  // open it
135  int ret = avcodec_open2(m_avContext, codec, nullptr);
136  if (ret < 0)
137  {
138  LOG(VB_GENERAL, LOG_ERR, LOC +
139  "Could not open codec, invalid bitrate or samplerate");
140 
141  return false;
142  }
143 
144  m_spdifEnc = new SPDIFEncoder("spdif", AV_CODEC_ID_AC3);
145  if (!m_spdifEnc->Succeeded())
146  {
147  LOG(VB_GENERAL, LOG_ERR, LOC + "Could not create spdif muxer");
148  return false;
149  }
150 
151  m_samplesPerFrame = m_avContext->frame_size * m_avContext->ch_layout.nb_channels;
152 
153  LOG(VB_AUDIO, LOG_INFO, QString("DigitalEncoder::Init fs=%1, spf=%2")
154  .arg(m_avContext->frame_size) .arg(m_samplesPerFrame));
155 
156  return true;
157 }
158 
159 // input = 6 channel data from upconvert or speedup
160 // m_inbuf = 6 channel data converted to S32 or FLT samples interleaved
161 // m_framebuf = 1 frame, deinterleaved into planar format
162 // m_inlen = number of bytes available in m_inbuf
163 // format = incoming sample format, normally FORMAT_FLT
164 // upconvert and speedup both use floating point for parameter format
165 
166 int AudioOutputDigitalEncoder::Encode(void *input, int len, AudioFormat format)
167 {
168  int sampleSize = AudioOutputSettings::SampleSize(format);
169  if (sampleSize <= 0)
170  {
171  LOG(VB_AUDIO, LOG_ERR, LOC + "AC-3 encode error, sample size is zero");
172  return 0;
173  }
174 
175  // Check if there is enough space in incoming buffer
176  ssize_t required_len = m_inlen +
178 
179  if (required_len > m_inSize)
180  {
181  required_len = ((required_len / INBUFSIZE) + 1) * INBUFSIZE;
182  LOG(VB_AUDIO, LOG_INFO, LOC +
183  QString("low mem, reallocating in buffer from %1 to %2")
184  .arg(m_inSize) .arg(required_len));
185  auto *tmp = static_cast<uint8_t*> (realloc(m_inbuf, m_inSize, required_len));
186  if (!tmp)
187  {
188  m_inbuf = nullptr;
189  m_inSize = 0;
190  LOG(VB_AUDIO, LOG_ERR, LOC +
191  "AC-3 encode error, insufficient memory");
192  return m_outlen;
193  }
194  m_inbuf = tmp;
195  m_inSize = required_len;
196  }
197 
198  if (format == MYTH_SAMPLE_FORMAT)
199  {
200  // The input format is the same as the ffmpeg desired format so just copy the data
201  memcpy(m_inbuf + m_inlen, input, len);
202  m_inlen += len;
203  }
204 #if ! MYTH_USE_FLOAT
205  else if (format == FORMAT_FLT)
206  {
207  // The input format is float but ffmpeg wants something else so convert it
209  input, len);
210  }
211 #endif
212  else
213  {
214  LOG(VB_AUDIO, LOG_ERR, LOC +
215  QString("AC-3 encode error, cannot handle input format %1")
216  .arg(format));
217  return 0;
218  }
219 
221  int i = 0;
222  int channels = m_avContext->ch_layout.nb_channels;
223  int size_channel = m_avContext->frame_size *
225  if (!m_frame)
226  {
227  m_frame = av_frame_alloc();
228  if (m_frame == nullptr)
229  {
230  m_inbuf = nullptr;
231  m_inSize = 0;
232  LOG(VB_AUDIO, LOG_ERR, LOC +
233  "AC-3 encode error, insufficient memory");
234  return m_outlen;
235  }
236  }
237  else
238  {
239  av_frame_unref(m_frame);
240  }
241  m_frame->nb_samples = m_avContext->frame_size;
242  m_frame->pts = AV_NOPTS_VALUE;
243  m_frame->format = m_avContext->sample_fmt;
244  av_channel_layout_copy(&(m_frame->ch_layout), &(m_avContext->ch_layout));
245  m_frame->sample_rate = m_avContext->sample_rate;
246 
247  if (frames > 0)
248  {
249  // init AVFrame for planar data (input is interleaved)
250  for (int j = 0, jj = 0; j < channels; j++, jj += size_channel)
251  {
252  m_frame->data[j] = m_framebuf + jj;
253  }
254  }
255 
256  while (i < frames)
257  {
258  AVPacket *pkt = av_packet_alloc();
259  if (pkt == nullptr)
260  {
261  LOG(VB_RECORD, LOG_ERR, "packet allocation failed");
262  return AVERROR(ENOMEM);
263  }
264  bool got_packet = false;
265 
267  MYTH_SAMPLE_FORMAT, channels,
268  m_framebuf,
269  m_inbuf + (static_cast<ptrdiff_t>(i) * size_channel * channels),
270  size_channel * channels);
271 
272  // SUGGESTION
273  // Now that avcodec_encode_audio2 is deprecated and replaced
274  // by 2 calls, this could be optimized
275  // into separate routines or separate threads.
276  int ret = avcodec_receive_packet(m_avContext, pkt);
277  if (ret == 0)
278  got_packet = true;
279  if (ret == AVERROR(EAGAIN))
280  ret = 0;
281  if (ret == 0)
282  ret = avcodec_send_frame(m_avContext, m_frame);
283  // if ret from avcodec_send_frame is AVERROR(EAGAIN) then
284  // there are 2 packets to be received while only 1 frame to be
285  // sent. The code does not cater for this. Hopefully it will not happen.
286 
287  if (ret < 0)
288  {
289  std::string error;
290  LOG(VB_GENERAL, LOG_ERR, LOC +
291  QString("audio encode error: %1 (%2)")
292  .arg(av_make_error_stdstring(error, ret))
293  .arg(got_packet));
294  av_packet_free(&pkt);
295  return ret;
296  }
297  i++;
298  if (!got_packet)
299  {
301  continue;
302  }
303  if (!m_spdifEnc)
304  {
305  m_spdifEnc = new SPDIFEncoder("spdif", AV_CODEC_ID_AC3);
306  }
307 
308  m_spdifEnc->WriteFrame(pkt->data, pkt->size);
309  av_packet_unref(pkt);
310  av_packet_free(&pkt);
311 
312  // Check if output buffer is big enough
313  required_len = m_outlen + m_spdifEnc->GetProcessedSize();
314  if (required_len > m_outSize)
315  {
316  required_len = ((required_len / OUTBUFSIZE) + 1) * OUTBUFSIZE;
317  LOG(VB_AUDIO, LOG_WARNING, LOC +
318  QString("low mem, reallocating out buffer from %1 to %2")
319  .arg(m_outSize) .arg(required_len));
320  auto *tmp = static_cast<uint8_t*>(realloc(m_outbuf, m_outSize, required_len));
321  if (!tmp)
322  {
323  m_outbuf = nullptr;
324  m_outSize = 0;
325  LOG(VB_AUDIO, LOG_ERR, LOC +
326  "AC-3 encode error, insufficient memory");
327  return m_outlen;
328  }
329  m_outbuf = tmp;
330  m_outSize = required_len;
331  }
332  size_t data_size = 0;
333  m_spdifEnc->GetData(m_outbuf + m_outlen, data_size);
334  m_outlen += data_size;
336  }
337 
338  memmove(m_inbuf, m_inbuf + (static_cast<ptrdiff_t>(i) * m_samplesPerFrame * AudioOutputSettings::SampleSize(MYTH_SAMPLE_FORMAT)), m_inlen);
339  return m_outlen;
340 }
341 
342 int AudioOutputDigitalEncoder::GetFrames(void *ptr, int maxlen)
343 {
344  int len = std::min(maxlen, m_outlen);
345  if (len != maxlen)
346  {
347  LOG(VB_AUDIO, LOG_INFO, LOC + "GetFrames: getting less than requested");
348  }
349  memcpy(ptr, m_outbuf, len);
350  m_outlen -= len;
351  memmove(m_outbuf, m_outbuf + len, m_outlen);
352  return len;
353 }
354 
356 {
357  m_inlen = m_outlen = 0;
358 }
SPDIFEncoder::Succeeded
bool Succeeded() const
Definition: spdifencoder.h:24
error
static void error(const char *str,...)
Definition: vbi.cpp:37
AudioOutputDigitalEncoder::~AudioOutputDigitalEncoder
~AudioOutputDigitalEncoder()
Definition: audiooutputdigitalencoder.cpp:37
AudioOutputDigitalEncoder::Init
bool Init(AVCodecID codec_id, int bitrate, int samplerate, int channels)
Definition: audiooutputdigitalencoder.cpp:102
AudioOutputDigitalEncoder::GetFrames
int GetFrames(void *ptr, int maxlen)
Definition: audiooutputdigitalencoder.cpp:342
audiooutpututil.h
AudioOutputDigitalEncoder::m_outlen
int m_outlen
Definition: audiooutputdigitalencoder.h:41
FORMAT_S32
@ FORMAT_S32
Definition: audiooutputsettings.h:30
AudioOutputDigitalEncoder::realloc
static void * realloc(void *ptr, size_t old_size, size_t new_size)
Definition: audiooutputdigitalencoder.cpp:69
OUTBUFSIZE
static constexpr ssize_t OUTBUFSIZE
Definition: audiooutputdigitalencoder.h:12
AudioOutputSettings::SampleSize
static int SampleSize(AudioFormat format)
Definition: audiooutputsettings.cpp:180
AudioOutputDigitalEncoder::clear
void clear()
Definition: audiooutputdigitalencoder.cpp:355
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
AudioOutputDigitalEncoder::m_outbuf
uint8_t * m_outbuf
Definition: audiooutputdigitalencoder.h:34
AudioOutputDigitalEncoder::m_framebuf
uint8_t * m_framebuf
Definition: audiooutputdigitalencoder.h:39
AudioOutputDigitalEncoder::m_inlen
int m_inlen
Definition: audiooutputdigitalencoder.h:43
FFMPEG_SAMPLE_FORMAT
static constexpr AVSampleFormat FFMPEG_SAMPLE_FORMAT
Definition: audiooutputdigitalencoder.cpp:97
AudioOutputDigitalEncoder::m_spdifEnc
SPDIFEncoder * m_spdifEnc
Definition: audiooutputdigitalencoder.h:45
tmp
static guint32 * tmp
Definition: goom_core.cpp:26
audiooutputdigitalencoder.h
mythlogging.h
LOC
#define LOC
Definition: audiooutputdigitalencoder.cpp:20
compat.h
AudioOutputDigitalEncoder::m_inSize
ssize_t m_inSize
Definition: audiooutputdigitalencoder.h:40
CODECNAME
static constexpr const char * CODECNAME
Definition: audiooutputdigitalencoder.cpp:96
AudioOutputDigitalEncoder::Encode
int Encode(void *input, int len, AudioFormat format)
Definition: audiooutputdigitalencoder.cpp:166
INBUFSIZE
static constexpr ssize_t INBUFSIZE
Definition: audiooutputdigitalencoder.h:11
SPDIFEncoder::GetProcessedSize
int GetProcessedSize()
Definition: spdifencoder.cpp:145
AudioOutputDigitalEncoder::m_avContext
AVCodecContext * m_avContext
Definition: audiooutputdigitalencoder.h:33
SPDIFEncoder::WriteFrame
void WriteFrame(unsigned char *data, int size)
Encode data through created muxer unsigned char data: pointer to data to encode int size: size of dat...
Definition: spdifencoder.cpp:99
SPDIFEncoder::GetData
int GetData(unsigned char *buffer, size_t &dest_size)
Retrieve encoded data and copy it in the provided buffer.
Definition: spdifencoder.cpp:127
AudioOutputDigitalEncoder::m_samplesPerFrame
int m_samplesPerFrame
Definition: audiooutputdigitalencoder.h:44
mythcorecontext.h
AudioOutputDigitalEncoder::AudioOutputDigitalEncoder
AudioOutputDigitalEncoder(void)
Definition: audiooutputdigitalencoder.cpp:22
AudioFormat
AudioFormat
Definition: audiooutputsettings.h:24
MYTH_SAMPLE_FORMAT
static constexpr AudioFormat MYTH_SAMPLE_FORMAT
Definition: audiooutputdigitalencoder.cpp:98
AudioOutputDigitalEncoder::m_inbuf
uint8_t * m_inbuf
Definition: audiooutputdigitalencoder.h:37
AudioOutputUtil::DeinterleaveSamples
static void DeinterleaveSamples(AudioFormat format, int channels, uint8_t *output, const uint8_t *input, int data_size)
Deinterleave input samples Deinterleave audio samples and compact them.
Definition: audiooutpututil.cpp:303
AudioOutputUtil::fromFloat
static int fromFloat(AudioFormat format, void *out, const void *in, int bytes)
Convert float samples to integers.
Definition: audiooutpututil.cpp:76
SPDIFEncoder
Definition: spdifencoder.h:14
FORMAT_FLT
@ FORMAT_FLT
Definition: audiooutputsettings.h:31
AudioOutputDigitalEncoder::m_outSize
ssize_t m_outSize
Definition: audiooutputdigitalencoder.h:35
av_make_error_stdstring
char * av_make_error_stdstring(std::string &errbuf, int errnum)
Definition: mythaverror.cpp:41
AudioOutputDigitalEncoder::Reset
void Reset(void)
Definition: audiooutputdigitalencoder.cpp:56
AudioOutputDigitalEncoder::m_frame
AVFrame * m_frame
Definition: audiooutputdigitalencoder.h:46