FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavfilter/ccfifo.c
Date: 2024-04-19 17:50:32
Exec Total Coverage
Lines: 27 81 33.3%
Functions: 4 6 66.7%
Branches: 13 48 27.1%

Line Branch Exec Source
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 #include "libavutil/fifo.h"
26
27 #define MAX_CC_ELEMENTS 128
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
46 272 void ff_ccfifo_uninit(CCFifo *ccf)
47 {
48 272 av_fifo_freep2(&ccf->cc_608_fifo);
49 272 av_fifo_freep2(&ccf->cc_708_fifo);
50 272 memset(ccf, 0, sizeof(*ccf));
51 272 }
52
53 134 int ff_ccfifo_init(CCFifo *ccf, AVRational framerate, void *log_ctx)
54 {
55 int i;
56
57 134 memset(ccf, 0, sizeof(*ccf));
58 134 ccf->log_ctx = log_ctx;
59 134 ccf->framerate = framerate;
60
61
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 134 times.
134 if (!(ccf->cc_708_fifo = av_fifo_alloc2(MAX_CC_ELEMENTS, CC_BYTES_PER_ENTRY, 0)))
62 goto error;
63
64
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 134 times.
134 if (!(ccf->cc_608_fifo = av_fifo_alloc2(MAX_CC_ELEMENTS, CC_BYTES_PER_ENTRY, 0)))
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
2/2
✓ Branch 0 taken 929 times.
✓ Branch 1 taken 131 times.
1060 for (i = 0; i < FF_ARRAY_ELEMS(cc_lookup_vals); i++) {
70
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 926 times.
929 if (framerate.num == cc_lookup_vals[i].num &&
71
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 framerate.den == cc_lookup_vals[i].den) {
72 3 ccf->expected_cc_count = cc_lookup_vals[i].cc_count;
73 3 ccf->expected_608 = cc_lookup_vals[i].num_608;
74 3 break;
75 }
76 }
77
78
2/2
✓ Branch 0 taken 131 times.
✓ Branch 1 taken 3 times.
134 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 131 ccf->passthrough = 1;
83 }
84
85 134 return 0;
86
87 error:
88 ff_ccfifo_uninit(ccf);
89 return AVERROR(ENOMEM);
90 }
91
92 int ff_ccfifo_injectbytes(CCFifo *ccf, uint8_t *cc_data, size_t len)
93 {
94 int cc_608_tuples = 0;
95 int cc_708_tuples = 0;
96 int cc_filled = 0;
97
98 if (ccf->passthrough) {
99 return 0;
100 }
101
102 if (len < ff_ccfifo_getoutputsize(ccf)) {
103 return AVERROR(EINVAL);
104 }
105
106 /* Insert any available data from the 608 FIFO */
107 if (ccf->expected_608 <= av_fifo_can_read(ccf->cc_608_fifo))
108 cc_608_tuples = ccf->expected_608;
109 else
110 cc_608_tuples = av_fifo_can_read(ccf->cc_608_fifo);
111 av_fifo_read(ccf->cc_608_fifo, cc_data, cc_608_tuples);
112 cc_filled += cc_608_tuples;
113
114 /* Insert any available data from the 708 FIFO */
115 if ((ccf->expected_cc_count - cc_filled) <= av_fifo_can_read(ccf->cc_708_fifo))
116 cc_708_tuples = ccf->expected_cc_count - cc_filled;
117 else
118 cc_708_tuples = av_fifo_can_read(ccf->cc_708_fifo);
119 av_fifo_read(ccf->cc_708_fifo, &cc_data[cc_filled * CC_BYTES_PER_ENTRY], cc_708_tuples);
120 cc_filled += cc_708_tuples;
121
122 /* Insert 708 padding into any remaining fields */
123 while (cc_filled < ccf->expected_cc_count) {
124 cc_data[cc_filled * CC_BYTES_PER_ENTRY] = 0xfa;
125 cc_data[cc_filled * CC_BYTES_PER_ENTRY + 1] = 0x00;
126 cc_data[cc_filled * CC_BYTES_PER_ENTRY + 2] = 0x00;
127 cc_filled++;
128 }
129
130 return 0;
131 }
132
133 1334 int ff_ccfifo_inject(CCFifo *ccf, AVFrame *frame)
134 {
135 AVFrameSideData *sd;
136 int ret;
137
138
3/4
✓ Branch 0 taken 712 times.
✓ Branch 1 taken 622 times.
✓ Branch 2 taken 712 times.
✗ Branch 3 not taken.
1334 if (ccf->passthrough == 1 || ccf->cc_detected == 0)
139 1334 return 0;
140
141 sd = av_frame_new_side_data(frame, AV_FRAME_DATA_A53_CC,
142 ff_ccfifo_getoutputsize(ccf));
143 if (sd) {
144 ret = ff_ccfifo_injectbytes(ccf, sd->data, sd->size);
145 if (ret < 0) {
146 av_frame_remove_side_data(frame, AV_FRAME_DATA_A53_CC);
147 return ret;
148 }
149 }
150
151 return 0;
152 }
153
154 int ff_ccfifo_extractbytes(CCFifo *ccf, uint8_t *cc_bytes, size_t len)
155 {
156 int cc_count = len / CC_BYTES_PER_ENTRY;
157
158 if (ccf->passthrough == 1) {
159 av_log_once(ccf->log_ctx, AV_LOG_WARNING, AV_LOG_DEBUG, &ccf->passthrough_warning,
160 "cc_fifo cannot transcode captions fps=%d/%d\n",
161 ccf->framerate.num, ccf->framerate.den);
162 return 0;
163 }
164
165 ccf->cc_detected = 1;
166
167 for (int i = 0; i < cc_count; i++) {
168 /* See ANSI/CTA-708-E Sec 4.3, Table 3 */
169 uint8_t cc_valid = (cc_bytes[CC_BYTES_PER_ENTRY*i] & 0x04) >> 2;
170 uint8_t cc_type = cc_bytes[CC_BYTES_PER_ENTRY*i] & 0x03;
171 if (cc_type == 0x00 || cc_type == 0x01) {
172 av_fifo_write(ccf->cc_608_fifo, &cc_bytes[CC_BYTES_PER_ENTRY*i], 1);
173 } else if (cc_valid && (cc_type == 0x02 || cc_type == 0x03)) {
174 av_fifo_write(ccf->cc_708_fifo, &cc_bytes[CC_BYTES_PER_ENTRY*i], 1);
175 }
176 }
177 return 0;
178 }
179
180 /* Read the A53 side data, discard padding, and put 608/708 into
181 queues so we can ensure they get into the output frames at
182 the correct rate... */
183 1072 int ff_ccfifo_extract(CCFifo *ccf, AVFrame *frame)
184 {
185 1072 AVFrameSideData *side_data = av_frame_get_side_data(frame, AV_FRAME_DATA_A53_CC);
186
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1072 times.
1072 if (side_data) {
187 ff_ccfifo_extractbytes(ccf, side_data->data, side_data->size);
188
189 /* Remove the side data, as we will re-create it on the
190 output as needed */
191 if (!ccf->passthrough)
192 av_frame_remove_side_data(frame, AV_FRAME_DATA_A53_CC);
193 }
194 1072 return 0;
195 }
196