[FFmpeg-devel] [PATCH 3/4] Add support for 10-bit output for Decklink SDI
Devin Heitmueller
dheitmueller at ltnglobal.com
Tue Sep 26 19:06:22 EEST 2017
From: Devin Heitmueller <dheitmueller at kernellabs.com>
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.
Signed-off-by: Devin Heitmueller <dheitmueller at ltnglobal.com>
---
libavdevice/decklink_enc.cpp | 110 ++++++++++++++++++++++++++++++++-----------
1 file changed, 83 insertions(+), 27 deletions(-)
diff --git a/libavdevice/decklink_enc.cpp b/libavdevice/decklink_enc.cpp
index 0f654faa19..0d965699ec 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; }
+ 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 HRESULT STDMETHODCALLTYPE GetBytes (void **buffer)
{
+ if (_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;
}
@@ -70,7 +95,10 @@ public:
{
int ret = --_refs;
if (!ret) {
- av_frame_free(&_avframe);
+ if (_codec_id == AV_CODEC_ID_WRAPPED_AVFRAME)
+ av_frame_free(&_avframe);
+ else
+ av_packet_unref(_avpacket);
delete this;
}
return ret;
@@ -78,6 +106,10 @@ public:
struct decklink_ctx *_ctx;
AVFrame *_avframe;
+ AVPacket *_avpacket;
+ AVCodecID _codec_id;
+ int _height;
+ int _width;
private:
std::atomic<int> _refs;
@@ -92,7 +124,10 @@ public:
struct decklink_ctx *ctx = frame->_ctx;
AVFrame *avframe = frame->_avframe;
- av_frame_unref(avframe);
+ if (avframe)
+ av_frame_unref(avframe);
+ else
+ av_packet_unref(frame->_avpacket);
pthread_mutex_lock(&ctx->mutex);
ctx->frames_buffer_available_spots++;
@@ -118,11 +153,14 @@ 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");
- return -1;
+ 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;
+ }
}
+
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 +268,45 @@ 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);
+
+ if (avframe)
+ av_frame_free(&avframe);
+ else
+ av_packet_unref(avpacket);
return AVERROR(EIO);
}
--
2.13.2
More information about the ffmpeg-devel
mailing list