summaryrefslogtreecommitdiff
path: root/omxdevice.c
diff options
context:
space:
mode:
Diffstat (limited to 'omxdevice.c')
-rw-r--r--omxdevice.c1149
1 files changed, 150 insertions, 999 deletions
diff --git a/omxdevice.c b/omxdevice.c
index aa5610e..d1893e5 100644
--- a/omxdevice.c
+++ b/omxdevice.c
@@ -5,6 +5,7 @@
*/
#include "omxdevice.h"
+#include "omx.h"
#include "audio.h"
#include "setup.h"
@@ -13,860 +14,13 @@
#include <string.h>
-extern "C"
-{
-#include "ilclient.h"
-}
-
-#include "bcm_host.h"
-
-#define OMX_INIT_STRUCT(a) \
- memset(&(a), 0, sizeof(a)); \
- (a).nSize = sizeof(a); \
- (a).nVersion.s.nVersionMajor = OMX_VERSION_MAJOR; \
- (a).nVersion.s.nVersionMinor = OMX_VERSION_MINOR; \
- (a).nVersion.s.nRevision = OMX_VERSION_REVISION; \
- (a).nVersion.s.nStep = OMX_VERSION_STEP
-
-#define OMX_AUDIO_CHANNEL_MAPPING(s, c) \
-switch (c) { \
-case 4: \
- (s).eChannelMapping[0] = OMX_AUDIO_ChannelLF; \
- (s).eChannelMapping[1] = OMX_AUDIO_ChannelRF; \
- (s).eChannelMapping[2] = OMX_AUDIO_ChannelLR; \
- (s).eChannelMapping[3] = OMX_AUDIO_ChannelRR; \
- break; \
-case 1: \
- (s).eChannelMapping[0] = OMX_AUDIO_ChannelCF; \
- break; \
-case 8: \
- (s).eChannelMapping[6] = OMX_AUDIO_ChannelLS; \
- (s).eChannelMapping[7] = OMX_AUDIO_ChannelRS; \
-case 6: \
- (s).eChannelMapping[2] = OMX_AUDIO_ChannelCF; \
- (s).eChannelMapping[3] = OMX_AUDIO_ChannelLFE; \
- (s).eChannelMapping[4] = OMX_AUDIO_ChannelLR; \
- (s).eChannelMapping[5] = OMX_AUDIO_ChannelRR; \
-case 2: \
-default: \
- (s).eChannelMapping[0] = OMX_AUDIO_ChannelLF; \
- (s).eChannelMapping[1] = OMX_AUDIO_ChannelRF; \
- break; }
-
-class cOmx
-{
-
-private:
-
- static const char* errStr(int err)
- {
- return err == OMX_ErrorNone ? "None" :
- err == OMX_ErrorInsufficientResources ? "InsufficientResources" :
- err == OMX_ErrorUndefined ? "Undefined" :
- err == OMX_ErrorInvalidComponentName ? "InvalidComponentName" :
- err == OMX_ErrorComponentNotFound ? "ComponentNotFound" :
- err == OMX_ErrorInvalidComponent ? "InvalidComponent" :
- err == OMX_ErrorBadParameter ? "BadParameter" :
- err == OMX_ErrorNotImplemented ? "NotImplemented" :
- err == OMX_ErrorUnderflow ? "Underflow" :
- err == OMX_ErrorOverflow ? "Overflow" :
- err == OMX_ErrorHardware ? "Hardware" :
- err == OMX_ErrorInvalidState ? "InvalidState" :
- err == OMX_ErrorStreamCorrupt ? "StreamCorrupt" :
- err == OMX_ErrorPortsNotCompatible ? "PortsNotCompatible" :
- err == OMX_ErrorResourcesLost ? "ResourcesLost" :
- err == OMX_ErrorNoMore ? "NoMore" :
- err == OMX_ErrorVersionMismatch ? "VersionMismatch" :
- err == OMX_ErrorNotReady ? "NotReady" :
- err == OMX_ErrorTimeout ? "Timeout" :
- err == OMX_ErrorSameState ? "SameState" :
- err == OMX_ErrorResourcesPreempted ? "ResourcesPreempted" :
- err == OMX_ErrorPortUnresponsiveDuringAllocation ? "PortUnresponsiveDuringAllocation" :
- err == OMX_ErrorPortUnresponsiveDuringDeallocation ? "PortUnresponsiveDuringDeallocation" :
- err == OMX_ErrorPortUnresponsiveDuringStop ? "PortUnresponsiveDuringStop" :
- err == OMX_ErrorIncorrectStateTransition ? "IncorrectStateTransition" :
- err == OMX_ErrorIncorrectStateOperation ? "IncorrectStateOperation" :
- err == OMX_ErrorUnsupportedSetting ? "UnsupportedSetting" :
- err == OMX_ErrorUnsupportedIndex ? "UnsupportedIndex" :
- err == OMX_ErrorBadPortIndex ? "BadPortIndex" :
- err == OMX_ErrorPortUnpopulated ? "PortUnpopulated" :
- err == OMX_ErrorComponentSuspended ? "ComponentSuspended" :
- err == OMX_ErrorDynamicResourcesUnavailable ? "DynamicResourcesUnavailable" :
- err == OMX_ErrorMbErrorsInFrame ? "MbErrorsInFrame" :
- err == OMX_ErrorFormatNotDetected ? "FormatNotDetected" :
- err == OMX_ErrorContentPipeOpenFailed ? "ContentPipeOpenFailed" :
- err == OMX_ErrorContentPipeCreationFailed ? "ContentPipeCreationFailed" :
- err == OMX_ErrorSeperateTablesUsed ? "SeperateTablesUsed" :
- err == OMX_ErrorTunnelingUnsupported ? "TunnelingUnsupported" :
- err == OMX_ErrorKhronosExtensions ? "KhronosExtensions" :
- err == OMX_ErrorVendorStartUnused ? "VendorStartUnused" :
- err == OMX_ErrorDiskFull ? "DiskFull" :
- err == OMX_ErrorMaxFileSize ? "MaxFileSize" :
- err == OMX_ErrorDrmUnauthorised ? "DrmUnauthorised" :
- err == OMX_ErrorDrmExpired ? "DrmExpired" :
- err == OMX_ErrorDrmGeneral ? "DrmGeneral" :
- "unknown";
- };
-
- enum eOmxComponent {
- eClock = 0,
- eVideoDecoder,
- eVideoScheduler,
- eVideoRender,
- eAudioRender,
- eNumComponents
- };
-
- enum eOmxTunnel {
- eVideoDecoderToVideoScheduler = 0,
- eVideoSchedulerToVideoRender,
- eClockToVideoScheduler,
- eClockToAudioRender,
- eNumTunnels
- };
-
- // to do: make this private!
-
- ILCLIENT_T *m_client;
- COMPONENT_T *m_comp[cOmx::eNumComponents + 1];
- TUNNEL_T m_tun[cOmx::eNumTunnels + 1];
-
- cMutex *m_mutex;
-
- bool m_firstVideoBuffer;
- bool m_firstAudioBuffer;
-
- int m_freeAudioBuffers;
- int m_freeVideoBuffers;
-
- void HandleEndOfStream(unsigned int portId)
- {
- dsyslog("rpihddevice: HandleEndOfStream(%d)", portId);
-
- switch (portId)
- {
- case 131:
- break;
-
- case 11:
- break;
-
- case 90:
- break;
- }
- }
-
- void HandlePortSettingsChanged(unsigned int portId)
- {
- //dsyslog("rpihddevice: HandlePortSettingsChanged(%d)", portId);
-
- switch (portId)
- {
- case 131:
-
- OMX_PARAM_PORTDEFINITIONTYPE portdef;
- OMX_INIT_STRUCT(portdef);
- portdef.nPortIndex = 131;
- if (OMX_GetParameter(ILC_GET_HANDLE(m_comp[eVideoDecoder]), OMX_IndexParamPortDefinition,
- &portdef) != OMX_ErrorNone)
- esyslog("rpihddevice: failed to get video decoder port format!");
-
- OMX_CONFIG_INTERLACETYPE interlace;
- OMX_INIT_STRUCT(interlace);
- interlace.nPortIndex = 131;
- if (OMX_GetConfig(ILC_GET_HANDLE(m_comp[eVideoDecoder]), OMX_IndexConfigCommonInterlace,
- &interlace) != OMX_ErrorNone)
- esyslog("rpihddevice: failed to get video decoder interlace config!");
-
- dsyslog("rpihddevice: decoding video %dx%d%s",
- portdef.format.video.nFrameWidth,
- portdef.format.video.nFrameHeight,
- interlace.eMode == OMX_InterlaceProgressive ? "p" : "i");
-
- if (ilclient_setup_tunnel(&m_tun[eVideoDecoderToVideoScheduler], 0, 0) != 0)
- esyslog("rpihddevice: failed to setup up tunnel from video decoder to scheduler!");
- if (ilclient_change_component_state(m_comp[eVideoScheduler], OMX_StateExecuting) != 0)
- esyslog("rpihddevice: failed to enable video scheduler!");
- 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_change_component_state(m_comp[eVideoRender], OMX_StateExecuting) != 0)
- esyslog("rpihddevice: failed to enable video render!");
- break;
- }
- }
-
- void HandleBufferEmpty(COMPONENT_T *comp)
- {
- if (comp == m_comp[eVideoDecoder])
- {
- m_mutex->Lock();
- m_freeVideoBuffers++;
- m_mutex->Unlock();
- }
- else if (comp == m_comp[eAudioRender])
- {
- m_mutex->Lock();
- m_freeAudioBuffers++;
- m_mutex->Unlock();
- }
- }
-
- static void OnBufferEmpty(void *instance, COMPONENT_T *comp)
- {
- cOmx* omx = static_cast <cOmx*> (instance);
- omx->HandleBufferEmpty(comp);
- }
-
- static void OnPortSettingsChanged(void *instance, COMPONENT_T *comp, unsigned int data)
- {
- cOmx* omx = static_cast <cOmx*> (instance);
- omx->HandlePortSettingsChanged(data);
- }
-
- static void OnEndOfStream(void *instance, COMPONENT_T *comp, unsigned int data)
- {
- cOmx* omx = static_cast <cOmx*> (instance);
- omx->HandleEndOfStream(data);
- }
-
- static void OnError(void *instance, COMPONENT_T *comp, unsigned int data)
- {
- if (data != OMX_ErrorSameState)
- esyslog("rpihddevice: OmxError(%s)", errStr((int)data));
- }
-
-public:
-
- cOmx() :
- m_mutex(new cMutex()),
- m_firstVideoBuffer(true),
- m_firstAudioBuffer(true),
- m_freeAudioBuffers(0),
- m_freeVideoBuffers(0)
- { }
-
- virtual ~cOmx()
- {
- delete m_mutex;
- }
-
- int Init(void)
- {
- m_client = ilclient_init();
- if (m_client == NULL)
- esyslog("rpihddevice: ilclient_init() failed!");
-
- if (OMX_Init() != OMX_ErrorNone)
- esyslog("rpihddevice: 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);
-
- // 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!");
-
- // 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!");
-
- //create clock
- if (ilclient_create_component(m_client, &m_comp[eClock],
- "clock", ILCLIENT_DISABLE_ALL_PORTS) != 0)
- esyslog("rpihddevice: 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!");
-
- //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!");
-
- // setup tunnels
- set_tunnel(&m_tun[eVideoDecoderToVideoScheduler], m_comp[eVideoDecoder], 131, m_comp[eVideoScheduler], 10);
- set_tunnel(&m_tun[eVideoSchedulerToVideoRender], m_comp[eVideoScheduler], 11, m_comp[eVideoRender], 90);
- set_tunnel(&m_tun[eClockToVideoScheduler], m_comp[eClock], 80, m_comp[eVideoScheduler], 12);
- set_tunnel(&m_tun[eClockToAudioRender], m_comp[eClock], 81, m_comp[eAudioRender], 101);
-
- // 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!");
-
- if (ilclient_setup_tunnel(&m_tun[eClockToAudioRender], 0, 0) != 0)
- esyslog("rpihddevice: failed to setup up tunnel from clock to audio render!");
-
- OMX_TIME_CONFIG_ACTIVEREFCLOCKTYPE refclock;
- OMX_INIT_STRUCT(refclock);
- refclock.eClock = OMX_TIME_RefClockAudio;
- // refclock.eClock = OMX_TIME_RefClockVideo;
-
- if (OMX_SetConfig(ILC_GET_HANDLE(m_comp[eClock]),
- OMX_IndexConfigTimeActiveRefClock, &refclock) != OMX_ErrorNone)
- esyslog("rpihddevice: failed set active clock reference!");
-
- ilclient_change_component_state(m_comp[eClock], OMX_StateExecuting);
- ilclient_change_component_state(m_comp[eVideoDecoder], OMX_StateIdle);
-
- // set up the number and size of buffers for audio render
- m_freeAudioBuffers = 16;
- 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 = 128 * 1024;
- param.nBufferCountActual = m_freeAudioBuffers;
- if (OMX_SetParameter(ILC_GET_HANDLE(m_comp[eAudioRender]),
- OMX_IndexParamPortDefinition, &param) != OMX_ErrorNone)
- esyslog("rpihddevice: failed to set audio render port parameters!");
-
- 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!");
-
- m_freeVideoBuffers = param.nBufferCountActual;
- dsyslog("rpihddevice: 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!");
-
- 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(comp[eAudioRender], 100, NULL, NULL, NULL) != 0)
- // esyslog("rpihddevice: failed to enable port buffer on audio render!");
-
- return 0;
- }
-
- int DeInit(void)
- {
- ilclient_teardown_tunnels(m_tun);
- ilclient_state_transition(m_comp, OMX_StateIdle);
- ilclient_state_transition(m_comp, OMX_StateLoaded);
- ilclient_cleanup_components(m_comp);
-
- OMX_Deinit();
- ilclient_destroy(m_client);
-
- return 0;
- }
-
- static void PtsToTicks(uint64_t pts, OMX_TICKS &ticks)
- {
- // ticks = pts * OMX_TICKS_PER_SECOND / PTSTICKS
- pts = pts * 100 / 9;
- ticks.nLowPart = (OMX_U32)pts;
- ticks.nHighPart = (OMX_U32)(pts >> 32);
- }
-
- static uint64_t TicksToPts(OMX_TICKS &ticks)
- {
- // pts = ticks * PTSTICKS / OMX_TICKS_PER_SECOND
- uint64_t pts = ticks.nHighPart;
- pts = (pts << 32) + ticks.nLowPart;
- pts = pts * 9 / 100;
- return pts;
- }
-
- int64_t GetSTC(void)
- {
- int64_t stc = -1;
-
- 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!");
- else
- stc = TicksToPts(timestamp.nTimestamp);
-
- return stc;
- }
-
- bool IsClockRunning(void)
- {
- 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 get clock state!");
-
- if (cstate.eState == OMX_TIME_ClockStateRunning)
- return true;
- else
- return false;
- }
-
- enum eClockState {
- eClockStateRun,
- eClockStateStop,
- eClockStateWaitForVideo,
- eClockStateWaitForAudio,
- eClockStateWaitForAudioVideo
- };
-
- void SetClockState(eClockState clockState)
- {
- dsyslog("rpihddevice: 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 get clock state!");
-
- if ((cstate.eState == OMX_TIME_ClockStateRunning) &&
- (clockState == eClockStateWaitForVideo ||
- clockState == eClockStateWaitForAudio ||
- clockState == eClockStateWaitForAudioVideo))
- {
- // clock already running, need to stop it first
- cstate.eState = OMX_TIME_ClockStateStopped;
- if (OMX_SetConfig(ILC_GET_HANDLE(m_comp[eClock]),
- OMX_IndexConfigTimeClockState, &cstate) != OMX_ErrorNone)
- esyslog("rpihddevice: failed set clock state!");
- }
-
- switch (clockState)
- {
- case eClockStateRun:
- cstate.eState = OMX_TIME_ClockStateRunning;
- break;
-
- case eClockStateStop:
- cstate.eState = OMX_TIME_ClockStateStopped;
- break;
-
- case eClockStateWaitForVideo:
- cstate.eState = OMX_TIME_ClockStateWaitingForStartTime;
- cstate.nWaitMask = OMX_CLOCKPORT0;
- m_firstVideoBuffer = true;
- break;
-
- case eClockStateWaitForAudio:
- cstate.eState = OMX_TIME_ClockStateWaitingForStartTime;
- cstate.nWaitMask = OMX_CLOCKPORT1;
- m_firstAudioBuffer = true;
- break;
-
- case eClockStateWaitForAudioVideo:
- cstate.eState = OMX_TIME_ClockStateWaitingForStartTime;
- cstate.nWaitMask = OMX_CLOCKPORT0 | OMX_CLOCKPORT1;
- m_firstVideoBuffer = true;
- m_firstAudioBuffer = true;
- break;
- }
-
- if (OMX_SetConfig(ILC_GET_HANDLE(m_comp[eClock]),
- OMX_IndexConfigTimeClockState, &cstate) != OMX_ErrorNone)
- esyslog("rpihddevice: failed set clock state!");
- }
-
- void SetClockScale(float scale)
- {
- OMX_TIME_CONFIG_SCALETYPE scaleType;
- OMX_INIT_STRUCT(scaleType);
- scaleType.xScale = floor(scale * pow(2, 16));
- if (OMX_SetConfig(ILC_GET_HANDLE(m_comp[eClock]),
- OMX_IndexConfigTimeScale, &scaleType) != OMX_ErrorNone)
- esyslog("rpihddevice: failed to set clock scale (%d)!", scaleType.xScale);
- else
- dsyslog("rpihddevice: set clock scale to %.2f (%d)", scale, scaleType.xScale);
- }
-
- void SetVolume(int vol)
- {
- dsyslog("rpihddevice: SetVolumeDevice(%d)", vol);
-
- OMX_AUDIO_CONFIG_VOLUMETYPE volume;
- OMX_INIT_STRUCT(volume);
- volume.nPortIndex = 100;
- volume.bLinear = OMX_TRUE;
- volume.sVolume.nValue = vol * 100 / 255;
-
- if (OMX_SetConfig(ILC_GET_HANDLE(m_comp[eAudioRender]),
- OMX_IndexConfigAudioVolume, &volume) != OMX_ErrorNone)
- esyslog("rpihddevice: failed to set volume!");
- }
-
- void SendEos(void)
- {
-#if 0
- OMX_BUFFERHEADERTYPE *buf = ilclient_get_input_buffer(m_comp[eVideoDecoder], 130, 1);
- if (buf == NULL)
- return;
-
- buf->nFilledLen = 0;
- 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!");
-
- if (!m_eosEvent->Wait(10000))
- esyslog("rpihddevice: time out waiting for EOS event!");
-#endif
- }
-
- void Stop(void)
- {
- // put video decoder into idle
- ilclient_change_component_state(m_comp[eVideoDecoder], OMX_StateIdle);
-
- // put video scheduler into idle
- ilclient_flush_tunnels(&m_tun[eVideoDecoderToVideoScheduler], 1);
- ilclient_disable_tunnel(&m_tun[eVideoDecoderToVideoScheduler]);
- ilclient_flush_tunnels(&m_tun[eClockToVideoScheduler], 1);
- ilclient_disable_tunnel(&m_tun[eClockToVideoScheduler]);
- ilclient_change_component_state(m_comp[eVideoScheduler], OMX_StateIdle);
-
- // put video render into idle
- ilclient_flush_tunnels(&m_tun[eVideoSchedulerToVideoRender], 1);
- ilclient_disable_tunnel(&m_tun[eVideoSchedulerToVideoRender]);
- ilclient_change_component_state(m_comp[eVideoRender], OMX_StateIdle);
-
- // 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);
-
- // disable port buffers and allow video decoder and audio render to reconfig
- ilclient_disable_port_buffers(m_comp[eVideoDecoder], 130, NULL, NULL, NULL);
- ilclient_disable_port_buffers(m_comp[eAudioRender], 100, NULL, NULL, NULL);
-
- SetClockState(eClockStateStop);
- }
-
- int SetVideoCodec(cOmxDevice::eVideoCodec codec)
- {
- // configure video decoder
- OMX_VIDEO_PARAM_PORTFORMATTYPE videoFormat;
- OMX_INIT_STRUCT(videoFormat);
- videoFormat.nPortIndex = 130;
- videoFormat.eCompressionFormat =
- codec == cOmxDevice::eMPEG2 ? OMX_VIDEO_CodingMPEG2 :
- codec == cOmxDevice::eH264 ? OMX_VIDEO_CodingAVC :
- OMX_VIDEO_CodingAutoDetect;
-
- if (OMX_SetParameter(ILC_GET_HANDLE(m_comp[eVideoDecoder]),
- OMX_IndexParamVideoPortFormat, &videoFormat) != OMX_ErrorNone)
- esyslog("rpihddevice: failed to set video decoder parameters!");
-
- OMX_PARAM_BRCMVIDEODECODEERRORCONCEALMENTTYPE ectype;
- OMX_INIT_STRUCT(ectype);
- ectype.bStartWithValidFrame = 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");
-
- if (ilclient_enable_port_buffers(m_comp[eVideoDecoder], 130, NULL, NULL, NULL) != 0)
- esyslog("rpihddevice: 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!");
-
- // 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!");
-
- return 0;
- }
-
- int SetupAudioRender(cAudioDecoder::eCodec outputFormat, int channels, int samplingRate,
- cAudioDecoder::ePort audioPort)
- {
- // put audio render onto idle
- ilclient_flush_tunnels(&m_tun[eClockToAudioRender], 1);
- ilclient_disable_tunnel(&m_tun[eClockToAudioRender]);
- ilclient_change_component_state(m_comp[eAudioRender], OMX_StateIdle);
- ilclient_disable_port_buffers(m_comp[eAudioRender], 100, NULL, NULL, NULL);
-
- OMX_AUDIO_PARAM_PORTFORMATTYPE format;
- OMX_INIT_STRUCT(format);
- format.nPortIndex = 100;
- if (OMX_GetParameter(ILC_GET_HANDLE(m_comp[eAudioRender]),
- OMX_IndexParamAudioPortFormat, &format) != OMX_ErrorNone)
- esyslog("rpihddevice: failed to get audio port format parameters!");
-
- format.eEncoding =
- outputFormat == cAudioDecoder::ePCM ? OMX_AUDIO_CodingPCM :
- outputFormat == cAudioDecoder::eMPG ? OMX_AUDIO_CodingMP3 :
- outputFormat == cAudioDecoder::eAC3 ? OMX_AUDIO_CodingDDP :
- outputFormat == cAudioDecoder::eEAC3 ? OMX_AUDIO_CodingDDP :
- outputFormat == cAudioDecoder::eAAC ? OMX_AUDIO_CodingAAC :
- outputFormat == cAudioDecoder::eDTS ? OMX_AUDIO_CodingDTS :
- OMX_AUDIO_CodingAutoDetect;
-
- if (OMX_SetParameter(ILC_GET_HANDLE(m_comp[eAudioRender]),
- OMX_IndexParamAudioPortFormat, &format) != OMX_ErrorNone)
- esyslog("rpihddevice: failed to set audio port format parameters!");
-
- switch (outputFormat)
- {
- case cAudioDecoder::eMPG:
- OMX_AUDIO_PARAM_MP3TYPE mp3;
- OMX_INIT_STRUCT(mp3);
- mp3.nPortIndex = 100;
- mp3.nChannels = channels;
- mp3.nSampleRate = samplingRate;
- mp3.eChannelMode = OMX_AUDIO_ChannelModeStereo; // ?
- mp3.eFormat = OMX_AUDIO_MP3StreamFormatMP1Layer3; // should be MPEG-1 layer 2
-
- if (OMX_SetParameter(ILC_GET_HANDLE(m_comp[eAudioRender]),
- OMX_IndexParamAudioMp3, &mp3) != OMX_ErrorNone)
- esyslog("rpihddevice: failed to set audio render mp3 parameters!");
- break;
-
- case cAudioDecoder::eAC3:
- case cAudioDecoder::eEAC3:
- OMX_AUDIO_PARAM_DDPTYPE ddp;
- OMX_INIT_STRUCT(ddp);
- ddp.nPortIndex = 100;
- ddp.nChannels = channels;
- ddp.nSampleRate = samplingRate;
- OMX_AUDIO_CHANNEL_MAPPING(ddp, channels);
-
- if (OMX_SetParameter(ILC_GET_HANDLE(m_comp[eAudioRender]),
- OMX_IndexParamAudioDdp, &ddp) != OMX_ErrorNone)
- esyslog("rpihddevice: failed to set audio render ddp parameters!");
- break;
-
- case cAudioDecoder::eAAC:
- OMX_AUDIO_PARAM_AACPROFILETYPE aac;
- OMX_INIT_STRUCT(aac);
- aac.nPortIndex = 100;
- aac.nChannels = channels;
- aac.nSampleRate = samplingRate;
- aac.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4LATM;
-
- if (OMX_SetParameter(ILC_GET_HANDLE(m_comp[eAudioRender]),
- OMX_IndexParamAudioAac, &aac) != OMX_ErrorNone)
- esyslog("rpihddevice: failed to set audio render aac parameters!");
- break;
-
- case cAudioDecoder::eDTS:
- OMX_AUDIO_PARAM_DTSTYPE dts;
- OMX_INIT_STRUCT(aac);
- dts.nPortIndex = 100;
- dts.nChannels = channels;
- dts.nSampleRate = samplingRate;
- dts.nDtsType = 1; // ??
- dts.nFormat = 0; // ??
- dts.nDtsFrameSizeBytes = 0; // ?
- OMX_AUDIO_CHANNEL_MAPPING(dts, channels);
-
- if (OMX_SetParameter(ILC_GET_HANDLE(m_comp[eAudioRender]),
- OMX_IndexParamAudioDts, &dts) != OMX_ErrorNone)
- esyslog("rpihddevice: failed to set audio render dts parameters!");
- break;
-
- case cAudioDecoder::ePCM:
- OMX_AUDIO_PARAM_PCMMODETYPE pcm;
- OMX_INIT_STRUCT(pcm);
- pcm.nPortIndex = 100;
- pcm.nChannels = channels == 6 ? 8 : channels;
- pcm.eNumData = OMX_NumericalDataSigned;
- pcm.eEndian = OMX_EndianLittle;
- pcm.bInterleaved = OMX_TRUE;
- pcm.nBitPerSample = 16;
- pcm.nSamplingRate = samplingRate;
- pcm.ePCMMode = OMX_AUDIO_PCMModeLinear;
- OMX_AUDIO_CHANNEL_MAPPING(pcm, channels);
-
- if (OMX_SetParameter(ILC_GET_HANDLE(m_comp[eAudioRender]),
- OMX_IndexParamAudioPcm, &pcm) != OMX_ErrorNone)
- esyslog("rpihddevice: failed to set audio render pcm parameters!");
- break;
-
- default:
- break;
- }
-
- OMX_CONFIG_BRCMAUDIODESTINATIONTYPE audioDest;
- OMX_INIT_STRUCT(audioDest);
- strcpy((char *)audioDest.sName,
- audioPort == cAudioDecoder::eLocal ? "local" : "hdmi");
-
- if (OMX_SetConfig(ILC_GET_HANDLE(m_comp[eAudioRender]),
- OMX_IndexConfigBrcmAudioDestination, &audioDest) != OMX_ErrorNone)
- esyslog("rpihddevice: failed to set audio destination!");
-
- if (ilclient_enable_port_buffers(m_comp[eAudioRender], 100, NULL, NULL, NULL) != 0)
- esyslog("rpihddevice: failed to enable port buffer on audio render!");
-
- 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!");
-
- return 0;
- }
-
- OMX_BUFFERHEADERTYPE* GetAudioBuffer(uint64_t pts = 0)
- {
- m_mutex->Lock();
- OMX_BUFFERHEADERTYPE* buf = NULL;
-
- if (m_freeAudioBuffers > 0)
- {
- buf = ilclient_get_input_buffer(m_comp[eAudioRender], 100, 0);
-
- if (buf != NULL)
- {
- cOmx::PtsToTicks(pts, buf->nTimeStamp);
- buf->nFlags = m_firstAudioBuffer ? OMX_BUFFERFLAG_STARTTIME : 0; //OMX_BUFFERFLAG_TIME_UNKNOWN;
- m_firstAudioBuffer = false;
- m_freeAudioBuffers--;
- }
- }
- m_mutex->Unlock();
- return buf;
- }
-
- OMX_BUFFERHEADERTYPE* GetVideoBuffer(uint64_t pts = 0)
- {
- m_mutex->Lock();
- OMX_BUFFERHEADERTYPE* buf = NULL;
-
- if (m_freeVideoBuffers > 0)
- {
- buf = ilclient_get_input_buffer(m_comp[eVideoDecoder], 130, 0);
-
- if (buf != NULL)
- {
- cOmx::PtsToTicks(pts, buf->nTimeStamp);
- buf->nFlags = m_firstVideoBuffer ? OMX_BUFFERFLAG_STARTTIME : 0; //OMX_BUFFERFLAG_TIME_UNKNOWN;
- m_firstVideoBuffer = false;
- m_freeVideoBuffers--;
- }
- }
- m_mutex->Unlock();
- return buf;
- }
-
- bool VideoBuffersAvailable(void)
- {
- return (m_freeVideoBuffers > 0);
- }
-
- bool EmptyAudioBuffer(OMX_BUFFERHEADERTYPE *buf)
- {
- if (!buf)
- return false;
-
- return (OMX_EmptyThisBuffer(ILC_GET_HANDLE(m_comp[eAudioRender]), buf) == OMX_ErrorNone);
- }
-
- bool EmptyVideoBuffer(OMX_BUFFERHEADERTYPE *buf)
- {
- if (!buf)
- return false;
-
- return (OMX_EmptyThisBuffer(ILC_GET_HANDLE(m_comp[eVideoDecoder]), buf) == OMX_ErrorNone);
- }
-};
-
-/* ------------------------------------------------------------------------- */
-#if 0
-class cAudio
-{
-
-public:
-
- cAudio() :
- sampleRate(0),
- bitDepth(0),
- nChannels(0),
- encoding(0),
- m_handle(0)
- {
- int ret;
- mpg123_init();
- m_handle = mpg123_new(NULL, &ret);
- if (m_handle == NULL)
- esyslog("rpihddevice: failed to create mpg123 handle!");
-
- if (mpg123_open_feed(m_handle) == MPG123_ERR)
- esyslog("rpihddevice: failed to open mpg123 feed!");
-
- dsyslog("rpihddevice: new cAudio()");
- }
-
- ~cAudio()
- {
- mpg123_delete(m_handle);
- dsyslog("rpihddevice: delete cAudio()");
- }
-
- bool writeData(const unsigned char *buf, unsigned int length)
- {
- return (mpg123_feed(m_handle, buf, length) != MPG123_ERR);
- }
-
- 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;
-};
-#endif
-/* ------------------------------------------------------------------------- */
-
cOmxDevice::cOmxDevice(void (*onPrimaryDevice)(void)) :
cDevice(),
m_onPrimaryDevice(onPrimaryDevice),
m_omx(new cOmx()),
- m_audio(new cAudioDecoder()),
+ m_audio(new cAudioDecoder(m_omx)),
m_mutex(new cMutex()),
- m_state(eStop),
- m_audioCodecReady(false),
- m_videoCodecReady(false),
+ m_state(eNone),
m_audioId(0)
{
}
@@ -880,14 +34,14 @@ cOmxDevice::~cOmxDevice()
int cOmxDevice::Init(void)
{
- if (m_audio->Init() < 0)
+ if (m_omx->Init() < 0)
{
- esyslog("rpihddevice: failed to initialize audio!");
+ esyslog("rpihddevice: failed to initialize OMX!");
return -1;
}
- if (m_omx->Init() < 0)
+ if (m_audio->Init() < 0)
{
- esyslog("rpihddevice: failed to initialize OMX!");
+ esyslog("rpihddevice: failed to initialize audio!");
return -1;
}
return 0;
@@ -895,14 +49,14 @@ int cOmxDevice::Init(void)
int cOmxDevice::DeInit(void)
{
- if (m_omx->DeInit() < 0)
+ if (m_audio->DeInit() < 0)
{
- esyslog("rpihddevice: failed to deinitialize OMX!");
+ esyslog("rpihddevice: failed to deinitialize audio!");
return -1;
}
- if (m_audio->DeInit() < 0)
+ if (m_omx->DeInit() < 0)
{
- esyslog("rpihddevice: failed to deinitialize audio!");
+ esyslog("rpihddevice: failed to deinitialize OMX!");
return -1;
}
return 0;
@@ -917,7 +71,7 @@ bool cOmxDevice::CanReplay(void) const
{
dsyslog("rpihddevice: CanReplay");
// video codec de-initialization done
- return (m_state == eStop);
+ return (m_state == eNone);
}
bool cOmxDevice::SetPlayMode(ePlayMode PlayMode)
@@ -936,19 +90,19 @@ bool cOmxDevice::SetPlayMode(ePlayMode PlayMode)
{
case pmNone:
m_mutex->Lock();
- m_state = eStop;
+ if (HasVideo())
+ m_omx->FlushVideo(true);
+ if (HasAudio())
+ {
+ m_audio->Reset();
+ m_omx->FlushAudio();
+ }
m_omx->Stop();
- m_audioCodecReady = false;
- m_videoCodecReady = false;
+ SetState(eNone);
m_mutex->Unlock();
break;
case pmAudioVideo:
- m_mutex->Lock();
- m_state = eStarting;
- m_mutex->Unlock();
- break;
-
case pmAudioOnly:
case pmAudioOnlyBlack:
case pmVideoOnly:
@@ -961,153 +115,123 @@ bool cOmxDevice::SetPlayMode(ePlayMode PlayMode)
int cOmxDevice::PlayAudio(const uchar *Data, int Length, uchar Id)
{
m_mutex->Lock();
+ int ret = Length;
- if (m_state == eStarting)
- {
- m_omx->SetClockState(cOmx::eClockStateWaitForAudio);
- m_state = ePlay;
- }
- else if (m_state != ePlay)
- {
- m_mutex->Unlock();
- dsyslog("rpihddevice: PlayAudio() not replaying!");
- return 0;
- }
+ // if first packet is audio, we assume audio only
+ if (State() == eNone)
+ SetState(eAudioOnly);
- if (!PesHasLength(Data))
+ if (State() == eAudioOnly || State() == eAudioVideo)
{
- esyslog("rpihddevice: empty audio packet dropped!");
- m_mutex->Unlock();
- return Length;
- }
-
- int64_t pts = PesHasPts(Data) ? PesGetPts(Data) : 0;
- const uchar *payload = Data + PesPayloadOffset(Data);
- int length = PesLength(Data) - PesPayloadOffset(Data);
-
- if (m_audioId != Id)
- {
- m_audioId = Id;
- m_audioCodecReady = false;
- }
-
- // try to init codec
- if (!m_audioCodecReady || cRpiSetup::HasAudioSetupChanged())
- {
- if (m_audio->SetupAudioCodec(Data, Length))
+ if (m_audio->Poll())
{
- m_audioCodecReady = true;
- m_omx->SetupAudioRender(
- m_audio->GetOutputFormat(),
- m_audio->GetChannels(),
- m_audio->GetSamplingrate(),
- m_audio->GetOutputPort());
+ if (m_audioId != Id)
+ {
+ m_audioId = Id;
+ m_audio->Reset();
+ }
+
+ //dsyslog("A %llu", PesGetPts(Data));
+ if (!m_audio->WriteData(Data + PesPayloadOffset(Data),
+ PesLength(Data) - PesPayloadOffset(Data),
+ PesHasPts(Data) ? PesGetPts(Data) : 0))
+ esyslog("rpihddevice: failed to write data to audio decoder!");
}
else
- {
- m_mutex->Unlock();
- return Length;
- }
- }
-
- OMX_BUFFERHEADERTYPE *buf = m_omx->GetAudioBuffer(pts);
- if (buf == NULL)
- {
- m_mutex->Unlock();
- return 0;
- }
-
- // decode and write audio packet
- buf->nFilledLen = m_audio->DecodeAudio(payload, length, buf->pBuffer, buf->nAllocLen);
-
- // if decoding failed, reset audio codec
- if (!buf->nFilledLen)
- m_audioCodecReady = false;
-
- if (!m_omx->EmptyAudioBuffer(buf))
- {
- m_mutex->Unlock();
- return 0;
+ ret = 0;
}
m_mutex->Unlock();
- return Length;
+ return ret;
}
int cOmxDevice::PlayVideo(const uchar *Data, int Length)
{
m_mutex->Lock();
+ int ret = Length;
- if (m_state == eStarting)
- {
- m_omx->SetClockState(cOmx::eClockStateWaitForAudioVideo);
- m_state = ePlay;
- }
- else if (m_state != ePlay)
- {
- m_mutex->Unlock();
- dsyslog("rpihddevice: PlayVideo() not replaying!");
- return 0;
- }
+ if (State() == eNone)
+ SetState(eStartingVideo);
- if (!PesHasLength(Data))
+ if (State() == eStartingVideo)
{
- esyslog("rpihddevice: empty video packet dropped!");
- m_mutex->Unlock();
- return Length;
+ cVideoCodec::eCodec codec = ParseVideoCodec(Data, Length);
+ if (codec != cVideoCodec::eInvalid)
+ {
+ if (cRpiSetup::IsVideoCodecSupported(codec))
+ {
+ m_omx->SetVideoCodec(codec);
+ SetState(eAudioVideo);
+ dsyslog("rpihddevice: set video codec to %s",
+ cVideoCodec::Str(codec));
+ }
+ else
+ {
+ SetState(eAudioOnly);
+ esyslog("rpihddevice: %s video codec not supported!",
+ cVideoCodec::Str(codec));
+ }
+ }
}
- int64_t pts = PesHasPts(Data) ? PesGetPts(Data) : 0;
-
- const uchar *payload = Data + PesPayloadOffset(Data);
- int length = PesLength(Data) - PesPayloadOffset(Data);
-
- // try to init codec if PTS is valid
- if (!m_videoCodecReady && pts != 0)
+ if (State() == eVideoOnly || State() == eAudioVideo)
{
- eVideoCodec codec = GetVideoCodec(Data, Length);
- if (cRpiSetup::IsVideoCodecSupported(codec))
+ int64_t pts = PesHasPts(Data) ? PesGetPts(Data) : 0;
+ OMX_BUFFERHEADERTYPE *buf = m_omx->GetVideoBuffer(pts);
+ if (buf)
{
- m_videoCodecReady = (m_omx->SetVideoCodec(codec) == 0);
- dsyslog("rpihddevice: set video codec to %s!",
- VideoCodecStr(codec));
+ //dsyslog("V %llu", PesGetPts(Data));
+ const uchar *payload = Data + PesPayloadOffset(Data);
+ int length = PesLength(Data) - PesPayloadOffset(Data);
+ if (length <= buf->nAllocLen)
+ {
+ memcpy(buf->pBuffer, payload, length);
+ buf->nFilledLen = length;
+ }
+ else
+ esyslog("rpihddevice: video packet too long for video buffer!");
+
+ if (!m_omx->EmptyVideoBuffer(buf))
+ {
+ ret = 0;
+ esyslog("rpihddevice: failed to pass buffer to video decoder!");
+ }
}
}
- if (!m_videoCodecReady)
- {
- m_mutex->Unlock();
- return Length;
- }
- OMX_BUFFERHEADERTYPE *buf = m_omx->GetVideoBuffer(pts);
- if (buf == NULL)
- {
- //esyslog("rpihddevice: failed to get video buffer!");
- m_mutex->Unlock();
- return 0;
- }
+ m_mutex->Unlock();
+ return ret;
+}
- if (length <= buf->nAllocLen)
+void cOmxDevice::SetState(eState state)
+{
+ switch (state)
{
- memcpy(buf->pBuffer, payload, length);
- buf->nFilledLen = length;
- }
- else
- esyslog("rpihddevice: video packet too long for video buffer!");
+ case eNone:
+ m_omx->SetClockState(cOmx::eClockStateStop);
+ break;
-// 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 (!m_omx->EmptyVideoBuffer(buf))
- esyslog("rpihddevice: failed to pass buffer to video decoder!");
+ case eStartingVideo:
+ break;
- m_mutex->Unlock();
- return Length;
+ case eAudioOnly:
+ m_omx->SetClockState(cOmx::eClockStateWaitForAudio);
+ break;
+
+ case eVideoOnly:
+ m_omx->SetClockState(cOmx::eClockStateWaitForVideo);
+ break;
+
+ case eAudioVideo:
+ m_omx->SetClockState(cOmx::eClockStateWaitForAudioVideo);
+ break;
+ }
+ m_state = state;
}
int64_t cOmxDevice::GetSTC(void)
{
+ //dsyslog("S %llu", m_omx->GetSTC());
return m_omx->GetSTC();
}
@@ -1139,7 +263,22 @@ bool cOmxDevice::Flush(int TimeoutMs)
void cOmxDevice::Clear(void)
{
+ m_mutex->Lock();
dsyslog("rpihddevice: Clear()");
+
+ m_omx->SetClockScale(1.0f);
+ m_omx->SetMediaTime(0);
+
+ if (HasAudio())
+ {
+ m_audio->Reset();
+ m_omx->FlushAudio();
+ }
+
+ if (HasVideo())
+ m_omx->FlushVideo(false);
+
+ m_mutex->Unlock();
cDevice::Clear();
}
@@ -1152,7 +291,7 @@ bool cOmxDevice::Poll(cPoller &Poller, int TimeoutMs)
{
cTimeMs time;
time.Set();
- while (!m_omx->VideoBuffersAvailable())
+ while (!m_omx->PollVideoBuffers() || !m_audio->Poll())
{
if (time.Elapsed() >= TimeoutMs)
return false;
@@ -1168,26 +307,38 @@ void cOmxDevice::MakePrimaryDevice(bool On)
cDevice::MakePrimaryDevice(On);
}
-cOmxDevice::eVideoCodec cOmxDevice::GetVideoCodec(const uchar *data, int length)
+cVideoCodec::eCodec cOmxDevice::ParseVideoCodec(const uchar *data, int length)
{
+ if (!PesHasPts(data))
+ return cVideoCodec::eInvalid;
+
if (PesLength(data) - PesPayloadOffset(data) < 6)
- return eUnknown;
+ return cVideoCodec::eInvalid;
const uchar *p = data + PesPayloadOffset(data);
+ for (int i = 0; i < 5; i++)
+ {
+ // find start code prefix - should be right at the beginning of payload
+ if ((!p[i] && !p[i + 1] && p[i + 2] == 0x01))
+ {
+ if (p[i + 3] == 0xb3) // sequence header
+ return cVideoCodec::eMPEG2;
- if (p[0] != 0x00 || p[1] != 0x00)
- return eUnknown;
-
- if (p[2] == 0x01 && p[3] == 0xb3)
- return eMPEG2;
-
- else if ((p[2] == 0x01 && p[3] == 0x09 && p[4] == 0x10) ||
- (p[2] == 0x00 && p[3] == 0x01 && p[4] == 0x09 && p[5] == 0x10))
- return eH264;
-
- //esyslog("rpihddevice: invalid start sequence: "
- // "%02x %02x %02x %02x %02x %02x %02x %02x",
- // p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
-
- return eUnknown;
+ else if (p[i + 3] == 0x09) // slice
+ {
+ switch (p[i + 4] >> 5)
+ {
+ case 0: case 3: case 5: // I frame
+ return cVideoCodec::eH264;
+
+ case 1: case 4: case 6: // P frame
+ case 2: case 7: // B frame
+ default:
+ return cVideoCodec::eInvalid;
+ }
+ }
+ return cVideoCodec::eInvalid;
+ }
+ }
+ return cVideoCodec::eInvalid;
}