summaryrefslogtreecommitdiff
path: root/omxdevice.c
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 /omxdevice.c
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
Diffstat (limited to 'omxdevice.c')
-rw-r--r--omxdevice.c192
1 files changed, 141 insertions, 51 deletions
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);