diff --git a/libavdevice/decklink_common.cpp b/libavdevice/decklink_common.cpp
index 31ab249..8d2c6d0 100644
--- a/libavdevice/decklink_common.cpp
+++ b/libavdevice/decklink_common.cpp
@@ -505,6 +505,22 @@ int avpacket_queue_get(AVPacketQueue *q, AVPacket *pkt, int block)
     return ret;
 }
 
+int64_t avpacket_queue_peekpts(AVPacketQueue *q)
+{
+    PacketListEntry *pkt1;
+    int64_t pts = -1;
+
+    pthread_mutex_lock(&q->mutex);
+    pkt1 = q->pkt_list.head;
+    if (pkt1) {
+        pts = pkt1->pkt.pts;
+    }
+    pthread_mutex_unlock(&q->mutex);
+
+    return pts;
+}
+
+
 int ff_decklink_list_devices(AVFormatContext *avctx,
                              struct AVDeviceInfoList *device_list,
                              int show_inputs, int show_outputs)
diff --git a/libavdevice/decklink_common.h b/libavdevice/decklink_common.h
index d4330e5..99afcd4 100644
--- a/libavdevice/decklink_common.h
+++ b/libavdevice/decklink_common.h
@@ -112,6 +112,9 @@ struct decklink_ctx {
     /* Capture buffer queue */
     AVPacketQueue queue;
 
+    /* Output VANC queue */
+    AVPacketQueue vanc_queue;
+
     /* Streams present */
     int audio;
     int video;
@@ -238,5 +241,6 @@ void avpacket_queue_end(AVPacketQueue *q);
 unsigned long long avpacket_queue_size(AVPacketQueue *q);
 int avpacket_queue_put(AVPacketQueue *q, AVPacket *pkt);
 int avpacket_queue_get(AVPacketQueue *q, AVPacket *pkt, int block);
+int64_t avpacket_queue_peekpts(AVPacketQueue *q);
 
 #endif /* AVDEVICE_DECKLINK_COMMON_H */
diff --git a/libavdevice/decklink_enc.cpp b/libavdevice/decklink_enc.cpp
index 92bfdb2..d7357a0 100644
--- a/libavdevice/decklink_enc.cpp
+++ b/libavdevice/decklink_enc.cpp
@@ -326,6 +326,25 @@ static int create_s337_payload(AVPacket *pkt, uint8_t **outbuf, int *outsize)
     return 0;
 }
 
+static int decklink_setup_data(AVFormatContext *avctx, AVStream *st)
+{
+    int ret = -1;
+
+    switch(st->codecpar->codec_id) {
+#if CONFIG_LIBKLVANC
+    case AV_CODEC_ID_SMPTE_2038:
+        /* No specific setup required */
+        ret = 0;
+        break;
+#endif
+    default:
+        av_log(avctx, AV_LOG_ERROR, "Unsupported data codec specified\n");
+        break;
+    }
+
+    return ret;
+}
+
 av_cold int ff_decklink_write_trailer(AVFormatContext *avctx)
 {
     struct decklink_cctx *cctx = (struct decklink_cctx *)avctx->priv_data;
@@ -351,6 +370,7 @@ av_cold int ff_decklink_write_trailer(AVFormatContext *avctx)
 #if CONFIG_LIBKLVANC
     klvanc_context_destroy(ctx->vanc_ctx);
 #endif
+    avpacket_queue_end(&ctx->vanc_queue);
 
     av_freep(&cctx->ctx);
 
@@ -516,6 +536,58 @@ static int decklink_construct_vanc(AVFormatContext *avctx, struct decklink_ctx *
     construct_cc(avctx, ctx, pkt, &vanc_lines);
     construct_afd(avctx, ctx, pkt, &vanc_lines, st);
 
+    /* See if there any pending data packets to process */
+    while (avpacket_queue_size(&ctx->vanc_queue) > 0) {
+        AVStream *vanc_st;
+        AVPacket vanc_pkt;
+        int64_t pts;
+
+        pts = avpacket_queue_peekpts(&ctx->vanc_queue);
+        if (pts > ctx->last_pts) {
+            /* We haven't gotten to the video frame we are supposed to inject
+               the oldest VANC packet into yet, so leave it on the queue... */
+            break;
+        }
+
+        avpacket_queue_get(&ctx->vanc_queue, &vanc_pkt, 1);
+        if (vanc_pkt.pts + 1 < ctx->last_pts) {
+            av_log(avctx, AV_LOG_WARNING, "VANC packet too old, throwing away\n");
+            av_packet_unref(&vanc_pkt);
+            continue;
+        }
+
+        vanc_st = avctx->streams[vanc_pkt.stream_index];
+        if (vanc_st->codecpar->codec_id == AV_CODEC_ID_SMPTE_2038) {
+            struct klvanc_smpte2038_anc_data_packet_s *pkt_2038 = 0;
+
+            klvanc_smpte2038_parse_pes_payload(vanc_pkt.data, vanc_pkt.size, &pkt_2038);
+            if (pkt_2038 == NULL) {
+                av_log(avctx, AV_LOG_ERROR, "failed to decode SMPTE 2038 PES packet");
+                av_packet_unref(&vanc_pkt);
+                continue;
+            }
+            for (int i = 0; i < pkt_2038->lineCount; i++) {
+                struct klvanc_smpte2038_anc_data_line_s *l = &pkt_2038->lines[i];
+                uint16_t *vancWords = NULL;
+                uint16_t vancWordCount;
+
+                if (klvanc_smpte2038_convert_line_to_words(l, &vancWords,
+                                                           &vancWordCount) < 0)
+                    break;
+
+                ret = klvanc_line_insert(ctx->vanc_ctx, &vanc_lines, vancWords,
+                                         vancWordCount, l->line_number, 0);
+                free(vancWords);
+                if (ret != 0) {
+                    av_log(avctx, AV_LOG_ERROR, "VANC line insertion failed\n");
+                    break;
+                }
+            }
+            klvanc_smpte2038_anc_data_packet_free(pkt_2038);
+        }
+        av_packet_unref(&vanc_pkt);
+    }
+
     IDeckLinkVideoFrameAncillary *vanc;
     int result = ctx->dlo->CreateAncillaryData(bmdFormat10BitYUV, &vanc);
     if (result != S_OK) {
@@ -704,6 +776,23 @@ static int decklink_write_audio_packet(AVFormatContext *avctx, AVPacket *pkt)
     return ret;
 }
 
+static int decklink_write_data_packet(AVFormatContext *avctx, AVPacket *pkt)
+{
+    struct decklink_cctx *cctx = (struct decklink_cctx *)avctx->priv_data;
+    struct decklink_ctx *ctx = (struct decklink_ctx *)cctx->ctx;
+
+    AVPacket *avpacket = av_packet_clone(pkt);
+    if (!avpacket) {
+        av_log(avctx, AV_LOG_ERROR, "Could not clone data packet.\n");
+        return AVERROR(EIO);
+    }
+    if (avpacket_queue_put(&ctx->vanc_queue, avpacket) < 0) {
+        av_log(avctx, AV_LOG_WARNING, "Failed to queue DATA packet\n");
+    }
+
+    return 0;
+}
+
 extern "C" {
 
 av_cold int ff_decklink_write_header(AVFormatContext *avctx)
@@ -768,12 +857,24 @@ av_cold int ff_decklink_write_header(AVFormatContext *avctx)
         } else if (c->codec_type == AVMEDIA_TYPE_VIDEO) {
             if (decklink_setup_video(avctx, st))
                 goto error;
+        } else if (c->codec_type == AVMEDIA_TYPE_DATA) {
+            if (decklink_setup_data(avctx, st))
+                goto error;
         } else {
             av_log(avctx, AV_LOG_ERROR, "Unsupported stream type.\n");
             goto error;
         }
     }
 
+    /* Reconfigure the data stream clocks to match the video */
+    for (n = 0; n < avctx->nb_streams; n++) {
+        AVStream *st = avctx->streams[n];
+        AVCodecParameters *c = st->codecpar;
+        if (c->codec_type == AVMEDIA_TYPE_DATA)
+            avpriv_set_pts_info(st, 64, ctx->bmd_tb_num, ctx->bmd_tb_den);
+    }
+    avpacket_queue_init (avctx, &ctx->vanc_queue);
+
     return 0;
 
 error:
@@ -789,6 +890,9 @@ int ff_decklink_write_packet(AVFormatContext *avctx, AVPacket *pkt)
         return decklink_write_video_packet(avctx, pkt);
     else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
         return decklink_write_audio_packet(avctx, pkt);
+    else if (st->codecpar->codec_type == AVMEDIA_TYPE_DATA) {
+        return decklink_write_data_packet(avctx, pkt);
+    }
 
     return AVERROR(EIO);
 }
diff --git a/libavdevice/decklink_enc_c.c b/libavdevice/decklink_enc_c.c
index f7e3150..7aab660 100644
--- a/libavdevice/decklink_enc_c.c
+++ b/libavdevice/decklink_enc_c.c
@@ -32,6 +32,7 @@ static const AVOption options[] = {
     { "list_devices", "use ffmpeg -sinks decklink instead", OFFSET(list_devices), AV_OPT_TYPE_BOOL, { .i64 = 0   }, 0, 1, ENC | AV_OPT_FLAG_DEPRECATED},
     { "list_formats", "list supported formats"  , OFFSET(list_formats), AV_OPT_TYPE_INT   , { .i64 = 0   }, 0, 1, ENC },
     { "preroll"     , "video preroll in seconds", OFFSET(preroll     ), AV_OPT_TYPE_DOUBLE, { .dbl = 0.5 }, 0, 5, ENC },
+    { "queue_size",   "output queue buffer size", OFFSET(queue_size  ), AV_OPT_TYPE_INT64, { .i64 = (1024 * 1024)}, 0, INT64_MAX, ENC },
 #if BLACKMAGIC_DECKLINK_API_VERSION >= 0x0b000000
     { "duplex_mode" , "duplex mode"             , OFFSET(duplex_mode ), AV_OPT_TYPE_INT   , { .i64 = 0   }, 0, 5, ENC, "duplex_mode"},
 #else
