|
|
|
@@ -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, |
|
|
|
|