|
|
@@ -44,20 +44,45 @@ extern "C" { |
|
|
class decklink_frame : public IDeckLinkVideoFrame |
|
|
class decklink_frame : public IDeckLinkVideoFrame |
|
|
{ |
|
|
{ |
|
|
public: |
|
|
public: |
|
|
decklink_frame(struct decklink_ctx *ctx, AVFrame *avframe) : |
|
|
|
|
|
_ctx(ctx), _avframe(avframe), _refs(1) { } |
|
|
|
|
|
|
|
|
|
|
|
virtual long STDMETHODCALLTYPE GetWidth (void) { return _avframe->width; } |
|
|
|
|
|
virtual long STDMETHODCALLTYPE GetHeight (void) { return _avframe->height; } |
|
|
|
|
|
virtual long STDMETHODCALLTYPE GetRowBytes (void) { return _avframe->linesize[0] < 0 ? -_avframe->linesize[0] : _avframe->linesize[0]; } |
|
|
|
|
|
virtual BMDPixelFormat STDMETHODCALLTYPE GetPixelFormat(void) { return bmdFormat8BitYUV; } |
|
|
|
|
|
virtual BMDFrameFlags STDMETHODCALLTYPE GetFlags (void) { return _avframe->linesize[0] < 0 ? bmdFrameFlagFlipVertical : bmdFrameFlagDefault; } |
|
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE GetBytes (void **buffer) |
|
|
|
|
|
|
|
|
decklink_frame(struct decklink_ctx *ctx, AVFrame *avframe, AVCodecID codec_id, int height, int width) : |
|
|
|
|
|
_ctx(ctx), _avframe(avframe), _avpacket(NULL), _codec_id(codec_id), _height(height), _width(width), _refs(1) { } |
|
|
|
|
|
decklink_frame(struct decklink_ctx *ctx, AVPacket *avpacket, AVCodecID codec_id, int height, int width) : |
|
|
|
|
|
_ctx(ctx), _avframe(NULL), _avpacket(avpacket), _codec_id(codec_id), _height(height), _width(width), _refs(1) { } |
|
|
|
|
|
|
|
|
|
|
|
virtual long STDMETHODCALLTYPE GetWidth (void) { return _width; } |
|
|
|
|
|
virtual long STDMETHODCALLTYPE GetHeight (void) { return _height; } |
|
|
|
|
|
virtual long STDMETHODCALLTYPE GetRowBytes (void) |
|
|
|
|
|
{ |
|
|
|
|
|
if (_codec_id == AV_CODEC_ID_WRAPPED_AVFRAME) |
|
|
|
|
|
return _avframe->linesize[0] < 0 ? -_avframe->linesize[0] : _avframe->linesize[0]; |
|
|
|
|
|
else |
|
|
|
|
|
return ((GetWidth() + 47) / 48) * 128; |
|
|
|
|
|
} |
|
|
|
|
|
virtual BMDPixelFormat STDMETHODCALLTYPE GetPixelFormat(void) |
|
|
{ |
|
|
{ |
|
|
if (_avframe->linesize[0] < 0) |
|
|
|
|
|
*buffer = (void *)(_avframe->data[0] + _avframe->linesize[0] * (_avframe->height - 1)); |
|
|
|
|
|
|
|
|
if (_codec_id == AV_CODEC_ID_WRAPPED_AVFRAME) |
|
|
|
|
|
return bmdFormat8BitYUV; |
|
|
else |
|
|
else |
|
|
*buffer = (void *)(_avframe->data[0]); |
|
|
|
|
|
|
|
|
return bmdFormat10BitYUV; |
|
|
|
|
|
} |
|
|
|
|
|
virtual BMDFrameFlags STDMETHODCALLTYPE GetFlags (void) |
|
|
|
|
|
{ |
|
|
|
|
|
if (_codec_id == AV_CODEC_ID_WRAPPED_AVFRAME) |
|
|
|
|
|
return _avframe->linesize[0] < 0 ? bmdFrameFlagFlipVertical : bmdFrameFlagDefault; |
|
|
|
|
|
else |
|
|
|
|
|
return bmdFrameFlagDefault; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE GetBytes (void **buffer) |
|
|
|
|
|
{ |
|
|
|
|
|
if (_codec_id == AV_CODEC_ID_WRAPPED_AVFRAME) { |
|
|
|
|
|
if (_avframe->linesize[0] < 0) |
|
|
|
|
|
*buffer = (void *)(_avframe->data[0] + _avframe->linesize[0] * (_avframe->height - 1)); |
|
|
|
|
|
else |
|
|
|
|
|
*buffer = (void *)(_avframe->data[0]); |
|
|
|
|
|
} else { |
|
|
|
|
|
*buffer = (void *)(_avpacket->data); |
|
|
|
|
|
} |
|
|
return S_OK; |
|
|
return S_OK; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@@ -71,6 +96,7 @@ public: |
|
|
int ret = --_refs; |
|
|
int ret = --_refs; |
|
|
if (!ret) { |
|
|
if (!ret) { |
|
|
av_frame_free(&_avframe); |
|
|
av_frame_free(&_avframe); |
|
|
|
|
|
av_packet_free(&_avpacket); |
|
|
delete this; |
|
|
delete this; |
|
|
} |
|
|
} |
|
|
return ret; |
|
|
return ret; |
|
|
@@ -78,6 +104,10 @@ public: |
|
|
|
|
|
|
|
|
struct decklink_ctx *_ctx; |
|
|
struct decklink_ctx *_ctx; |
|
|
AVFrame *_avframe; |
|
|
AVFrame *_avframe; |
|
|
|
|
|
AVPacket *_avpacket; |
|
|
|
|
|
AVCodecID _codec_id; |
|
|
|
|
|
int _height; |
|
|
|
|
|
int _width; |
|
|
|
|
|
|
|
|
private: |
|
|
private: |
|
|
std::atomic<int> _refs; |
|
|
std::atomic<int> _refs; |
|
|
@@ -90,9 +120,11 @@ public: |
|
|
{ |
|
|
{ |
|
|
decklink_frame *frame = static_cast<decklink_frame *>(_frame); |
|
|
decklink_frame *frame = static_cast<decklink_frame *>(_frame); |
|
|
struct decklink_ctx *ctx = frame->_ctx; |
|
|
struct decklink_ctx *ctx = frame->_ctx; |
|
|
AVFrame *avframe = frame->_avframe; |
|
|
|
|
|
|
|
|
|
|
|
av_frame_unref(avframe); |
|
|
|
|
|
|
|
|
if (frame->_avframe) |
|
|
|
|
|
av_frame_unref(frame->_avframe); |
|
|
|
|
|
if (frame->_avpacket) |
|
|
|
|
|
av_packet_unref(frame->_avpacket); |
|
|
|
|
|
|
|
|
pthread_mutex_lock(&ctx->mutex); |
|
|
pthread_mutex_lock(&ctx->mutex); |
|
|
ctx->frames_buffer_available_spots++; |
|
|
ctx->frames_buffer_available_spots++; |
|
|
@@ -118,11 +150,18 @@ static int decklink_setup_video(AVFormatContext *avctx, AVStream *st) |
|
|
return -1; |
|
|
return -1; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (c->format != AV_PIX_FMT_UYVY422) { |
|
|
|
|
|
av_log(avctx, AV_LOG_ERROR, "Unsupported pixel format!" |
|
|
|
|
|
" Only AV_PIX_FMT_UYVY422 is supported.\n"); |
|
|
|
|
|
|
|
|
if (c->codec_id == AV_CODEC_ID_WRAPPED_AVFRAME) { |
|
|
|
|
|
if (c->format != AV_PIX_FMT_UYVY422) { |
|
|
|
|
|
av_log(avctx, AV_LOG_ERROR, "Unsupported pixel format!" |
|
|
|
|
|
" Only AV_PIX_FMT_UYVY422 is supported.\n"); |
|
|
|
|
|
return -1; |
|
|
|
|
|
} |
|
|
|
|
|
} else if (c->codec_id != AV_CODEC_ID_V210) { |
|
|
|
|
|
av_log(avctx, AV_LOG_ERROR, "Unsupported codec type!" |
|
|
|
|
|
" Only V210 and wrapped frame with AV_PIX_FMT_UYVY422 are supported.\n"); |
|
|
return -1; |
|
|
return -1; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (ff_decklink_set_format(avctx, c->width, c->height, |
|
|
if (ff_decklink_set_format(avctx, c->width, c->height, |
|
|
st->time_base.num, st->time_base.den, c->field_order)) { |
|
|
st->time_base.num, st->time_base.den, c->field_order)) { |
|
|
av_log(avctx, AV_LOG_ERROR, "Unsupported video size, framerate or field order!" |
|
|
av_log(avctx, AV_LOG_ERROR, "Unsupported video size, framerate or field order!" |
|
|
@@ -230,27 +269,42 @@ static int decklink_write_video_packet(AVFormatContext *avctx, AVPacket *pkt) |
|
|
{ |
|
|
{ |
|
|
struct decklink_cctx *cctx = (struct decklink_cctx *)avctx->priv_data; |
|
|
struct decklink_cctx *cctx = (struct decklink_cctx *)avctx->priv_data; |
|
|
struct decklink_ctx *ctx = (struct decklink_ctx *)cctx->ctx; |
|
|
struct decklink_ctx *ctx = (struct decklink_ctx *)cctx->ctx; |
|
|
AVFrame *avframe, *tmp = (AVFrame *)pkt->data; |
|
|
|
|
|
|
|
|
AVStream *st = avctx->streams[pkt->stream_index]; |
|
|
|
|
|
AVFrame *avframe = NULL, *tmp = (AVFrame *)pkt->data; |
|
|
|
|
|
AVPacket *avpacket = NULL; |
|
|
decklink_frame *frame; |
|
|
decklink_frame *frame; |
|
|
buffercount_type buffered; |
|
|
buffercount_type buffered; |
|
|
HRESULT hr; |
|
|
HRESULT hr; |
|
|
|
|
|
|
|
|
if (tmp->format != AV_PIX_FMT_UYVY422 || |
|
|
|
|
|
tmp->width != ctx->bmd_width || |
|
|
|
|
|
tmp->height != ctx->bmd_height) { |
|
|
|
|
|
av_log(avctx, AV_LOG_ERROR, "Got a frame with invalid pixel format or dimension.\n"); |
|
|
|
|
|
return AVERROR(EINVAL); |
|
|
|
|
|
} |
|
|
|
|
|
avframe = av_frame_clone(tmp); |
|
|
|
|
|
if (!avframe) { |
|
|
|
|
|
av_log(avctx, AV_LOG_ERROR, "Could not clone video frame.\n"); |
|
|
|
|
|
return AVERROR(EIO); |
|
|
|
|
|
|
|
|
if (st->codecpar->codec_id == AV_CODEC_ID_WRAPPED_AVFRAME) { |
|
|
|
|
|
if (tmp->format != AV_PIX_FMT_UYVY422 || |
|
|
|
|
|
tmp->width != ctx->bmd_width || |
|
|
|
|
|
tmp->height != ctx->bmd_height) { |
|
|
|
|
|
av_log(avctx, AV_LOG_ERROR, "Got a frame with invalid pixel format or dimension.\n"); |
|
|
|
|
|
return AVERROR(EINVAL); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
avframe = av_frame_clone(tmp); |
|
|
|
|
|
if (!avframe) { |
|
|
|
|
|
av_log(avctx, AV_LOG_ERROR, "Could not clone video frame.\n"); |
|
|
|
|
|
return AVERROR(EIO); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
frame = new decklink_frame(ctx, avframe, st->codecpar->codec_id, avframe->height, avframe->width); |
|
|
|
|
|
} else { |
|
|
|
|
|
avpacket = av_packet_clone(pkt); |
|
|
|
|
|
if (!avpacket) { |
|
|
|
|
|
av_log(avctx, AV_LOG_ERROR, "Could not clone video frame.\n"); |
|
|
|
|
|
return AVERROR(EIO); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
frame = new decklink_frame(ctx, avpacket, st->codecpar->codec_id, ctx->bmd_height, ctx->bmd_width); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
frame = new decklink_frame(ctx, avframe); |
|
|
|
|
|
if (!frame) { |
|
|
if (!frame) { |
|
|
av_log(avctx, AV_LOG_ERROR, "Could not create new frame.\n"); |
|
|
av_log(avctx, AV_LOG_ERROR, "Could not create new frame.\n"); |
|
|
av_frame_free(&avframe); |
|
|
av_frame_free(&avframe); |
|
|
|
|
|
av_packet_free(&avpacket); |
|
|
return AVERROR(EIO); |
|
|
return AVERROR(EIO); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|