6

Is LibAV/FFMpeg thread safe? For example. Could I read from a file using AVFormatContext* in one thread and decode the read packet it in another with simple additions of mutexes or is the thread safetyness of the library a "don't know don't care" type deal? I know that libav has basic support for encoder threads but I'm trying more of a blackbox type approach where I break it up into multiple threads (Source -> Decoder -> Filter -> Encoder -> Sink) and trying to understand the complications of such.

Anyone with any experience with ffmpeg and threads and would like to chime in with any other info pertinent to this would also be greatly appreciated.

Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156
user71512
  • 167
  • 2
  • 7
  • 3
    I'm not entirely sure so I'm not making this an answer, but I think the basic idea is that the library is thread-safe, but the caller must ensure that individual av objects are accessed by only one thread at a time. – R.. GitHub STOP HELPING ICE Dec 15 '12 at 03:49

2 Answers2

8

You can register your own lock manager. The ffmpeg library will control thread safety.

Example:

::av_lockmgr_register(&my_lockmgr_cb);
 

 //// ..........

int my_lockmgr_cb(void **mutex, enum AVLockOp op)
{
  if (NULL == mutex)
    return -1;

  switch(op)
  {
   case AV_LOCK_CREATE:
   {
    *mutex = NULL;
    boost::mutex * m = new boost::mutex();
    *mutex = static_cast<void*>(m);
    break;
   }
   case AV_LOCK_OBTAIN:
   {
    boost::mutex * m =  static_cast<boost::mutex*>(*mutex);
    m->lock();
    break;
   }
   case AV_LOCK_RELEASE:
   {
    boost::mutex * m = static_cast<boost::mutex*>(*mutex);
    m->unlock();
    break;
   }
   case AV_LOCK_DESTROY:
   {
    boost::mutex * m = static_cast<boost::mutex*>(*mutex);
    delete m;
    break;
   }
   default:
   break;
  }
  return 0;
}
Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156
pogorskiy
  • 4,705
  • 1
  • 22
  • 21
  • 1
    If you build FFmpeg with `--enable-pthreads`, FFmpeg automatically uses its own default lock manager implementation, so there's no need to call `av_lockmgr_register()`. – smokris Nov 23 '13 at 18:05
  • 1
    `av_lockmgr_register` is "now" deprecated and is a no-op. At least as of release 4.2.2, maybe earlier. The comment on that function reads "This function does nothing, and always returns 0. Be sure to build with thread support to get basic thread safety.". – Pablo H May 12 '20 at 15:53
  • And now `av_lockmgr_register()` is only mentioned in the changelog. It's gone from their git master. – Alexis Wilke Sep 14 '22 at 22:42
4

To expand on the existing answer:

ffmpeg's av_lockmgr_register() is the way to deal with locking.

An ffmpeg build with threads (and a later version than LIBAVCODEC_VERSION_MAJOR 55, LIBAVCODEC_VERSION_MINOR 38 and LIBAVCODEC_VERSION_MICRO 100 - roughly about October 2013, see ffmpeg commit adding default lockmgr) will have a default lock manager that you can just use.

If you need to be compatible with libav then (at the time of writing, September 2016) this does not yet have a default lock manager and you need to provide your own.

Here is a pure C pthread's implementation:

static int ffmpeg_lockmgr_cb(void **arg, enum AVLockOp op)
{
    pthread_mutex_t *mutex = *arg;
    int err;

    switch (op) {
    case AV_LOCK_CREATE:
        mutex = malloc(sizeof(*mutex));
        if (!mutex)
            return AVERROR(ENOMEM);
        if ((err = pthread_mutex_init(mutex, NULL))) {
            free(mutex);
            return AVERROR(err);
        }
        *arg = mutex;
        return 0;
    case AV_LOCK_OBTAIN:
        if ((err = pthread_mutex_lock(mutex)))
            return AVERROR(err);

        return 0;
    case AV_LOCK_RELEASE:
        if ((err = pthread_mutex_unlock(mutex)))
            return AVERROR(err);

        return 0;
    case AV_LOCK_DESTROY:
        if (mutex)
            pthread_mutex_destroy(mutex);
        free(mutex);
        *arg = NULL;
        return 0;
    }
    return 1;
}

which is registered like so:

ret = av_lockmgr_register(ffmpeg_lockmgr_cb);
if (ret < 0)
{
    fprintf(stderr, "av_lockmgr_register failed (%d)\n", ret);
    abort();
}
Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156
JosephH
  • 37,173
  • 19
  • 130
  • 154