diff options
Diffstat (limited to 'libavcodec/pthread_frame.c')
-rw-r--r-- | libavcodec/pthread_frame.c | 160 |
1 files changed, 131 insertions, 29 deletions
diff --git a/libavcodec/pthread_frame.c b/libavcodec/pthread_frame.c index a658f3e..1db46fc 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 */ @@ -30,6 +30,8 @@ #include <pthread.h> #elif HAVE_W32THREADS #include "compat/w32pthreads.h" +#elif HAVE_OS2THREADS +#include "compat/os2threads.h" #endif #include "avcodec.h" @@ -77,6 +79,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; @@ -90,6 +96,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; /** @@ -112,6 +121,14 @@ typedef struct FrameThreadContext { int die; ///< Set when threads should exit. } FrameThreadContext; +#if FF_API_GET_BUFFER +#define THREAD_SAFE_CALLBACKS(avctx) \ +((avctx)->thread_safe_callbacks || (!(avctx)->get_buffer && (avctx)->get_buffer2 == avcodec_default_get_buffer2)) +#else +#define THREAD_SAFE_CALLBACKS(avctx) \ +((avctx)->thread_safe_callbacks || (avctx)->get_buffer2 == avcodec_default_get_buffer2) +#endif + /** * Codec worker thread. * @@ -126,20 +143,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); av_frame_unref(p->frame); p->got_frame = 0; p->result = codec->decode(avctx, p->frame, &p->got_frame, &p->avpkt); @@ -153,14 +166,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; } @@ -210,10 +230,16 @@ FF_ENABLE_DEPRECATION_WARNINGS 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 (for_user) { + dst->delay = src->thread_count - 1; dst->coded_frame = src->coded_frame; } else { if (dst->codec->update_thread_context) @@ -246,6 +272,7 @@ FF_ENABLE_DEPRECATION_WARNINGS dst->opaque = src->opaque; dst->debug = src->debug; + dst->debug_mv = src->debug_mv; dst->slice_flags = src->slice_flags; dst->flags2 = src->flags2; @@ -254,6 +281,7 @@ FF_ENABLE_DEPRECATION_WARNINGS 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) { @@ -284,7 +312,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); @@ -336,18 +365,30 @@ static int submit_packet(PerThreadContext *p, AVPacket *avpkt) FF_DISABLE_DEPRECATION_WARNINGS 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)) { FF_ENABLE_DEPRECATION_WARNINGS 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 = ff_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); } @@ -384,9 +425,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; @@ -437,7 +479,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; @@ -455,7 +497,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; @@ -475,6 +517,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); @@ -495,6 +541,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; } } @@ -507,7 +554,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; + } fctx->die = 1; @@ -520,6 +571,7 @@ 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) codec->close(p->avctx); @@ -569,7 +621,8 @@ int ff_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); @@ -584,7 +637,7 @@ int ff_frame_thread_init(AVCodecContext *avctx) avctx->internal->thread_ctx = fctx = av_mallocz(sizeof(FrameThreadContext)); - fctx->threads = av_mallocz(sizeof(PerThreadContext) * thread_count); + fctx->threads = av_mallocz_array(thread_count, sizeof(PerThreadContext)); pthread_mutex_init(&fctx->buffer_mutex, NULL); fctx->delaying = 1; @@ -601,6 +654,7 @@ int ff_frame_thread_init(AVCodecContext *avctx) p->frame = av_frame_alloc(); if (!p->frame) { err = AVERROR(ENOMEM); + av_freep(©); goto error; } @@ -645,8 +699,10 @@ 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; + err = AVERROR(pthread_create(&p->thread, NULL, frame_worker_thread, p)); + p->thread_init= !err; + if(!p->thread_init) + goto error; } return 0; @@ -686,18 +742,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->internal->thread_ctx; + 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->internal->thread_ctx; 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; } @@ -723,11 +791,11 @@ FF_DISABLE_DEPRECATION_WARNINGS FF_ENABLE_DEPRECATION_WARNINGS 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); @@ -737,7 +805,7 @@ FF_ENABLE_DEPRECATION_WARNINGS 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) @@ -748,6 +816,40 @@ FF_ENABLE_DEPRECATION_WARNINGS 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 (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->internal->thread_ctx; |