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  AVCodec *codec;
92  int ret;
93 
94  LOG(VB_AUDIO, LOG_INFO, LOC +
95  QString("Init codecid=%1, br=%2, sr=%3, ch=%4")
96  .arg(ff_codec_id_string(codec_id)) .arg(bitrate)
97  .arg(samplerate) .arg(channels));
98 
99  if (!(m_in || m_inp || m_out))
100  {
101  LOG(VB_GENERAL, LOG_ERR, LOC + "Memory allocation failed");
102  return false;
103  }
104 
105  // Clear digital encoder from all existing content
106  Reset();
107 
108  codec = avcodec_find_encoder_by_name("ac3_fixed");
109  if (!codec)
110  {
111  LOG(VB_GENERAL, LOG_ERR, LOC + "Could not find codec");
112  return false;
113  }
114 
115  m_av_context = avcodec_alloc_context3(codec);
116 
117  m_av_context->bit_rate = bitrate;
118  m_av_context->sample_rate = samplerate;
119  m_av_context->channels = channels;
120  m_av_context->channel_layout = av_get_default_channel_layout(channels);
121  m_av_context->sample_fmt = AV_SAMPLE_FMT_S16P;
122 
123  // open it
124  ret = avcodec_open2(m_av_context, codec, nullptr);
125  if (ret < 0)
126  {
127  LOG(VB_GENERAL, LOG_ERR, LOC +
128  "Could not open codec, invalid bitrate or samplerate");
129 
130  return false;
131  }
132 
133  m_spdifenc = new SPDIFEncoder("spdif", AV_CODEC_ID_AC3);
134  if (!m_spdifenc->Succeeded())
135  {
136  LOG(VB_GENERAL, LOG_ERR, LOC + "Could not create spdif muxer");
137  return false;
138  }
139 
140  m_samples_per_frame = m_av_context->frame_size * m_av_context->channels;
141 
142  LOG(VB_AUDIO, LOG_INFO, QString("DigitalEncoder::Init fs=%1, spf=%2")
143  .arg(m_av_context->frame_size) .arg(m_samples_per_frame));
144 
145  return true;
146 }
147 
148 size_t AudioOutputDigitalEncoder::Encode(void *buf, int len, AudioFormat format)
149 {
150  int sampleSize = AudioOutputSettings::SampleSize(format);
151  if (sampleSize <= 0)
152  {
153  LOG(VB_AUDIO, LOG_ERR, LOC + "AC-3 encode error, sample size is zero");
154  return 0;
155  }
156 
157  // Check if there is enough space in incoming buffer
158  int required_len = m_inlen +
159  len * AudioOutputSettings::SampleSize(FORMAT_S16) / sampleSize;
160 
161  if (required_len > (int)m_in_size)
162  {
163  required_len = ((required_len / INBUFSIZE) + 1) * INBUFSIZE;
164  LOG(VB_AUDIO, LOG_INFO, LOC +
165  QString("low mem, reallocating in buffer from %1 to %2")
166  .arg(m_in_size) .arg(required_len));
167  inbuf_t *tmp = reinterpret_cast<inbuf_t*>
168  (realloc(m_in, m_in_size, required_len));
169  if (!tmp)
170  {
171  m_in = nullptr;
172  m_in_size = 0;
173  LOG(VB_AUDIO, LOG_ERR, LOC +
174  "AC-3 encode error, insufficient memory");
175  return m_outlen;
176  }
177  m_in = tmp;
178  m_in_size = required_len;
179  }
180  if (format != FORMAT_S16)
181  {
183  buf, len);
184  }
185  else
186  {
187  memcpy((char *)m_in + m_inlen, buf, len);
188  m_inlen += len;
189  }
190 
191  int frames = m_inlen / sizeof(inbuf_t) / m_samples_per_frame;
192  int i = 0;
193  int channels = m_av_context->channels;
194  int size_channel = m_av_context->frame_size *
196  if (!m_frame)
197  {
198  if (!(m_frame = av_frame_alloc()))
199  {
200  m_in = nullptr;
201  m_in_size = 0;
202  LOG(VB_AUDIO, LOG_ERR, LOC +
203  "AC-3 encode error, insufficient memory");
204  return m_outlen;
205  }
206  }
207  else
208  {
209  av_frame_unref(m_frame);
210  }
211  m_frame->nb_samples = m_av_context->frame_size;
212  m_frame->pts = AV_NOPTS_VALUE;
213 
214  if (frames > 0)
215  {
216  // init AVFrame for planar data (input is interleaved)
217  for (int j = 0, jj = 0; j < channels; j++, jj += m_av_context->frame_size)
218  {
219  m_frame->data[j] = (uint8_t*)(m_inp + jj);
220  }
221  }
222 
223  while (i < frames)
224  {
225  AVPacket pkt;
226  av_init_packet(&pkt);
227  pkt.data = nullptr;
228  pkt.size = 0;
229  bool got_packet = false;
230 
232  FORMAT_S16, channels,
233  (uint8_t*)m_inp,
234  (uint8_t*)(m_in + i * m_samples_per_frame),
235  size_channel * channels);
236 
237  // SUGGESTION
238  // Now that avcodec_encode_audio2 is deprecated and replaced
239  // by 2 calls, this could be optimized
240  // into separate routines or separate threads.
241  int ret = avcodec_receive_packet(m_av_context, &pkt);
242  if (ret == 0)
243  got_packet = true;
244  if (ret == AVERROR(EAGAIN))
245  ret = 0;
246  if (ret == 0)
247  ret = avcodec_send_frame(m_av_context, m_frame);
248  // if ret from avcodec_send_frame is AVERROR(EAGAIN) then
249  // there are 2 packets to be received while only 1 frame to be
250  // sent. The code does not cater for this. Hopefully it will not happen.
251 
252  if (ret < 0)
253  {
254  char error[AV_ERROR_MAX_STRING_SIZE];
255  LOG(VB_GENERAL, LOG_ERR, LOC +
256  QString("audio encode error: %1 (%2)")
257  .arg(av_make_error_string(error, sizeof(error), ret))
258  .arg(got_packet));
259  return ret;
260  }
261  i++;
262  if (!got_packet)
263  continue;
264 
265  if (!m_spdifenc)
266  {
267  m_spdifenc = new SPDIFEncoder("spdif", AV_CODEC_ID_AC3);
268  }
269 
270  m_spdifenc->WriteFrame(pkt.data, pkt.size);
271  av_packet_unref(&pkt);
272 
273  // Check if output buffer is big enough
274  required_len = m_outlen + m_spdifenc->GetProcessedSize();
275  if (required_len > (int)m_out_size)
276  {
277  required_len = ((required_len / OUTBUFSIZE) + 1) * OUTBUFSIZE;
278  LOG(VB_AUDIO, LOG_WARNING, LOC +
279  QString("low mem, reallocating out buffer from %1 to %2")
280  .arg(m_out_size) .arg(required_len));
281  outbuf_t *tmp = reinterpret_cast<outbuf_t*>
282  (realloc(m_out, m_out_size, required_len));
283  if (!tmp)
284  {
285  m_out = nullptr;
286  m_out_size = 0;
287  LOG(VB_AUDIO, LOG_ERR, LOC +
288  "AC-3 encode error, insufficient memory");
289  return m_outlen;
290  }
291  m_out = tmp;
292  m_out_size = required_len;
293  }
294  int data_size = 0;
295  m_spdifenc->GetData((uint8_t *)m_out + m_outlen, data_size);
296  m_outlen += data_size;
297  m_inlen -= m_samples_per_frame * sizeof(inbuf_t);
298  }
299 
300  memmove(m_in, m_in + i * m_samples_per_frame, m_inlen);
301  return m_outlen;
302 }
303 
304 size_t AudioOutputDigitalEncoder::GetFrames(void *ptr, int maxlen)
305 {
306  int len = std::min(maxlen, m_outlen);
307  if (len != maxlen)
308  {
309  LOG(VB_AUDIO, LOG_INFO, LOC + "GetFrames: getting less than requested");
310  }
311  memcpy(ptr, m_out, len);
312  m_outlen -= len;
313  memmove(m_out, (char *)m_out + len, m_outlen);
314  return len;
315 }
316 
318 {
319  m_inlen = m_outlen = 0;
320 }
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.