diff options
author | Thomas Reufer <thomas@reufer.ch> | 2014-02-10 21:53:25 +0100 |
---|---|---|
committer | Thomas Reufer <thomas@reufer.ch> | 2014-02-10 21:53:25 +0100 |
commit | 0094472cda6eefa9b5363ad844daf0fcfd00c326 (patch) | |
tree | b577f931820ef3899da856f9ccd0de04f4c8ffa8 /omxdevice.c | |
parent | 88f137d194b1768344e954a1b1d35fb1fce03df9 (diff) | |
download | vdr-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.c | 192 |
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); |