mirror of https://git.ffmpeg.org/ffmpeg.git
libavdevice/decklink: add support for 10-bit output for Decklink SDI
Can be tested via the following command: ./ffmpeg -i foo.ts -f decklink -vcodec v210 'DeckLink Duo (1)' Note that the 8-bit support works as it did before, and setting the pix_fmt isn't required for 10-bit mode. The code defaults to operating in 8-bit mode when no vcodec is specified, for backward compatibility. Updated to reflect feedback from Marton Balint <cus@passwd.hu> Signed-off-by: Devin Heitmueller <dheitmueller@ltnglobal.com> Signed-off-by: Marton Balint <cus@passwd.hu>
This commit is contained in:
parent
278588cd0b
commit
77f7d710e0
|
@ -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) :
|
decklink_frame(struct decklink_ctx *ctx, AVFrame *avframe, AVCodecID codec_id, int height, int width) :
|
||||||
_ctx(ctx), _avframe(avframe), _refs(1) { }
|
_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 (_codec_id == AV_CODEC_ID_WRAPPED_AVFRAME)
|
||||||
|
return bmdFormat8BitYUV;
|
||||||
|
else
|
||||||
|
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 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)
|
virtual HRESULT STDMETHODCALLTYPE GetBytes (void **buffer)
|
||||||
{
|
{
|
||||||
if (_avframe->linesize[0] < 0)
|
if (_codec_id == AV_CODEC_ID_WRAPPED_AVFRAME) {
|
||||||
*buffer = (void *)(_avframe->data[0] + _avframe->linesize[0] * (_avframe->height - 1));
|
if (_avframe->linesize[0] < 0)
|
||||||
else
|
*buffer = (void *)(_avframe->data[0] + _avframe->linesize[0] * (_avframe->height - 1));
|
||||||
*buffer = (void *)(_avframe->data[0]);
|
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) {
|
if (c->codec_id == AV_CODEC_ID_WRAPPED_AVFRAME) {
|
||||||
av_log(avctx, AV_LOG_ERROR, "Unsupported pixel format!"
|
if (c->format != AV_PIX_FMT_UYVY422) {
|
||||||
" Only AV_PIX_FMT_UYVY422 is supported.\n");
|
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 ||
|
if (st->codecpar->codec_id == AV_CODEC_ID_WRAPPED_AVFRAME) {
|
||||||
tmp->width != ctx->bmd_width ||
|
if (tmp->format != AV_PIX_FMT_UYVY422 ||
|
||||||
tmp->height != ctx->bmd_height) {
|
tmp->width != ctx->bmd_width ||
|
||||||
av_log(avctx, AV_LOG_ERROR, "Got a frame with invalid pixel format or dimension.\n");
|
tmp->height != ctx->bmd_height) {
|
||||||
return AVERROR(EINVAL);
|
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");
|
avframe = av_frame_clone(tmp);
|
||||||
return AVERROR(EIO);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue