[FFmpeg-cvslog] pthread_frame: ensure the threads don't run simultaneously with hwaccel

Anton Khirnov git at videolan.org
Wed Apr 26 18:31:38 EEST 2017


ffmpeg | branch: master | Anton Khirnov <anton at khirnov.net> | Sat Dec  3 15:21:40 2016 +0100| [8dfba25ce89b62c80ba83e2116d549176c376144] | committer: Anton Khirnov

pthread_frame: ensure the threads don't run simultaneously with hwaccel

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=8dfba25ce89b62c80ba83e2116d549176c376144
---

 libavcodec/h263dec.c       |  2 +-
 libavcodec/h264dec.c       |  2 +-
 libavcodec/pthread_frame.c | 35 +++++++++++++++++++++++++++++++++++
 3 files changed, 37 insertions(+), 2 deletions(-)

diff --git a/libavcodec/h263dec.c b/libavcodec/h263dec.c
index e4a7227575..921ff5fb98 100644
--- a/libavcodec/h263dec.c
+++ b/libavcodec/h263dec.c
@@ -558,7 +558,7 @@ int ff_h263_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
     if ((ret = ff_mpv_frame_start(s, avctx)) < 0)
         return ret;
 
-    if (!s->divx_packed && !avctx->hwaccel)
+    if (!s->divx_packed)
         ff_thread_finish_setup(avctx);
 
     if (avctx->hwaccel) {
diff --git a/libavcodec/h264dec.c b/libavcodec/h264dec.c
index 330a74dcb4..83b3ab3be1 100644
--- a/libavcodec/h264dec.c
+++ b/libavcodec/h264dec.c
@@ -573,7 +573,7 @@ static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size)
             if ((err = ff_h264_queue_decode_slice(h, nal)))
                 break;
 
-            if (avctx->active_thread_type & FF_THREAD_FRAME && !h->avctx->hwaccel &&
+            if (avctx->active_thread_type & FF_THREAD_FRAME &&
                 i >= nals_needed && !h->setup_finished && h->cur_pic_ptr) {
                 ff_thread_finish_setup(avctx);
                 h->setup_finished = 1;
diff --git a/libavcodec/pthread_frame.c b/libavcodec/pthread_frame.c
index 2a800e1e35..fd35456f59 100644
--- a/libavcodec/pthread_frame.c
+++ b/libavcodec/pthread_frame.c
@@ -99,6 +99,8 @@ typedef struct PerThreadContext {
     int      requested_flags;       ///< flags passed to get_buffer() for requested_frame
 
     int die;                       ///< Set when the thread should exit.
+
+    int hwaccel_serializing;
 } PerThreadContext;
 
 /**
@@ -109,6 +111,11 @@ typedef struct FrameThreadContext {
     PerThreadContext *prev_thread; ///< The last thread submit_packet() was called on.
 
     pthread_mutex_t buffer_mutex;  ///< Mutex used to protect get/release_buffer().
+    /**
+     * This lock is used for ensuring threads run in serial when hwaccel
+     * is used.
+     */
+    pthread_mutex_t hwaccel_mutex;
 
     int next_decoding;             ///< The next context to submit a packet to.
     int next_finished;             ///< The next context to return output from.
@@ -149,6 +156,22 @@ static attribute_align_arg void *frame_worker_thread(void *arg)
             ff_thread_finish_setup(avctx);
 
         pthread_mutex_lock(&p->mutex);
+
+        /* If a decoder supports hwaccel, then it must call ff_get_format().
+         * Since that call must happen before ff_thread_finish_setup(), the
+         * decoder is required to implement update_thread_context() and call
+         * ff_thread_finish_setup() manually. Therefore the above
+         * ff_thread_finish_setup() call did not happen and hwaccel_serializing
+         * cannot be true here. */
+        av_assert0(!p->hwaccel_serializing);
+
+        /* if the previous thread uses hwaccel then we take the lock to ensure
+         * the threads don't run concurrently */
+        if (avctx->hwaccel) {
+            pthread_mutex_lock(&p->parent->hwaccel_mutex);
+            p->hwaccel_serializing = 1;
+        }
+
         av_frame_unref(p->frame);
         p->got_frame = 0;
         p->result = codec->decode(avctx, p->frame, &p->got_frame, &p->avpkt);
@@ -163,6 +186,11 @@ static attribute_align_arg void *frame_worker_thread(void *arg)
         if (atomic_load(&p->state) == STATE_SETTING_UP)
             ff_thread_finish_setup(avctx);
 
+        if (p->hwaccel_serializing) {
+            p->hwaccel_serializing = 0;
+            pthread_mutex_unlock(&p->parent->hwaccel_mutex);
+        }
+
         atomic_store(&p->state, STATE_INPUT_READY);
 
         pthread_mutex_lock(&p->progress_mutex);
@@ -499,6 +527,11 @@ void ff_thread_finish_setup(AVCodecContext *avctx) {
 
     if (!(avctx->active_thread_type&FF_THREAD_FRAME)) return;
 
+    if (avctx->hwaccel && !p->hwaccel_serializing) {
+        pthread_mutex_lock(&p->parent->hwaccel_mutex);
+        p->hwaccel_serializing = 1;
+    }
+
     pthread_mutex_lock(&p->progress_mutex);
 
     atomic_store(&p->state, STATE_SETUP_FINISHED);
@@ -579,6 +612,7 @@ void ff_frame_thread_free(AVCodecContext *avctx, int thread_count)
 
     av_freep(&fctx->threads);
     pthread_mutex_destroy(&fctx->buffer_mutex);
+    pthread_mutex_destroy(&fctx->hwaccel_mutex);
     av_freep(&avctx->internal->thread_ctx);
 }
 
@@ -620,6 +654,7 @@ int ff_frame_thread_init(AVCodecContext *avctx)
     }
 
     pthread_mutex_init(&fctx->buffer_mutex, NULL);
+    pthread_mutex_init(&fctx->hwaccel_mutex, NULL);
     fctx->delaying = 1;
 
     for (i = 0; i < thread_count; i++) {



More information about the ffmpeg-cvslog mailing list