FFmpeg
ccfifo.c
Go to the documentation of this file.
1 /*
2  * CEA-708 Closed Captioning FIFO
3  * Copyright (c) 2023 LTN Global Communications
4  *
5  * Author: Devin Heitmueller <dheitmueller@ltnglobal.com>
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 "ccfifo.h"
25 
26 #define MAX_CC_ELEMENTS 128
27 #define CC_BYTES_PER_ENTRY 3
28 
29 struct cc_lookup {
30  int num;
31  int den;
32  int cc_count;
33  int num_608;
34 };
35 
36 const static struct cc_lookup cc_lookup_vals[] = {
37  { 15, 1, 40, 4 },
38  { 24, 1, 25, 3 },
39  { 24000, 1001, 25, 3 },
40  { 30, 1, 20, 2 },
41  { 30000, 1001, 20, 2},
42  { 60, 1, 10, 1 },
43  { 60000, 1001, 10, 1},
44 };
45 
47 {
50  memset(ccf, 0, sizeof(*ccf));
51 }
52 
53 int ff_ccfifo_init(CCFifo *ccf, AVRational framerate, void *log_ctx)
54 {
55  int i;
56 
57  memset(ccf, 0, sizeof(*ccf));
58  ccf->log_ctx = log_ctx;
59  ccf->framerate = framerate;
60 
62  goto error;
63 
65  goto error;
66 
67  /* Based on the target FPS, figure out the expected cc_count and number of
68  608 tuples per packet. See ANSI/CTA-708-E Sec 4.3.6.1. */
69  for (i = 0; i < FF_ARRAY_ELEMS(cc_lookup_vals); i++) {
70  if (framerate.num == cc_lookup_vals[i].num &&
71  framerate.den == cc_lookup_vals[i].den) {
74  break;
75  }
76  }
77 
78  if (ccf->expected_608 == 0) {
79  /* We didn't find an output frame we support. We'll let the call succeed
80  and the FIFO to be allocated, but the extract/inject functions will simply
81  leave everything the way it is */
82  ccf->passthrough = 1;
83  }
84 
85  return 0;
86 
87 error:
88  ff_ccfifo_uninit(ccf);
89  return AVERROR(ENOMEM);
90 }
91 
93 {
95 }
96 
98 {
99  return ccf->cc_detected;
100 }
101 
102 int ff_ccfifo_injectbytes(CCFifo *ccf, uint8_t *cc_data, size_t len)
103 {
104  int cc_608_tuples = 0;
105  int cc_708_tuples = 0;
106  int cc_filled = 0;
107 
108  if (ccf->passthrough) {
109  return 0;
110  }
111 
112  if (len < ff_ccfifo_getoutputsize(ccf)) {
113  return AVERROR(EINVAL);
114  }
115 
116  /* Insert any available data from the 608 FIFO */
117  if (ccf->expected_608 <= av_fifo_can_read(ccf->cc_608_fifo))
118  cc_608_tuples = ccf->expected_608;
119  else
120  cc_608_tuples = av_fifo_can_read(ccf->cc_608_fifo);
121  av_fifo_read(ccf->cc_608_fifo, cc_data, cc_608_tuples);
122  cc_filled += cc_608_tuples;
123 
124  /* Insert any available data from the 708 FIFO */
125  if ((ccf->expected_cc_count - cc_filled) <= av_fifo_can_read(ccf->cc_708_fifo))
126  cc_708_tuples = ccf->expected_cc_count - cc_filled;
127  else
128  cc_708_tuples = av_fifo_can_read(ccf->cc_708_fifo);
129  av_fifo_read(ccf->cc_708_fifo, &cc_data[cc_filled * CC_BYTES_PER_ENTRY], cc_708_tuples);
130  cc_filled += cc_708_tuples;
131 
132  /* Insert 708 padding into any remaining fields */
133  while (cc_filled < ccf->expected_cc_count) {
134  cc_data[cc_filled * CC_BYTES_PER_ENTRY] = 0xfa;
135  cc_data[cc_filled * CC_BYTES_PER_ENTRY + 1] = 0x00;
136  cc_data[cc_filled * CC_BYTES_PER_ENTRY + 2] = 0x00;
137  cc_filled++;
138  }
139 
140  return 0;
141 }
142 
144 {
145  AVFrameSideData *sd;
146  int ret;
147 
148  if (ccf->passthrough == 1 || ccf->cc_detected == 0)
149  return 0;
150 
153  if (sd) {
154  ret = ff_ccfifo_injectbytes(ccf, sd->data, sd->size);
155  if (ret < 0) {
157  return ret;
158  }
159  }
160 
161  return 0;
162 }
163 
164 int ff_ccfifo_extractbytes(CCFifo *ccf, uint8_t *cc_bytes, size_t len)
165 {
167 
168  if (ccf->passthrough == 1) {
170  "cc_fifo cannot transcode captions fps=%d/%d\n",
171  ccf->framerate.num, ccf->framerate.den);
172  return 0;
173  }
174 
175  ccf->cc_detected = 1;
176 
177  for (int i = 0; i < cc_count; i++) {
178  /* See ANSI/CTA-708-E Sec 4.3, Table 3 */
179  uint8_t cc_valid = (cc_bytes[CC_BYTES_PER_ENTRY*i] & 0x04) >> 2;
180  uint8_t cc_type = cc_bytes[CC_BYTES_PER_ENTRY*i] & 0x03;
181  if (cc_type == 0x00 || cc_type == 0x01) {
182  av_fifo_write(ccf->cc_608_fifo, &cc_bytes[CC_BYTES_PER_ENTRY*i], 1);
183  } else if (cc_valid && (cc_type == 0x02 || cc_type == 0x03)) {
184  av_fifo_write(ccf->cc_708_fifo, &cc_bytes[CC_BYTES_PER_ENTRY*i], 1);
185  }
186  }
187  return 0;
188 }
189 
190 /* Read the A53 side data, discard padding, and put 608/708 into
191  queues so we can ensure they get into the output frames at
192  the correct rate... */
194 {
196  if (side_data) {
197  ff_ccfifo_extractbytes(ccf, side_data->data, side_data->size);
198 
199  /* Remove the side data, as we will re-create it on the
200  output as needed */
201  if (!ccf->passthrough)
203  }
204  return 0;
205 }
error
static void error(const char *err)
Definition: target_bsf_fuzzer.c:31
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:186
ff_ccfifo_extractbytes
int ff_ccfifo_extractbytes(CCFifo *ccf, uint8_t *cc_bytes, size_t len)
Just like ff_ccfifo_extract(), but takes the raw bytes instead of an AVFrame.
Definition: ccfifo.c:164
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
av_frame_get_side_data
AVFrameSideData * av_frame_get_side_data(const AVFrame *frame, enum AVFrameSideDataType type)
Definition: frame.c:824
av_frame_new_side_data
AVFrameSideData * av_frame_new_side_data(AVFrame *frame, enum AVFrameSideDataType type, size_t size)
Add a new side data to a frame.
Definition: frame.c:812
AV_FRAME_DATA_A53_CC
@ AV_FRAME_DATA_A53_CC
ATSC A53 Part 4 Closed Captions.
Definition: frame.h:59
cc_lookup_vals
const static struct cc_lookup cc_lookup_vals[]
Definition: ccfifo.c:36
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:340
ff_ccfifo_ccdetected
int ff_ccfifo_ccdetected(const CCFifo *ccf)
Returns 1 if captions have been found as a prior call to ff_ccfifo_extract() or ff_ccfifo_extractbyte...
Definition: ccfifo.c:97
CCFifo::framerate
AVRational framerate
Definition: ccfifo.h:39
av_fifo_write
int av_fifo_write(AVFifo *f, const void *buf, size_t nb_elems)
Write data into a FIFO.
Definition: fifo.c:188
ff_ccfifo_uninit
void ff_ccfifo_uninit(CCFifo *ccf)
Free all memory allocated in a CCFifo and clear the context.
Definition: ccfifo.c:46
CC_BYTES_PER_ENTRY
#define CC_BYTES_PER_ENTRY
Definition: ccfifo.c:27
AVRational::num
int num
Numerator.
Definition: rational.h:59
CCFifo::expected_608
int expected_608
Definition: ccfifo.h:41
CCFifo::cc_detected
int cc_detected
Definition: ccfifo.h:42
AVFrameSideData::size
size_t size
Definition: frame.h:249
FF_ARRAY_ELEMS
#define FF_ARRAY_ELEMS(a)
Definition: sinewin_tablegen.c:29
av_fifo_read
int av_fifo_read(AVFifo *f, void *buf, size_t nb_elems)
Read data from a FIFO.
Definition: fifo.c:240
ff_ccfifo_inject
int ff_ccfifo_inject(CCFifo *ccf, AVFrame *frame)
Insert CC data from the FIFO into an AVFrame (as side data)
Definition: ccfifo.c:143
MAX_CC_ELEMENTS
#define MAX_CC_ELEMENTS
Definition: ccfifo.c:26
cc_lookup::cc_count
int cc_count
Definition: ccfifo.c:32
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:201
frame
static AVFrame * frame
Definition: demux_decode.c:54
CCFifo::passthrough
int passthrough
Definition: ccfifo.h:43
framerate
float framerate
Definition: av1_levels.c:29
cc_lookup
Definition: ccfifo.c:29
AVRational
Rational number (pair of numerator and denominator).
Definition: rational.h:58
av_fifo_can_read
size_t av_fifo_can_read(const AVFifo *f)
Definition: fifo.c:87
ff_ccfifo_extract
int ff_ccfifo_extract(CCFifo *ccf, AVFrame *frame)
Extract CC data from an AVFrame.
Definition: ccfifo.c:193
CCFifo
Definition: ccfifo.h:36
cc_lookup::den
int den
Definition: ccfifo.c:31
AVFrameSideData::data
uint8_t * data
Definition: frame.h:248
av_frame_remove_side_data
void av_frame_remove_side_data(AVFrame *frame, enum AVFrameSideDataType type)
Remove and free all side data instances of the given type.
Definition: frame.c:919
ff_ccfifo_getoutputsize
int ff_ccfifo_getoutputsize(const CCFifo *ccf)
Provide the size in bytes of an output buffer to allocate.
Definition: ccfifo.c:92
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:255
len
int len
Definition: vorbis_enc_data.h:426
ff_ccfifo_init
int ff_ccfifo_init(CCFifo *ccf, AVRational framerate, void *log_ctx)
Initialize a CCFifo.
Definition: ccfifo.c:53
ret
ret
Definition: filter_design.txt:187
ff_ccfifo_injectbytes
int ff_ccfifo_injectbytes(CCFifo *ccf, uint8_t *cc_data, size_t len)
Just like ff_ccfifo_inject(), but takes the raw bytes to insert the CC data int rather than an AVFram...
Definition: ccfifo.c:102
cc_lookup::num
int num
Definition: ccfifo.c:30
av_fifo_alloc2
AVFifo * av_fifo_alloc2(size_t nb_elems, size_t elem_size, unsigned int flags)
Allocate and initialize an AVFifo with a given element size.
Definition: fifo.c:47
CCFifo::expected_cc_count
int expected_cc_count
Definition: ccfifo.h:40
CCFifo::log_ctx
void * log_ctx
Definition: ccfifo.h:45
AVRational::den
int den
Denominator.
Definition: rational.h:60
CCFifo::cc_608_fifo
AVFifo * cc_608_fifo
Definition: ccfifo.h:37
av_log_once
void av_log_once(void *avcl, int initial_level, int subsequent_level, int *state, const char *fmt,...)
Definition: log.c:417
AVFrameSideData
Structure to hold side data for an AVFrame.
Definition: frame.h:246
av_fifo_freep2
void av_fifo_freep2(AVFifo **f)
Free an AVFifo and reset pointer to NULL.
Definition: fifo.c:286
ccfifo.h
cc_lookup::num_608
int num_608
Definition: ccfifo.c:33
CCFifo::passthrough_warning
int passthrough_warning
Definition: ccfifo.h:44
CCFifo::cc_708_fifo
AVFifo * cc_708_fifo
Definition: ccfifo.h:38