summaryrefslogtreecommitdiff
path: root/audio.c
diff options
context:
space:
mode:
authorThomas Reufer <thomas@reufer.ch>2014-01-07 16:40:32 +0100
committerThomas Reufer <thomas@reufer.ch>2014-01-07 16:40:32 +0100
commit88f137d194b1768344e954a1b1d35fb1fce03df9 (patch)
treeb2b3a5293fe02ba30fe57f39ef3edc42d7ec7a04 /audio.c
parent4e710fc5c2bf2e2e33518eb3c537b7022085bda9 (diff)
downloadvdr-plugin-rpihddevice-0.0.7.tar.gz
vdr-plugin-rpihddevice-0.0.7.tar.bz2
2013-12-30: Version 0.0.70.0.7
------------------------- - new: - support audio sampling rates other than 48kHz - changed setting of trick speed with APIVERSNUM >= 20103 - added deinterlacer - fixed: - improved audio parser - fixed still image for H264 video - mute audio render if volume is set to zero - missing: - image grabbing - video format/output options
Diffstat (limited to 'audio.c')
-rw-r--r--audio.c278
1 files changed, 163 insertions, 115 deletions
diff --git a/audio.c b/audio.c
index cacc47a..33ba917 100644
--- a/audio.c
+++ b/audio.c
@@ -42,6 +42,13 @@ public:
return m_channels;
}
+ unsigned int GetSamplingRate(void)
+ {
+ if (!m_parsed)
+ Parse();
+ return m_samplingRate;
+ }
+
bool Empty(void)
{
if (!m_parsed)
@@ -69,6 +76,7 @@ public:
{
m_codec = cAudioCodec::eInvalid;
m_channels = 0;
+ m_samplingRate = 0;
m_packet.size = 0;
m_size = 0;
m_parsed = false;
@@ -122,12 +130,10 @@ private:
int channels = 0;
int offset = 0;
int frameSize = 0;
+ int samplingRate = 0;
while (m_size - offset >= 3)
{
- const uint8_t *p = m_packet.data + offset;
- int n = m_size - offset;
-
// 4 bytes 0xFFExxxxx MPEG audio
// 3 bytes 0x56Exxx AAC LATM audio
// 5 bytes 0x0B77xxxxxx AC-3 audio
@@ -135,58 +141,72 @@ private:
// 7/9 bytes 0xFFFxxxxxxxxxxx ADTS audio
// PCM audio can't be found
- if (FastMpegCheck(p))
+ const uint8_t *p = m_packet.data + offset;
+ int n = m_size - offset;
+
+ switch (FastCheck(p))
{
- if (MpegCheck(p, n, frameSize))
- {
+ case cAudioCodec::eMPG:
+ if (MpegCheck(p, n, frameSize, channels, samplingRate))
codec = cAudioCodec::eMPG;
- channels = 2;
- }
break;
- }
- else if (FastAc3Check(p))
- {
- if (Ac3Check(p, n, frameSize, channels))
+
+ case cAudioCodec::eAC3:
+ if (Ac3Check(p, n, frameSize, channels, samplingRate))
{
codec = cAudioCodec::eAC3;
if (n > 5 && p[5] > (10 << 3))
codec = cAudioCodec::eEAC3;
}
break;
- }
- else if (FastLatmCheck(p))
- {
- if (LatmCheck(p, n, frameSize))
- {
+
+ case cAudioCodec::eAAC:
+ if (LatmCheck(p, n, frameSize, channels, samplingRate))
codec = cAudioCodec::eAAC;
- channels = 2;
- }
break;
- }
- else if (FastAdtsCheck(p))
- {
- if (AdtsCheck(p, n, frameSize, channels))
+
+ case cAudioCodec::eADTS:
+ if (AdtsCheck(p, n, frameSize, channels, samplingRate))
codec = cAudioCodec::eADTS;
break;
+
+ default:
+ break;
+ }
+
+ if (codec != cAudioCodec::eInvalid)
+ {
+ // if there is enough data in buffer, check if predicted next
+ // frame start is valid
+ if (n < frameSize + 3 ||
+ FastCheck(p + frameSize) != cAudioCodec::eInvalid)
+ {
+ // if codec has been detected but buffer does not yet
+ // contains a complete frame, set size to zero to prevent
+ // frame from being decoded
+ if (frameSize > n)
+ frameSize = 0;
+
+ break;
+ }
}
++offset;
}
- if (codec != cAudioCodec::eInvalid)
+ if (offset)
{
- if (offset)
- {
- dsyslog("rpihddevice: audio packet shrinked by %d bytes", offset);
- Shrink(offset);
- }
+ dsyslog("rpihddevice: audio parser skipped %d of %d bytes", offset, m_size);
+ Shrink(offset);
+ }
+ if (codec != cAudioCodec::eInvalid)
+ {
m_codec = codec;
m_channels = channels;
+ m_samplingRate = samplingRate;
m_packet.size = frameSize;
}
- else
- Reset();
m_parsed = true;
}
@@ -194,18 +214,29 @@ private:
AVPacket m_packet;
cAudioCodec::eCodec m_codec;
unsigned int m_channels;
+ unsigned int m_samplingRate;
unsigned int m_size;
bool m_parsed;
/* ------------------------------------------------------------------------- */
- /* audio codec parser helper functions, taken from 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];
+ static const uint32_t Mpeg4SampleRateTable[16];
static const uint16_t Ac3SampleRateTable[4];
static const uint16_t Ac3FrameSizeTable[38][3];
+ static cAudioCodec::eCodec FastCheck(const uint8_t *p)
+ {
+ return FastMpegCheck(p) ? cAudioCodec::eMPG :
+ FastAc3Check (p) ? cAudioCodec::eAC3 :
+ FastLatmCheck(p) ? cAudioCodec::eAAC :
+ FastAdtsCheck(p) ? cAudioCodec::eADTS :
+ cAudioCodec::eInvalid;
+ }
+
///
/// Fast check for MPEG audio.
///
@@ -242,6 +273,8 @@ private:
/// o e 2x BitRate index
/// o f 2x SampleRate index (41000, 48000, 32000, 0)
/// o g 1x Padding bit
+ /// o h 1x Private bit
+ /// o i 2x Channel mode
/// o .. Doesn't care
///
/// frame length:
@@ -250,48 +283,45 @@ private:
/// Layer II & III:
/// FrameLengthInBytes = 144 * BitRate / SampleRate + Padding
///
- static bool MpegCheck(const uint8_t *data, int size, int &frame_size)
+ static bool MpegCheck(const uint8_t *p, int size, int &frameSize, int &channels, int &samplingRate)
{
- frame_size = 0;
+ frameSize = size;
if (size < 3)
return true;
- int mpeg2 = !(data[1] & 0x08) && (data[1] & 0x10);
- int mpeg25 = !(data[1] & 0x08) && !(data[1] & 0x10);
- int layer = 4 - ((data[1] >> 1) & 0x03);
- int padding = (data[2] >> 1) & 0x01;
+ int cmode = (p[3] >> 6) & 0x03;
+ int mpeg2 = !(p[1] & 0x08) && (p[1] & 0x10);
+ int mpeg25 = !(p[1] & 0x08) && !(p[1] & 0x10);
+ int layer = 4 - ((p[1] >> 1) & 0x03);
+ int padding = (p[2] >> 1) & 0x01;
+
+ // channel mode = [ stereo, joint stereo, dual channel, mono]
+ channels = cmode == 0x03 ? 1 : 2;
- int sample_rate = MpegSampleRateTable[(data[2] >> 2) & 0x03];
- if (!sample_rate)
+ samplingRate = MpegSampleRateTable[(p[2] >> 2) & 0x03];
+ if (!samplingRate)
return false;
- sample_rate >>= mpeg2; // MPEG 2 half rate
- sample_rate >>= mpeg25; // MPEG 2.5 quarter rate
+ samplingRate >>= mpeg2; // MPEG 2 half rate
+ samplingRate >>= mpeg25; // MPEG 2.5 quarter rate
- int bit_rate = BitRateTable[mpeg2 | mpeg25][layer - 1][(data[2] >> 4) & 0x0F];
+ int bit_rate = BitRateTable[mpeg2 | mpeg25][layer - 1][(p[2] >> 4) & 0x0F];
if (!bit_rate)
return false;
switch (layer)
{
case 1:
- frame_size = (12000 * bit_rate) / sample_rate;
- frame_size = (frame_size + padding) * 4;
+ frameSize = (12000 * bit_rate) / samplingRate;
+ frameSize = (frameSize + padding) * 4;
break;
case 2:
case 3:
default:
- frame_size = (144000 * bit_rate) / sample_rate;
- frame_size = frame_size + padding;
+ frameSize = (144000 * bit_rate) / samplingRate;
+ frameSize = frameSize + padding;
break;
}
-
- if (size >= frame_size + 3 && !FastMpegCheck(data + frame_size))
- return false;
-
- if (frame_size > size)
- frame_size = 0;
-
return true;
}
@@ -331,38 +361,43 @@ private:
/// o a 16x Frame sync, always 0x0B77
/// o b 2x Frame type
/// o c 3x Sub stream ID
- /// o d 10x Frame size - 1 in words
+ /// o d 11x Frame size - 1 in words
/// o e 2x Frame size code
/// o f 2x Frame size code 2
/// o g 3x Channel mode
/// 0 h 1x LFE on
///
- static bool Ac3Check(const uint8_t *p, int size, int &frame_size, int &channels)
+ static bool Ac3Check(const uint8_t *p, int size, int &frameSize, int &channels, int &samplingRate)
{
- frame_size = 0;
+ frameSize = size;
if (size < 7)
return true;
int acmod;
bool lfe;
- int sample_rate; // for future use, E-AC3 t.b.d.
+ int fscod = (p[4] & 0xC0) >> 6;
+
+ samplingRate = Ac3SampleRateTable[fscod];
if (p[5] > (10 << 3)) // E-AC-3
{
- if ((p[4] & 0xF0) == 0xF0) // invalid fscod fscod2
- return false;
+ if (fscod == 0x03)
+ {
+ int fscod2 = (p[4] & 0x30) >> 4;
+ if (fscod2 == 0x03)
+ return false; // invalid fscod & fscod2
+
+ samplingRate = Ac3SampleRateTable[fscod2] / 2;
+ }
acmod = (p[4] & 0x0E) >> 1; // number of channels, LFE excluded
lfe = p[4] & 0x01;
- frame_size = ((p[2] & 0x03) << 8) + p[3] + 1;
- frame_size *= 2;
+ frameSize = ((p[2] & 0x07) << 8) + p[3] + 1;
+ frameSize *= 2;
}
else // AC-3
{
- sample_rate = Ac3SampleRateTable[(p[4] >> 6) & 0x03];
-
- int fscod = p[4] >> 6;
if (fscod == 0x03) // invalid sample rate
return false;
@@ -382,7 +417,7 @@ private:
lfe = (p[lfe_bptr / 8] & (1 << (7 - (lfe_bptr % 8))));
// invalid is checked above
- frame_size = Ac3FrameSizeTable[frmsizcod][fscod] * 2;
+ frameSize = Ac3FrameSizeTable[frmsizcod][fscod] * 2;
}
channels =
@@ -396,13 +431,6 @@ private:
acmod == 0x07 ? 5 : 0; // L, C, R, RL, RR
if (lfe) channels++;
-
- if (size >= frame_size + 2 && !FastAc3Check(p + frame_size))
- return false;
-
- if (frame_size > size)
- frame_size = 0;
-
return true;
}
@@ -425,22 +453,21 @@ private:
///
/// 0x56Exxx already checked.
///
- static bool LatmCheck(const uint8_t *p, int size, int &frame_size)
+ static bool LatmCheck(const uint8_t *p, int size, int &frameSize, int &channels, int &samplingRate)
{
- frame_size = 0;
+ frameSize = size;
if (size < 3)
return true;
- // 13 bit frame size without header
- frame_size = ((p[1] & 0x1F) << 8) + p[2];
- frame_size += 3;
-
- if (size >= frame_size + 3 && !FastLatmCheck(p + frame_size))
- return false;
+ // to do: determine channels
+ channels = 2;
- if (frame_size > size)
- frame_size = 0;
+ // to do: determine sampling rate
+ samplingRate = 48000;
+ // 13 bit frame size without header
+ frameSize = ((p[1] & 0x1F) << 8) + p[2];
+ frameSize += 3;
return true;
}
@@ -478,36 +505,34 @@ private:
/// o ...
/// o M*13 frame length
///
- static bool AdtsCheck(const uint8_t *p, int size, int &frame_size, int &channels)
+ static bool AdtsCheck(const uint8_t *p, int size, int &frameSize, int &channels, int &samplingRate)
{
- frame_size = 0;
+ frameSize = size;
if (size < 6)
return true;
- frame_size = (p[3] & 0x03) << 11;
- frame_size |= (p[4] & 0xFF) << 3;
- frame_size |= (p[5] & 0xE0) >> 5;
+ samplingRate = Mpeg4SampleRateTable[(p[2] >> 2) & 0x0F];
+ if (!samplingRate)
+ return false;
+
+ frameSize = (p[3] & 0x03) << 11;
+ frameSize |= (p[4] & 0xFF) << 3;
+ frameSize |= (p[5] & 0xE0) >> 5;
- int ch_config = (p[2] & 0x01) << 7;
- ch_config |= (p[3] & 0xC0) >> 6;
+ int cConf = (p[2] & 0x01) << 7;
+ cConf |= (p[3] & 0xC0) >> 6;
channels =
- ch_config == 0x00 ? 0 : // defined in AOT specific config
- ch_config == 0x01 ? 1 : // C
- ch_config == 0x02 ? 2 : // L, R
- ch_config == 0x03 ? 3 : // C, L, R
- ch_config == 0x04 ? 4 : // C, L, R, RC
- ch_config == 0x05 ? 5 : // C, L, R, RL, RR
- ch_config == 0x06 ? 6 : // C, L, R, RL, RR, LFE
- ch_config == 0x07 ? 8 : // C, L, R, SL, SR, RL, RR, LFE
+ cConf == 0x00 ? 0 : // defined in AOT specific config
+ cConf == 0x01 ? 1 : // C
+ cConf == 0x02 ? 2 : // L, R
+ cConf == 0x03 ? 3 : // C, L, R
+ cConf == 0x04 ? 4 : // C, L, R, RC
+ cConf == 0x05 ? 5 : // C, L, R, RL, RR
+ cConf == 0x06 ? 6 : // C, L, R, RL, RR, LFE
+ cConf == 0x07 ? 8 : // C, L, R, SL, SR, RL, RR, LFE
0;
- if (size >= frame_size + 3 && !FastAdtsCheck(p + frame_size))
- return false;
-
- if (frame_size > size)
- frame_size = 0;
-
- return true;
+ return true;
}
};
@@ -536,6 +561,14 @@ const uint16_t cAudioParser::BitRateTable[2][3][16] =
const uint16_t cAudioParser::MpegSampleRateTable[4] = { 44100, 48000, 32000, 0 };
///
+/// MPEG-4 sample rate table.
+///
+const uint32_t cAudioParser::Mpeg4SampleRateTable[16] = {
+ 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
+ 16000, 12000, 11025, 8000, 7350, 0, 0, 0
+};
+
+///
/// AC-3 sample rate table.
///
const uint16_t cAudioParser::Ac3SampleRateTable[4] = { 48000, 44100, 32000, 0 };
@@ -679,8 +712,10 @@ void cAudioDecoder::Action(void)
{
unsigned int channels = 0;
unsigned int outputChannels = 0;
+ unsigned int samplingRate = 0;
bool bufferFull = false;
+ bool setupChanged = false;
cAudioCodec::eCodec codec = cAudioCodec::eInvalid;
OMX_BUFFERHEADERTYPE *buf = 0;
@@ -697,11 +732,15 @@ void cAudioDecoder::Action(void)
while (!m_reset)
{
+ setupChanged |= cRpiSetup::HasAudioSetupChanged();
+
// check for data if no decoded samples are pending
if (!m_parser->Empty() && !frame->nb_samples)
{
- if (codec != m_parser->GetCodec() ||
- channels != m_parser->GetChannels())
+ if (setupChanged ||
+ codec != m_parser->GetCodec() ||
+ channels != m_parser->GetChannels() ||
+ samplingRate != m_parser->GetSamplingRate())
{
// to change codec config, we need to empty buffer first
if (buf)
@@ -710,9 +749,12 @@ void cAudioDecoder::Action(void)
{
codec = m_parser->GetCodec();
channels = m_parser->GetChannels();
+ samplingRate = m_parser->GetSamplingRate();
outputChannels = channels;
- SetCodec(codec, outputChannels);
+ SetCodec(codec, outputChannels, samplingRate);
+
+ setupChanged = false;
}
}
}
@@ -836,6 +878,10 @@ void cAudioDecoder::Action(void)
// we have a buffer to empty
if (buf && bufferFull)
{
+ // send empty buffer if we're about to reset
+ if (m_reset)
+ buf->nFilledLen = 0;
+
if (m_omx->EmptyAudioBuffer(buf))
{
bufferFull = false;
@@ -854,7 +900,6 @@ void cAudioDecoder::Action(void)
}
}
- dsyslog("reset");
if (buf && m_omx->EmptyAudioBuffer(buf))
buf = 0;
@@ -864,27 +909,29 @@ void cAudioDecoder::Action(void)
dsyslog("rpihddevice: cAudioDecoder() thread ended");
}
-void cAudioDecoder::SetCodec(cAudioCodec::eCodec codec, unsigned int &channels)
+void cAudioDecoder::SetCodec(cAudioCodec::eCodec codec, unsigned int &channels, unsigned int samplingRate)
{
if (codec != cAudioCodec::eInvalid && channels > 0)
{
dsyslog("rpihddevice: set audio codec to %dch %s",
channels, cAudioCodec::Str(codec));
+ avcodec_flush_buffers(m_codecs[codec].context);
m_codecs[codec].context->request_channel_layout = AV_CH_LAYOUT_NATIVE;
m_codecs[codec].context->request_channels = 0;
+ //m_codecs[codec].context->bit_rate = 0;
m_passthrough = false;
cAudioCodec::eCodec outputFormat = cAudioCodec::ePCM;
cAudioPort::ePort outputPort = cAudioPort::eLocal;
if (cRpiSetup::GetAudioPort() == cAudioPort::eHDMI &&
- cRpiSetup::IsAudioFormatSupported(cAudioCodec::ePCM, channels, 48000))
+ cRpiSetup::IsAudioFormatSupported(cAudioCodec::ePCM, channels, samplingRate))
{
outputPort = cAudioPort::eHDMI;
if (cRpiSetup::IsAudioPassthrough() &&
- cRpiSetup::IsAudioFormatSupported(codec, channels, 48000))
+ cRpiSetup::IsAudioFormatSupported(codec, channels, samplingRate))
{
m_passthrough = true;
outputFormat = codec;
@@ -898,13 +945,14 @@ void cAudioDecoder::SetCodec(cAudioCodec::eCodec codec, unsigned int &channels)
// if 2ch PCM audio on HDMI is supported
if (cRpiSetup::GetAudioPort() == cAudioPort::eHDMI &&
- cRpiSetup::IsAudioFormatSupported(cAudioCodec::ePCM, 2, 48000))
+ cRpiSetup::IsAudioFormatSupported(cAudioCodec::ePCM, 2, samplingRate))
outputPort = cAudioPort::eHDMI;
}
- m_omx->SetupAudioRender(outputFormat, channels, outputPort, 48000);
- dsyslog("rpihddevice: set %s audio output format to %dch %s%s",
+ m_omx->SetupAudioRender(outputFormat, channels, outputPort, samplingRate);
+ dsyslog("rpihddevice: set %s audio output format to %dch %s, %d.%dkHz%s",
cAudioPort::Str(outputPort), channels, cAudioCodec::Str(outputFormat),
+ samplingRate / 1000, (samplingRate % 1000) / 100,
m_passthrough ? " (pass-through)" : "");
}
}