summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Reufer <thomas@reufer.ch>2014-01-07 16:31:12 +0100
committerThomas Reufer <thomas@reufer.ch>2014-01-07 16:31:12 +0100
commit9512123c95324f1679d748993662bd9f08f6f763 (patch)
treed532e2af4d30847eeaaf69faf427c6f77fc5afb8
parent66cb725c2146b4fdeeed1dd201dd58be42104bab (diff)
downloadvdr-plugin-rpihddevice-0.0.4.tar.gz
vdr-plugin-rpihddevice-0.0.4.tar.bz2
2013-10-14: Version 0.0.40.0.4
------------------------- - new: - changed to libav for audio decoding - added support multi-channel audio codecs - added audio format/output options - fixed: - removed drawing of black box in front of console which lead to malfunction due to memory bandwidth problem. console blank out will be handled with video format/output options in future versions. - missing - trick modes - deinterlacer - video format/output options - much more...
-rw-r--r--HISTORY16
-rw-r--r--Makefile8
-rw-r--r--audio.c229
-rw-r--r--audio.h85
-rw-r--r--omxdevice.c434
-rw-r--r--omxdevice.h32
-rw-r--r--ovgosd.c6
-rw-r--r--po/de_DE.po30
-rw-r--r--rpihddevice.c36
-rw-r--r--setup.c170
-rw-r--r--setup.h57
11 files changed, 932 insertions, 171 deletions
diff --git a/HISTORY b/HISTORY
index 244c31f..bad3594 100644
--- a/HISTORY
+++ b/HISTORY
@@ -1,6 +1,22 @@
VDR Plugin 'rpihddevice' Revision History
-----------------------------------------
+2013-10-14: Version 0.0.4
+-------------------------
+- new:
+ - changed to libav for audio decoding
+ - added support multi-channel audio codecs
+ - added audio format/output options
+- fixed:
+ - removed drawing of black box in front of console which lead to malfunction
+ due to memory bandwidth problem. console blank out will be handled with
+ video format/output options in future versions.
+- missing
+ - trick modes
+ - deinterlacer
+ - video format/output options
+ - much more...
+
2013-10-02: Version 0.0.3
-------------------------
- new:
diff --git a/Makefile b/Makefile
index e393804..4b02ae3 100644
--- a/Makefile
+++ b/Makefile
@@ -51,19 +51,21 @@ DEFINES += -DPLUGIN_NAME_I18N='"$(PLUGIN)"'
DEFINES += -DHAVE_LIBOPENMAX=2 -DOMX -DOMX_SKIP64BIT -DUSE_EXTERNAL_OMX -DHAVE_LIBBCM_HOST -DUSE_EXTERNAL_LIBBCM_HOST -DUSE_VCHIQ_ARM
DEFINES += -Wno-write-strings -fpermissive
+CXXFLAGS += -D__STDC_CONSTANT_MACROS
+
ILCDIR =ilclient
VCINCDIR =/opt/vc/include
VCLIBDIR =/opt/vc/lib
INCLUDES += -I$(ILCDIR) -I$(VCINCDIR) -I$(VCINCDIR)/interface/vcos/pthreads -I$(VCINCDIR)/interface/vmcs_host/linux
-LDFLAGS += -L$(VCLIBDIR) -lbcm_host -lvcos -lvchiq_arm -lopenmaxil -lGLESv2 -lEGL -lpthread -lrt -lmpg123
+LDFLAGS += -L$(VCLIBDIR) -lbcm_host -lvcos -lvchiq_arm -lopenmaxil -lGLESv2 -lEGL -lpthread -lrt -lavcodec -lavformat
LDFLAGS += -Wl,--whole-archive $(ILCDIR)/libilclient.a -Wl,--no-whole-archive
-
+
### The object files (add further files here):
ILCLIENT = $(ILCDIR)/libilclient.a
-OBJS = $(PLUGIN).o omxdevice.o ovgosd.o
+OBJS = $(PLUGIN).o setup.o audio.o omxdevice.o ovgosd.o
### The main target:
diff --git a/audio.c b/audio.c
new file mode 100644
index 0000000..f85a4ff
--- /dev/null
+++ b/audio.c
@@ -0,0 +1,229 @@
+/*
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id$
+ */
+
+#include "audio.h"
+#include "setup.h"
+
+#include <vdr/tools.h>
+#include <vdr/remux.h>
+
+#include <string.h>
+
+cAudioDecoder::cAudioDecoder() :
+ m_codec(ePCM),
+ m_outputFormat(ePCM),
+ m_outputPort(eLocal),
+ m_channels(0),
+ m_samplingRate(0),
+ m_passthrough(false),
+ m_frame(0),
+ m_mutex(new cMutex()) { }
+
+cAudioDecoder::~cAudioDecoder()
+{
+ delete m_mutex;
+}
+
+int cAudioDecoder::Init(void)
+{
+ int ret = 0;
+
+ avcodec_register_all();
+
+ m_codecs[ePCM ].codec = NULL;
+ m_codecs[eMPG ].codec = avcodec_find_decoder(CODEC_ID_MP3);
+ m_codecs[eAC3 ].codec = avcodec_find_decoder(CODEC_ID_AC3);
+ m_codecs[eEAC3].codec = avcodec_find_decoder(CODEC_ID_EAC3);
+ m_codecs[eAAC ].codec = avcodec_find_decoder(CODEC_ID_AAC_LATM);
+ m_codecs[eDTS ].codec = avcodec_find_decoder(CODEC_ID_DTS);
+
+ for (int i = 0; i < eNumCodecs; i++)
+ {
+ eCodec codec = static_cast<eCodec>(i);
+ if (m_codecs[codec].codec)
+ {
+ m_codecs[codec].context = avcodec_alloc_context3(m_codecs[codec].codec);
+ if (!m_codecs[codec].context)
+ {
+ esyslog("rpihddevice: failed to allocate %s context!", CodecStr(codec));
+ ret = -1;
+ break;
+ }
+ if (avcodec_open2(m_codecs[codec].context, m_codecs[codec].codec, NULL) < 0)
+ {
+ esyslog("rpihddevice: failed to open %s decoder!", CodecStr(codec));
+ ret = -1;
+ break;
+ }
+ }
+ }
+
+ m_frame = avcodec_alloc_frame();
+ if (!m_frame)
+ {
+ esyslog("rpihddevice: failed to allocate audio frame!");
+ ret = -1;
+ }
+
+ if (ret < 0)
+ DeInit();
+
+ return ret;
+}
+
+int cAudioDecoder::DeInit(void)
+{
+ for (int i = 0; i < eNumCodecs; i++)
+ {
+ eCodec codec = static_cast<eCodec>(i);
+ avcodec_close(m_codecs[codec].context);
+ av_free(m_codecs[codec].context);
+ }
+
+ av_free(m_frame);
+ return 0;
+}
+
+bool cAudioDecoder::SetupAudioCodec(const unsigned char *data, int length)
+{
+ m_mutex->Lock();
+
+ bool ret = false;
+
+ // try to decode audio sample
+ AVPacket avpkt;
+ av_init_packet(&avpkt);
+ avpkt.data = (unsigned char *)(data + PesPayloadOffset(data));
+ avpkt.size = PesLength(data) - PesPayloadOffset(data);
+
+ for (int i = 0; i < eNumCodecs; i++)
+ {
+ eCodec codec = static_cast<eCodec>(i);
+ if (m_codecs[codec].codec)
+ {
+ int frame = 0;
+ avcodec_get_frame_defaults(m_frame);
+
+ m_codecs[codec].context->request_channel_layout = AV_CH_LAYOUT_NATIVE;
+ m_codecs[codec].context->request_channels = 0;
+
+ int len = avcodec_decode_audio4(m_codecs[codec].context, m_frame, &frame, &avpkt);
+
+ if (len > 0 && frame)
+ {
+ m_codec = codec;
+ m_channels = m_codecs[m_codec].context->channels;
+ m_samplingRate = m_codecs[m_codec].context->sample_rate;
+ dsyslog("rpihddevice: set audio codec to %s with %d channels, %dHz",
+ CodecStr(m_codec), m_channels, m_samplingRate);
+
+ m_passthrough = false;
+ m_outputFormat = ePCM;
+ m_outputPort = eLocal;
+
+ if (cRpiSetup::GetAudioPort() == eHDMI &&
+ cRpiSetup::IsAudioFormatSupported(ePCM, 2, 48000))
+ {
+ m_outputPort = eHDMI;
+
+ if (cRpiSetup::IsAudioPassthrough() &&
+ cRpiSetup::IsAudioFormatSupported(m_codec, m_channels, m_samplingRate))
+ {
+ m_passthrough = true;
+ m_outputFormat = m_codec;
+ }
+ dsyslog("rpihddevice: set HDMI audio output format to %s%s",
+ CodecStr(m_outputFormat), m_passthrough ? " (pass-through)" : "");
+ }
+ else
+ {
+ m_codecs[m_codec].context->request_channel_layout = AV_CH_LAYOUT_STEREO_DOWNMIX;
+ m_codecs[m_codec].context->request_channels = 2;
+ m_channels = 2;
+ dsyslog("rpihddevice: set analog audio output format to PCM stereo");
+ }
+
+ ret = true;
+ break;
+ }
+ }
+ }
+ m_mutex->Unlock();
+ return ret;
+}
+
+unsigned int cAudioDecoder::DecodeAudio(const unsigned char *data, int length, unsigned char *outbuf, int bufsize)
+{
+ m_mutex->Lock();
+
+ if (m_passthrough)
+ {
+ if (length > bufsize)
+ esyslog("rpihddevice: pass-through audio frame is bigger than output buffer!");
+ else
+ memcpy(outbuf, data, length);
+
+ return length;
+ }
+
+ AVPacket avpkt;
+ av_init_packet(&avpkt);
+
+ avpkt.data = (unsigned char *)data;
+ avpkt.size = length;
+
+ unsigned int outsize = 0;
+
+ while (avpkt.size > 0)
+ {
+ int frame = 0;
+ avcodec_get_frame_defaults(m_frame);
+
+ int len = avcodec_decode_audio4(m_codecs[m_codec].context, m_frame, &frame, &avpkt);
+ if (len < 0)
+ break;
+
+ if (frame)
+ {
+ unsigned int framesize = av_samples_get_buffer_size(NULL,
+ m_channels == 6 ? 8 : m_channels, m_frame->nb_samples,
+ m_codecs[m_codec].context->sample_fmt, 1);
+
+ if (outsize + framesize <= bufsize)
+ {
+ if (m_channels == 6)
+ {
+ // interleaved copy to fit 5.1 data into 8 channels
+ int32_t* src = (int32_t*)m_frame->data[0];
+ int32_t* dst = (int32_t*)outbuf;
+
+ for (int i = 0; i < m_frame->nb_samples; i++)
+ {
+ *dst++ = *src++; // LF & RF
+ *dst++ = *src++; // CF & LFE
+ *dst++ = *src++; // LR & RR
+ *dst++ = 0; // empty channels
+ }
+ }
+ else
+ memcpy(outbuf, m_frame->data[0], framesize);
+
+ outsize += framesize;
+ outbuf += framesize;
+ }
+ else
+ {
+ esyslog("rpihddevice: decoded audio frame is bigger than output buffer!");
+ break;
+ }
+ }
+ avpkt.size -= len;
+ avpkt.data += len;
+ }
+
+ m_mutex->Unlock();
+ return outsize;
+}
diff --git a/audio.h b/audio.h
new file mode 100644
index 0000000..a4ade81
--- /dev/null
+++ b/audio.h
@@ -0,0 +1,85 @@
+/*
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id$
+ */
+
+#ifndef AUDIO_H
+#define AUDIO_H
+
+extern "C"
+{
+#include <libavcodec/avcodec.h>
+}
+
+class cMutex;
+
+class cAudioDecoder
+{
+
+public:
+
+ enum eCodec {
+ ePCM,
+ eMPG,
+ eAC3,
+ eEAC3,
+ eAAC,
+ eDTS,
+ eNumCodecs
+ };
+
+ enum ePort {
+ eLocal,
+ eHDMI
+ };
+
+ static const char* CodecStr(eCodec codec)
+ {
+ return (codec == ePCM) ? "PCM" :
+ (codec == eMPG) ? "MPG" :
+ (codec == eAC3) ? "AC3" :
+ (codec == eEAC3) ? "E-AC3" :
+ (codec == eAAC) ? "AAC" :
+ (codec == eDTS) ? "DTS" : "unknown";
+ }
+
+ cAudioDecoder();
+ virtual ~cAudioDecoder();
+
+ virtual int Init(void);
+ virtual int DeInit(void);
+
+ virtual bool SetupAudioCodec(const unsigned char *data, int length);
+
+ virtual eCodec GetCodec(void) { return m_codec; }
+ virtual eCodec GetOutputFormat(void) { return m_outputFormat; }
+ virtual ePort GetOutputPort(void) { return m_outputPort; }
+ virtual int GetChannels(void) { return m_channels; }
+ virtual int GetSamplingrate(void) { return m_samplingRate; }
+
+ virtual unsigned int DecodeAudio(const unsigned char *data, int length,
+ unsigned char *outbuf, int bufsize);
+
+private:
+
+ struct Codec
+ {
+ AVCodec *codec;
+ AVCodecContext *context;
+ };
+
+ Codec m_codecs[eNumCodecs];
+ eCodec m_codec;
+ eCodec m_outputFormat;
+ ePort m_outputPort;
+ int m_channels;
+ int m_samplingRate;
+
+ bool m_passthrough;
+
+ AVFrame *m_frame;
+ cMutex *m_mutex;
+};
+
+#endif
diff --git a/omxdevice.c b/omxdevice.c
index a6514bc..aa5610e 100644
--- a/omxdevice.c
+++ b/omxdevice.c
@@ -3,15 +3,14 @@
*
* $Id$
*/
-//#pragma pack(1)
#include "omxdevice.h"
+#include "audio.h"
+#include "setup.h"
#include <vdr/remux.h>
#include <vdr/tools.h>
-#include <mpg123.h>
-
#include <string.h>
extern "C"
@@ -21,6 +20,39 @@ extern "C"
#include "bcm_host.h"
+#define OMX_INIT_STRUCT(a) \
+ memset(&(a), 0, sizeof(a)); \
+ (a).nSize = sizeof(a); \
+ (a).nVersion.s.nVersionMajor = OMX_VERSION_MAJOR; \
+ (a).nVersion.s.nVersionMinor = OMX_VERSION_MINOR; \
+ (a).nVersion.s.nRevision = OMX_VERSION_REVISION; \
+ (a).nVersion.s.nStep = OMX_VERSION_STEP
+
+#define OMX_AUDIO_CHANNEL_MAPPING(s, c) \
+switch (c) { \
+case 4: \
+ (s).eChannelMapping[0] = OMX_AUDIO_ChannelLF; \
+ (s).eChannelMapping[1] = OMX_AUDIO_ChannelRF; \
+ (s).eChannelMapping[2] = OMX_AUDIO_ChannelLR; \
+ (s).eChannelMapping[3] = OMX_AUDIO_ChannelRR; \
+ break; \
+case 1: \
+ (s).eChannelMapping[0] = OMX_AUDIO_ChannelCF; \
+ break; \
+case 8: \
+ (s).eChannelMapping[6] = OMX_AUDIO_ChannelLS; \
+ (s).eChannelMapping[7] = OMX_AUDIO_ChannelRS; \
+case 6: \
+ (s).eChannelMapping[2] = OMX_AUDIO_ChannelCF; \
+ (s).eChannelMapping[3] = OMX_AUDIO_ChannelLFE; \
+ (s).eChannelMapping[4] = OMX_AUDIO_ChannelLR; \
+ (s).eChannelMapping[5] = OMX_AUDIO_ChannelRR; \
+case 2: \
+default: \
+ (s).eChannelMapping[0] = OMX_AUDIO_ChannelLF; \
+ (s).eChannelMapping[1] = OMX_AUDIO_ChannelRF; \
+ break; }
+
class cOmx
{
@@ -126,11 +158,31 @@ private:
void HandlePortSettingsChanged(unsigned int portId)
{
- dsyslog("rpihddevice: HandlePortSettingsChanged(%d)", portId);
+ //dsyslog("rpihddevice: HandlePortSettingsChanged(%d)", portId);
switch (portId)
{
case 131:
+
+ OMX_PARAM_PORTDEFINITIONTYPE portdef;
+ OMX_INIT_STRUCT(portdef);
+ portdef.nPortIndex = 131;
+ if (OMX_GetParameter(ILC_GET_HANDLE(m_comp[eVideoDecoder]), OMX_IndexParamPortDefinition,
+ &portdef) != OMX_ErrorNone)
+ esyslog("rpihddevice: failed to get video decoder port format!");
+
+ OMX_CONFIG_INTERLACETYPE interlace;
+ OMX_INIT_STRUCT(interlace);
+ interlace.nPortIndex = 131;
+ if (OMX_GetConfig(ILC_GET_HANDLE(m_comp[eVideoDecoder]), OMX_IndexConfigCommonInterlace,
+ &interlace) != OMX_ErrorNone)
+ esyslog("rpihddevice: failed to get video decoder interlace config!");
+
+ dsyslog("rpihddevice: decoding video %dx%d%s",
+ 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)
@@ -256,9 +308,7 @@ public:
esyslog("rpihddevice: failed to setup up tunnel from clock to audio render!");
OMX_TIME_CONFIG_ACTIVEREFCLOCKTYPE refclock;
- memset(&refclock, 0, sizeof(refclock));
- refclock.nSize = sizeof(refclock);
- refclock.nVersion.nVersion = OMX_VERSION;
+ OMX_INIT_STRUCT(refclock);
refclock.eClock = OMX_TIME_RefClockAudio;
// refclock.eClock = OMX_TIME_RefClockVideo;
@@ -270,24 +320,20 @@ public:
ilclient_change_component_state(m_comp[eVideoDecoder], OMX_StateIdle);
// set up the number and size of buffers for audio render
- m_freeAudioBuffers = 64;
+ m_freeAudioBuffers = 16;
OMX_PARAM_PORTDEFINITIONTYPE param;
- memset(&param, 0, sizeof(param));
- param.nSize = sizeof(param);
- param.nVersion.nVersion = OMX_VERSION;
+ OMX_INIT_STRUCT(param);
param.nPortIndex = 100;
if (OMX_GetParameter(ILC_GET_HANDLE(m_comp[eAudioRender]),
OMX_IndexParamPortDefinition, &param) != OMX_ErrorNone)
esyslog("rpihddevice: failed to get audio render port parameters!");
- param.nBufferSize = 65536;
+ param.nBufferSize = 128 * 1024;
param.nBufferCountActual = m_freeAudioBuffers;
if (OMX_SetParameter(ILC_GET_HANDLE(m_comp[eAudioRender]),
OMX_IndexParamPortDefinition, &param) != OMX_ErrorNone)
esyslog("rpihddevice: failed to set audio render port parameters!");
- memset(&param, 0, sizeof(param));
- param.nSize = sizeof(param);
- param.nVersion.nVersion = OMX_VERSION;
+ OMX_INIT_STRUCT(param);
param.nPortIndex = 130;
if (OMX_GetParameter(ILC_GET_HANDLE(m_comp[eVideoDecoder]),
OMX_IndexParamPortDefinition, &param) != OMX_ErrorNone)
@@ -297,41 +343,9 @@ public:
dsyslog("rpihddevice: started with %d video and %d audio buffers",
m_freeVideoBuffers, m_freeAudioBuffers);
- // configure audio render
- OMX_AUDIO_PARAM_PCMMODETYPE pcmMode;
- memset(&pcmMode, 0, sizeof(pcmMode));
- pcmMode.nSize = sizeof(pcmMode);
- pcmMode.nVersion.nVersion = OMX_VERSION;
- pcmMode.nPortIndex = 100;
- pcmMode.nChannels = 2;
- pcmMode.eNumData = OMX_NumericalDataSigned;
- pcmMode.eEndian = OMX_EndianLittle;
- pcmMode.bInterleaved = OMX_TRUE;
- pcmMode.nBitPerSample = 16;
- pcmMode.nSamplingRate = 48000;
- pcmMode.ePCMMode = OMX_AUDIO_PCMModeLinear;
- pcmMode.eChannelMapping[0] = OMX_AUDIO_ChannelLF;
- pcmMode.eChannelMapping[1] = OMX_AUDIO_ChannelRF;
-
- if (OMX_SetParameter(ILC_GET_HANDLE(m_comp[eAudioRender]),
- OMX_IndexParamAudioPcm, &pcmMode) != OMX_ErrorNone)
- esyslog("rpihddevice: failed to set audio render parameters!");
-
- OMX_CONFIG_BRCMAUDIODESTINATIONTYPE audioDest;
- memset(&audioDest, 0, sizeof(audioDest));
- audioDest.nSize = sizeof(audioDest);
- audioDest.nVersion.nVersion = OMX_VERSION;
- strcpy((char *)audioDest.sName, "local");
-
- if (OMX_SetConfig(ILC_GET_HANDLE(m_comp[eAudioRender]),
- OMX_IndexConfigBrcmAudioDestination, &audioDest) != OMX_ErrorNone)
- esyslog("rpihddevice: failed to set audio destination!");
-
/* // configure video decoder stall callback
OMX_CONFIG_BUFFERSTALLTYPE stallConf;
- memset(&stallConf, 0, sizeof(stallConf));
- stallConf.nSize = sizeof(stallConf);
- stallConf.nVersion.nVersion = OMX_VERSION;
+ OMX_INIT_STRUCT(stallConf);
stallConf.nPortIndex = 131;
stallConf.nDelay = 1500 * 1000;
if (OMX_SetConfig(m_comp[eVideoDecoder], OMX_IndexConfigBufferStall,
@@ -339,9 +353,7 @@ public:
esyslog("rpihddevice: failed to set video decoder stall config!");
OMX_CONFIG_REQUESTCALLBACKTYPE reqCallback;
- memset(&reqCallback, 0, sizeof(reqCallback));
- reqCallback.nSize = sizeof(reqCallback);
- reqCallback.nVersion.nVersion = OMX_VERSION;
+ OMX_INIT_STRUCT(reqCallback);
reqCallback.nPortIndex = 131;
reqCallback.nIndex = OMX_IndexConfigBufferStall;
reqCallback.bEnable = OMX_TRUE;
@@ -390,10 +402,8 @@ public:
int64_t stc = -1;
OMX_TIME_CONFIG_TIMESTAMPTYPE timestamp;
- memset(&timestamp, 0, sizeof(timestamp));
- timestamp.nSize = sizeof(timestamp);
+ OMX_INIT_STRUCT(timestamp);
timestamp.nPortIndex = OMX_ALL;
- timestamp.nVersion.nVersion = OMX_VERSION;
if (OMX_GetConfig(ILC_GET_HANDLE(m_comp[eClock]),
OMX_IndexConfigTimeCurrentMediaTime, &timestamp) != OMX_ErrorNone)
@@ -407,9 +417,7 @@ public:
bool IsClockRunning(void)
{
OMX_TIME_CONFIG_CLOCKSTATETYPE cstate;
- memset(&cstate, 0, sizeof(cstate));
- cstate.nSize = sizeof(cstate);
- cstate.nVersion.nVersion = OMX_VERSION;
+ OMX_INIT_STRUCT(cstate);
if (OMX_GetConfig(ILC_GET_HANDLE(m_comp[eClock]),
OMX_IndexConfigTimeClockState, &cstate) != OMX_ErrorNone)
@@ -439,9 +447,7 @@ public:
clockState == eClockStateWaitForAudioVideo ? "eClockStateWaitForAudioVideo" : "unknown");
OMX_TIME_CONFIG_CLOCKSTATETYPE cstate;
- memset(&cstate, 0, sizeof(cstate));
- cstate.nSize = sizeof(cstate);
- cstate.nVersion.nVersion = OMX_VERSION;
+ OMX_INIT_STRUCT(cstate);
if (OMX_GetConfig(ILC_GET_HANDLE(m_comp[eClock]),
OMX_IndexConfigTimeClockState, &cstate) != OMX_ErrorNone)
@@ -497,9 +503,7 @@ public:
void SetClockScale(float scale)
{
OMX_TIME_CONFIG_SCALETYPE scaleType;
- memset(&scaleType, 0, sizeof(scaleType));
- scaleType.nSize = sizeof(scaleType);
- scaleType.nVersion.nVersion = OMX_VERSION;
+ OMX_INIT_STRUCT(scaleType);
scaleType.xScale = floor(scale * pow(2, 16));
if (OMX_SetConfig(ILC_GET_HANDLE(m_comp[eClock]),
OMX_IndexConfigTimeScale, &scaleType) != OMX_ErrorNone)
@@ -513,9 +517,7 @@ public:
dsyslog("rpihddevice: SetVolumeDevice(%d)", vol);
OMX_AUDIO_CONFIG_VOLUMETYPE volume;
- memset(&volume, 0, sizeof(volume));
- volume.nSize = sizeof(volume);
- volume.nVersion.nVersion = OMX_VERSION;
+ OMX_INIT_STRUCT(volume);
volume.nPortIndex = 100;
volume.bLinear = OMX_TRUE;
volume.sVolume.nValue = vol * 100 / 255;
@@ -572,23 +574,23 @@ public:
SetClockState(eClockStateStop);
}
- int SetVideoCodec(OMX_VIDEO_CODINGTYPE coding)
+ int SetVideoCodec(cOmxDevice::eVideoCodec codec)
{
// configure video decoder
OMX_VIDEO_PARAM_PORTFORMATTYPE videoFormat;
- memset(&videoFormat, 0, sizeof(videoFormat));
- videoFormat.nSize = sizeof(videoFormat);
- videoFormat.nVersion.nVersion = OMX_VERSION;
+ OMX_INIT_STRUCT(videoFormat);
videoFormat.nPortIndex = 130;
- videoFormat.eCompressionFormat = coding;
+ videoFormat.eCompressionFormat =
+ codec == cOmxDevice::eMPEG2 ? OMX_VIDEO_CodingMPEG2 :
+ codec == cOmxDevice::eH264 ? OMX_VIDEO_CodingAVC :
+ OMX_VIDEO_CodingAutoDetect;
+
if (OMX_SetParameter(ILC_GET_HANDLE(m_comp[eVideoDecoder]),
OMX_IndexParamVideoPortFormat, &videoFormat) != OMX_ErrorNone)
esyslog("rpihddevice: failed to set video decoder parameters!");
OMX_PARAM_BRCMVIDEODECODEERRORCONCEALMENTTYPE ectype;
- memset (&ectype, 0, sizeof(ectype));
- ectype.nSize = sizeof(ectype);
- ectype.nVersion.nVersion = OMX_VERSION;
+ OMX_INIT_STRUCT(ectype);
ectype.bStartWithValidFrame = OMX_FALSE;
if (OMX_SetParameter(ILC_GET_HANDLE(m_comp[eVideoDecoder]),
OMX_IndexParamBrcmVideoDecodeErrorConcealment, &ectype) != OMX_ErrorNone)
@@ -607,8 +609,125 @@ public:
return 0;
}
- int SetAudioCodec(OMX_AUDIO_CODINGTYPE coding)
+ int SetupAudioRender(cAudioDecoder::eCodec outputFormat, int channels, int samplingRate,
+ cAudioDecoder::ePort audioPort)
{
+ // put audio render onto idle
+ ilclient_flush_tunnels(&m_tun[eClockToAudioRender], 1);
+ ilclient_disable_tunnel(&m_tun[eClockToAudioRender]);
+ ilclient_change_component_state(m_comp[eAudioRender], OMX_StateIdle);
+ ilclient_disable_port_buffers(m_comp[eAudioRender], 100, NULL, NULL, NULL);
+
+ OMX_AUDIO_PARAM_PORTFORMATTYPE format;
+ OMX_INIT_STRUCT(format);
+ format.nPortIndex = 100;
+ if (OMX_GetParameter(ILC_GET_HANDLE(m_comp[eAudioRender]),
+ OMX_IndexParamAudioPortFormat, &format) != OMX_ErrorNone)
+ esyslog("rpihddevice: failed to get audio port format parameters!");
+
+ format.eEncoding =
+ outputFormat == cAudioDecoder::ePCM ? OMX_AUDIO_CodingPCM :
+ outputFormat == cAudioDecoder::eMPG ? OMX_AUDIO_CodingMP3 :
+ outputFormat == cAudioDecoder::eAC3 ? OMX_AUDIO_CodingDDP :
+ outputFormat == cAudioDecoder::eEAC3 ? OMX_AUDIO_CodingDDP :
+ outputFormat == cAudioDecoder::eAAC ? OMX_AUDIO_CodingAAC :
+ outputFormat == cAudioDecoder::eDTS ? OMX_AUDIO_CodingDTS :
+ OMX_AUDIO_CodingAutoDetect;
+
+ if (OMX_SetParameter(ILC_GET_HANDLE(m_comp[eAudioRender]),
+ OMX_IndexParamAudioPortFormat, &format) != OMX_ErrorNone)
+ esyslog("rpihddevice: failed to set audio port format parameters!");
+
+ switch (outputFormat)
+ {
+ case cAudioDecoder::eMPG:
+ OMX_AUDIO_PARAM_MP3TYPE mp3;
+ OMX_INIT_STRUCT(mp3);
+ mp3.nPortIndex = 100;
+ mp3.nChannels = channels;
+ mp3.nSampleRate = samplingRate;
+ mp3.eChannelMode = OMX_AUDIO_ChannelModeStereo; // ?
+ mp3.eFormat = OMX_AUDIO_MP3StreamFormatMP1Layer3; // should be MPEG-1 layer 2
+
+ if (OMX_SetParameter(ILC_GET_HANDLE(m_comp[eAudioRender]),
+ OMX_IndexParamAudioMp3, &mp3) != OMX_ErrorNone)
+ esyslog("rpihddevice: failed to set audio render mp3 parameters!");
+ break;
+
+ case cAudioDecoder::eAC3:
+ case cAudioDecoder::eEAC3:
+ OMX_AUDIO_PARAM_DDPTYPE ddp;
+ OMX_INIT_STRUCT(ddp);
+ ddp.nPortIndex = 100;
+ ddp.nChannels = channels;
+ ddp.nSampleRate = samplingRate;
+ OMX_AUDIO_CHANNEL_MAPPING(ddp, channels);
+
+ if (OMX_SetParameter(ILC_GET_HANDLE(m_comp[eAudioRender]),
+ OMX_IndexParamAudioDdp, &ddp) != OMX_ErrorNone)
+ esyslog("rpihddevice: failed to set audio render ddp parameters!");
+ break;
+
+ case cAudioDecoder::eAAC:
+ OMX_AUDIO_PARAM_AACPROFILETYPE aac;
+ OMX_INIT_STRUCT(aac);
+ aac.nPortIndex = 100;
+ aac.nChannels = channels;
+ aac.nSampleRate = samplingRate;
+ aac.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4LATM;
+
+ 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 cAudioDecoder::eDTS:
+ 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 cAudioDecoder::ePCM:
+ OMX_AUDIO_PARAM_PCMMODETYPE pcm;
+ OMX_INIT_STRUCT(pcm);
+ pcm.nPortIndex = 100;
+ pcm.nChannels = channels == 6 ? 8 : channels;
+ pcm.eNumData = OMX_NumericalDataSigned;
+ pcm.eEndian = OMX_EndianLittle;
+ pcm.bInterleaved = OMX_TRUE;
+ pcm.nBitPerSample = 16;
+ pcm.nSamplingRate = samplingRate;
+ pcm.ePCMMode = OMX_AUDIO_PCMModeLinear;
+ OMX_AUDIO_CHANNEL_MAPPING(pcm, channels);
+
+ if (OMX_SetParameter(ILC_GET_HANDLE(m_comp[eAudioRender]),
+ OMX_IndexParamAudioPcm, &pcm) != OMX_ErrorNone)
+ esyslog("rpihddevice: failed to set audio render pcm parameters!");
+ break;
+
+ default:
+ break;
+ }
+
+ OMX_CONFIG_BRCMAUDIODESTINATIONTYPE audioDest;
+ OMX_INIT_STRUCT(audioDest);
+ strcpy((char *)audioDest.sName,
+ audioPort == cAudioDecoder::eLocal ? "local" : "hdmi");
+
+ if (OMX_SetConfig(ILC_GET_HANDLE(m_comp[eAudioRender]),
+ OMX_IndexConfigBrcmAudioDestination, &audioDest) != OMX_ErrorNone)
+ esyslog("rpihddevice: failed to set audio destination!");
+
if (ilclient_enable_port_buffers(m_comp[eAudioRender], 100, NULL, NULL, NULL) != 0)
esyslog("rpihddevice: failed to enable port buffer on audio render!");
@@ -632,7 +751,7 @@ public:
if (buf != NULL)
{
cOmx::PtsToTicks(pts, buf->nTimeStamp);
- buf->nFlags = m_firstAudioBuffer ? OMX_BUFFERFLAG_STARTTIME : OMX_BUFFERFLAG_TIME_UNKNOWN;
+ buf->nFlags = m_firstAudioBuffer ? OMX_BUFFERFLAG_STARTTIME : 0; //OMX_BUFFERFLAG_TIME_UNKNOWN;
m_firstAudioBuffer = false;
m_freeAudioBuffers--;
}
@@ -653,7 +772,7 @@ public:
if (buf != NULL)
{
cOmx::PtsToTicks(pts, buf->nTimeStamp);
- buf->nFlags = m_firstVideoBuffer ? OMX_BUFFERFLAG_STARTTIME : OMX_BUFFERFLAG_TIME_UNKNOWN;
+ buf->nFlags = m_firstVideoBuffer ? OMX_BUFFERFLAG_STARTTIME : 0; //OMX_BUFFERFLAG_TIME_UNKNOWN;
m_firstVideoBuffer = false;
m_freeVideoBuffers--;
}
@@ -672,7 +791,7 @@ public:
if (!buf)
return false;
- return (OMX_EmptyThisBuffer(ILC_GET_HANDLE(m_comp[eAudioRender]), buf) != OMX_ErrorNone);
+ return (OMX_EmptyThisBuffer(ILC_GET_HANDLE(m_comp[eAudioRender]), buf) == OMX_ErrorNone);
}
bool EmptyVideoBuffer(OMX_BUFFERHEADERTYPE *buf)
@@ -680,12 +799,12 @@ public:
if (!buf)
return false;
- return (OMX_EmptyThisBuffer(ILC_GET_HANDLE(m_comp[eVideoDecoder]), buf) != OMX_ErrorNone);
+ return (OMX_EmptyThisBuffer(ILC_GET_HANDLE(m_comp[eVideoDecoder]), buf) == OMX_ErrorNone);
}
};
/* ------------------------------------------------------------------------- */
-
+#if 0
class cAudio
{
@@ -736,18 +855,19 @@ public:
mpg123_handle *m_handle;
};
-
+#endif
/* ------------------------------------------------------------------------- */
cOmxDevice::cOmxDevice(void (*onPrimaryDevice)(void)) :
cDevice(),
m_onPrimaryDevice(onPrimaryDevice),
m_omx(new cOmx()),
- m_audio(new cAudio()),
+ m_audio(new cAudioDecoder()),
m_mutex(new cMutex()),
m_state(eStop),
m_audioCodecReady(false),
- m_videoCodecReady(false)
+ m_videoCodecReady(false),
+ m_audioId(0)
{
}
@@ -760,12 +880,37 @@ cOmxDevice::~cOmxDevice()
int cOmxDevice::Init(void)
{
- return m_omx->Init();
+ if (m_audio->Init() < 0)
+ {
+ esyslog("rpihddevice: failed to initialize audio!");
+ return -1;
+ }
+ if (m_omx->Init() < 0)
+ {
+ esyslog("rpihddevice: failed to initialize OMX!");
+ return -1;
+ }
+ return 0;
}
int cOmxDevice::DeInit(void)
{
- return m_omx->DeInit();
+ if (m_omx->DeInit() < 0)
+ {
+ esyslog("rpihddevice: failed to deinitialize OMX!");
+ return -1;
+ }
+ if (m_audio->DeInit() < 0)
+ {
+ esyslog("rpihddevice: failed to deinitialize audio!");
+ return -1;
+ }
+ return 0;
+}
+
+void cOmxDevice::GetOsdSize(int &Width, int &Height, double &PixelAspect)
+{
+ cRpiSetup::GetDisplaySize(Width, Height, PixelAspect);
}
bool cOmxDevice::CanReplay(void) const
@@ -837,43 +982,52 @@ int cOmxDevice::PlayAudio(const uchar *Data, int Length, uchar Id)
}
int64_t pts = PesHasPts(Data) ? PesGetPts(Data) : 0;
-
const uchar *payload = Data + PesPayloadOffset(Data);
int length = PesLength(Data) - PesPayloadOffset(Data);
- // try to init codec if PTS is valid
- if (!m_audioCodecReady && pts != 0)
- m_audioCodecReady = OmxSetAudioCodec(payload);
+ if (m_audioId != Id)
+ {
+ m_audioId = Id;
+ m_audioCodecReady = false;
+ }
- if (!m_audioCodecReady)
+ // try to init codec
+ if (!m_audioCodecReady || cRpiSetup::HasAudioSetupChanged())
{
- m_mutex->Unlock();
- return Length;
+ if (m_audio->SetupAudioCodec(Data, Length))
+ {
+ m_audioCodecReady = true;
+ m_omx->SetupAudioRender(
+ m_audio->GetOutputFormat(),
+ m_audio->GetChannels(),
+ m_audio->GetSamplingrate(),
+ m_audio->GetOutputPort());
+ }
+ else
+ {
+ m_mutex->Unlock();
+ return Length;
+ }
}
- if (!m_audio->writeData(payload, length))
+ OMX_BUFFERHEADERTYPE *buf = m_omx->GetAudioBuffer(pts);
+ if (buf == NULL)
{
- esyslog("rpihddevice: failed to pass buffer to audio decoder!");
m_mutex->Unlock();
return 0;
}
- bool done = false;
- while (!done)
- {
- OMX_BUFFERHEADERTYPE *buf = m_omx->GetAudioBuffer(pts);
- if (buf == NULL)
- {
- //esyslog("rpihddevice: failed to get audio buffer!");
- m_mutex->Unlock();
- return 0;
- }
+ // decode and write audio packet
+ buf->nFilledLen = m_audio->DecodeAudio(payload, length, buf->pBuffer, buf->nAllocLen);
- // decode and write audio packet
- buf->nFilledLen = m_audio->readSamples(buf->pBuffer, buf->nAllocLen, done);
+ // if decoding failed, reset audio codec
+ if (!buf->nFilledLen)
+ m_audioCodecReady = false;
- if (m_omx->EmptyAudioBuffer(buf))
- break;
+ if (!m_omx->EmptyAudioBuffer(buf))
+ {
+ m_mutex->Unlock();
+ return 0;
}
m_mutex->Unlock();
@@ -910,7 +1064,15 @@ int cOmxDevice::PlayVideo(const uchar *Data, int Length)
// try to init codec if PTS is valid
if (!m_videoCodecReady && pts != 0)
- m_videoCodecReady = OmxSetVideoCodec(payload);
+ {
+ eVideoCodec codec = GetVideoCodec(Data, Length);
+ if (cRpiSetup::IsVideoCodecSupported(codec))
+ {
+ m_videoCodecReady = (m_omx->SetVideoCodec(codec) == 0);
+ dsyslog("rpihddevice: set video codec to %s!",
+ VideoCodecStr(codec));
+ }
+ }
if (!m_videoCodecReady)
{
@@ -937,7 +1099,7 @@ int cOmxDevice::PlayVideo(const uchar *Data, int Length)
// dsyslog("rpihddevice: PlayVideo(%u.%u, %02x %02x %02x %02x %02x %02x %02x %02x, %d)", buf->nTimeStamp.nHighPart, buf->nTimeStamp.nLowPart,
// buf->pBuffer[0], buf->pBuffer[1], buf->pBuffer[2], buf->pBuffer[3],
// buf->pBuffer[4], buf->pBuffer[5], buf->pBuffer[6], buf->pBuffer[7], buf->nFilledLen);
- if (m_omx->EmptyVideoBuffer(buf))
+ if (!m_omx->EmptyVideoBuffer(buf))
esyslog("rpihddevice: failed to pass buffer to video decoder!");
m_mutex->Unlock();
@@ -953,12 +1115,14 @@ void cOmxDevice::Play(void)
{
dsyslog("rpihddevice: Play()");
m_omx->SetClockScale(1.0f);
+ cDevice::Play();
}
void cOmxDevice::Freeze(void)
{
dsyslog("rpihddevice: Freeze()");
m_omx->SetClockScale(0.0f);
+ cDevice::Freeze();
}
void cOmxDevice::TrickSpeed(int Speed)
@@ -1004,46 +1168,26 @@ void cOmxDevice::MakePrimaryDevice(bool On)
cDevice::MakePrimaryDevice(On);
}
-bool cOmxDevice::OmxSetVideoCodec(const uchar *data)
+cOmxDevice::eVideoCodec cOmxDevice::GetVideoCodec(const uchar *data, int length)
{
- if (data[0] != 0x00 || data[1] != 0x00)
- return false;
+ if (PesLength(data) - PesPayloadOffset(data) < 6)
+ return eUnknown;
- if (data[2] == 0x01 && data[3] == 0xb3)
- {
- dsyslog("rpihddevice: set video codec to MPEG2");
- return (m_omx->SetVideoCodec(OMX_VIDEO_CodingMPEG2) == 0);
- }
-
- else if ((data[2] == 0x01 && data[3] == 0x09 && data[4] == 0x10) ||
- (data[2] == 0x00 && data[3] == 0x01 && data[4] == 0x09 && data[5] == 0x10))
- {
- dsyslog("rpihddevice: set video codec to H264");
- return (m_omx->SetVideoCodec(OMX_VIDEO_CodingAVC) == 0);
- }
+ const uchar *p = data + PesPayloadOffset(data);
- esyslog("rpihddevice: invalid start sequence: %02x %02x %02x %02x %02x %02x %02x %02x",
- data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]);
+ if (p[0] != 0x00 || p[1] != 0x00)
+ return eUnknown;
- return false;
-}
+ if (p[2] == 0x01 && p[3] == 0xb3)
+ return eMPEG2;
-bool cOmxDevice::OmxSetAudioCodec(const uchar *data)
-{
- return (m_omx->SetAudioCodec(OMX_AUDIO_CodingPCM) == 0);
-}
+ else if ((p[2] == 0x01 && p[3] == 0x09 && p[4] == 0x10) ||
+ (p[2] == 0x00 && p[3] == 0x01 && p[4] == 0x09 && p[5] == 0x10))
+ return eH264;
-void cOmxDevice::GetDisplaySize(int &width, int &height, double &aspect)
-{
- uint32_t screenWidth;
- uint32_t screenHeight;
+ //esyslog("rpihddevice: invalid start sequence: "
+ // "%02x %02x %02x %02x %02x %02x %02x %02x",
+ // p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
- if (graphics_get_display_size(0 /* LCD */, &screenWidth, &screenHeight) < 0)
- esyslog("rpihddevice: failed to get display size!");
- else
- {
- width = (int)screenWidth;
- height = (int)screenHeight;
- aspect = 1;
- }
+ return eUnknown;
}
diff --git a/omxdevice.h b/omxdevice.h
index ea3628a..affe2a9 100644
--- a/omxdevice.h
+++ b/omxdevice.h
@@ -11,7 +11,7 @@
#include <vdr/thread.h>
class cOmx;
-class cAudio;
+class cAudioDecoder;
class cOmxDevice : cDevice
{
@@ -24,12 +24,26 @@ public:
ePlay
};
+ enum eVideoCodec {
+ eMPEG2,
+ eH264,
+ eUnknown
+ };
+
+ static const char* VideoCodecStr(eVideoCodec codec)
+ {
+ return (codec == eMPEG2) ? "MPEG2" :
+ (codec == eH264) ? "H264" : "unknown";
+ }
+
cOmxDevice(void (*onPrimaryDevice)(void));
virtual ~cOmxDevice();
virtual int Init(void);
virtual int DeInit(void);
+ virtual void GetOsdSize(int &Width, int &Height, double &PixelAspect);
+
virtual bool HasDecoder(void) const { return true; };
virtual bool SetPlayMode(ePlayMode PlayMode);
@@ -52,11 +66,6 @@ public:
virtual bool Poll(cPoller &Poller, int TimeoutMs = 0);
- virtual void GetOsdSize(int &Width, int &Height, double &PixelAspect)
- { cOmxDevice::GetDisplaySize(Width, Height, PixelAspect); }
-
- static void GetDisplaySize(int &width, int &height, double &aspect);
-
protected:
virtual void MakePrimaryDevice(bool On);
@@ -65,17 +74,18 @@ private:
void (*m_onPrimaryDevice)(void);
- virtual bool OmxSetVideoCodec(const uchar *data);
- virtual bool OmxSetAudioCodec(const uchar *data);
+ virtual eVideoCodec GetVideoCodec(const uchar *data, int length);
- cOmx *m_omx;
- cAudio *m_audio;
- cMutex *m_mutex;
+ cOmx *m_omx;
+ cAudioDecoder *m_audio;
+ cMutex *m_mutex;
eState m_state;
bool m_audioCodecReady;
bool m_videoCodecReady;
+
+ uchar m_audioId;
};
#endif
diff --git a/ovgosd.c b/ovgosd.c
index 773513c..4513a98 100644
--- a/ovgosd.c
+++ b/ovgosd.c
@@ -11,6 +11,7 @@
#include "ovgosd.h"
#include "omxdevice.h"
+#include "setup.h"
class cOvg : public cThread
{
@@ -32,7 +33,7 @@ public:
m_h(0),
m_clear(false)
{
- cOmxDevice::GetDisplaySize(m_width, m_height, m_aspect);
+ cRpiSetup::GetDisplaySize(m_width, m_height, m_aspect);
m_do = new cCondWait();
m_done = new cCondWait();
@@ -128,6 +129,7 @@ protected:
dispmanUpdate, dispmanDisplay, 2 /*layer*/, &dstRect, 0, &srcRect,
DISPMANX_PROTECTION_NONE, 0, 0, (DISPMANX_TRANSFORM_T)0);
+#if 0
// create black layer in front of console
uint32_t pBgImage;
uint16_t bgImage = 0x0000; // black
@@ -138,7 +140,7 @@ protected:
vc_dispmanx_rect_set(&dstRect, 0, 0, 1 << 16, 1 << 16);
vc_dispmanx_element_add(dispmanUpdate, dispmanDisplay, -1 /*layer*/, &srcRect,
bgRsc, &dstRect, DISPMANX_PROTECTION_NONE, 0, 0, (DISPMANX_TRANSFORM_T)0);
-
+#endif
vc_dispmanx_update_submit_sync(dispmanUpdate);
EGL_DISPMANX_WINDOW_T nativewindow;
diff --git a/po/de_DE.po b/po/de_DE.po
new file mode 100644
index 0000000..7d6bc20
--- /dev/null
+++ b/po/de_DE.po
@@ -0,0 +1,30 @@
+# German translations for vdr-rpihddevice package.
+# Copyright (C) 2013 THE vdr-rpihddevice'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the vdr-rpihddevice package.
+# <thomas@reufer.ch>, 2013.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: vdr-rpihddevice 0.0.4\n"
+"Report-Msgid-Bugs-To: <see README>\n"
+"POT-Creation-Date: 2013-10-14 13:33+0200\n"
+"PO-Revision-Date: 2013-10-14 13:36+0200\n"
+"Last-Translator: <thomas@reufer.ch>\n"
+"Language-Team: German <translation-team-de@lists.sourceforge.net>\n"
+"Language: de\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ASCII\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+msgid "analog"
+msgstr "analog"
+
+msgid "HDMI"
+msgstr "HDMI"
+
+msgid "Audio Port"
+msgstr "Audioanschluss"
+
+msgid "Digital Audio Pass-Through"
+msgstr "Digitalton durchreichen"
diff --git a/rpihddevice.c b/rpihddevice.c
index 9ca329a..fb90c11 100644
--- a/rpihddevice.c
+++ b/rpihddevice.c
@@ -9,10 +9,9 @@
#include "ovgosd.h"
#include "omxdevice.h"
+#include "setup.h"
-#include "bcm_host.h"
-
-static const char *VERSION = "0.0.3";
+static const char *VERSION = "0.0.4";
static const char *DESCRIPTION = "HD output device for Raspberry Pi";
class cDummyDevice : cDevice
@@ -29,7 +28,8 @@ public:
virtual bool Poll(cPoller &Poller, int TimeoutMs = 0) { return true; }
virtual bool Flush(int TimeoutMs = 0) { return true; }
virtual void GetOsdSize(int &Width, int &Height, double &PixelAspect)
- { cOmxDevice::GetDisplaySize(Width, Height, PixelAspect); }
+ { cRpiSetup::GetDisplaySize(Width, Height, PixelAspect); }
+
bool Start(void) {return true;}
protected:
@@ -43,7 +43,7 @@ private:
cOmxDevice *m_device;
- static void OnPrimaryDevice() { new cRpiOsdProvider(); }
+ static void OnPrimaryDevice(void) { new cRpiOsdProvider(); }
public:
cPluginRpiHdDevice(void);
@@ -58,30 +58,36 @@ public:
virtual void Housekeeping(void) {}
virtual const char *MainMenuEntry(void) { return NULL; }
virtual cOsdObject *MainMenuAction(void) { return NULL; }
- virtual cMenuSetupPage *SetupMenu(void) { return NULL; }
- virtual bool SetupParse(const char *Name, const char *Value) { return false; };
+ virtual cMenuSetupPage *SetupMenu(void);
+ virtual bool SetupParse(const char *Name, const char *Value);
};
cPluginRpiHdDevice::cPluginRpiHdDevice(void) :
m_device(0)
{
- m_device = new cOmxDevice(&cPluginRpiHdDevice::OnPrimaryDevice);
//new cDummyDevice();
}
cPluginRpiHdDevice::~cPluginRpiHdDevice()
{
delete m_device;
+ cRpiSetup::DropInstance();
}
bool cPluginRpiHdDevice::Initialize(void)
{
- bcm_host_init();
+ if (!cRpiSetup::HwInit())
+ return false;
+
+ if (!cRpiSetup::IsVideoCodecSupported(cOmxDevice::eMPEG2))
+ esyslog("rpihddevice: WARNING: MPEG2 video decoder not enabled!");
+
+ m_device = new cOmxDevice(&OnPrimaryDevice);
if (m_device)
return (m_device->Init() == 0);
- return true;
+ return false;
}
bool cPluginRpiHdDevice::Start(void)
@@ -95,4 +101,14 @@ void cPluginRpiHdDevice::Stop(void)
m_device->DeInit();
}
+cMenuSetupPage* cPluginRpiHdDevice::SetupMenu(void)
+{
+ return cRpiSetup::GetInstance()->GetSetupPage();
+}
+
+bool cPluginRpiHdDevice::SetupParse(const char *Name, const char *Value)
+{
+ return cRpiSetup::GetInstance()->Parse(Name, Value);
+}
+
VDRPLUGINCREATOR(cPluginRpiHdDevice); // Don't touch this!
diff --git a/setup.c b/setup.c
new file mode 100644
index 0000000..7ce7d71
--- /dev/null
+++ b/setup.c
@@ -0,0 +1,170 @@
+/*
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id$
+ */
+
+#include "setup.h"
+
+#include <vdr/tools.h>
+#include <vdr/menuitems.h>
+
+#include <bcm_host.h>
+#include "interface/vchiq_arm/vchiq_if.h"
+#include "interface/vmcs_host/vc_tvservice.h"
+
+cRpiSetup* cRpiSetup::s_instance = 0;
+
+cRpiSetup* cRpiSetup::GetInstance(void)
+{
+ if (!s_instance)
+ s_instance = new cRpiSetup();
+
+ return s_instance;
+}
+
+void cRpiSetup::DropInstance(void)
+{
+ delete s_instance;
+ s_instance = 0;
+}
+
+class cRpiSetupPage : public cMenuSetupPage
+{
+
+public:
+
+ cRpiSetupPage(int *audioPort, int *passthrough, bool *audioSetupChanged) :
+ m_audioPort(audioPort),
+ m_passthrough(passthrough),
+ m_audioSetupChanged(audioSetupChanged)
+ {
+ static const char *const audioport[] = { tr("analog"), tr("HDMI") };
+
+ m_newAudioPort = *m_audioPort;
+ m_newPassthrough = *m_passthrough;
+
+ Add(new cMenuEditStraItem(tr("Audio Port"), &m_newAudioPort, 2, audioport));
+ Add(new cMenuEditBoolItem(tr("Digital Audio Pass-Through"), &m_newPassthrough));
+ }
+
+protected:
+
+ virtual void Store(void)
+ {
+ *m_audioSetupChanged =
+ (*m_audioPort != m_newAudioPort) ||
+ (*m_passthrough != m_newPassthrough);
+
+ SetupStore("AudioPort", *m_audioPort = m_newAudioPort);
+ SetupStore("PassThrough", *m_passthrough = m_newPassthrough);
+ }
+
+private:
+
+ int m_newAudioPort;
+ int m_newPassthrough;
+
+ int *m_audioPort;
+ int *m_passthrough;
+
+ bool *m_audioSetupChanged;
+
+};
+
+bool cRpiSetup::HwInit(void)
+{
+ bcm_host_init();
+ vcos_init();
+
+ VCHI_INSTANCE_T vchiInstance;
+ VCHI_CONNECTION_T *vchiConnections;
+ if (vchi_initialise(&vchiInstance) != VCHIQ_SUCCESS)
+ {
+ esyslog("rpihddevice: failed to open vchiq instance!");
+ return false;
+ }
+ if (vchi_connect(NULL, 0, vchiInstance) != 0)
+ {
+ esyslog("rpihddevice: failed to connect to vchi!");
+ return false;
+ }
+ if (vc_vchi_tv_init(vchiInstance, &vchiConnections, 1) != 0)
+ {
+ esyslog("rpihddevice: failed to connect to tvservice!");
+ return false;
+ }
+
+ if (!vc_gencmd_send("codec_enabled MPG2"))
+ {
+ char buffer[1024];
+ if (!vc_gencmd_read_response(buffer, sizeof(buffer)))
+ {
+ if (!strcasecmp(buffer,"MPG2=enabled"))
+ GetInstance()->m_mpeg2Enabled = true;
+ }
+ }
+
+ return true;
+}
+
+bool cRpiSetup::IsAudioFormatSupported(cAudioDecoder::eCodec codec, int channels, int samplingRate)
+{
+ if (vc_tv_hdmi_audio_supported(
+ codec == cAudioDecoder::eMPG ? EDID_AudioFormat_eMPEG1 :
+ codec == cAudioDecoder::eAC3 ? EDID_AudioFormat_eAC3 :
+ codec == cAudioDecoder::eEAC3 ? EDID_AudioFormat_eEAC3 :
+ codec == cAudioDecoder::eAAC ? EDID_AudioFormat_eAAC :
+ codec == cAudioDecoder::eDTS ? EDID_AudioFormat_eDTS :
+ EDID_AudioFormat_ePCM, channels,
+ samplingRate == 32000 ? EDID_AudioSampleRate_e32KHz :
+ samplingRate == 44000 ? EDID_AudioSampleRate_e44KHz :
+ samplingRate == 88000 ? EDID_AudioSampleRate_e88KHz :
+ samplingRate == 96000 ? EDID_AudioSampleRate_e96KHz :
+ samplingRate == 176000 ? EDID_AudioSampleRate_e176KHz :
+ samplingRate == 192000 ? EDID_AudioSampleRate_e192KHz :
+ EDID_AudioSampleRate_e48KHz, EDID_AudioSampleSize_16bit) == 0)
+ return true;
+
+ return false;
+}
+
+int cRpiSetup::GetDisplaySize(int &width, int &height, double &aspect)
+{
+ uint32_t screenWidth;
+ uint32_t screenHeight;
+
+ if (graphics_get_display_size(0 /* LCD */, &screenWidth, &screenHeight) < 0)
+ esyslog("rpihddevice: failed to get display size!");
+ else
+ {
+ width = (int)screenWidth;
+ height = (int)screenHeight;
+ aspect = 1;
+ return 0;
+ }
+ return -1;
+}
+
+bool cRpiSetup::HasAudioSetupChanged(void)
+{
+ if (!GetInstance()->m_audioSetupChanged)
+ return false;
+
+ GetInstance()->m_audioSetupChanged = false;
+ return true;
+}
+
+cMenuSetupPage* cRpiSetup::GetSetupPage(void)
+{
+ return new cRpiSetupPage(&m_audioPort, &m_passthrough, &m_audioSetupChanged);
+}
+
+bool cRpiSetup::Parse(const char *name, const char *value)
+{
+ if (!strcasecmp(name, "AudioPort")) m_audioPort = atoi(value);
+ else if (!strcasecmp(name, "PassThrough")) m_passthrough = atoi(value);
+ else return false;
+
+ return true;
+}
diff --git a/setup.h b/setup.h
new file mode 100644
index 0000000..39735eb
--- /dev/null
+++ b/setup.h
@@ -0,0 +1,57 @@
+/*
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id$
+ */
+
+#ifndef SETUP_H
+#define SETUP_H
+
+#include "audio.h"
+#include "omxdevice.h"
+
+class cMenuSetupPage;
+
+class cRpiSetup
+{
+
+public:
+
+ static bool HwInit(void);
+
+ static cAudioDecoder::ePort GetAudioPort(void) {
+ return (GetInstance()->m_audioPort) ? cAudioDecoder::eHDMI : cAudioDecoder::eLocal; }
+ static bool IsAudioPassthrough(void) { return GetInstance()->m_passthrough; }
+ static bool HasAudioSetupChanged(void);
+
+ static bool IsAudioFormatSupported(cAudioDecoder::eCodec codec, int channels, int samplingRate);
+
+ static bool IsVideoCodecSupported(cOmxDevice::eVideoCodec codec) {
+ return codec == cOmxDevice::eMPEG2 ? GetInstance()->m_mpeg2Enabled :
+ codec == cOmxDevice::eH264 ? true : false;
+ }
+
+ static int GetDisplaySize(int &width, int &height, double &aspect);
+
+ static cRpiSetup* GetInstance(void);
+ static void DropInstance(void);
+
+ cMenuSetupPage* GetSetupPage(void);
+ bool Parse(const char *name, const char *value);
+
+private:
+
+ cRpiSetup() : m_audioSetupChanged(false), m_mpeg2Enabled(false) { }
+ virtual ~cRpiSetup() { }
+
+ static cRpiSetup* s_instance;
+
+ int m_audioPort;
+ int m_passthrough;
+
+ bool m_audioSetupChanged;
+
+ bool m_mpeg2Enabled;
+};
+
+#endif