mirror of https://github.com/FFmpeg/FFmpeg.git
* cigaes/master: ffmpeg: use thread message API. lavu: add thread message API. compat/w32pthreads: add return value to pthread_cond_init(). Merged-by: Michael Niedermayer <michaelni@gmx.at>pull/72/head
commit
2db89765f3
8 changed files with 316 additions and 81 deletions
@ -0,0 +1,184 @@ |
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014 Nicolas George |
||||||
|
* |
||||||
|
* This file is part of FFmpeg. |
||||||
|
* |
||||||
|
* FFmpeg is free software; you can redistribute it and/or |
||||||
|
* modify it under the terms of the GNU Lesser General Public License |
||||||
|
* as published by the Free Software Foundation; either |
||||||
|
* version 2.1 of the License, or (at your option) any later version. |
||||||
|
* |
||||||
|
* FFmpeg is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU Lesser General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU Lesser General Public License |
||||||
|
* along with FFmpeg; if not, write to the Free Software Foundation, Inc., |
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "fifo.h" |
||||||
|
#include "threadmessage.h" |
||||||
|
#if HAVE_THREADS |
||||||
|
#if HAVE_PTHREADS |
||||||
|
#include <pthread.h> |
||||||
|
#elif HAVE_W32THREADS |
||||||
|
#include "compat/w32pthreads.h" |
||||||
|
#elif HAVE_OS2THREADS |
||||||
|
#include "compat/os2threads.h" |
||||||
|
#else |
||||||
|
#error "Unknown threads implementation" |
||||||
|
#endif |
||||||
|
#endif |
||||||
|
|
||||||
|
struct AVThreadMessageQueue { |
||||||
|
#if HAVE_THREADS |
||||||
|
AVFifoBuffer *fifo; |
||||||
|
pthread_mutex_t lock; |
||||||
|
pthread_cond_t cond; |
||||||
|
int err_send; |
||||||
|
int err_recv; |
||||||
|
unsigned elsize; |
||||||
|
#else |
||||||
|
int dummy; |
||||||
|
#endif |
||||||
|
}; |
||||||
|
|
||||||
|
int av_thread_message_queue_alloc(AVThreadMessageQueue **mq, |
||||||
|
unsigned nelem, |
||||||
|
unsigned elsize) |
||||||
|
{ |
||||||
|
#if HAVE_THREADS |
||||||
|
AVThreadMessageQueue *rmq; |
||||||
|
int ret = 0; |
||||||
|
|
||||||
|
if (nelem > INT_MAX / elsize) |
||||||
|
return AVERROR(EINVAL); |
||||||
|
if (!(rmq = av_mallocz(sizeof(*rmq)))) |
||||||
|
return AVERROR(ENOMEM); |
||||||
|
if ((ret = pthread_mutex_init(&rmq->lock, NULL))) { |
||||||
|
av_free(rmq); |
||||||
|
return AVERROR(ret); |
||||||
|
} |
||||||
|
if ((ret = pthread_cond_init(&rmq->cond, NULL))) { |
||||||
|
pthread_mutex_destroy(&rmq->lock); |
||||||
|
av_free(rmq); |
||||||
|
return AVERROR(ret); |
||||||
|
} |
||||||
|
if (!(rmq->fifo = av_fifo_alloc(elsize * nelem))) { |
||||||
|
pthread_cond_destroy(&rmq->cond); |
||||||
|
pthread_mutex_destroy(&rmq->lock); |
||||||
|
av_free(rmq); |
||||||
|
return AVERROR(ret); |
||||||
|
} |
||||||
|
rmq->elsize = elsize; |
||||||
|
*mq = rmq; |
||||||
|
return 0; |
||||||
|
#else |
||||||
|
*mq = NULL; |
||||||
|
return AVERROR(ENOSYS); |
||||||
|
#endif /* HAVE_THREADS */ |
||||||
|
} |
||||||
|
|
||||||
|
void av_thread_message_queue_free(AVThreadMessageQueue **mq) |
||||||
|
{ |
||||||
|
#if HAVE_THREADS |
||||||
|
if (*mq) { |
||||||
|
av_fifo_freep(&(*mq)->fifo); |
||||||
|
pthread_cond_destroy(&(*mq)->cond); |
||||||
|
pthread_mutex_destroy(&(*mq)->lock); |
||||||
|
av_freep(mq); |
||||||
|
} |
||||||
|
#endif |
||||||
|
} |
||||||
|
|
||||||
|
#if HAVE_THREADS |
||||||
|
|
||||||
|
static int av_thread_message_queue_send_locked(AVThreadMessageQueue *mq, |
||||||
|
void *msg, |
||||||
|
unsigned flags) |
||||||
|
{ |
||||||
|
while (!mq->err_send && av_fifo_space(mq->fifo) < mq->elsize) { |
||||||
|
if ((flags & AV_THREAD_MESSAGE_NONBLOCK)) |
||||||
|
return AVERROR(EAGAIN); |
||||||
|
pthread_cond_wait(&mq->cond, &mq->lock); |
||||||
|
} |
||||||
|
if (mq->err_send) |
||||||
|
return mq->err_send; |
||||||
|
av_fifo_generic_write(mq->fifo, msg, mq->elsize, NULL); |
||||||
|
pthread_cond_signal(&mq->cond); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
static int av_thread_message_queue_recv_locked(AVThreadMessageQueue *mq, |
||||||
|
void *msg, |
||||||
|
unsigned flags) |
||||||
|
{ |
||||||
|
while (!mq->err_recv && av_fifo_size(mq->fifo) < mq->elsize) { |
||||||
|
if ((flags & AV_THREAD_MESSAGE_NONBLOCK)) |
||||||
|
return AVERROR(EAGAIN); |
||||||
|
pthread_cond_wait(&mq->cond, &mq->lock); |
||||||
|
} |
||||||
|
if (av_fifo_size(mq->fifo) < mq->elsize) |
||||||
|
return mq->err_recv; |
||||||
|
av_fifo_generic_read(mq->fifo, msg, mq->elsize, NULL); |
||||||
|
pthread_cond_signal(&mq->cond); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
#endif /* HAVE_THREADS */ |
||||||
|
|
||||||
|
int av_thread_message_queue_send(AVThreadMessageQueue *mq, |
||||||
|
void *msg, |
||||||
|
unsigned flags) |
||||||
|
{ |
||||||
|
#if HAVE_THREADS |
||||||
|
int ret; |
||||||
|
|
||||||
|
pthread_mutex_lock(&mq->lock); |
||||||
|
ret = av_thread_message_queue_send_locked(mq, msg, flags); |
||||||
|
pthread_mutex_unlock(&mq->lock); |
||||||
|
return ret; |
||||||
|
#else |
||||||
|
return AVERROR(ENOSYS); |
||||||
|
#endif /* HAVE_THREADS */ |
||||||
|
} |
||||||
|
|
||||||
|
int av_thread_message_queue_recv(AVThreadMessageQueue *mq, |
||||||
|
void *msg, |
||||||
|
unsigned flags) |
||||||
|
{ |
||||||
|
#if HAVE_THREADS |
||||||
|
int ret; |
||||||
|
|
||||||
|
pthread_mutex_lock(&mq->lock); |
||||||
|
ret = av_thread_message_queue_recv_locked(mq, msg, flags); |
||||||
|
pthread_mutex_unlock(&mq->lock); |
||||||
|
return ret; |
||||||
|
#else |
||||||
|
return AVERROR(ENOSYS); |
||||||
|
#endif /* HAVE_THREADS */ |
||||||
|
} |
||||||
|
|
||||||
|
void av_thread_message_queue_set_err_send(AVThreadMessageQueue *mq, |
||||||
|
int err) |
||||||
|
{ |
||||||
|
#if HAVE_THREADS |
||||||
|
pthread_mutex_lock(&mq->lock); |
||||||
|
mq->err_send = err; |
||||||
|
pthread_cond_broadcast(&mq->cond); |
||||||
|
pthread_mutex_unlock(&mq->lock); |
||||||
|
#endif /* HAVE_THREADS */ |
||||||
|
} |
||||||
|
|
||||||
|
void av_thread_message_queue_set_err_recv(AVThreadMessageQueue *mq, |
||||||
|
int err) |
||||||
|
{ |
||||||
|
#if HAVE_THREADS |
||||||
|
pthread_mutex_lock(&mq->lock); |
||||||
|
mq->err_recv = err; |
||||||
|
pthread_cond_broadcast(&mq->cond); |
||||||
|
pthread_mutex_unlock(&mq->lock); |
||||||
|
#endif /* HAVE_THREADS */ |
||||||
|
} |
@ -0,0 +1,91 @@ |
|||||||
|
/*
|
||||||
|
* This file is part of FFmpeg. |
||||||
|
* |
||||||
|
* FFmpeg is free software; you can redistribute it and/or |
||||||
|
* modify it under the terms of the GNU Lesser General Public License |
||||||
|
* as published by the Free Software Foundation; either |
||||||
|
* version 2.1 of the License, or (at your option) any later version. |
||||||
|
* |
||||||
|
* FFmpeg is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU Lesser General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU Lesser General Public License |
||||||
|
* along with FFmpeg; if not, write to the Free Software Foundation, Inc., |
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef AVUTIL_THREADMESSAGE_H |
||||||
|
#define AVUTIL_THREADMESSAGE_H |
||||||
|
|
||||||
|
typedef struct AVThreadMessageQueue AVThreadMessageQueue; |
||||||
|
|
||||||
|
typedef enum AVThreadMessageFlags { |
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform non-blocking operation. |
||||||
|
* If this flag is set, send and recv operations are non-blocking and |
||||||
|
* return AVERROR(EAGAIN) immediately if they can not proceed. |
||||||
|
*/ |
||||||
|
AV_THREAD_MESSAGE_NONBLOCK = 1, |
||||||
|
|
||||||
|
} AVThreadMessageFlags; |
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocate a new message queue. |
||||||
|
* |
||||||
|
* @param mq pointer to the message queue |
||||||
|
* @param nelem maximum number of elements in the queue |
||||||
|
* @param elsize size of each element in the queue |
||||||
|
* @return >=0 for success; <0 for error, in particular AVERROR(ENOSYS) if |
||||||
|
* lavu was built without thread support |
||||||
|
*/ |
||||||
|
int av_thread_message_queue_alloc(AVThreadMessageQueue **mq, |
||||||
|
unsigned nelem, |
||||||
|
unsigned elsize); |
||||||
|
|
||||||
|
/**
|
||||||
|
* Free a message queue. |
||||||
|
* |
||||||
|
* The message queue must no longer be in use by another thread. |
||||||
|
*/ |
||||||
|
void av_thread_message_queue_free(AVThreadMessageQueue **mq); |
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a message on the queue. |
||||||
|
*/ |
||||||
|
int av_thread_message_queue_send(AVThreadMessageQueue *mq, |
||||||
|
void *msg, |
||||||
|
unsigned flags); |
||||||
|
|
||||||
|
/**
|
||||||
|
* Receive a message from the queue. |
||||||
|
*/ |
||||||
|
int av_thread_message_queue_recv(AVThreadMessageQueue *mq, |
||||||
|
void *msg, |
||||||
|
unsigned flags); |
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the sending error code. |
||||||
|
* |
||||||
|
* If the error code is set to non-zero, av_thread_message_queue_recv() will |
||||||
|
* return it immediately when there are no longer available messages. |
||||||
|
* Conventional values, such as AVERROR_EOF or AVERROR(EAGAIN), can be used |
||||||
|
* to cause the receiving thread to stop or suspend its operation. |
||||||
|
*/ |
||||||
|
void av_thread_message_queue_set_err_send(AVThreadMessageQueue *mq, |
||||||
|
int err); |
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the receiving error code. |
||||||
|
* |
||||||
|
* If the error code is set to non-zero, av_thread_message_queue_send() will |
||||||
|
* return it immediately. Conventional values, such as AVERROR_EOF or |
||||||
|
* AVERROR(EAGAIN), can be used to cause the sending thread to stop or |
||||||
|
* suspend its operation. |
||||||
|
*/ |
||||||
|
void av_thread_message_queue_set_err_recv(AVThreadMessageQueue *mq, |
||||||
|
int err); |
||||||
|
|
||||||
|
#endif /* AVUTIL_THREADMESSAGE_H */ |
Loading…
Reference in new issue