summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Reufer <thomas@reufer.ch>2014-02-10 21:53:25 +0100
committerThomas Reufer <thomas@reufer.ch>2014-02-10 21:53:25 +0100
commit0094472cda6eefa9b5363ad844daf0fcfd00c326 (patch)
treeb577f931820ef3899da856f9ccd0de04f4c8ffa8
parent88f137d194b1768344e954a1b1d35fb1fce03df9 (diff)
downloadvdr-plugin-rpihddevice-0.0.8.tar.gz
vdr-plugin-rpihddevice-0.0.8.tar.bz2
2014-02-10: Version 0.0.80.0.8
------------------------- - new: - image grabbing - implemented proper handling in case of buffer stall - reporting video size - support letter box and center cut out set by VDR - support video scaling - fixed: - increased number of audio buffer to fix replay issues with PES recordings - return correct number of audio bytes written from PlayAudio() - fixed start up in audio only mode - fixed still image with deinterlacer - fixed crash during deinitialization - fixed crash when copying 5.1 PCM audio - use cThread::mutex for locking - implement cOvgOsd::SetAreas() and cOvgOsd::SetActive() - audio codec clean up, drop AAC-LATM and rename ADTS to AAC - audio decoding thread clean up - known issues - StillImage() will cause buffer stall - artifacts with StillImage() and PES recordings - speed to fast when fast replaying audio only recordings
-rw-r--r--.project79
-rw-r--r--HISTORY24
-rw-r--r--Makefile9
-rw-r--r--audio.c407
-rw-r--r--audio.h9
-rw-r--r--display.c106
-rw-r--r--display.h32
-rw-r--r--omx.c386
-rw-r--r--omx.h26
-rw-r--r--omxdevice.c192
-rw-r--r--omxdevice.h20
-rw-r--r--ovgosd.c137
-rw-r--r--ovgosd.h17
-rw-r--r--po/de_DE.po5
-rw-r--r--rpihddevice.c10
-rw-r--r--setup.c105
-rw-r--r--setup.h18
-rw-r--r--tools.h90
18 files changed, 1113 insertions, 559 deletions
diff --git a/.project b/.project
new file mode 100644
index 0000000..b385bd0
--- /dev/null
+++ b/.project
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>rpihddevice</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
+ <triggers>clean,full,incremental,</triggers>
+ <arguments>
+ <dictionary>
+ <key>?name?</key>
+ <value></value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.append_environment</key>
+ <value>true</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.autoBuildTarget</key>
+ <value>all</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.buildArguments</key>
+ <value></value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.buildCommand</key>
+ <value>make</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.cleanBuildTarget</key>
+ <value>clean</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.contents</key>
+ <value>org.eclipse.cdt.make.core.activeConfigSettings</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.enableAutoBuild</key>
+ <value>false</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.enableCleanBuild</key>
+ <value>true</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.enableFullBuild</key>
+ <value>true</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.fullBuildTarget</key>
+ <value>all</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.stopOnError</key>
+ <value>true</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.useDefaultBuildCmd</key>
+ <value>true</value>
+ </dictionary>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
+ <triggers>full,incremental,</triggers>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.cdt.core.cnature</nature>
+ <nature>org.eclipse.cdt.core.ccnature</nature>
+ <nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
+ <nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
+ </natures>
+</projectDescription>
diff --git a/HISTORY b/HISTORY
index 3daa975..266c231 100644
--- a/HISTORY
+++ b/HISTORY
@@ -1,6 +1,30 @@
VDR Plugin 'rpihddevice' Revision History
-----------------------------------------
+2014-02-10: Version 0.0.8
+-------------------------
+- new:
+ - image grabbing
+ - implemented proper handling in case of buffer stall
+ - reporting video size
+ - support letter box and center cut out set by VDR
+ - support video scaling
+- fixed:
+ - increased number of audio buffer to fix replay issues with PES recordings
+ - return correct number of audio bytes written from PlayAudio()
+ - fixed start up in audio only mode
+ - fixed still image with deinterlacer
+ - fixed crash during deinitialization
+ - fixed crash when copying 5.1 PCM audio
+ - use cThread::mutex for locking
+ - implement cOvgOsd::SetAreas() and cOvgOsd::SetActive()
+ - audio codec clean up, drop AAC-LATM and rename ADTS to AAC
+ - audio decoding thread clean up
+- known issues
+ - StillImage() will cause buffer stall
+ - artifacts with StillImage() and PES recordings
+ - speed to fast when fast replaying audio only recordings
+
2013-12-30: Version 0.0.7
-------------------------
- new:
diff --git a/Makefile b/Makefile
index 58af8bd..3012449 100644
--- a/Makefile
+++ b/Makefile
@@ -16,7 +16,7 @@ VERSION = $(shell grep 'static const char \*VERSION *=' $(PLUGIN).c | awk '{ pri
### The directory environment:
# Use package data if installed...otherwise assume we're under the VDR source directory:
-PKGCFG = $(if $(VDRDIR),$(shell pkg-config --variable=$(1) $(VDRDIR)/vdr.pc),$(shell pkg-config --variable=$(1) vdr || pkg-config --variable=$(1) ../../../vdr.pc))
+PKGCFG = $(if $(VDRDIR),$(shell pkg-config --variable=$(1) $(VDRDIR)/vdr.pc),$(shell PKG_CONFIG_PATH="$$PKG_CONFIG_PATH:../../.." pkg-config --variable=$(1) vdr))
LIBDIR = $(call PKGCFG,libdir)
LOCDIR = $(call PKGCFG,locdir)
PLGCFG = $(call PKGCFG,plgcfg)
@@ -62,10 +62,15 @@ INCLUDES += -I$(ILCDIR) -I$(VCINCDIR) -I$(VCINCDIR)/interface/vcos/pthreads -I$(
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
+DEBUG ?= 0
+ifeq ($(DEBUG), 1)
+ DEFINES += -DDEBUG
+endif
+
### The object files (add further files here):
ILCLIENT = $(ILCDIR)/libilclient.a
-OBJS = $(PLUGIN).o setup.o omx.o audio.o omxdevice.o ovgosd.o
+OBJS = $(PLUGIN).o setup.o omx.o audio.o omxdevice.o ovgosd.o display.o
### The main target:
diff --git a/audio.c b/audio.c
index 33ba917..b629db9 100644
--- a/audio.c
+++ b/audio.c
@@ -20,8 +20,15 @@ class cAudioParser
public:
- cAudioParser() { }
- ~cAudioParser() { }
+ cAudioParser()
+ {
+ m_mutex = new cMutex();
+ }
+
+ ~cAudioParser()
+ {
+ delete m_mutex;
+ }
AVPacket* Packet(void)
{
@@ -85,19 +92,26 @@ public:
bool Append(const unsigned char *data, unsigned int length)
{
- if (m_size + length + FF_INPUT_BUFFER_PADDING_SIZE > AVPKT_BUFFER_SIZE)
- return false;
-
- memcpy(m_packet.data + m_size, data, length);
- m_size += length;
- memset(m_packet.data + m_size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
+ m_mutex->Lock();
+ bool ret = true;
- m_parsed = false;
- return true;
+ if (m_size + length + FF_INPUT_BUFFER_PADDING_SIZE > AVPKT_BUFFER_SIZE)
+ ret = false;
+ else
+ {
+ memcpy(m_packet.data + m_size, data, length);
+ m_size += length;
+ memset(m_packet.data + m_size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
+ m_parsed = false;
+ }
+ m_mutex->Unlock();
+ return ret;
}
void Shrink(unsigned int length)
{
+ m_mutex->Lock();
+
if (length < m_size)
{
memmove(m_packet.data, m_packet.data + length, m_size - length);
@@ -108,6 +122,8 @@ public:
}
else
Reset();
+
+ m_mutex->Unlock();
}
private:
@@ -126,6 +142,7 @@ private:
void Parse()
{
+ m_mutex->Lock();
cAudioCodec::eCodec codec = cAudioCodec::eInvalid;
int channels = 0;
int offset = 0;
@@ -159,15 +176,9 @@ private:
codec = cAudioCodec::eEAC3;
}
break;
-
case cAudioCodec::eAAC:
- if (LatmCheck(p, n, frameSize, channels, samplingRate))
- codec = cAudioCodec::eAAC;
- break;
-
- case cAudioCodec::eADTS:
if (AdtsCheck(p, n, frameSize, channels, samplingRate))
- codec = cAudioCodec::eADTS;
+ codec = cAudioCodec::eAAC;
break;
default:
@@ -196,7 +207,7 @@ private:
if (offset)
{
- dsyslog("rpihddevice: audio parser skipped %d of %d bytes", offset, m_size);
+ DLOG("audio parser skipped %d of %d bytes", offset, m_size);
Shrink(offset);
}
@@ -209,8 +220,10 @@ private:
}
m_parsed = true;
+ m_mutex->Unlock();
}
+ cMutex* m_mutex;
AVPacket m_packet;
cAudioCodec::eCodec m_codec;
unsigned int m_channels;
@@ -232,8 +245,7 @@ private:
{
return FastMpegCheck(p) ? cAudioCodec::eMPG :
FastAc3Check (p) ? cAudioCodec::eAC3 :
- FastLatmCheck(p) ? cAudioCodec::eAAC :
- FastAdtsCheck(p) ? cAudioCodec::eADTS :
+ FastAdtsCheck(p) ? cAudioCodec::eAAC :
cAudioCodec::eInvalid;
}
@@ -600,7 +612,6 @@ cAudioDecoder::cAudioDecoder(cOmx *omx) :
m_reset(false),
m_ready(false),
m_pts(0),
- m_mutex(new cMutex()),
m_wait(new cCondWait()),
m_parser(new cAudioParser()),
m_omx(omx)
@@ -611,7 +622,6 @@ cAudioDecoder::~cAudioDecoder()
{
delete m_parser;
delete m_wait;
- delete m_mutex;
}
int cAudioDecoder::Init(void)
@@ -626,8 +636,7 @@ int cAudioDecoder::Init(void)
m_codecs[cAudioCodec::eMPG ].codec = avcodec_find_decoder(CODEC_ID_MP3);
m_codecs[cAudioCodec::eAC3 ].codec = avcodec_find_decoder(CODEC_ID_AC3);
m_codecs[cAudioCodec::eEAC3].codec = avcodec_find_decoder(CODEC_ID_EAC3);
- m_codecs[cAudioCodec::eAAC ].codec = avcodec_find_decoder(CODEC_ID_AAC_LATM);
- m_codecs[cAudioCodec::eADTS].codec = avcodec_find_decoder(CODEC_ID_AAC);
+ m_codecs[cAudioCodec::eAAC].codec = avcodec_find_decoder(CODEC_ID_AAC);
for (int i = 0; i < cAudioCodec::eNumCodecs; i++)
{
@@ -637,13 +646,13 @@ int cAudioDecoder::Init(void)
m_codecs[codec].context = avcodec_alloc_context3(m_codecs[codec].codec);
if (!m_codecs[codec].context)
{
- esyslog("rpihddevice: failed to allocate %s context!", cAudioCodec::Str(codec));
+ ELOG("failed to allocate %s context!", cAudioCodec::Str(codec));
ret = -1;
break;
}
if (avcodec_open2(m_codecs[codec].context, m_codecs[codec].codec, NULL) < 0)
{
- esyslog("rpihddevice: failed to open %s decoder!", cAudioCodec::Str(codec));
+ ELOG("failed to open %s decoder!", cAudioCodec::Str(codec));
ret = -1;
break;
}
@@ -660,266 +669,254 @@ int cAudioDecoder::Init(void)
int cAudioDecoder::DeInit(void)
{
- Cancel();
+ Lock();
+
+ Reset();
+ Cancel(-1);
+ m_wait->Signal();
+
+ while (Active())
+ cCondWait::SleepMs(50);
for (int i = 0; i < cAudioCodec::eNumCodecs; i++)
{
cAudioCodec::eCodec codec = static_cast<cAudioCodec::eCodec>(i);
- avcodec_close(m_codecs[codec].context);
- av_free(m_codecs[codec].context);
+ if (m_codecs[codec].codec)
+ {
+ avcodec_close(m_codecs[codec].context);
+ av_free(m_codecs[codec].context);
+ }
}
m_parser->DeInit();
+
+ Unlock();
return 0;
}
-int cAudioDecoder::WriteData(const unsigned char *buf, unsigned int length, uint64_t pts)
+bool cAudioDecoder::WriteData(const unsigned char *buf, unsigned int length, uint64_t pts)
{
- int ret = 0;
+ Lock();
+ bool ret = false;
+
if (m_ready)
{
- m_mutex->Lock();
if (m_parser->Append(buf, length))
{
m_pts = pts;
m_ready = false;
m_wait->Signal();
- ret = length;
+ ret = true;
}
- m_mutex->Unlock();
}
+ Unlock();
return ret;
}
void cAudioDecoder::Reset(void)
{
- m_mutex->Lock();
+ Lock();
+
m_reset = true;
m_wait->Signal();
- m_mutex->Unlock();
+ while (m_reset)
+ cCondWait::SleepMs(1);
+
+ Unlock();
}
bool cAudioDecoder::Poll(void)
{
- return m_ready && m_omx->PollAudioBuffers();
+ return m_ready;
}
void cAudioDecoder::Action(void)
{
- dsyslog("rpihddevice: cAudioDecoder() thread started");
+ DLOG("cAudioDecoder() thread started");
- while (Running())
- {
- unsigned int channels = 0;
- unsigned int outputChannels = 0;
- unsigned int samplingRate = 0;
+ unsigned int channels = 0;
+ unsigned int outputChannels = 0;
+ unsigned int samplingRate = 0;
+ bool setupChanged = true;
- bool bufferFull = false;
- bool setupChanged = false;
+ cAudioCodec::eCodec codec = cAudioCodec::eInvalid;
+ OMX_BUFFERHEADERTYPE *buf = 0;
- cAudioCodec::eCodec codec = cAudioCodec::eInvalid;
- OMX_BUFFERHEADERTYPE *buf = 0;
+ AVFrame *frame = avcodec_alloc_frame();
+ if (!frame)
+ {
+ ELOG("failed to allocate audio frame!");
+ return;
+ }
- AVFrame *frame = avcodec_alloc_frame();
- if (!frame)
- {
- esyslog("rpihddevice: failed to allocate audio frame!");
- return;
- }
+ m_ready = true;
- m_reset = false;
- m_ready = true;
+ while (Running())
+ {
+ setupChanged |= cRpiSetup::HasAudioSetupChanged();
- while (!m_reset)
+ // test for codec change if there is data in parser and no left over
+ if (!m_parser->Empty() && !frame->nb_samples)
+ setupChanged |= codec != m_parser->GetCodec() ||
+ channels != m_parser->GetChannels() ||
+ samplingRate != m_parser->GetSamplingRate();
+
+ // if necessary, set up audio codec
+ if (setupChanged)
{
- setupChanged |= cRpiSetup::HasAudioSetupChanged();
+ codec = m_parser->GetCodec();
+ channels = m_parser->GetChannels();
+ samplingRate = m_parser->GetSamplingRate();
- // check for data if no decoded samples are pending
- if (!m_parser->Empty() && !frame->nb_samples)
- {
- 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)
- bufferFull = true;
- else
- {
- codec = m_parser->GetCodec();
- channels = m_parser->GetChannels();
- samplingRate = m_parser->GetSamplingRate();
+ outputChannels = channels;
+ SetCodec(codec, outputChannels, samplingRate);
- outputChannels = channels;
- SetCodec(codec, outputChannels, samplingRate);
+ avcodec_get_frame_defaults(frame);
+ setupChanged = false;
- setupChanged = false;
- }
- }
- }
+ if (codec == cAudioCodec::eInvalid)
+ m_reset = true;
+ }
- // if codec has been configured but we don't have a buffer, get one
- while (codec != cAudioCodec::eInvalid && !buf && !m_reset)
+ // get free buffer
+ while ((!m_parser->Empty() || frame->nb_samples) && !buf && !m_reset)
+ {
+ buf = m_omx->GetAudioBuffer(m_pts);
+ if (!buf)
+ m_wait->Wait(10);
+ else
{
- buf = m_omx->GetAudioBuffer(m_pts);
- if (buf)
- m_pts = 0;
- else
- m_wait->Wait(10);
+ m_pts = 0;
+ buf->nFilledLen = 0;
}
+ }
- // we have a non-full buffer and data to encode / copy
- if (buf && !bufferFull && !m_parser->Empty())
+ // decoding loop
+ while ((!m_parser->Empty() || frame->nb_samples) && buf && !m_reset)
+ {
+ if (setupChanged |= (codec != m_parser->GetCodec() ||
+ channels != m_parser->GetChannels() ||
+ samplingRate != m_parser->GetSamplingRate()))
+ break;
+
+ // -- decode frame --
+ if (!frame->nb_samples && !m_passthrough)
{
- int copied = 0;
- if (m_passthrough)
+ // if frame has been emptied, decode new data, rise reset
+ // flag if something goes wrong
+ int gotFrame = 0;
+ int len = avcodec_decode_audio4(m_codecs[codec].context,
+ frame, &gotFrame, m_parser->Packet());
+ if (len > 0)
+ m_parser->Shrink(len);
+
+ if (len < 0)
{
- // for pass-through directly copy AV packet to buffer
- if (m_parser->Packet()->size <= buf->nAllocLen - buf->nFilledLen)
- {
- m_mutex->Lock();
-
- memcpy(buf->pBuffer + buf->nFilledLen,
- m_parser->Packet()->data, m_parser->Packet()->size);
- buf->nFilledLen += m_parser->Packet()->size;
- m_parser->Shrink(m_parser->Packet()->size);
-
- m_mutex->Unlock();
- }
- else
- if (m_parser->Packet()->size > buf->nAllocLen)
- {
- esyslog("rpihddevice: encoded audio frame too big!");
- m_reset = true;
- break;
- }
- else
- bufferFull = true;
+ ELOG("failed to decode audio frame!");
+ m_reset = true;
+ break;
}
- else
- {
- // decode frame if we do not pass-through
- m_mutex->Lock();
-
- int gotFrame = 0;
- int len = avcodec_decode_audio4(m_codecs[codec].context,
- frame, &gotFrame, m_parser->Packet());
-
- if (len > 0)
- m_parser->Shrink(len);
+ }
- m_mutex->Unlock();
+ // -- get length --
+ int len = m_passthrough ? m_parser->Packet()->size :
+ av_samples_get_buffer_size(NULL,
+ outputChannels == 6 ? 8 : outputChannels, frame->nb_samples,
+ m_codecs[codec].context->sample_fmt, 1);
- if (len < 0)
- {
- esyslog("rpihddevice: failed to decode audio frame!");
- m_reset = true;
- break;
- }
- }
+ if (len > (signed)(buf->nAllocLen - buf->nFilledLen) || len < 0)
+ {
+ // rise reset flag if packet is even bigger than allocated buffer
+ m_reset = len > (signed)(buf->nAllocLen) || len < 0;
+ if (m_reset)
+ ELOG("encoded audio frame too big!");
+ break;
}
- // we have decoded samples we need to copy to buffer
- if (buf && !bufferFull && frame->nb_samples > 0)
+ // -- copy frame --
+ if (m_passthrough)
{
- int length = av_samples_get_buffer_size(NULL,
- outputChannels == 6 ? 8 : outputChannels, frame->nb_samples,
- m_codecs[codec].context->sample_fmt, 1);
+ // for pass-through directly copy AV packet to buffer
+ memcpy(buf->pBuffer + buf->nFilledLen,
+ m_parser->Packet()->data, len);
- if (length <= buf->nAllocLen - buf->nFilledLen)
+ buf->nFilledLen += len;
+ m_parser->Shrink(len);
+ }
+ else if (frame->nb_samples)
+ {
+ if (outputChannels == 6)
{
- if (outputChannels == 6)
- {
- // interleaved copy to fit 5.1 data into 8 channels
- int32_t* src = (int32_t*)frame->data[0];
- int32_t* dst = (int32_t*)buf->pBuffer + buf->nFilledLen;
-
- for (int i = 0; i < frame->nb_samples; i++)
- {
- *dst++ = *src++; // LF & RF
- *dst++ = *src++; // CF & LFE
- *dst++ = *src++; // LR & RR
- *dst++ = 0; // empty channels
- }
- }
- else
- memcpy(buf->pBuffer + buf->nFilledLen, frame->data[0], length);
+ int32_t* src = (int32_t*)frame->data[0];
+ int32_t* dst = (int32_t*)(buf->pBuffer + buf->nFilledLen);
- buf->nFilledLen += length;
- frame->nb_samples = 0;
- }
- else
- {
- if (length > buf->nAllocLen)
+ // interleaved copy to fit 5.1 data into 8 channels
+ for (int i = 0; i < frame->nb_samples; i++)
{
- esyslog("rpihddevice: decoded audio frame too big!");
- m_reset = true;
- break;
+ *dst++ = *src++; // LF & RF
+ *dst++ = *src++; // CF & LFE
+ *dst++ = *src++; // LR & RR
+ *dst++ = 0; // empty channels
}
- else
- bufferFull = true;
}
- }
-
- // check if no decoded samples are pending and parser is empty
- if (!frame->nb_samples && m_parser->Empty())
- {
- // if no more data but buffer with data -> end of PES packet
- if (buf && buf->nFilledLen > 0)
- bufferFull = true;
else
- {
- m_ready = true;
- m_wait->Wait(50);
- }
+ memcpy(buf->pBuffer + buf->nFilledLen, frame->data[0], len);
+
+ buf->nFilledLen += len;
+ avcodec_get_frame_defaults(frame);
}
+ }
- // we have a buffer to empty
- if (buf && bufferFull)
+ // -- reset --
+ if (m_reset)
+ {
+ m_parser->Reset();
+ avcodec_get_frame_defaults(frame);
+ if (buf)
{
- // send empty buffer if we're about to reset
- if (m_reset)
- buf->nFilledLen = 0;
-
- if (m_omx->EmptyAudioBuffer(buf))
- {
- bufferFull = false;
- buf = 0;
-
- // if parser is empty, get new data
- if (m_parser->Empty())
- m_ready = true;
- }
- else
- {
- esyslog("rpihddevice: failed to empty audio buffer!");
- m_reset = true;
- break;
- }
+ cOmx::PtsToTicks(0, buf->nTimeStamp);
+ buf->nFilledLen = 0;
+ buf->nFlags = 0;
}
}
- if (buf && m_omx->EmptyAudioBuffer(buf))
- buf = 0;
+ // -- empty buffer --
+ if (buf)
+ {
+ if (buf->nFilledLen)
+ m_omx->SetClockReference(cOmx::eClockRefAudio);
+ if (m_omx->EmptyAudioBuffer(buf))
+ buf = 0;
+ }
+
+ m_reset = false;
- av_free(frame);
- m_parser->Reset();
+ // accept new packets as soon as parser is empty and frame has been sent
+ if (m_parser->Empty() && !frame->nb_samples)
+ {
+ if (m_ready)
+ m_wait->Wait(50);
+ else
+ m_ready = true;
+ }
}
- dsyslog("rpihddevice: cAudioDecoder() thread ended");
+
+ av_free(frame);
+ SetCodec(cAudioCodec::eInvalid, outputChannels, samplingRate);
+ DLOG("cAudioDecoder() thread ended");
}
void cAudioDecoder::SetCodec(cAudioCodec::eCodec codec, unsigned int &channels, unsigned int samplingRate)
{
+ m_omx->StopAudio();
+
if (codec != cAudioCodec::eInvalid && channels > 0)
{
- dsyslog("rpihddevice: set audio codec to %dch %s",
- channels, cAudioCodec::Str(codec));
+ DLOG("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;
@@ -950,7 +947,7 @@ void cAudioDecoder::SetCodec(cAudioCodec::eCodec codec, unsigned int &channels,
}
m_omx->SetupAudioRender(outputFormat, channels, outputPort, samplingRate);
- dsyslog("rpihddevice: set %s audio output format to %dch %s, %d.%dkHz%s",
+ ILOG("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 8a7c318..071f22f 100644
--- a/audio.h
+++ b/audio.h
@@ -13,7 +13,7 @@ extern "C" {
#include <vdr/thread.h>
-#include "types.h"
+#include "tools.h"
#include "omx.h"
class cAudioParser;
@@ -29,7 +29,7 @@ public:
virtual int Init(void);
virtual int DeInit(void);
- virtual int WriteData(const unsigned char *buf, unsigned int length, uint64_t pts = 0);
+ virtual bool WriteData(const unsigned char *buf, unsigned int length, uint64_t pts = 0);
virtual bool Poll(void);
virtual void Reset(void);
@@ -53,9 +53,8 @@ private:
bool m_ready;
uint64_t m_pts;
- cMutex *m_mutex;
- cCondWait *m_wait;
- cAudioParser *m_parser;
+ cCondWait *m_wait;
+ cAudioParser *m_parser;
cOmx *m_omx;
};
diff --git a/display.c b/display.c
new file mode 100644
index 0000000..64b83e6
--- /dev/null
+++ b/display.c
@@ -0,0 +1,106 @@
+/*
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id$
+ */
+
+#include "display.h"
+#include "tools.h"
+
+#include <vdr/tools.h>
+
+#include "interface/vmcs_host/vc_dispmanx.h"
+
+#define ALIGN_UP(value, align) (((value) & (align-1)) ? \
+ (((value) + (align-1)) & ~(align-1)) : (value))
+
+DISPMANX_DISPLAY_HANDLE_T cRpiDisplay::s_display = 0;
+DISPMANX_UPDATE_HANDLE_T cRpiDisplay::s_update = 0;
+
+int cRpiDisplay::Open(int device)
+{
+ s_display = vc_dispmanx_display_open(device);
+ if (!s_display)
+ {
+ ELOG("failed to open display!");
+ return -1;
+ }
+
+ s_update = vc_dispmanx_update_start(0);
+ if (s_update == DISPMANX_NO_HANDLE)
+ {
+ ELOG("failed to start display update!");
+ Close();
+ return -1;
+ }
+ return 0;
+}
+
+void cRpiDisplay::Close(void)
+{
+ if (s_display)
+ vc_dispmanx_display_close(s_display);
+
+ s_display = 0;
+}
+
+int cRpiDisplay::GetSize(int &width, int &height)
+{
+ if (!s_display)
+ return -1;
+
+ DISPMANX_MODEINFO_T info;
+ memset(&info, 0, sizeof(info));
+
+ if (vc_dispmanx_display_get_info(s_display, &info))
+ {
+ ELOG("failed to get display info!");
+ return -1;
+ }
+
+ width = info.width;
+ height = info.height;
+
+ return 0;
+}
+
+int cRpiDisplay::AddElement(DISPMANX_ELEMENT_HANDLE_T &element,
+ int width, int height, int layer)
+{
+ if (!s_display)
+ return -1;
+
+ VC_RECT_T dstRect = { 0, 0, width, height };
+ VC_RECT_T srcRect = { 0, 0, width << 16, height << 16 };
+
+ element = vc_dispmanx_element_add(s_update, s_display, layer, &dstRect, 0,
+ &srcRect, DISPMANX_PROTECTION_NONE, 0, 0, (DISPMANX_TRANSFORM_T)0);
+
+ if (!element)
+ {
+ ELOG("failed to add display element!");
+ return -1;
+ }
+
+ vc_dispmanx_update_submit_sync(s_update);
+ return 0;
+}
+
+int cRpiDisplay::Snapshot(uint8_t* frame, int width, int height)
+{
+ if (!s_display)
+ return -1;
+
+ uint32_t image;
+ DISPMANX_RESOURCE_HANDLE_T res = vc_dispmanx_resource_create(
+ VC_IMAGE_RGB888, width, height, &image);
+
+ vc_dispmanx_snapshot(s_display, res,
+ (DISPMANX_TRANSFORM_T)(DISPMANX_SNAPSHOT_PACK));
+
+ VC_RECT_T rect = { 0, 0, width, height };
+ vc_dispmanx_resource_read_data(res, &rect, frame, width * 3);
+
+ vc_dispmanx_resource_delete(res);
+ return 0;
+}
diff --git a/display.h b/display.h
new file mode 100644
index 0000000..bf608c9
--- /dev/null
+++ b/display.h
@@ -0,0 +1,32 @@
+/*
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id$
+ */
+
+#ifndef DISPLAY_H
+#define DISPLAY_H
+
+#include "interface/vmcs_host/vc_dispmanx_types.h"
+
+class cRpiDisplay
+{
+
+public:
+
+ static int Open(int device);
+ static void Close(void);
+
+ static int GetSize(int &width, int &height);
+ static int AddElement(DISPMANX_ELEMENT_HANDLE_T &element,
+ int width, int height, int layer);
+ static int Snapshot(uint8_t* frame, int width, int height);
+
+private:
+
+ static DISPMANX_DISPLAY_HANDLE_T s_display;
+ static DISPMANX_UPDATE_HANDLE_T s_update;
+
+};
+
+#endif
diff --git a/omx.c b/omx.c
index e049281..7e79f87 100644
--- a/omx.c
+++ b/omx.c
@@ -17,12 +17,12 @@ 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
+ 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) { \
@@ -104,26 +104,32 @@ void cOmx::Action(void)
{
while (Running())
{
- m_portEventReady->Wait();
+ m_eventReady->Wait();
while (!m_portEvents->empty())
{
HandlePortSettingsChanged(m_portEvents->front());
m_portEvents->pop();
}
+ if (m_stallEvent)
+ {
+ if (IsBufferStall() && m_onBufferStall)
+ m_onBufferStall(m_onBufferStallData);
+ m_stallEvent = false;
+ }
}
}
void cOmx::HandlePortSettingsChanged(unsigned int portId)
{
-// dsyslog("rpihddevice: HandlePortSettingsChanged(%d)", portId);
+ DBG("HandlePortSettingsChanged(%d)", portId);
switch (portId)
{
case 191:
if (ilclient_setup_tunnel(&m_tun[eVideoFxToVideoScheduler], 0, 0) != 0)
- esyslog("rpihddevice: failed to setup up tunnel from video fx to scheduler!");
+ ELOG("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!");
+ ELOG("failed to enable video scheduler!");
break;
case 131:
@@ -132,46 +138,51 @@ void cOmx::HandlePortSettingsChanged(unsigned int portId)
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!");
+ ELOG("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!");
+ ELOG("failed to get video decoder interlace config!");
+
+ m_videoWidth = portdef.format.video.nFrameWidth;
+ m_videoHeight = portdef.format.video.nFrameHeight;
+ m_videoInterlaced = interlace.eMode != OMX_InterlaceProgressive;
bool deinterlace;
- deinterlace = (cRpiSetup::IsDisplayProgressive() &&
- (interlace.eMode != OMX_InterlaceProgressive));
+ deinterlace = (cRpiSetup::IsDisplayProgressive() && m_videoInterlaced);
- dsyslog("rpihddevice: decoding video %dx%d%s, %sabling deinterlacer",
- portdef.format.video.nFrameWidth,
- portdef.format.video.nFrameHeight,
- interlace.eMode == OMX_InterlaceProgressive ? "p" : "i",
+ ILOG("decoding video %dx%d%s, %sabling deinterlacer",
+ m_videoWidth, m_videoHeight, m_videoInterlaced ? "i" : "p",
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;
+ filterparam.eImageFilter = OMX_ImageFilterNone;
+ if (deinterlace)
+ {
+ filterparam.nNumParams = 1;
+ filterparam.nParams[0] = 3;
+ filterparam.eImageFilter = OMX_ImageFilterDeInterlaceAdvanced;
+ }
if (OMX_SetConfig(ILC_GET_HANDLE(m_comp[eVideoFx]),
OMX_IndexConfigCommonImageFilterParameters, &filterparam) != OMX_ErrorNone)
- esyslog("rpihddevice: failed to set deinterlacing paramaters!");
+ ELOG("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!");
+ ELOG("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!");
+ ELOG("failed to enable video fx!");
break;
case 11:
- if (ilclient_setup_tunnel(&m_tun[eVideoSchedulerToVideoRender], 0, 1000) != 0)
- esyslog("rpihddevice: failed to setup up tunnel from scheduler to render!");
+ if (ilclient_setup_tunnel(&m_tun[eVideoSchedulerToVideoRender], 0, 0) != 0)
+ ELOG("failed to setup up tunnel from scheduler to render!");
if (ilclient_change_component_state(m_comp[eVideoRender], OMX_StateExecuting) != 0)
- esyslog("rpihddevice: failed to enable video render!");
+ ELOG("failed to enable video render!");
break;
}
}
@@ -189,38 +200,54 @@ void cOmx::OnPortSettingsChanged(void *instance, COMPONENT_T *comp, OMX_U32 data
{
cOmx* omx = static_cast <cOmx*> (instance);
omx->m_portEvents->push(data);
- omx->m_portEventReady->Signal();
+ omx->m_eventReady->Signal();
}
void cOmx::OnEndOfStream(void *instance, COMPONENT_T *comp, OMX_U32 data)
{
- cOmx* omx = static_cast <cOmx*> (instance);
+ //cOmx* omx = static_cast <cOmx*> (instance);
}
void cOmx::OnError(void *instance, COMPONENT_T *comp, OMX_U32 data)
{
if ((OMX_S32)data != OMX_ErrorSameState)
- esyslog("rpihddevice: OmxError(%s)", errStr((int)data));
+ ELOG("OmxError(%s)", errStr((int)data));
+}
+
+void cOmx::OnConfigChanged(void *instance, COMPONENT_T *comp, OMX_U32 data)
+{
+ cOmx* omx = static_cast <cOmx*> (instance);
+ if (data == OMX_IndexConfigBufferStall)
+ {
+ omx->m_stallEvent = true;
+ omx->m_eventReady->Signal();
+ }
}
cOmx::cOmx() :
cThread(),
- m_mutex(new cMutex()),
+ m_videoWidth(0),
+ m_videoHeight(0),
+ m_videoInterlaced(false),
m_setAudioStartTime(false),
m_setVideoStartTime(false),
m_setVideoDiscontinuity(false),
m_freeAudioBuffers(0),
m_freeVideoBuffers(0),
- m_clockReference(eClockRefAudio),
- m_portEventReady(new cCondWait()),
- m_portEvents(new std::queue<unsigned int>)
+ m_clockReference(eClockRefNone),
+ m_eventReady(new cCondWait()),
+ m_portEvents(new std::queue<unsigned int>),
+ m_stallEvent(false),
+ m_onBufferStall(0),
+ m_onBufferStallData(0)
{
+ memset(m_tun, 0, sizeof(m_tun));
+ memset(m_comp, 0, sizeof(m_comp));
}
cOmx::~cOmx()
{
- delete m_mutex;
- delete m_portEventReady;
+ delete m_eventReady;
delete m_portEvents;
}
@@ -228,47 +255,48 @@ int cOmx::Init(void)
{
m_client = ilclient_init();
if (m_client == NULL)
- esyslog("rpihddevice: ilclient_init() failed!");
+ ELOG("ilclient_init() failed!");
if (OMX_Init() != OMX_ErrorNone)
- esyslog("rpihddevice: OMX_Init() failed!");
+ ELOG("OMX_Init() failed!");
ilclient_set_error_callback(m_client, OnError, this);
ilclient_set_empty_buffer_done_callback(m_client, OnBufferEmpty, this);
ilclient_set_port_settings_callback(m_client, OnPortSettingsChanged, this);
ilclient_set_eos_callback(m_client, OnEndOfStream, this);
+ ilclient_set_configchanged_callback(m_client, OnConfigChanged, this);
// create video_decode
if (ilclient_create_component(m_client, &m_comp[eVideoDecoder],
"video_decode", (ILCLIENT_CREATE_FLAGS_T)
(ILCLIENT_DISABLE_ALL_PORTS | ILCLIENT_ENABLE_INPUT_BUFFERS)) != 0)
- esyslog("rpihddevice: failed creating video decoder!");
+ ELOG("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!");
+ ELOG("failed creating video fx!");
// create video_render
if (ilclient_create_component(m_client, &m_comp[eVideoRender],
"video_render", ILCLIENT_DISABLE_ALL_PORTS) != 0)
- esyslog("rpihddevice: failed creating video render!");
+ ELOG("failed creating video render!");
//create clock
if (ilclient_create_component(m_client, &m_comp[eClock],
"clock", ILCLIENT_DISABLE_ALL_PORTS) != 0)
- esyslog("rpihddevice: failed creating clock!");
+ ELOG("failed creating clock!");
// create audio_render
if (ilclient_create_component(m_client, &m_comp[eAudioRender],
"audio_render", (ILCLIENT_CREATE_FLAGS_T)
(ILCLIENT_DISABLE_ALL_PORTS | ILCLIENT_ENABLE_INPUT_BUFFERS)) != 0)
- esyslog("rpihddevice: failed creating audio render!");
+ ELOG("failed creating audio render!");
//create video_scheduler
if (ilclient_create_component(m_client, &m_comp[eVideoScheduler],
"video_scheduler", ILCLIENT_DISABLE_ALL_PORTS) != 0)
- esyslog("rpihddevice: failed creating video scheduler!");
+ ELOG("failed creating video scheduler!");
// setup tunnels
set_tunnel(&m_tun[eVideoDecoderToVideoFx],
@@ -288,62 +316,45 @@ int cOmx::Init(void)
// setup clock tunnels first
if (ilclient_setup_tunnel(&m_tun[eClockToVideoScheduler], 0, 0) != 0)
- esyslog("rpihddevice: failed to setup up tunnel from clock to video scheduler!");
+ ELOG("failed to setup up tunnel from clock to video scheduler!");
if (ilclient_setup_tunnel(&m_tun[eClockToAudioRender], 0, 0) != 0)
- esyslog("rpihddevice: failed to setup up tunnel from clock to audio render!");
+ ELOG("failed to setup up tunnel from clock to audio render!");
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);
+ ilclient_change_component_state(m_comp[eAudioRender], OMX_StateIdle);
// set up the number and size of buffers for audio render
- m_freeAudioBuffers = 2; //64;
+ m_freeAudioBuffers = 8;
OMX_PARAM_PORTDEFINITIONTYPE param;
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 = 160 * 1024;
+ ELOG("failed to get audio render port parameters!");
+ param.nBufferSize = KILOBYTE(160);
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!");
+ ELOG("failed to set audio render port parameters!");
OMX_INIT_STRUCT(param);
param.nPortIndex = 130;
if (OMX_GetParameter(ILC_GET_HANDLE(m_comp[eVideoDecoder]),
OMX_IndexParamPortDefinition, &param) != OMX_ErrorNone)
- esyslog("rpihddevice: failed to get video decoder port parameters!");
+ ELOG("failed to get video decoder port parameters!");
m_freeVideoBuffers = param.nBufferCountActual;
- dsyslog("rpihddevice: started with %d video and %d audio buffers",
+ DBG("started with %d video and %d audio buffers",
m_freeVideoBuffers, m_freeAudioBuffers);
-/* // configure video decoder stall callback
- OMX_CONFIG_BUFFERSTALLTYPE stallConf;
- OMX_INIT_STRUCT(stallConf);
- stallConf.nPortIndex = 131;
- stallConf.nDelay = 1500 * 1000;
- if (OMX_SetConfig(m_comp[eVideoDecoder], OMX_IndexConfigBufferStall,
- &stallConf) != OMX_ErrorNone)
- esyslog("rpihddevice: failed to set video decoder stall config!");
+ SetBufferStall(1500);
- OMX_CONFIG_REQUESTCALLBACKTYPE reqCallback;
- OMX_INIT_STRUCT(reqCallback);
- reqCallback.nPortIndex = 131;
- reqCallback.nIndex = OMX_IndexConfigBufferStall;
- reqCallback.bEnable = OMX_TRUE;
- if (OMX_SetConfig(m_comp[eVideoDecoder], OMX_IndexConfigRequestCallback,
- &reqCallback) != OMX_ErrorNone)
- esyslog("rpihddevice: failed to set video decoder stall callback!");
-*/
-// if (ilclient_enable_port_buffers(m_comp[eAudioRender], 100, NULL, NULL, NULL) != 0)
-// esyslog("rpihddevice: failed to enable port buffer on audio render!");
-
- SetClockState(cOmx::eClockStateRun);
+ FlushVideo();
+ FlushAudio();
Start();
@@ -360,11 +371,18 @@ int cOmx::DeInit(void)
ilclient_cleanup_components(m_comp);
OMX_Deinit();
+
ilclient_destroy(m_client);
return 0;
}
+void cOmx::SetBufferStallCallback(void (*onBufferStall)(void*), void* data)
+{
+ m_onBufferStall = onBufferStall;
+ m_onBufferStallData = data;
+}
+
OMX_TICKS cOmx::ToOmxTicks(int64_t val)
{
OMX_TICKS ticks;
@@ -399,20 +417,16 @@ uint64_t cOmx::TicksToPts(OMX_TICKS &ticks)
int64_t cOmx::GetSTC(void)
{
int64_t stc = -1;
-// return stc;
-
OMX_TIME_CONFIG_TIMESTAMPTYPE timestamp;
OMX_INIT_STRUCT(timestamp);
timestamp.nPortIndex = OMX_ALL;
if (OMX_GetConfig(ILC_GET_HANDLE(m_comp[eClock]),
OMX_IndexConfigTimeCurrentMediaTime, &timestamp) != OMX_ErrorNone)
- esyslog("rpihddevice: failed get current clock reference!");
+ ELOG("failed get current clock reference!");
else
stc = TicksToPts(timestamp.nTimestamp);
-// dsyslog("S %u", timestamp.nTimestamp.nLowPart);
-
return stc;
}
@@ -423,7 +437,7 @@ bool cOmx::IsClockRunning(void)
if (OMX_GetConfig(ILC_GET_HANDLE(m_comp[eClock]),
OMX_IndexConfigTimeClockState, &cstate) != OMX_ErrorNone)
- esyslog("rpihddevice: failed get clock state!");
+ ELOG("failed get clock state!");
if (cstate.eState == OMX_TIME_ClockStateRunning)
return true;
@@ -433,20 +447,20 @@ bool cOmx::IsClockRunning(void)
void cOmx::SetClockState(eClockState clockState)
{
-/* dsyslog("rpihddevice: SetClockState(%s)",
+ DBG("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);
if (OMX_GetConfig(ILC_GET_HANDLE(m_comp[eClock]),
OMX_IndexConfigTimeClockState, &cstate) != OMX_ErrorNone)
- esyslog("rpihddevice: failed to get clock state!");
+ ELOG("failed to get clock state!");
// if clock is already running, we need to stop it first
if ((cstate.eState == OMX_TIME_ClockStateRunning) &&
@@ -457,7 +471,7 @@ void cOmx::SetClockState(eClockState clockState)
cstate.eState = OMX_TIME_ClockStateStopped;
if (OMX_SetConfig(ILC_GET_HANDLE(m_comp[eClock]),
OMX_IndexConfigTimeClockState, &cstate) != OMX_ErrorNone)
- esyslog("rpihddevice: failed to stop clock!");
+ ELOG("failed to stop clock!");
}
cstate.nWaitMask = 0;
@@ -492,13 +506,13 @@ void cOmx::SetClockState(eClockState clockState)
break;
}
- if (cstate.eState == OMX_TIME_ClockStateWaitingForStartTime)
- // 200ms pre roll, value taken from omxplayer
- cstate.nOffset = ToOmxTicks(-1000LL * 200);
+// if (cstate.eState == OMX_TIME_ClockStateWaitingForStartTime)
+ // 50ms pre roll, was 200ms at omxplayer
+// cstate.nOffset = ToOmxTicks(-1000LL * 50);
if (OMX_SetConfig(ILC_GET_HANDLE(m_comp[eClock]),
OMX_IndexConfigTimeClockState, &cstate) != OMX_ErrorNone)
- esyslog("rpihddevice: failed to set clock state!");
+ ELOG("failed to set clock state!");
}
void cOmx::SetClockScale(float scale)
@@ -509,7 +523,7 @@ void cOmx::SetClockScale(float scale)
if (OMX_SetConfig(ILC_GET_HANDLE(m_comp[eClock]),
OMX_IndexConfigTimeScale, &scaleType) != OMX_ErrorNone)
- esyslog("rpihddevice: failed to set clock scale (%d)!", scaleType.xScale);
+ ELOG("failed to set clock scale (%d)!", scaleType.xScale);
}
void cOmx::SetStartTime(uint64_t pts)
@@ -521,7 +535,7 @@ void cOmx::SetStartTime(uint64_t pts)
if (OMX_SetConfig(ILC_GET_HANDLE(m_comp[eClock]),
OMX_IndexConfigTimeClientStartTime, &timeStamp) != OMX_ErrorNone)
- esyslog("rpihddevice: failed to set current start time!");
+ ELOG("failed to set current start time!");
}
void cOmx::SetCurrentReferenceTime(uint64_t pts)
@@ -535,7 +549,7 @@ void cOmx::SetCurrentReferenceTime(uint64_t pts)
m_clockReference == eClockRefAudio ?
OMX_IndexConfigTimeCurrentAudioReference :
OMX_IndexConfigTimeCurrentVideoReference, &timeStamp) != OMX_ErrorNone)
- esyslog("rpihddevice: failed to set current %s reference time!",
+ ELOG("failed to set current %s reference time!",
m_clockReference == eClockRefAudio ? "audio" : "video");
}
@@ -549,7 +563,7 @@ unsigned int cOmx::GetMediaTime(void)
if (OMX_GetConfig(ILC_GET_HANDLE(m_comp[eClock]),
OMX_IndexConfigTimeCurrentMediaTime, &timestamp) != OMX_ErrorNone)
- esyslog("rpihddevice: failed get current clock reference!");
+ ELOG("failed get current clock reference!");
else
ret = timestamp.nTimestamp.nLowPart;
@@ -558,19 +572,61 @@ unsigned int cOmx::GetMediaTime(void)
void cOmx::SetClockReference(eClockReference clockReference)
{
- m_clockReference = clockReference;
+ if (m_clockReference != clockReference)
+ {
+ OMX_TIME_CONFIG_ACTIVEREFCLOCKTYPE refClock;
+ OMX_INIT_STRUCT(refClock);
+ refClock.eClock =
+ (clockReference == eClockRefAudio) ? OMX_TIME_RefClockAudio :
+ (clockReference == eClockRefVideo) ? OMX_TIME_RefClockVideo :
+ OMX_TIME_RefClockNone;
- OMX_TIME_CONFIG_ACTIVEREFCLOCKTYPE refClock;
- OMX_INIT_STRUCT(refClock);
- refClock.eClock = (m_clockReference == eClockRefAudio) ?
- OMX_TIME_RefClockAudio : OMX_TIME_RefClockVideo;
+ if (OMX_SetConfig(ILC_GET_HANDLE(m_comp[eClock]),
+ OMX_IndexConfigTimeActiveRefClock, &refClock) != OMX_ErrorNone)
+ ELOG("failed set active clock reference!");
+ else
+ DBG("set active clock reference to %s",
+ clockReference == eClockRefAudio ? "audio" :
+ clockReference == eClockRefVideo ? "video" : "none");
+
+ m_clockReference = clockReference;
+ }
+}
- if (OMX_SetConfig(ILC_GET_HANDLE(m_comp[eClock]),
- OMX_IndexConfigTimeActiveRefClock, &refClock) != OMX_ErrorNone)
- esyslog("rpihddevice: failed set active clock reference!");
-/* else
- dsyslog("rpihddevice: set active clock reference to %s",
- m_clockReference == eClockRefAudio ? "audio" : "video"); */
+void cOmx::SetBufferStall(int delayMs)
+{
+ if (delayMs > 0)
+ {
+ OMX_CONFIG_BUFFERSTALLTYPE stallConf;
+ OMX_INIT_STRUCT(stallConf);
+ stallConf.nPortIndex = 131;
+ stallConf.nDelay = delayMs * 1000;
+ if (OMX_SetConfig(ILC_GET_HANDLE(m_comp[eVideoDecoder]),
+ OMX_IndexConfigBufferStall, &stallConf) != OMX_ErrorNone)
+ ELOG("failed to set video decoder stall config!");
+ }
+
+ // set buffer stall call back
+ OMX_CONFIG_REQUESTCALLBACKTYPE reqCallback;
+ OMX_INIT_STRUCT(reqCallback);
+ reqCallback.nPortIndex = 131;
+ reqCallback.nIndex = OMX_IndexConfigBufferStall;
+ reqCallback.bEnable = delayMs > 0 ? OMX_TRUE : OMX_FALSE;
+ if (OMX_SetConfig(ILC_GET_HANDLE(m_comp[eVideoDecoder]),
+ OMX_IndexConfigRequestCallback, &reqCallback) != OMX_ErrorNone)
+ ELOG("failed to set video decoder stall call back!");
+}
+
+bool cOmx::IsBufferStall(void)
+{
+ OMX_CONFIG_BUFFERSTALLTYPE stallConf;
+ OMX_INIT_STRUCT(stallConf);
+ stallConf.nPortIndex = 131;
+ if (OMX_GetConfig(ILC_GET_HANDLE(m_comp[eVideoDecoder]),
+ OMX_IndexConfigBufferStall, &stallConf) != OMX_ErrorNone)
+ ELOG("failed to get video decoder stall config!");
+
+ return stallConf.bStalled == OMX_TRUE;
}
void cOmx::SetVolume(int vol)
@@ -583,7 +639,7 @@ void cOmx::SetVolume(int vol)
if (OMX_SetConfig(ILC_GET_HANDLE(m_comp[eAudioRender]),
OMX_IndexConfigAudioVolume, &volume) != OMX_ErrorNone)
- esyslog("rpihddevice: failed to set volume!");
+ ELOG("failed to set volume!");
}
void cOmx::SetMute(bool mute)
@@ -595,7 +651,7 @@ void cOmx::SetMute(bool mute)
if (OMX_SetConfig(ILC_GET_HANDLE(m_comp[eAudioRender]),
OMX_IndexConfigAudioMute, &amute) != OMX_ErrorNone)
- esyslog("rpihddevice: failed to set mute state!");
+ ELOG("failed to set mute state!");
}
void cOmx::SendEos(void)
@@ -609,17 +665,15 @@ void cOmx::SendEos(void)
buf->nFlags = OMX_BUFFERFLAG_TIME_UNKNOWN | OMX_BUFFERFLAG_EOS;
if (OMX_EmptyThisBuffer(ILC_GET_HANDLE(m_comp[eVideoDecoder]), buf) != OMX_ErrorNone)
- esyslog("rpihddevice: failed to send empty packet to video decoder!");
+ ELOG("failed to send empty packet to video decoder!");
if (!m_eosEvent->Wait(10000))
- esyslog("rpihddevice: time out waiting for EOS event!");
+ ELOG("time out waiting for EOS event!");
#endif
}
void cOmx::StopVideo(void)
{
- dsyslog("rpihddevice: StopVideo()");
-
// put video decoder into idle
ilclient_change_component_state(m_comp[eVideoDecoder], OMX_StateIdle);
@@ -642,13 +696,17 @@ void cOmx::StopVideo(void)
// disable port buffers and allow video decoder to reconfig
ilclient_disable_port_buffers(m_comp[eVideoDecoder], 130, NULL, NULL, NULL);
+
+ m_videoWidth = 0;
+ m_videoHeight = 0;
+ m_videoInterlaced = false;
}
void cOmx::StopAudio(void)
{
// put audio render onto idle
ilclient_flush_tunnels(&m_tun[eClockToAudioRender], 1);
-// ilclient_disable_tunnel(&m_tun[eClockToAudioRender]);
+ 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);
}
@@ -665,7 +723,7 @@ void cOmx::SetVideoDataUnitType(eDataUnitType dataUnitType)
if (OMX_SetParameter(ILC_GET_HANDLE(m_comp[eVideoDecoder]),
OMX_IndexParamBrcmDataUnit, &dataUnit) != OMX_ErrorNone)
- esyslog("rpihddevice: failed to set video decoder data unit type!");
+ ELOG("failed to set video decoder data unit type!");
}
@@ -676,7 +734,7 @@ void cOmx::SetVideoErrorConcealment(bool startWithValidFrame)
ectype.bStartWithValidFrame = startWithValidFrame ? OMX_TRUE : OMX_FALSE;
if (OMX_SetParameter(ILC_GET_HANDLE(m_comp[eVideoDecoder]),
OMX_IndexParamBrcmVideoDecodeErrorConcealment, &ectype) != OMX_ErrorNone)
- esyslog("rpihddevice: failed to set video decode error concealment failed\n");
+ ELOG("failed to set video decode error concealment failed\n");
}
void cOmx::FlushAudio(void)
@@ -684,7 +742,7 @@ void cOmx::FlushAudio(void)
ilclient_flush_tunnels(&m_tun[eClockToAudioRender], 1);
if (OMX_SendCommand(ILC_GET_HANDLE(m_comp[eAudioRender]), OMX_CommandFlush, 100, NULL) != OMX_ErrorNone)
- esyslog("rpihddevice: failed to flush audio render!");
+ ELOG("failed to flush audio render!");
}
void cOmx::FlushVideo(bool flushRender)
@@ -692,7 +750,7 @@ void cOmx::FlushVideo(bool flushRender)
ilclient_flush_tunnels(&m_tun[eClockToVideoScheduler], 1);
if (OMX_SendCommand(ILC_GET_HANDLE(m_comp[eVideoDecoder]), OMX_CommandFlush, 130, NULL) != OMX_ErrorNone)
- esyslog("rpihddevice: failed to flush video decoder!");
+ ELOG("failed to flush video decoder!");
ilclient_flush_tunnels(&m_tun[eVideoDecoderToVideoFx], 1);
ilclient_flush_tunnels(&m_tun[eVideoFxToVideoScheduler], 1);
@@ -706,7 +764,7 @@ void cOmx::FlushVideo(bool flushRender)
int cOmx::SetVideoCodec(cVideoCodec::eCodec codec, eDataUnitType dataUnit)
{
if (ilclient_change_component_state(m_comp[eVideoDecoder], OMX_StateIdle) != 0)
- esyslog("rpihddevice: failed to set video decoder to idle state!");
+ ELOG("failed to set video decoder to idle state!");
// configure video decoder
OMX_VIDEO_PARAM_PORTFORMATTYPE videoFormat;
@@ -719,7 +777,7 @@ int cOmx::SetVideoCodec(cVideoCodec::eCodec codec, eDataUnitType dataUnit)
if (OMX_SetParameter(ILC_GET_HANDLE(m_comp[eVideoDecoder]),
OMX_IndexParamVideoPortFormat, &videoFormat) != OMX_ErrorNone)
- esyslog("rpihddevice: failed to set video decoder parameters!");
+ ELOG("failed to set video decoder parameters!");
// start with valid frames only if codec is MPEG2
SetVideoErrorConcealment(codec == cVideoCodec::eMPEG2);
@@ -727,14 +785,14 @@ int cOmx::SetVideoCodec(cVideoCodec::eCodec codec, eDataUnitType dataUnit)
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!");
+ ELOG("failed to enable port buffer on video decoder!");
if (ilclient_change_component_state(m_comp[eVideoDecoder], OMX_StateExecuting) != 0)
- esyslog("rpihddevice: failed to set video decoder to executing state!");
+ ELOG("failed to set video decoder to executing state!");
// setup clock tunnels first
if (ilclient_setup_tunnel(&m_tun[eClockToVideoScheduler], 0, 0) != 0)
- esyslog("rpihddevice: failed to setup up tunnel from clock to video scheduler!");
+ ELOG("failed to setup up tunnel from clock to video scheduler!");
return 0;
}
@@ -747,27 +805,18 @@ void cOmx::SetVideoDecoderExtraBuffers(int extraBuffers)
u32.nU32 = extraBuffers;
if (OMX_SetParameter(ILC_GET_HANDLE(m_comp[eVideoDecoder]),
OMX_IndexParamBrcmExtraBuffers, &u32) != OMX_ErrorNone)
- esyslog("rpihddevice: failed to set video decoder extra buffers!");
+ ELOG("failed to set video decoder extra buffers!");
}
int cOmx::SetupAudioRender(cAudioCodec::eCodec outputFormat, int channels,
cAudioPort::ePort audioPort, int samplingRate)
{
- // 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);
-
- if (OMX_SendCommand(ILC_GET_HANDLE(m_comp[eAudioRender]), OMX_CommandFlush, 100, NULL) != OMX_ErrorNone)
- esyslog("rpihddevice: failed to flush audio render!");
-
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!");
+ ELOG("failed to get audio port format parameters!");
format.eEncoding =
outputFormat == cAudioCodec::ePCM ? OMX_AUDIO_CodingPCM :
@@ -775,12 +824,12 @@ 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_CodingAAC :
+ outputFormat == cAudioCodec::eAAC ? OMX_AUDIO_CodingAAC :
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!");
+ ELOG("failed to set audio port format parameters!");
switch (outputFormat)
{
@@ -795,7 +844,7 @@ int cOmx::SetupAudioRender(cAudioCodec::eCodec outputFormat, int channels,
if (OMX_SetParameter(ILC_GET_HANDLE(m_comp[eAudioRender]),
OMX_IndexParamAudioMp3, &mp3) != OMX_ErrorNone)
- esyslog("rpihddevice: failed to set audio render mp3 parameters!");
+ ELOG("failed to set audio render mp3 parameters!");
break;
case cAudioCodec::eAC3:
@@ -809,24 +858,20 @@ int cOmx::SetupAudioRender(cAudioCodec::eCodec outputFormat, int channels,
if (OMX_SetParameter(ILC_GET_HANDLE(m_comp[eAudioRender]),
OMX_IndexParamAudioDdp, &ddp) != OMX_ErrorNone)
- esyslog("rpihddevice: failed to set audio render ddp parameters!");
+ ELOG("failed to set audio render ddp parameters!");
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 =
- outputFormat == cAudioCodec::eAAC ? OMX_AUDIO_AACStreamFormatMP4LATM :
- outputFormat == cAudioCodec::eADTS ? OMX_AUDIO_AACStreamFormatMP4ADTS :
- (OMX_AUDIO_AACSTREAMFORMATTYPE)0;
+ aac.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4ADTS;
if (OMX_SetParameter(ILC_GET_HANDLE(m_comp[eAudioRender]),
OMX_IndexParamAudioAac, &aac) != OMX_ErrorNone)
- esyslog("rpihddevice: failed to set audio render aac parameters!");
+ ELOG("failed to set audio render aac parameters!");
break;
case cAudioCodec::ePCM:
@@ -844,11 +889,11 @@ int cOmx::SetupAudioRender(cAudioCodec::eCodec outputFormat, int channels,
if (OMX_SetParameter(ILC_GET_HANDLE(m_comp[eAudioRender]),
OMX_IndexParamAudioPcm, &pcm) != OMX_ErrorNone)
- esyslog("rpihddevice: failed to set audio render pcm parameters!");
+ ELOG("failed to set audio render pcm parameters!");
break;
default:
- esyslog("rpihddevice: output codec not supported: %s!",
+ ELOG("output codec not supported: %s!",
cAudioCodec::Str(outputFormat));
break;
}
@@ -860,22 +905,65 @@ int cOmx::SetupAudioRender(cAudioCodec::eCodec outputFormat, int channels,
if (OMX_SetConfig(ILC_GET_HANDLE(m_comp[eAudioRender]),
OMX_IndexConfigBrcmAudioDestination, &audioDest) != OMX_ErrorNone)
- esyslog("rpihddevice: failed to set audio destination!");
+ ELOG("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!");
+ ELOG("failed to enable port buffer on audio render!");
ilclient_change_component_state(m_comp[eAudioRender], OMX_StateExecuting);
if (ilclient_setup_tunnel(&m_tun[eClockToAudioRender], 0, 0) != 0)
- esyslog("rpihddevice: failed to setup up tunnel from clock to video scheduler!");
+ ELOG("failed to setup up tunnel from clock to video scheduler!");
return 0;
}
+void cOmx::GetVideoSize(int &width, int &height, bool &interlaced)
+{
+ width = m_videoWidth;
+ height = m_videoHeight;
+ interlaced = m_videoInterlaced;
+}
+
+void cOmx::SetDisplayMode(bool letterbox, bool noaspect)
+{
+ OMX_CONFIG_DISPLAYREGIONTYPE region;
+ OMX_INIT_STRUCT(region);
+ region.nPortIndex = 90;
+ region.set = (OMX_DISPLAYSETTYPE)
+ (OMX_DISPLAY_SET_MODE | OMX_DISPLAY_SET_NOASPECT);
+
+ region.noaspect = noaspect ? OMX_TRUE : OMX_FALSE;
+ region.mode = letterbox ?
+ OMX_DISPLAY_MODE_LETTERBOX : OMX_DISPLAY_MODE_FILL;
+
+ if (OMX_SetConfig(ILC_GET_HANDLE(m_comp[eVideoRender]),
+ OMX_IndexConfigDisplayRegion, &region) != OMX_ErrorNone)
+ ELOG("failed to set display region!");
+}
+
+void cOmx::SetDisplayRegion(int x, int y, int width, int height)
+{
+ OMX_CONFIG_DISPLAYREGIONTYPE region;
+ OMX_INIT_STRUCT(region);
+ region.nPortIndex = 90;
+ region.set = (OMX_DISPLAYSETTYPE)
+ (OMX_DISPLAY_SET_FULLSCREEN | OMX_DISPLAY_SET_DEST_RECT);
+
+ region.fullscreen = (!x && !y && !width && !height) ? OMX_TRUE : OMX_FALSE;
+ region.dest_rect.x_offset = x;
+ region.dest_rect.y_offset = y;
+ region.dest_rect.width = width;
+ region.dest_rect.height = height;
+
+ if (OMX_SetConfig(ILC_GET_HANDLE(m_comp[eVideoRender]),
+ OMX_IndexConfigDisplayRegion, &region) != OMX_ErrorNone)
+ ELOG("failed to set display region!");
+}
+
OMX_BUFFERHEADERTYPE* cOmx::GetAudioBuffer(uint64_t pts)
{
- m_mutex->Lock();
+ Lock();
OMX_BUFFERHEADERTYPE* buf = NULL;
if (m_freeAudioBuffers > 0)
@@ -891,13 +979,14 @@ OMX_BUFFERHEADERTYPE* cOmx::GetAudioBuffer(uint64_t pts)
m_freeAudioBuffers--;
}
}
- m_mutex->Unlock();
+
+ Unlock();
return buf;
}
OMX_BUFFERHEADERTYPE* cOmx::GetVideoBuffer(uint64_t pts)
{
- m_mutex->Lock();
+ Lock();
OMX_BUFFERHEADERTYPE* buf = NULL;
if (m_freeVideoBuffers > 0)
@@ -915,7 +1004,8 @@ OMX_BUFFERHEADERTYPE* cOmx::GetVideoBuffer(uint64_t pts)
m_freeVideoBuffers--;
}
}
- m_mutex->Unlock();
+
+ Unlock();
return buf;
}
diff --git a/omx.h b/omx.h
index d442d50..205c36d 100644
--- a/omx.h
+++ b/omx.h
@@ -9,7 +9,7 @@
#include <queue>
#include <vdr/thread.h>
-#include "types.h"
+#include "tools.h"
extern "C"
{
@@ -26,6 +26,8 @@ public:
int Init(void);
int DeInit(void);
+ void SetBufferStallCallback(void (*onBufferStall)(void*), void* data);
+
static OMX_TICKS ToOmxTicks(int64_t val);
static int64_t FromOmxTicks(OMX_TICKS &ticks);
static void PtsToTicks(uint64_t pts, OMX_TICKS &ticks);
@@ -50,7 +52,8 @@ public:
enum eClockReference {
eClockRefAudio,
- eClockRefVideo
+ eClockRefVideo,
+ eClockRefNone
};
void SetClockReference(eClockReference clockReference);
@@ -76,6 +79,10 @@ public:
eDataUnitType dataUnit = eArbitraryStreamSection);
int SetupAudioRender(cAudioCodec::eCodec outputFormat,
int channels, cAudioPort::ePort audioPort, int samplingRate = 0);
+ void GetVideoSize(int &width, int &height, bool &interlaced);
+
+ void SetDisplayMode(bool letterbox, bool noaspect);
+ void SetDisplayRegion(int x, int y, int width, int height);
OMX_BUFFERHEADERTYPE* GetAudioBuffer(uint64_t pts = 0);
OMX_BUFFERHEADERTYPE* GetVideoBuffer(uint64_t pts = 0);
@@ -114,7 +121,9 @@ private:
COMPONENT_T *m_comp[cOmx::eNumComponents + 1];
TUNNEL_T m_tun[cOmx::eNumTunnels + 1];
- cMutex *m_mutex;
+ int m_videoWidth;
+ int m_videoHeight;
+ bool m_videoInterlaced;
bool m_setAudioStartTime;
bool m_setVideoStartTime;
@@ -125,14 +134,21 @@ private:
eClockReference m_clockReference;
- cCondWait *m_portEventReady;
- std::queue<unsigned int> *m_portEvents;
+ cCondWait *m_eventReady;
+ std::queue<unsigned int> *m_portEvents;
+ bool m_stallEvent;
+ void (*m_onBufferStall)(void*);
+ void *m_onBufferStallData;
+
void HandlePortSettingsChanged(unsigned int portId);
+ void SetBufferStall(int delayMs);
+ bool IsBufferStall(void);
static void OnBufferEmpty(void *instance, COMPONENT_T *comp);
static void OnPortSettingsChanged(void *instance, COMPONENT_T *comp, OMX_U32 data);
static void OnEndOfStream(void *instance, COMPONENT_T *comp, OMX_U32 data);
static void OnError(void *instance, COMPONENT_T *comp, OMX_U32 data);
+ static void OnConfigChanged(void *instance, COMPONENT_T *comp, OMX_U32 data);
};
diff --git a/omxdevice.c b/omxdevice.c
index a87bd87..f80a1e2 100644
--- a/omxdevice.c
+++ b/omxdevice.c
@@ -7,6 +7,7 @@
#include "omxdevice.h"
#include "omx.h"
#include "audio.h"
+#include "display.h"
#include "setup.h"
#include <vdr/thread.h>
@@ -35,6 +36,8 @@ cOmxDevice::cOmxDevice(void (*onPrimaryDevice)(void)) :
cOmxDevice::~cOmxDevice()
{
+ DeInit();
+
delete m_omx;
delete m_audio;
delete m_mutex;
@@ -44,14 +47,15 @@ int cOmxDevice::Init(void)
{
if (m_omx->Init() < 0)
{
- esyslog("rpihddevice: failed to initialize OMX!");
+ ELOG("failed to initialize OMX!");
return -1;
}
if (m_audio->Init() < 0)
{
- esyslog("rpihddevice: failed to initialize audio!");
+ ELOG("failed to initialize audio!");
return -1;
}
+ m_omx->SetBufferStallCallback(&OnBufferStall, this);
return 0;
}
@@ -59,12 +63,12 @@ int cOmxDevice::DeInit(void)
{
if (m_audio->DeInit() < 0)
{
- esyslog("rpihddevice: failed to deinitialize audio!");
+ ELOG("failed to deinitialize audio!");
return -1;
}
if (m_omx->DeInit() < 0)
{
- esyslog("rpihddevice: failed to deinitialize OMX!");
+ ELOG("failed to deinitialize OMX!");
return -1;
}
return 0;
@@ -75,10 +79,39 @@ void cOmxDevice::GetOsdSize(int &Width, int &Height, double &PixelAspect)
cRpiSetup::GetDisplaySize(Width, Height, PixelAspect);
}
+void cOmxDevice::GetVideoSize(int &Width, int &Height, double &VideoAspect)
+{
+ bool interlaced;
+ m_omx->GetVideoSize(Width, Height, interlaced);
+
+ if (Height)
+ VideoAspect = (double)Width / Height;
+}
+
+void cOmxDevice::SetVideoDisplayFormat(eVideoDisplayFormat VideoDisplayFormat)
+{
+ DBG("SetVideoDisplayFormat(%s)",
+ VideoDisplayFormat == vdfPanAndScan ? "PanAndScan" :
+ VideoDisplayFormat == vdfLetterBox ? "LetterBox" :
+ VideoDisplayFormat == vdfCenterCutOut ? "CenterCutOut" : "undefined");
+
+ m_omx->SetDisplayMode(VideoDisplayFormat == vdfLetterBox, false);
+
+ cDevice::SetVideoDisplayFormat(VideoDisplayFormat);
+}
+
+void cOmxDevice::ScaleVideo(const cRect &Rect)
+{
+ DBG("ScaleVideo(%d, %d, %d, %d)",
+ Rect.X(), Rect.Y(), Rect.Width(), Rect.Height());
+
+ m_omx->SetDisplayRegion(Rect.X(), Rect.Y(), Rect.Width(), Rect.Height());
+}
+
bool cOmxDevice::SetPlayMode(ePlayMode PlayMode)
{
m_mutex->Lock();
- dsyslog("rpihddevice: SetPlayMode(%s)",
+ DBG("SetPlayMode(%s)",
PlayMode == pmNone ? "none" :
PlayMode == pmAudioVideo ? "Audio/Video" :
PlayMode == pmAudioOnly ? "Audio only" :
@@ -120,9 +153,11 @@ void cOmxDevice::StillPicture(const uchar *Data, int Length)
cDevice::StillPicture(Data, Length);
else
{
+ Clear(); //?
// to get a picture displayed, PlayVideo() needs to be called
- // twice for MPEG2 and 10x for H264... ?
- int repeat = ParseVideoCodec(Data, Length) == cVideoCodec::eMPEG2 ? 2 : 10;
+ // 4x for MPEG2 and 12x for H264... ?
+ int repeat =
+ ParseVideoCodec(Data, Length) == cVideoCodec::eMPEG2 ? 4 : 12;
while (repeat--)
PlayVideo(Data, Length, true);
@@ -135,14 +170,17 @@ int cOmxDevice::PlayAudio(const uchar *Data, int Length, uchar Id)
return Length;
m_mutex->Lock();
- int64_t pts = PesHasPts(Data) ? PesGetPts(Data) : 0;
if (!m_hasAudio)
{
- m_omx->SetClockReference(cOmx::eClockRefAudio);
+ // start clock once an audio packet is played, even
+ // if it's been set to wait state before
+ m_omx->SetClockState(cOmx::eClockStateRun);
m_hasAudio = true;
}
+ int64_t pts = PesHasPts(Data) ? PesGetPts(Data) : 0;
+
// keep track of direction in case of trick speed
if (m_trickRequest && pts)
{
@@ -153,7 +191,7 @@ int cOmxDevice::PlayAudio(const uchar *Data, int Length, uchar Id)
}
int ret = m_audio->WriteData(Data + PesPayloadOffset(Data),
- Length - PesPayloadOffset(Data), pts);
+ Length - PesPayloadOffset(Data), pts) ? Length : 0;
m_mutex->Unlock();
return ret;
@@ -186,8 +224,7 @@ int cOmxDevice::PlayVideo(const uchar *Data, int Length, bool singleFrame)
{
videoRestart = true;
m_omx->SetVideoCodec(codec, cOmx::eArbitraryStreamSection);
- dsyslog("rpihddevice: set video codec to %s",
- cVideoCodec::Str(codec));
+ DLOG("set video codec to %s", cVideoCodec::Str(codec));
}
else
Skins.QueueMessage(mtError, tr("video format not supported!"));
@@ -195,14 +232,12 @@ int cOmxDevice::PlayVideo(const uchar *Data, int Length, bool singleFrame)
if (videoRestart)
{
- m_hasVideo = true;
-
+ // put clock in waiting state. that's only needed for video only
+ // play back, since audio will start clock directly
if (!m_hasAudio)
- {
- m_omx->SetClockReference(cOmx::eClockRefVideo);
- m_omx->SetCurrentReferenceTime(0);
m_omx->SetClockState(cOmx::eClockStateWaitForVideo);
- }
+
+ m_hasVideo = true;
}
// keep track of direction in case of trick speed
@@ -218,17 +253,12 @@ int cOmxDevice::PlayVideo(const uchar *Data, int Length, bool singleFrame)
{
while (Length)
{
- 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)
{
- buf->nFilledLen = length;
- memcpy(buf->pBuffer, payload, length);
+ buf->nFilledLen = PesLength(Data) - PesPayloadOffset(Data);
+ memcpy(buf->pBuffer, Data + PesPayloadOffset(Data),
+ PesLength(Data) - PesPayloadOffset(Data));
if (singleFrame && Length == PesLength(Data))
buf->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME;
@@ -236,7 +266,7 @@ int cOmxDevice::PlayVideo(const uchar *Data, int Length, bool singleFrame)
if (!m_omx->EmptyVideoBuffer(buf))
{
ret = 0;
- esyslog("rpihddevice: failed to pass buffer to video decoder!");
+ ELOG("failed to pass buffer to video decoder!");
break;
}
}
@@ -245,8 +275,10 @@ int cOmxDevice::PlayVideo(const uchar *Data, int Length, bool singleFrame)
ret = 0;
break;
}
+
Length -= PesLength(Data);
Data += PesLength(Data);
+ pts = PesHasPts(Data) ? PesGetPts(Data) : 0;
}
}
@@ -259,19 +291,73 @@ int64_t cOmxDevice::GetSTC(void)
return m_omx->GetSTC();
}
-void cOmxDevice::Play(void)
+uchar *cOmxDevice::GrabImage(int &Size, bool Jpeg, int Quality, int SizeX, int SizeY)
{
- m_mutex->Lock();
+ DBG("GrabImage(%s, %dx%d)", Jpeg ? "JPEG" : "PNM", SizeX, SizeY);
+
+ uint8_t* ret = NULL;
+ int width, height;
+ cRpiDisplay::GetSize(width, height);
+
+ SizeX = (SizeX > 0) ? SizeX : width;
+ SizeY = (SizeY > 0) ? SizeY : height;
+
+ // bigger than needed, but uint32_t ensures proper alignment
+ uint8_t* frame = (uint8_t*)(MALLOC(uint32_t, SizeX * SizeY));
+
+ if (!frame)
+ {
+ ELOG("failed to allocate image buffer!");
+ return ret;
+ }
+
+ if (cRpiDisplay::Snapshot(frame, SizeX, SizeY))
+ {
+ ELOG("failed to grab image!");
+ free(frame);
+ return ret;
+ }
+
+ if (Jpeg)
+ ret = RgbToJpeg(frame, SizeX, SizeY, Size, Quality);
+ else
+ {
+ char buf[32];
+ snprintf(buf, sizeof(buf), "P6\n%d\n%d\n255\n", SizeX, SizeY);
+ int l = strlen(buf);
+ Size = l + SizeX * SizeY * 3;
+ ret = (uint8_t *)malloc(Size);
+ if (ret)
+ {
+ memcpy(ret, buf, l);
+ memcpy(ret + l, frame, SizeX * SizeY * 3);
+ }
+ }
+ free(frame);
+ return ret;
+}
+void cOmxDevice::Clear(void)
+{
+ DBG("Clear()");
+ m_mutex->Lock();
ResetAudioVideo();
- m_omx->SetStartTime(0);
+ m_mutex->Unlock();
+ cDevice::Clear();
+}
+void cOmxDevice::Play(void)
+{
+ DBG("Play()");
+ m_mutex->Lock();
+ ResetAudioVideo();
m_mutex->Unlock();
cDevice::Play();
}
void cOmxDevice::Freeze(void)
{
+ DBG("Freeze()");
m_mutex->Lock();
m_omx->SetClockScale(0.0f);
m_mutex->Unlock();
@@ -281,6 +367,7 @@ void cOmxDevice::Freeze(void)
#if APIVERSNUM >= 20103
void cOmxDevice::TrickSpeed(int Speed, bool Forward)
{
+ DBG("TrickSpeed(%d, %sward)", Speed, Forward ? "for" : "back");
m_mutex->Lock();
ApplyTrickSpeed(Speed, Forward);
m_mutex->Unlock();
@@ -288,6 +375,7 @@ void cOmxDevice::TrickSpeed(int Speed, bool Forward)
#else
void cOmxDevice::TrickSpeed(int Speed)
{
+ DBG("TrickSpeed(%d)", Speed);
m_mutex->Lock();
m_audioPts = 0;
m_videoPts = 0;
@@ -324,11 +412,14 @@ void cOmxDevice::ApplyTrickSpeed(int trickSpeed, bool forward)
m_omx->SetClockScale(scale);
m_omx->SetClockReference(cOmx::eClockRefVideo);
- m_trickRequest = 0;
+ if (m_hasAudio)
+ {
+ m_audio->Reset();
+ m_omx->FlushAudio();
+ }
m_skipAudio = true;
- dsyslog("rpihddevice: ApplyTrickSpeed(%.3f, %sward)",
- scale, forward ? "for" : "back");
+ DBG("ApplyTrickSpeed(%.3f, %sward)", scale, forward ? "for" : "back");
}
@@ -340,33 +431,24 @@ void cOmxDevice::PtsTracker(int64_t ptsDiff)
m_playDirection += 2;
if (m_playDirection < -2 || m_playDirection > 3)
+ {
ApplyTrickSpeed(m_trickRequest, m_playDirection > 0);
+ m_trickRequest = 0;
+ }
}
-bool cOmxDevice::Flush(int TimeoutMs)
-{
- dsyslog("rpihddevice: Flush()");
- return true;
-}
-
-void cOmxDevice::Clear(void)
+void cOmxDevice::HandleBufferStall()
{
+ ELOG("buffer stall!");
m_mutex->Lock();
-
ResetAudioVideo();
- m_omx->SetStartTime(0);
-
m_mutex->Unlock();
- cDevice::Clear();
}
void cOmxDevice::ResetAudioVideo(bool flushVideoRender)
{
- m_omx->SetClockScale(1.0f);
- m_skipAudio = false;
- m_trickRequest = 0;
- m_audioPts = 0;
- m_videoPts = 0;
+ if (m_hasVideo)
+ m_omx->FlushVideo(flushVideoRender);
if (m_hasAudio)
{
@@ -374,8 +456,15 @@ void cOmxDevice::ResetAudioVideo(bool flushVideoRender)
m_omx->FlushAudio();
}
- if (m_hasVideo)
- m_omx->FlushVideo(flushVideoRender);
+ m_omx->SetClockReference(cOmx::eClockRefVideo);
+ m_omx->SetClockScale(1.0f);
+ m_omx->SetStartTime(0);
+ m_omx->SetClockState(cOmx::eClockStateStop);
+
+ m_skipAudio = false;
+ m_trickRequest = 0;
+ m_audioPts = 0;
+ m_videoPts = 0;
m_hasAudio = false;
m_hasVideo = false;
@@ -384,6 +473,7 @@ void cOmxDevice::ResetAudioVideo(bool flushVideoRender)
void cOmxDevice::SetVolumeDevice(int Volume)
{
+ DBG("SetVolume(%d)", Volume);
if (Volume)
{
m_omx->SetVolume(Volume);
diff --git a/omxdevice.h b/omxdevice.h
index d28543e..ac77823 100644
--- a/omxdevice.h
+++ b/omxdevice.h
@@ -9,7 +9,7 @@
#include <vdr/device.h>
-#include "types.h"
+#include "tools.h"
class cOmx;
class cAudioDecoder;
@@ -26,10 +26,17 @@ public:
virtual int Init(void);
virtual int DeInit(void);
- virtual bool HasDecoder(void) const { return true; };
- virtual bool CanReplay(void) const { return true; };
+ virtual bool HasDecoder(void) const { return true; }
+ virtual bool CanReplay(void) const { return true; }
+ virtual bool HasIBPTrickSpeed(void) { return true; }
virtual void GetOsdSize(int &Width, int &Height, double &PixelAspect);
+ virtual void GetVideoSize(int &Width, int &Height, double &VideoAspect);
+ virtual void SetVideoDisplayFormat(eVideoDisplayFormat VideoDisplayFormat);
+
+ virtual cRect CanScaleVideo(const cRect &Rect, int Alignment = taCenter)
+ { return Rect; }
+ virtual void ScaleVideo(const cRect &Rect = cRect::Null);
virtual bool SetPlayMode(ePlayMode PlayMode);
@@ -43,7 +50,7 @@ public:
virtual int64_t GetSTC(void);
- virtual bool HasIBPTrickSpeed(void) { return true; }
+ virtual uchar *GrabImage(int &Size, bool Jpeg = true, int Quality = -1, int SizeX = -1, int SizeY = -1);
#if APIVERSNUM >= 20103
virtual void TrickSpeed(int Speed, bool Forward);
@@ -57,7 +64,6 @@ public:
virtual void SetVolumeDevice(int Volume);
- virtual bool Flush(int TimeoutMs = 0);
virtual bool Poll(cPoller &Poller, int TimeoutMs = 0);
protected:
@@ -69,6 +75,10 @@ private:
void (*m_onPrimaryDevice)(void);
virtual cVideoCodec::eCodec ParseVideoCodec(const uchar *data, int length);
+ static void OnBufferStall(void *data)
+ { (static_cast <cOmxDevice*> (data))->HandleBufferStall(); }
+
+ void HandleBufferStall();
void ResetAudioVideo(bool flushVideoRender = false);
void ApplyTrickSpeed(int trickSpeed, bool forward = true);
diff --git a/ovgosd.c b/ovgosd.c
index 50b75bd..6574658 100644
--- a/ovgosd.c
+++ b/ovgosd.c
@@ -10,8 +10,33 @@
#include <GLES/gl.h>
#include "ovgosd.h"
+#include "display.h"
#include "omxdevice.h"
#include "setup.h"
+#include "tools.h"
+
+class cOvgOsd : public cOsd
+{
+
+public:
+
+ cOvgOsd(int Left, int Top, uint Level, cOvg *ovg);
+ virtual ~cOvgOsd();
+
+ virtual void Flush(void);
+ virtual eOsdError SetAreas(const tArea *Areas, int NumAreas);
+
+protected:
+
+ virtual void SetActive(bool On);
+
+private:
+
+ cOvg *m_ovg;
+
+};
+
+/* ------------------------------------------------------------------------- */
class cOvg : public cThread
{
@@ -21,7 +46,6 @@ public:
cThread(),
m_do(0),
m_done(0),
- m_mutex(0),
m_width(0),
m_height(0),
m_aspect(0),
@@ -37,7 +61,6 @@ public:
m_do = new cCondWait();
m_done = new cCondWait();
- m_mutex = new cMutex();
Start();
}
@@ -46,10 +69,11 @@ public:
{
Cancel(-1);
Clear();
+ while (Active())
+ cCondWait::SleepMs(50);
delete m_do;
delete m_done;
- delete m_mutex;
}
void GetDisplaySize(int &width, int &height, double &aspect)
@@ -61,7 +85,7 @@ public:
void DrawPixmap(int x, int y, int w, int h, int d, const uint8_t *data)
{
- m_mutex->Lock();
+ Lock();
m_pixmap = data;
m_d = d;
m_x = x;
@@ -70,34 +94,34 @@ public:
m_h = h;
m_do->Signal();
m_done->Wait();
- m_mutex->Unlock();
+ Unlock();
}
void Clear()
{
- m_mutex->Lock();
+ Lock();
m_clear = true;
m_do->Signal();
m_done->Wait();
- m_mutex->Unlock();
+ Unlock();
}
protected:
virtual void Action(void)
{
- dsyslog("rpihddevice: cOvg() thread started");
+ DLOG("cOvg() thread started");
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if (display == EGL_NO_DISPLAY)
- esyslog("rpihddevice: failed to get EGL display connection!");
+ ELOG("failed to get EGL display connection!");
if (eglInitialize(display, NULL, NULL) == EGL_FALSE)
- esyslog("rpihddevice: failed to init EGL display connection!");
+ ELOG("failed to init EGL display connection!");
eglBindAPI(EGL_OPENVG_API);
- const EGLint fbAttr[] = {
+ const EGLint attr[] = {
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
@@ -108,40 +132,20 @@ protected:
};
EGLConfig config;
- EGLint numConfig;
+ EGLint nConfig;
// get an appropriate EGL frame buffer configuration
- if (eglChooseConfig(display, fbAttr, &config, 1, &numConfig) == EGL_FALSE)
- esyslog("rpihddevice: failed to get EGL frame buffer config!");
+ if (eglChooseConfig(display, attr, &config, 1, &nConfig) == EGL_FALSE)
+ ELOG("failed to get EGL frame buffer config!");
// create an EGL rendering context
EGLContext context = eglCreateContext(display, config, NULL, NULL);
if (context == EGL_NO_CONTEXT)
- esyslog("rpihddevice: failed to create EGL rendering context!");
-
- DISPMANX_DISPLAY_HANDLE_T dispmanDisplay = vc_dispmanx_display_open(0 /* LCD */);
- DISPMANX_UPDATE_HANDLE_T dispmanUpdate = vc_dispmanx_update_start(0);
-
- VC_RECT_T dstRect = { 0, 0, m_width, m_height };
- VC_RECT_T srcRect = { 0, 0, m_width << 16, m_height << 16 };
-
- DISPMANX_ELEMENT_HANDLE_T dispmanElement = vc_dispmanx_element_add(
- 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
- DISPMANX_RESOURCE_HANDLE_T bgRsc = vc_dispmanx_resource_create(VC_IMAGE_RGB565, 1, 1, &pBgImage);
- vc_dispmanx_rect_set(&dstRect, 0, 0, 1, 1);
- vc_dispmanx_resource_write_data(bgRsc, VC_IMAGE_RGB565, sizeof(bgImage), &bgImage, &dstRect);
- vc_dispmanx_rect_set(&srcRect, 0, 0, 0, 0);
- 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);
+ ELOG("failed to create EGL rendering context!");
+
+ cRpiDisplay::Open(0 /* LCD */);
+ DISPMANX_ELEMENT_HANDLE_T dispmanElement;
+ cRpiDisplay::AddElement(dispmanElement, m_width, m_height, 2);
EGL_DISPMANX_WINDOW_T nativewindow;
nativewindow.element = dispmanElement;
@@ -153,13 +157,14 @@ protected:
EGL_NONE
};
- EGLSurface surface = eglCreateWindowSurface(display, config, &nativewindow, windowAttr);
+ EGLSurface surface = eglCreateWindowSurface(display, config,
+ &nativewindow, windowAttr);
if (surface == EGL_NO_SURFACE)
- esyslog("rpihddevice: failed to create EGL window surface!");
+ ELOG("failed to create EGL window surface!");
// connect the context to the surface
if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE)
- esyslog("rpihddevice: failed to connect context to surface!");
+ ELOG("failed to connect context to surface!");
float color[4] = {0.0f, 0.0f, 0.0f, 0.0f};
vgSetfv(VG_CLEAR_COLOR, 4, color);
@@ -175,7 +180,8 @@ protected:
vgScale(1.0f, -1.0f);
vgTranslate(0.0f, -m_height);
- VGImage image = vgCreateImage(VG_sARGB_8888, m_width, m_height, VG_IMAGE_QUALITY_BETTER);
+ VGImage image = vgCreateImage(VG_sARGB_8888, m_width, m_height,
+ VG_IMAGE_QUALITY_BETTER);
while (Running())
{
@@ -183,7 +189,8 @@ protected:
if (m_pixmap)
{
vgClearImage(image, m_x, m_y, m_w, m_h);
- vgImageSubData(image, m_pixmap, m_d, VG_sARGB_8888, m_x, m_y, m_w, m_h);
+ vgImageSubData(image, m_pixmap, m_d, VG_sARGB_8888,
+ m_x, m_y, m_w, m_h);
vgDrawImage(image);
m_pixmap = 0;
}
@@ -204,19 +211,21 @@ protected:
eglSwapBuffers(display, surface);
// Release OpenGL resources
- eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ eglMakeCurrent(display,
+ EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglDestroySurface(display, surface);
eglDestroyContext(display, context);
eglTerminate(display);
- dsyslog("rpihddevice: cOvg() thread ended");
+ cRpiDisplay::Close();
+
+ DLOG("cOvg() thread ended");
}
private:
cCondWait* m_do;
cCondWait* m_done;
- cMutex* m_mutex;
int m_width;
int m_height;
@@ -237,13 +246,13 @@ cRpiOsdProvider::cRpiOsdProvider() :
cOsdProvider(),
m_ovg(0)
{
- dsyslog("rpihddevice: new cOsdProvider()");
+ DLOG("new cOsdProvider()");
m_ovg = new cOvg();
}
cRpiOsdProvider::~cRpiOsdProvider()
{
- dsyslog("rpihddevice: delete cOsdProvider()");
+ DLOG("delete cOsdProvider()");
delete m_ovg;
}
@@ -252,6 +261,8 @@ cOsd *cRpiOsdProvider::CreateOsd(int Left, int Top, uint Level)
return new cOvgOsd(Left, Top, Level, m_ovg);
}
+/* ------------------------------------------------------------------------- */
+
cOvgOsd::cOvgOsd(int Left, int Top, uint Level, cOvg *ovg) :
cOsd(Left, Top, Level),
m_ovg(ovg)
@@ -304,3 +315,31 @@ void cOvgOsd::Flush(void)
}
}
+eOsdError cOvgOsd::SetAreas(const tArea *Areas, int NumAreas)
+{
+ eOsdError error;
+ cBitmap * bitmap;
+
+ if (Active())
+ m_ovg->Clear();
+
+ error = cOsd::SetAreas(Areas, NumAreas);
+
+ for (int i = 0; (bitmap = GetBitmap(i)) != NULL; i++)
+ bitmap->Clean();
+
+ return error;
+}
+
+void cOvgOsd::SetActive(bool On)
+{
+ if (On != Active())
+ {
+ cOsd::SetActive(On);
+ if (!On)
+ m_ovg->Clear();
+ else
+ if (GetBitmap(0))
+ Flush();
+ }
+}
diff --git a/ovgosd.h b/ovgosd.h
index d4a7c0d..311e33a 100644
--- a/ovgosd.h
+++ b/ovgosd.h
@@ -31,22 +31,5 @@ private:
cOvg *m_ovg;
};
-
-class cOvgOsd : public cOsd
-{
-
-public:
-
- cOvgOsd(int Left, int Top, uint Level, cOvg *ovg);
- virtual ~cOvgOsd();
-
- virtual void Flush(void);
-
-private:
-
- cOvg *m_ovg;
-
-};
-
#endif
diff --git a/po/de_DE.po b/po/de_DE.po
index 6976645..658e571 100644
--- a/po/de_DE.po
+++ b/po/de_DE.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: vdr-rpihddevice 0.0.4\n"
"Report-Msgid-Bugs-To: <see README>\n"
-"POT-Creation-Date: 2013-12-08 12:29+0100\n"
+"POT-Creation-Date: 2014-01-11 15:12+0100\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"
@@ -20,6 +20,9 @@ msgstr ""
msgid "video format not supported!"
msgstr "Videoformat nicht unterstützt!"
+msgid "HD output device for Raspberry Pi"
+msgstr "HD Ausgabegerät für Raspberry Pi"
+
msgid "analog"
msgstr "analog"
diff --git a/rpihddevice.c b/rpihddevice.c
index 03c0813..5f22b39 100644
--- a/rpihddevice.c
+++ b/rpihddevice.c
@@ -10,10 +10,10 @@
#include "ovgosd.h"
#include "omxdevice.h"
#include "setup.h"
-#include "types.h"
+#include "tools.h"
-static const char *VERSION = "0.0.7";
-static const char *DESCRIPTION = "HD output device for Raspberry Pi";
+static const char *VERSION = "0.0.8";
+static const char *DESCRIPTION = tr("HD output device for Raspberry Pi");
class cDummyDevice : cDevice
{
@@ -81,7 +81,7 @@ bool cPluginRpiHdDevice::Initialize(void)
// test whether MPEG2 license is available
if (!cRpiSetup::IsVideoCodecSupported(cVideoCodec::eMPEG2))
- dsyslog("rpihddevice: MPEG2 video decoder not enabled!");
+ DLOG("MPEG2 video decoder not enabled!");
m_device = new cOmxDevice(&OnPrimaryDevice);
@@ -98,8 +98,6 @@ bool cPluginRpiHdDevice::Start(void)
void cPluginRpiHdDevice::Stop(void)
{
- if (m_device)
- m_device->DeInit();
}
cMenuSetupPage* cPluginRpiHdDevice::SetupMenu(void)
diff --git a/setup.c b/setup.c
index de2a4af..8a1697f 100644
--- a/setup.c
+++ b/setup.c
@@ -27,6 +27,8 @@ void cRpiSetup::DropInstance(void)
{
delete s_instance;
s_instance = 0;
+
+ bcm_host_deinit();
}
class cRpiSetupPage : public cMenuSetupPage
@@ -77,25 +79,6 @@ private:
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"))
{
@@ -107,23 +90,52 @@ bool cRpiSetup::HwInit(void)
}
}
+ int height = 0, width = 0;
+ bool progressive = false;
+ cVideoPort::ePort port = cVideoPort::eComposite;
+
+ 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;
+ height = tvstate.display.hdmi.height;
+ width = tvstate.display.hdmi.width;
+ port = cVideoPort::eHDMI;
+ }
+ else
+ {
+ height = tvstate.display.sdtv.height;
+ width = tvstate.display.sdtv.width;
+ }
+
+ ILOG("using %s video output at %dx%d%s",
+ cVideoPort::Str(port), width, height, progressive ? "p" : "i");
+
+ GetInstance()->m_isProgressive = progressive;
+ GetInstance()->m_displayHeight = height;
+ GetInstance()->m_displayWidth = width;
+ }
+ else
+ {
+ ELOG("failed to get display parameters!");
+ return false;
+ }
+
return true;
}
bool cRpiSetup::IsAudioFormatSupported(cAudioCodec::eCodec codec,
int channels, int samplingRate)
{
- // 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 :
+ codec == cAudioCodec::eAAC ? EDID_AudioFormat_eAAC :
EDID_AudioFormat_ePCM, channels,
samplingRate == 32000 ? EDID_AudioSampleRate_e32KHz :
samplingRate == 44100 ? EDID_AudioSampleRate_e44KHz :
@@ -135,7 +147,7 @@ bool cRpiSetup::IsAudioFormatSupported(cAudioCodec::eCodec codec,
EDID_AudioSampleSize_16bit) == 0)
return true;
- dsyslog("rpihddevice: %dch %s, %d.%dkHz not supported by HDMI device",
+ DLOG("%dch %s, %d.%dkHz not supported by HDMI device",
channels, cAudioCodec::Str(codec),
samplingRate / 1000, (samplingRate % 1000) / 100);
@@ -144,41 +156,10 @@ bool cRpiSetup::IsAudioFormatSupported(cAudioCodec::eCodec codec,
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::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;
+ height = GetInstance()->m_displayHeight;
+ width = GetInstance()->m_displayWidth;
+ aspect = (double)width / height;
+ return 0;
}
bool cRpiSetup::HasAudioSetupChanged(void)
diff --git a/setup.h b/setup.h
index a5ee414..6951a96 100644
--- a/setup.h
+++ b/setup.h
@@ -8,7 +8,7 @@
#define SETUP_H
#include "omx.h"
-#include "types.h"
+#include "tools.h"
class cRpiSetup
{
@@ -34,7 +34,9 @@ public:
}
static int GetDisplaySize(int &width, int &height, double &aspect);
- static bool IsDisplayProgressive(void);
+
+ static bool IsDisplayProgressive(void) {
+ return GetInstance()->m_isProgressive; }
static cRpiSetup* GetInstance(void);
static void DropInstance(void);
@@ -44,7 +46,13 @@ public:
private:
- cRpiSetup() : m_audioSetupChanged(false), m_mpeg2Enabled(false) { }
+ cRpiSetup() :
+ m_audioSetupChanged(false),
+ m_mpeg2Enabled(false),
+ m_isProgressive(false),
+ m_displayHeight(0),
+ m_displayWidth(0) { }
+
virtual ~cRpiSetup() { }
static cRpiSetup* s_instance;
@@ -55,6 +63,10 @@ private:
bool m_audioSetupChanged;
bool m_mpeg2Enabled;
+ bool m_isProgressive;
+
+ int m_displayHeight;
+ int m_displayWidth;
};
#endif
diff --git a/tools.h b/tools.h
new file mode 100644
index 0000000..e5a2b6d
--- /dev/null
+++ b/tools.h
@@ -0,0 +1,90 @@
+/*
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id$
+ */
+
+#ifndef TOOLS_H
+#define TOOLS_H
+
+#define ELOG(a...) esyslog("rpihddevice: " a)
+#define ILOG(a...) isyslog("rpihddevice: " a)
+#define DLOG(a...) dsyslog("rpihddevice: " a)
+
+#ifdef DEBUG
+#define DBG(a...) dsyslog("rpihddevice: " a)
+#else
+#define DBG(a...) void()
+#endif
+
+class cAudioCodec
+{
+public:
+
+ enum eCodec {
+ ePCM,
+ eMPG,
+ eAC3,
+ eEAC3,
+ eAAC,
+ eNumCodecs,
+ eInvalid
+ };
+
+ static const char* Str(eCodec codec) {
+ return (codec == ePCM) ? "PCM" :
+ (codec == eMPG) ? "MPEG" :
+ (codec == eAC3) ? "AC3" :
+ (codec == eEAC3) ? "E-AC3" :
+ (codec == eAAC) ? "AAC" : "unknown";
+ }
+};
+
+class cVideoCodec
+{
+public:
+
+ enum eCodec {
+ eMPEG2,
+ eH264,
+ eNumCodecs,
+ eInvalid
+ };
+
+ static const char* Str(eCodec codec) {
+ return (codec == eMPEG2) ? "MPEG2" :
+ (codec == eH264) ? "H264" : "unknown";
+ }
+};
+
+class cAudioPort
+{
+public:
+
+ enum ePort {
+ eLocal,
+ eHDMI
+ };
+
+ static const char* Str(ePort port) {
+ return (port == eLocal) ? "local" :
+ (port == eHDMI) ? "HDMI" : "unknown";
+ }
+};
+
+class cVideoPort
+{
+public:
+
+ enum ePort {
+ eComposite,
+ eHDMI
+ };
+
+ static const char* Str(ePort port) {
+ return (port == eComposite) ? "composite" :
+ (port == eHDMI) ? "HDMI" : "unknown";
+ }
+};
+
+#endif