diff --git a/libavcodec/h263dec.c b/libavcodec/h263dec.c index 405d3c68fd..cc87bc7dee 100644 --- a/libavcodec/h263dec.c +++ b/libavcodec/h263dec.c @@ -64,7 +64,7 @@ av_cold int ff_h263_decode_init(AVCodecContext *avctx) if (avctx->codec->id == AV_CODEC_ID_MSS2) avctx->pix_fmt = AV_PIX_FMT_YUV420P; else - avctx->pix_fmt = avctx->get_format(avctx, avctx->codec->pix_fmts); + avctx->pix_fmt = ff_thread_get_format(avctx, avctx->codec->pix_fmts); s->unrestricted_mv= 1; /* select sub codec */ diff --git a/libavcodec/h264.c b/libavcodec/h264.c index b4df424f5b..e5bab1b7b6 100644 --- a/libavcodec/h264.c +++ b/libavcodec/h264.c @@ -3043,7 +3043,7 @@ static enum AVPixelFormat get_pixel_format(H264Context *h, int force_callback) for (i=0; fmt[i] != AV_PIX_FMT_NONE; i++) if (fmt[i] == h->avctx->pix_fmt && !force_callback) return fmt[i]; - return h->avctx->get_format(h->avctx, fmt); + return ff_thread_get_format(h->avctx, fmt); } break; default: diff --git a/libavcodec/mpeg12dec.c b/libavcodec/mpeg12dec.c index 9221fc3915..e969893f77 100644 --- a/libavcodec/mpeg12dec.c +++ b/libavcodec/mpeg12dec.c @@ -1131,7 +1131,7 @@ static enum AVPixelFormat mpeg_get_pixelformat(AVCodecContext *avctx) MpegEncContext *s = &s1->mpeg_enc_ctx; if(s->chroma_format < 2) { - return avctx->get_format(avctx, + return ff_thread_get_format(avctx, avctx->codec_id == AV_CODEC_ID_MPEG1VIDEO ? mpeg1_hwaccel_pixfmt_list_420 : mpeg2_hwaccel_pixfmt_list_420); diff --git a/libavcodec/pthread.c b/libavcodec/pthread.c index 29a2308fae..7e33ba5d19 100644 --- a/libavcodec/pthread.c +++ b/libavcodec/pthread.c @@ -119,6 +119,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; @@ -132,6 +136,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; /** @@ -586,17 +593,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); } @@ -1018,6 +1037,32 @@ static int thread_get_buffer_internal(AVCodecContext *avctx, ThreadFrame *f, int 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); diff --git a/libavcodec/thread.h b/libavcodec/thread.h index 24e62b4967..0dc04e0702 100644 --- a/libavcodec/thread.h +++ b/libavcodec/thread.h @@ -97,6 +97,16 @@ void ff_thread_report_progress(ThreadFrame *f, int progress, int field); */ void ff_thread_await_progress(ThreadFrame *f, int progress, int field); +/** + * Wrapper around get_format() for frame-multithreaded codecs. + * Call this function instead of avctx->get_format(). + * Cannot be called after the codec has called ff_thread_finish_setup(). + * + * @param avctx The current context. + * @param fmt The list of available formats. + */ +enum AVPixelFormat ff_thread_get_format(AVCodecContext *avctx, const enum AVPixelFormat *fmt); + /** * Wrapper around get_buffer() for frame-multithreaded codecs. * Call this function instead of ff_get_buffer(f). diff --git a/libavcodec/utils.c b/libavcodec/utils.c index e4ea32523d..034b54a460 100644 --- a/libavcodec/utils.c +++ b/libavcodec/utils.c @@ -3034,6 +3034,11 @@ int ff_thread_ref_frame(ThreadFrame *dst, ThreadFrame *src) #if !HAVE_THREADS +enum AVPixelFormat ff_thread_get_format(AVCodecContext *avctx, const enum AVPixelFormat *fmt) +{ + return avctx->get_format(avctx, fmt); +} + int ff_thread_get_buffer(AVCodecContext *avctx, ThreadFrame *f, int flags) { f->owner = avctx;