FFmpeg
Loading...
Searching...
No Matches
eia608_to_smpte436m.c
Go to the documentation of this file.
1/*
2 * EIA-608 to MXF SMPTE-436M ANC bitstream filter
3 * Copyright (c) 2025 Jacob Lifshay
4 *
5 * This file is part of FFmpeg.
6 *
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22#include "libavcodec/bsf.h"
24#include "libavcodec/codec_id.h"
27#include "libavutil/avassert.h"
28#include "libavutil/avutil.h"
29#include "libavutil/error.h"
31#include "libavutil/macros.h"
32#include "libavutil/opt.h"
33#include "libavutil/rational.h"
34
46
47// clang-format off
49 .did = 0x61,
50 .sdid_or_dbn = 0x01,
51 .data_count = 0x49,
52 .payload = {
53 // header
54 0x96, 0x69, 0x49, 0x7F, 0x43, 0xFA, 0x8D, 0x72, 0xF4,
55
56 // 608 triples
57 0xFC, 0x80, 0x80, 0xFD, 0x80, 0x80,
58
59 // 708 padding
60 0xFA, 0x00, 0x00, 0xFA, 0x00, 0x00, 0xFA, 0x00, 0x00,
61 0xFA, 0x00, 0x00, 0xFA, 0x00, 0x00, 0xFA, 0x00, 0x00,
62 0xFA, 0x00, 0x00, 0xFA, 0x00, 0x00, 0xFA, 0x00, 0x00,
63 0xFA, 0x00, 0x00, 0xFA, 0x00, 0x00, 0xFA, 0x00, 0x00,
64 0xFA, 0x00, 0x00, 0xFA, 0x00, 0x00, 0xFA, 0x00, 0x00,
65 0xFA, 0x00, 0x00, 0xFA, 0x00, 0x00, 0xFA, 0x00, 0x00,
66
67 // footer
68 0x74, 0xFA, 0x8D, 0x81,
69 },
70 .checksum = 0xAB,
71};
72// clang-format on
73
75{
76 EIA608ToSMPTE436MContext *priv = ctx->priv_data;
77
78 priv->wrapping_type = priv->wrapping_type_opt;
79 priv->sample_coding = priv->sample_coding_opt;
80
81 // validate we can handle the selected wrapping type and sample coding
82
83 AVSmpte436mCodedAnc coded_anc;
84
86 &coded_anc, priv->line_number, priv->wrapping_type, priv->sample_coding, &test_anc, ctx);
87 if (ret < 0)
88 return ret;
89
90 ctx->par_out->codec_type = AVMEDIA_TYPE_DATA;
91 ctx->par_out->codec_id = AV_CODEC_ID_SMPTE_436M_ANC;
92
93 static const struct {
94 AVRational frame_rate;
95 uint8_t cdp_frame_rate;
96 } known_frame_rates[] = {
97 { .frame_rate = { .num = 24000, .den = 1001 }, .cdp_frame_rate = 0x1F },
98 { .frame_rate = { .num = 24, .den = 1 }, .cdp_frame_rate = 0x2F },
99 { .frame_rate = { .num = 25, .den = 1 }, .cdp_frame_rate = 0x3F },
100 { .frame_rate = { .num = 30000, .den = 1001 }, .cdp_frame_rate = 0x4F },
101 { .frame_rate = { .num = 30, .den = 1 }, .cdp_frame_rate = 0x5F },
102 { .frame_rate = { .num = 50, .den = 1 }, .cdp_frame_rate = 0x6F },
103 { .frame_rate = { .num = 60000, .den = 1001 }, .cdp_frame_rate = 0x7F },
104 { .frame_rate = { .num = 60, .den = 1 }, .cdp_frame_rate = 0x8F },
105 };
106
107 priv->cdp_frame_rate_byte = 0;
108
109 for (int i = 0; i < FF_ARRAY_ELEMS(known_frame_rates); i++) {
110 if (known_frame_rates[i].frame_rate.num == priv->cdp_frame_rate.num && known_frame_rates[i].frame_rate.den == priv->cdp_frame_rate.den) {
111 priv->cdp_frame_rate_byte = known_frame_rates[i].cdp_frame_rate;
112 break;
113 }
114 }
115
116 if (priv->cdp_frame_rate_byte == 0) {
117 av_log(ctx,
119 "cdp_frame_rate not supported: %d/%d\n",
120 priv->cdp_frame_rate.num,
121 priv->cdp_frame_rate.den);
122 return AVERROR(EINVAL);
123 }
124
125 return 0;
126}
127
129{
130 EIA608ToSMPTE436MContext *priv = ctx->priv_data;
131 AVPacket *in;
132
133 int ret = ff_bsf_get_packet(ctx, &in);
134 if (ret < 0)
135 return ret;
136
138 anc.did = 0x61;
139 anc.sdid_or_dbn = 0x1;
140
141 uint8_t *p = anc.payload;
142
143 *p++ = 0x96; // cdp_identifier -- always 0x9669
144 *p++ = 0x69;
145
146 uint8_t *cdp_length_p = p++;
147
148 *p++ = priv->cdp_frame_rate_byte;
149
150 const uint8_t FLAG_CC_DATA_PRESENT = 0x40;
151 const uint8_t FLAG_CAPTION_SERVICE_ACTIVE = 0x2;
152 const uint8_t FLAG_RESERVED = 0x1; // must always be set
153
154 *p++ = FLAG_CC_DATA_PRESENT | FLAG_CAPTION_SERVICE_ACTIVE | FLAG_RESERVED;
155
156 AV_WB16(p, priv->cdp_sequence_cntr);
157 p += 2;
158
159 const uint8_t CC_DATA_SECTION_ID = 0x72;
160
161 *p++ = CC_DATA_SECTION_ID;
162
163 uint8_t *cc_count_p = p++;
164
165 const uint8_t CC_COUNT_MASK = 0x1F;
166 const int CDP_FOOTER_SIZE = 4;
167
168 int cc_count = in->size / 3;
169 int space_left = AV_SMPTE_291M_ANC_PAYLOAD_CAPACITY - (p - anc.payload);
170 int cc_data_space_left = space_left - CDP_FOOTER_SIZE;
171 int max_cc_count = FFMAX(cc_data_space_left / 3, CC_COUNT_MASK);
172
173 if (cc_count > max_cc_count) {
174 av_log(ctx,
176 "cc_count (%d) is bigger than the maximum supported (%d), truncating captions packet\n",
177 cc_count,
178 max_cc_count);
179 cc_count = max_cc_count;
180 }
181
182 *cc_count_p = cc_count | ~CC_COUNT_MASK; // other bits are reserved and set to ones
183
184 for (size_t i = 0; i < cc_count; i++) {
185 size_t start = i * 3;
186 *p++ = in->data[start] | 0xF8; // fill reserved bits with ones
187 *p++ = in->data[start + 1];
188 *p++ = in->data[start + 2];
189 }
190
191 const uint8_t CDP_FOOTER_ID = 0x74;
192
193 *p++ = CDP_FOOTER_ID;
194
195 AV_WB16(p, priv->cdp_sequence_cntr);
196 p += 2;
197
198 uint8_t *packet_checksum_p = p;
199 *p++ = 0;
200
201 anc.data_count = p - anc.payload;
202 *cdp_length_p = anc.data_count;
203
204 int sum = 0;
205 for (int i = 0; i < anc.data_count; i++) {
206 sum += anc.payload[i];
207 }
208 // set to an 8-bit value such that the sum of the bytes of the whole CDP mod 2^8 is 0
209 *packet_checksum_p = -sum;
210
211 priv->cdp_sequence_cntr++;
212 // cdp_sequence_cntr wraps around at 16-bits
213 priv->cdp_sequence_cntr &= 0xFFFFU;
214
216
217 AVSmpte436mCodedAnc coded_anc;
219 &coded_anc, priv->line_number, (AVSmpte436mWrappingType)priv->wrapping_type, priv->sample_coding, &anc, ctx);
220 if (ret < 0)
221 goto fail;
222
223 ret = av_smpte_436m_anc_encode(NULL, 0, 1, &coded_anc);
224 if (ret < 0)
225 goto fail;
226
227 ret = av_new_packet(out, ret);
228 if (ret < 0)
229 goto fail;
230
231 ret = av_packet_copy_props(out, in);
232 if (ret < 0)
233 goto fail;
234
235 ret = av_smpte_436m_anc_encode(out->data, out->size, 1, &coded_anc);
236 if (ret < 0)
237 goto fail;
238
239 ret = 0;
240
241fail:
242 if (ret < 0)
244 av_packet_free(&in);
245 return ret;
246}
247
248#define OFFSET(x) offsetof(EIA608ToSMPTE436MContext, x)
249#define FLAGS AV_OPT_FLAG_BSF_PARAM
250// clang-format off
251static const AVOption options[] = {
252 { "line_number", "line number -- you probably want 9 or 11", OFFSET(line_number), AV_OPT_TYPE_UINT, { .i64 = 9 }, 0, 0xFFFF, FLAGS },
253 { "wrapping_type", "wrapping type", OFFSET(wrapping_type_opt), AV_OPT_TYPE_UINT, { .i64 = AV_SMPTE_436M_WRAPPING_TYPE_VANC_FRAME }, 0, 0xFF, FLAGS, .unit = "wrapping_type" },
255 { "sample_coding", "payload sample coding", OFFSET(sample_coding_opt), AV_OPT_TYPE_UINT, { .i64 = AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA }, 0, 0xFF, FLAGS, .unit = "sample_coding" },
257 { "initial_cdp_sequence_cntr", "initial cdp_*_sequence_cntr value", OFFSET(cdp_sequence_cntr), AV_OPT_TYPE_UINT, { .i64 = 0 }, 0, 0xFFFF, FLAGS },
258 { "cdp_frame_rate", "set the `cdp_frame_rate` fields", OFFSET(cdp_frame_rate), AV_OPT_TYPE_VIDEO_RATE, { .str = "30000/1001" }, 0, INT_MAX, FLAGS },
259 { NULL },
260};
261// clang-format on
262
264 .class_name = "eia608_to_smpte436m bitstream filter",
265 .item_name = av_default_item_name,
266 .option = options,
267 .version = LIBAVUTIL_VERSION_INT,
268};
269
271 .p.name = "eia608_to_smpte436m",
272 .p.codec_ids = (const enum AVCodecID[]){ AV_CODEC_ID_EIA_608, AV_CODEC_ID_NONE },
273 .p.priv_class = &eia608_to_smpte436m_class,
274 .priv_data_size = sizeof(EIA608ToSMPTE436MContext),
277};
static FILE * out
static AVFormatContext * ctx
simple assert() macros that are a bit more flexible than ISO C assert().
Convenience header that includes libavutil's core.
const FFBitStreamFilter ff_eia608_to_smpte436m_bsf
int ff_bsf_get_packet(AVBSFContext *ctx, AVPacket **pkt)
Called by the bitstream filters to get the next packet for filtering.
Definition bsf.c:233
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define FLAGS
Definition cmdutils.c:598
#define NULL
Definition coverity.c:32
int(* init)(AVBSFContext *ctx)
Definition dts2pts.c:608
static const AVClass eia608_to_smpte436m_class
static int ff_eia608_to_smpte436m_filter(AVBSFContext *ctx, AVPacket *out)
static av_cold int ff_eia608_to_smpte436m_init(AVBSFContext *ctx)
#define OFFSET(x)
static const AVSmpte291mAnc8bit test_anc
error code definitions
#define fail
Definition test.h:479
@ AV_OPT_TYPE_VIDEO_RATE
Underlying C type is AVRational.
Definition opt.h:314
@ AV_OPT_TYPE_UINT
Underlying C type is unsigned int.
Definition opt.h:334
AVCodecID
Identify the syntax and semantics of the bitstream.
Definition codec_id.h:47
@ AV_CODEC_ID_NONE
Definition codec_id.h:48
@ AV_CODEC_ID_EIA_608
Definition codec_id.h:576
@ AV_CODEC_ID_SMPTE_436M_ANC
Definition codec_id.h:610
void av_packet_free(AVPacket **pkt)
Free the packet, if the packet is reference counted, it will be unreferenced first.
Definition packet.c:74
void av_packet_unref(AVPacket *pkt)
Wipe the packet.
Definition packet.c:434
int av_packet_copy_props(AVPacket *dst, const AVPacket *src)
Copy only "properties" fields from src to dst.
Definition packet.c:397
int av_new_packet(AVPacket *pkt, int size)
Allocate the payload of a packet and initialize its fields with default values.
Definition packet.c:98
#define AVERROR(e)
Definition error.h:45
#define AV_LOG_FATAL
Something went wrong and recovery is not possible.
Definition log.h:204
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
const char * av_default_item_name(void *ptr)
Return the context name.
Definition log.c:241
@ AVMEDIA_TYPE_DATA
Opaque data information usually continuous.
Definition avutil.h:202
#define LIBAVUTIL_VERSION_INT
Definition version.h:85
#define AV_WB16(p, v)
#define av_cold
Definition attributes.h:117
Utility Preprocessor macros.
#define FFMAX(a, b)
Definition macros.h:47
@ FLAG_RESERVED
Definition nut.h:50
AVOptions.
Utilities for rational number calculation.
#define FF_ARRAY_ELEMS(a)
int av_smpte_291m_anc_8bit_encode(AVSmpte436mCodedAnc *out, uint16_t line_number, AVSmpte436mWrappingType wrapping_type, AVSmpte436mPayloadSampleCoding sample_coding, const AVSmpte291mAnc8bit *payload, void *log_ctx)
Encode a AVSmpte291mAnc8bit into a AVSmpte436mCodedAnc.
Definition smpte_436m.c:375
int av_smpte_436m_anc_encode(uint8_t *out, int size, int anc_packet_count, const AVSmpte436mCodedAnc *anc_packets)
Encode ANC packets into a single AV_CODEC_ID_SMPTE_436M_ANC AVPacket's data.
Definition smpte_436m.c:173
void av_smpte_291m_anc_8bit_fill_checksum(AVSmpte291mAnc8bit *anc)
Fill in the correct checksum for a AVSmpte291mAnc8bit.
Definition smpte_436m.c:337
AVSmpte436mPayloadSampleCoding
Payload Sample Coding from Table 4 (page 10) and Table 7 (page 13) of: https://pub....
Definition smpte_436m.h:59
@ AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA
used for VBI and ANC
Definition smpte_436m.h:67
#define AV_SMPTE_291M_ANC_PAYLOAD_CAPACITY
the payload capacity of AVSmpte291mAnc8bit (and of AVSmpte291mAnc10bit when that gets added)
Definition smpte_436m.h:89
AVSmpte436mWrappingType
Wrapping Type from Table 7 (page 13) of: https://pub.smpte.org/latest/st436/s436m-2006....
Definition smpte_436m.h:41
@ AV_SMPTE_436M_WRAPPING_TYPE_VANC_FRAME
Definition smpte_436m.h:42
#define FF_SMPTE_436M_PAYLOAD_SAMPLE_CODING_ANC_AVOPTIONS(flags, unit_name)
#define FF_SMPTE_436M_WRAPPING_TYPE_VANC_AVOPTIONS(flags, unit_name)
The bitstream filter state.
Definition bsf.h:68
Describe the class of an AVClass context structure.
Definition log.h:76
AVOption.
Definition opt.h:428
This structure stores compressed data.
Definition packet.h:580
int size
Definition packet.h:604
uint8_t * data
Definition packet.h:603
Rational number (pair of numerator and denominator).
Definition rational.h:58
int num
Numerator.
Definition rational.h:59
int den
Denominator.
Definition rational.h:60
An ANC packet with an 8-bit payload.
Definition smpte_436m.h:98
uint8_t payload[AV_SMPTE_291M_ANC_PAYLOAD_CAPACITY]
Definition smpte_436m.h:102
An encoded ANC packet within a single AV_CODEC_ID_SMPTE_436M_ANC AVPacket's data.
Definition smpte_436m.h:117
AVSmpte436mPayloadSampleCoding sample_coding
AVSmpte436mWrappingType wrapping_type
#define av_log(a,...)
void(* filter)(uint8_t *src, ptrdiff_t stride, int qscale)
Definition h263dsp.c:29