virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived(IDeckLinkVideoInputFrame*, IDeckLinkAudioInputPacket*);
private:
- ULONG m_refCount;
- pthread_mutex_t m_mutex;
+ std::atomic<int> _refs;
AVFormatContext *avctx;
decklink_ctx *ctx;
int no_video;
int64_t initial_audio_pts;
};
-decklink_input_callback::decklink_input_callback(AVFormatContext *_avctx) : m_refCount(0)
+decklink_input_callback::decklink_input_callback(AVFormatContext *_avctx) : _refs(1)
{
avctx = _avctx;
decklink_cctx *cctx = (struct decklink_cctx *)avctx->priv_data;
ctx = (struct decklink_ctx *)cctx->ctx;
no_video = 0;
initial_audio_pts = initial_video_pts = AV_NOPTS_VALUE;
- pthread_mutex_init(&m_mutex, NULL);
}
decklink_input_callback::~decklink_input_callback()
{
- pthread_mutex_destroy(&m_mutex);
}
ULONG decklink_input_callback::AddRef(void)
{
- pthread_mutex_lock(&m_mutex);
- m_refCount++;
- pthread_mutex_unlock(&m_mutex);
-
- return (ULONG)m_refCount;
+ return ++_refs;
}
ULONG decklink_input_callback::Release(void)
{
- pthread_mutex_lock(&m_mutex);
- m_refCount--;
- pthread_mutex_unlock(&m_mutex);
-
- if (m_refCount == 0) {
+ int ret = --_refs;
+ if (!ret)
delete this;
- return 0;
- }
-
- return (ULONG)m_refCount;
+ return ret;
}
static int64_t get_pkt_pts(IDeckLinkVideoInputFrame *videoFrame,
"- Frames dropped %u\n", ctx->frameCount, ++ctx->dropped);
}
no_video = 0;
+
+ // Handle Timecode (if requested)
+ if (ctx->tc_format) {
+ IDeckLinkTimecode *timecode;
+ if (videoFrame->GetTimecode(ctx->tc_format, &timecode) == S_OK) {
+ const char *tc = NULL;
+ DECKLINK_STR decklink_tc;
+ if (timecode->GetString(&decklink_tc) == S_OK) {
+ tc = DECKLINK_STRDUP(decklink_tc);
+ DECKLINK_FREE(decklink_tc);
+ }
+ timecode->Release();
+ if (tc) {
+ AVDictionary* metadata_dict = NULL;
+ int metadata_len;
+ uint8_t* packed_metadata;
+ if (av_dict_set(&metadata_dict, "timecode", tc, AV_DICT_DONT_STRDUP_VAL) >= 0) {
+ packed_metadata = av_packet_pack_dictionary(metadata_dict, &metadata_len);
+ av_dict_free(&metadata_dict);
+ if (packed_metadata) {
+ if (av_packet_add_side_data(&pkt, AV_PKT_DATA_STRINGS_METADATA, packed_metadata, metadata_len) < 0)
+ av_freep(&packed_metadata);
+ }
+ }
+ }
+ } else {
+ av_log(avctx, AV_LOG_DEBUG, "Unable to find timecode.\n");
+ }
+ }
}
pkt.pts = get_pkt_pts(videoFrame, audioFrame, wallclock, abs_wallclock, ctx->video_pts_source, ctx->video_st->time_base, &initial_video_pts, cctx->copyts);
struct decklink_cctx *cctx = (struct decklink_cctx *)avctx->priv_data;
struct decklink_ctx *ctx;
class decklink_allocator *allocator;
+ class decklink_input_callback *input_callback;
AVStream *st;
HRESULT result;
char fname[1024];
ctx->teletext_lines = cctx->teletext_lines;
ctx->preroll = cctx->preroll;
ctx->duplex_mode = cctx->duplex_mode;
+ if (cctx->tc_format > 0 && (unsigned int)cctx->tc_format < FF_ARRAY_ELEMS(decklink_timecode_format_map))
+ ctx->tc_format = decklink_timecode_format_map[cctx->tc_format];
if (cctx->video_input > 0 && (unsigned int)cctx->video_input < FF_ARRAY_ELEMS(decklink_video_connection_map))
ctx->video_input = decklink_video_connection_map[cctx->video_input];
if (cctx->audio_input > 0 && (unsigned int)cctx->audio_input < FF_ARRAY_ELEMS(decklink_audio_connection_map))
goto error;
}
- ctx->input_callback = new decklink_input_callback(avctx);
- ctx->dli->SetCallback(ctx->input_callback);
+ input_callback = new decklink_input_callback(avctx);
+ ret = (ctx->dli->SetCallback(input_callback) == S_OK ? 0 : AVERROR_EXTERNAL);
+ input_callback->Release();
+ if (ret < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Cannot set input callback\n");
+ goto error;
+ }
allocator = new decklink_allocator();
ret = (ctx->dli->SetVideoInputFrameMemoryAllocator(allocator) == S_OK ? 0 : AVERROR_EXTERNAL);
avpacket_queue_get(&ctx->queue, pkt, 1);
+ if (ctx->tc_format && !(av_dict_get(ctx->video_st->metadata, "timecode", NULL, 0))) {
+ int size;
+ const uint8_t *side_metadata = av_packet_get_side_data(pkt, AV_PKT_DATA_STRINGS_METADATA, &size);
+ if (side_metadata) {
+ if (av_packet_unpack_dictionary(side_metadata, size, &ctx->video_st->metadata) < 0)
+ av_log(avctx, AV_LOG_ERROR, "Unable to set timecode\n");
+ }
+ }
+
return 0;
}