Skip to content
Permalink
Browse files

mmalrenderer: Execute callbacks from main thread

  • Loading branch information...
popcornmix committed Jun 25, 2016
1 parent 9d552b1 commit 54f7015e8b4e7641d7ad689583fd3fc04eafb62c
@@ -67,14 +67,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)
@@ -215,13 +208,15 @@ bool CMMALRenderer::init_vout(ERenderFormat format, AVPixelFormat pixfmt, bool o
m_vout_input_pool = std::make_shared<CMMALPool>(m_vout_input, m_vout_input->buffer_num, m_opaque ? m_vout_input->buffer_size:0);
if (!CSettings::GetInstance().GetBool("videoplayer.usedisplayasclock"))
{
m_queue = mmal_queue_create();
m_queue_render = mmal_queue_create();
Create();
}
m_queue_process = mmal_queue_create();
m_processThread.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;
@@ -236,7 +231,8 @@ 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_fps = 0.0;
m_error = 0.0;
m_lastPts = DVD_NOPTS_VALUE;
@@ -264,6 +260,7 @@ void CMMALRenderer::Process()
double inc = 1.0;
g_RBP.WaitVsync();

CSingleLock lock(m_sharedSection);
// if good enough framerate measure then use it
if (dfps > 0.0 && m_frameInterval > 0.0 && m_frameIntervalDiff * 1e-6 < 1e-3)
{
@@ -278,38 +275,76 @@ void CMMALRenderer::Process()
}
// 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 += inc;
CLog::Log(LOGDEBUG, "%s::%s - debug vsync:%d queue:%d fps:%.2f/%.2f/%.2f inc:%f diff:%f", CLASSNAME, __func__, g_RBP.LastVsync(), mmal_queue_length(m_queue), fps, m_fps, dfps, inc, m_error);
CLog::Log(LOGDEBUG, "%s::%s - debug vsync:%d queue:%d fps:%.2f/%.2f/%.2f inc:%f diff:%f", CLASSNAME, __func__, g_RBP.LastVsync(), mmal_queue_length(m_queue_render), fps, m_fps, dfps, inc, m_error);
// 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 || (mmal_queue_length(m_queue) > 1 && m_error > 1.0))
assert(m_queue_render);
while (mmal_queue_length(m_queue_render) > 2 || (mmal_queue_length(m_queue_render) > 1 && m_error > 1.0))
{
if (m_error > 1.0)
m_error -= 1.0;
MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(m_queue);
MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(m_queue_render);
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);
MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(m_queue_render);
if (buffer)
mmal_port_send_buffer(m_vout_input, 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()
{
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 omvb:%p mmal:%p dts:%.3f pts:%.3f len:%d cmd:%x flags:%x flight:%d", CLASSNAME, __func__,
omvb, buffer, buffer->dts*1e-6, buffer->pts*1e-6, buffer->length, buffer->cmd, buffer->flags, 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)));
if (omvb)
{
assert(buffer->length == 0);
m_inflight--;
omvb->Release();
kept = true;
}
if (!kept)
{
mmal_buffer_header_reset(buffer);
buffer->cmd = 0;
mmal_buffer_header_release(buffer);
}
}
}

void CMMALRenderer::UpdateFramerateStats(double pts)
{
double diff = 0.0;
@@ -485,6 +520,7 @@ void CMMALRenderer::RenderUpdate(bool clear, DWORD flags, DWORD alpha)

if (omvb && omvb->mmal_buffer)
{
MMAL_STATUS_T status = MMAL_SUCCESS;
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
@@ -498,7 +534,7 @@ void CMMALRenderer::RenderUpdate(bool clear, DWORD flags, DWORD alpha)
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);
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));
@@ -510,10 +546,12 @@ void CMMALRenderer::RenderUpdate(bool clear, DWORD flags, DWORD alpha)
omvb->Acquire();
omvb->mmal_buffer->flags |= MMAL_BUFFER_HEADER_FLAG_USER1 | MMAL_BUFFER_HEADER_FLAG_USER2;
omvb->mmal_buffer->user_data = omvb;
if (m_queue)
mmal_queue_put(m_queue, omvb->mmal_buffer);
if (m_queue_render)
mmal_queue_put(m_queue_render, omvb->mmal_buffer);
else
mmal_port_send_buffer(m_vout_input, omvb->mmal_buffer);
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 vout input port (status=0%x %s)", CLASSNAME, __func__, omvb->mmal_buffer, status, mmal_status_to_string(status));
}
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);
@@ -568,14 +606,7 @@ void CMMALRenderer::ReleaseBuffers()

void CMMALRenderer::UnInitMMAL()
{
CSingleLock lock(m_sharedSection);
CLog::Log(LOGDEBUG, "%s::%s pool(%p)", CLASSNAME, __func__, m_vout_input_pool ? m_vout_input_pool->Get() : nullptr);
if (m_queue)
{
StopThread(true);
mmal_queue_destroy(m_queue);
m_queue = nullptr;
}
if (m_vout)
{
mmal_component_disable(m_vout);
@@ -599,6 +630,24 @@ void CMMALRenderer::UnInitMMAL()
m_vout = NULL;
}

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);
if (m_queue_render)
StopThread(true);
m_processThread.StopThread();
}

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

mmal_queue_destroy(m_queue_process);
m_queue_process = nullptr;

m_src_rect.SetRect(0, 0, 0, 0);
m_dst_rect.SetRect(0, 0, 0, 0);
m_video_stereo_mode = RENDER_STEREO_MODE_OFF;
@@ -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();
@@ -124,7 +124,10 @@ class CMMALRenderer : public CBaseRenderer, public CThread
MMAL_COMPONENT_T *m_vout;
MMAL_PORT_T *m_vout_input;
std::shared_ptr<CMMALPool> m_vout_input_pool;
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;
double m_lastPts;
double m_frameInterval;
@@ -134,4 +137,5 @@ class CMMALRenderer : public CBaseRenderer, public CThread
void ReleaseBuffers();
void UnInitMMAL();
void UpdateFramerateStats(double pts);
virtual void Run() override;
};

0 comments on commit 54f7015

Please sign in to comment.
You can’t perform that action at this time.