]> git.sesse.net Git - ffmpeg/blobdiff - libavdevice/decklink_enc.cpp
Merge commit '014773b66bdff4de24f384066d1a85d2a5bb6774'
[ffmpeg] / libavdevice / decklink_enc.cpp
index dc4a24b8b1c3c57c342eb1547f63589e5436c677..8892d1972fb77f6eadaa12aae208d8a12bb66b8d 100644 (file)
@@ -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 _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);