Skip to content

Commit

Permalink
mmalrenderer: Execute callbacks from dedicated thread
Browse files Browse the repository at this point in the history
  • Loading branch information
popcornmix committed Jul 15, 2016
1 parent fd45d09 commit 5c3a729
Show file tree
Hide file tree
Showing 2 changed files with 132 additions and 52 deletions.
176 changes: 126 additions & 50 deletions xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/MMALRenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,7 @@ CRenderInfo CMMALRenderer::GetRenderInfo()

void CMMALRenderer::vout_input_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
{
assert(!(buffer->flags & MMAL_BUFFER_HEADER_FLAG_TRANSMISSION_FAILED));
buffer->flags &= ~MMAL_BUFFER_HEADER_FLAG_USER2;
CMMALBuffer *omvb = (CMMALBuffer *)buffer->user_data;
if (VERBOSE && g_advancedSettings.CanLogComponent(LOGVIDEO))
CLog::Log(LOGDEBUG, "%s::%s port:%p omvb:%p mmal:%p:%p len:%d cmd:%x flags:%x flight:%d", CLASSNAME, __func__, port, omvb, buffer, omvb->mmal_buffer, buffer->length, buffer->cmd, buffer->flags, m_inflight);
assert(buffer == omvb->mmal_buffer);
m_inflight--;
omvb->Release();
mmal_queue_put(m_queue_process, buffer);
}

static void vout_input_port_cb_static(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
Expand Down Expand Up @@ -170,13 +163,13 @@ bool CMMALRenderer::init_vout(ERenderFormat format, uint32_t encoding)

if (!CSettings::GetInstance().GetBool("videoplayer.usedisplayasclock"))
{
m_queue = mmal_queue_create();
m_queue_render = mmal_queue_create();
Create();
}
return true;
}

CMMALRenderer::CMMALRenderer() : CThread("MMALRenderer")
CMMALRenderer::CMMALRenderer() : CThread("MMALRenderer"), m_processThread(this, "MMALProcess")
{
CLog::Log(LOGDEBUG, "%s::%s", CLASSNAME, __func__);
m_vout = NULL;
Expand All @@ -189,61 +182,157 @@ CMMALRenderer::CMMALRenderer() : CThread("MMALRenderer")
m_bMMALConfigured = false;
m_iYV12RenderBuffer = 0;
m_inflight = 0;
m_queue = nullptr;
m_queue_render = nullptr;
m_queue_process = nullptr;
m_error = 0.0;

m_queue_process = mmal_queue_create();
m_processThread.Create();
}

CMMALRenderer::~CMMALRenderer()
{
CSingleLock lock(m_sharedSection);
CLog::Log(LOGDEBUG, "%s::%s", CLASSNAME, __func__);
UnInit();

if (m_queue_process)
mmal_queue_put(m_queue_process, &m_quitpacket);

{
// leave the lock to allow other threads to exit
CSingleExit unlock(m_sharedSection);
m_processThread.StopThread();
}

mmal_queue_destroy(m_queue_process);
m_queue_process = nullptr;
}


void CMMALRenderer::Process()
{
bool bStop = false;
SetPriority(THREAD_PRIORITY_ABOVE_NORMAL);
CLog::Log(LOGDEBUG, "%s::%s - starting", CLASSNAME, __func__);
while (!m_bStop)
while (!bStop)
{
g_RBP.WaitVsync();

CSingleLock lock(m_sharedSection);

double dfps = g_graphicsContext.GetFPS();
if (dfps <= 0.0)
dfps = m_fps;
// This algorithm is basically making the decision according to Bresenham's line algorithm. Imagine drawing a line where x-axis is display frames, and y-axis is video frames
m_error += m_fps / dfps;
// we may need to discard frames if queue length gets too high or video frame rate is above display frame rate
assert(m_queue);
while (mmal_queue_length(m_queue) > 2 || m_error > 1.0)
assert(m_queue_render);
while (mmal_queue_length(m_queue_render) > 2 || m_error > 1.0)
{
if (m_error > 1.0)
m_error -= 1.0;
MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(m_queue);
if (buffer)
MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(m_queue_render);
if (buffer == &m_quitpacket)
bStop = true;
else if (buffer)
{
CMMALBuffer *omvb = (CMMALBuffer *)buffer->user_data;
assert(buffer == omvb->mmal_buffer);
m_inflight--;
omvb->Release();
if (g_advancedSettings.CanLogComponent(LOGVIDEO))
CLog::Log(LOGDEBUG, "%s::%s - discard buffer:%p vsync:%d queue:%d diff:%f", CLASSNAME, __func__, buffer, g_RBP.LastVsync(), mmal_queue_length(m_queue), m_error);
CLog::Log(LOGDEBUG, "%s::%s - discard buffer:%p vsync:%d queue:%d diff:%f", CLASSNAME, __func__, buffer, g_RBP.LastVsync(), mmal_queue_length(m_queue_render), m_error);
}
}
// this is case where we would like to display a new frame
if (m_error > 0.0)
{
MMAL_STATUS_T status = MMAL_SUCCESS;
m_error -= 1.0;
MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(m_queue);
if (buffer)
mmal_port_send_buffer(m_vout_input, buffer);
MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(m_queue_render);
if (buffer == &m_quitpacket)
bStop = true;
else if (buffer)
status = mmal_port_send_buffer(m_vout_input, buffer);
if (status != MMAL_SUCCESS)
CLog::Log(LOGERROR, "%s::%s - Failed to send buffer %p to vout input port (status=0%x %s)", CLASSNAME, __func__, buffer, status, mmal_status_to_string(status));
if (g_advancedSettings.CanLogComponent(LOGVIDEO))
CLog::Log(LOGDEBUG, "%s::%s - buffer:%p vsync:%d queue:%d diff:%f", CLASSNAME, __func__, buffer, g_RBP.LastVsync(), mmal_queue_length(m_queue), m_error);
CLog::Log(LOGDEBUG, "%s::%s - buffer:%p vsync:%d queue:%d diff:%f", CLASSNAME, __func__, buffer, g_RBP.LastVsync(), mmal_queue_length(m_queue_render), m_error);
}
}
CLog::Log(LOGDEBUG, "%s::%s - stopping", CLASSNAME, __func__);
}

void CMMALRenderer::Run()
{
CLog::Log(LOGDEBUG, "%s::%s - starting", CLASSNAME, __func__);
while (1)
{
MMAL_BUFFER_HEADER_T *buffer = mmal_queue_wait(m_queue_process);
assert(buffer);
if (buffer == &m_quitpacket)
break;
CSingleLock lock(m_sharedSection);
bool kept = false;

CMMALBuffer *omvb = (CMMALBuffer *)buffer->user_data;
if (VERBOSE && g_advancedSettings.CanLogComponent(LOGVIDEO))
CLog::Log(LOGDEBUG, "%s::%s %s omvb:%p mmal:%p dts:%.3f pts:%.3f len:%d cmd:%x flags:%x encoding:%.4s flight:%d", CLASSNAME, __func__,
omvb ? omvb->GetStateName():"", omvb, buffer, buffer->dts*1e-6, buffer->pts*1e-6, buffer->length, buffer->cmd, buffer->flags, omvb ? (char *)&omvb->m_encoding:"", m_inflight);

assert(omvb && buffer == omvb->mmal_buffer);
assert(buffer->cmd == 0);
assert(!(buffer->flags & (MMAL_BUFFER_HEADER_FLAG_EOS | MMAL_BUFFER_HEADER_FLAG_TRANSMISSION_FAILED)));
switch (omvb->m_state)
{
case MMALStateHWDec:
case MMALStateFFDec:
{
if (buffer->length == 0)
{
m_inflight--;
omvb->Release();
kept = true;
break;
}
MMAL_STATUS_T status = MMAL_SUCCESS;
// check for changes in aligned sizes
if (omvb->m_width != (uint32_t)m_vout_input->format->es->video.crop.width || omvb->m_height != (uint32_t)m_vout_input->format->es->video.crop.height ||
omvb->m_aligned_width != m_vout_input->format->es->video.width || omvb->m_aligned_height != m_vout_input->format->es->video.height)
{
CLog::Log(LOGDEBUG, "%s::%s Changing dimensions from %dx%d (%dx%d) to %dx%d (%dx%d)", CLASSNAME, __func__,
m_vout_input->format->es->video.crop.width, m_vout_input->format->es->video.crop.height, omvb->m_width, omvb->m_height,
m_vout_input->format->es->video.width, m_vout_input->format->es->video.height, omvb->m_aligned_width, omvb->m_aligned_height);
m_vout_input->format->es->video.width = omvb->m_aligned_width;
m_vout_input->format->es->video.height = omvb->m_aligned_height;
m_vout_input->format->es->video.crop.width = omvb->m_width;
m_vout_input->format->es->video.crop.height = omvb->m_height;
status = mmal_port_format_commit(m_vout_input);
if (status != MMAL_SUCCESS)
CLog::Log(LOGERROR, "%s::%s Failed to commit vout input format (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status));
}
if (m_queue_render && m_fps > 0.0f)
mmal_queue_put(m_queue_render, omvb->mmal_buffer);
else
status = mmal_port_send_buffer(m_vout_input, omvb->mmal_buffer);
if (status != MMAL_SUCCESS)
CLog::Log(LOGERROR, "%s::%s - Failed to send buffer %p to input port (status=0%x %s)", CLASSNAME, __func__, omvb->mmal_buffer, status, mmal_status_to_string(status));
kept = true;
break;
}
default: assert(0); break;
}
if (!kept)
{
mmal_buffer_header_reset(buffer);
buffer->cmd = 0;
mmal_buffer_header_release(buffer);
}
}
CLog::Log(LOGDEBUG, "%s::%s - stopping", CLASSNAME, __func__);
}

void CMMALRenderer::AddVideoPictureHW(DVDVideoPicture& pic, int index)
{
if (m_format != RENDER_FMT_MMAL)
Expand Down Expand Up @@ -395,33 +484,12 @@ void CMMALRenderer::RenderUpdate(bool clear, DWORD flags, DWORD alpha)
{
if (g_advancedSettings.CanLogComponent(LOGVIDEO))
CLog::Log(LOGDEBUG, "%s::%s - MMAL: clear:%d flags:%x alpha:%d source:%d omvb:%p mmal:%p mflags:%x pts:%.3f", CLASSNAME, __func__, clear, flags, alpha, source, omvb, omvb->mmal_buffer, omvb->mmal_buffer->flags, m_pts[source]*1e-6);
// check for changes in aligned sizes
if (omvb->m_width != (uint32_t)m_vout_input->format->es->video.crop.width || omvb->m_height != (uint32_t)m_vout_input->format->es->video.crop.height ||
omvb->m_aligned_width != m_vout_input->format->es->video.width || omvb->m_aligned_height != m_vout_input->format->es->video.height)
{
CLog::Log(LOGDEBUG, "%s::%s Changing dimensions from %dx%d (%dx%d) to %dx%d (%dx%d)", CLASSNAME, __func__,
m_vout_input->format->es->video.crop.width, m_vout_input->format->es->video.crop.height, omvb->m_width, omvb->m_height,
m_vout_input->format->es->video.width, m_vout_input->format->es->video.height, omvb->m_aligned_width, omvb->m_aligned_height);
m_vout_input->format->es->video.width = omvb->m_aligned_width;
m_vout_input->format->es->video.height = omvb->m_aligned_height;
m_vout_input->format->es->video.crop.width = omvb->m_width;
m_vout_input->format->es->video.crop.height = omvb->m_height;
MMAL_STATUS_T status = mmal_port_format_commit(m_vout_input);
if (status != MMAL_SUCCESS)
{
CLog::Log(LOGERROR, "%s::%s Failed to commit vout input format (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status));
goto exit;
}
}
m_inflight++;
assert(omvb->mmal_buffer && omvb->mmal_buffer->data && omvb->mmal_buffer->length);
omvb->Acquire();
omvb->m_rendered = true;
omvb->mmal_buffer->user_data = omvb;
if (m_queue && m_fps > 0.0f)
mmal_queue_put(m_queue, omvb->mmal_buffer);
else
mmal_port_send_buffer(m_vout_input, omvb->mmal_buffer);
mmal_queue_put(m_queue_process, omvb->mmal_buffer);
}
else
CLog::Log(LOGDEBUG, "%s::%s - MMAL: No buffer to update clear:%d flags:%x alpha:%d source:%d omvb:%p mmal:%p", CLASSNAME, __func__, clear, flags, alpha, source, omvb, omvb ? omvb->mmal_buffer : nullptr);
Expand Down Expand Up @@ -476,14 +544,7 @@ void CMMALRenderer::ReleaseBuffers()

void CMMALRenderer::UnInitMMAL()
{
CSingleLock lock(m_sharedSection);
CLog::Log(LOGDEBUG, "%s::%s", CLASSNAME, __func__);
if (m_queue)
{
StopThread(true);
mmal_queue_destroy(m_queue);
m_queue = nullptr;
}
if (m_vout)
{
mmal_component_disable(m_vout);
Expand All @@ -497,6 +558,20 @@ void CMMALRenderer::UnInitMMAL()

ReleaseBuffers();

if (m_queue_render)
mmal_queue_put(m_queue_render, &m_quitpacket);

{
// leave the lock to allow other threads to exit
CSingleExit unlock(m_sharedSection);
if (m_queue_render)
StopThread(true);
}

if (m_queue_render)
mmal_queue_destroy(m_queue_render);
m_queue_render = nullptr;

m_vout_input = NULL;

if (m_vout)
Expand All @@ -518,6 +593,7 @@ void CMMALRenderer::UnInitMMAL()

void CMMALRenderer::UnInit()
{
CSingleLock lock(m_sharedSection);
UnInitMMAL();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class CMMALPool
MMAL_PORT_T *m_input;
};

class CMMALRenderer : public CBaseRenderer, public CThread
class CMMALRenderer : public CBaseRenderer, public CThread, public IRunnable
{
public:
CMMALRenderer();
Expand Down Expand Up @@ -120,10 +120,14 @@ class CMMALRenderer : public CBaseRenderer, public CThread
CCriticalSection m_sharedSection;
MMAL_COMPONENT_T *m_vout;
MMAL_PORT_T *m_vout_input;
MMAL_QUEUE_T *m_queue;
MMAL_QUEUE_T *m_queue_render;
MMAL_QUEUE_T *m_queue_process;
CThread m_processThread;
MMAL_BUFFER_HEADER_T m_quitpacket;
double m_error;

bool init_vout(ERenderFormat format, uint32_t encoding);
void ReleaseBuffers();
void UnInitMMAL();
virtual void Run() override;
};

0 comments on commit 5c3a729

Please sign in to comment.