diff options
Diffstat (limited to 'libavcodec/pthread.c')
-rw-r--r-- | libavcodec/pthread.c | 157 |
1 files changed, 127 insertions, 30 deletions
diff --git a/libavcodec/pthread.c b/libavcodec/pthread.c index 1523353580..7968a61358 100644 --- a/libavcodec/pthread.c +++ b/libavcodec/pthread.c @@ -6,20 +6,20 @@ * to Michael Niedermayer <michaelni@gmx.at> for writing initial * implementation. * - * 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 */ @@ -42,6 +42,8 @@ #include <pthread.h> #elif HAVE_W32THREADS #include "compat/w32pthreads.h" +#elif HAVE_OS2THREADS +#include "compat/os2threads.h" #endif typedef int (action_func)(AVCodecContext *c, void *arg); @@ -61,6 +63,7 @@ typedef struct ThreadContext { pthread_cond_t current_job_cond; pthread_mutex_t current_job_lock; int current_job; + unsigned int current_execute; int done; } ThreadContext; @@ -96,6 +99,10 @@ typedef struct PerThreadContext { * Set when the codec calls get_buffer(). * State is returned to STATE_SETTING_UP afterwards. */ + STATE_GET_FORMAT, /**< + * 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; @@ -109,6 +116,9 @@ typedef struct PerThreadContext { AVFrame *requested_frame; ///< AVFrame the codec passed to get_buffer() int requested_flags; ///< flags passed to get_buffer() for requested_frame + + const enum AVPixelFormat *available_formats; ///< Format array for get_format() + enum AVPixelFormat result_format; ///< get_format() result } PerThreadContext; /** @@ -141,6 +151,7 @@ static void* attribute_align_arg worker(void *v) AVCodecContext *avctx = v; ThreadContext *c = avctx->thread_opaque; int our_job = c->job_count; + int last_execute = 0; int thread_count = avctx->thread_count; int self_id; @@ -151,7 +162,9 @@ static void* attribute_align_arg worker(void *v) if (c->current_job == thread_count + c->job_count) pthread_cond_signal(&c->last_job_cond); - pthread_cond_wait(&c->current_job_cond, &c->current_job_lock); + while (last_execute == c->current_execute && !c->done) + pthread_cond_wait(&c->current_job_cond, &c->current_job_lock); + last_execute = c->current_execute; our_job = self_id; if (c->done) { @@ -171,7 +184,8 @@ static void* attribute_align_arg worker(void *v) static av_always_inline void avcodec_thread_park_workers(ThreadContext *c, int thread_count) { - pthread_cond_wait(&c->last_job_cond, &c->current_job_lock); + while (c->current_job != thread_count + c->job_count) + pthread_cond_wait(&c->last_job_cond, &c->current_job_lock); pthread_mutex_unlock(&c->current_job_lock); } @@ -220,6 +234,7 @@ static int avcodec_thread_execute(AVCodecContext *avctx, action_func* func, void c->rets = &dummy_ret; c->rets_count = 1; } + c->current_execute++; pthread_cond_broadcast(&c->current_job_cond); avcodec_thread_park_workers(c, avctx->thread_count); @@ -242,7 +257,8 @@ static int thread_init(AVCodecContext *avctx) if (!thread_count) { int nb_cpus = av_cpu_count(); - av_log(avctx, AV_LOG_DEBUG, "detected %d logical cores\n", nb_cpus); + if (avctx->height) + nb_cpus = FFMIN(nb_cpus, (avctx->height+15)/16); // 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); @@ -290,6 +306,9 @@ static int thread_init(AVCodecContext *avctx) return 0; } +#define THREAD_SAFE_CALLBACKS(avctx) \ +((avctx)->thread_safe_callbacks || (!(avctx)->get_buffer && (avctx)->get_buffer2 == avcodec_default_get_buffer2)) + /** * Codec worker thread. * @@ -304,20 +323,16 @@ 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 (p->state == STATE_INPUT_READY && !fctx->die) { - pthread_mutex_lock(&p->mutex); while (p->state == STATE_INPUT_READY && !fctx->die) pthread_cond_wait(&p->input_cond, &p->mutex); - pthread_mutex_unlock(&p->mutex); - } if (fctx->die) break; - if (!codec->update_thread_context && avctx->thread_safe_callbacks) + if (!codec->update_thread_context && THREAD_SAFE_CALLBACKS(avctx)) ff_thread_finish_setup(avctx); - pthread_mutex_lock(&p->mutex); avcodec_get_frame_defaults(&p->frame); p->got_frame = 0; p->result = codec->decode(avctx, &p->frame, &p->got_frame, &p->avpkt); @@ -328,14 +343,21 @@ static attribute_align_arg void *frame_worker_thread(void *arg) if (p->state == STATE_SETTING_UP) ff_thread_finish_setup(avctx); + pthread_mutex_lock(&p->progress_mutex); +#if 0 //BUFREF-FIXME + for (i = 0; i < MAX_BUFFERS; i++) + if (p->progress_used[i] && (p->got_frame || p->result<0 || avctx->codec_id != AV_CODEC_ID_H264)) { + p->progress[i][0] = INT_MAX; + p->progress[i][1] = INT_MAX; + } +#endif 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); } + pthread_mutex_unlock(&p->mutex); return NULL; } @@ -384,6 +406,7 @@ static int update_context_from_thread(AVCodecContext *dst, AVCodecContext *src, } if (for_user) { + dst->delay = src->thread_count - 1; dst->coded_frame = src->coded_frame; } else { if (dst->codec->update_thread_context) @@ -423,6 +446,7 @@ 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) { @@ -512,17 +536,29 @@ static int submit_packet(PerThreadContext *p, AVPacket *avpkt) */ if (!p->avctx->thread_safe_callbacks && ( + p->avctx->get_format != avcodec_default_get_format || #if FF_API_GET_BUFFER p->avctx->get_buffer || #endif p->avctx->get_buffer2 != avcodec_default_get_buffer2)) { while (p->state != STATE_SETUP_FINISHED && p->state != STATE_INPUT_READY) { + int call_done = 1; pthread_mutex_lock(&p->progress_mutex); while (p->state == STATE_SETTING_UP) pthread_cond_wait(&p->progress_cond, &p->progress_mutex); - if (p->state == STATE_GET_BUFFER) { + switch (p->state) { + 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 = p->avctx->get_format(p->avctx, p->available_formats); + break; + default: + call_done = 0; + break; + } + if (call_done) { p->state = STATE_SETTING_UP; pthread_cond_signal(&p->progress_cond); } @@ -559,9 +595,10 @@ 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) return avpkt->size; @@ -612,7 +649,7 @@ int ff_thread_decode_frame(AVCodecContext *avctx, void ff_thread_report_progress(ThreadFrame *f, int n, int field) { PerThreadContext *p; - int *progress = f->progress ? (int*)f->progress->data : NULL; + volatile int *progress = f->progress ? (int*)f->progress->data : NULL; if (!progress || progress[field] >= n) return; @@ -630,7 +667,7 @@ void ff_thread_report_progress(ThreadFrame *f, int n, int field) void ff_thread_await_progress(ThreadFrame *f, int n, int field) { PerThreadContext *p; - int *progress = f->progress ? (int*)f->progress->data : NULL; + volatile int *progress = f->progress ? (int*)f->progress->data : NULL; if (!progress || progress[field] >= n) return; @@ -650,6 +687,10 @@ void ff_thread_finish_setup(AVCodecContext *avctx) { if (!(avctx->active_thread_type&FF_THREAD_FRAME)) return; + if(p->state == STATE_SETUP_FINISHED){ + av_log(avctx, AV_LOG_WARNING, "Multiple ff_thread_finish_setup() calls\n"); + } + pthread_mutex_lock(&p->progress_mutex); p->state = STATE_SETUP_FINISHED; pthread_cond_broadcast(&p->progress_cond); @@ -670,6 +711,7 @@ 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; } } @@ -682,7 +724,11 @@ static void 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; + } fctx->die = 1; @@ -695,6 +741,7 @@ static void frame_thread_free(AVCodecContext *avctx, int thread_count) if (p->thread_init) pthread_join(p->thread, NULL); + p->thread_init=0; if (codec->close) codec->close(p->avctx); @@ -741,7 +788,8 @@ static int frame_thread_init(AVCodecContext *avctx) if (!thread_count) { int nb_cpus = av_cpu_count(); - av_log(avctx, AV_LOG_DEBUG, "detected %d logical cores\n", nb_cpus); + if ((avctx->debug & (FF_DEBUG_VIS_QP | FF_DEBUG_VIS_MB_TYPE)) || avctx->debug_mv) + nb_cpus = 1; // 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); @@ -810,8 +858,10 @@ static int frame_thread_init(AVCodecContext *avctx) if (err) goto error; - if (!pthread_create(&p->thread, NULL, frame_worker_thread, p)) - p->thread_init = 1; + err = AVERROR(pthread_create(&p->thread, NULL, frame_worker_thread, p)); + p->thread_init= !err; + if(!p->thread_init) + goto error; } return 0; @@ -850,18 +900,30 @@ 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->thread_opaque; + if ((avctx->active_thread_type&FF_THREAD_FRAME) && 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->thread_opaque; int err; f->owner = avctx; + ff_init_buffer_info(avctx, f->f); + if (!(avctx->active_thread_type & FF_THREAD_FRAME)) return ff_get_buffer(avctx, f->f, flags); if (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; } @@ -878,6 +940,7 @@ int ff_thread_get_buffer(AVCodecContext *avctx, ThreadFrame *f, int flags) } pthread_mutex_lock(&p->parent->buffer_mutex); + if (avctx->thread_safe_callbacks || ( #if FF_API_GET_BUFFER !avctx->get_buffer && @@ -885,11 +948,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; p->state = STATE_GET_BUFFER; - pthread_mutex_lock(&p->progress_mutex); - pthread_cond_signal(&p->progress_cond); + pthread_cond_broadcast(&p->progress_cond); while (p->state != STATE_SETTING_UP) pthread_cond_wait(&p->progress_cond, &p->progress_mutex); @@ -899,7 +962,7 @@ 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) @@ -910,6 +973,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->thread_opaque; + if (!(avctx->active_thread_type & FF_THREAD_FRAME) || avctx->thread_safe_callbacks || + avctx->get_format == avcodec_default_get_format) + return avctx->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"); + return -1; + } + pthread_mutex_lock(&p->progress_mutex); + p->available_formats = fmt; + p->state = STATE_GET_FORMAT; + pthread_cond_broadcast(&p->progress_cond); + + while (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->thread_opaque; |