summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--HISTORY19
-rw-r--r--audio.c278
-rw-r--r--audio.h2
-rw-r--r--ilclient/ilclient.c2
-rw-r--r--omx.c167
-rw-r--r--omx.h17
-rw-r--r--omxdevice.c51
-rw-r--r--omxdevice.h20
-rw-r--r--rpihddevice.c3
-rw-r--r--setup.c37
-rw-r--r--setup.h1
11 files changed, 370 insertions, 227 deletions
diff --git a/HISTORY b/HISTORY
index 240d47b..3daa975 100644
--- a/HISTORY
+++ b/HISTORY
@@ -1,6 +1,25 @@
VDR Plugin 'rpihddevice' Revision History
-----------------------------------------
+2013-12-30: Version 0.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
+
+2013-12-16: Version 0.0.6a
+--------------------------
+- fixed:
+ - removed OMX mutex
+
2013-12-15: Version 0.0.6
-------------------------
- new:
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)" : "");
}
}
diff --git a/audio.h b/audio.h
index dd1f9f5..8a7c318 100644
--- a/audio.h
+++ b/audio.h
@@ -37,7 +37,7 @@ public:
protected:
virtual void Action(void);
- void SetCodec(cAudioCodec::eCodec codec, unsigned int &channels);
+ void SetCodec(cAudioCodec::eCodec codec, unsigned int &channels, unsigned int samplingRate);
struct Codec
{
diff --git a/ilclient/ilclient.c b/ilclient/ilclient.c
index da08ad0..66d70a8 100644
--- a/ilclient/ilclient.c
+++ b/ilclient/ilclient.c
@@ -1080,7 +1080,7 @@ int ilclient_setup_tunnel(TUNNEL_T *tunnel, unsigned int portStream, int timeout
vc_assert(error == OMX_ErrorNone);
error = OMX_SetupTunnel(tunnel->sink->comp, tunnel->sink_port, NULL, 0);
vc_assert(error == OMX_ErrorNone);
-
+
if(enable_error)
{
//Clean up the errors. This does risk removing an error that was nothing to do with this tunnel :-/
diff --git a/omx.c b/omx.c
index 035450b..e049281 100644
--- a/omx.c
+++ b/omx.c
@@ -5,6 +5,7 @@
*/
#include "omx.h"
+#include "setup.h"
#include <vdr/tools.h>
#include <vdr/thread.h>
@@ -99,31 +100,33 @@ const char* cOmx::errStr(int err)
"unknown";
}
-void cOmx::HandleEndOfStream(unsigned int portId)
- {
- dsyslog("rpihddevice: HandleEndOfStream(%d)", portId);
-
- switch (portId)
+void cOmx::Action(void)
+{
+ while (Running())
{
- case 131:
- break;
-
- case 11:
- break;
-
- case 90:
- break;
+ m_portEventReady->Wait();
+ while (!m_portEvents->empty())
+ {
+ HandlePortSettingsChanged(m_portEvents->front());
+ m_portEvents->pop();
+ }
}
}
void cOmx::HandlePortSettingsChanged(unsigned int portId)
{
- //dsyslog("rpihddevice: HandlePortSettingsChanged(%d)", portId);
+// dsyslog("rpihddevice: HandlePortSettingsChanged(%d)", portId);
switch (portId)
{
- case 131:
+ case 191:
+ if (ilclient_setup_tunnel(&m_tun[eVideoFxToVideoScheduler], 0, 0) != 0)
+ esyslog("rpihddevice: failed to setup up tunnel from video fx to scheduler!");
+ if (ilclient_change_component_state(m_comp[eVideoScheduler], OMX_StateExecuting) != 0)
+ esyslog("rpihddevice: failed to enable video scheduler!");
+ break;
+ case 131:
OMX_PARAM_PORTDEFINITIONTYPE portdef;
OMX_INIT_STRUCT(portdef);
portdef.nPortIndex = 131;
@@ -138,15 +141,30 @@ void cOmx::HandlePortSettingsChanged(unsigned int portId)
&interlace) != OMX_ErrorNone)
esyslog("rpihddevice: failed to get video decoder interlace config!");
- dsyslog("rpihddevice: decoding video %dx%d%s",
+ bool deinterlace;
+ deinterlace = (cRpiSetup::IsDisplayProgressive() &&
+ (interlace.eMode != OMX_InterlaceProgressive));
+
+ dsyslog("rpihddevice: decoding video %dx%d%s, %sabling deinterlacer",
portdef.format.video.nFrameWidth,
portdef.format.video.nFrameHeight,
- interlace.eMode == OMX_InterlaceProgressive ? "p" : "i");
-
- if (ilclient_setup_tunnel(&m_tun[eVideoDecoderToVideoScheduler], 0, 0) != 0)
- esyslog("rpihddevice: failed to setup up tunnel from video decoder to scheduler!");
- if (ilclient_change_component_state(m_comp[eVideoScheduler], OMX_StateExecuting) != 0)
- esyslog("rpihddevice: failed to enable video scheduler!");
+ interlace.eMode == OMX_InterlaceProgressive ? "p" : "i",
+ deinterlace ? "en" : "dis");
+
+ OMX_CONFIG_IMAGEFILTERPARAMSTYPE filterparam;
+ OMX_INIT_STRUCT(filterparam);
+ filterparam.nPortIndex = 191;
+ filterparam.nNumParams = 1;
+ filterparam.nParams[0] = 3;
+ filterparam.eImageFilter = deinterlace ? OMX_ImageFilterDeInterlaceAdvanced : OMX_ImageFilterNone;
+ if (OMX_SetConfig(ILC_GET_HANDLE(m_comp[eVideoFx]),
+ OMX_IndexConfigCommonImageFilterParameters, &filterparam) != OMX_ErrorNone)
+ esyslog("rpihddevice: failed to set deinterlacing paramaters!");
+
+ if (ilclient_setup_tunnel(&m_tun[eVideoDecoderToVideoFx], 0, 0) != 0)
+ esyslog("rpihddevice: failed to setup up tunnel from video decoder to fx!");
+ if (ilclient_change_component_state(m_comp[eVideoFx], OMX_StateExecuting) != 0)
+ esyslog("rpihddevice: failed to enable video fx!");
break;
case 11:
@@ -158,30 +176,25 @@ void cOmx::HandlePortSettingsChanged(unsigned int portId)
}
}
-void cOmx::HandleBufferEmpty(COMPONENT_T *comp)
-{
- if (comp == m_comp[eVideoDecoder])
- m_freeVideoBuffers++;
- else if (comp == m_comp[eAudioRender])
- m_freeAudioBuffers++;
-}
-
void cOmx::OnBufferEmpty(void *instance, COMPONENT_T *comp)
{
cOmx* omx = static_cast <cOmx*> (instance);
- omx->HandleBufferEmpty(comp);
+ if (comp == omx->m_comp[eVideoDecoder])
+ omx->m_freeVideoBuffers++;
+ else if (comp == omx->m_comp[eAudioRender])
+ omx->m_freeAudioBuffers++;
}
void cOmx::OnPortSettingsChanged(void *instance, COMPONENT_T *comp, OMX_U32 data)
{
cOmx* omx = static_cast <cOmx*> (instance);
- omx->HandlePortSettingsChanged(data);
+ omx->m_portEvents->push(data);
+ omx->m_portEventReady->Signal();
}
void cOmx::OnEndOfStream(void *instance, COMPONENT_T *comp, OMX_U32 data)
{
cOmx* omx = static_cast <cOmx*> (instance);
- omx->HandleEndOfStream(data);
}
void cOmx::OnError(void *instance, COMPONENT_T *comp, OMX_U32 data)
@@ -191,19 +204,24 @@ void cOmx::OnError(void *instance, COMPONENT_T *comp, OMX_U32 data)
}
cOmx::cOmx() :
+ cThread(),
m_mutex(new cMutex()),
m_setAudioStartTime(false),
m_setVideoStartTime(false),
m_setVideoDiscontinuity(false),
m_freeAudioBuffers(0),
m_freeVideoBuffers(0),
- m_clockReference(eClockRefAudio)
+ m_clockReference(eClockRefAudio),
+ m_portEventReady(new cCondWait()),
+ m_portEvents(new std::queue<unsigned int>)
{
}
cOmx::~cOmx()
{
delete m_mutex;
+ delete m_portEventReady;
+ delete m_portEvents;
}
int cOmx::Init(void)
@@ -226,6 +244,11 @@ int cOmx::Init(void)
(ILCLIENT_DISABLE_ALL_PORTS | ILCLIENT_ENABLE_INPUT_BUFFERS)) != 0)
esyslog("rpihddevice: failed creating video decoder!");
+ // create image_fx
+ if (ilclient_create_component(m_client, &m_comp[eVideoFx],
+ "image_fx", ILCLIENT_DISABLE_ALL_PORTS) != 0)
+ esyslog("rpihddevice: failed creating video fx!");
+
// create video_render
if (ilclient_create_component(m_client, &m_comp[eVideoRender],
"video_render", ILCLIENT_DISABLE_ALL_PORTS) != 0)
@@ -248,8 +271,11 @@ int cOmx::Init(void)
esyslog("rpihddevice: failed creating video scheduler!");
// setup tunnels
- set_tunnel(&m_tun[eVideoDecoderToVideoScheduler],
- m_comp[eVideoDecoder], 131, m_comp[eVideoScheduler], 10);
+ set_tunnel(&m_tun[eVideoDecoderToVideoFx],
+ m_comp[eVideoDecoder], 131, m_comp[eVideoFx], 190);
+
+ set_tunnel(&m_tun[eVideoFxToVideoScheduler],
+ m_comp[eVideoFx], 191, m_comp[eVideoScheduler], 10);
set_tunnel(&m_tun[eVideoSchedulerToVideoRender],
m_comp[eVideoScheduler], 11, m_comp[eVideoRender], 90);
@@ -269,6 +295,7 @@ int cOmx::Init(void)
ilclient_change_component_state(m_comp[eClock], OMX_StateExecuting);
ilclient_change_component_state(m_comp[eVideoDecoder], OMX_StateIdle);
+ ilclient_change_component_state(m_comp[eVideoFx], OMX_StateIdle);
// set up the number and size of buffers for audio render
m_freeAudioBuffers = 2; //64;
@@ -318,11 +345,15 @@ int cOmx::Init(void)
SetClockState(cOmx::eClockStateRun);
+ Start();
+
return 0;
}
int cOmx::DeInit(void)
{
+ Cancel();
+
ilclient_teardown_tunnels(m_tun);
ilclient_state_transition(m_comp, OMX_StateIdle);
ilclient_state_transition(m_comp, OMX_StateLoaded);
@@ -402,14 +433,14 @@ bool cOmx::IsClockRunning(void)
void cOmx::SetClockState(eClockState clockState)
{
- dsyslog("rpihddevice: SetClockState(%s)",
+/* dsyslog("rpihddevice: SetClockState(%s)",
clockState == eClockStateRun ? "eClockStateRun" :
clockState == eClockStateStop ? "eClockStateStop" :
clockState == eClockStateWaitForVideo ? "eClockStateWaitForVideo" :
clockState == eClockStateWaitForAudio ? "eClockStateWaitForAudio" :
clockState == eClockStateWaitForAudioVideo ? "eClockStateWaitForAudioVideo" :
"unknown");
-
+*/
OMX_TIME_CONFIG_CLOCKSTATETYPE cstate;
OMX_INIT_STRUCT(cstate);
@@ -463,7 +494,7 @@ void cOmx::SetClockState(eClockState clockState)
if (cstate.eState == OMX_TIME_ClockStateWaitingForStartTime)
// 200ms pre roll, value taken from omxplayer
- cstate.nOffset = ToOmxTicks(-1000LL * 400);
+ cstate.nOffset = ToOmxTicks(-1000LL * 200);
if (OMX_SetConfig(ILC_GET_HANDLE(m_comp[eClock]),
OMX_IndexConfigTimeClockState, &cstate) != OMX_ErrorNone)
@@ -537,15 +568,13 @@ void cOmx::SetClockReference(eClockReference clockReference)
if (OMX_SetConfig(ILC_GET_HANDLE(m_comp[eClock]),
OMX_IndexConfigTimeActiveRefClock, &refClock) != OMX_ErrorNone)
esyslog("rpihddevice: failed set active clock reference!");
- else
+/* else
dsyslog("rpihddevice: set active clock reference to %s",
- m_clockReference == eClockRefAudio ? "audio" : "video");
+ m_clockReference == eClockRefAudio ? "audio" : "video"); */
}
void cOmx::SetVolume(int vol)
{
- dsyslog("rpihddevice: SetVolumeDevice(%d)", vol);
-
OMX_AUDIO_CONFIG_VOLUMETYPE volume;
OMX_INIT_STRUCT(volume);
volume.nPortIndex = 100;
@@ -557,6 +586,18 @@ void cOmx::SetVolume(int vol)
esyslog("rpihddevice: failed to set volume!");
}
+void cOmx::SetMute(bool mute)
+{
+ OMX_AUDIO_CONFIG_MUTETYPE amute;
+ OMX_INIT_STRUCT(amute);
+ amute.nPortIndex = 100;
+ amute.bMute = mute ? OMX_TRUE : OMX_FALSE;
+
+ if (OMX_SetConfig(ILC_GET_HANDLE(m_comp[eAudioRender]),
+ OMX_IndexConfigAudioMute, &amute) != OMX_ErrorNone)
+ esyslog("rpihddevice: failed to set mute state!");
+}
+
void cOmx::SendEos(void)
{
#if 0
@@ -582,9 +623,14 @@ void cOmx::StopVideo(void)
// put video decoder into idle
ilclient_change_component_state(m_comp[eVideoDecoder], OMX_StateIdle);
+ // put video fx into idle
+ ilclient_flush_tunnels(&m_tun[eVideoDecoderToVideoFx], 1);
+ ilclient_disable_tunnel(&m_tun[eVideoDecoderToVideoFx]);
+ ilclient_change_component_state(m_comp[eVideoFx], OMX_StateIdle);
+
// put video scheduler into idle
- ilclient_flush_tunnels(&m_tun[eVideoDecoderToVideoScheduler], 1);
- ilclient_disable_tunnel(&m_tun[eVideoDecoderToVideoScheduler]);
+ ilclient_flush_tunnels(&m_tun[eVideoFxToVideoScheduler], 1);
+ ilclient_disable_tunnel(&m_tun[eVideoFxToVideoScheduler]);
ilclient_flush_tunnels(&m_tun[eClockToVideoScheduler], 1);
ilclient_disable_tunnel(&m_tun[eClockToVideoScheduler]);
ilclient_change_component_state(m_comp[eVideoScheduler], OMX_StateIdle);
@@ -648,7 +694,8 @@ void cOmx::FlushVideo(bool flushRender)
if (OMX_SendCommand(ILC_GET_HANDLE(m_comp[eVideoDecoder]), OMX_CommandFlush, 130, NULL) != OMX_ErrorNone)
esyslog("rpihddevice: failed to flush video decoder!");
- ilclient_flush_tunnels(&m_tun[eVideoDecoderToVideoScheduler], 1);
+ ilclient_flush_tunnels(&m_tun[eVideoDecoderToVideoFx], 1);
+ ilclient_flush_tunnels(&m_tun[eVideoFxToVideoScheduler], 1);
if (flushRender)
ilclient_flush_tunnels(&m_tun[eVideoSchedulerToVideoRender], 1);
@@ -658,8 +705,6 @@ void cOmx::FlushVideo(bool flushRender)
int cOmx::SetVideoCodec(cVideoCodec::eCodec codec, eDataUnitType dataUnit)
{
- dsyslog("rpihddevice: SetVideoCodec()");
-
if (ilclient_change_component_state(m_comp[eVideoDecoder], OMX_StateIdle) != 0)
esyslog("rpihddevice: failed to set video decoder to idle state!");
@@ -679,7 +724,7 @@ int cOmx::SetVideoCodec(cVideoCodec::eCodec codec, eDataUnitType dataUnit)
// start with valid frames only if codec is MPEG2
SetVideoErrorConcealment(codec == cVideoCodec::eMPEG2);
SetVideoDataUnitType(dataUnit);
- //SetVideoDecoderExtraBuffers(3);
+ SetVideoDecoderExtraBuffers(3);
if (ilclient_enable_port_buffers(m_comp[eVideoDecoder], 130, NULL, NULL, NULL) != 0)
esyslog("rpihddevice: failed to enable port buffer on video decoder!");
@@ -730,7 +775,7 @@ int cOmx::SetupAudioRender(cAudioCodec::eCodec outputFormat, int channels,
outputFormat == cAudioCodec::eAC3 ? OMX_AUDIO_CodingDDP :
outputFormat == cAudioCodec::eEAC3 ? OMX_AUDIO_CodingDDP :
outputFormat == cAudioCodec::eAAC ? OMX_AUDIO_CodingAAC :
- outputFormat == cAudioCodec::eADTS ? OMX_AUDIO_CodingDTS :
+ outputFormat == cAudioCodec::eADTS ? OMX_AUDIO_CodingAAC :
OMX_AUDIO_CodingAutoDetect;
if (OMX_SetParameter(ILC_GET_HANDLE(m_comp[eAudioRender]),
@@ -768,34 +813,22 @@ int cOmx::SetupAudioRender(cAudioCodec::eCodec outputFormat, int channels,
break;
case cAudioCodec::eAAC:
+ case cAudioCodec::eADTS:
OMX_AUDIO_PARAM_AACPROFILETYPE aac;
OMX_INIT_STRUCT(aac);
aac.nPortIndex = 100;
aac.nChannels = channels;
aac.nSampleRate = samplingRate;
- aac.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4LATM;
+ aac.eAACStreamFormat =
+ outputFormat == cAudioCodec::eAAC ? OMX_AUDIO_AACStreamFormatMP4LATM :
+ outputFormat == cAudioCodec::eADTS ? OMX_AUDIO_AACStreamFormatMP4ADTS :
+ (OMX_AUDIO_AACSTREAMFORMATTYPE)0;
if (OMX_SetParameter(ILC_GET_HANDLE(m_comp[eAudioRender]),
OMX_IndexParamAudioAac, &aac) != OMX_ErrorNone)
esyslog("rpihddevice: failed to set audio render aac parameters!");
break;
- case cAudioCodec::eADTS:
- OMX_AUDIO_PARAM_DTSTYPE dts;
- OMX_INIT_STRUCT(aac);
- dts.nPortIndex = 100;
- dts.nChannels = channels;
- dts.nSampleRate = samplingRate;
- dts.nDtsType = 1; // ??
- dts.nFormat = 0; // ??
- dts.nDtsFrameSizeBytes = 0; // ?
- OMX_AUDIO_CHANNEL_MAPPING(dts, channels);
-
- if (OMX_SetParameter(ILC_GET_HANDLE(m_comp[eAudioRender]),
- OMX_IndexParamAudioDts, &dts) != OMX_ErrorNone)
- esyslog("rpihddevice: failed to set audio render dts parameters!");
- break;
-
case cAudioCodec::ePCM:
OMX_AUDIO_PARAM_PCMMODETYPE pcm;
OMX_INIT_STRUCT(pcm);
diff --git a/omx.h b/omx.h
index 10efdce..d442d50 100644
--- a/omx.h
+++ b/omx.h
@@ -7,6 +7,8 @@
#ifndef OMX_H
#define OMX_H
+#include <queue>
+#include <vdr/thread.h>
#include "types.h"
extern "C"
@@ -14,9 +16,7 @@ extern "C"
#include "ilclient.h"
}
-class cMutex;
-
-class cOmx
+class cOmx : public cThread
{
public:
@@ -55,6 +55,7 @@ public:
void SetClockReference(eClockReference clockReference);
void SetVolume(int vol);
+ void SetMute(bool mute);
void SendEos(void);
void StopVideo(void);
void StopAudio(void);
@@ -86,11 +87,14 @@ public:
private:
+ virtual void Action(void);
+
static const char* errStr(int err);
enum eOmxComponent {
eClock = 0,
eVideoDecoder,
+ eVideoFx,
eVideoScheduler,
eVideoRender,
eAudioRender,
@@ -98,7 +102,8 @@ private:
};
enum eOmxTunnel {
- eVideoDecoderToVideoScheduler = 0,
+ eVideoDecoderToVideoFx = 0,
+ eVideoFxToVideoScheduler,
eVideoSchedulerToVideoRender,
eClockToVideoScheduler,
eClockToAudioRender,
@@ -120,9 +125,9 @@ private:
eClockReference m_clockReference;
- void HandleEndOfStream(unsigned int portId);
+ cCondWait *m_portEventReady;
+ std::queue<unsigned int> *m_portEvents;
void HandlePortSettingsChanged(unsigned int portId);
- void HandleBufferEmpty(COMPONENT_T *comp);
static void OnBufferEmpty(void *instance, COMPONENT_T *comp);
static void OnPortSettingsChanged(void *instance, COMPONENT_T *comp, OMX_U32 data);
diff --git a/omxdevice.c b/omxdevice.c
index 456f5b4..a87bd87 100644
--- a/omxdevice.c
+++ b/omxdevice.c
@@ -9,6 +9,7 @@
#include "audio.h"
#include "setup.h"
+#include <vdr/thread.h>
#include <vdr/remux.h>
#include <vdr/tools.h>
#include <vdr/skins.h>
@@ -120,8 +121,10 @@ void cOmxDevice::StillPicture(const uchar *Data, int Length)
else
{
// to get a picture displayed, PlayVideo() needs to be called
- // twice for MPEG2 and 6x for H264... ?
- for (int i = 0; i < (m_videoCodec == cVideoCodec::eMPEG2 ? 2 : 6); i++)
+ // twice for MPEG2 and 10x for H264... ?
+ int repeat = ParseVideoCodec(Data, Length) == cVideoCodec::eMPEG2 ? 2 : 10;
+
+ while (repeat--)
PlayVideo(Data, Length, true);
}
}
@@ -218,6 +221,9 @@ int cOmxDevice::PlayVideo(const uchar *Data, int Length, bool singleFrame)
const uchar *payload = Data + PesPayloadOffset(Data);
unsigned int length = PesLength(Data) - PesPayloadOffset(Data);
+ if (length > Length)
+ esyslog("rpihddevice: PES-Length > Length!");
+
OMX_BUFFERHEADERTYPE *buf = m_omx->GetVideoBuffer(pts);
if (buf)
{
@@ -255,17 +261,10 @@ int64_t cOmxDevice::GetSTC(void)
void cOmxDevice::Play(void)
{
- dsyslog("rpihddevice: Play()");
-
- Clear();
- return;
-
m_mutex->Lock();
- m_skipAudio = false;
- m_omx->SetClockScale(1.0f);
- m_omx->SetClockReference(m_hasAudio ?
- cOmx::eClockRefAudio : cOmx::eClockRefVideo);
+ ResetAudioVideo();
+ m_omx->SetStartTime(0);
m_mutex->Unlock();
cDevice::Play();
@@ -279,6 +278,14 @@ void cOmxDevice::Freeze(void)
cDevice::Freeze();
}
+#if APIVERSNUM >= 20103
+void cOmxDevice::TrickSpeed(int Speed, bool Forward)
+{
+ m_mutex->Lock();
+ ApplyTrickSpeed(Speed, Forward);
+ m_mutex->Unlock();
+}
+#else
void cOmxDevice::TrickSpeed(int Speed)
{
m_mutex->Lock();
@@ -294,8 +301,9 @@ void cOmxDevice::TrickSpeed(int Speed)
m_mutex->Unlock();
}
+#endif
-void cOmxDevice::ApplyTrickSpeed(int trickSpeed, bool reverse)
+void cOmxDevice::ApplyTrickSpeed(int trickSpeed, bool forward)
{
float scale =
// slow forward
@@ -304,9 +312,9 @@ void cOmxDevice::ApplyTrickSpeed(int trickSpeed, bool reverse)
trickSpeed == 2 ? 0.5f :
// fast for-/backward
- trickSpeed == 6 ? (reverse ? -2.0f : 2.0f) :
- trickSpeed == 3 ? (reverse ? -4.0f : 4.0f) :
- trickSpeed == 1 ? (reverse ? -12.0f : 12.0f) :
+ trickSpeed == 6 ? (forward ? 2.0f : -2.0f) :
+ trickSpeed == 3 ? (forward ? 4.0f : -4.0f) :
+ trickSpeed == 1 ? (forward ? 12.0f : -12.0f) :
// slow backward
trickSpeed == 63 ? -0.125f :
@@ -320,7 +328,7 @@ void cOmxDevice::ApplyTrickSpeed(int trickSpeed, bool reverse)
m_skipAudio = true;
dsyslog("rpihddevice: ApplyTrickSpeed(%.3f, %sward)",
- scale, reverse ? "back" : "for");
+ scale, forward ? "for" : "back");
}
@@ -332,7 +340,7 @@ void cOmxDevice::PtsTracker(int64_t ptsDiff)
m_playDirection += 2;
if (m_playDirection < -2 || m_playDirection > 3)
- ApplyTrickSpeed(m_trickRequest, m_playDirection < 0);
+ ApplyTrickSpeed(m_trickRequest, m_playDirection > 0);
}
bool cOmxDevice::Flush(int TimeoutMs)
@@ -343,7 +351,6 @@ bool cOmxDevice::Flush(int TimeoutMs)
void cOmxDevice::Clear(void)
{
- dsyslog("rpihddevice: Clear()");
m_mutex->Lock();
ResetAudioVideo();
@@ -377,7 +384,13 @@ void cOmxDevice::ResetAudioVideo(bool flushVideoRender)
void cOmxDevice::SetVolumeDevice(int Volume)
{
- m_omx->SetVolume(Volume);
+ if (Volume)
+ {
+ m_omx->SetVolume(Volume);
+ m_omx->SetMute(false);
+ }
+ else
+ m_omx->SetMute(true);
}
bool cOmxDevice::Poll(cPoller &Poller, int TimeoutMs)
diff --git a/omxdevice.h b/omxdevice.h
index 797c58d..d28543e 100644
--- a/omxdevice.h
+++ b/omxdevice.h
@@ -8,26 +8,18 @@
#define OMX_DEVICE_H
#include <vdr/device.h>
-#include <vdr/thread.h>
#include "types.h"
class cOmx;
class cAudioDecoder;
+class cMutex;
class cOmxDevice : cDevice
{
public:
- enum eState {
- eNone,
- eStartingVideo,
- eAudioOnly,
- eVideoOnly,
- eAudioVideo
- };
-
cOmxDevice(void (*onPrimaryDevice)(void));
virtual ~cOmxDevice();
@@ -47,12 +39,18 @@ public:
virtual int PlayVideo(const uchar *Data, int Length)
{ return PlayVideo(Data, Length, false); }
- virtual int PlayVideo(const uchar *Data, int Length, bool singleFrame = false);
+ virtual int PlayVideo(const uchar *Data, int Length, bool singleFrame);
virtual int64_t GetSTC(void);
virtual bool HasIBPTrickSpeed(void) { return true; }
+
+#if APIVERSNUM >= 20103
+ virtual void TrickSpeed(int Speed, bool Forward);
+#else
virtual void TrickSpeed(int Speed);
+#endif
+
virtual void Clear(void);
virtual void Play(void);
virtual void Freeze(void);
@@ -73,7 +71,7 @@ private:
void ResetAudioVideo(bool flushVideoRender = false);
- void ApplyTrickSpeed(int trickSpeed, bool reverse = false);
+ void ApplyTrickSpeed(int trickSpeed, bool forward = true);
void PtsTracker(int64_t ptsDiff);
cOmx *m_omx;
diff --git a/rpihddevice.c b/rpihddevice.c
index 05ce3d0..03c0813 100644
--- a/rpihddevice.c
+++ b/rpihddevice.c
@@ -12,7 +12,7 @@
#include "setup.h"
#include "types.h"
-static const char *VERSION = "0.0.6a";
+static const char *VERSION = "0.0.7";
static const char *DESCRIPTION = "HD output device for Raspberry Pi";
class cDummyDevice : cDevice
@@ -71,7 +71,6 @@ cPluginRpiHdDevice::cPluginRpiHdDevice(void) :
cPluginRpiHdDevice::~cPluginRpiHdDevice()
{
- delete m_device;
cRpiSetup::DropInstance();
}
diff --git a/setup.c b/setup.c
index a763ef1..de2a4af 100644
--- a/setup.c
+++ b/setup.c
@@ -113,19 +113,20 @@ bool cRpiSetup::HwInit(void)
bool cRpiSetup::IsAudioFormatSupported(cAudioCodec::eCodec codec,
int channels, int samplingRate)
{
- // AAC and DTS pass-through currently not supported
- if (codec == cAudioCodec::eAAC ||
- codec == cAudioCodec::eADTS)
- return false;
+ // AAC-LATM and AAC pass-through currently not supported
+// if (codec == cAudioCodec::eAAC ||
+// codec == cAudioCodec::eADTS)
+// return false;
if (vc_tv_hdmi_audio_supported(
codec == cAudioCodec::eMPG ? EDID_AudioFormat_eMPEG1 :
codec == cAudioCodec::eAC3 ? EDID_AudioFormat_eAC3 :
codec == cAudioCodec::eEAC3 ? EDID_AudioFormat_eEAC3 :
codec == cAudioCodec::eAAC ? EDID_AudioFormat_eAAC :
+ codec == cAudioCodec::eADTS ? EDID_AudioFormat_eAAC :
EDID_AudioFormat_ePCM, channels,
samplingRate == 32000 ? EDID_AudioSampleRate_e32KHz :
- samplingRate == 44000 ? EDID_AudioSampleRate_e44KHz :
+ samplingRate == 44100 ? EDID_AudioSampleRate_e44KHz :
samplingRate == 88000 ? EDID_AudioSampleRate_e88KHz :
samplingRate == 96000 ? EDID_AudioSampleRate_e96KHz :
samplingRate == 176000 ? EDID_AudioSampleRate_e176KHz :
@@ -134,6 +135,10 @@ bool cRpiSetup::IsAudioFormatSupported(cAudioCodec::eCodec codec,
EDID_AudioSampleSize_16bit) == 0)
return true;
+ dsyslog("rpihddevice: %dch %s, %d.%dkHz not supported by HDMI device",
+ channels, cAudioCodec::Str(codec),
+ samplingRate / 1000, (samplingRate % 1000) / 100);
+
return false;
}
@@ -151,9 +156,31 @@ int cRpiSetup::GetDisplaySize(int &width, int &height, double &aspect)
aspect = 1;
return 0;
}
+
return -1;
}
+bool cRpiSetup::IsDisplayProgressive(void)
+{
+ bool progressive = false;
+
+ TV_DISPLAY_STATE_T tvstate;
+ memset(&tvstate, 0, sizeof(TV_DISPLAY_STATE_T));
+ if (!vc_tv_get_display_state(&tvstate))
+ {
+ // HDMI
+ if ((tvstate.state & (VC_HDMI_HDMI | VC_HDMI_DVI)))
+ progressive = tvstate.display.hdmi.scan_mode == 0;
+ // composite
+ else
+ progressive = false;
+ }
+ else
+ esyslog("rpihddevice: failed to get display state!");
+
+ return progressive;
+}
+
bool cRpiSetup::HasAudioSetupChanged(void)
{
if (!GetInstance()->m_audioSetupChanged)
diff --git a/setup.h b/setup.h
index 761e14b..a5ee414 100644
--- a/setup.h
+++ b/setup.h
@@ -34,6 +34,7 @@ public:
}
static int GetDisplaySize(int &width, int &height, double &aspect);
+ static bool IsDisplayProgressive(void);
static cRpiSetup* GetInstance(void);
static void DropInstance(void);