diff options
-rw-r--r-- | HISTORY | 19 | ||||
-rw-r--r-- | Makefile | 9 | ||||
-rw-r--r-- | omxdevice.c | 311 | ||||
-rw-r--r-- | omxdevice.h | 30 | ||||
-rw-r--r-- | rpihddevice.c | 6 |
5 files changed, 267 insertions, 108 deletions
@@ -1,9 +1,23 @@ VDR Plugin 'rpihddevice' Revision History ----------------------------------------- -2013-09-27: Version 0.0.1 +2013-09-29: Version 0.0.2 +------------------------- +- new: + - volume control + - H264 support +- fixed: + - added missing includes to Makefile + - PTS/OMX_TICKS conversion +- missing: + - audio only play mode + - buffer handling for proper replay support + - other audio formats + - much more... -Initial prototype +2013-09-27: Version 0.0.1 +------------------------- +initial prototype - limitations: - video codec hard coded to MPEG2, output on HDMI - audio codec hard coded to MP3, output on phone jack @@ -14,4 +28,3 @@ Initial prototype - dynamic switching between MPEG2 and H264 video codec - trick speeds - much more... - @@ -51,16 +51,15 @@ DEFINES += -DPLUGIN_NAME_I18N='"$(PLUGIN)"' DEFINES += -DHAVE_LIBOPENMAX=2 -DOMX -DOMX_SKIP64BIT -DUSE_EXTERNAL_OMX -DHAVE_LIBBCM_HOST -DUSE_EXTERNAL_LIBBCM_HOST -DUSE_VCHIQ_ARM DEFINES += -Wno-write-strings -fpermissive -INCLUDES += -I/opt/vc/include/ -I/opt/vc/include/interface/vcos/pthreads +ILCDIR =ilclient +VCINCDIR =/opt/vc/include +VCLIBDIR =/opt/vc/lib -ILCDIR = ilclient -VCLIBDIR = /opt/vc/lib +INCLUDES += -I$(ILCDIR) -I$(VCINCDIR) -I$(VCINCDIR)/interface/vcos/pthreads -I$(VCINCDIR)/interface/vmcs_host/linux LDFLAGS += -L$(VCLIBDIR) -lbcm_host -lvcos -lvchiq_arm -lopenmaxil -lGLESv2 -lEGL -lpthread -lrt -lmpg123 LDFLAGS += -Wl,--whole-archive $(ILCDIR)/libilclient.a -Wl,--no-whole-archive -# -I/opt/vc/src/hello_pi/libs/vgfont - ### The object files (add further files here): ILCLIENT = $(ILCDIR)/libilclient.a diff --git a/omxdevice.c b/omxdevice.c index 2034e51..b4f7167 100644 --- a/omxdevice.c +++ b/omxdevice.c @@ -3,6 +3,7 @@ * * $Id$ */ +//#pragma pack(1) #include "omxdevice.h" @@ -130,7 +131,8 @@ public: static uint64_t TicksToPts(OMX_TICKS &ticks) { // pts = ticks * PTSTICKS / OMX_TICKS_PER_SECOND - uint64_t pts = ticks.nHighPart << 32 + ticks.nLowPart; + uint64_t pts = ticks.nHighPart; + pts = (pts << 32) + ticks.nLowPart; pts = pts * 9 / 100; return pts; } @@ -146,6 +148,7 @@ public: sampleRate(0), bitDepth(0), nChannels(0), + encoding(0), m_handle(0) { int ret; @@ -166,17 +169,23 @@ public: dsyslog("rpihddevice: delete cAudio()"); } - unsigned int decode(const unsigned char *inbuf, unsigned int length, unsigned char *outbuf, unsigned int bufsize) + bool writeData(const unsigned char *buf, unsigned int length) { - unsigned int done = 0; - if (mpg123_decode(m_handle, inbuf, length, outbuf, bufsize, &done) == MPG123_ERR) - esyslog("rpihddevice: failed to decode audio data!"); - return done; + return (mpg123_feed(m_handle, buf, length) != MPG123_ERR); } - int sampleRate; + unsigned int readSamples(unsigned char *buf, unsigned length, bool &done) + { + unsigned int read = 0; + done = (mpg123_read(m_handle, buf, length, &read) == MPG123_NEED_MORE); + mpg123_getformat(m_handle, &sampleRate, &nChannels, &encoding); + return read; + } + + long sampleRate; int bitDepth; int nChannels; + int encoding; mpg123_handle *m_handle; }; @@ -191,6 +200,8 @@ cOmxDevice::cOmxDevice(void (*onPrimaryDevice)(void)) : m_firstVideoPacket(false), m_firstAudioPacket(false) { + bcm_host_init(); + m_eosEvent = new cCondWait(); m_mutex = new cMutex(); } @@ -226,13 +237,16 @@ bool cOmxDevice::SetPlayMode(ePlayMode PlayMode) break; case pmAudioVideo: - Start(); + Start(eAudioVideo); break; case pmAudioOnly: case pmAudioOnlyBlack: - case pmVideoOnly: + Start(eAudioOnly); + break; + case pmVideoOnly: + Start(eVideoOnly); break; } @@ -269,31 +283,44 @@ int cOmxDevice::PlayAudio(const uchar *Data, int Length, uchar Id) return Length; } - if (m_firstAudioPacket) - OmxSetAudioCodec(payload); + if (m_firstAudioPacket && !OmxSetAudioCodec(payload)) + { + m_mutex->Unlock(); + return Length; + } - OMX_BUFFERHEADERTYPE *buf = ilclient_get_input_buffer(m_omx->comp[cOmx::eAudioRender], 100, 1); - if (buf == NULL) + if (!m_audio->writeData(payload, length)) { - esyslog("rpihddevice: failed to get audio buffer!"); + esyslog("rpihddevice: failed to pass buffer to audio decoder!"); m_mutex->Unlock(); return 0; } - // decode audio packet - buf->nFilledLen = m_audio->decode(payload, length, buf->pBuffer, buf->nAllocLen); - - buf->nFlags = m_firstAudioPacket ? OMX_BUFFERFLAG_STARTTIME : 0; - cOmx::PtsToTicks(pts, buf->nTimeStamp); + bool done = false; + while (!done) + { + OMX_BUFFERHEADERTYPE *buf = ilclient_get_input_buffer(m_omx->comp[cOmx::eAudioRender], 100, 0); + if (buf == NULL) + { + esyslog("rpihddevice: failed to get audio buffer!"); + m_mutex->Unlock(); + return Length; + } -// dsyslog("A: %u.%u - %lld", buf->nTimeStamp.nHighPart, buf->nTimeStamp.nLowPart, pts); -// dsyslog("rpihddevice: PlayAudio(%u.%u, %02x %02x %02x %02x, %d)", buf->nTimeStamp.nHighPart, buf->nTimeStamp.nLowPart, -// buf->pBuffer[0], buf->pBuffer[1], buf->pBuffer[2], buf->pBuffer[3], buf->nFilledLen); + // decode audio packet + buf->nFilledLen = m_audio->readSamples(buf->pBuffer, buf->nAllocLen, done); + cOmx::PtsToTicks(pts, buf->nTimeStamp); + buf->nFlags = m_firstAudioPacket ? OMX_BUFFERFLAG_STARTTIME : 0; //OMX_BUFFERFLAG_TIME_UNKNOWN; + m_firstAudioPacket = false; - if (OMX_EmptyThisBuffer(ILC_GET_HANDLE(m_omx->comp[cOmx::eAudioRender]), buf) != OMX_ErrorNone) - esyslog("rpihddevice: failed to pass buffer to audio render!"); +// dsyslog("A: %u.%u - f:%d %lld", buf->nTimeStamp.nHighPart, buf->nTimeStamp.nLowPart, buf->nFlags, pts); - m_firstAudioPacket = false; + if (OMX_EmptyThisBuffer(ILC_GET_HANDLE(m_omx->comp[cOmx::eAudioRender]), buf) != OMX_ErrorNone) + { + esyslog("rpihddevice: failed to pass buffer to audio render!"); + break; + } + } m_mutex->Unlock(); return Length; @@ -322,28 +349,30 @@ int cOmxDevice::PlayVideo(const uchar *Data, int Length) const uchar *payload = Data + PesPayloadOffset(Data); int length = PesLength(Data) - PesPayloadOffset(Data); - // first packet of a new stream needs valid PTS and MPEG start code - if (m_firstVideoPacket && - (pts == 0 || !(payload[0] == 0x00 && payload[1] == 0x00 && - payload[2] == 0x01 && payload[3] == 0xb3))) + // first packet of a new stream needs valid PTS + if (m_firstVideoPacket && pts == 0) { + esyslog("rpihddevice: PTS missing for first video packet!"); m_mutex->Unlock(); return Length; } - if (m_firstVideoPacket) - OmxSetVideoCodec(payload); + if (m_firstVideoPacket && !OmxSetVideoCodec(payload)) + { + m_mutex->Unlock(); + return Length; + } - OMX_BUFFERHEADERTYPE *buf = ilclient_get_input_buffer(m_omx->comp[cOmx::eVideoDecoder], 130, 1); + OMX_BUFFERHEADERTYPE *buf = ilclient_get_input_buffer(m_omx->comp[cOmx::eVideoDecoder], 130, 0); if (buf == NULL) { esyslog("rpihddevice: failed to get video buffer!"); m_mutex->Unlock(); - return 0; + return Length; } cOmx::PtsToTicks(pts, buf->nTimeStamp); - buf->nFlags = m_firstVideoPacket ? OMX_BUFFERFLAG_STARTTIME : OMX_BUFFERFLAG_TIME_UNKNOWN; + buf->nFlags = m_firstVideoPacket ? OMX_BUFFERFLAG_STARTTIME : 0; //OMX_BUFFERFLAG_TIME_UNKNOWN; if (length <= buf->nAllocLen) { @@ -353,9 +382,10 @@ int cOmxDevice::PlayVideo(const uchar *Data, int Length) else esyslog("rpihddevice: video packet too long for video buffer!"); -// dsyslog("V: %u.%u - %lld", buf->nTimeStamp.nHighPart, buf->nTimeStamp.nLowPart, pts); -// dsyslog("rpihddevice: PlayVideo(%u.%u, %02x %02x %02x %02x, %d)", buf->nTimeStamp.nHighPart, buf->nTimeStamp.nLowPart, -// buf->pBuffer[0], buf->pBuffer[1], buf->pBuffer[2], buf->pBuffer[3], buf->nFilledLen); +// dsyslog("V: %u.%u - f:%d %lld", buf->nTimeStamp.nHighPart, buf->nTimeStamp.nLowPart, buf->nFlags, pts); +// dsyslog("rpihddevice: PlayVideo(%u.%u, %02x %02x %02x %02x %02x %02x %02x %02x, %d)", buf->nTimeStamp.nHighPart, buf->nTimeStamp.nLowPart, +// buf->pBuffer[0], buf->pBuffer[1], buf->pBuffer[2], buf->pBuffer[3], +// buf->pBuffer[4], buf->pBuffer[5], buf->pBuffer[6], buf->pBuffer[7], buf->nFilledLen); if (OMX_EmptyThisBuffer(ILC_GET_HANDLE(m_omx->comp[cOmx::eVideoDecoder]), buf) != OMX_ErrorNone) esyslog("rpihddevice: failed to pass buffer to video decoder!"); @@ -370,9 +400,10 @@ int64_t cOmxDevice::GetSTC(void) { int64_t stc = -1; -/* OMX_TIME_CONFIG_TIMESTAMPTYPE timestamp; + OMX_TIME_CONFIG_TIMESTAMPTYPE timestamp; memset(×tamp, 0, sizeof(timestamp)); timestamp.nSize = sizeof(timestamp); + timestamp.nPortIndex = OMX_ALL; timestamp.nVersion.nVersion = OMX_VERSION; if (OMX_GetConfig(ILC_GET_HANDLE(m_omx->comp[cOmx::eClock]), @@ -381,24 +412,65 @@ int64_t cOmxDevice::GetSTC(void) else stc = cOmx::TicksToPts(timestamp.nTimestamp); - dsyslog("rpihddevice: GetSTC() = %llu", stc); -*/ + dsyslog("-: %d.%d - %llu", timestamp.nTimestamp.nHighPart, timestamp.nTimestamp.nLowPart, stc); + return stc; } void cOmxDevice::Play(void) { dsyslog("rpihddevice: Play()"); + SetClockScale(1.0f); +} + +void cOmxDevice::Freeze(void) +{ + dsyslog("rpihddevice: Freeze()"); + SetClockScale(0.0f); +} +void cOmxDevice::TrickSpeed(int Speed) +{ + dsyslog("rpihddevice: TrickSpeed(%d)", Speed); } bool cOmxDevice::Flush(int TimeoutMs) { - dsyslog("rpihddevice: flush()"); + dsyslog("rpihddevice: Flush()"); return true; } +void cOmxDevice::Clear(void) +{ + dsyslog("rpihddevice: Clear()"); + cDevice::Clear(); +} + +void cOmxDevice::SetVolumeDevice(int Volume) +{ + dsyslog("rpihddevice: SetVolumeDevice(%d)", Volume); + + OMX_AUDIO_CONFIG_VOLUMETYPE volume; + memset(&volume, 0, sizeof(volume)); + volume.nSize = sizeof(volume); + volume.nVersion.nVersion = OMX_VERSION; + volume.nPortIndex = 100; + volume.bLinear = OMX_TRUE; + volume.sVolume.nValue = Volume * 100 / 255; + + if (OMX_SetConfig(ILC_GET_HANDLE(m_omx->comp[cOmx::eAudioRender]), + OMX_IndexConfigAudioVolume, &volume) != OMX_ErrorNone) + esyslog("rpihddevice: failed to set volume!"); +} + +bool cOmxDevice::Poll(cPoller &Poller, int TimeoutMs) +{ + dsyslog("rpihddevice: Poll()"); + + return false; +} + void cOmxDevice::MakePrimaryDevice(bool On) { if (On && m_onPrimaryDevice) @@ -456,26 +528,46 @@ void cOmxDevice::HandlePortSettingsChanged(unsigned int portId) } } -void cOmxDevice::SetClockState(eClockState clockState) +bool cOmxDevice::IsClockRunning() { - dsyslog("rpihddevice: SetClockState(%s)", + OMX_TIME_CONFIG_CLOCKSTATETYPE cstate; + memset(&cstate, 0, sizeof(cstate)); + cstate.nSize = sizeof(cstate); + cstate.nVersion.nVersion = OMX_VERSION; + + if (OMX_GetConfig(ILC_GET_HANDLE(m_omx->comp[cOmx::eClock]), + OMX_IndexConfigTimeClockState, &cstate) != OMX_ErrorNone) + esyslog("rpihddevice: failed get clock state!"); + + if (cstate.eState == OMX_TIME_ClockStateRunning) + return true; + else + return false; +} + +void cOmxDevice::SetClockState(eClockState clockState, bool armVideo, bool armAudio) +{ + dsyslog("rpihddevice: SetClockState(%s, %s, %s)", clockState == eClockStateRunning ? "eClockStateRunning" : clockState == eClockStateStopped ? "eClockStateStopped" : - clockState == eClockStateWaiting ? "eClockStateWaiting" : "unknown"); + clockState == eClockStateWaiting ? "eClockStateWaiting" : "unknown", + armVideo ? "true" : "false", armAudio ? "true" : "false"); OMX_TIME_CONFIG_CLOCKSTATETYPE cstate; memset(&cstate, 0, sizeof(cstate)); cstate.nSize = sizeof(cstate); cstate.nVersion.nVersion = OMX_VERSION; - if (OMX_GetConfig(ILC_GET_HANDLE(m_omx->comp[cOmx::eClock]), OMX_IndexConfigTimeClockState, &cstate) != OMX_ErrorNone) + if (OMX_GetConfig(ILC_GET_HANDLE(m_omx->comp[cOmx::eClock]), + OMX_IndexConfigTimeClockState, &cstate) != OMX_ErrorNone) esyslog("rpihddevice: failed get clock state!"); if ((clockState == eClockStateWaiting) && (cstate.eState == OMX_TIME_ClockStateRunning)) { esyslog("rpihddevice: need to disable clock first!"); cstate.eState = OMX_TIME_ClockStateStopped; - if (OMX_SetConfig(ILC_GET_HANDLE(m_omx->comp[cOmx::eClock]), OMX_IndexConfigTimeClockState, &cstate) != OMX_ErrorNone) + if (OMX_SetConfig(ILC_GET_HANDLE(m_omx->comp[cOmx::eClock]), + OMX_IndexConfigTimeClockState, &cstate) != OMX_ErrorNone) esyslog("rpihddevice: failed set clock state!"); } @@ -491,21 +583,27 @@ void cOmxDevice::SetClockState(eClockState clockState) case eClockStateWaiting: cstate.eState = OMX_TIME_ClockStateWaitingForStartTime; - cstate.nWaitMask = OMX_CLOCKPORT0 | OMX_CLOCKPORT1; + cstate.nWaitMask = (armVideo ? OMX_CLOCKPORT0 : 0) | (armAudio ? OMX_CLOCKPORT1 : 0); break; } - if (OMX_SetConfig(ILC_GET_HANDLE(m_omx->comp[cOmx::eClock]), OMX_IndexConfigTimeClockState, &cstate) != OMX_ErrorNone) + esyslog("rpihddevice: wait mask: %d", cstate.nWaitMask); + + if (OMX_SetConfig(ILC_GET_HANDLE(m_omx->comp[cOmx::eClock]), + OMX_IndexConfigTimeClockState, &cstate) != OMX_ErrorNone) esyslog("rpihddevice: failed set clock state!"); } -void cOmxDevice::SetClockScale(int scale) +void cOmxDevice::SetClockScale(float scale) { OMX_TIME_CONFIG_SCALETYPE scaleType; memset(&scaleType, 0, sizeof(scaleType)); - scaleType.xScale = scale; - if (OMX_SetConfig(ILC_GET_HANDLE(m_omx->comp[cOmx::eClock]), OMX_IndexConfigTimeScale, &scaleType) != OMX_ErrorNone) - esyslog("rpihddevice: failed configuring clock!"); + scaleType.xScale = floor(scale * pow(2, 16)); + if (OMX_SetConfig(ILC_GET_HANDLE(m_omx->comp[cOmx::eClock]), + OMX_IndexConfigTimeScale, &scaleType) != OMX_ErrorNone) + esyslog("rpihddevice: failed to set clock scale (%d)!", scaleType.xScale); + else + dsyslog("rpihddevice: set clock scale to %.2f (%d)", scale, scaleType.xScale); } int cOmxDevice::OmxInit() @@ -526,7 +624,8 @@ int cOmxDevice::OmxInit() // create video_decode if (ilclient_create_component(m_omx->client, &m_omx->comp[cOmx::eVideoDecoder], - "video_decode", (ILCLIENT_CREATE_FLAGS_T)(ILCLIENT_DISABLE_ALL_PORTS | ILCLIENT_ENABLE_INPUT_BUFFERS)) != 0) + "video_decode", (ILCLIENT_CREATE_FLAGS_T) + (ILCLIENT_DISABLE_ALL_PORTS | ILCLIENT_ENABLE_INPUT_BUFFERS)) != 0) esyslog("rpihddevice: failed creating video decoder!"); // create video_render @@ -541,7 +640,8 @@ int cOmxDevice::OmxInit() // create audio_render if (ilclient_create_component(m_omx->client, &m_omx->comp[cOmx::eAudioRender], - "audio_render", (ILCLIENT_CREATE_FLAGS_T)(ILCLIENT_DISABLE_ALL_PORTS | ILCLIENT_ENABLE_INPUT_BUFFERS)) != 0) + "audio_render", (ILCLIENT_CREATE_FLAGS_T) + (ILCLIENT_DISABLE_ALL_PORTS | ILCLIENT_ENABLE_INPUT_BUFFERS)) != 0) esyslog("rpihddevice: failed creating audio render!"); //create video_scheduler @@ -576,26 +676,27 @@ int cOmxDevice::OmxInit() refclock.eClock = OMX_TIME_RefClockAudio; // refclock.eClock = OMX_TIME_RefClockVideo; - if (OMX_SetConfig(ILC_GET_HANDLE(m_omx->comp[cOmx::eClock]), OMX_IndexConfigTimeActiveRefClock, &refclock) != OMX_ErrorNone) + if (OMX_SetConfig(ILC_GET_HANDLE(m_omx->comp[cOmx::eClock]), + OMX_IndexConfigTimeActiveRefClock, &refclock) != OMX_ErrorNone) esyslog("rpihddevice: failed set active clock reference!"); ilclient_change_component_state(m_omx->comp[cOmx::eClock], OMX_StateExecuting); ilclient_change_component_state(m_omx->comp[cOmx::eVideoDecoder], OMX_StateIdle); + // set up the number and size of buffers for audio render OMX_PARAM_PORTDEFINITIONTYPE param; memset(¶m, 0, sizeof(param)); param.nSize = sizeof(param); param.nVersion.nVersion = OMX_VERSION; param.nPortIndex = 100; - if (OMX_GetParameter(ILC_GET_HANDLE(m_omx->comp[cOmx::eAudioRender]), OMX_IndexParamPortDefinition, ¶m) != OMX_ErrorNone) + if (OMX_GetParameter(ILC_GET_HANDLE(m_omx->comp[cOmx::eAudioRender]), + OMX_IndexParamPortDefinition, ¶m) != OMX_ErrorNone) esyslog("rpihddevice: failed to get audio render port parameters!"); - - // set up the number and size of buffers param.nBufferSize = 65536; - param.nBufferSize = (param.nBufferSize + 15) & ~15; // 16 byte aligned - param.nBufferCountActual = 16; - if (OMX_SetParameter(ILC_GET_HANDLE(m_omx->comp[cOmx::eAudioRender]), OMX_IndexParamPortDefinition, ¶m) != OMX_ErrorNone) - esyslog("rpihddevice: failed to get audio render port parameters!"); + param.nBufferCountActual = 64; + if (OMX_SetParameter(ILC_GET_HANDLE(m_omx->comp[cOmx::eAudioRender]), + OMX_IndexParamPortDefinition, ¶m) != OMX_ErrorNone) + esyslog("rpihddevice: failed to set audio render port parameters!"); // configure audio render OMX_AUDIO_PARAM_PCMMODETYPE pcmMode; @@ -613,7 +714,8 @@ int cOmxDevice::OmxInit() pcmMode.eChannelMapping[0] = OMX_AUDIO_ChannelLF; pcmMode.eChannelMapping[1] = OMX_AUDIO_ChannelRF; - if (OMX_SetParameter(ILC_GET_HANDLE(m_omx->comp[cOmx::eAudioRender]), OMX_IndexParamAudioPcm, &pcmMode) != OMX_ErrorNone) + if (OMX_SetParameter(ILC_GET_HANDLE(m_omx->comp[cOmx::eAudioRender]), + OMX_IndexParamAudioPcm, &pcmMode) != OMX_ErrorNone) esyslog("rpihddevice: failed to set audio render parameters!"); OMX_CONFIG_BRCMAUDIODESTINATIONTYPE audioDest; @@ -622,13 +724,17 @@ int cOmxDevice::OmxInit() audioDest.nVersion.nVersion = OMX_VERSION; strcpy((char *)audioDest.sName, "local"); - if (OMX_SetConfig(ILC_GET_HANDLE(m_omx->comp[cOmx::eAudioRender]), OMX_IndexConfigBrcmAudioDestination, &audioDest) != OMX_ErrorNone) + if (OMX_SetConfig(ILC_GET_HANDLE(m_omx->comp[cOmx::eAudioRender]), + OMX_IndexConfigBrcmAudioDestination, &audioDest) != OMX_ErrorNone) esyslog("rpihddevice: failed to set audio destination!"); +// if (ilclient_enable_port_buffers(m_omx->comp[cOmx::eAudioRender], 100, NULL, NULL, NULL) != 0) +// esyslog("rpihddevice: failed to enable port buffer on audio render!"); + return 0; } -void cOmxDevice::Start() +void cOmxDevice::Start(eMode mode) { dsyslog("rpihddevice: Start()"); m_mutex->Lock(); @@ -637,7 +743,9 @@ void cOmxDevice::Start() m_firstVideoPacket = true; m_firstAudioPacket = true; - SetClockState(eClockStateWaiting); + SetClockState(eClockStateWaiting, + (mode == eAudioVideo || mode == eVideoOnly), + (mode == eAudioVideo || mode == eAudioOnly)); m_mutex->Unlock(); dsyslog("rpihddevice: Start() end"); @@ -649,20 +757,24 @@ void cOmxDevice::Stop() m_mutex->Lock(); m_state = eStop; -/* - OMX_BUFFERHEADERTYPE *buf = ilclient_get_input_buffer(m_omx->comp[cOmx::eVideoDecoder], 130, 1); - if (buf == NULL) - return; - buf->nFilledLen = 0; - buf->nFlags = OMX_BUFFERFLAG_TIME_UNKNOWN | OMX_BUFFERFLAG_EOS; + // really necessary? + if (false && IsClockRunning()) + { + OMX_BUFFERHEADERTYPE *buf = ilclient_get_input_buffer(m_omx->comp[cOmx::eVideoDecoder], 130, 1); + if (buf == NULL) + return; - if (OMX_EmptyThisBuffer(ILC_GET_HANDLE(m_omx->comp[cOmx::eVideoDecoder]), buf) != OMX_ErrorNone) - esyslog("rpihddevice: failed to send empty packet to video decoder!"); + buf->nFilledLen = 0; + buf->nFlags = OMX_BUFFERFLAG_TIME_UNKNOWN | OMX_BUFFERFLAG_EOS; + + if (OMX_EmptyThisBuffer(ILC_GET_HANDLE(m_omx->comp[cOmx::eVideoDecoder]), buf) != OMX_ErrorNone) + esyslog("rpihddevice: failed to send empty packet to video decoder!"); + + if (!m_eosEvent->Wait(10000)) + esyslog("rpihddevice: time out waiting for EOS event!"); + } - if (!m_eosEvent->Wait(10000)) - esyslog("rpihddevice: time out waiting for EOS event!"); -*/ // need to flush the renderer to allow video_decode to disable its input port // put video decoder into idle @@ -695,21 +807,48 @@ void cOmxDevice::Stop() dsyslog("rpihddevice: Stop() end"); } -void cOmxDevice::OmxSetVideoCodec(const uchar *data) +bool cOmxDevice::OmxSetVideoCodec(const uchar *data) { - dsyslog("rpihddevice: OmxSetVideoCodec()"); - // configure video decoder OMX_VIDEO_PARAM_PORTFORMATTYPE videoFormat; memset(&videoFormat, 0, sizeof(videoFormat)); videoFormat.nSize = sizeof(videoFormat); videoFormat.nVersion.nVersion = OMX_VERSION; videoFormat.nPortIndex = 130; - videoFormat.eCompressionFormat = OMX_VIDEO_CodingMPEG2; - if (OMX_SetParameter(ILC_GET_HANDLE(m_omx->comp[cOmx::eVideoDecoder]), OMX_IndexParamVideoPortFormat, &videoFormat) != OMX_ErrorNone) + if (data[0] == 0x00 && data[1] == 0x00 && + data[2] == 0x01 && data[3] == 0xb3) + { + dsyslog("rpihddevice: set video codec to MPEG2"); + videoFormat.eCompressionFormat = OMX_VIDEO_CodingMPEG2; + } + + else if (data[0] == 0x00 && data[1] == 0x00 && + data[2] == 0x00 && data[3] == 0x01 && data[4] == 0x09 && data[5] == 0x10) + { + dsyslog("rpihddevice: set video codec to H264"); + videoFormat.eCompressionFormat = OMX_VIDEO_CodingAVC; + } + else + { + esyslog("rpihddevice: wrong start sequence: %02x %02x %02x %02x %02x %02x %02x %02x", + data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]); + return false; + } + + if (OMX_SetParameter(ILC_GET_HANDLE(m_omx->comp[cOmx::eVideoDecoder]), + OMX_IndexParamVideoPortFormat, &videoFormat) != OMX_ErrorNone) esyslog("rpihddevice: failed to set video decoder parameters!"); + OMX_PARAM_BRCMVIDEODECODEERRORCONCEALMENTTYPE ectype; + memset (&ectype, 0, sizeof(ectype)); + ectype.nSize = sizeof(ectype); + ectype.nVersion.nVersion = OMX_VERSION; + ectype.bStartWithValidFrame = OMX_FALSE; + if (OMX_SetParameter(ILC_GET_HANDLE(m_omx->comp[cOmx::eVideoDecoder]), + OMX_IndexParamBrcmVideoDecodeErrorConcealment, &ectype) != OMX_ErrorNone) + esyslog("rpihddevice: failed to set video decode error concealment failed\n"); + if (ilclient_enable_port_buffers(m_omx->comp[cOmx::eVideoDecoder], 130, NULL, NULL, NULL) != 0) esyslog("rpihddevice: failed to enable port buffer on video decoder!"); @@ -720,13 +859,11 @@ void cOmxDevice::OmxSetVideoCodec(const uchar *data) if (ilclient_setup_tunnel(&m_omx->tun[cOmx::eClockToVideoScheduler], 0, 0) != 0) esyslog("rpihddevice: failed to setup up tunnel from clock to video scheduler!"); - dsyslog("rpihddevice: OmxSetVideoCodec() end"); + return true; } -void cOmxDevice::OmxSetAudioCodec(const uchar *data) +bool cOmxDevice::OmxSetAudioCodec(const uchar *data) { - dsyslog("rpihddevice: OmxSetAudioCodec()"); - if (ilclient_enable_port_buffers(m_omx->comp[cOmx::eAudioRender], 100, NULL, NULL, NULL) != 0) esyslog("rpihddevice: failed to enable port buffer on audio render!"); @@ -735,7 +872,7 @@ void cOmxDevice::OmxSetAudioCodec(const uchar *data) if (ilclient_setup_tunnel(&m_omx->tun[cOmx::eClockToAudioRender], 0, 0) != 0) esyslog("rpihddevice: failed to setup up tunnel from clock to video scheduler!"); - dsyslog("rpihddevice: OmxSetAudioCodec() end"); + return true; } int cOmxDevice::OmxDeInit() diff --git a/omxdevice.h b/omxdevice.h index a06d822..2d734b7 100644 --- a/omxdevice.h +++ b/omxdevice.h @@ -29,13 +29,18 @@ public: eClockStateWaiting }; + enum eMode { + eAudioVideo, + eAudioOnly, + eVideoOnly + }; + cOmxDevice(void (*onPrimaryDevice)(void)); virtual ~cOmxDevice(); virtual bool HasDecoder(void) const { return true; }; virtual bool SetPlayMode(ePlayMode PlayMode); - virtual bool CanReplay(void) const; virtual int PlayVideo(const uchar *Data, int Length); @@ -43,10 +48,18 @@ public: virtual int64_t GetSTC(void); + virtual bool Flush(int TimeoutMs = 0); + +// virtual bool HasIBPTrickSpeed(void); + virtual void TrickSpeed(int Speed); + virtual void Clear(void); virtual void Play(void); + virtual void Freeze(void); + + virtual void SetVolumeDevice(int Volume); + + virtual bool Poll(cPoller &Poller, int TimeoutMs = 0); - virtual bool Flush(int TimeoutMs = 0); - virtual void HandlePortSettingsChanged(unsigned int portId); virtual void HandleEndOfStream(unsigned int portId); @@ -66,14 +79,15 @@ private: void (*m_onPrimaryDevice)(void); - virtual void Start(void); + virtual void Start(eMode mode = eAudioVideo); virtual void Stop(void); - virtual void SetClockScale(int scale); - virtual void SetClockState(eClockState clockState); + virtual void SetClockScale(float scale); + virtual void SetClockState(eClockState clockState, bool armVideo = true, bool armAudio = true); + virtual bool IsClockRunning(); - virtual void OmxSetVideoCodec(const uchar *data); - virtual void OmxSetAudioCodec(const uchar *data); + virtual bool OmxSetVideoCodec(const uchar *data); + virtual bool OmxSetAudioCodec(const uchar *data); cOmx *m_omx; cAudio *m_audio; diff --git a/rpihddevice.c b/rpihddevice.c index b66af7e..1cf5191 100644 --- a/rpihddevice.c +++ b/rpihddevice.c @@ -10,9 +10,7 @@ #include "ovgosd.h" #include "omxdevice.h" -#include "bcm_host.h" - -static const char *VERSION = "0.0.1"; +static const char *VERSION = "0.0.2"; static const char *DESCRIPTION = "HD output device for Raspberry Pi"; class cDummyDevice : cDevice @@ -65,8 +63,6 @@ public: cPluginRpiHdDevice::cPluginRpiHdDevice(void) : m_device(0) { - bcm_host_init(); - m_device = new cOmxDevice(&cPluginRpiHdDevice::OnPrimaryDevice); //new cDummyDevice(); } |