X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavdevice%2Fdecklink_enc.cpp;h=8892d1972fb77f6eadaa12aae208d8a12bb66b8d;hb=4708f978902b9b65c00a41d0ce51107fa843efeb;hp=ad00224cce4bb2941a88e2d32c36084171d0732d;hpb=e26e6240b6700c5e8c16d0f092f1ad46805a723c;p=ffmpeg diff --git a/libavdevice/decklink_enc.cpp b/libavdevice/decklink_enc.cpp index ad00224cce4..8892d1972fb 100644 --- a/libavdevice/decklink_enc.cpp +++ b/libavdevice/decklink_enc.cpp @@ -28,6 +28,7 @@ extern "C" { #include "libavformat/avformat.h" #include "libavformat/internal.h" #include "libavutil/imgutils.h" +#include "libavutil/atomic.h" } #include "decklink_common.h" @@ -38,33 +39,43 @@ extern "C" { class decklink_frame : public IDeckLinkVideoFrame { public: - decklink_frame(struct decklink_ctx *ctx, AVFrame *avframe, long width, - long height, void *buffer) : - _ctx(ctx), _avframe(avframe), _width(width), - _height(height), _buffer(buffer), _refs(0) { } - - virtual long STDMETHODCALLTYPE GetWidth (void) { return _width; } - virtual long STDMETHODCALLTYPE GetHeight (void) { return _height; } - virtual long STDMETHODCALLTYPE GetRowBytes (void) { return _width<<1; } + 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 bmdVideoOutputFlagDefault; } - virtual HRESULT STDMETHODCALLTYPE GetBytes (void **buffer) { *buffer = _buffer; return S_OK; } + 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]); + return S_OK; + } virtual HRESULT STDMETHODCALLTYPE GetTimecode (BMDTimecodeFormat format, IDeckLinkTimecode **timecode) { return S_FALSE; } virtual HRESULT STDMETHODCALLTYPE GetAncillaryData(IDeckLinkVideoFrameAncillary **ancillary) { return S_FALSE; } virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv) { return E_NOINTERFACE; } - virtual ULONG STDMETHODCALLTYPE AddRef(void) { return ++_refs; } - virtual ULONG STDMETHODCALLTYPE Release(void) { if (!--_refs) {delete this; return 0;} return _refs; } + virtual ULONG STDMETHODCALLTYPE AddRef(void) { return avpriv_atomic_int_add_and_fetch(&_refs, 1); } + virtual ULONG STDMETHODCALLTYPE Release(void) + { + int ret = avpriv_atomic_int_add_and_fetch(&_refs, -1); + if (!ret) { + av_frame_free(&_avframe); + delete this; + } + return ret; + } struct decklink_ctx *_ctx; AVFrame *_avframe; private: - long _width; - long _height; - void *_buffer; - int _refs; + volatile int _refs; }; class decklink_output_callback : public IDeckLinkVideoOutputCallback @@ -76,7 +87,7 @@ public: struct decklink_ctx *ctx = frame->_ctx; AVFrame *avframe = frame->_avframe; - av_frame_free(&avframe); + av_frame_unref(avframe); sem_post(&ctx->semaphore); @@ -92,21 +103,21 @@ static int decklink_setup_video(AVFormatContext *avctx, AVStream *st) { struct decklink_cctx *cctx = (struct decklink_cctx *)avctx->priv_data; struct decklink_ctx *ctx = (struct decklink_ctx *)cctx->ctx; - AVCodecContext *c = st->codec; + AVCodecParameters *c = st->codecpar; if (ctx->video) { av_log(avctx, AV_LOG_ERROR, "Only one video stream is supported!\n"); return -1; } - if (c->pix_fmt != AV_PIX_FMT_UYVY422) { + 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, - c->time_base.num, c->time_base.den)) { - av_log(avctx, AV_LOG_ERROR, "Unsupported video size or framerate!" + st->time_base.num, st->time_base.den, c->field_order)) { + av_log(avctx, AV_LOG_ERROR, "Unsupported video size, framerate or field order!" " Check available formats with -list_formats 1.\n"); return -1; } @@ -121,8 +132,8 @@ static int decklink_setup_video(AVFormatContext *avctx, AVStream *st) ctx->dlo->SetScheduledFrameCompletionCallback(ctx->output_callback); /* Start video semaphore. */ - ctx->frames_preroll = c->time_base.den * ctx->preroll; - if (c->time_base.den > 1000) + ctx->frames_preroll = st->time_base.den * ctx->preroll; + if (st->time_base.den > 1000) ctx->frames_preroll /= 1000; /* Buffer twice as many frames as the preroll. */ @@ -131,7 +142,7 @@ static int decklink_setup_video(AVFormatContext *avctx, AVStream *st) sem_init(&ctx->semaphore, 0, ctx->frames_buffer); /* The device expects the framerate to be fixed. */ - avpriv_set_pts_info(st, 64, c->time_base.num, c->time_base.den); + avpriv_set_pts_info(st, 64, st->time_base.num, st->time_base.den); ctx->video = 1; @@ -142,7 +153,7 @@ static int decklink_setup_audio(AVFormatContext *avctx, AVStream *st) { struct decklink_cctx *cctx = (struct decklink_cctx *)avctx->priv_data; struct decklink_ctx *ctx = (struct decklink_ctx *)cctx->ctx; - AVCodecContext *c = st->codec; + AVCodecParameters *c = st->codecpar; if (ctx->audio) { av_log(avctx, AV_LOG_ERROR, "Only one audio stream is supported!\n"); @@ -209,41 +220,27 @@ 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; - AVPicture *avpicture = (AVPicture *) pkt->data; - AVFrame *avframe, *tmp; + AVFrame *avframe, *tmp = (AVFrame *)pkt->data; decklink_frame *frame; buffercount_type buffered; HRESULT hr; - /* HACK while av_uncoded_frame() isn't implemented */ - int ret; - - tmp = av_frame_alloc(); - if (!tmp) - return AVERROR(ENOMEM); - tmp->format = AV_PIX_FMT_UYVY422; - tmp->width = ctx->bmd_width; - tmp->height = ctx->bmd_height; - ret = av_frame_get_buffer(tmp, 32); - if (ret < 0) { - av_frame_free(&tmp); - return ret; + 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); } - av_image_copy(tmp->data, tmp->linesize, (const uint8_t **) avpicture->data, - avpicture->linesize, (AVPixelFormat) tmp->format, tmp->width, - tmp->height); avframe = av_frame_clone(tmp); - av_frame_free(&tmp); if (!avframe) { av_log(avctx, AV_LOG_ERROR, "Could not clone video frame.\n"); return AVERROR(EIO); } - /* end HACK */ - frame = new decklink_frame(ctx, avframe, ctx->bmd_width, ctx->bmd_height, - (void *) avframe->data[0]); + frame = new decklink_frame(ctx, avframe); if (!frame) { av_log(avctx, AV_LOG_ERROR, "Could not create new frame.\n"); + av_frame_free(&avframe); return AVERROR(EIO); } @@ -254,10 +251,11 @@ static int decklink_write_video_packet(AVFormatContext *avctx, AVPacket *pkt) hr = ctx->dlo->ScheduleVideoFrame((struct IDeckLinkVideoFrame *) frame, pkt->pts * ctx->bmd_tb_num, ctx->bmd_tb_num, ctx->bmd_tb_den); + /* Pass ownership to DeckLink, or release on failure */ + frame->Release(); if (hr != S_OK) { av_log(avctx, AV_LOG_ERROR, "Could not schedule video frame." " error %08x.\n", (uint32_t) hr); - frame->Release(); return AVERROR(EIO); } @@ -352,7 +350,7 @@ av_cold int ff_decklink_write_header(AVFormatContext *avctx) ret = AVERROR(EIO); for (n = 0; n < avctx->nb_streams; n++) { AVStream *st = avctx->streams[n]; - AVCodecContext *c = st->codec; + AVCodecParameters *c = st->codecpar; if (c->codec_type == AVMEDIA_TYPE_AUDIO) { if (decklink_setup_audio(avctx, st)) goto error; @@ -380,9 +378,9 @@ int ff_decklink_write_packet(AVFormatContext *avctx, AVPacket *pkt) ctx->last_pts = FFMAX(ctx->last_pts, pkt->pts); - if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) + if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) return decklink_write_video_packet(avctx, pkt); - else if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) + else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) return decklink_write_audio_packet(avctx, pkt); return AVERROR(EIO);