pthread: Fix deadlock during thread initialization
[ffmpeg.git] / libavcodec / pthread.c
index 21e32b5..b0d9e27 100644 (file)
  */
 
 #include "config.h"
+
 #include "avcodec.h"
 #include "internal.h"
 #include "thread.h"
+#include "libavutil/avassert.h"
+#include "libavutil/common.h"
+#include "libavutil/cpu.h"
+#include "libavutil/internal.h"
 
 #if HAVE_PTHREADS
 #include <pthread.h>
 #elif HAVE_W32THREADS
-#include "w32pthreads.h"
+#include "compat/w32pthreads.h"
 #endif
 
 typedef int (action_func)(AVCodecContext *c, void *arg);
@@ -60,9 +65,6 @@ typedef struct ThreadContext {
     int done;
 } ThreadContext;
 
-/// Max number of frame buffers that can be allocated when using frame threads.
-#define MAX_BUFFERS (32+1)
-
 /**
  * Context used by codec threads and stored in their AVCodecContext thread_opaque.
  */
@@ -81,7 +83,8 @@ typedef struct PerThreadContext {
     AVCodecContext *avctx;          ///< Context used to decode packets passed to this thread.
 
     AVPacket       avpkt;           ///< Input packet (for decoding) or output (for encoding).
-    int            allocated_buf_size; ///< Size allocated for avpkt.data
+    uint8_t       *buf;             ///< backup storage for packet data when the input packet is not refcounted
+    int            allocated_buf_size; ///< Size allocated for buf
 
     AVFrame frame;                  ///< Output frame (for decoding) or input (for encoding).
     int     got_frame;              ///< The output of got_picture_ptr from the last avcodec_decode_video() call.
@@ -101,16 +104,12 @@ typedef struct PerThreadContext {
      * Array of frames passed to ff_thread_release_buffer().
      * Frames are released after all threads referencing them are finished.
      */
-    AVFrame released_buffers[MAX_BUFFERS];
-    int     num_released_buffers;
-
-    /**
-     * Array of progress values used by ff_thread_get_buffer().
-     */
-    int     progress[MAX_BUFFERS][2];
-    uint8_t progress_used[MAX_BUFFERS];
+    AVFrame *released_buffers;
+    int  num_released_buffers;
+    int      released_buffers_allocated;
 
     AVFrame *requested_frame;       ///< AVFrame the codec passed to get_buffer()
+    int      requested_flags;       ///< flags passed to get_buffer() for requested_frame
 } PerThreadContext;
 
 /**
@@ -133,6 +132,11 @@ typedef struct FrameThreadContext {
     int die;                       ///< Set when threads should exit.
 } FrameThreadContext;
 
+
+/* H264 slice threading seems to be buggy with more than 16 threads,
+ * limit the number of threads to 16 for automatic detection */
+#define MAX_AUTO_THREADS 16
+
 static void* attribute_align_arg worker(void *v)
 {
     AVCodecContext *avctx = v;
@@ -148,7 +152,8 @@ 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);
+            if (!c->done)
+                pthread_cond_wait(&c->current_job_cond, &c->current_job_lock);
             our_job = self_id;
 
             if (c->done) {
@@ -231,14 +236,26 @@ static int avcodec_thread_execute2(AVCodecContext *avctx, action_func2* func2, v
     return avcodec_thread_execute(avctx, NULL, arg, ret, job_count, 0);
 }
 
-static int thread_init(AVCodecContext *avctx)
+static int thread_init_internal(AVCodecContext *avctx)
 {
     int i;
     ThreadContext *c;
     int thread_count = avctx->thread_count;
 
-    if (thread_count <= 1)
+    if (!thread_count) {
+        int nb_cpus = av_cpu_count();
+        av_log(avctx, AV_LOG_DEBUG, "detected %d logical cores\n", nb_cpus);
+        // 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);
+        else
+            thread_count = avctx->thread_count = 1;
+    }
+
+    if (thread_count <= 1) {
+        avctx->active_thread_type = 0;
         return 0;
+    }
 
     c = av_mallocz(sizeof(ThreadContext));
     if (!c)
@@ -287,7 +304,7 @@ static attribute_align_arg void *frame_worker_thread(void *arg)
     PerThreadContext *p = arg;
     FrameThreadContext *fctx = p->parent;
     AVCodecContext *avctx = p->avctx;
-    AVCodec *codec = avctx->codec;
+    const AVCodec *codec = avctx->codec;
 
     while (1) {
         if (p->state == STATE_INPUT_READY && !fctx->die) {
@@ -307,6 +324,10 @@ static attribute_align_arg void *frame_worker_thread(void *arg)
         p->got_frame = 0;
         p->result = codec->decode(avctx, &p->frame, &p->got_frame, &p->avpkt);
 
+        /* many decoders assign whole AVFrames, thus overwriting extended_data;
+         * make sure it's set correctly */
+        p->frame.extended_data = p->frame.data;
+
         if (p->state == STATE_SETTING_UP) ff_thread_finish_setup(avctx);
 
         p->state = STATE_INPUT_READY;
@@ -322,7 +343,7 @@ static attribute_align_arg void *frame_worker_thread(void *arg)
 }
 
 /**
- * Updates the next thread's AVCodecContext with values from the reference thread's context.
+ * Update the next thread's AVCodecContext with values from the reference thread's context.
  *
  * @param dst The destination context.
  * @param src The source context.
@@ -333,7 +354,6 @@ static int update_context_from_thread(AVCodecContext *dst, AVCodecContext *src,
     int err = 0;
 
     if (dst != src) {
-        dst->sub_id    = src->sub_id;
         dst->time_base = src->time_base;
         dst->width     = src->width;
         dst->height    = src->height;
@@ -344,7 +364,6 @@ static int update_context_from_thread(AVCodecContext *dst, AVCodecContext *src,
 
         dst->has_b_frames = src->has_b_frames;
         dst->idct_algo    = src->idct_algo;
-        dst->slice_count  = src->slice_count;
 
         dst->bits_per_coded_sample = src->bits_per_coded_sample;
         dst->sample_aspect_ratio   = src->sample_aspect_ratio;
@@ -361,6 +380,9 @@ static int update_context_from_thread(AVCodecContext *dst, AVCodecContext *src,
         dst->colorspace  = src->colorspace;
         dst->color_range = src->color_range;
         dst->chroma_sample_location = src->chroma_sample_location;
+
+        dst->hwaccel = src->hwaccel;
+        dst->hwaccel_context = src->hwaccel_context;
     }
 
     if (for_user) {
@@ -378,37 +400,50 @@ static int update_context_from_thread(AVCodecContext *dst, AVCodecContext *src,
  *
  * @param dst The destination context.
  * @param src The source context.
+ * @return 0 on success, negative error code on failure
  */
-static void update_context_from_user(AVCodecContext *dst, AVCodecContext *src)
+static int update_context_from_user(AVCodecContext *dst, AVCodecContext *src)
 {
 #define copy_fields(s, e) memcpy(&dst->s, &src->s, (char*)&dst->e - (char*)&dst->s);
     dst->flags          = src->flags;
 
     dst->draw_horiz_band= src->draw_horiz_band;
+    dst->get_buffer2    = src->get_buffer2;
+#if FF_API_GET_BUFFER
+FF_DISABLE_DEPRECATION_WARNINGS
     dst->get_buffer     = src->get_buffer;
     dst->release_buffer = src->release_buffer;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
 
     dst->opaque   = src->opaque;
-    dst->dsp_mask = src->dsp_mask;
     dst->debug    = src->debug;
     dst->debug_mv = src->debug_mv;
 
     dst->slice_flags = src->slice_flags;
     dst->flags2      = src->flags2;
 
-    copy_fields(skip_loop_filter, bidir_refine);
+    copy_fields(skip_loop_filter, subtitle_header);
 
     dst->frame_number     = src->frame_number;
     dst->reordered_opaque = src->reordered_opaque;
-#undef copy_fields
-}
-
-static void free_progress(AVFrame *f)
-{
-    PerThreadContext *p = f->owner->thread_opaque;
-    int *progress = f->thread_opaque;
 
-    p->progress_used[(progress - p->progress[0]) / 2] = 0;
+    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;
+        }
+        memcpy(dst->slice_offset, src->slice_offset,
+               src->slice_count * sizeof(*dst->slice_offset));
+    }
+    dst->slice_count = src->slice_count;
+    return 0;
+#undef copy_fields
 }
 
 /// Releases the buffers that this decoding thread was the last user of.
@@ -420,11 +455,13 @@ static void release_delayed_buffers(PerThreadContext *p)
         AVFrame *f;
 
         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);
         f = &p->released_buffers[--p->num_released_buffers];
-        free_progress(f);
-        f->thread_opaque = NULL;
+        f->extended_data = f->data;
+        av_frame_unref(f);
 
-        f->owner->release_buffer(f->owner, f);
         pthread_mutex_unlock(&fctx->buffer_mutex);
     }
 }
@@ -433,8 +470,7 @@ static int submit_packet(PerThreadContext *p, AVPacket *avpkt)
 {
     FrameThreadContext *fctx = p->parent;
     PerThreadContext *prev_thread = fctx->prev_thread;
-    AVCodec *codec = p->avctx->codec;
-    uint8_t *buf = p->avpkt.data;
+    const AVCodec *codec = p->avctx->codec;
 
     if (!avpkt->size && !(codec->capabilities & CODEC_CAP_DELAY)) return 0;
 
@@ -458,11 +494,16 @@ static int submit_packet(PerThreadContext *p, AVPacket *avpkt)
         }
     }
 
-    av_fast_malloc(&buf, &p->allocated_buf_size, avpkt->size + FF_INPUT_BUFFER_PADDING_SIZE);
+    av_buffer_unref(&p->avpkt.buf);
     p->avpkt = *avpkt;
-    p->avpkt.data = buf;
-    memcpy(buf, avpkt->data, avpkt->size);
-    memset(buf + avpkt->size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
+    if (avpkt->buf)
+        p->avpkt.buf = av_buffer_ref(avpkt->buf);
+    else {
+        av_fast_malloc(&p->buf, &p->allocated_buf_size, avpkt->size + FF_INPUT_BUFFER_PADDING_SIZE);
+        p->avpkt.data = p->buf;
+        memcpy(p->buf, avpkt->data, avpkt->size);
+        memset(p->buf + avpkt->size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
+    }
 
     p->state = STATE_SETTING_UP;
     pthread_cond_signal(&p->input_cond);
@@ -474,15 +515,20 @@ 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_buffer != avcodec_default_get_buffer) {
+FF_DISABLE_DEPRECATION_WARNINGS
+    if (!p->avctx->thread_safe_callbacks && (
+#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) {
             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) {
-                p->result = p->avctx->get_buffer(p->avctx, p->requested_frame);
+                p->result = ff_get_buffer(p->avctx, p->requested_frame, p->requested_flags);
                 p->state  = STATE_SETTING_UP;
                 pthread_cond_signal(&p->progress_cond);
             }
@@ -491,6 +537,7 @@ static int submit_packet(PerThreadContext *p, AVPacket *avpkt)
     }
 
     fctx->prev_thread = p;
+    fctx->next_decoding++;
 
     return 0;
 }
@@ -509,21 +556,21 @@ int ff_thread_decode_frame(AVCodecContext *avctx,
      */
 
     p = &fctx->threads[fctx->next_decoding];
-    update_context_from_user(p->avctx, avctx);
+    err = update_context_from_user(p->avctx, avctx);
+    if (err) return err;
     err = submit_packet(p, avpkt);
     if (err) return err;
 
-    fctx->next_decoding++;
-
     /*
      * If we're still receiving the initial packets, don't return a frame.
      */
 
-    if (fctx->delaying && avpkt->size) {
+    if (fctx->delaying) {
         if (fctx->next_decoding >= (avctx->thread_count-1)) fctx->delaying = 0;
 
         *got_picture_ptr=0;
-        return avpkt->size;
+        if (avpkt->size)
+            return avpkt->size;
     }
 
     /*
@@ -543,7 +590,7 @@ int ff_thread_decode_frame(AVCodecContext *avctx,
             pthread_mutex_unlock(&p->progress_mutex);
         }
 
-        *picture = p->frame;
+        av_frame_move_ref(picture, &p->frame);
         *got_picture_ptr = p->got_frame;
         picture->pkt_dts = p->avpkt.dts;
 
@@ -568,10 +615,10 @@ int ff_thread_decode_frame(AVCodecContext *avctx,
     return (p->result >= 0) ? avpkt->size : p->result;
 }
 
-void ff_thread_report_progress(AVFrame *f, int n, int field)
+void ff_thread_report_progress(ThreadFrame *f, int n, int field)
 {
     PerThreadContext *p;
-    int *progress = f->thread_opaque;
+    int *progress = f->progress ? (int*)f->progress->data : NULL;
 
     if (!progress || progress[field] >= n) return;
 
@@ -586,10 +633,10 @@ void ff_thread_report_progress(AVFrame *f, int n, int field)
     pthread_mutex_unlock(&p->progress_mutex);
 }
 
-void ff_thread_await_progress(AVFrame *f, int n, int field)
+void ff_thread_await_progress(ThreadFrame *f, int n, int field)
 {
     PerThreadContext *p;
-    int *progress = f->thread_opaque;
+    int *progress = f->progress ? (int*)f->progress->data : NULL;
 
     if (!progress || progress[field] >= n) return;
 
@@ -635,7 +682,7 @@ static void park_frame_worker_threads(FrameThreadContext *fctx, int thread_count
 static void frame_thread_free(AVCodecContext *avctx, int thread_count)
 {
     FrameThreadContext *fctx = avctx->thread_opaque;
-    AVCodec *codec = avctx->codec;
+    const AVCodec *codec = avctx->codec;
     int i;
 
     park_frame_worker_threads(fctx, thread_count);
@@ -661,23 +708,25 @@ static void frame_thread_free(AVCodecContext *avctx, int thread_count)
         avctx->codec = NULL;
 
         release_delayed_buffers(p);
+        av_frame_unref(&p->frame);
     }
 
     for (i = 0; i < thread_count; i++) {
         PerThreadContext *p = &fctx->threads[i];
 
-        avcodec_default_free_buffers(p->avctx);
-
         pthread_mutex_destroy(&p->mutex);
         pthread_mutex_destroy(&p->progress_mutex);
         pthread_cond_destroy(&p->input_cond);
         pthread_cond_destroy(&p->progress_cond);
         pthread_cond_destroy(&p->output_cond);
-        av_freep(&p->avpkt.data);
+        av_buffer_unref(&p->avpkt.buf);
+        av_freep(&p->buf);
+        av_freep(&p->released_buffers);
 
         if (i) {
             av_freep(&p->avctx->priv_data);
             av_freep(&p->avctx->internal);
+            av_freep(&p->avctx->slice_offset);
         }
 
         av_freep(&p->avctx);
@@ -691,11 +740,21 @@ static void frame_thread_free(AVCodecContext *avctx, int thread_count)
 static int frame_thread_init(AVCodecContext *avctx)
 {
     int thread_count = avctx->thread_count;
-    AVCodec *codec = avctx->codec;
+    const AVCodec *codec = avctx->codec;
     AVCodecContext *src = avctx;
     FrameThreadContext *fctx;
     int i, err = 0;
 
+    if (!thread_count) {
+        int nb_cpus = av_cpu_count();
+        av_log(avctx, AV_LOG_DEBUG, "detected %d logical cores\n", nb_cpus);
+        // 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);
+        else
+            thread_count = avctx->thread_count = 1;
+    }
+
     if (thread_count <= 1) {
         avctx->active_thread_type = 0;
         return 0;
@@ -748,7 +807,7 @@ static int frame_thread_init(AVCodecContext *avctx)
                 err = AVERROR(ENOMEM);
                 goto error;
             }
-            *(copy->internal) = *(src->internal);
+            *copy->internal = *src->internal;
             copy->internal->is_copy = 1;
 
             if (codec->init_thread_copy)
@@ -771,6 +830,7 @@ error:
 
 void ff_thread_flush(AVCodecContext *avctx)
 {
+    int i;
     FrameThreadContext *fctx = avctx->thread_opaque;
 
     if (!avctx->thread_opaque) return;
@@ -786,36 +846,25 @@ void ff_thread_flush(AVCodecContext *avctx)
     fctx->next_decoding = fctx->next_finished = 0;
     fctx->delaying = 1;
     fctx->prev_thread = NULL;
-}
-
-static int *allocate_progress(PerThreadContext *p)
-{
-    int i;
-
-    for (i = 0; i < MAX_BUFFERS; i++)
-        if (!p->progress_used[i]) break;
+    for (i = 0; i < avctx->thread_count; i++) {
+        PerThreadContext *p = &fctx->threads[i];
+        // Make sure decode flush calls with size=0 won't return old frames
+        p->got_frame = 0;
+        av_frame_unref(&p->frame);
 
-    if (i == MAX_BUFFERS) {
-        av_log(p->avctx, AV_LOG_ERROR, "allocate_progress() overflow\n");
-        return NULL;
+        release_delayed_buffers(p);
     }
-
-    p->progress_used[i] = 1;
-
-    return p->progress[i];
 }
 
-int ff_thread_get_buffer(AVCodecContext *avctx, AVFrame *f)
+int ff_thread_get_buffer(AVCodecContext *avctx, ThreadFrame *f, int flags)
 {
     PerThreadContext *p = avctx->thread_opaque;
-    int *progress, err;
+    int err;
 
     f->owner = avctx;
 
-    if (!(avctx->active_thread_type&FF_THREAD_FRAME)) {
-        f->thread_opaque = NULL;
-        return avctx->get_buffer(avctx, 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)) {
@@ -823,22 +872,29 @@ int ff_thread_get_buffer(AVCodecContext *avctx, AVFrame *f)
         return -1;
     }
 
-    pthread_mutex_lock(&p->parent->buffer_mutex);
-    f->thread_opaque = progress = allocate_progress(p);
+    if (avctx->internal->allocate_progress) {
+        int *progress;
+        f->progress = av_buffer_alloc(2 * sizeof(int));
+        if (!f->progress) {
+            return AVERROR(ENOMEM);
+        }
+        progress = (int*)f->progress->data;
 
-    if (!progress) {
-        pthread_mutex_unlock(&p->parent->buffer_mutex);
-        return -1;
+        progress[0] = progress[1] = -1;
     }
 
-    progress[0] =
-    progress[1] = -1;
-
-    if (avctx->thread_safe_callbacks ||
-        avctx->get_buffer == avcodec_default_get_buffer) {
-        err = avctx->get_buffer(avctx, f);
+    pthread_mutex_lock(&p->parent->buffer_mutex);
+FF_DISABLE_DEPRECATION_WARNINGS
+    if (avctx->thread_safe_callbacks || (
+#if FF_API_GET_BUFFER
+        !avctx->get_buffer &&
+#endif
+        avctx->get_buffer2 == avcodec_default_get_buffer2)) {
+FF_ENABLE_DEPRECATION_WARNINGS
+        err = ff_get_buffer(avctx, f->f, flags);
     } else {
-        p->requested_frame = f;
+        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);
@@ -850,45 +906,66 @@ int ff_thread_get_buffer(AVCodecContext *avctx, AVFrame *f)
 
         pthread_mutex_unlock(&p->progress_mutex);
 
-        if (!avctx->codec->update_thread_context)
-            ff_thread_finish_setup(avctx);
     }
+    if (!avctx->thread_safe_callbacks && !avctx->codec->update_thread_context)
+        ff_thread_finish_setup(avctx);
 
-    pthread_mutex_unlock(&p->parent->buffer_mutex);
+    if (err)
+        av_buffer_unref(&f->progress);
 
-    /*
-     * Buffer age is difficult to keep track of between
-     * multiple threads, and the optimizations it allows
-     * are not worth the effort. It is disabled for now.
-     */
-    f->age = INT_MAX;
+    pthread_mutex_unlock(&p->parent->buffer_mutex);
 
     return err;
 }
 
-void ff_thread_release_buffer(AVCodecContext *avctx, AVFrame *f)
+void ff_thread_release_buffer(AVCodecContext *avctx, ThreadFrame *f)
 {
     PerThreadContext *p = avctx->thread_opaque;
     FrameThreadContext *fctx;
+    AVFrame *dst, *tmp;
+FF_DISABLE_DEPRECATION_WARNINGS
+    int can_direct_free = !(avctx->active_thread_type & FF_THREAD_FRAME) ||
+                          avctx->thread_safe_callbacks                   ||
+                          (
+#if FF_API_GET_BUFFER
+                           !avctx->get_buffer &&
+#endif
+                           avctx->get_buffer2 == avcodec_default_get_buffer2);
+FF_ENABLE_DEPRECATION_WARNINGS
 
-    if (!(avctx->active_thread_type&FF_THREAD_FRAME)) {
-        avctx->release_buffer(avctx, f);
+    if (!f->f->data[0])
         return;
-    }
 
-    if (p->num_released_buffers >= MAX_BUFFERS) {
-        av_log(p->avctx, AV_LOG_ERROR, "too many thread_release_buffer calls!\n");
+    if (avctx->debug & FF_DEBUG_BUFFERS)
+        av_log(avctx, AV_LOG_DEBUG, "thread_release_buffer called on pic %p\n", f);
+
+    av_buffer_unref(&f->progress);
+    f->owner    = NULL;
+
+    if (can_direct_free) {
+        av_frame_unref(f->f);
         return;
     }
 
-    if(avctx->debug & FF_DEBUG_BUFFERS)
-        av_log(avctx, AV_LOG_DEBUG, "thread_release_buffer called on pic %p\n", f);
-
     fctx = p->parent;
     pthread_mutex_lock(&fctx->buffer_mutex);
-    p->released_buffers[p->num_released_buffers++] = *f;
+
+    if (p->num_released_buffers + 1 >= INT_MAX / sizeof(*p->released_buffers))
+        goto fail;
+    tmp = av_fast_realloc(p->released_buffers, &p->released_buffers_allocated,
+                          (p->num_released_buffers + 1) *
+                          sizeof(*p->released_buffers));
+    if (!tmp)
+        goto fail;
+    p->released_buffers = tmp;
+
+    dst = &p->released_buffers[p->num_released_buffers];
+    av_frame_move_ref(dst, f->f);
+
+    p->num_released_buffers++;
+
+fail:
     pthread_mutex_unlock(&fctx->buffer_mutex);
-    memset(f->data, 0, sizeof(f->data));
 }
 
 /**
@@ -913,28 +990,29 @@ static void validate_thread_parameters(AVCodecContext *avctx)
     } else if (avctx->codec->capabilities & CODEC_CAP_SLICE_THREADS &&
                avctx->thread_type & FF_THREAD_SLICE) {
         avctx->active_thread_type = FF_THREAD_SLICE;
+    } else if (!(avctx->codec->capabilities & CODEC_CAP_AUTO_THREADS)) {
+        avctx->thread_count       = 1;
+        avctx->active_thread_type = 0;
     }
+
+    if (avctx->thread_count > MAX_AUTO_THREADS)
+        av_log(avctx, AV_LOG_WARNING,
+               "Application has requested %d threads. Using a thread count greater than %d is not recommended.\n",
+               avctx->thread_count, MAX_AUTO_THREADS);
 }
 
 int ff_thread_init(AVCodecContext *avctx)
 {
-    if (avctx->thread_opaque) {
-        av_log(avctx, AV_LOG_ERROR, "avcodec_thread_init is ignored after avcodec_open\n");
-        return -1;
-    }
-
 #if HAVE_W32THREADS
     w32thread_init();
 #endif
 
-    if (avctx->codec) {
-        validate_thread_parameters(avctx);
+    validate_thread_parameters(avctx);
 
-        if (avctx->active_thread_type&FF_THREAD_SLICE)
-            return thread_init(avctx);
-        else if (avctx->active_thread_type&FF_THREAD_FRAME)
-            return frame_thread_init(avctx);
-    }
+    if (avctx->active_thread_type&FF_THREAD_SLICE)
+        return thread_init_internal(avctx);
+    else if (avctx->active_thread_type&FF_THREAD_FRAME)
+        return frame_thread_init(avctx);
 
     return 0;
 }