diff options
Diffstat (limited to 'libavcodec/pthread_frame.c')
-rw-r--r-- | libavcodec/pthread_frame.c | 320 |
1 files changed, 219 insertions, 101 deletions
diff --git a/libavcodec/pthread_frame.c b/libavcodec/pthread_frame.c index a72391b..5104b1b 100644 --- a/libavcodec/pthread_frame.c +++ b/libavcodec/pthread_frame.c @@ -1,18 +1,18 @@ /* - * This file is part of Libav. + * This file is part of FFmpeg. * - * Libav is free software; you can redistribute it and/or + * 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. * - * Libav is distributed in the hope that it will be useful, + * 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 Libav; if not, write to the Free Software + * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ @@ -27,12 +27,6 @@ #include <stdatomic.h> #include <stdint.h> -#if HAVE_PTHREADS -#include <pthread.h> -#elif HAVE_W32THREADS -#include "compat/w32pthreads.h" -#endif - #include "avcodec.h" #include "hwaccel.h" #include "internal.h" @@ -48,6 +42,8 @@ #include "libavutil/internal.h" #include "libavutil/log.h" #include "libavutil/mem.h" +#include "libavutil/opt.h" +#include "libavutil/thread.h" enum { ///< Set when the thread is awaiting a packet. @@ -59,6 +55,11 @@ enum { * State is returned to STATE_SETTING_UP afterwards. */ STATE_GET_BUFFER, + /** + * Set when the codec calls get_format(). + * State is returned to STATE_SETTING_UP afterwards. + */ + STATE_GET_FORMAT, ///< Set after the codec has called ff_thread_finish_setup(). STATE_SETUP_FINISHED, }; @@ -99,10 +100,15 @@ typedef struct PerThreadContext { AVFrame *requested_frame; ///< AVFrame the codec passed to get_buffer() int requested_flags; ///< flags passed to get_buffer() for requested_frame - int die; ///< Set when the thread should exit. + const enum AVPixelFormat *available_formats; ///< Format array for get_format() + enum AVPixelFormat result_format; ///< get_format() result + + int die; ///< Set when the thread should exit. int hwaccel_serializing; int async_serializing; + + atomic_int debug_threads; ///< Set if the FF_DEBUG_THREADS option is set. } PerThreadContext; /** @@ -119,6 +125,8 @@ typedef struct FrameThreadContext { */ pthread_mutex_t hwaccel_mutex; pthread_mutex_t async_mutex; + pthread_cond_t async_cond; + int async_lock; int next_decoding; ///< The next context to submit a packet to. int next_finished; ///< The next context to return output from. @@ -129,6 +137,27 @@ typedef struct FrameThreadContext { */ } FrameThreadContext; +#define THREAD_SAFE_CALLBACKS(avctx) \ +((avctx)->thread_safe_callbacks || (avctx)->get_buffer2 == avcodec_default_get_buffer2) + +static void async_lock(FrameThreadContext *fctx) +{ + pthread_mutex_lock(&fctx->async_mutex); + while (fctx->async_lock) + pthread_cond_wait(&fctx->async_cond, &fctx->async_mutex); + fctx->async_lock = 1; + pthread_mutex_unlock(&fctx->async_mutex); +} + +static void async_unlock(FrameThreadContext *fctx) +{ + pthread_mutex_lock(&fctx->async_mutex); + av_assert0(fctx->async_lock); + fctx->async_lock = 0; + pthread_cond_broadcast(&fctx->async_cond); + pthread_mutex_unlock(&fctx->async_mutex); +} + /** * Codec worker thread. * @@ -142,23 +171,15 @@ static attribute_align_arg void *frame_worker_thread(void *arg) AVCodecContext *avctx = p->avctx; const AVCodec *codec = avctx->codec; + pthread_mutex_lock(&p->mutex); while (1) { - if (atomic_load(&p->state) == STATE_INPUT_READY) { - pthread_mutex_lock(&p->mutex); - while (atomic_load(&p->state) == STATE_INPUT_READY) { - if (p->die) { - pthread_mutex_unlock(&p->mutex); - goto die; - } - pthread_cond_wait(&p->input_cond, &p->mutex); - } - pthread_mutex_unlock(&p->mutex); - } + while (atomic_load(&p->state) == STATE_INPUT_READY && !p->die) + pthread_cond_wait(&p->input_cond, &p->mutex); - if (!codec->update_thread_context && avctx->thread_safe_callbacks) - ff_thread_finish_setup(avctx); + if (p->die) break; - pthread_mutex_lock(&p->mutex); + if (!codec->update_thread_context && THREAD_SAFE_CALLBACKS(avctx)) + ff_thread_finish_setup(avctx); /* If a decoder supports hwaccel, then it must call ff_get_format(). * Since that call must happen before ff_thread_finish_setup(), the @@ -196,18 +217,19 @@ static attribute_align_arg void *frame_worker_thread(void *arg) if (p->async_serializing) { p->async_serializing = 0; - pthread_mutex_unlock(&p->parent->async_mutex); + + async_unlock(p->parent); } + pthread_mutex_lock(&p->progress_mutex); + atomic_store(&p->state, STATE_INPUT_READY); - pthread_mutex_lock(&p->progress_mutex); + pthread_cond_broadcast(&p->progress_cond); pthread_cond_signal(&p->output_cond); pthread_mutex_unlock(&p->progress_mutex); - - pthread_mutex_unlock(&p->mutex); } -die: + pthread_mutex_unlock(&p->mutex); return NULL; } @@ -218,12 +240,13 @@ die: * @param dst The destination context. * @param src The source context. * @param for_user 0 if the destination is a codec thread, 1 if the destination is the user's thread + * @return 0 on success, negative error code on failure */ static int update_context_from_thread(AVCodecContext *dst, AVCodecContext *src, int for_user) { int err = 0; - if (dst != src) { + if (dst != src && (for_user || !(src->codec_descriptor->props & AV_CODEC_PROP_INTRA_ONLY))) { dst->time_base = src->time_base; dst->framerate = src->framerate; dst->width = src->width; @@ -254,6 +277,11 @@ static int update_context_from_thread(AVCodecContext *dst, AVCodecContext *src, dst->hwaccel = src->hwaccel; dst->hwaccel_context = src->hwaccel_context; + + dst->channels = src->channels; + dst->sample_rate = src->sample_rate; + dst->sample_fmt = src->sample_fmt; + dst->channel_layout = src->channel_layout; dst->internal->hwaccel_priv_data = src->internal->hwaccel_priv_data; if (!!dst->hw_frames_ctx != !!src->hw_frames_ctx || @@ -271,6 +299,7 @@ static int update_context_from_thread(AVCodecContext *dst, AVCodecContext *src, } if (for_user) { + dst->delay = src->thread_count - 1; #if FF_API_CODED_FRAME FF_DISABLE_DEPRECATION_WARNINGS dst->coded_frame = src->coded_frame; @@ -301,6 +330,7 @@ static int update_context_from_user(AVCodecContext *dst, AVCodecContext *src) dst->opaque = src->opaque; dst->debug = src->debug; + dst->debug_mv = src->debug_mv; dst->slice_flags = src->slice_flags; dst->flags2 = src->flags2; @@ -309,16 +339,14 @@ static int update_context_from_user(AVCodecContext *dst, AVCodecContext *src) dst->frame_number = src->frame_number; dst->reordered_opaque = src->reordered_opaque; + dst->thread_safe_callbacks = src->thread_safe_callbacks; if (src->slice_count && src->slice_offset) { if (dst->slice_count < src->slice_count) { - int *tmp = av_realloc(dst->slice_offset, src->slice_count * - sizeof(*dst->slice_offset)); - if (!tmp) { - av_free(dst->slice_offset); - return AVERROR(ENOMEM); - } - dst->slice_offset = tmp; + int err = av_reallocp_array(&dst->slice_offset, src->slice_count, + sizeof(*dst->slice_offset)); + if (err < 0) + return err; } memcpy(dst->slice_offset, src->slice_offset, src->slice_count * sizeof(*dst->slice_offset)); @@ -339,7 +367,8 @@ static void release_delayed_buffers(PerThreadContext *p) pthread_mutex_lock(&fctx->buffer_mutex); // fix extended data in case the caller screwed it up - av_assert0(p->avctx->codec_type == AVMEDIA_TYPE_VIDEO); + av_assert0(p->avctx->codec_type == AVMEDIA_TYPE_VIDEO || + p->avctx->codec_type == AVMEDIA_TYPE_AUDIO); f = &p->released_buffers[--p->num_released_buffers]; f->extended_data = f->data; av_frame_unref(f); @@ -348,17 +377,28 @@ static void release_delayed_buffers(PerThreadContext *p) } } -static int submit_packet(PerThreadContext *p, AVPacket *avpkt) +static int submit_packet(PerThreadContext *p, AVCodecContext *user_avctx, + AVPacket *avpkt) { FrameThreadContext *fctx = p->parent; PerThreadContext *prev_thread = fctx->prev_thread; const AVCodec *codec = p->avctx->codec; + int ret; if (!avpkt->size && !(codec->capabilities & AV_CODEC_CAP_DELAY)) return 0; pthread_mutex_lock(&p->mutex); + ret = update_context_from_user(p->avctx, user_avctx); + if (ret) { + pthread_mutex_unlock(&p->mutex); + return ret; + } + atomic_store_explicit(&p->debug_threads, + (p->avctx->debug & FF_DEBUG_THREADS) != 0, + memory_order_relaxed); + release_delayed_buffers(p); if (prev_thread) { @@ -378,7 +418,12 @@ static int submit_packet(PerThreadContext *p, AVPacket *avpkt) } av_packet_unref(&p->avpkt); - av_packet_ref(&p->avpkt, avpkt); + ret = av_packet_ref(&p->avpkt, avpkt); + if (ret < 0) { + pthread_mutex_unlock(&p->mutex); + av_log(p->avctx, AV_LOG_ERROR, "av_packet_ref() failed in submit_packet()\n"); + return ret; + } atomic_store(&p->state, STATE_SETTING_UP); pthread_cond_signal(&p->input_cond); @@ -390,16 +435,27 @@ static int submit_packet(PerThreadContext *p, AVPacket *avpkt) * and it calls back to the client here. */ - if (!p->avctx->thread_safe_callbacks && - p->avctx->get_buffer2 != avcodec_default_get_buffer2) { - while (atomic_load(&p->state) != STATE_SETUP_FINISHED && - atomic_load(&p->state) != STATE_INPUT_READY) { + if (!p->avctx->thread_safe_callbacks && ( + p->avctx->get_format != avcodec_default_get_format || + p->avctx->get_buffer2 != avcodec_default_get_buffer2)) { + while (atomic_load(&p->state) != STATE_SETUP_FINISHED && atomic_load(&p->state) != STATE_INPUT_READY) { + int call_done = 1; pthread_mutex_lock(&p->progress_mutex); while (atomic_load(&p->state) == STATE_SETTING_UP) pthread_cond_wait(&p->progress_cond, &p->progress_mutex); - if (atomic_load_explicit(&p->state, memory_order_acquire) == STATE_GET_BUFFER) { + switch (atomic_load_explicit(&p->state, memory_order_acquire)) { + case STATE_GET_BUFFER: p->result = ff_get_buffer(p->avctx, p->requested_frame, p->requested_flags); + break; + case STATE_GET_FORMAT: + p->result_format = ff_get_format(p->avctx, p->available_formats); + break; + default: + call_done = 0; + break; + } + if (call_done) { atomic_store(&p->state, STATE_SETTING_UP); pthread_cond_signal(&p->progress_cond); } @@ -420,21 +476,18 @@ int ff_thread_decode_frame(AVCodecContext *avctx, FrameThreadContext *fctx = avctx->internal->thread_ctx; int finished = fctx->next_finished; PerThreadContext *p; - int err, ret; + int err; /* release the async lock, permitting blocked hwaccel threads to * go forward while we are in this function */ - pthread_mutex_unlock(&fctx->async_mutex); + async_unlock(fctx); /* * Submit a packet to the next decoding thread. */ p = &fctx->threads[fctx->next_decoding]; - err = update_context_from_user(p->avctx, avctx); - if (err) - goto finish; - err = submit_packet(p, avpkt); + err = submit_packet(p, avctx, avpkt); if (err) goto finish; @@ -442,12 +495,13 @@ int ff_thread_decode_frame(AVCodecContext *avctx, * If we're still receiving the initial packets, don't return a frame. */ - if (fctx->delaying) { - if (fctx->next_decoding >= (avctx->thread_count-1)) fctx->delaying = 0; + if (fctx->next_decoding > (avctx->thread_count-1-(avctx->codec_id == AV_CODEC_ID_FFV1))) + fctx->delaying = 0; + if (fctx->delaying) { *got_picture_ptr=0; if (avpkt->size) { - ret = avpkt->size; + err = avpkt->size; goto finish; } } @@ -455,8 +509,8 @@ int ff_thread_decode_frame(AVCodecContext *avctx, /* * Return the next available frame from the oldest thread. * If we're at the end of the stream, then we have to skip threads that - * didn't output a frame, because we don't want to accidentally signal - * EOF (avpkt->size == 0 && *got_picture_ptr == 0). + * didn't output a frame/error, because we don't want to accidentally signal + * EOF (avpkt->size == 0 && *got_picture_ptr == 0 && err >= 0). */ do { @@ -472,17 +526,19 @@ int ff_thread_decode_frame(AVCodecContext *avctx, av_frame_move_ref(picture, p->frame); *got_picture_ptr = p->got_frame; picture->pkt_dts = p->avpkt.dts; + err = p->result; /* * A later call with avkpt->size == 0 may loop over all threads, - * including this one, searching for a frame to return before being + * including this one, searching for a frame/error to return before being * stopped by the "finished != fctx->next_finished" condition. - * Make sure we don't mistakenly return the same frame again. + * Make sure we don't mistakenly return the same frame/error again. */ p->got_frame = 0; + p->result = 0; if (finished >= avctx->thread_count) finished = 0; - } while (!avpkt->size && !*got_picture_ptr && finished != fctx->next_finished); + } while (!avpkt->size && !*got_picture_ptr && err >= 0 && finished != fctx->next_finished); update_context_from_thread(avctx, p->avctx, 1); @@ -491,12 +547,11 @@ int ff_thread_decode_frame(AVCodecContext *avctx, fctx->next_finished = finished; /* return the size of the consumed packet if no error occurred */ - ret = (p->result >= 0) ? avpkt->size : p->result; + if (err >= 0) + err = avpkt->size; finish: - pthread_mutex_lock(&fctx->async_mutex); - if (err < 0) - return err; - return ret; + async_lock(fctx); + return err; } void ff_thread_report_progress(ThreadFrame *f, int n, int field) @@ -508,10 +563,11 @@ void ff_thread_report_progress(ThreadFrame *f, int n, int field) atomic_load_explicit(&progress[field], memory_order_relaxed) >= n) return; - p = f->owner->internal->thread_ctx; + p = f->owner[field]->internal->thread_ctx; - if (f->owner->debug&FF_DEBUG_THREADS) - av_log(f->owner, AV_LOG_DEBUG, "%p finished %d field %d\n", progress, n, field); + if (atomic_load_explicit(&p->debug_threads, memory_order_relaxed)) + av_log(f->owner[field], AV_LOG_DEBUG, + "%p finished %d field %d\n", progress, n, field); pthread_mutex_lock(&p->progress_mutex); @@ -530,10 +586,11 @@ void ff_thread_await_progress(ThreadFrame *f, int n, int field) atomic_load_explicit(&progress[field], memory_order_acquire) >= n) return; - p = f->owner->internal->thread_ctx; + p = f->owner[field]->internal->thread_ctx; - if (f->owner->debug&FF_DEBUG_THREADS) - av_log(f->owner, AV_LOG_DEBUG, "thread awaiting %d field %d from %p\n", n, field, progress); + if (atomic_load_explicit(&p->debug_threads, memory_order_relaxed)) + av_log(f->owner[field], AV_LOG_DEBUG, + "thread awaiting %d field %d from %p\n", n, field, progress); pthread_mutex_lock(&p->progress_mutex); while (atomic_load_explicit(&progress[field], memory_order_relaxed) < n) @@ -555,10 +612,14 @@ void ff_thread_finish_setup(AVCodecContext *avctx) { if (avctx->hwaccel && !(avctx->hwaccel->caps_internal & HWACCEL_CAP_ASYNC_SAFE)) { p->async_serializing = 1; - pthread_mutex_lock(&p->parent->async_mutex); + + async_lock(p->parent); } pthread_mutex_lock(&p->progress_mutex); + if(atomic_load(&p->state) == STATE_SETUP_FINISHED){ + av_log(avctx, AV_LOG_WARNING, "Multiple ff_thread_finish_setup() calls\n"); + } atomic_store(&p->state, STATE_SETUP_FINISHED); @@ -571,7 +632,7 @@ static void park_frame_worker_threads(FrameThreadContext *fctx, int thread_count { int i; - pthread_mutex_unlock(&fctx->async_mutex); + async_unlock(fctx); for (i = 0; i < thread_count; i++) { PerThreadContext *p = &fctx->threads[i]; @@ -582,9 +643,10 @@ static void park_frame_worker_threads(FrameThreadContext *fctx, int thread_count pthread_cond_wait(&p->output_cond, &p->progress_mutex); pthread_mutex_unlock(&p->progress_mutex); } + p->got_frame = 0; } - pthread_mutex_lock(&fctx->async_mutex); + async_lock(fctx); } void ff_frame_thread_free(AVCodecContext *avctx, int thread_count) @@ -596,7 +658,11 @@ void ff_frame_thread_free(AVCodecContext *avctx, int thread_count) park_frame_worker_threads(fctx, thread_count); if (fctx->prev_thread && fctx->prev_thread != fctx->threads) - update_context_from_thread(fctx->threads->avctx, fctx->prev_thread->avctx, 0); + if (update_context_from_thread(fctx->threads->avctx, fctx->prev_thread->avctx, 0) < 0) { + av_log(avctx, AV_LOG_ERROR, "Final thread update failed\n"); + fctx->prev_thread->avctx->internal->is_copy = fctx->threads->avctx->internal->is_copy; + fctx->threads->avctx->internal->is_copy = 1; + } for (i = 0; i < thread_count; i++) { PerThreadContext *p = &fctx->threads[i]; @@ -608,12 +674,11 @@ void ff_frame_thread_free(AVCodecContext *avctx, int thread_count) if (p->thread_init) pthread_join(p->thread, NULL); + p->thread_init=0; - if (codec->close) + if (codec->close && p->avctx) codec->close(p->avctx); - avctx->codec = NULL; - release_delayed_buffers(p); av_frame_free(&p->frame); } @@ -629,25 +694,30 @@ void ff_frame_thread_free(AVCodecContext *avctx, int thread_count) av_packet_unref(&p->avpkt); av_freep(&p->released_buffers); - if (i) { + if (i && p->avctx) { av_freep(&p->avctx->priv_data); av_freep(&p->avctx->slice_offset); } - av_buffer_unref(&p->avctx->hw_frames_ctx); + if (p->avctx) { + av_freep(&p->avctx->internal); + av_buffer_unref(&p->avctx->hw_frames_ctx); + } - av_freep(&p->avctx->internal); av_freep(&p->avctx); } av_freep(&fctx->threads); pthread_mutex_destroy(&fctx->buffer_mutex); pthread_mutex_destroy(&fctx->hwaccel_mutex); - - pthread_mutex_unlock(&fctx->async_mutex); pthread_mutex_destroy(&fctx->async_mutex); + pthread_cond_destroy(&fctx->async_cond); av_freep(&avctx->internal->thread_ctx); + + if (avctx->priv_data && avctx->codec && avctx->codec->priv_class) + av_opt_free(avctx->priv_data); + avctx->codec = NULL; } int ff_frame_thread_init(AVCodecContext *avctx) @@ -658,13 +728,12 @@ int ff_frame_thread_init(AVCodecContext *avctx) FrameThreadContext *fctx; int i, err = 0; -#if HAVE_W32THREADS - w32thread_init(); -#endif - if (!thread_count) { int nb_cpus = av_cpu_count(); - av_log(avctx, AV_LOG_DEBUG, "detected %d logical cores\n", nb_cpus); +#if FF_API_DEBUG_MV + if ((avctx->debug & (FF_DEBUG_VIS_QP | FF_DEBUG_VIS_MB_TYPE)) || avctx->debug_mv) + nb_cpus = 1; +#endif // use number of cores + 1 as thread count if there is more than one if (nb_cpus > 1) thread_count = avctx->thread_count = FFMIN(nb_cpus + 1, MAX_AUTO_THREADS); @@ -681,7 +750,7 @@ int ff_frame_thread_init(AVCodecContext *avctx) if (!fctx) return AVERROR(ENOMEM); - fctx->threads = av_mallocz(sizeof(PerThreadContext) * thread_count); + fctx->threads = av_mallocz_array(thread_count, sizeof(PerThreadContext)); if (!fctx->threads) { av_freep(&avctx->internal->thread_ctx); return AVERROR(ENOMEM); @@ -689,10 +758,10 @@ int ff_frame_thread_init(AVCodecContext *avctx) pthread_mutex_init(&fctx->buffer_mutex, NULL); pthread_mutex_init(&fctx->hwaccel_mutex, NULL); - pthread_mutex_init(&fctx->async_mutex, NULL); - pthread_mutex_lock(&fctx->async_mutex); + pthread_cond_init(&fctx->async_cond, NULL); + fctx->async_lock = 1; fctx->delaying = 1; for (i = 0; i < thread_count; i++) { @@ -724,6 +793,7 @@ int ff_frame_thread_init(AVCodecContext *avctx) copy->internal = av_malloc(sizeof(AVCodecInternal)); if (!copy->internal) { + copy->priv_data = NULL; err = AVERROR(ENOMEM); goto error; } @@ -753,8 +823,12 @@ int ff_frame_thread_init(AVCodecContext *avctx) if (err) goto error; - if (!pthread_create(&p->thread, NULL, frame_worker_thread, p)) - p->thread_init = 1; + atomic_init(&p->debug_threads, (copy->debug & FF_DEBUG_THREADS) != 0); + + err = AVERROR(pthread_create(&p->thread, NULL, frame_worker_thread, p)); + p->thread_init= !err; + if(!p->thread_init) + goto error; } return 0; @@ -786,6 +860,7 @@ void ff_thread_flush(AVCodecContext *avctx) // Make sure decode flush calls with size=0 won't return old frames p->got_frame = 0; av_frame_unref(p->frame); + p->result = 0; release_delayed_buffers(p); @@ -794,18 +869,28 @@ void ff_thread_flush(AVCodecContext *avctx) } } -int ff_thread_get_buffer(AVCodecContext *avctx, ThreadFrame *f, int flags) +int ff_thread_can_start_frame(AVCodecContext *avctx) +{ + PerThreadContext *p = avctx->internal->thread_ctx; + if ((avctx->active_thread_type&FF_THREAD_FRAME) && atomic_load(&p->state) != STATE_SETTING_UP && + (avctx->codec->update_thread_context || !THREAD_SAFE_CALLBACKS(avctx))) { + return 0; + } + return 1; +} + +static int thread_get_buffer_internal(AVCodecContext *avctx, ThreadFrame *f, int flags) { PerThreadContext *p = avctx->internal->thread_ctx; int err; - f->owner = avctx; + f->owner[0] = f->owner[1] = avctx; if (!(avctx->active_thread_type & FF_THREAD_FRAME)) return ff_get_buffer(avctx, f->f, flags); if (atomic_load(&p->state) != STATE_SETTING_UP && - (avctx->codec->update_thread_context || !avctx->thread_safe_callbacks)) { + (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"); return -1; } @@ -827,11 +912,11 @@ int ff_thread_get_buffer(AVCodecContext *avctx, ThreadFrame *f, int flags) avctx->get_buffer2 == avcodec_default_get_buffer2) { err = ff_get_buffer(avctx, f->f, flags); } else { + pthread_mutex_lock(&p->progress_mutex); p->requested_frame = f->f; p->requested_flags = flags; atomic_store_explicit(&p->state, STATE_GET_BUFFER, memory_order_release); - pthread_mutex_lock(&p->progress_mutex); - pthread_cond_signal(&p->progress_cond); + pthread_cond_broadcast(&p->progress_cond); while (atomic_load(&p->state) != STATE_SETTING_UP) pthread_cond_wait(&p->progress_cond, &p->progress_mutex); @@ -841,9 +926,8 @@ int ff_thread_get_buffer(AVCodecContext *avctx, ThreadFrame *f, int flags) pthread_mutex_unlock(&p->progress_mutex); } - if (!avctx->thread_safe_callbacks && !avctx->codec->update_thread_context) + if (!THREAD_SAFE_CALLBACKS(avctx) && !avctx->codec->update_thread_context) ff_thread_finish_setup(avctx); - if (err) av_buffer_unref(&f->progress); @@ -852,6 +936,40 @@ int ff_thread_get_buffer(AVCodecContext *avctx, ThreadFrame *f, int flags) return err; } +enum AVPixelFormat ff_thread_get_format(AVCodecContext *avctx, const enum AVPixelFormat *fmt) +{ + 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) + return ff_get_format(avctx, fmt); + if (atomic_load(&p->state) != STATE_SETTING_UP) { + av_log(avctx, AV_LOG_ERROR, "get_format() cannot be called after ff_thread_finish_setup()\n"); + return -1; + } + pthread_mutex_lock(&p->progress_mutex); + p->available_formats = fmt; + atomic_store(&p->state, STATE_GET_FORMAT); + pthread_cond_broadcast(&p->progress_cond); + + while (atomic_load(&p->state) != STATE_SETTING_UP) + pthread_cond_wait(&p->progress_cond, &p->progress_mutex); + + res = p->result_format; + + pthread_mutex_unlock(&p->progress_mutex); + + return res; +} + +int ff_thread_get_buffer(AVCodecContext *avctx, ThreadFrame *f, int flags) +{ + int ret = thread_get_buffer_internal(avctx, f, flags); + if (ret < 0) + av_log(avctx, AV_LOG_ERROR, "thread_get_buffer() failed\n"); + return ret; +} + void ff_thread_release_buffer(AVCodecContext *avctx, ThreadFrame *f) { PerThreadContext *p = avctx->internal->thread_ctx; @@ -868,7 +986,7 @@ void ff_thread_release_buffer(AVCodecContext *avctx, ThreadFrame *f) av_log(avctx, AV_LOG_DEBUG, "thread_release_buffer called on pic %p\n", f); av_buffer_unref(&f->progress); - f->owner = NULL; + f->owner[0] = f->owner[1] = NULL; if (can_direct_free) { av_frame_unref(f->f); |