On Tue, 26 Sep 2017, Devin Heitmueller wrote:
From: Devin Heitmueller <dheitmuel...@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 <dheitmuel...@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) {
Maybe you should check for codec id here as well for consistency.
if (_avframe->linesize[0] < 0) *buffer = (void *)(_avframe->data[0] + _avframe->linesize[0] * (_avframe->height - 1)); else *buffer = (void *)(_avframe->data[0]);
I think this section is short enough to reindent it in the same patch.
+ } else { + *buffer = (void *)(_avpacket->data);
The DeckLink SDK requires a 128 byte alignment for data. I am thinking AVPacket does not always provides that. Maybe we should simply ignore the SDK requirement (if it works without it?) Can you test this somehow?
+ } 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);
You are using av_packet_unref instead of av_packet_free, is this intentional? av_frame_free and av_packet_free can handle NULL pointers, so you don't have to check the codec type, just free both.
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);
Maybe something like this is simpler and easier to follow: 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 +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);
av_packet_free here as well.
return AVERROR(EIO); } -- 2.13.2
Regards, Marton _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel