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 #include "mythcorecontext.h"
7 #include "config.h"
8 
9 // libav headers
10 extern "C" {
11 #include "libavutil/mem.h" // for av_free
12 #include "libavcodec/avcodec.h"
13 }
14 
15 // MythTV headers
17 #include "audiooutpututil.h"
18 #include "compat.h"
19 #include "mythlogging.h"
20 
21 #define LOC QString("DEnc: ")
22 
24 {
25  m_out = (outbuf_t *)av_mallocz(OUTBUFSIZE);
26  if (m_out)
27  {
29  }
30  m_in = (inbuf_t *)av_mallocz(INBUFSIZE);
31  if (m_in)
32  {
34  }
35  m_inp = (inbuf_t *)av_mallocz(INBUFSIZE);
36 }
37 
39 {
40  Reset();
41  if (m_out)
42  {
43  av_freep(&m_out);
44  m_out_size = 0;
45  }
46  if (m_in)
47  {
48  av_freep(&m_in);
49  m_in_size = 0;
50  }
51  if (m_inp)
52  {
53  av_freep(&m_inp);
54  }
55 }
56 
58 {
59  if (m_av_context)
60  avcodec_free_context(&m_av_context);
61 
62  av_frame_free(&m_frame);
63 
64  delete m_spdifenc;
65  m_spdifenc = nullptr;
66 
67  clear();
68 }
69 
71  size_t old_size, size_t new_size)
72 {
73  if (!ptr)
74  return ptr;
75 
76  // av_realloc doesn't maintain 16 bytes alignment
77  void *new_ptr = av_malloc(new_size);
78  if (!new_ptr)
79  {
80  av_free(ptr);
81  return new_ptr;
82  }
83  memcpy(new_ptr, ptr, old_size);
84  av_free(ptr);
85  return new_ptr;
86 }
87 
89  AVCodecID codec_id, int bitrate, int samplerate, int channels)
90 {
91  LOG(VB_AUDIO, LOG_INFO, LOC +
92  QString("Init codecid=%1, br=%2, sr=%3, ch=%4")
93  .arg(ff_codec_id_string(codec_id)) .arg(bitrate)
94  .arg(samplerate) .arg(channels));
95 
96  if (!(m_in || m_inp || m_out))
97  {
98  LOG(VB_GENERAL, LOG_ERR, LOC + "Memory allocation failed");
99  return false;
100  }
101 
102  // Clear digital encoder from all existing content
103  Reset();
104 
105  AVCodec *codec = avcodec_find_encoder_by_name("ac3_fixed");
106  if (!codec)
107  {
108  LOG(VB_GENERAL, LOG_ERR, LOC + "Could not find codec");
109  return false;
110  }
111 
112  m_av_context = avcodec_alloc_context3(codec);
113 
114  m_av_context->bit_rate = bitrate;
115  m_av_context->sample_rate = samplerate;
116  m_av_context->channels = channels;
117  m_av_context->channel_layout = av_get_default_channel_layout(channels);
118  m_av_context->sample_fmt = AV_SAMPLE_FMT_S16P;
119 
120  // open it
121  int ret = avcodec_open2(m_av_context, codec, nullptr);
122  if (ret < 0)
123  {
124  LOG(VB_GENERAL, LOG_ERR, LOC +
125  "Could not open codec, invalid bitrate or samplerate");
126 
127  return false;
128  }
129 
130  m_spdifenc = new SPDIFEncoder("spdif", AV_CODEC_ID_AC3);
131  if (!m_spdifenc->Succeeded())
132  {
133  LOG(VB_GENERAL, LOG_ERR, LOC + "Could not create spdif muxer");
134  return false;
135  }
136 
137  m_samples_per_frame = m_av_context->frame_size * m_av_context->channels;
138 
139  LOG(VB_AUDIO, LOG_INFO, QString("DigitalEncoder::Init fs=%1, spf=%2")
140  .arg(m_av_context->frame_size) .arg(m_samples_per_frame));
141 
142  return true;
143 }
144 
145 size_t AudioOutputDigitalEncoder::Encode(void *buf, int len, AudioFormat format)
146 {
147  int sampleSize = AudioOutputSettings::SampleSize(format);
148  if (sampleSize <= 0)
149  {
150  LOG(VB_AUDIO, LOG_ERR, LOC + "AC-3 encode error, sample size is zero");
151  return 0;
152  }
153 
154  // Check if there is enough space in incoming buffer
155  int required_len = m_inlen +
156  len * AudioOutputSettings::SampleSize(FORMAT_S16) / sampleSize;
157 
158  if (required_len > (int)m_in_size)
159  {
160  required_len = ((required_len / INBUFSIZE) + 1) * INBUFSIZE;
161  LOG(VB_AUDIO, LOG_INFO, LOC +
162  QString("low mem, reallocating in buffer from %1 to %2")
163  .arg(m_in_size) .arg(required_len));
164  inbuf_t *tmp = reinterpret_cast<inbuf_t*>
165  (realloc(m_in, m_in_size, required_len));
166  if (!tmp)
167  {
168  m_in = nullptr;
169  m_in_size = 0;
170  LOG(VB_AUDIO, LOG_ERR, LOC +
171  "AC-3 encode error, insufficient memory");
172  return m_outlen;
173  }
174  m_in = tmp;
175  m_in_size = required_len;
176  }
177  if (format != FORMAT_S16)
178  {
180  buf, len);
181  }
182  else
183  {
184  memcpy((char *)m_in + m_inlen, buf, len);
185  m_inlen += len;
186  }
187 
188  int frames = m_inlen / sizeof(inbuf_t) / m_samples_per_frame;
189  int i = 0;
190  int channels = m_av_context->channels;
191  int size_channel = m_av_context->frame_size *
193  if (!m_frame)
194  {
195  if (!(m_frame = av_frame_alloc()))
196  {
197  m_in = nullptr;
198  m_in_size = 0;
199  LOG(VB_AUDIO, LOG_ERR, LOC +
200  "AC-3 encode error, insufficient memory");
201  return m_outlen;
202  }
203  }
204  else
205  {
206  av_frame_unref(m_frame);
207  }
208  m_frame->nb_samples = m_av_context->frame_size;
209  m_frame->pts = AV_NOPTS_VALUE;
210 
211  if (frames > 0)
212  {
213  // init AVFrame for planar data (input is interleaved)
214  for (int j = 0, jj = 0; j < channels; j++, jj += m_av_context->frame_size)
215  {
216  m_frame->data[j] = (uint8_t*)(m_inp + jj);
217  }
218  }
219 
220  while (i < frames)
221  {
222  AVPacket pkt;
223  av_init_packet(&pkt);
224  pkt.data = nullptr;
225  pkt.size = 0;
226  bool got_packet = false;
227 
229  FORMAT_S16, channels,
230  (uint8_t*)m_inp,
231  (uint8_t*)(m_in + i * m_samples_per_frame),
232  size_channel * channels);
233 
234  // SUGGESTION
235  // Now that avcodec_encode_audio2 is deprecated and replaced
236  // by 2 calls, this could be optimized
237  // into separate routines or separate threads.
238  int ret = avcodec_receive_packet(m_av_context, &pkt);
239  if (ret == 0)
240  got_packet = true;
241  if (ret == AVERROR(EAGAIN))
242  ret = 0;
243  if (ret == 0)
244  ret = avcodec_send_frame(m_av_context, m_frame);
245  // if ret from avcodec_send_frame is AVERROR(EAGAIN) then
246  // there are 2 packets to be received while only 1 frame to be
247  // sent. The code does not cater for this. Hopefully it will not happen.
248 
249  if (ret < 0)
250  {
251  char error[AV_ERROR_MAX_STRING_SIZE];
252  LOG(VB_GENERAL, LOG_ERR, LOC +
253  QString("audio encode error: %1 (%2)")
254  .arg(av_make_error_string(error, sizeof(error), ret))
255  .arg(got_packet));
256  return ret;
257  }
258  i++;
259  if (!got_packet)
260  continue;
261 
262  if (!m_spdifenc)
263  {
264  m_spdifenc = new SPDIFEncoder("spdif", AV_CODEC_ID_AC3);
265  }
266 
267  m_spdifenc->WriteFrame(pkt.data, pkt.size);
268  av_packet_unref(&pkt);
269 
270  // Check if output buffer is big enough
271  required_len = m_outlen + m_spdifenc->GetProcessedSize();
272  if (required_len > (int)m_out_size)
273  {
274  required_len = ((required_len / OUTBUFSIZE) + 1) * OUTBUFSIZE;
275  LOG(VB_AUDIO, LOG_WARNING, LOC +
276  QString("low mem, reallocating out buffer from %1 to %2")
277  .arg(m_out_size) .arg(required_len));
278  outbuf_t *tmp = reinterpret_cast<outbuf_t*>
279  (realloc(m_out, m_out_size, required_len));
280  if (!tmp)
281  {
282  m_out = nullptr;
283  m_out_size = 0;
284  LOG(VB_AUDIO, LOG_ERR, LOC +
285  "AC-3 encode error, insufficient memory");
286  return m_outlen;
287  }
288  m_out = tmp;
289  m_out_size = required_len;
290  }
291  int data_size = 0;
292  m_spdifenc->GetData((uint8_t *)m_out + m_outlen, data_size);
293  m_outlen += data_size;
294  m_inlen -= m_samples_per_frame * sizeof(inbuf_t);
295  }
296 
297  memmove(m_in, m_in + i * m_samples_per_frame, m_inlen);
298  return m_outlen;
299 }
300 
301 size_t AudioOutputDigitalEncoder::GetFrames(void *ptr, int maxlen)
302 {
303  int len = std::min(maxlen, m_outlen);
304  if (len != maxlen)
305  {
306  LOG(VB_AUDIO, LOG_INFO, LOC + "GetFrames: getting less than requested");
307  }
308  memcpy(ptr, m_out, len);
309  m_outlen -= len;
310  memmove(m_out, (char *)m_out + len, m_outlen);
311  return len;
312 }
313 
315 {
316  m_inlen = m_outlen = 0;
317 }
static void * realloc(void *ptr, size_t old_size, size_t new_size)
bool Init(AVCodecID codec_id, int bitrate, int samplerate, int channels)
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...
static void error(const char *str,...)
Definition: vbi.c:42
size_t GetFrames(void *ptr, int maxlen)
static guint32 * tmp
Definition: goom_core.c:35
static int fromFloat(AudioFormat format, void *out, const void *in, int bytes)
Convert float samples to integers.
static int SampleSize(AudioFormat format)
void * av_malloc(unsigned int size)
bool Succeeded()
Definition: spdifencoder.h:24
#define INBUFSIZE
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
int GetProcessedSize()
Definition: spdifencoder.h:21
const char * frames[3]
Definition: element.c:46
int GetData(unsigned char *buffer, int &dest_size)
Retrieve encoded data and copy it in the provided buffer.
void av_free(void *ptr)
size_t Encode(void *buf, int len, AudioFormat format)
#define OUTBUFSIZE
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.