diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
index f722ae7632..bef910a787 100644
--- a/fftools/ffmpeg.c
+++ b/fftools/ffmpeg.c
@@ -2543,11 +2543,6 @@ static int init_input_stream(InputStream *ist, char *error, int error_len)
 
         ist->dec_ctx->opaque                = ist;
         ist->dec_ctx->get_format            = get_format;
-#if LIBAVCODEC_VERSION_MAJOR < 60
-        AV_NOWARN_DEPRECATED({
-        ist->dec_ctx->thread_safe_callbacks = 1;
-        })
-#endif
 
         if (ist->dec_ctx->codec_id == AV_CODEC_ID_DVB_SUBTITLE &&
            (ist->decoding_needed & DECODING_FOR_OST)) {
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 0ac581d660..c1a4fbf4d0 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -1484,27 +1484,6 @@ typedef struct AVCodecContext {
      */
     int active_thread_type;
 
-#if FF_API_THREAD_SAFE_CALLBACKS
-    /**
-     * Set by the client if its custom get_buffer() callback can be called
-     * synchronously from another thread, which allows faster multithreaded decoding.
-     * draw_horiz_band() will be called from other threads regardless of this setting.
-     * Ignored if the default get_buffer() is used.
-     * - encoding: Set by user.
-     * - decoding: Set by user.
-     *
-     * @deprecated the custom get_buffer2() callback should always be
-     *   thread-safe. Thread-unsafe get_buffer2() implementations will be
-     *   invalid starting with LIBAVCODEC_VERSION_MAJOR=60; in other words,
-     *   libavcodec will behave as if this field was always set to 1.
-     *   Callers that want to be forward compatible with future libavcodec
-     *   versions should wrap access to this field in
-     *     `#if LIBAVCODEC_VERSION_MAJOR < 60`
-     */
-    attribute_deprecated
-    int thread_safe_callbacks;
-#endif
-
     /**
      * The codec may call this to execute several independent things.
      * It will return only after finishing all tasks.
diff --git a/libavcodec/decode.c b/libavcodec/decode.c
index 0abc88737b..3680fc539c 100644
--- a/libavcodec/decode.c
+++ b/libavcodec/decode.c
@@ -1593,19 +1593,6 @@ int ff_decode_preinit(AVCodecContext *avctx)
      * free the already allocated subtitle_header before overwriting it */
     av_freep(&avctx->subtitle_header);
 
-#if FF_API_THREAD_SAFE_CALLBACKS
-FF_DISABLE_DEPRECATION_WARNINGS
-    if ((avctx->thread_type & FF_THREAD_FRAME) &&
-        avctx->get_buffer2 != avcodec_default_get_buffer2 &&
-        !avctx->thread_safe_callbacks) {
-        av_log(avctx, AV_LOG_WARNING, "Requested frame threading with a "
-               "custom get_buffer2() implementation which is not marked as "
-               "thread safe. This is not supported anymore, make your "
-               "callback thread-safe.\n");
-    }
-FF_ENABLE_DEPRECATION_WARNINGS
-#endif
-
     if (avctx->codec->max_lowres < avctx->lowres || avctx->lowres < 0) {
         av_log(avctx, AV_LOG_WARNING, "The maximum value for lowres supported by the decoder is %d\n",
                avctx->codec->max_lowres);
diff --git a/libavcodec/encode.c b/libavcodec/encode.c
index fbe2c97cd6..9f45927390 100644
--- a/libavcodec/encode.c
+++ b/libavcodec/encode.c
@@ -231,10 +231,9 @@ int ff_encode_encode_cb(AVCodecContext *avctx, AVPacket *avpkt,
 unref:
         av_packet_unref(avpkt);
     }
-#if !FF_API_THREAD_SAFE_CALLBACKS
+
     if (frame)
         av_frame_unref(frame);
-#endif
 
     return ret;
 }
@@ -275,10 +274,6 @@ static int encode_simple_internal(AVCodecContext *avctx, AVPacket *avpkt)
         ret = ff_thread_video_encode_frame(avctx, avpkt, frame, &got_packet);
     else {
         ret = ff_encode_encode_cb(avctx, avpkt, frame, &got_packet);
-#if FF_API_THREAD_SAFE_CALLBACKS
-        if (frame)
-            av_frame_unref(frame);
-#endif
     }
 
     if (avci->draining && !got_packet)
diff --git a/libavcodec/frame_thread_encoder.c b/libavcodec/frame_thread_encoder.c
index 35775ae823..62d9580ad4 100644
--- a/libavcodec/frame_thread_encoder.c
+++ b/libavcodec/frame_thread_encoder.c
@@ -48,9 +48,6 @@ typedef struct{
 
 typedef struct{
     AVCodecContext *parent_avctx;
-#if FF_API_THREAD_SAFE_CALLBACKS
-    pthread_mutex_t buffer_mutex;
-#endif
 
     pthread_mutex_t task_fifo_mutex; /* Used to guard (next_)task_index */
     pthread_cond_t task_fifo_cond;
@@ -70,15 +67,9 @@ typedef struct{
 } ThreadContext;
 
 #define OFF(member) offsetof(ThreadContext, member)
-#if FF_API_THREAD_SAFE_CALLBACKS
-DEFINE_OFFSET_ARRAY(ThreadContext, thread_ctx, pthread_init_cnt,
-                    (OFF(buffer_mutex), OFF(task_fifo_mutex), OFF(finished_task_mutex)),
-                    (OFF(task_fifo_cond), OFF(finished_task_cond)));
-#else
 DEFINE_OFFSET_ARRAY(ThreadContext, thread_ctx, pthread_init_cnt,
                     (OFF(task_fifo_mutex), OFF(finished_task_mutex)),
                     (OFF(task_fifo_cond),  OFF(finished_task_cond)));
-#endif
 #undef OFF
 
 static void * attribute_align_arg worker(void *v){
@@ -112,11 +103,6 @@ static void * attribute_align_arg worker(void *v){
         pkt   = task->outdata;
 
         ret = ff_encode_encode_cb(avctx, pkt, frame, &task->got_packet);
-#if FF_API_THREAD_SAFE_CALLBACKS
-        pthread_mutex_lock(&c->buffer_mutex);
-        av_frame_unref(frame);
-        pthread_mutex_unlock(&c->buffer_mutex);
-#endif
         pthread_mutex_lock(&c->finished_task_mutex);
         task->return_code = ret;
         task->finished    = 1;
@@ -124,13 +110,7 @@ static void * attribute_align_arg worker(void *v){
         pthread_mutex_unlock(&c->finished_task_mutex);
     }
 end:
-#if FF_API_THREAD_SAFE_CALLBACKS
-    pthread_mutex_lock(&c->buffer_mutex);
-#endif
     avcodec_close(avctx);
-#if FF_API_THREAD_SAFE_CALLBACKS
-    pthread_mutex_unlock(&c->buffer_mutex);
-#endif
     av_freep(&avctx);
     return NULL;
 }
diff --git a/libavcodec/pthread_frame.c b/libavcodec/pthread_frame.c
index 62a0b18a8a..81c2114378 100644
--- a/libavcodec/pthread_frame.c
+++ b/libavcodec/pthread_frame.c
@@ -99,22 +99,6 @@ typedef struct PerThreadContext {
 
     atomic_int state;
 
-#if FF_API_THREAD_SAFE_CALLBACKS
-    /**
-     * Array of frames passed to ff_thread_release_buffer().
-     * Frames are released after all threads referencing them are finished.
-     */
-    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
-
-    const enum AVPixelFormat *available_formats; ///< Format array for get_format()
-    enum AVPixelFormat result_format;            ///< get_format() result
-#endif
-
     int die;                        ///< Set when the thread should exit.
 
     int hwaccel_serializing;
@@ -156,11 +140,6 @@ typedef struct FrameThreadContext {
     void            *stash_hwaccel_priv;
 } FrameThreadContext;
 
-#if FF_API_THREAD_SAFE_CALLBACKS
-#define THREAD_SAFE_CALLBACKS(avctx) \
-((avctx)->thread_safe_callbacks || (avctx)->get_buffer2 == avcodec_default_get_buffer2)
-#endif
-
 static void async_lock(FrameThreadContext *fctx)
 {
     pthread_mutex_lock(&fctx->async_mutex);
@@ -212,14 +191,8 @@ static attribute_align_arg void *frame_worker_thread(void *arg)
 
         if (p->die) break;
 
-FF_DISABLE_DEPRECATION_WARNINGS
-        if (!codec->update_thread_context
-#if FF_API_THREAD_SAFE_CALLBACKS
-            && THREAD_SAFE_CALLBACKS(avctx)
-#endif
-            )
+        if (!codec->update_thread_context)
             ff_thread_finish_setup(avctx);
-FF_ENABLE_DEPRECATION_WARNINGS
 
         /* If a decoder supports hwaccel, then it must call ff_get_format().
          * Since that call must happen before ff_thread_finish_setup(), the
@@ -391,11 +364,6 @@ static int update_context_from_user(AVCodecContext *dst, AVCodecContext *src)
 
     dst->frame_number     = src->frame_number;
     dst->reordered_opaque = src->reordered_opaque;
-#if FF_API_THREAD_SAFE_CALLBACKS
-FF_DISABLE_DEPRECATION_WARNINGS
-    dst->thread_safe_callbacks = src->thread_safe_callbacks;
-FF_ENABLE_DEPRECATION_WARNINGS
-#endif
 
     if (src->slice_count && src->slice_offset) {
         if (dst->slice_count < src->slice_count) {
@@ -417,29 +385,6 @@ FF_ENABLE_DEPRECATION_WARNINGS
     return 0;
 }
 
-#if FF_API_THREAD_SAFE_CALLBACKS
-/// Releases the buffers that this decoding thread was the last user of.
-static void release_delayed_buffers(PerThreadContext *p)
-{
-    FrameThreadContext *fctx = p->parent;
-
-    while (p->num_released_buffers > 0) {
-        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 ||
-                   p->avctx->codec_type == AVMEDIA_TYPE_AUDIO);
-        f = p->released_buffers[--p->num_released_buffers];
-        f->extended_data = f->data;
-        av_frame_unref(f);
-
-        pthread_mutex_unlock(&fctx->buffer_mutex);
-    }
-}
-#endif
-
 static int submit_packet(PerThreadContext *p, AVCodecContext *user_avctx,
                          AVPacket *avpkt)
 {
@@ -462,10 +407,6 @@ static int submit_packet(PerThreadContext *p, AVCodecContext *user_avctx,
                           (p->avctx->debug & FF_DEBUG_THREADS) != 0,
                           memory_order_relaxed);
 
-#if FF_API_THREAD_SAFE_CALLBACKS
-    release_delayed_buffers(p);
-#endif
-
     if (prev_thread) {
         int err;
         if (atomic_load(&prev_thread->state) == STATE_SETTING_UP) {
@@ -500,44 +441,6 @@ static int submit_packet(PerThreadContext *p, AVCodecContext *user_avctx,
     pthread_cond_signal(&p->input_cond);
     pthread_mutex_unlock(&p->mutex);
 
-#if FF_API_THREAD_SAFE_CALLBACKS
-FF_DISABLE_DEPRECATION_WARNINGS
-    /*
-     * If the client doesn't have a thread-safe get_buffer(),
-     * then decoding threads call back to the main thread,
-     * and it calls back to the client here.
-     */
-
-    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);
-
-            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);
-            }
-            pthread_mutex_unlock(&p->progress_mutex);
-        }
-    }
-FF_ENABLE_DEPRECATION_WARNINGS
-#endif
-
     fctx->prev_thread = p;
     fctx->next_decoding++;
 
@@ -768,12 +671,6 @@ void ff_frame_thread_free(AVCodecContext *avctx, int thread_count)
             if (codec->close && p->thread_init != UNINITIALIZED)
                 codec->close(ctx);
 
-#if FF_API_THREAD_SAFE_CALLBACKS
-            release_delayed_buffers(p);
-            for (int j = 0; j < p->released_buffers_allocated; j++)
-                av_frame_free(&p->released_buffers[j]);
-            av_freep(&p->released_buffers);
-#endif
             if (ctx->priv_data) {
                 if (codec->p.priv_class)
                     av_opt_free(ctx->priv_data);
@@ -971,10 +868,6 @@ void ff_thread_flush(AVCodecContext *avctx)
         av_frame_unref(p->frame);
         p->result = 0;
 
-#if FF_API_THREAD_SAFE_CALLBACKS
-        release_delayed_buffers(p);
-#endif
-
         if (ffcodec(avctx->codec)->flush)
             ffcodec(avctx->codec)->flush(p->avctx);
     }
@@ -983,16 +876,12 @@ void ff_thread_flush(AVCodecContext *avctx)
 int ff_thread_can_start_frame(AVCodecContext *avctx)
 {
     PerThreadContext *p = avctx->internal->thread_ctx;
-FF_DISABLE_DEPRECATION_WARNINGS
+
     if ((avctx->active_thread_type&FF_THREAD_FRAME) && atomic_load(&p->state) != STATE_SETTING_UP &&
-        (ffcodec(avctx->codec)->update_thread_context
-#if FF_API_THREAD_SAFE_CALLBACKS
-         || !THREAD_SAFE_CALLBACKS(avctx)
-#endif
-         )) {
+        ffcodec(avctx->codec)->update_thread_context) {
         return 0;
     }
-FF_ENABLE_DEPRECATION_WARNINGS
+
     return 1;
 }
 
@@ -1007,80 +896,20 @@ static int thread_get_buffer_internal(AVCodecContext *avctx, AVFrame *f, int fla
     p = avctx->internal->thread_ctx;
 FF_DISABLE_DEPRECATION_WARNINGS
     if (atomic_load(&p->state) != STATE_SETTING_UP &&
-        (ffcodec(avctx->codec)->update_thread_context
-#if FF_API_THREAD_SAFE_CALLBACKS
-         || !THREAD_SAFE_CALLBACKS(avctx)
-#endif
-         )) {
+        ffcodec(avctx->codec)->update_thread_context) {
 FF_ENABLE_DEPRECATION_WARNINGS
         av_log(avctx, AV_LOG_ERROR, "get_buffer() cannot be called after ff_thread_finish_setup()\n");
         return -1;
     }
 
     pthread_mutex_lock(&p->parent->buffer_mutex);
-#if !FF_API_THREAD_SAFE_CALLBACKS
     err = ff_get_buffer(avctx, f, flags);
-#else
-FF_DISABLE_DEPRECATION_WARNINGS
-    if (THREAD_SAFE_CALLBACKS(avctx)) {
-        err = ff_get_buffer(avctx, f, flags);
-    } else {
-        pthread_mutex_lock(&p->progress_mutex);
-        p->requested_frame = f;
-        p->requested_flags = flags;
-        atomic_store_explicit(&p->state, STATE_GET_BUFFER, memory_order_release);
-        pthread_cond_broadcast(&p->progress_cond);
-
-        while (atomic_load(&p->state) != STATE_SETTING_UP)
-            pthread_cond_wait(&p->progress_cond, &p->progress_mutex);
-
-        err = p->result;
-
-        pthread_mutex_unlock(&p->progress_mutex);
-
-    }
-    if (!THREAD_SAFE_CALLBACKS(avctx) && !ffcodec(avctx->codec)->update_thread_context)
-        ff_thread_finish_setup(avctx);
-FF_ENABLE_DEPRECATION_WARNINGS
-#endif
 
     pthread_mutex_unlock(&p->parent->buffer_mutex);
 
     return err;
 }
 
-#if FF_API_THREAD_SAFE_CALLBACKS
-FF_DISABLE_DEPRECATION_WARNINGS
-enum AVPixelFormat ff_thread_get_format(AVCodecContext *avctx, const enum AVPixelFormat *fmt)
-{
-    enum AVPixelFormat res;
-    PerThreadContext *p;
-    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);
-
-    p = avctx->internal->thread_ctx;
-    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;
-}
-FF_ENABLE_DEPRECATION_WARNINGS
-#endif
-
 int ff_thread_get_buffer(AVCodecContext *avctx, AVFrame *f, int flags)
 {
     int ret = thread_get_buffer_internal(avctx, f, flags);
@@ -1122,69 +951,13 @@ int ff_thread_get_ext_buffer(AVCodecContext *avctx, ThreadFrame *f, int flags)
 
 void ff_thread_release_buffer(AVCodecContext *avctx, AVFrame *f)
 {
-#if FF_API_THREAD_SAFE_CALLBACKS
-FF_DISABLE_DEPRECATION_WARNINGS
-    PerThreadContext *p;
-    FrameThreadContext *fctx;
-    AVFrame *dst;
-    int ret = 0;
-    int can_direct_free = !(avctx->active_thread_type & FF_THREAD_FRAME) ||
-                          THREAD_SAFE_CALLBACKS(avctx);
-FF_ENABLE_DEPRECATION_WARNINGS
-#endif
-
     if (!f)
         return;
 
     if (avctx->debug & FF_DEBUG_BUFFERS)
         av_log(avctx, AV_LOG_DEBUG, "thread_release_buffer called on pic %p\n", f);
 
-#if !FF_API_THREAD_SAFE_CALLBACKS
     av_frame_unref(f);
-#else
-    // when the frame buffers are not allocated, just reset it to clean state
-    if (can_direct_free || !f->buf[0]) {
-        av_frame_unref(f);
-        return;
-    }
-
-    p    = avctx->internal->thread_ctx;
-    fctx = p->parent;
-    pthread_mutex_lock(&fctx->buffer_mutex);
-
-    if (p->num_released_buffers == p->released_buffers_allocated) {
-        AVFrame **tmp = av_realloc_array(p->released_buffers, p->released_buffers_allocated + 1,
-                                         sizeof(*p->released_buffers));
-        if (tmp) {
-            tmp[p->released_buffers_allocated] = av_frame_alloc();
-            p->released_buffers = tmp;
-        }
-
-        if (!tmp || !tmp[p->released_buffers_allocated]) {
-            ret = AVERROR(ENOMEM);
-            goto fail;
-        }
-        p->released_buffers_allocated++;
-    }
-
-    dst = p->released_buffers[p->num_released_buffers];
-    av_frame_move_ref(dst, f);
-
-    p->num_released_buffers++;
-
-fail:
-    pthread_mutex_unlock(&fctx->buffer_mutex);
-
-    // make sure the frame is clean even if we fail to free it
-    // this leaks, but it is better than crashing
-    if (ret < 0) {
-        av_log(avctx, AV_LOG_ERROR, "Could not queue a frame for freeing, this will leak\n");
-        memset(f->buf, 0, sizeof(f->buf));
-        if (f->extended_buf)
-            memset(f->extended_buf, 0, f->nb_extended_buf * sizeof(*f->extended_buf));
-        av_frame_unref(f);
-    }
-#endif
 }
 
 void ff_thread_release_ext_buffer(AVCodecContext *avctx, ThreadFrame *f)
diff --git a/libavcodec/thread.h b/libavcodec/thread.h
index d5673f25ea..88a14cfeb1 100644
--- a/libavcodec/thread.h
+++ b/libavcodec/thread.h
@@ -62,19 +62,7 @@ int ff_thread_decode_frame(AVCodecContext *avctx, AVFrame *picture,
  */
 void ff_thread_finish_setup(AVCodecContext *avctx);
 
-#if FF_API_THREAD_SAFE_CALLBACKS
-/**
- * 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);
-#else
 #define ff_thread_get_format ff_get_format
-#endif
 
 /**
  * Wrapper around get_buffer() for frame-multithreaded codecs.
diff --git a/libavcodec/utils.c b/libavcodec/utils.c
index 2b63a498b9..1e57a81b8b 100644
--- a/libavcodec/utils.c
+++ b/libavcodec/utils.c
@@ -906,11 +906,6 @@ int ff_thread_ref_frame(ThreadFrame *dst, const ThreadFrame *src)
 
 #if !HAVE_THREADS
 
-enum AVPixelFormat ff_thread_get_format(AVCodecContext *avctx, const enum AVPixelFormat *fmt)
-{
-    return ff_get_format(avctx, fmt);
-}
-
 int ff_thread_get_buffer(AVCodecContext *avctx, AVFrame *f, int flags)
 {
     return ff_get_buffer(avctx, f, flags);
diff --git a/libavcodec/version_major.h b/libavcodec/version_major.h
index 282fcea55e..8550610b4e 100644
--- a/libavcodec/version_major.h
+++ b/libavcodec/version_major.h
@@ -37,7 +37,6 @@
  * at once through the bump. This improves the git bisect-ability of the change.
  */
 
-#define FF_API_THREAD_SAFE_CALLBACKS (LIBAVCODEC_VERSION_MAJOR < 60)
 #define FF_API_DEBUG_MV          (LIBAVCODEC_VERSION_MAJOR < 60)
 #define FF_API_GET_FRAME_CLASS     (LIBAVCODEC_VERSION_MAJOR < 60)
 #define FF_API_AUTO_THREADS        (LIBAVCODEC_VERSION_MAJOR < 60)
