[FFmpeg-devel] [PATCH 2/2] libavdevice/decklink: add support for 10-bit output for Decklink SDI
Devin Heitmueller
dheitmueller at ltnglobal.com
Thu Oct 5 22:32:06 EEST 2017
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 Balink <cus at passwd.hu>
Signed-off-by: Devin Heitmueller <dheitmueller at ltnglobal.com>
---
libavdevice/decklink_enc.cpp | 112 ++++++++++++++++++++++++++++++++-----------
1 file changed, 83 insertions(+), 29 deletions(-)
diff --git a/libavdevice/decklink_enc.cpp b/libavdevice/decklink_enc.cpp
index 0776741812..81df563b3b 100644
--- a/libavdevice/decklink_enc.cpp
+++ b/libavdevice/decklink_enc.cpp
@@ -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) { }
-
- 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
- *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;
}
@@ -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);
}
--
2.13.2
More information about the ffmpeg-devel
mailing list