MythTV  master
audioreencodebuffer.cpp
Go to the documentation of this file.
1 
2 #include "audioreencodebuffer.h"
3 
4 #include <algorithm> // for min/max
5 
6 extern "C" {
7 #include "libavutil/mem.h"
8 }
9 
10 
12 {
13  m_buffer = (uint8_t *)av_malloc(ABLOCK_SIZE);
14  if (m_buffer == nullptr)
15  {
16  throw std::bad_alloc();
17  }
18 }
19 
21  : m_size(old.m_size), m_realsize(old.m_realsize),
22  m_frames(old.m_frames), m_time(old.m_time)
23 {
24  m_buffer = (uint8_t *)av_malloc(m_realsize);
25  if (m_buffer == nullptr)
26  {
27  throw std::bad_alloc();
28  }
29  memcpy(m_buffer, old.m_buffer, m_size);
30 }
31 
33 {
34  av_free(m_buffer);
35 }
36 
37 void AudioBuffer::appendData(unsigned char *buffer, int len, int frames,
38  std::chrono::milliseconds time)
39 {
40  if ((m_size + len) > m_realsize)
41  {
42  // buffer is too small to fit all
43  // can't use av_realloc as it doesn't guarantee reallocated memory
44  // to be 16 bytes aligned
45  m_realsize = ((m_size + len) / ABLOCK_SIZE + 1 ) * ABLOCK_SIZE;
46  auto *tmp = (uint8_t *)av_malloc(m_realsize);
47  if (tmp == nullptr)
48  {
49  throw std::bad_alloc();
50  }
51  memcpy(tmp, m_buffer, m_size);
52  av_free(m_buffer);
53  m_buffer = tmp;
54  }
55 
56  memcpy(m_buffer + m_size, buffer, len);
57  m_size += len;
58  m_frames += frames;
59  m_time = time;
60 }
61 
63 
65  int audio_channels, bool passthru)
66  : m_initpassthru(passthru)
67 {
69  const AudioSettings settings(audio_format, audio_channels, AV_CODEC_ID_NONE, 0, false);
71 }
72 
74 {
76  delete m_saveBuffer;
77 }
78 
83 {
84  ClearError();
85 
86  m_passthru = settings.m_usePassthru;
87  m_channels = settings.m_channels;
90  m_eff_audiorate = settings.m_sampleRate;
91 }
92 
97 {
98  m_eff_audiorate = (dsprate / 100);
99 }
100 
102 {
103  QMutexLocker locker(&m_bufferMutex);
104  for (AudioBuffer *ab : qAsConst(m_bufferList))
105  {
106  delete ab;
107  }
108  m_bufferList.clear();
109 }
110 
121 bool AudioReencodeBuffer::AddFrames(void *buffer, int frames, std::chrono::milliseconds timecode)
122 {
123  return AddData(buffer, frames * m_bytes_per_frame, timecode, frames);
124 }
125 
137 bool AudioReencodeBuffer::AddData(void *buffer, int len, std::chrono::milliseconds timecode,
138  int frames)
139 {
140  auto *buf = (unsigned char *)buffer;
141 
142  // Test if target is using a fixed buffer size.
143  if (m_audioFrameSize)
144  {
145  int index = 0;
146 
147  // Target has a fixed buffer size, which may not match len.
148  // Redistribute the bytes into appropriately sized buffers.
149  while (index < len)
150  {
151  // See if we have some saved from last iteration in
152  // m_saveBuffer. If not create a new empty buffer.
153  if (!m_saveBuffer)
154  m_saveBuffer = new AudioBuffer();
155 
156  // Use as many of the remaining frames as will fit in the space
157  // left in the buffer.
158  int bufsize = m_saveBuffer->size();
159  int part = std::min(len - index, m_audioFrameSize - bufsize);
160  int out_frames = part / m_bytes_per_frame;
161  timecode += std::chrono::milliseconds(out_frames * 1000 / m_eff_audiorate);
162 
163  // Store frames in buffer, basing frame count on number of
164  // bytes, which works only for uncompressed data.
165  m_saveBuffer->appendData(&buf[index], part,
166  out_frames, timecode);
167 
168  // If we have filled the buffer...
170  {
171  QMutexLocker locker(&m_bufferMutex);
172 
173  // store the buffer
174  m_bufferList.append(m_saveBuffer);
175  // mark m_saveBuffer as emtpy.
176  m_saveBuffer = nullptr;
177  // m_last_audiotime is updated iff we store a buffer.
178  m_last_audiotime = timecode;
179  }
180 
181  index += part;
182  }
183  }
184  else
185  {
186  // Target has no fixed buffer size. We can use a simpler algorithm
187  // and use 'frames' directly rather than 'len / m_bytes_per_frame',
188  // thus also covering the passthrough case.
189  m_saveBuffer = new AudioBuffer();
190  timecode += std::chrono::milliseconds(frames * 1000 / m_eff_audiorate);
191  m_saveBuffer->appendData(buf, len, frames, timecode);
192 
193  QMutexLocker locker(&m_bufferMutex);
194  m_bufferList.append(m_saveBuffer);
195  m_saveBuffer = nullptr;
196  m_last_audiotime = timecode;
197  }
198 
199  return true;
200 }
201 
202 AudioBuffer *AudioReencodeBuffer::GetData(std::chrono::milliseconds time)
203 {
204  QMutexLocker locker(&m_bufferMutex);
205 
206  if (m_bufferList.isEmpty())
207  return nullptr;
208 
209  AudioBuffer *ab = m_bufferList.front();
210 
211  if (ab->m_time <= time)
212  {
213  m_bufferList.pop_front();
214  return ab;
215  }
216 
217  return nullptr;
218 }
219 
220 long long AudioReencodeBuffer::GetSamples(std::chrono::milliseconds time)
221 {
222  QMutexLocker locker(&m_bufferMutex);
223 
224  if (m_bufferList.isEmpty())
225  return 0;
226 
227  long long samples = 0;
228  for (auto *ab : qAsConst(m_bufferList))
229  {
230  if (ab->m_time <= time)
231  samples += ab->m_frames;
232  else
233  break;
234  }
235  return samples;
236 }
237 
238 void AudioReencodeBuffer::SetTimecode(std::chrono::milliseconds timecode)
239 {
240  m_last_audiotime = timecode;
241 }
242 
243 /* vim: set expandtab tabstop=4 shiftwidth=4: */
244 
AudioBuffer::appendData
void appendData(unsigned char *buffer, int len, int frames, std::chrono::milliseconds time)
Definition: audioreencodebuffer.cpp:37
AudioReencodeBuffer::~AudioReencodeBuffer
~AudioReencodeBuffer() override
Definition: audioreencodebuffer.cpp:73
AudioBuffer::m_buffer
uint8_t * m_buffer
Definition: audioreencodebuffer.h:20
AudioReencodeBuffer::m_eff_audiorate
int m_eff_audiorate
Definition: audioreencodebuffer.h:73
AudioReencodeBuffer::AudioReencodeBuffer
AudioReencodeBuffer(AudioFormat audio_format, int audio_channels, bool passthru)
Definition: audioreencodebuffer.cpp:64
AudioBuffer::m_size
size_t m_size
Definition: audioreencodebuffer.h:21
AudioOutputSettings::SampleSize
static int SampleSize(AudioFormat format)
Definition: audiooutputsettings.cpp:180
tmp
static guint32 * tmp
Definition: goom_core.cpp:26
AudioSettings::m_sampleRate
int m_sampleRate
Definition: audiosettings.h:76
AudioSettings
Definition: audiosettings.h:28
AudioBuffer::m_time
std::chrono::milliseconds m_time
Definition: audioreencodebuffer.h:24
AudioReencodeBuffer::Reconfigure
void Reconfigure(const AudioSettings &settings) override
reconfigure sound out for new params
Definition: audioreencodebuffer.cpp:82
AudioBuffer::~AudioBuffer
~AudioBuffer()
Definition: audioreencodebuffer.cpp:32
AudioReencodeBuffer::GetData
AudioBuffer * GetData(std::chrono::milliseconds time)
Definition: audioreencodebuffer.cpp:202
AudioReencodeBuffer::m_bytes_per_frame
int m_bytes_per_frame
Definition: audioreencodebuffer.h:72
AudioReencodeBuffer::m_saveBuffer
AudioBuffer * m_saveBuffer
Definition: audioreencodebuffer.h:82
AudioReencodeBuffer::SetEffDsp
void SetEffDsp(int dsprate) override
Definition: audioreencodebuffer.cpp:96
AudioReencodeBuffer::m_audioFrameSize
int m_audioFrameSize
Definition: audioreencodebuffer.h:76
AudioBuffer::size
int size(void) const
Definition: audioreencodebuffer.h:18
AudioBuffer::m_realsize
size_t m_realsize
Definition: audioreencodebuffer.h:22
AudioReencodeBuffer::Reset
void Reset(void) override
Definition: audioreencodebuffer.cpp:101
AudioBuffer::m_frames
int m_frames
Definition: audioreencodebuffer.h:23
AudioReencodeBuffer::AddData
bool AddData(void *buffer, int len, std::chrono::milliseconds timecode, int frames) override
Add data to the audiobuffer for playback.
Definition: audioreencodebuffer.cpp:137
AudioSettings::m_usePassthru
bool m_usePassthru
Definition: audiosettings.h:78
AudioSettings::m_format
AudioFormat m_format
Definition: audiosettings.h:72
ABLOCK_SIZE
static constexpr size_t ABLOCK_SIZE
Definition: audioreencodebuffer.h:7
AudioReencodeBuffer::m_passthru
bool m_passthru
Definition: audioreencodebuffer.h:75
AudioReencodeBuffer::SetTimecode
void SetTimecode(std::chrono::milliseconds timecode) override
Definition: audioreencodebuffer.cpp:238
AudioReencodeBuffer::m_bufferMutex
QMutex m_bufferMutex
Definition: audioreencodebuffer.h:80
AudioOutput::ClearError
void ClearError(void)
Definition: audiooutput.cpp:292
AudioReencodeBuffer::m_bufferList
QList< AudioBuffer * > m_bufferList
Definition: audioreencodebuffer.h:81
AudioReencodeBuffer::m_last_audiotime
std::chrono::milliseconds m_last_audiotime
Definition: audioreencodebuffer.h:74
AudioBuffer
Definition: audioreencodebuffer.h:9
audioreencodebuffer.h
AudioBuffer::AudioBuffer
AudioBuffer()
Definition: audioreencodebuffer.cpp:11
AudioFormat
AudioFormat
Definition: audiooutputsettings.h:24
AudioReencodeBuffer::m_channels
int m_channels
Definition: audioreencodebuffer.h:71
samples
static const std::array< const uint64_t, 4 > samples
Definition: element.cpp:46
AudioReencodeBuffer::AddFrames
bool AddFrames(void *buffer, int frames, std::chrono::milliseconds timecode) override
Add frames to the audiobuffer for playback.
Definition: audioreencodebuffer.cpp:121
AudioReencodeBuffer::GetSamples
long long GetSamples(std::chrono::milliseconds time)
Definition: audioreencodebuffer.cpp:220
AudioSettings::m_channels
int m_channels
Definition: audiosettings.h:73