avdevice/decklink: remove pthread dependency
authorAaron Levinson <alevinsn@aracnet.com>
Sat, 15 Apr 2017 06:41:46 +0000 (08:41 +0200)
committerMarton Balint <cus@passwd.hu>
Sat, 15 Apr 2017 10:26:21 +0000 (12:26 +0200)
Purpose: avdevice/decklink: Removed pthread dependency by replacing
semaphore used in code appropriately.  Doing so makes it easier to
build ffmpeg using Visual C++ on Windows.  This is a contination of
Kyle Schwarz's "avdevice/decklink: Remove pthread dependency" patch
that is available at https://patchwork.ffmpeg.org/patch/2654/ .  This
patch wasn't accepted, and as far as I can tell, there was no
follow-up after it was rejected.

Notes: Used Visual Studio 2015 (with update 3) for this.

Comments:

-- configure: Eliminated pthreads dependency for decklink_indev_deps
   and decklink_outdev_deps and replaced with threads dependency

-- libavdevice/decklink_common.cpp / .h:
a) Eliminated semaphore and replaced with a combination of a mutex,
   condition variable, and a counter (frames_buffer_available_spots).
b) Removed include of pthread.h and semaphore.h and now using
   libavutil/thread.h instead.

-- libavdevice/decklink_dec.cpp: Eliminated include of pthread.h and
   semaphore.h.

-- libavdevice/decklink_enc.cpp:
a) Eliminated include of pthread.h and semaphore.h.
b) Replaced use of semaphore with the equivalent using a combination
   of a mutex, condition variable, and a counter
   (frames_buffer_available_spots).  In theory, libavutil/thread.h and
   the associated code could have been modified instead to add
   cross-platform implementations of the sem_ functions, but an
   inspection of the ffmpeg source base indicates that there are only
   two cases in which semaphores are used (including this one that was
   replaced), so it was deemed to not be worth the effort.

Signed-off-by: Marton Balint <cus@passwd.hu>
configure
libavdevice/decklink_common.cpp
libavdevice/decklink_common.h
libavdevice/decklink_dec.cpp
libavdevice/decklink_enc.cpp

index 98f7828..3f2811a 100755 (executable)
--- a/configure
+++ b/configure
@@ -2995,9 +2995,9 @@ avfoundation_indev_deps="pthreads"
 avfoundation_indev_extralibs="-framework Foundation -framework AVFoundation -framework CoreVideo -framework CoreMedia"
 bktr_indev_deps_any="dev_bktr_ioctl_bt848_h machine_ioctl_bt848_h dev_video_bktr_ioctl_bt848_h dev_ic_bt8xx_h"
 caca_outdev_deps="libcaca"
-decklink_indev_deps="decklink pthreads"
+decklink_indev_deps="decklink threads"
 decklink_indev_extralibs="-lstdc++"
-decklink_outdev_deps="decklink pthreads"
+decklink_outdev_deps="decklink threads"
 decklink_outdev_extralibs="-lstdc++"
 dshow_indev_deps="IBaseFilter"
 dshow_indev_extralibs="-lpsapi -lole32 -lstrmiids -luuid -loleaut32 -lshlwapi"
index c9107c0..f01fba9 100644 (file)
@@ -26,9 +26,6 @@
 #include <DeckLinkAPIDispatch.cpp>
 #endif
 
-#include <pthread.h>
-#include <semaphore.h>
-
 extern "C" {
 #include "libavformat/avformat.h"
 #include "libavformat/internal.h"
index 4753287..c12cf18 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <DeckLinkAPIVersion.h>
 
+#include "libavutil/thread.h"
 #include "decklink_common_c.h"
 
 class decklink_output_callback;
@@ -89,7 +90,9 @@ struct decklink_ctx {
     int frames_preroll;
     int frames_buffer;
 
-    sem_t semaphore;
+    pthread_mutex_t mutex;
+    pthread_cond_t cond;
+    int frames_buffer_available_spots;
 
     int channels;
 };
index 8cc1bdf..67eaf97 100644 (file)
@@ -21,9 +21,6 @@
 
 #include <DeckLinkAPI.h>
 
-#include <pthread.h>
-#include <semaphore.h>
-
 extern "C" {
 #include "config.h"
 #include "libavformat/avformat.h"
index 18ef905..5105967 100644 (file)
@@ -24,9 +24,6 @@ using std::atomic;
 
 #include <DeckLinkAPI.h>
 
-#include <pthread.h>
-#include <semaphore.h>
-
 extern "C" {
 #include "libavformat/avformat.h"
 #include "libavformat/internal.h"
@@ -91,7 +88,10 @@ public:
 
         av_frame_unref(avframe);
 
-        sem_post(&ctx->semaphore);
+        pthread_mutex_lock(&ctx->mutex);
+        ctx->frames_buffer_available_spots++;
+        pthread_cond_broadcast(&ctx->cond);
+        pthread_mutex_unlock(&ctx->mutex);
 
         return S_OK;
     }
@@ -133,7 +133,6 @@ static int decklink_setup_video(AVFormatContext *avctx, AVStream *st)
     ctx->output_callback = new decklink_output_callback();
     ctx->dlo->SetScheduledFrameCompletionCallback(ctx->output_callback);
 
-    /* Start video semaphore. */
     ctx->frames_preroll = st->time_base.den * ctx->preroll;
     if (st->time_base.den > 1000)
         ctx->frames_preroll /= 1000;
@@ -141,7 +140,9 @@ static int decklink_setup_video(AVFormatContext *avctx, AVStream *st)
     /* Buffer twice as many frames as the preroll. */
     ctx->frames_buffer = ctx->frames_preroll * 2;
     ctx->frames_buffer = FFMIN(ctx->frames_buffer, 60);
-    sem_init(&ctx->semaphore, 0, ctx->frames_buffer);
+    pthread_mutex_init(&ctx->mutex, NULL);
+    pthread_cond_init(&ctx->cond, NULL);
+    ctx->frames_buffer_available_spots = ctx->frames_buffer;
 
     /* The device expects the framerate to be fixed. */
     avpriv_set_pts_info(st, 64, st->time_base.num, st->time_base.den);
@@ -211,7 +212,8 @@ av_cold int ff_decklink_write_trailer(AVFormatContext *avctx)
     if (ctx->output_callback)
         delete ctx->output_callback;
 
-    sem_destroy(&ctx->semaphore);
+    pthread_mutex_destroy(&ctx->mutex);
+    pthread_cond_destroy(&ctx->cond);
 
     av_freep(&cctx->ctx);
 
@@ -247,7 +249,12 @@ static int decklink_write_video_packet(AVFormatContext *avctx, AVPacket *pkt)
     }
 
     /* Always keep at most one second of frames buffered. */
-    sem_wait(&ctx->semaphore);
+    pthread_mutex_lock(&ctx->mutex);
+    while (ctx->frames_buffer_available_spots == 0) {
+        pthread_cond_wait(&ctx->cond, &ctx->mutex);
+    }
+    ctx->frames_buffer_available_spots--;
+    pthread_mutex_unlock(&ctx->mutex);
 
     /* Schedule frame for playback. */
     hr = ctx->dlo->ScheduleVideoFrame((struct IDeckLinkVideoFrame *) frame,