* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <atomic>
+using std::atomic;
+
/* Include internal.h first to avoid conflict between winsock.h (used by
* DeckLink headers) and winsock2.h (used by libavformat) in MSVC++ builds */
extern "C" {
{bmdModeUnknown, 0, -1, -1, -1}
};
+class decklink_allocator : public IDeckLinkMemoryAllocator
+{
+public:
+ decklink_allocator(): _refs(1) { }
+ virtual ~decklink_allocator() { }
+
+ // IDeckLinkMemoryAllocator methods
+ virtual HRESULT STDMETHODCALLTYPE AllocateBuffer(unsigned int bufferSize, void* *allocatedBuffer)
+ {
+ void *buf = av_malloc(bufferSize + AV_INPUT_BUFFER_PADDING_SIZE);
+ if (!buf)
+ return E_OUTOFMEMORY;
+ *allocatedBuffer = buf;
+ return S_OK;
+ }
+ virtual HRESULT STDMETHODCALLTYPE ReleaseBuffer(void* buffer)
+ {
+ av_free(buffer);
+ return S_OK;
+ }
+ virtual HRESULT STDMETHODCALLTYPE Commit() { return S_OK; }
+ virtual HRESULT STDMETHODCALLTYPE Decommit() { return S_OK; }
+
+ // IUnknown methods
+ virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv) { return E_NOINTERFACE; }
+ virtual ULONG STDMETHODCALLTYPE AddRef(void) { return ++_refs; }
+ virtual ULONG STDMETHODCALLTYPE Release(void)
+ {
+ int ret = --_refs;
+ if (!ret)
+ delete this;
+ return ret;
+ }
+
+private:
+ std::atomic<int> _refs;
+};
+
+extern "C" {
+static void decklink_object_free(void *opaque, uint8_t *data)
+{
+ IUnknown *obj = (class IUnknown *)opaque;
+ obj->Release();
+}
+}
+
static int get_vanc_line_idx(BMDDisplayMode mode)
{
unsigned int i;
}
}
+static void unpack_v210(uint16_t *dst, const uint8_t *src, int width)
+{
+ int i;
+ for (i = 0; i < width * 2 / 3; i++) {
+ *dst++ = src[0] + ((src[1] & 3) << 8);
+ *dst++ = (src[1] >> 2) + ((src[2] & 15) << 6);
+ *dst++ = (src[2] >> 4) + ((src[3] & 63) << 4);
+ src += 4;
+ }
+}
+
static uint8_t calc_parity_and_line_offset(int line)
{
uint8_t ret = (line < 313) << 5;
static int avpacket_queue_put(AVPacketQueue *q, AVPacket *pkt)
{
AVPacketList *pkt1;
- int ret;
// Drop Packet if queue size is > maximum queue size
if (avpacket_queue_size(q) > (uint64_t)q->max_q_size) {
+ av_packet_unref(pkt);
av_log(q->avctx, AV_LOG_WARNING, "Decklink input buffer overrun!\n");
return -1;
}
-
- pkt1 = (AVPacketList *)av_mallocz(sizeof(AVPacketList));
- if (!pkt1) {
+ /* ensure the packet is reference counted */
+ if (av_packet_make_refcounted(pkt) < 0) {
+ av_packet_unref(pkt);
return -1;
}
- ret = av_packet_ref(&pkt1->pkt, pkt);
- av_packet_unref(pkt);
- if (ret < 0) {
- av_free(pkt1);
+
+ pkt1 = (AVPacketList *)av_malloc(sizeof(AVPacketList));
+ if (!pkt1) {
+ av_packet_unref(pkt);
return -1;
}
+ av_packet_move_ref(&pkt1->pkt, pkt);
pkt1->next = NULL;
pthread_mutex_lock(&q->mutex);
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,
for (i = vanc_line_numbers[idx].vanc_start; i <= vanc_line_numbers[idx].vanc_end; i++) {
uint8_t *buf;
if (vanc->GetBufferForVerticalBlankingLine(i, (void**)&buf) == S_OK) {
- uint16_t luma_vanc[MAX_WIDTH_VANC];
- extract_luma_from_v210(luma_vanc, buf, videoFrame->GetWidth());
- txt_buf = get_metadata(avctx, luma_vanc, videoFrame->GetWidth(),
+ uint16_t vanc[MAX_WIDTH_VANC];
+ size_t vanc_size = videoFrame->GetWidth();
+ if (ctx->bmd_mode == bmdModeNTSC && videoFrame->GetWidth() * 2 <= MAX_WIDTH_VANC) {
+ vanc_size = vanc_size * 2;
+ unpack_v210(vanc, buf, videoFrame->GetWidth());
+ } else {
+ extract_luma_from_v210(vanc, buf, videoFrame->GetWidth());
+ }
+ txt_buf = get_metadata(avctx, vanc, vanc_size,
txt_buf, sizeof(txt_buf0) - (txt_buf - txt_buf0), &pkt);
}
if (i == vanc_line_numbers[idx].field0_vanc_end)
}
}
+ pkt.buf = av_buffer_create(pkt.data, pkt.size, decklink_object_free, videoFrame, 0);
+ if (pkt.buf)
+ videoFrame->AddRef();
+
if (avpacket_queue_put(&ctx->queue, &pkt) < 0) {
++ctx->dropped;
}
{
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];
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);
+ allocator->Release();
+ if (ret < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Cannot set custom memory allocator\n");
+ goto error;
+ }
if (mode_num == 0 && !cctx->format_code) {
if (decklink_autodetect(cctx) < 0) {
break;
case bmdFormat8BitARGB:
st->codecpar->codec_id = AV_CODEC_ID_RAWVIDEO;
- st->codecpar->codec_tag = avcodec_pix_fmt_to_codec_tag((enum AVPixelFormat)st->codecpar->format);;
+ st->codecpar->codec_tag = avcodec_pix_fmt_to_codec_tag((enum AVPixelFormat)st->codecpar->format);
st->codecpar->format = AV_PIX_FMT_0RGB;
st->codecpar->bit_rate = av_rescale(ctx->bmd_width * ctx->bmd_height * 32, st->time_base.den, st->time_base.num);
break;