On 2016-12-14 09:56:23 +0100, Anton Khirnov wrote:
> ---
>  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 e4a7227..921ff5f 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 330a74d..83b3ab3 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 75f4ff4..364a998 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++) {

ok, thanks for the verbose comment

Janne
_______________________________________________
libav-devel mailing list
libav-devel@libav.org
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to