Skip to content

Commit 9f4df9a

Browse files
dheitmuellerlance-lmwang
authored andcommitted
avdevice/decklink_enc: add support for playout of 608 captions in MOV files
Unlike other cases where the closed captions are embedded in the video stream as MPEG-2 userdata or H.264 SEI data, with MOV files the captions are often found on a separate "e608" subtitle track. Add support for playout of such files, leveraging the new ccfifo mechanism to ensure that they are embedded into VANC at the correct rate (since e608 packets often contain batches of multiple 608 pairs). Note this patch includes a new file named libavdevice/ccfifo.c, which allows the ccfifo functionality in libavfilter to be reused even if doing shared builds. This is the same approach used for log2_tab.c. Signed-off-by: Devin Heitmueller <[email protected]> Signed-off-by: Limin Wang <[email protected]>
1 parent 0e12cdc commit 9f4df9a

File tree

5 files changed

+94
-1
lines changed

5 files changed

+94
-1
lines changed

libavdevice/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ OBJS-$(CONFIG_LIBDC1394_INDEV) += libdc1394.o
5757

5858
# Objects duplicated from other libraries for shared builds
5959
SHLIBOBJS-$(CONFIG_DECKLINK_INDEV) += reverse.o
60+
SHLIBOBJS-$(CONFIG_DECKLINK_OUTDEV) += ccfifo.o
6061

6162
# Windows resource file
6263
SHLIBOBJS-$(HAVE_GNU_WINDRES) += avdeviceres.o

libavdevice/ccfifo.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* CEA-708 Closed Captioning FIFO
3+
* Copyright (c) 2023 LTN Global Communications
4+
*
5+
* Author: Devin Heitmueller <[email protected]>
6+
*
7+
* This file is part of FFmpeg.
8+
*
9+
* FFmpeg is free software; you can redistribute it and/or
10+
* modify it under the terms of the GNU Lesser General Public
11+
* License as published by the Free Software Foundation; either
12+
* version 2.1 of the License, or (at your option) any later version.
13+
*
14+
* FFmpeg is distributed in the hope that it will be useful,
15+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17+
* Lesser General Public License for more details.
18+
*
19+
* You should have received a copy of the GNU Lesser General Public
20+
* License along with FFmpeg; if not, write to the Free Software
21+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22+
*/
23+
24+
#include "libavfilter/ccfifo.c"

libavdevice/decklink_common.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131

3232
extern "C" {
3333
#include "libavcodec/packet_internal.h"
34+
#include "libavfilter/ccfifo.h"
3435
}
3536
#include "libavutil/thread.h"
3637
#include "decklink_common_c.h"
@@ -112,6 +113,8 @@ struct decklink_ctx {
112113
/* Capture buffer queue */
113114
AVPacketQueue queue;
114115

116+
AVCCFifo *cc_fifo; ///< closed captions
117+
115118
/* Streams present */
116119
int audio;
117120
int video;

libavdevice/decklink_enc.cpp

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,25 @@ static int create_s337_payload(AVPacket *pkt, uint8_t **outbuf, int *outsize)
326326
return 0;
327327
}
328328

329+
static int decklink_setup_subtitle(AVFormatContext *avctx, AVStream *st)
330+
{
331+
int ret = -1;
332+
333+
switch(st->codecpar->codec_id) {
334+
#if CONFIG_LIBKLVANC
335+
case AV_CODEC_ID_EIA_608:
336+
/* No special setup required */
337+
ret = 0;
338+
break;
339+
#endif
340+
default:
341+
av_log(avctx, AV_LOG_ERROR, "Unsupported subtitle codec specified\n");
342+
break;
343+
}
344+
345+
return ret;
346+
}
347+
329348
av_cold int ff_decklink_write_trailer(AVFormatContext *avctx)
330349
{
331350
struct decklink_cctx *cctx = (struct decklink_cctx *)avctx->priv_data;
@@ -352,6 +371,7 @@ av_cold int ff_decklink_write_trailer(AVFormatContext *avctx)
352371
klvanc_context_destroy(ctx->vanc_ctx);
353372
#endif
354373

374+
ff_ccfifo_freep(&ctx->cc_fifo);
355375
av_freep(&cctx->ctx);
356376

357377
return 0;
@@ -503,6 +523,21 @@ static void construct_afd(AVFormatContext *avctx, struct decklink_ctx *ctx,
503523
free(afd_words);
504524
}
505525

526+
/* Parse any EIA-608 subtitles sitting on the queue, and write packet side data
527+
that will later be handled by construct_cc... */
528+
static void parse_608subs(AVFormatContext *avctx, struct decklink_ctx *ctx, AVPacket *pkt)
529+
{
530+
size_t cc_size = ff_ccfifo_getoutputsize(ctx->cc_fifo);
531+
uint8_t *cc_data;
532+
533+
if (!ff_ccfifo_ccdetected(ctx->cc_fifo))
534+
return;
535+
536+
cc_data = av_packet_new_side_data(pkt, AV_PKT_DATA_A53_CC, cc_size);
537+
if (cc_data)
538+
ff_ccfifo_injectbytes(ctx->cc_fifo, cc_data, cc_size);
539+
}
540+
506541
static int decklink_construct_vanc(AVFormatContext *avctx, struct decklink_ctx *ctx,
507542
AVPacket *pkt, decklink_frame *frame,
508543
AVStream *st)
@@ -513,6 +548,7 @@ static int decklink_construct_vanc(AVFormatContext *avctx, struct decklink_ctx *
513548
if (!ctx->supports_vanc)
514549
return 0;
515550

551+
parse_608subs(avctx, ctx, pkt);
516552
construct_cc(avctx, ctx, pkt, &vanc_lines);
517553
construct_afd(avctx, ctx, pkt, &vanc_lines, st);
518554

@@ -704,6 +740,16 @@ static int decklink_write_audio_packet(AVFormatContext *avctx, AVPacket *pkt)
704740
return ret;
705741
}
706742

743+
static int decklink_write_subtitle_packet(AVFormatContext *avctx, AVPacket *pkt)
744+
{
745+
struct decklink_cctx *cctx = (struct decklink_cctx *)avctx->priv_data;
746+
struct decklink_ctx *ctx = (struct decklink_ctx *)cctx->ctx;
747+
748+
ff_ccfifo_extractbytes(ctx->cc_fifo, pkt->data, pkt->size);
749+
750+
return 0;
751+
}
752+
707753
extern "C" {
708754

709755
av_cold int ff_decklink_write_header(AVFormatContext *avctx)
@@ -768,12 +814,29 @@ av_cold int ff_decklink_write_header(AVFormatContext *avctx)
768814
} else if (c->codec_type == AVMEDIA_TYPE_VIDEO) {
769815
if (decklink_setup_video(avctx, st))
770816
goto error;
817+
} else if (c->codec_type == AVMEDIA_TYPE_SUBTITLE) {
818+
if (decklink_setup_subtitle(avctx, st))
819+
goto error;
771820
} else {
772821
av_log(avctx, AV_LOG_ERROR, "Unsupported stream type.\n");
773822
goto error;
774823
}
775824
}
776825

826+
for (n = 0; n < avctx->nb_streams; n++) {
827+
AVStream *st = avctx->streams[n];
828+
AVCodecParameters *c = st->codecpar;
829+
830+
if(c->codec_type == AVMEDIA_TYPE_SUBTITLE)
831+
avpriv_set_pts_info(st, 64, ctx->bmd_tb_num, ctx->bmd_tb_den);
832+
}
833+
834+
if (!(ctx->cc_fifo = ff_ccfifo_alloc(av_make_q(ctx->bmd_tb_den, ctx->bmd_tb_num), avctx))) {
835+
av_log(ctx, AV_LOG_ERROR, "Failure to setup CC FIFO queue\n");
836+
ret = AVERROR(ENOMEM);
837+
goto error;
838+
}
839+
777840
return 0;
778841

779842
error:
@@ -789,6 +852,8 @@ int ff_decklink_write_packet(AVFormatContext *avctx, AVPacket *pkt)
789852
return decklink_write_video_packet(avctx, pkt);
790853
else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
791854
return decklink_write_audio_packet(avctx, pkt);
855+
else if (st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE)
856+
return decklink_write_subtitle_packet(avctx, pkt);
792857

793858
return AVERROR(EIO);
794859
}

libavdevice/decklink_enc_c.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ const FFOutputFormat ff_decklink_muxer = {
7777
.p.long_name = NULL_IF_CONFIG_SMALL("Blackmagic DeckLink output"),
7878
.p.audio_codec = AV_CODEC_ID_PCM_S16LE,
7979
.p.video_codec = AV_CODEC_ID_WRAPPED_AVFRAME,
80-
.p.subtitle_codec = AV_CODEC_ID_NONE,
80+
.p.subtitle_codec = AV_CODEC_ID_EIA_608,
8181
.p.flags = AVFMT_NOFILE,
8282
.p.priv_class = &decklink_muxer_class,
8383
.get_device_list = ff_decklink_list_output_devices,

0 commit comments

Comments
 (0)