90 changes: 64 additions & 26 deletions mythtv/libs/libmythbluray/hdmv/hdmv_vm.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "util/macro.h"
#include "util/strutl.h"
#include "util/logging.h"
#include "util/mutex.h"

#include <stdlib.h>
#include <string.h>
Expand All @@ -38,6 +39,9 @@ typedef struct {
} NV_TIMER;

struct hdmv_vm_s {

BD_MUTEX mutex;

/* state */
uint32_t pc; /* program counter */
BD_REGISTERS *regs; /* player registers */
Expand Down Expand Up @@ -243,6 +247,8 @@ HDMV_VM *hdmv_vm_init(const char *disc_root, BD_REGISTERS *regs)

p->regs = regs;

bd_mutex_init(&p->mutex);

return p;
}

Expand All @@ -258,6 +264,8 @@ void hdmv_vm_free(HDMV_VM **p)
{
if (p && *p) {

bd_mutex_destroy(&(*p)->mutex);

mobj_free(&(*p)->movie_objects);

_free_ig_object(*p);
Expand Down Expand Up @@ -313,14 +321,17 @@ static int _resume_object(HDMV_VM *p)

static int _jump_object(HDMV_VM *p, int object)
{
if (object < 0 || object > p->movie_objects->num_objects) {
if (object < 0 || object >= p->movie_objects->num_objects) {
DEBUG(DBG_HDMV|DBG_CRIT, "_jump_object(): invalid object %d\n", object);
return -1;
}

DEBUG(DBG_HDMV, "_jump_object(): jumping to object %d\n", object);

hdmv_vm_select_object(p, object);
_free_ig_object(p);

p->pc = 0;
p->object = &p->movie_objects->objects[object];

return 0;
}
Expand Down Expand Up @@ -882,23 +893,20 @@ static int _hdmv_step(HDMV_VM *p)

int hdmv_vm_select_object(HDMV_VM *p, int object)
{
if (object >= 0) {
if (object >= p->movie_objects->num_objects) {
DEBUG(DBG_HDMV|DBG_CRIT, "hdmv_vm_select_object(): invalid object reference (%d) !\n", object);
return -1;
}
int result;
bd_mutex_lock(&p->mutex);

_free_ig_object(p);
result = _jump_object(p, object);

p->pc = 0;
p->object = &p->movie_objects->objects[object];
}

return 0;
bd_mutex_unlock(&p->mutex);
return result;
}

int hdmv_vm_set_object(HDMV_VM *p, int num_nav_cmds, void *nav_cmds)
{
int result = -1;
bd_mutex_lock(&p->mutex);

p->object = NULL;

_free_ig_object(p);
Expand All @@ -909,48 +917,69 @@ int hdmv_vm_set_object(HDMV_VM *p, int num_nav_cmds, void *nav_cmds)
ig_object->cmds = calloc(num_nav_cmds, sizeof(MOBJ_CMD));
memcpy(ig_object->cmds, nav_cmds, num_nav_cmds * sizeof(MOBJ_CMD));

#if 0
/* ??? */
if (!p->ig_object && p->object) {
_suspend_object(p);
}
#endif
p->pc = 0;
p->ig_object = ig_object;
p->object = ig_object;

result = 0;
}

return 0;
bd_mutex_unlock(&p->mutex);

return result;
}

int hdmv_vm_get_event(HDMV_VM *p, HDMV_EVENT *ev)
{
return _get_event(p, ev);
int result;
bd_mutex_lock(&p->mutex);

result = _get_event(p, ev);

bd_mutex_unlock(&p->mutex);
return result;
}

int hdmv_vm_running(HDMV_VM *p)
{
return !!p->object;
int result;
bd_mutex_lock(&p->mutex);

result = !!p->object;

bd_mutex_unlock(&p->mutex);
return result;
}

int hdmv_vm_resume(HDMV_VM *p)
{
return _resume_object(p);
int result;
bd_mutex_lock(&p->mutex);

result = _resume_object(p);

bd_mutex_unlock(&p->mutex);
return result;
}

int hdmv_vm_suspend(HDMV_VM *p)
{
int result = -1;
bd_mutex_lock(&p->mutex);

if (p->object && !p->ig_object) {
_suspend_object(p);
return 0;
result = 0;
}
return -1;

bd_mutex_unlock(&p->mutex);
return result;
}

/* terminate program after MAX_LOOP instructions */
#define MAX_LOOP 1000000

int hdmv_vm_run(HDMV_VM *p, HDMV_EVENT *ev)
static int _vm_run(HDMV_VM *p, HDMV_EVENT *ev)
{
int max_loop = MAX_LOOP;

Expand Down Expand Up @@ -998,4 +1027,13 @@ int hdmv_vm_run(HDMV_VM *p, HDMV_EVENT *ev)
return -1;
}

int hdmv_vm_run(HDMV_VM *p, HDMV_EVENT *ev)
{
int result;
bd_mutex_lock(&p->mutex);

result = _vm_run(p, ev);

bd_mutex_unlock(&p->mutex);
return result;
}
8 changes: 4 additions & 4 deletions mythtv/libs/libmythtv/avformatdecoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2185,7 +2185,7 @@ int get_avf_buffer(struct AVCodecContext *c, AVFrame *pic)
}
nd->directrendering = true;

VideoFrame *frame = nd->GetPlayer()->GetNextVideoFrame(true);
VideoFrame *frame = nd->GetPlayer()->GetNextVideoFrame();

if (!frame)
return -1;
Expand Down Expand Up @@ -2252,7 +2252,7 @@ void release_avf_buffer(struct AVCodecContext *c, AVFrame *pic)
int get_avf_buffer_vdpau(struct AVCodecContext *c, AVFrame *pic)
{
AvFormatDecoder *nd = (AvFormatDecoder *)(c->opaque);
VideoFrame *frame = nd->GetPlayer()->GetNextVideoFrame(false);
VideoFrame *frame = nd->GetPlayer()->GetNextVideoFrame();

pic->data[0] = frame->buf;
pic->data[1] = frame->priv[0];
Expand Down Expand Up @@ -2882,7 +2882,7 @@ bool AvFormatDecoder::ProcessVideoFrame(AVStream *stream, AVFrame *mpa_pic)
AVPicture tmppicture;

VideoFrame *xf = picframe;
picframe = m_parent->GetNextVideoFrame(false);
picframe = m_parent->GetNextVideoFrame();

unsigned char *buf = picframe->buf;
avpicture_fill(&tmppicture, buf, PIX_FMT_YUV420P, context->width,
Expand Down Expand Up @@ -4154,7 +4154,7 @@ bool AvFormatDecoder::GenerateDummyVideoFrame(void)
if (!m_parent->getVideoOutput())
return false;

VideoFrame *frame = m_parent->GetNextVideoFrame(true);
VideoFrame *frame = m_parent->GetNextVideoFrame();
if (!frame)
return false;

Expand Down
4 changes: 2 additions & 2 deletions mythtv/libs/libmythtv/mythplayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1088,9 +1088,9 @@ void MythPlayer::InitFilters(void)
* of frames ready for display if we can't find a frame in the
* available queue.
*/
VideoFrame *MythPlayer::GetNextVideoFrame(bool allow_unsafe)
VideoFrame *MythPlayer::GetNextVideoFrame(void)
{
return videoOutput->GetNextFreeFrame(false, allow_unsafe);
return videoOutput->GetNextFreeFrame();
}

/** \fn MythPlayer::ReleaseNextVideoFrame(VideoFrame*, int64_t)
Expand Down
4 changes: 2 additions & 2 deletions mythtv/libs/libmythtv/mythplayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -216,13 +216,13 @@ class MTV_PUBLIC MythPlayer
void SetCutList(const frm_dir_map_t &newCutList);

// Decoder stuff..
VideoFrame *GetNextVideoFrame(bool allow_unsafe = true);
VideoFrame *GetNextVideoFrame(void);
VideoFrame *GetRawVideoFrame(long long frameNumber = -1);
VideoFrame *GetCurrentFrame(int &w, int &h);
virtual void ReleaseNextVideoFrame(VideoFrame *buffer, int64_t timecode,
bool wrap = true);
void ReleaseNextVideoFrame(void)
{ videoOutput->ReleaseFrame(GetNextVideoFrame(false)); }
{ videoOutput->ReleaseFrame(GetNextVideoFrame()); }
void ReleaseCurrentFrame(VideoFrame *frame);
void DiscardVideoFrame(VideoFrame *buffer);
void DiscardVideoFrames(bool next_frame_keyframe);
Expand Down
223 changes: 6 additions & 217 deletions mythtv/libs/libmythtv/videobuffers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ extern "C" {
#include "compat.h"
#include "mythverbose.h"

#define DEBUG_FRAME_LOCKS 0

#define TRY_LOCK_SPINS 100
#define TRY_LOCK_SPINS_BEFORE_WARNING 10
#define TRY_LOCK_SPIN_WAIT 100 /* usec */
Expand Down Expand Up @@ -89,13 +87,6 @@ YUVInfo::YUVInfo(uint w, uint h, uint sz, const int *p, const int *o)
* being displayed at the end of the next
* DoneDisplayingFrame(), finally adding them to available.
*
* Frame locking is also available, the locks are reqursive
* QMutex locks. If more than one frame lock is needed the
* LockFrames should generally be called with all the needed
* locks in the list, and no locks currently held. This
* function will spin until all the locks can be held at
* once, avoiding deadlocks from mismatched locking order.
*
* The only method that returns with a lock held on the VideoBuffers
* object itself, preventing anyone else from using the VideoBuffers
* class, inluding to unlocking frames, is the begin_lock(BufferType).
Expand All @@ -113,8 +104,7 @@ VideoBuffers::VideoBuffers()
: numbuffers(0), needfreeframes(0), needprebufferframes(0),
needprebufferframes_normal(0), needprebufferframes_small(0),
keepprebufferframes(0), need_extra_for_pause(false), rpos(0), vpos(0),
global_lock(QMutex::Recursive), use_frame_locks(true),
frame_lock(QMutex::Recursive)
global_lock(QMutex::Recursive)
{
}

Expand Down Expand Up @@ -143,14 +133,10 @@ VideoBuffers::~VideoBuffers()
* after SetPrebuffering(false) has been called.
* \param keepprebuffer number of buffers in used or limbo that are considered
* enough for decent playback.
* \param enable_frame_locking if true, the frames will be locked with a mutex,
* this makes XvMC decoding safe, but adds some CPU
* overhead. It is normally left off.
*/
void VideoBuffers::Init(uint numdecode, bool extra_for_pause,
uint need_free, uint needprebuffer_normal,
uint needprebuffer_small, uint keepprebuffer,
bool enable_frame_locking)
uint needprebuffer_small, uint keepprebuffer)
{
QMutexLocker locker(&global_lock);

Expand Down Expand Up @@ -179,7 +165,6 @@ void VideoBuffers::Init(uint numdecode, bool extra_for_pause,
needprebufferframes_small = needprebuffer_small;
keepprebufferframes = keepprebuffer;
need_extra_for_pause = extra_for_pause;
use_frame_locks = enable_frame_locking;

for (uint i = 0; i < numdecode; i++)
enqueue(kVideoBuffer_avail, at(i));
Expand Down Expand Up @@ -224,8 +209,7 @@ void VideoBuffers::SetPrebuffering(bool normal)
needprebufferframes_normal : needprebufferframes_small;
}

VideoFrame *VideoBuffers::GetNextFreeFrameInternal(
bool with_lock, bool allow_unsafe, BufferType enqueue_to)
VideoFrame *VideoBuffers::GetNextFreeFrameInternal(BufferType enqueue_to)
{
QMutexLocker locker(&global_lock);
VideoFrame *frame = available.dequeue();
Expand All @@ -247,58 +231,23 @@ VideoFrame *VideoBuffers::GetNextFreeFrameInternal(
frame = available.dequeue();
}

// only way this should be triggered if we're in unsafe mode
if (!frame && allow_unsafe)
{
VERBOSE(VB_PLAYBACK,
QString("GetNextFreeFrame() is getting a busy frame %1. "
" %2")
.arg(DebugString(frame, true)).arg(GetStatus()));
frame = used.dequeue();
}

if (frame)
{
safeEnqueue(enqueue_to, frame);

bool success = true;
if (with_lock)
success = TryLockFrame(frame, "GetNextFreeFrame");

if (!success)
{
safeEnqueue(kVideoBuffer_avail, frame);
VERBOSE(VB_IMPORTANT,
QString("GetNextFreeFrame() unable to lock frame %1. "
"Dropping %2. w/lock(%3) unsafe(%4)")
.arg(DebugString(frame)).arg(GetStatus())
.arg(with_lock).arg(allow_unsafe));
DiscardFrame(frame);
frame = NULL;
}
}

return frame;
}

/**
* \fn VideoBuffers::GetNextFreeFrame(bool,bool,BufferType)
* Gets a frame from available buffers list.
*
* \param with_lock locks the frame, so that UnlockFrame() must be
* called before anyone else can use it.
* \param allow_unsafe allows busy buffers to be used if no available
* buffers exist. Historic, should never be used.
* \param enqueue_to put new frame in some state other than limbo.
*/
VideoFrame *VideoBuffers::GetNextFreeFrame(bool with_lock,
bool allow_unsafe,
BufferType enqueue_to)
VideoFrame *VideoBuffers::GetNextFreeFrame(BufferType enqueue_to)
{
for (uint tries = 1; true; tries++)
{
VideoFrame *frame = VideoBuffers::GetNextFreeFrameInternal(
with_lock, allow_unsafe, enqueue_to);
VideoFrame *frame = VideoBuffers::GetNextFreeFrameInternal(enqueue_to);

if (frame)
return frame;
Expand Down Expand Up @@ -396,27 +345,7 @@ void VideoBuffers::DoneDisplayingFrame(VideoFrame *frame)
void VideoBuffers::DiscardFrame(VideoFrame *frame)
{
QMutexLocker locker(&global_lock);

bool ok = TryLockFrame(frame, "DiscardFrame A");
for (uint i=0; i<5 && !ok; i++)
{
global_lock.unlock();
usleep(50);
global_lock.lock();
ok = TryLockFrame(frame, "DiscardFrame B");
}

if (ok)
{
safeEnqueue(kVideoBuffer_avail, frame);
UnlockFrame(frame, "DiscardFrame");
}
else
{
VERBOSE(VB_IMPORTANT, QString("VideoBuffers::DiscardFrame(): "
"Unable to obtain lock on %1, %2")
.arg(DebugString(frame, true)).arg(GetStatus()));
}
safeEnqueue(kVideoBuffer_avail, frame);
}

frame_queue_t *VideoBuffers::queue(BufferType type)
Expand Down Expand Up @@ -734,146 +663,6 @@ void VideoBuffers::ClearAfterSeek(void)
}
}

void VideoBuffers::LockFrame(const VideoFrame *frame, const char* owner)
{
if (!use_frame_locks)
return;

QMutex *mutex = NULL;
(void)owner;

if (!frame)
return;

frame_lock.lock();
#if DEBUG_FRAME_LOCKS
if (owner!="")
VERBOSE(VB_PLAYBACK, QString("locking frame: %1 %2 %3")
.arg(DebugString(frame)).arg(GetStatus()).arg(owner));
#endif

frame_lock_map_t::iterator it = frame_locks.find(frame);
if (it == frame_locks.end())
mutex = frame_locks[frame] = new QMutex(QMutex::Recursive);
else
mutex = it->second;

frame_lock.unlock();

mutex->lock();
}

void VideoBuffers::LockFrames(vector<const VideoFrame*>& vec,
const char* owner)
{
if (!use_frame_locks)
return;

(void)owner;
bool ok;
vector<bool> oks;
oks.resize(vec.size());

#if DEBUG_FRAME_LOCKS
VERBOSE(VB_PLAYBACK, QString("lock frames: %1 %2 %3")
.arg(DebugString(vec)).arg(GetStatus()).arg(owner));
#endif
do
{
ok = true;
for (uint i=0; i<vec.size(); i++)
ok &= oks[i] = TryLockFrame(vec[i], "");
if (!ok)
{
for (uint i=0; i<vec.size(); i++)
if (oks[i])
UnlockFrame(vec[i], "");
usleep(50);
#if DEBUG_FRAME_LOCKS
VERBOSE(VB_PLAYBACK, QString("no lock, frames: %1 %2 %3")
.arg(DebugString(vec)).arg(GetStatus()).arg(owner));
#endif
}
}
while (!ok);
}

bool VideoBuffers::TryLockFrame(const VideoFrame *frame, const char* owner)
{
if (!use_frame_locks)
return true;

QMutex *mutex = NULL;
(void)owner;

if (!frame)
return true;

frame_lock.lock();
#if DEBUG_FRAME_LOCKS
if (owner!="")
VERBOSE(VB_PLAYBACK, QString("try lock frame: %1 %2 %3")
.arg(DebugString(frame)).arg(GetStatus()).arg(owner));
#endif

frame_lock_map_t::iterator it = frame_locks.find(frame);
if (it == frame_locks.end())
mutex = frame_locks[frame] = new QMutex(QMutex::Recursive);
else
mutex = it->second;

bool ok = mutex->tryLock();

#if DEBUG_FRAME_LOCKS
if (owner!="")
{
QString str = (ok) ? "got lock: " : "try lock failed: ";
VERBOSE(VB_PLAYBACK, str.append(DebugString(frame)));
}
#endif
frame_lock.unlock();

return ok;
}

void VideoBuffers::UnlockFrame(const VideoFrame *frame, const char* owner)
{
if (!use_frame_locks)
return;

(void)owner;

if (!frame)
return;

frame_lock.lock();
#if DEBUG_FRAME_LOCKS
if (owner!="")
VERBOSE(VB_PLAYBACK, QString("unlocking frame: %1 %2 %3")
.arg(DebugString(frame)).arg(GetStatus()).arg(owner));
#endif

frame_lock_map_t::iterator it = frame_locks.find(frame);
it->second->unlock();

frame_lock.unlock();
}

void VideoBuffers::UnlockFrames(vector<const VideoFrame*>& vec,
const char* owner)
{
if (!use_frame_locks)
return;

(void)owner;
#if DEBUG_FRAME_LOCKS
VERBOSE(VB_PLAYBACK, QString("unlocking frames:%1 %2 %3")
.arg(DebugString(vec)).arg(GetStatus()).arg(owner));
#endif
for (uint i=0; i<vec.size(); i++)
UnlockFrame(vec[i], "");
}

bool VideoBuffers::CreateBuffers(VideoFrameType type, int width, int height)
{
vector<unsigned char*> bufs;
Expand Down
19 changes: 3 additions & 16 deletions mythtv/libs/libmythtv/videobuffers.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,7 @@ class VideoBuffers

void Init(uint numdecode, bool extra_for_pause,
uint need_free, uint needprebuffer_normal,
uint needprebuffer_small, uint keepprebuffer,
bool enable_frame_locking = false);
uint needprebuffer_small, uint keepprebuffer);

bool CreateBuffers(VideoFrameType type, int width, int height,
vector<unsigned char*> bufs,
Expand All @@ -80,8 +79,7 @@ class VideoBuffers

void SetPrebuffering(bool normal);

VideoFrame *GetNextFreeFrame(bool with_lock, bool allow_unsafe,
BufferType enqueue_to = kVideoBuffer_limbo);
VideoFrame *GetNextFreeFrame(BufferType enqueue_to = kVideoBuffer_limbo);
void ReleaseFrame(VideoFrame *frame);
void DeLimboFrame(VideoFrame *frame);
void StartDisplayingFrame(void);
Expand Down Expand Up @@ -123,12 +121,6 @@ class VideoBuffers
uint size() const { return numbuffers; }
uint allocSize() const { return buffers.size(); }

void LockFrame(const VideoFrame *, const char* owner);
void LockFrames(vector<const VideoFrame*>&, const char* owner);
bool TryLockFrame(const VideoFrame *, const char* owner);
void UnlockFrame(const VideoFrame *, const char* owner);
void UnlockFrames(vector<const VideoFrame*>&, const char* owner);

void Clear(uint i);
void Clear(void);

Expand All @@ -139,8 +131,7 @@ class VideoBuffers
private:
frame_queue_t *queue(BufferType type);
const frame_queue_t *queue(BufferType type) const;
VideoFrame *GetNextFreeFrameInternal(
bool with_lock, bool allow_unsafe, BufferType enqueue_to);
VideoFrame *GetNextFreeFrameInternal(BufferType enqueue_to);

frame_queue_t available, used, limbo, pause, displayed, decode;
vbuffer_map_t vbufferMap; // videobuffers to buffer's index
Expand All @@ -160,10 +151,6 @@ class VideoBuffers
uint vpos;

mutable QMutex global_lock;

bool use_frame_locks;
QMutex frame_lock;
frame_lock_map_t frame_locks;
};

#endif // __VIDEOBUFFERS_H__
25 changes: 2 additions & 23 deletions mythtv/libs/libmythtv/videoout_null.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,11 @@ VideoOutputNull::~VideoOutputNull()
VERBOSE(VB_PLAYBACK, "~VideoOutputNull()");
QMutexLocker locker(&global_lock);

vbuffers.LockFrame(&av_pause_frame, "DeletePauseFrame");
if (av_pause_frame.buf)
{
delete [] av_pause_frame.buf;
memset(&av_pause_frame, 0, sizeof(av_pause_frame));
}
vbuffers.UnlockFrame(&av_pause_frame, "DeletePauseFrame");

vbuffers.DeleteBuffers();
}
Expand All @@ -61,8 +59,6 @@ void VideoOutputNull::Zoom(ZoomDirection direction)

void VideoOutputNull::CreatePauseFrame(void)
{
vbuffers.LockFrame(&av_pause_frame, "CreatePauseFrame");

if (av_pause_frame.buf)
{
delete [] av_pause_frame.buf;
Expand All @@ -78,8 +74,6 @@ void VideoOutputNull::CreatePauseFrame(void)
av_pause_frame.frameNumber = vbuffers.GetScratchFrame()->frameNumber;

clear(&av_pause_frame);

vbuffers.UnlockFrame(&av_pause_frame, "CreatePauseFrame");
}

bool VideoOutputNull::InputChanged(const QSize &input_size,
Expand Down Expand Up @@ -191,9 +185,7 @@ void VideoOutputNull::PrepareFrame(VideoFrame *buffer, FrameScanType t,
if (!buffer)
buffer = vbuffers.GetScratchFrame();

vbuffers.LockFrame(buffer, "PrepareFrame");
framesPlayed = buffer->frameNumber + 1;
vbuffers.UnlockFrame(buffer, "PrepareFrame");
}

void VideoOutputNull::Show(FrameScanType )
Expand All @@ -209,33 +201,20 @@ void VideoOutputNull::UpdatePauseFrame(void)
QMutexLocker locker(&global_lock);

// Try used frame first, then fall back to scratch frame.
vbuffers.LockFrame(&av_pause_frame, "UpdatePauseFrame -- pause");

vbuffers.begin_lock(kVideoBuffer_used);
VideoFrame *used_frame = NULL;
if (vbuffers.size(kVideoBuffer_used) > 0)
{
used_frame = vbuffers.head(kVideoBuffer_used);
if (!vbuffers.TryLockFrame(used_frame, "UpdatePauseFrame -- used"))
used_frame = NULL;
}

if (used_frame)
{
CopyFrame(&av_pause_frame, used_frame);
vbuffers.UnlockFrame(used_frame, "UpdatePauseFrame -- used");
}
vbuffers.end_lock();

if (!used_frame &&
vbuffers.TryLockFrame(vbuffers.GetScratchFrame(),
"UpdatePauseFrame -- scratch"))
if (!used_frame)
{
vbuffers.GetScratchFrame()->frameNumber = framesPlayed - 1;
CopyFrame(&av_pause_frame, vbuffers.GetScratchFrame());
vbuffers.UnlockFrame(vbuffers.GetScratchFrame(),
"UpdatePauseFrame -- scratch");
}
vbuffers.UnlockFrame(&av_pause_frame, "UpdatePauseFrame - used");
}

void VideoOutputNull::ProcessFrame(VideoFrame *frame, OSD *osd,
Expand Down
2 changes: 1 addition & 1 deletion mythtv/libs/libmythtv/videoout_opengl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ void VideoOutputOpenGL::InitOSD(void)
bool VideoOutputOpenGL::CreateBuffers(void)
{
QMutexLocker locker(&gl_context_lock);
vbuffers.Init(31, true, 1, 12, 4, 2, false);
vbuffers.Init(31, true, 1, 12, 4, 2);
return vbuffers.CreateBuffers(FMT_YV12,
window.GetVideoDim().width(),
window.GetVideoDim().height());
Expand Down
2 changes: 1 addition & 1 deletion mythtv/libs/libmythtv/videoout_vdpau.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ bool VideoOutputVDPAU::InitBuffers(void)
const QSize video_dim = codec_is_std(video_codec_id) ?
window.GetVideoDim() : window.GetActualVideoDim();

vbuffers.Init(m_buffer_size, false, 2, 1, 4, 1, false);
vbuffers.Init(m_buffer_size, false, 2, 1, 4, 1);

bool ok = false;
if (codec_is_vdpau(video_codec_id))
Expand Down
52 changes: 5 additions & 47 deletions mythtv/libs/libmythtv/videoout_xv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -517,8 +517,6 @@ int VideoOutputXv::GrabSuitableXvPort(MythXDisplay* disp, Window root,
*/
void VideoOutputXv::CreatePauseFrame(VOSType subtype)
{
vbuffers.LockFrame(&av_pause_frame, "CreatePauseFrame");

if (av_pause_frame.buf)
{
delete [] av_pause_frame.buf;
Expand All @@ -534,8 +532,6 @@ void VideoOutputXv::CreatePauseFrame(VOSType subtype)
av_pause_frame.frameNumber = vbuffers.GetScratchFrame()->frameNumber;

clear(&av_pause_frame);

vbuffers.UnlockFrame(&av_pause_frame, "CreatePauseFrame");
}

/**
Expand All @@ -551,7 +547,7 @@ bool VideoOutputXv::InitVideoBuffers(bool use_xv, bool use_shm)

// Create ffmpeg VideoFrames
if (!done)
vbuffers.Init(31, true, 1, 12, 4, 2, false);
vbuffers.Init(31, true, 1, 12, 4, 2);

// Fall back to XVideo if there is an xv_port
if (!done && use_xv)
Expand Down Expand Up @@ -1339,11 +1335,6 @@ void VideoOutputXv::StopEmbedding(void)
MoveResize();
}

VideoFrame *VideoOutputXv::GetNextFreeFrame(bool /*allow_unsafe*/)
{
return vbuffers.GetNextFreeFrame(false, false);
}

/**
* \fn VideoOutputXv::DiscardFrame(VideoFrame *frame)
* Frame is ready to be reused by decoder added to the
Expand Down Expand Up @@ -1390,10 +1381,8 @@ void VideoOutputXv::PrepareFrameXv(VideoFrame *frame)
XvImage *image = NULL;
{
QMutexLocker locker(&global_lock);
vbuffers.LockFrame(frame, "PrepareFrameXv");
framesPlayed = frame->frameNumber + 1;
image = (XvImage*) xv_buffers[frame->buf];
vbuffers.UnlockFrame(frame, "PrepareFrameXv");
}

if (vbuffers.GetScratchFrame() == frame)
Expand All @@ -1410,14 +1399,10 @@ void VideoOutputXv::PrepareFrameMem(VideoFrame *buffer, FrameScanType /*scan*/)
if (!buffer)
buffer = vbuffers.GetScratchFrame();

vbuffers.LockFrame(buffer, "PrepareFrameMem");

framesPlayed = buffer->frameNumber + 1;
int width = buffer->width;
int height = buffer->height;

vbuffers.UnlockFrame(buffer, "PrepareFrameMem");

// bad way to throttle frame display for non-Xv mode.
// calculate fps we can do and skip enough frames so we don't exceed.
if (non_xv_frames_shown == 0)
Expand Down Expand Up @@ -1463,7 +1448,6 @@ void VideoOutputXv::PrepareFrameMem(VideoFrame *buffer, FrameScanType /*scan*/)
avpicture_fill(&image_out, (uint8_t *)sbuf, PIX_FMT_YUV420P,
out_width, out_height);

vbuffers.LockFrame(buffer, "PrepareFrameMem");
if ((out_width == width) &&
(out_height == height))
{
Expand All @@ -1481,7 +1465,6 @@ void VideoOutputXv::PrepareFrameMem(VideoFrame *buffer, FrameScanType /*scan*/)
sws_scale(scontext, image_in.data, image_in.linesize, 0, height,
image_out.data, image_out.linesize);
}
vbuffers.UnlockFrame(buffer, "PrepareFrameMem");

avpicture_fill(&image_in, (uint8_t *)XJ_non_xv_image->data,
non_xv_av_format, out_width, out_height);
Expand Down Expand Up @@ -1606,14 +1589,9 @@ void VideoOutputXv::ShowXVideo(FrameScanType scan)
{
VideoFrame *frame = GetLastShownFrame();

vbuffers.LockFrame(frame, "ShowXVideo");

XvImage *image = (XvImage*) xv_buffers[frame->buf];
if (!image)
{
vbuffers.UnlockFrame(frame, "ShowXVideo");
return;
}

const QRect video_rect = window.GetVideoRect();
const QRect display_video_rect = (vsz_enabled && chroma_osd) ?
Expand All @@ -1632,10 +1610,8 @@ void VideoOutputXv::ShowXVideo(FrameScanType scan)
dest_y += xv_dest_y_incr;
}

vbuffers.UnlockFrame(frame, "ShowXVideo");
{
QMutexLocker locker(&global_lock);
vbuffers.LockFrame(frame, "ShowXVideo");
int video_height = (3 != field) ?
(video_rect.height()/2) : video_rect.height();
disp->Lock();
Expand All @@ -1647,7 +1623,6 @@ void VideoOutputXv::ShowXVideo(FrameScanType scan)
display_video_rect.width(),
display_video_rect.height(), False);
disp->Unlock();
vbuffers.UnlockFrame(frame, "ShowXVideo");
}
}

Expand Down Expand Up @@ -1793,33 +1768,22 @@ void VideoOutputXv::UpdatePauseFrame(void)
if (VideoOutputSubType() <= XVideo)
{
// Try used frame first, then fall back to scratch frame.
vbuffers.LockFrame(&av_pause_frame, "UpdatePauseFrame -- pause");

vbuffers.begin_lock(kVideoBuffer_used);

VideoFrame *used_frame = NULL;
if (vbuffers.size(kVideoBuffer_used) > 0)
{
used_frame = vbuffers.head(kVideoBuffer_used);
if (!vbuffers.TryLockFrame(used_frame, "UpdatePauseFrame -- used"))
used_frame = NULL;
}

if (used_frame)
{
CopyFrame(&av_pause_frame, used_frame);
vbuffers.UnlockFrame(used_frame, "UpdatePauseFrame -- used");
}

vbuffers.end_lock();

if (!used_frame &&
vbuffers.TryLockFrame(vbuffers.GetScratchFrame(),
"UpdatePauseFrame -- scratch"))
if (!used_frame)
{
vbuffers.GetScratchFrame()->frameNumber = framesPlayed - 1;
CopyFrame(&av_pause_frame, vbuffers.GetScratchFrame());
vbuffers.UnlockFrame(vbuffers.GetScratchFrame(),
"UpdatePauseFrame -- scratch");
}
vbuffers.UnlockFrame(&av_pause_frame, "UpdatePauseFrame - used");
}
}

Expand All @@ -1836,14 +1800,10 @@ void VideoOutputXv::ProcessFrameMem(VideoFrame *frame, OSD *osd,
vector<const VideoFrame*> locks;
locks.push_back(frame);
locks.push_back(&av_pause_frame);
vbuffers.LockFrames(locks, "ProcessFrameMem -- pause");
CopyFrame(frame, &av_pause_frame);
vbuffers.UnlockFrames(locks, "ProcessFrameMem -- pause");
pauseframe = true;
}

vbuffers.LockFrame(frame, "ProcessFrameMem");

bool safepauseframe = pauseframe && !IsBobDeint();
if (!pauseframe || safepauseframe)
{
Expand Down Expand Up @@ -1873,8 +1833,6 @@ void VideoOutputXv::ProcessFrameMem(VideoFrame *frame, OSD *osd,
{
m_deintFilter->ProcessFrame(frame, scan);
}

vbuffers.UnlockFrame(frame, "ProcessFrameMem");
}

// this is documented in videooutbase.cpp
Expand Down
1 change: 0 additions & 1 deletion mythtv/libs/libmythtv/videoout_xv.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,6 @@ class VideoOutputXv : public VideoOutput

private:
virtual bool hasFullScreenOSD(void) const { return chroma_osd; }
VideoFrame *GetNextFreeFrame(bool allow_unsafe);
void DiscardFrame(VideoFrame*);
void DiscardFrames(bool next_frame_keyframe);

Expand Down
9 changes: 2 additions & 7 deletions mythtv/libs/libmythtv/videooutbase.h
Original file line number Diff line number Diff line change
Expand Up @@ -182,14 +182,9 @@ class VideoOutput

/**
* \brief Blocks until it is possible to return a frame for decoding onto.
* \param with_lock if true frames are properly locked, but this means you
* must unlock them when you are done, so this is disabled by default.
* \param allow_unsafe if true then that are queued for display can be
* returned as frames to decode onto, this defaults to false.
*/
virtual VideoFrame *GetNextFreeFrame(bool with_lock = false,
bool allow_unsafe = false)
{ return vbuffers.GetNextFreeFrame(with_lock, allow_unsafe); }
virtual VideoFrame *GetNextFreeFrame(void)
{ return vbuffers.GetNextFreeFrame(); }
/// \brief Releases a frame from the ready for decoding queue onto the
/// queue of frames ready for display.
virtual void ReleaseFrame(VideoFrame *frame) { vbuffers.ReleaseFrame(frame); }
Expand Down