From b52c216539bdbee830e0d306b372037d4e0cb35f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Reimar=20D=C3=B6ffinger?= Date: Sun, 8 Mar 2015 19:44:12 +0100 Subject: [PATCH] pthread: Fix ff_thread_get_format issues when called outside frame decode Patch part of the XBMC patch set for ffmpeg, downloaded from https://github.com/xbmc/FFmpeg/. Signed-off-by: Bernd Kuhls --- libavcodec/pthread_frame.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/libavcodec/pthread_frame.c b/libavcodec/pthread_frame.c index 5a4ab84..c29d0a9 100644 --- a/libavcodec/pthread_frame.c +++ b/libavcodec/pthread_frame.c @@ -53,6 +53,7 @@ * Context used by codec threads and stored in their AVCodecInternal thread_ctx. */ typedef struct PerThreadContext { + int main_thread; struct FrameThreadContext *parent; pthread_t thread; @@ -83,7 +84,8 @@ typedef struct PerThreadContext { * Set when the codec calls get_format(). * State is returned to STATE_SETTING_UP afterwards. */ - STATE_SETUP_FINISHED ///< Set after the codec has called ff_thread_finish_setup(). + STATE_SETUP_FINISHED, ///< Set after the codec has called ff_thread_finish_setup(). + STATE_UPDATE_CONTEXT, ///< Main thread is updating its context } state; /** @@ -105,6 +107,7 @@ typedef struct PerThreadContext { * Context stored in the client AVCodecInternal thread_ctx. */ typedef struct FrameThreadContext { + int main_thread; PerThreadContext *threads; ///< The contexts for each thread. PerThreadContext *prev_thread; ///< The last thread submit_packet() was called on. @@ -143,6 +146,7 @@ static attribute_align_arg void *frame_worker_thread(void *arg) AVCodecContext *avctx = p->avctx; const AVCodec *codec = avctx->codec; + av_assert0(!p->main_thread); pthread_mutex_lock(&p->mutex); while (1) { while (p->state == STATE_INPUT_READY && !fctx->die) @@ -330,6 +334,8 @@ static int submit_packet(PerThreadContext *p, AVPacket *avpkt) pthread_mutex_lock(&p->mutex); + p->state = STATE_UPDATE_CONTEXT; + release_delayed_buffers(p); if (prev_thread) { @@ -408,6 +414,7 @@ int ff_thread_decode_frame(AVCodecContext *avctx, int finished = fctx->next_finished; PerThreadContext *p; int err; + av_assert0(fctx->main_thread); /* * Submit a packet to the next decoding thread. @@ -515,6 +522,7 @@ void ff_thread_finish_setup(AVCodecContext *avctx) { if (!(avctx->active_thread_type&FF_THREAD_FRAME)) return; + av_assert0(!p->main_thread); if(p->state == STATE_SETUP_FINISHED){ av_log(avctx, AV_LOG_WARNING, "Multiple ff_thread_finish_setup() calls\n"); } @@ -549,6 +557,7 @@ void ff_frame_thread_free(AVCodecContext *avctx, int thread_count) const AVCodec *codec = avctx->codec; int i; + av_assert0(fctx->main_thread); park_frame_worker_threads(fctx, thread_count); if (fctx->prev_thread && fctx->prev_thread != fctx->threads) @@ -634,6 +643,7 @@ int ff_frame_thread_init(AVCodecContext *avctx) } avctx->internal->thread_ctx = fctx = av_mallocz(sizeof(FrameThreadContext)); + fctx->main_thread = 1; fctx->threads = av_mallocz_array(thread_count, sizeof(PerThreadContext)); pthread_mutex_init(&fctx->buffer_mutex, NULL); @@ -718,6 +728,7 @@ void ff_thread_flush(AVCodecContext *avctx) if (!fctx) return; + av_assert0(fctx->main_thread); park_frame_worker_threads(fctx, avctx->thread_count); if (fctx->prev_thread) { if (fctx->prev_thread != &fctx->threads[0]) @@ -743,7 +754,10 @@ void ff_thread_flush(AVCodecContext *avctx) int ff_thread_can_start_frame(AVCodecContext *avctx) { PerThreadContext *p = avctx->internal->thread_ctx; - if ((avctx->active_thread_type&FF_THREAD_FRAME) && p->state != STATE_SETTING_UP && + if (!(avctx->active_thread_type&FF_THREAD_FRAME)) + return 1; + av_assert0(!p->main_thread); + if (p->state != STATE_SETTING_UP && (avctx->codec->update_thread_context || !THREAD_SAFE_CALLBACKS(avctx))) { return 0; } @@ -762,6 +776,7 @@ static int thread_get_buffer_internal(AVCodecContext *avctx, ThreadFrame *f, int if (!(avctx->active_thread_type & FF_THREAD_FRAME)) return ff_get_buffer(avctx, f->f, flags); + av_assert0(!p->main_thread); if (p->state != STATE_SETTING_UP && (avctx->codec->update_thread_context || !THREAD_SAFE_CALLBACKS(avctx))) { av_log(avctx, AV_LOG_ERROR, "get_buffer() cannot be called after ff_thread_finish_setup()\n"); @@ -819,7 +834,8 @@ enum AVPixelFormat ff_thread_get_format(AVCodecContext *avctx, const enum AVPixe enum AVPixelFormat res; PerThreadContext *p = avctx->internal->thread_ctx; if (!(avctx->active_thread_type & FF_THREAD_FRAME) || avctx->thread_safe_callbacks || - avctx->get_format == avcodec_default_get_format) + avctx->get_format == avcodec_default_get_format || + p->main_thread || p->state == STATE_UPDATE_CONTEXT) return ff_get_format(avctx, fmt); if (p->state != STATE_SETTING_UP) { av_log(avctx, AV_LOG_ERROR, "get_format() cannot be called after ff_thread_finish_setup()\n");