Merge commit '1a5e9130162b8adc898e5f6aea82b6372d1e4e6c'
authorMichael Niedermayer <michaelni@gmx.at>
Fri, 8 Mar 2013 18:17:31 +0000 (19:17 +0100)
committerMichael Niedermayer <michaelni@gmx.at>
Fri, 8 Mar 2013 18:17:38 +0000 (19:17 +0100)
* commit '1a5e9130162b8adc898e5f6aea82b6372d1e4e6c':
  pthread: avoid copying input packets when possible.

Merged-by: Michael Niedermayer <michaelni@gmx.at>
1  2 
libavcodec/pthread.c

diff --combined libavcodec/pthread.c
@@@ -6,20 -6,20 +6,20 @@@
   * to Michael Niedermayer <michaelni@gmx.at> for writing initial
   * implementation.
   *
 - * This file is part of Libav.
 + * This file is part of FFmpeg.
   *
 - * Libav is free software; you can redistribute it and/or
 + * FFmpeg is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 2.1 of the License, or (at your option) any later version.
   *
 - * Libav is distributed in the hope that it will be useful,
 + * FFmpeg is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   * Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
 - * License along with Libav; if not, write to the Free Software
 + * License along with FFmpeg; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
   */
  
@@@ -32,9 -32,7 +32,9 @@@
  #include "config.h"
  
  #if HAVE_SCHED_GETAFFINITY
 -#define _GNU_SOURCE
 +#ifndef _GNU_SOURCE
 +# define _GNU_SOURCE
 +#endif
  #include <sched.h>
  #endif
  #if HAVE_GETPROCESSAFFINITYMASK
@@@ -45,7 -43,6 +45,7 @@@
  #include <sys/param.h>
  #endif
  #include <sys/types.h>
 +#include <sys/param.h>
  #include <sys/sysctl.h>
  #endif
  #if HAVE_SYSCONF
@@@ -61,8 -58,6 +61,8 @@@
  #include <pthread.h>
  #elif HAVE_W32THREADS
  #include "w32pthreads.h"
 +#elif HAVE_OS2THREADS
 +#include "os2threads.h"
  #endif
  
  typedef int (action_func)(AVCodecContext *c, void *arg);
@@@ -82,12 -77,11 +82,12 @@@ typedef struct ThreadContext 
      pthread_cond_t current_job_cond;
      pthread_mutex_t current_job_lock;
      int current_job;
 +    unsigned int current_execute;
      int done;
  } ThreadContext;
  
  /// Max number of frame buffers that can be allocated when using frame threads.
 -#define MAX_BUFFERS (32+1)
 +#define MAX_BUFFERS (34+1)
  
  /**
   * Context used by codec threads and stored in their AVCodecContext thread_opaque.
@@@ -107,7 -101,8 +107,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.
      /**
       * Array of progress values used by ff_thread_get_buffer().
       */
 -    int     progress[MAX_BUFFERS][2];
 -    uint8_t progress_used[MAX_BUFFERS];
 +    volatile int     progress[MAX_BUFFERS][2];
 +    volatile uint8_t progress_used[MAX_BUFFERS];
  
      AVFrame *requested_frame;       ///< AVFrame the codec passed to get_buffer()
  } PerThreadContext;
@@@ -164,7 -159,7 +165,7 @@@ typedef struct FrameThreadContext 
   * limit the number of threads to 16 for automatic detection */
  #define MAX_AUTO_THREADS 16
  
 -static int get_logical_cpus(AVCodecContext *avctx)
 +int ff_get_logical_cpus(AVCodecContext *avctx)
  {
      int ret, nb_cpus = 1;
  #if HAVE_SCHED_GETAFFINITY && defined(CPU_COUNT)
      nb_cpus = sysconf(_SC_NPROCESSORS_ONLN);
  #endif
      av_log(avctx, AV_LOG_DEBUG, "detected %d logical cores\n", nb_cpus);
 +
 +    if  (avctx->height)
 +        nb_cpus = FFMIN(nb_cpus, (avctx->height+15)/16);
 +
      return nb_cpus;
  }
  
@@@ -207,7 -198,6 +208,7 @@@ static void* attribute_align_arg worker
      AVCodecContext *avctx = v;
      ThreadContext *c = avctx->thread_opaque;
      int our_job = c->job_count;
 +    int last_execute = 0;
      int thread_count = avctx->thread_count;
      int self_id;
  
              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);
 +            while (last_execute == c->current_execute && !c->done)
 +                pthread_cond_wait(&c->current_job_cond, &c->current_job_lock);
 +            last_execute = c->current_execute;
              our_job = self_id;
  
              if (c->done) {
  
  static av_always_inline void avcodec_thread_park_workers(ThreadContext *c, int thread_count)
  {
 -    pthread_cond_wait(&c->last_job_cond, &c->current_job_lock);
 +    while (c->current_job != thread_count + c->job_count)
 +        pthread_cond_wait(&c->last_job_cond, &c->current_job_lock);
      pthread_mutex_unlock(&c->current_job_lock);
  }
  
@@@ -290,7 -277,6 +291,7 @@@ static int avcodec_thread_execute(AVCod
          c->rets = &dummy_ret;
          c->rets_count = 1;
      }
 +    c->current_execute++;
      pthread_cond_broadcast(&c->current_job_cond);
  
      avcodec_thread_park_workers(c, avctx->thread_count);
@@@ -312,7 -298,7 +313,7 @@@ static int thread_init(AVCodecContext *
      int thread_count = avctx->thread_count;
  
      if (!thread_count) {
 -        int nb_cpus = get_logical_cpus(avctx);
 +        int nb_cpus = ff_get_logical_cpus(avctx);
          // 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);
@@@ -374,17 -360,20 +375,17 @@@ static attribute_align_arg void *frame_
      AVCodecContext *avctx = p->avctx;
      const AVCodec *codec = avctx->codec;
  
 +    pthread_mutex_lock(&p->mutex);
      while (1) {
 -        if (p->state == STATE_INPUT_READY && !fctx->die) {
 -            pthread_mutex_lock(&p->mutex);
 +        int i;
              while (p->state == STATE_INPUT_READY && !fctx->die)
                  pthread_cond_wait(&p->input_cond, &p->mutex);
 -            pthread_mutex_unlock(&p->mutex);
 -        }
  
          if (fctx->die) break;
  
 -        if (!codec->update_thread_context && avctx->thread_safe_callbacks)
 +        if (!codec->update_thread_context && (avctx->thread_safe_callbacks || avctx->get_buffer == avcodec_default_get_buffer))
              ff_thread_finish_setup(avctx);
  
 -        pthread_mutex_lock(&p->mutex);
          avcodec_get_frame_defaults(&p->frame);
          p->got_frame = 0;
          p->result = codec->decode(avctx, &p->frame, &p->got_frame, &p->avpkt);
  
          if (p->state == STATE_SETTING_UP) ff_thread_finish_setup(avctx);
  
 +        pthread_mutex_lock(&p->progress_mutex);
 +        for (i = 0; i < MAX_BUFFERS; i++)
 +            if (p->progress_used[i] && (p->got_frame || p->result<0 || avctx->codec_id != AV_CODEC_ID_H264)) {
 +                p->progress[i][0] = INT_MAX;
 +                p->progress[i][1] = INT_MAX;
 +            }
          p->state = STATE_INPUT_READY;
  
 -        pthread_mutex_lock(&p->progress_mutex);
 +        pthread_cond_broadcast(&p->progress_cond);
          pthread_cond_signal(&p->output_cond);
          pthread_mutex_unlock(&p->progress_mutex);
 -
 -        pthread_mutex_unlock(&p->mutex);
      }
 +    pthread_mutex_unlock(&p->mutex);
  
      return NULL;
  }
@@@ -453,7 -437,6 +454,7 @@@ static int update_context_from_thread(A
      }
  
      if (for_user) {
 +        dst->delay       = src->thread_count - 1;
          dst->coded_frame = src->coded_frame;
      } else {
          if (dst->codec->update_thread_context)
@@@ -490,7 -473,6 +491,7 @@@ static int update_context_from_user(AVC
  
      dst->frame_number     = src->frame_number;
      dst->reordered_opaque = src->reordered_opaque;
 +    dst->thread_safe_callbacks = src->thread_safe_callbacks;
  
      if (src->slice_count && src->slice_offset) {
          if (dst->slice_count < src->slice_count) {
  static void free_progress(AVFrame *f)
  {
      PerThreadContext *p = f->owner->thread_opaque;
 -    int *progress = f->thread_opaque;
 +    volatile int *progress = f->thread_opaque;
  
      p->progress_used[(progress - p->progress[0]) / 2] = 0;
  }
@@@ -541,7 -523,6 +542,6 @@@ static int submit_packet(PerThreadConte
      FrameThreadContext *fctx = p->parent;
      PerThreadContext *prev_thread = fctx->prev_thread;
      const AVCodec *codec = p->avctx->codec;
-     uint8_t *buf = p->avpkt.data;
  
      if (!avpkt->size && !(codec->capabilities & CODEC_CAP_DELAY)) return 0;
  
          }
      }
  
-     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);
@@@ -679,7 -665,7 +684,7 @@@ int ff_thread_decode_frame(AVCodecConte
  void ff_thread_report_progress(AVFrame *f, int n, int field)
  {
      PerThreadContext *p;
 -    int *progress = f->thread_opaque;
 +    volatile int *progress = f->thread_opaque;
  
      if (!progress || progress[field] >= n) return;
  
  void ff_thread_await_progress(AVFrame *f, int n, int field)
  {
      PerThreadContext *p;
 -    int *progress = f->thread_opaque;
 +    volatile int *progress = f->thread_opaque;
  
      if (!progress || progress[field] >= n) return;
  
@@@ -717,10 -703,6 +722,10 @@@ void ff_thread_finish_setup(AVCodecCont
  
      if (!(avctx->active_thread_type&FF_THREAD_FRAME)) return;
  
 +    if(p->state == STATE_SETUP_FINISHED){
 +        av_log(avctx, AV_LOG_WARNING, "Multiple ff_thread_finish_setup() calls\n");
 +    }
 +
      pthread_mutex_lock(&p->progress_mutex);
      p->state = STATE_SETUP_FINISHED;
      pthread_cond_broadcast(&p->progress_cond);
@@@ -741,7 -723,6 +746,7 @@@ static void park_frame_worker_threads(F
                  pthread_cond_wait(&p->output_cond, &p->progress_mutex);
              pthread_mutex_unlock(&p->progress_mutex);
          }
 +        p->got_frame = 0;
      }
  }
  
@@@ -754,11 -735,7 +759,11 @@@ static void frame_thread_free(AVCodecCo
      park_frame_worker_threads(fctx, thread_count);
  
      if (fctx->prev_thread && fctx->prev_thread != fctx->threads)
 -        update_context_from_thread(fctx->threads->avctx, fctx->prev_thread->avctx, 0);
 +        if (update_context_from_thread(fctx->threads->avctx, fctx->prev_thread->avctx, 0) < 0) {
 +            av_log(avctx, AV_LOG_ERROR, "Final thread update failed\n");
 +            fctx->prev_thread->avctx->internal->is_copy = fctx->threads->avctx->internal->is_copy;
 +            fctx->threads->avctx->internal->is_copy = 1;
 +        }
  
      fctx->die = 1;
  
  
          if (p->thread_init)
              pthread_join(p->thread, NULL);
 +        p->thread_init=0;
  
          if (codec->close)
              codec->close(p->avctx);
          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);
  
          if (i) {
              av_freep(&p->avctx->priv_data);
@@@ -816,9 -793,7 +822,9 @@@ static int frame_thread_init(AVCodecCon
      int i, err = 0;
  
      if (!thread_count) {
 -        int nb_cpus = get_logical_cpus(avctx);
 +        int nb_cpus = ff_get_logical_cpus(avctx);
 +        if ((avctx->debug & (FF_DEBUG_VIS_QP | FF_DEBUG_VIS_MB_TYPE)) || avctx->debug_mv)
 +            nb_cpus = 1;
          // 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);
  
          if (err) goto error;
  
 -        if (!pthread_create(&p->thread, NULL, frame_worker_thread, p))
 -            p->thread_init = 1;
 +        err = AVERROR(pthread_create(&p->thread, NULL, frame_worker_thread, p));
 +        p->thread_init= !err;
 +        if(!p->thread_init)
 +            goto error;
      }
  
      return 0;
@@@ -928,7 -901,7 +934,7 @@@ void ff_thread_flush(AVCodecContext *av
      }
  }
  
 -static int *allocate_progress(PerThreadContext *p)
 +static volatile int *allocate_progress(PerThreadContext *p)
  {
      int i;
  
      return p->progress[i];
  }
  
 +int ff_thread_can_start_frame(AVCodecContext *avctx)
 +{
 +    PerThreadContext *p = avctx->thread_opaque;
 +    if ((avctx->active_thread_type&FF_THREAD_FRAME) && p->state != STATE_SETTING_UP &&
 +        (avctx->codec->update_thread_context || (!avctx->thread_safe_callbacks &&
 +                avctx->get_buffer != avcodec_default_get_buffer))) {
 +        return 0;
 +    }
 +    return 1;
 +}
 +
  int ff_thread_get_buffer(AVCodecContext *avctx, AVFrame *f)
  {
      PerThreadContext *p = avctx->thread_opaque;
 -    int *progress, err;
 +    int err;
 +    volatile int *progress;
  
      f->owner = avctx;
  
 +    ff_init_buffer_info(avctx, f);
 +
      if (!(avctx->active_thread_type&FF_THREAD_FRAME)) {
          f->thread_opaque = NULL;
          return ff_get_buffer(avctx, f);
      }
  
      if (p->state != STATE_SETTING_UP &&
 -        (avctx->codec->update_thread_context || !avctx->thread_safe_callbacks)) {
 +        (avctx->codec->update_thread_context || (!avctx->thread_safe_callbacks &&
 +                avctx->get_buffer != avcodec_default_get_buffer))) {
          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);
 -    f->thread_opaque = progress = allocate_progress(p);
 +    f->thread_opaque = (int*)(progress = allocate_progress(p));
  
      if (!progress) {
          pthread_mutex_unlock(&p->parent->buffer_mutex);
          avctx->get_buffer == avcodec_default_get_buffer) {
          err = ff_get_buffer(avctx, f);
      } else {
 +        pthread_mutex_lock(&p->progress_mutex);
          p->requested_frame = f;
          p->state = STATE_GET_BUFFER;
 -        pthread_mutex_lock(&p->progress_mutex);
 -        pthread_cond_signal(&p->progress_cond);
 +        pthread_cond_broadcast(&p->progress_cond);
  
          while (p->state != STATE_SETTING_UP)
              pthread_cond_wait(&p->progress_cond, &p->progress_mutex);