summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Reufer <thomas@reufer.ch>2015-01-17 16:10:24 +0100
committerThomas Reufer <thomas@reufer.ch>2015-01-17 16:30:27 +0100
commit8882672ee12216184d3afa21fdfee843ea1c08b0 (patch)
treec3911fa3788656380424b7e20de2d3b527209676
parenta0ddf4b2ad85370e723f8fd25fe33aeee400a9d1 (diff)
downloadvdr-plugin-rpihddevice-8882672ee12216184d3afa21fdfee843ea1c08b0.tar.gz
vdr-plugin-rpihddevice-8882672ee12216184d3afa21fdfee843ea1c08b0.tar.bz2
reworked audio decoder, increase buffering of audio samples
-rw-r--r--HISTORY1
-rw-r--r--audio.c568
-rw-r--r--audio.h18
3 files changed, 341 insertions, 246 deletions
diff --git a/HISTORY b/HISTORY
index f9b5875..2b2dc55 100644
--- a/HISTORY
+++ b/HISTORY
@@ -2,6 +2,7 @@ VDR Plugin 'rpihddevice' Revision History
-----------------------------------------
- new:
+ - reworked audio decoder, increase buffering of audio samples
- reworked omxdevice and improved clock stretching for transfer mode
- added Hungarian translations (thanks to Füley István)
- updated Finnish translations and fixed tr() usage (thanks to Rolf Ahrenberg)
diff --git a/audio.c b/audio.c
index 8b746c2..1c8aa0d 100644
--- a/audio.c
+++ b/audio.c
@@ -19,14 +19,12 @@ extern "C" {
// ffmpeg's resampling
#ifdef HAVE_LIBSWRESAMPLE
# include <libswresample/swresample.h>
-# define DO_RESAMPLE
#endif
// libav's resampling
#ifdef HAVE_LIBAVRESAMPLE
# include <libavresample/avresample.h>
# include <libavutil/samplefmt.h>
-# define DO_RESAMPLE
# define SwrContext AVAudioResampleContext
# define swr_alloc avresample_alloc_context
# define swr_init avresample_open
@@ -221,6 +219,7 @@ public:
}
else
{
+ m_ptsQueue.front()->pts = 0;
length -= m_ptsQueue.front()->length -= length;
length = 0;
}
@@ -355,9 +354,9 @@ private:
std::queue<Pts*> m_ptsQueue;
bool m_parsed;
- /* ------------------------------------------------------------------------- */
- /* audio codec parser helper functions, based on vdr-softhddevice */
- /* ------------------------------------------------------------------------- */
+ /* ---------------------------------------------------------------------- */
+ /* audio codec parser helper functions, based on vdr-softhddevice */
+ /* ---------------------------------------------------------------------- */
static const uint16_t BitRateTable[2][3][16];
static const uint16_t MpegSampleRateTable[4];
@@ -445,7 +444,8 @@ private:
samplingRate >>= mpeg2; // MPEG 2 half rate
samplingRate >>= mpeg25; // MPEG 2.5 quarter rate
- int bit_rate = BitRateTable[mpeg2 | mpeg25][layer - 1][(p[2] >> 4) & 0x0F];
+ int bit_rate =
+ BitRateTable[mpeg2 | mpeg25][layer - 1][(p[2] >> 4) & 0x0F];
if (!bit_rate)
return false;
@@ -856,20 +856,283 @@ const uint32_t cRpiAudioDecoder::cParser::DtsSampleRateTable[16] =
fmt == AV_SAMPLE_FMT_FLTP ? "float, planar" : \
fmt == AV_SAMPLE_FMT_DBLP ? "double, planar" : "unknown")
+/* ------------------------------------------------------------------------- */
+
+class cRpiAudioRender
+{
+
+public:
+
+ cRpiAudioRender(cOmx *omx) :
+ m_mutex(new cMutex()),
+ m_omx(omx),
+ m_resample(0),
+ m_port(cRpiAudioPort::eLocal),
+ m_codec(cAudioCodec::eInvalid),
+ m_inChannels(0),
+ m_outChannels(0),
+ m_samplingRate(0),
+ m_frameSize(0),
+ m_configured(false),
+ m_running(false),
+ m_pcmSampleFormat(AV_SAMPLE_FMT_NONE),
+ m_resamplerConfigured(false),
+ m_pts(0)
+ {
+ }
+
+ ~cRpiAudioRender()
+ {
+ Flush();
+ swr_free(&m_resample);
+ delete m_mutex;
+ }
+
+ int WriteSamples(uint8_t** data, int samples, uint64_t pts,
+ AVSampleFormat sampleFormat = AV_SAMPLE_FMT_NONE)
+ {
+ if (!Ready())
+ return 0;
+
+ m_mutex->Lock();
+ int copied = 0;
+
+ if (sampleFormat == AV_SAMPLE_FMT_NONE)
+ {
+ // pass through
+ while (samples > copied)
+ {
+ OMX_BUFFERHEADERTYPE *buf = m_omx->GetAudioBuffer(pts);
+ if (!buf)
+ break;
+
+ unsigned int len = samples - copied;
+ if (len > buf->nAllocLen)
+ len = buf->nAllocLen;
+
+ memcpy(buf->pBuffer, *data + copied, len);
+ buf->nFilledLen = len;
+
+ if (!m_omx->EmptyAudioBuffer(buf))
+ break;
+
+ copied += len;
+ pts = 0;
+ }
+ }
+ else
+ {
+ if (!m_resamplerConfigured || m_pcmSampleFormat != sampleFormat)
+ {
+ m_pcmSampleFormat = sampleFormat;
+ ApplyResamplerSettings();
+ }
+ if (m_resample)
+ {
+ // local decode, do resampling
+ m_pts = pts ? pts : m_pts;
+ OMX_BUFFERHEADERTYPE *buf = m_omx->GetAudioBuffer(m_pts);
+ if (buf)
+ {
+ if (buf->nAllocLen >= (samples * m_outChannels *
+ av_get_bytes_per_sample(AV_SAMPLE_FMT_S16)))
+ {
+ uint8_t *dst[] = { buf->pBuffer };
+ int copiedSamples = swr_convert(m_resample,
+ dst, samples, (const uint8_t **)data, samples);
+
+ buf->nFilledLen = av_samples_get_buffer_size(NULL,
+ m_outChannels, copiedSamples, AV_SAMPLE_FMT_S16, 1);
+
+ m_pts += copiedSamples * 90000 / m_samplingRate;
+ }
+ copied = m_omx->EmptyAudioBuffer(buf) ? samples : 0;
+ }
+ }
+ else
+ copied = samples;
+ }
+ m_mutex->Unlock();
+ return copied;
+ }
+
+ void Flush(void)
+ {
+ m_mutex->Lock();
+ if (m_running)
+ m_omx->StopAudio();
+ m_configured = false;
+ m_running = false;
+ m_pts = 0;
+ m_mutex->Unlock();
+ }
+
+ void SetCodec(cAudioCodec::eCodec codec, unsigned int channels,
+ unsigned int samplingRate, unsigned int frameSize)
+ {
+ m_mutex->Lock();
+ if (codec != cAudioCodec::eInvalid && channels > 0)
+ {
+ m_inChannels = channels;
+ cRpiAudioPort::ePort newPort = cRpiAudioPort::eLocal;
+ cAudioCodec::eCodec newCodec = cAudioCodec::ePCM;
+
+ DLOG("new audio codec: %dch %s", channels, cAudioCodec::Str(codec));
+
+ if (cRpiSetup::GetAudioPort() == cRpiAudioPort::eHDMI &&
+ cRpiSetup::IsAudioFormatSupported(cAudioCodec::ePCM, channels,
+ samplingRate))
+ {
+ newPort = cRpiAudioPort::eHDMI;
+
+ // check if pass through is possible
+ if (cRpiSetup::IsAudioPassthrough() &&
+ cRpiSetup::IsAudioFormatSupported(codec, channels,
+ samplingRate))
+ newCodec = codec;
+
+ // if we decode locally, upmix mono channels to 2.0
+ else if (channels == 1)
+ channels = 2;
+ }
+ else
+ {
+ channels = 2;
+ // if 2ch PCM audio on HDMI is supported
+ if (cRpiSetup::GetAudioPort() == cRpiAudioPort::eHDMI &&
+ cRpiSetup::IsAudioFormatSupported(cAudioCodec::ePCM, 2,
+ samplingRate))
+ newPort = cRpiAudioPort::eHDMI;
+ }
+
+ // if the user changes the port, this should change immediately
+ if (newPort != m_port)
+ Flush();
+
+ // save new settings to be applied when render is ready
+ if (newPort != m_port || m_codec != newCodec ||
+ m_outChannels != channels || m_samplingRate != samplingRate)
+ {
+ m_configured = false;
+ m_port = newPort;
+ m_codec = newCodec;
+ m_outChannels = channels;
+ m_samplingRate = samplingRate;
+ m_frameSize = frameSize;
+ }
+ m_resamplerConfigured = false;
+ }
+ m_mutex->Unlock();
+ }
+
+ bool IsPassthrough(void)
+ {
+ return m_codec != cAudioCodec::ePCM;
+ }
+
+ bool Ready(void)
+ {
+ if (!m_configured)
+ {
+ // wait until render is ready before applying new settings
+ if (m_running && m_omx->GetAudioLatency())
+ return false;
+
+ ApplyRenderSettings();
+ }
+ return true;
+ }
+
+private:
+
+ cRpiAudioRender(const cRpiAudioRender&);
+ cRpiAudioRender& operator= (const cRpiAudioRender&);
+
+ void ApplyRenderSettings(void)
+ {
+ if (m_running)
+ m_omx->StopAudio();
+
+ if (m_codec != cAudioCodec::eInvalid)
+ {
+ m_omx->SetupAudioRender(m_codec, m_outChannels, m_port,
+ m_samplingRate, m_frameSize);
+
+ ILOG("set %s audio output format to %dch %s, %d.%dkHz%s",
+ cRpiAudioPort::Str(m_port), m_outChannels,
+ cAudioCodec::Str(m_codec),
+ m_samplingRate / 1000, (m_samplingRate % 1000) / 100,
+ m_codec != cAudioCodec::ePCM ? " (pass-through)" : "");
+
+ if (m_port == cRpiAudioPort::eHDMI)
+ cRpiSetup::SetHDMIChannelMapping(m_codec != cAudioCodec::ePCM,
+ m_outChannels);
+ }
+ m_running = m_codec != cAudioCodec::eInvalid;
+ m_configured = true;
+ }
+
+ void ApplyResamplerSettings(void)
+ {
+ swr_free(&m_resample);
+ m_resample = swr_alloc();
+ if (m_resample)
+ {
+ av_opt_set_int(m_resample, "in_sample_rate", m_samplingRate, 0);
+ av_opt_set_int(m_resample, "in_sample_fmt", m_pcmSampleFormat, 0);
+ av_opt_set_int(m_resample, "in_channel_layout",
+ AV_CH_LAYOUT(m_inChannels), 0);
+
+ av_opt_set_int(m_resample, "out_sample_rate", m_samplingRate, 0);
+ av_opt_set_int(m_resample, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0);
+ av_opt_set_int(m_resample, "out_channel_layout",
+ AV_CH_LAYOUT(m_outChannels), 0);
+
+ swr_init(m_resample);
+ m_resamplerConfigured = true;
+ }
+ else
+ ELOG("failed to allocate resampling context!");
+ }
+
+ cMutex *m_mutex;
+ cOmx *m_omx;
+ SwrContext *m_resample;
+
+ cRpiAudioPort::ePort m_port;
+ cAudioCodec::eCodec m_codec;
+ unsigned int m_inChannels;
+ unsigned int m_outChannels;
+ unsigned int m_samplingRate;
+ unsigned int m_frameSize;
+ bool m_configured;
+ bool m_running;
+
+ AVSampleFormat m_pcmSampleFormat;
+ bool m_resamplerConfigured;
+ uint64_t m_pts;
+};
+
+/* ------------------------------------------------------------------------- */
+
cRpiAudioDecoder::cRpiAudioDecoder(cOmx *omx) :
- cThread(),
+ cThread("audio decoder"),
m_passthrough(false),
m_reset(false),
m_setupChanged(true),
m_wait(new cCondWait()),
m_parser(new cParser()),
- m_omx(omx)
+ m_render(new cRpiAudioRender(omx))
{
memset(m_codecs, 0, sizeof(m_codecs));
}
cRpiAudioDecoder::~cRpiAudioDecoder()
{
+ if (Active())
+ Reset();
+
+ delete m_render;
delete m_parser;
delete m_wait;
}
@@ -937,8 +1200,9 @@ int cRpiAudioDecoder::DeInit(void)
m_wait->Signal();
while (Active())
- cCondWait::SleepMs(50);
+ cCondWait::SleepMs(5);
+ m_render->Flush();
cRpiSetup::SetAudioSetupChangedCallback(0);
for (int i = 0; i < cAudioCodec::eNumCodecs; i++)
@@ -971,12 +1235,10 @@ bool cRpiAudioDecoder::WriteData(const unsigned char *buf, unsigned int length,
void cRpiAudioDecoder::Reset(void)
{
Lock();
-
m_reset = true;
m_wait->Signal();
while (m_reset)
- cCondWait::SleepMs(1);
-
+ cCondWait::SleepMs(5);
Unlock();
}
@@ -996,18 +1258,10 @@ void cRpiAudioDecoder::Action(void)
DLOG("cAudioDecoder() thread started");
unsigned int channels = 0;
- unsigned int outputChannels = 0;
unsigned int samplingRate = 0;
-
-#ifdef DO_RESAMPLE
- AVSampleFormat sampleFormat = AV_SAMPLE_FMT_NONE;
- SwrContext *resample = 0;
-#endif
-
cAudioCodec::eCodec codec = cAudioCodec::eInvalid;
- OMX_BUFFERHEADERTYPE *buf = 0;
- AVFrame *frame = av_frame_alloc();
+ AVFrame *frame = av_frame_alloc();
if (!frame)
{
ELOG("failed to allocate audio frame!");
@@ -1016,6 +1270,14 @@ void cRpiAudioDecoder::Action(void)
while (Running())
{
+ if (m_reset)
+ {
+ m_parser->Reset();
+ m_render->Flush();
+ av_frame_unref(frame);
+ m_reset = false;
+ }
+
// test for codec change if there is data in parser and no left over
if (!m_parser->Empty() && !frame->nb_samples)
m_setupChanged |= codec != m_parser->GetCodec() ||
@@ -1023,259 +1285,91 @@ void cRpiAudioDecoder::Action(void)
samplingRate != m_parser->GetSamplingRate();
// if necessary, set up audio codec
- if (m_setupChanged)
+ if (!m_parser->Empty() && m_setupChanged)
{
+ if (codec != m_parser->GetCodec() && codec != cAudioCodec::eInvalid)
+ avcodec_flush_buffers(m_codecs[codec].context);
+
codec = m_parser->GetCodec();
channels = m_parser->GetChannels();
samplingRate = m_parser->GetSamplingRate();
- outputChannels = channels;
- SetCodec(codec, outputChannels, samplingRate,
- m_parser->GetFrameSize());
-
- av_frame_unref(frame);
- m_setupChanged = false;
-#ifdef DO_RESAMPLE
- sampleFormat = AV_SAMPLE_FMT_NONE;
+#if FF_API_REQUEST_CHANNELS
+ m_codecs[codec].context->request_channels = channels;
#endif
+ m_codecs[codec].context->request_channel_layout =
+ AV_CH_LAYOUT(channels);
- if (codec == cAudioCodec::eInvalid)
- m_reset = true;
- }
-
- // get free buffer
- while ((!m_parser->Empty() || frame->nb_samples) && !buf && !m_reset)
- {
- buf = m_omx->GetAudioBuffer(m_parser->GetPts());
- if (!buf)
- m_wait->Wait(10);
- else
- buf->nFilledLen = 0;
+ // validate channel layout and apply new audio parameters
+ if (m_codecs[codec].context->request_channel_layout)
+ {
+ m_setupChanged = false;
+ m_render->SetCodec(codec, channels, samplingRate,
+ m_parser->GetFrameSize());
+ }
+ m_reset = m_setupChanged;
+ continue;
}
- // decoding loop
- while ((!m_parser->Empty() || frame->nb_samples) && buf && !m_reset)
+ // if there's audio data available...
+ if (!m_parser->Empty())
{
- if (m_setupChanged |= (codec != m_parser->GetCodec() ||
- channels != m_parser->GetChannels() ||
- samplingRate != m_parser->GetSamplingRate()))
- break;
-
- if (m_passthrough)
+ // ... either pass through if render is ready
+ if (m_render->IsPassthrough())
{
- int len = m_parser->Packet()->size;
-
- // enough space in current buffer?
- if (len > (signed)(buf->nAllocLen - buf->nFilledLen))
+ if (m_render->Ready())
{
- // rise reset flag if packet is even bigger than
- // allocated buffer
- m_reset = len > (signed)(buf->nAllocLen) || len < 0;
- if (m_reset)
- ELOG("encoded audio frame too big!");
- break;
+ int len = m_render->WriteSamples(&m_parser->Packet()->data,
+ m_parser->Packet()->size, m_parser->GetPts());
+ if (len)
+ {
+ m_parser->Shrink(len);
+ continue;
+ }
}
- // for pass-through directly copy AV packet to buffer
- memcpy(buf->pBuffer + buf->nFilledLen,
- m_parser->Packet()->data, len);
-
- buf->nFilledLen += len;
- m_parser->Shrink(len);
-
- // if there's a valid PTS after shrinking, a complete PES packet
- // has been handled and is ready to play
- if (m_parser->GetPts())
- break;
-
- continue;
}
-
- // if all samples have been copied, decode new frame
- if (!frame->nb_samples)
+ // ... or decode if there's no leftover
+ else if (!frame->nb_samples)
{
- // if frame has been emptied, decode new data, rise reset
- // flag if something goes wrong
int gotFrame = 0;
int len = avcodec_decode_audio4(m_codecs[codec].context,
frame, &gotFrame, m_parser->Packet());
- if (len > 0)
- m_parser->Shrink(len);
- else
- {
- ELOG("failed to decode audio frame!");
- m_reset = true;
- break;
- }
- }
- if (frame->nb_samples)
- {
-#ifdef DO_RESAMPLE
- // setup resampler if needed
- if (sampleFormat != m_codecs[codec].context->sample_fmt)
+ if (len > 0 && gotFrame
+ && frame->channels == (int)channels
+ && frame->sample_rate == (int)samplingRate)
{
- sampleFormat = m_codecs[codec].context->sample_fmt;
- swr_free(&resample);
- resample = swr_alloc();
-
- if (!resample)
- {
- ELOG("failed to allocate resampling context!");
- m_reset = true;
- break;
- }
-
- DBG("decoding %s samples in %d channels",
- AV_SAMPLE_STR(sampleFormat),
- m_codecs[codec].context->channels);
-
- av_opt_set_int(resample, "in_channel_layout",
- AV_CH_LAYOUT(m_codecs[codec].context->channels), 0);
- av_opt_set_int(resample, "out_channel_layout",
- AV_CH_LAYOUT(outputChannels), 0);
-
- av_opt_set_int(resample, "in_sample_rate",
- m_codecs[codec].context->sample_rate, 0);
- av_opt_set_int(resample, "out_sample_rate",
- m_codecs[codec].context->sample_rate, 0);
-
- av_opt_set_int(resample, "in_sample_fmt",
- m_codecs[codec].context->sample_fmt, 0);
- av_opt_set_int(resample, "out_sample_fmt",
- AV_SAMPLE_FMT_S16, 0);
-
- swr_init(resample);
- }
-
- // now do the resampling
- uint8_t *dst[] = { buf->pBuffer + buf->nFilledLen };
- const uint8_t** src = (const uint8_t **)(frame->extended_data);
- int dstSize = (buf->nAllocLen - buf->nFilledLen) /
- (outputChannels *
- av_get_bytes_per_sample(AV_SAMPLE_FMT_S16));
-
- int copiedSamples = swr_convert(resample,
- dst, dstSize, src, frame->nb_samples);
-
- av_frame_unref(frame);
-
- if (copiedSamples > 0)
- {
- buf->nFilledLen += av_samples_get_buffer_size(NULL,
- outputChannels, copiedSamples, AV_SAMPLE_FMT_S16, 1);
-
- // get new buffer if not all samples have been resampled
- if (copiedSamples != frame->nb_samples)
- break;
+ frame->pts = m_parser->GetPts();
+ m_parser->Shrink(len);
}
else
{
+ ELOG("failed to decode audio frame!");
m_reset = true;
- ELOG("failed to resample audio frame!");
- break;
+ continue;
}
-#else
- // -- get length --
- int len = m_passthrough ? m_parser->Packet()->size :
- av_samples_get_buffer_size(NULL, outputChannels,
- frame->nb_samples, AV_SAMPLE_FMT_S16, 1);
-
- memcpy(buf->pBuffer + buf->nFilledLen, frame->data[0], len);
- buf->nFilledLen += len;
- av_frame_unref(frame);
-#endif
}
- // if there's a valid PTS after shrinking, a complete PES packet
- // has been handled and is ready to play
- if (m_parser->GetPts())
- break;
}
-
- // -- reset --
- if (m_reset)
+ // if there's leftover, pass decoded audio data to render when ready
+ if (frame->nb_samples && m_render->Ready())
{
- m_parser->Reset();
- av_frame_unref(frame);
- if (buf)
+ int len = m_render->WriteSamples(frame->extended_data,
+ frame->nb_samples, frame->pts,
+ (AVSampleFormat)frame->format);
+ if (len)
{
- cOmx::PtsToTicks(0, buf->nTimeStamp);
- buf->nFilledLen = 0;
- buf->nFlags = OMX_BUFFERFLAG_TIME_UNKNOWN;
+ av_frame_unref(frame);
+ continue;
}
}
-
- // -- empty buffer --
- if (buf && m_omx->EmptyAudioBuffer(buf))
- buf = 0;
-
- m_reset = false;
-
- // wait for new audio packets
- if (m_parser->Empty() && !frame->nb_samples)
- m_wait->Wait(50);
+ // nothing to be done...
+ m_wait->Wait(50);
}
-#ifdef DO_RESAMPLE
- swr_free(&resample);
-#endif
-
av_frame_free(&frame);
- SetCodec(cAudioCodec::eInvalid, outputChannels, samplingRate);
DLOG("cAudioDecoder() thread ended");
}
-void cRpiAudioDecoder::SetCodec(cAudioCodec::eCodec codec, unsigned int &channels, unsigned int samplingRate, unsigned int frameSize)
-{
- m_omx->StopAudio();
-
- if (codec != cAudioCodec::eInvalid && channels > 0)
- {
- DLOG("set audio codec to %dch %s", channels, cAudioCodec::Str(codec));
-
- avcodec_flush_buffers(m_codecs[codec].context);
- m_passthrough = false;
- cAudioCodec::eCodec outputFormat = cAudioCodec::ePCM;
- cRpiAudioPort::ePort outputPort = cRpiAudioPort::eLocal;
-
- if (cRpiSetup::GetAudioPort() == cRpiAudioPort::eHDMI &&
- cRpiSetup::IsAudioFormatSupported(cAudioCodec::ePCM, channels, samplingRate))
- {
- outputPort = cRpiAudioPort::eHDMI;
-
- if (cRpiSetup::IsAudioPassthrough() &&
- cRpiSetup::IsAudioFormatSupported(codec, channels, samplingRate))
- {
- m_passthrough = true;
- outputFormat = codec;
- }
- // if we decode locally, upmix mono channels to 2.0
- else if (channels == 1)
- channels = 2;
- }
- else
- {
- channels = 2;
- // if 2ch PCM audio on HDMI is supported
- if (cRpiSetup::GetAudioPort() == cRpiAudioPort::eHDMI &&
- cRpiSetup::IsAudioFormatSupported(cAudioCodec::ePCM, 2, samplingRate))
- outputPort = cRpiAudioPort::eHDMI;
- }
-
- m_codecs[codec].context->request_channel_layout = AV_CH_LAYOUT(channels);
-#if FF_API_REQUEST_CHANNELS
- m_codecs[codec].context->request_channels = channels;
-#endif
- m_omx->SetupAudioRender(outputFormat, channels, outputPort, samplingRate, frameSize);
- ILOG("set %s audio output format to %dch %s, %d.%dkHz%s",
- cRpiAudioPort::Str(outputPort), channels, cAudioCodec::Str(outputFormat),
- samplingRate / 1000, (samplingRate % 1000) / 100,
- m_passthrough ? " (pass-through)" : "");
-
- if (outputPort == cRpiAudioPort::eHDMI)
- cRpiSetup::SetHDMIChannelMapping(m_passthrough, channels);
- }
-}
-
void cRpiAudioDecoder::Log(void* ptr, int level, const char* fmt, va_list vl)
{
if (level == AV_LOG_QUIET)
diff --git a/audio.h b/audio.h
index ac7b838..9560513 100644
--- a/audio.h
+++ b/audio.h
@@ -12,6 +12,8 @@
#include "tools.h"
#include "omx.h"
+class cRpiAudioRender;
+
class cRpiAudioDecoder : public cThread
{
@@ -32,8 +34,6 @@ public:
protected:
virtual void Action(void);
- void SetCodec(cAudioCodec::eCodec codec, unsigned int &channels,
- unsigned int samplingRate, unsigned int frameSize = 0);
static void OnAudioSetupChanged(void *data)
{ (static_cast <cRpiAudioDecoder*> (data))->HandleAudioSetupChanged(); }
@@ -52,14 +52,14 @@ private:
class cParser;
- Codec m_codecs[cAudioCodec::eNumCodecs];
- bool m_passthrough;
- bool m_reset;
- bool m_setupChanged;
+ Codec m_codecs[cAudioCodec::eNumCodecs];
+ bool m_passthrough;
+ bool m_reset;
+ bool m_setupChanged;
- cCondWait *m_wait;
- cParser *m_parser;
- cOmx *m_omx;
+ cCondWait *m_wait;
+ cParser *m_parser;
+ cRpiAudioRender *m_render;
};
#endif