mirror of
https://github.com/xenia-project/FFmpeg.git
synced 2024-11-23 19:49:56 +00:00
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
|
||||
{
|
||||
public:
|
||||
decklink_frame(struct decklink_ctx *ctx, AVFrame *avframe) :
|
||||
_ctx(ctx), _avframe(avframe), _refs(1) { }
|
||||
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 (_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)
|
||||
{
|
||||
if (_avframe->linesize[0] < 0)
|
||||
*buffer = (void *)(_avframe->data[0] + _avframe->linesize[0] * (_avframe->height - 1));
|
||||
else
|
||||
*buffer = (void *)(_avframe->data[0]);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -71,6 +96,7 @@ public:
|
||||
int ret = --_refs;
|
||||
if (!ret) {
|
||||
av_frame_free(&_avframe);
|
||||
av_packet_free(&_avpacket);
|
||||
delete this;
|
||||
}
|
||||
return ret;
|
||||
@ -78,6 +104,10 @@ public:
|
||||
|
||||
struct decklink_ctx *_ctx;
|
||||
AVFrame *_avframe;
|
||||
AVPacket *_avpacket;
|
||||
AVCodecID _codec_id;
|
||||
int _height;
|
||||
int _width;
|
||||
|
||||
private:
|
||||
std::atomic<int> _refs;
|
||||
@ -90,9 +120,11 @@ public:
|
||||
{
|
||||
decklink_frame *frame = static_cast<decklink_frame *>(_frame);
|
||||
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);
|
||||
ctx->frames_buffer_available_spots++;
|
||||
@ -118,11 +150,18 @@ static int decklink_setup_video(AVFormatContext *avctx, AVStream *st)
|
||||
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;
|
||||
}
|
||||
|
||||
if (ff_decklink_set_format(avctx, c->width, c->height,
|
||||
st->time_base.num, st->time_base.den, c->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_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;
|
||||
buffercount_type buffered;
|
||||
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) {
|
||||
av_log(avctx, AV_LOG_ERROR, "Could not create new frame.\n");
|
||||
av_frame_free(&avframe);
|
||||
av_packet_free(&avpacket);
|
||||
return AVERROR(EIO);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user