Coverage Report

Created: 2026-11-12 07:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-smpte-291-vanc.c
Line
Count
Source
1
/* packet-smpte-291-vanc.c
2
 * SMPTE ST 291 ancillary-data parsing and built-in VANC application dissectors.
3
 *
4
 * Built-in application payloads implemented in this source file:
5
 *   SMPTE ST 12-2, SMPTE ST 2010, SMPTE ST 2016-3, SMPTE ST 2031,
6
 *   SMPTE ST 334-2, and Free TV Australia OP-47 / SMPTE RDD 8.
7
 *
8
 * Copyright (c) 2026, Devin Heitmueller <dheitmueller@ltnglobal.com>
9
 *
10
 * Wireshark - Network traffic analyzer
11
 * By Gerald Combs <gerald@wireshark.org>
12
 * Copyright 1998 Gerald Combs
13
 *
14
 * SPDX-License-Identifier: GPL-2.0-or-later
15
 */
16
17
#include "config.h"
18
19
#include <string.h>
20
21
#include <epan/expert.h>
22
#include <epan/packet.h>
23
#include <epan/reassemble.h>
24
#include <epan/tfs.h>
25
#include <wsutil/array.h>
26
#include <wsutil/bitswap.h>
27
28
#include "packet-smpte-291-vanc.h"
29
30
/* Protocol, field, subtree, expert, and dissector declarations */
31
32
/* SMPTE ST 291 common declarations */
33
static int proto_st291;
34
static int hf_st291_did;
35
static int hf_st291_sdid;
36
static int hf_st291_dbn;
37
static dissector_table_t st291_did_sdid_table;
38
39
typedef struct {
40
    tvbuff_t *full_tvb;
41
    tvbuff_t *byte_tvb;
42
} st291_vanc_udw_t;
43
44
/* SMPTE ST 12-2 declarations */
45
static int proto_st12_2;
46
static int hf_st12_2_timecode;
47
static int hf_st12_2_frame_units;
48
static int hf_st12_2_frame_tens;
49
static int hf_st12_2_second_units;
50
static int hf_st12_2_second_tens;
51
static int hf_st12_2_minute_units;
52
static int hf_st12_2_minute_tens;
53
static int hf_st12_2_hour_units;
54
static int hf_st12_2_hour_tens;
55
static int hf_st12_2_binary_group_1;
56
static int hf_st12_2_binary_group_2;
57
static int hf_st12_2_binary_group_3;
58
static int hf_st12_2_binary_group_4;
59
static int hf_st12_2_binary_group_5;
60
static int hf_st12_2_binary_group_6;
61
static int hf_st12_2_binary_group_7;
62
static int hf_st12_2_binary_group_8;
63
static int hf_st12_2_flag_bit_10;
64
static int hf_st12_2_flag_bit_11;
65
static int hf_st12_2_flag_bit_27;
66
static int hf_st12_2_flag_bit_43;
67
static int hf_st12_2_flag_bit_58;
68
static int hf_st12_2_flag_bit_59;
69
static int hf_st12_2_payload_type;
70
static int hf_st12_2_vitc;
71
static int hf_st12_2_vitc_line_sel;
72
static int hf_st12_2_vitc_line_dup;
73
static int hf_st12_2_vitc_validity;
74
static int hf_st12_2_vitc_process;
75
static int ett_st12_2;
76
static int ett_st12_2_timecode;
77
static int ett_st12_2_vitc;
78
static expert_field ei_st12_2_bad_length = EI_INIT;
79
static dissector_handle_t st12_2_handle;
80
81
/* SMPTE ST 2010 declarations */
82
static int proto_st2010;
83
static int hf_st2010_payload_descriptor;
84
static int hf_st2010_reserved;
85
static int hf_st2010_version;
86
static int hf_st2010_continued_pkt;
87
static int hf_st2010_following_pkt;
88
static int hf_st2010_duplicate_msg;
89
static int hf_st2010_payload;
90
static int hf_st2010_fragments;
91
static int hf_st2010_fragment;
92
static int hf_st2010_fragment_overlap;
93
static int hf_st2010_fragment_overlap_conflict;
94
static int hf_st2010_fragment_multiple_tails;
95
static int hf_st2010_fragment_too_long_fragment;
96
static int hf_st2010_fragment_error;
97
static int hf_st2010_fragment_count;
98
static int hf_st2010_reassembled_in;
99
static int hf_st2010_reassembled_length;
100
static int hf_st2010_reassembled_data;
101
static int ett_st2010;
102
static int ett_st2010_fragment;
103
static int ett_st2010_fragments;
104
static expert_field ei_st2010_bad_version = EI_INIT;
105
static expert_field ei_st2010_reserved_bits = EI_INIT;
106
static expert_field ei_st2010_orphan_fragment = EI_INIT;
107
static expert_field ei_st2010_overlapping_message = EI_INIT;
108
static expert_field ei_st2010_empty_payload = EI_INIT;
109
static dissector_handle_t st2010_handle;
110
static dissector_table_t st2010_payload_table;
111
static reassembly_table st2010_reassembly_table;
112
113
/* SMPTE ST 2016-3 declarations */
114
static int proto_st2016_3;
115
static int hf_st2016_3_afd_byte;
116
static int hf_st2016_3_afd_code;
117
static int hf_st2016_3_afd_ar;
118
static int hf_st2016_3_afd_reserved;
119
static int hf_st2016_3_reserved_1;
120
static int hf_st2016_3_reserved_2;
121
static int hf_st2016_3_bar_flags;
122
static int hf_st2016_3_bar_top;
123
static int hf_st2016_3_bar_bottom;
124
static int hf_st2016_3_bar_left;
125
static int hf_st2016_3_bar_right;
126
static int hf_st2016_3_bar_reserved;
127
static int hf_st2016_3_bar_value_1;
128
static int hf_st2016_3_bar_value_1_marker;
129
static int hf_st2016_3_bar_value_1_data;
130
static int hf_st2016_3_bar_value_2;
131
static int hf_st2016_3_bar_value_2_marker;
132
static int hf_st2016_3_bar_value_2_data;
133
static int hf_st2016_3_bar_value_1_meaning;
134
static int hf_st2016_3_bar_value_2_meaning;
135
static int ett_st2016_3;
136
static int ett_st2016_3_afd;
137
static int ett_st2016_3_bar_flags;
138
static int ett_st2016_3_bar_value_1;
139
static int ett_st2016_3_bar_value_2;
140
static expert_field ei_st2016_3_bad_length;
141
static expert_field ei_st2016_3_afd_reserved;
142
static expert_field ei_st2016_3_reserved_udw;
143
static expert_field ei_st2016_3_bar_reserved;
144
static expert_field ei_st2016_3_bar_flags_invalid;
145
static expert_field ei_st2016_3_bar_marker;
146
static dissector_handle_t st2016_3_handle;
147
148
/* SMPTE ST 334-2 declarations */
149
static int proto_st334_2;
150
static int hf_st334_2_cdp_identifier;
151
static int hf_st334_2_cdp_length;
152
static int hf_st334_2_frame_rate;
153
static int hf_st334_2_header_reserved;
154
static int hf_st334_2_time_code_present;
155
static int hf_st334_2_ccdata_present;
156
static int hf_st334_2_svcinfo_present;
157
static int hf_st334_2_svc_info_start;
158
static int hf_st334_2_svc_info_change;
159
static int hf_st334_2_svc_info_complete;
160
static int hf_st334_2_caption_service_active;
161
static int hf_st334_2_header_reserved_bit;
162
static int hf_st334_2_header_sequence_counter;
163
static int hf_st334_2_section_id;
164
static int hf_st334_2_timecode;
165
static int hf_st334_2_tc_field_flag;
166
static int hf_st334_2_drop_frame_flag;
167
static int hf_st334_2_cc_count;
168
static int hf_st334_2_cc_marker_bits;
169
static int hf_st334_2_cc_valid;
170
static int hf_st334_2_cc_type;
171
static int hf_st334_2_cc_data_1;
172
static int hf_st334_2_cc_data_2;
173
static int hf_st334_2_dtvcc_data;
174
static int hf_st334_2_svc_reserved;
175
static int hf_st334_2_svc_info_start_section;
176
static int hf_st334_2_svc_info_change_section;
177
static int hf_st334_2_svc_info_complete_section;
178
static int hf_st334_2_svc_count;
179
static int hf_st334_2_csn_reserved;
180
static int hf_st334_2_csn_size;
181
static int hf_st334_2_csn_reserved_2;
182
static int hf_st334_2_caption_service_number;
183
static int hf_st334_2_service_data;
184
static int hf_st334_2_service_language;
185
static int hf_st334_2_service_digital_cc;
186
static int hf_st334_2_service_digital_reserved;
187
static int hf_st334_2_service_line21_reserved;
188
static int hf_st334_2_service_line21_field;
189
static int hf_st334_2_service_descriptor_number;
190
static int hf_st334_2_service_easy_reader;
191
static int hf_st334_2_service_wide_aspect_ratio;
192
static int hf_st334_2_service_reserved_14;
193
static int hf_st334_2_future_length;
194
static int hf_st334_2_future_data;
195
static int hf_st334_2_footer_sequence_counter;
196
static int hf_st334_2_packet_checksum;
197
static int hf_st334_2_checksum_calculated;
198
static int ett_st334_2;
199
static int ett_st334_2_header;
200
static int ett_st334_2_timecode;
201
static int ett_st334_2_ccdata;
202
static int ett_st334_2_cc_construct;
203
static int ett_st334_2_svcinfo;
204
static int ett_st334_2_service;
205
static int ett_st334_2_service_data;
206
static int ett_st334_2_future;
207
static int ett_st334_2_footer;
208
static expert_field ei_st334_2_bad_identifier;
209
static expert_field ei_st334_2_bad_length;
210
static expert_field ei_st334_2_bad_reserved;
211
static expert_field ei_st334_2_bad_section_order;
212
static expert_field ei_st334_2_duplicate_section;
213
static expert_field ei_st334_2_missing_section;
214
static expert_field ei_st334_2_cc_count;
215
static expert_field ei_st334_2_bad_marker;
216
static expert_field ei_st334_2_sequence_mismatch;
217
static expert_field ei_st334_2_bad_checksum;
218
static expert_field ei_st334_2_truncated;
219
static dissector_handle_t st334_2_handle;
220
221
/* SMPTE ST 2031 declarations */
222
static int proto_st2031;
223
static int hf_st2031_data_identifier;
224
static int hf_st2031_data_unit_id;
225
static int hf_st2031_data_unit_length;
226
static int hf_st2031_field_parity;
227
static int hf_st2031_line_offset;
228
static int hf_st2031_framing_code;
229
static int hf_st2031_magazine_hamming;
230
static int hf_st2031_magazine;
231
static int hf_st2031_packet_number_hamming;
232
static int hf_st2031_packet_number;
233
static int hf_st2031_page_units_hamming;
234
static int hf_st2031_page_units;
235
static int hf_st2031_page_tens_hamming;
236
static int hf_st2031_page_tens;
237
static int hf_st2031_data_string;
238
static int hf_st2031_textdata_array;
239
static int hf_st2031_erase_page;
240
static int hf_st2031_newsflash;
241
static int hf_st2031_subtitle;
242
static int hf_st2031_suppress_header;
243
static int hf_st2031_update_indicator;
244
static int hf_st2031_interrupted_sequence;
245
static int hf_st2031_inhibit_display;
246
static int hf_st2031_magazine_serial;
247
static int hf_st2031_character_set;
248
static int hf_st2031_tt_control;
249
static int ett_st2031;
250
static dissector_handle_t st2031_handle;
251
252
/* OP-47 / SMPTE RDD 8 declarations */
253
static int proto_op47;
254
static int hf_op47_sdp_identifier;
255
static int hf_op47_sdp_length;
256
static int hf_op47_sdp_format_code;
257
static int hf_op47_sdp_adaption_header;
258
static int hf_op47_sdp_pkt_desc_b;
259
static int hf_op47_clock_runin;
260
static int hf_op47_framing_code;
261
static int hf_op47_magazine_hamming;
262
static int hf_op47_magazine;
263
static int hf_op47_packet_number_hamming;
264
static int hf_op47_packet_number;
265
static int hf_op47_page_units_hamming;
266
static int hf_op47_page_units;
267
static int hf_op47_page_tens_hamming;
268
static int hf_op47_page_tens;
269
static int hf_op47_data_string;
270
static int hf_op47_textdata_array;
271
static int hf_op47_erase_page;
272
static int hf_op47_newsflash;
273
static int hf_op47_subtitle;
274
static int hf_op47_suppress_header;
275
static int hf_op47_update_indicator;
276
static int hf_op47_interrupted_sequence;
277
static int hf_op47_inhibit_display;
278
static int hf_op47_magazine_serial;
279
static int hf_op47_character_set;
280
static int hf_op47_tt_control;
281
static int ett_op47;
282
static int ett_op47_wst;
283
static dissector_handle_t op47_handle;
284
285
/* ST 291 Type 2 DID/SDID keys used by the built-in VANC dissectors. */
286
16
#define ST12_2_DID_SDID_KEY   0x6060
287
16
#define ST2010_DID_SDID_KEY   0x4107
288
16
#define ST2016_3_DID_SDID_KEY 0x4105
289
16
#define ST334_2_DID_SDID_KEY  0x6101
290
0
#define ST334_2_CDP_IDENTIFIER 0x9669
291
16
#define ST2031_DID_SDID_KEY   0x4108
292
16
#define OP47_DID_SDID_KEY     0x4302
293
294
0
#define ST2010_PAYLOAD_SCTE104 0
295
/*
296
 * SMPTE ST 291-1 ancillary-data core and DID/SDID dispatch
297
 */
298
299
300
/*
301
 * Registered SMPTE ST 291 DID/SDID assignments.
302
 *
303
 * SMPTE ST 291-1:2011, Sec. 4 assigns DID values through the SMPTE
304
 * Registration Authority; Sec. 5.1 defines Type 1 versus Type 2 packets.
305
 *
306
 * Source: SMPTE Registration Authority, "Data Identification Word
307
 * Assignments for Registered DIDs", downloaded from:
308
 * https://www.smpte-ra.org/smpte-ancillary-data-smpte-st-291
309
 *
310
 * The register contained 81 assignments when reviewed on 2026-09-05.
311
 * Keep this table synchronized with the SMPTE RA register rather than with
312
 * transport-specific dissectors such as ST 2110-40 or ST 2038.
313
 */
314
typedef struct {
315
    uint8_t did;
316
    uint8_t sdid;
317
    const char *description;
318
} st291_did_sdid_entry_t;
319
320
typedef struct {
321
    uint8_t did;
322
    const char *description;
323
} st291_did_entry_t;
324
325
/* Type 2 identities: SMPTE ST 291-1:2011, Sec. 5.1 uses DID + SDID. */
326
static const st291_did_sdid_entry_t st291_did_sdid_assignments[] = {
327
    { 0x08, 0x08, "SMPTE ST 353: MPEG recoding data, VANC space" },
328
    { 0x08, 0x0c, "SMPTE ST 353: MPEG recoding data, HANC space" },
329
    { 0x40, 0x01, "SMPTE ST 305: SDTI transport in active frame space" },
330
    { 0x40, 0x02, "SMPTE ST 348: HD-SDTI transport in active frame space" },
331
    { 0x40, 0x04, "SMPTE ST 427: Link Encryption Message 1" },
332
    { 0x40, 0x05, "SMPTE ST 427: Link Encryption Message 2" },
333
    { 0x40, 0x06, "SMPTE ST 427: Link Encryption Metadata" },
334
    { 0x41, 0x01, "SMPTE ST 352: Payload Identification, HANC space" },
335
    { 0x41, 0x05, "SMPTE ST 2016-3: AFD and Bar Data" },
336
    { 0x41, 0x06, "SMPTE ST 2016-4: Pan-Scan Data" },
337
    { 0x41, 0x07, "SMPTE ST 2010: ANSI/SCTE 104 messages" },
338
    { 0x41, 0x08, "SMPTE ST 2031: DVB/SCTE VBI data" },
339
    { 0x41, 0x09, "SMPTE ST 2056: MPEG TS packets in VANC" },
340
    { 0x41, 0x0a, "SMPTE ST 2068: Stereoscopic 3D Frame Compatible Packing and Signaling" },
341
    { 0x41, 0x0b, "SMPTE ST 2064-2: Lip Sync data as specified by ST 2064-1" },
342
    { 0x41, 0x0c, "SMPTE ST 2108-1: Extended HDR/WCG for SDI" },
343
    { 0x41, 0x0d, "SMPTE ST 2108-2: Vertical Ancillary Data Mapping of KLV Formatted HDR/WCG Metadata" },
344
    { 0x43, 0x01, "ITU-R BT.1685: Structure of inter-station control data conveyed by ancillary data packets" },
345
    { 0x43, 0x02, "SMPTE RDD 8: Subtitling Distribution packet (SDP)" },
346
    { 0x43, 0x03, "SMPTE RDD 8: Transport of ANC packet in an ANC Multipacket" },
347
    { 0x43, 0x04, "ARIB TR-B29: Metadata to monitor errors of audio and video signals on a broadcasting chain" },
348
    { 0x43, 0x05, "SMPTE RDD 18: Acquisition Metadata Sets for Video Camera Parameters" },
349
    { 0x44, 0x04, "SMPTE RP 214: KLV Metadata transport in VANC space" },
350
    { 0x44, 0x14, "SMPTE RP 214: KLV Metadata transport in HANC space" },
351
    { 0x44, 0x44, "SMPTE RP 223: Packing UMID and Program Identification Label Data into ST 291 ancillary data packets" },
352
    { 0x45, 0x01, "SMPTE ST 2020-1: Compressed Audio Metadata" },
353
    { 0x45, 0x02, "SMPTE ST 2020-1: Compressed Audio Metadata" },
354
    { 0x45, 0x03, "SMPTE ST 2020-1: Compressed Audio Metadata" },
355
    { 0x45, 0x04, "SMPTE ST 2020-1: Compressed Audio Metadata" },
356
    { 0x45, 0x05, "SMPTE ST 2020-1: Compressed Audio Metadata" },
357
    { 0x45, 0x06, "SMPTE ST 2020-1: Compressed Audio Metadata" },
358
    { 0x45, 0x07, "SMPTE ST 2020-1: Compressed Audio Metadata" },
359
    { 0x45, 0x08, "SMPTE ST 2020-1: Compressed Audio Metadata" },
360
    { 0x45, 0x09, "SMPTE ST 2020-1: Compressed Audio Metadata" },
361
    { 0x46, 0x01, "SMPTE ST 2051: Two Frame Marker in HANC" },
362
    { 0x50, 0x01, "SMPTE RDD 8: WSS data" },
363
    { 0x51, 0x01, "SMPTE RP 215: Film Codes in VANC space" },
364
    { 0x60, 0x60, "SMPTE ST 12-2: Ancillary Time Code" },
365
    { 0x60, 0x61, "SMPTE ST 12-3: Time Code for High Frame Rate Signals" },
366
    { 0x60, 0x62, "SMPTE ST 2103: Generic Time Label" },
367
    { 0x61, 0x01, "SMPTE ST 334-1: EIA 708B Data mapping into VANC space" },
368
    { 0x61, 0x02, "SMPTE ST 334-1: EIA 608 Data mapping into VANC space" },
369
    { 0x62, 0x01, "SMPTE RP 207: Program Description in VANC space" },
370
    { 0x62, 0x02, "SMPTE ST 334-1: Data broadcast (DTV) in VANC space" },
371
    { 0x62, 0x03, "SMPTE RP 208: VBI Data in VANC space" },
372
    { 0x64, 0x64, "SMPTE RP 196 (withdrawn): Time Code in HANC space" },
373
    { 0x64, 0x7f, "SMPTE RP 196 (withdrawn): VITC in HANC space" },
374
};
375
376
/* Type 1 identities: SMPTE ST 291-1:2011, Sec. 5.1 uses DID + DBN. */
377
static const st291_did_entry_t st291_did_assignments[] = {
378
    { 0x00, "SMPTE ST 291: Undefined data deleted (deprecated)" },
379
    { 0x80, "SMPTE ST 291: Packet marked for deletion" },
380
    { 0x84, "SMPTE ST 291: End packet deleted (deprecated)" },
381
    { 0x88, "SMPTE ST 291: Start packet deleted (deprecated)" },
382
    { 0xa0, "SMPTE ST 299-2: Audio data in HANC space (3G), Group 8 Control packet" },
383
    { 0xa1, "SMPTE ST 299-2: Audio data in HANC space (3G), Group 7 Control packet" },
384
    { 0xa2, "SMPTE ST 299-2: Audio data in HANC space (3G), Group 6 Control packet" },
385
    { 0xa3, "SMPTE ST 299-2: Audio data in HANC space (3G), Group 5 Control packet" },
386
    { 0xa4, "SMPTE ST 299-2: Audio data in HANC space (3G), Group 8" },
387
    { 0xa5, "SMPTE ST 299-2: Audio data in HANC space (3G), Group 7" },
388
    { 0xa6, "SMPTE ST 299-2: Audio data in HANC space (3G), Group 6" },
389
    { 0xa7, "SMPTE ST 299-2: Audio data in HANC space (3G), Group 5" },
390
    { 0xe0, "SMPTE ST 299-1: Audio data in HANC space (HDTV)" },
391
    { 0xe1, "SMPTE ST 299-1: Audio data in HANC space (HDTV)" },
392
    { 0xe2, "SMPTE ST 299-1: Audio data in HANC space (HDTV)" },
393
    { 0xe3, "SMPTE ST 299-1: Audio data in HANC space (HDTV)" },
394
    { 0xe4, "SMPTE ST 299-1: Audio data in HANC space (HDTV)" },
395
    { 0xe5, "SMPTE ST 299-1: Audio data in HANC space (HDTV)" },
396
    { 0xe6, "SMPTE ST 299-1: Audio data in HANC space (HDTV)" },
397
    { 0xe7, "SMPTE ST 299-1: Audio data in HANC space (HDTV)" },
398
    { 0xec, "SMPTE ST 272: Audio data in HANC space (SDTV)" },
399
    { 0xed, "SMPTE ST 272: Audio data in HANC space (SDTV)" },
400
    { 0xee, "SMPTE ST 272: Audio data in HANC space (SDTV)" },
401
    { 0xef, "SMPTE ST 272: Audio data in HANC space (SDTV)" },
402
    { 0xf0, "SMPTE ST 315: Camera position (HANC or VANC space)" },
403
    { 0xf4, "SMPTE RP 165: Error Detection and Handling (HANC space)" },
404
    { 0xf8, "SMPTE ST 272: Audio data in HANC space (SDTV)" },
405
    { 0xf9, "SMPTE ST 272: Audio data in HANC space (SDTV)" },
406
    { 0xfa, "SMPTE ST 272: Audio data in HANC space (SDTV)" },
407
    { 0xfb, "SMPTE ST 272: Audio data in HANC space (SDTV)" },
408
    { 0xfc, "SMPTE ST 272: Audio data in HANC space (SDTV)" },
409
    { 0xfd, "SMPTE ST 272: Audio data in HANC space (SDTV)" },
410
    { 0xfe, "SMPTE ST 272: Audio data in HANC space (SDTV)" },
411
    { 0xff, "SMPTE ST 272: Audio data in HANC space (SDTV)" },
412
};
413
414
static const char *
415
st291_lookup_did(uint8_t did)
416
0
{
417
0
    unsigned i;
418
419
0
    for (i = 0; i < array_length(st291_did_assignments); i++) {
420
0
        if (st291_did_assignments[i].did == did)
421
0
            return st291_did_assignments[i].description;
422
0
    }
423
0
    return NULL;
424
0
}
425
426
static const char *
427
st291_lookup_did_sdid(uint8_t did, uint8_t sdid)
428
0
{
429
0
    unsigned i;
430
431
0
    for (i = 0; i < array_length(st291_did_sdid_assignments); i++) {
432
0
        if (st291_did_sdid_assignments[i].did == did &&
433
0
            st291_did_sdid_assignments[i].sdid == sdid)
434
0
            return st291_did_sdid_assignments[i].description;
435
0
    }
436
0
    return NULL;
437
0
}
438
439
static bool
440
st291_id_word_parity_ok(uint16_t word)
441
0
{
442
0
    unsigned ones = 0;
443
0
    unsigned bit;
444
0
    uint8_t data = word & 0x00ff;
445
0
    unsigned b8 = (word >> 8) & 1U;
446
0
    unsigned b9 = (word >> 9) & 1U;
447
448
0
    for (bit = 0; bit < 8; bit++)
449
0
        ones += (data >> bit) & 1U;
450
451
0
    return (((ones + b8) & 1U) == 0) && (b9 == (b8 ^ 1U));
452
0
}
453
454
bool
455
st291_vanc_packet_from_words(tvbuff_t *parent_tvb, packet_info *pinfo,
456
                             const uint16_t *words, unsigned word_count,
457
                             st291_vanc_packet_t *packet)
458
0
{
459
0
    uint16_t *normalized_words;
460
0
    uint8_t *packed_data;
461
0
    unsigned expected_words;
462
0
    unsigned packed_length;
463
0
    unsigned i;
464
465
0
    DISSECTOR_ASSERT(parent_tvb != NULL);
466
0
    DISSECTOR_ASSERT(pinfo != NULL);
467
0
    DISSECTOR_ASSERT(words != NULL || word_count == 0);
468
0
    DISSECTOR_ASSERT(packet != NULL);
469
470
0
    memset(packet, 0, sizeof(*packet));
471
0
    if (word_count < 4)
472
0
        return false;
473
474
0
    expected_words = 4U + (words[2] & 0x00ff);
475
0
    if (word_count < expected_words)
476
0
        return false;
477
478
0
    normalized_words = wmem_alloc_array(pinfo->pool, uint16_t, expected_words);
479
0
    for (i = 0; i < expected_words; i++)
480
0
        normalized_words[i] = words[i] & 0x03ff;
481
482
0
    packet->parent_tvb = parent_tvb;
483
0
    packet->words = normalized_words;
484
0
    packet->word_count = expected_words;
485
0
    packet->did = normalized_words[0] & 0x00ff;
486
0
    packet->sdid_or_dbn = normalized_words[1] & 0x00ff;
487
0
    packet->data_count = normalized_words[2] & 0x00ff;
488
0
    packet->checksum = normalized_words[3 + packet->data_count];
489
0
    packet->did_parity_ok = st291_id_word_parity_ok(normalized_words[0]);
490
0
    packet->second_word_parity_ok = st291_id_word_parity_ok(normalized_words[1]);
491
0
    packet->data_count_parity_ok = st291_id_word_parity_ok(normalized_words[2]);
492
493
0
    packet->checksum_calculated = 0;
494
0
    for (i = 0; i < 3U + packet->data_count; i++) {
495
0
        packet->checksum_calculated =
496
0
            (packet->checksum_calculated + (normalized_words[i] & 0x01ff)) &
497
0
            0x01ff;
498
0
    }
499
0
    if ((packet->checksum_calculated & 0x0100) == 0)
500
0
        packet->checksum_calculated |= 0x0200;
501
0
    packet->checksum_ok = packet->checksum == packet->checksum_calculated;
502
503
    /* Word-oriented transports do not necessarily have a contiguous source
504
     * range (for example, one component of an interleaved SDI raster). Build
505
     * a canonical packed representation so the shared renderer can still
506
     * display the logical 10-bit UDW sequence. */
507
0
    if (packet->data_count != 0) {
508
0
        packed_length = (packet->data_count * 10 + 7) / 8;
509
0
        packed_data = wmem_alloc0(pinfo->pool, packed_length);
510
0
        for (i = 0; i < packet->data_count; i++) {
511
0
            uint16_t word = normalized_words[3 + i];
512
0
            unsigned bit;
513
514
0
            for (bit = 0; bit < 10; bit++) {
515
0
                if ((word & (1U << (9 - bit))) != 0) {
516
0
                    unsigned packed_bit = i * 10 + bit;
517
0
                    packed_data[packed_bit / 8] |= 1U << (7 - packed_bit % 8);
518
0
                }
519
0
            }
520
0
        }
521
0
        packet->packed_udw_tvb = tvb_new_child_real_data(parent_tvb,
522
0
                                                          packed_data,
523
0
                                                          packed_length,
524
0
                                                          packed_length);
525
0
    }
526
0
    return true;
527
0
}
528
529
bool
530
st291_vanc_packet_from_packed(tvbuff_t *tvb, packet_info *pinfo,
531
                              unsigned bit_offset, unsigned available_bits,
532
                              st291_vanc_packet_t *packet)
533
0
{
534
0
    uint16_t header_words[3];
535
0
    uint16_t *words;
536
0
    unsigned required_bits;
537
0
    unsigned udw_bit_offset;
538
0
    unsigned word_count;
539
0
    unsigned byte_offset;
540
0
    unsigned byte_length;
541
0
    unsigned i;
542
543
0
    DISSECTOR_ASSERT(tvb != NULL);
544
0
    DISSECTOR_ASSERT(pinfo != NULL);
545
0
    DISSECTOR_ASSERT(packet != NULL);
546
547
0
    memset(packet, 0, sizeof(*packet));
548
0
    if (available_bits < 30)
549
0
        return false;
550
551
0
    for (i = 0; i < array_length(header_words); i++)
552
0
        header_words[i] = tvb_get_bits16(tvb, bit_offset + i * 10, 10,
553
0
                                         ENC_BIG_ENDIAN);
554
555
0
    word_count = 4U + (header_words[2] & 0x00ff);
556
0
    required_bits = word_count * 10;
557
0
    if (required_bits > available_bits) {
558
        /* Preserve the decoded header so the transport can distinguish a
559
         * truncated ST 291 header from a complete header whose declared
560
         * packet extends beyond the transport boundary. */
561
0
        packet->did = header_words[0] & 0x00ff;
562
0
        packet->sdid_or_dbn = header_words[1] & 0x00ff;
563
0
        packet->data_count = header_words[2] & 0x00ff;
564
0
        packet->word_count = word_count;
565
0
        return false;
566
0
    }
567
568
0
    words = wmem_alloc_array(pinfo->pool, uint16_t, word_count);
569
0
    for (i = 0; i < word_count; i++)
570
0
        words[i] = tvb_get_bits16(tvb, bit_offset + i * 10, 10,
571
0
                                  ENC_BIG_ENDIAN);
572
573
0
    if (!st291_vanc_packet_from_words(tvb, pinfo, words, word_count, packet))
574
0
        return false;
575
576
0
    if (packet->data_count != 0) {
577
0
        udw_bit_offset = bit_offset + 30;
578
0
        byte_offset = (unsigned)(udw_bit_offset / 8);
579
0
        packet->packed_udw_bit_offset = (unsigned)(udw_bit_offset % 8);
580
0
        byte_length = (packet->packed_udw_bit_offset +
581
0
                       packet->data_count * 10 + 7) / 8;
582
0
        packet->packed_udw_tvb = tvb_new_subset_length(tvb, byte_offset,
583
0
                                                        byte_length);
584
0
    }
585
586
0
    return true;
587
0
}
588
589
/* Keep the canonical full-width and compatibility byte TVBs here so every
590
 * ST 291 transport presents the same subdissector interface. */
591
static void
592
st291_vanc_create_udw_tvbs(tvbuff_t *parent_tvb, packet_info *pinfo,
593
                           const uint16_t *udw_words, unsigned udw_count,
594
                           st291_vanc_udw_t *udw)
595
0
{
596
0
    uint8_t *full_data;
597
0
    uint8_t *payload_data;
598
0
    unsigned i;
599
600
0
    DISSECTOR_ASSERT(udw != NULL);
601
0
    DISSECTOR_ASSERT(udw_words != NULL || udw_count == 0);
602
603
0
    full_data = wmem_alloc(pinfo->pool, MAX(2U, udw_count * 2U));
604
0
    payload_data = wmem_alloc(pinfo->pool, MAX(1U, udw_count));
605
606
0
    for (i = 0; i < udw_count; i++) {
607
0
        uint16_t word = udw_words[i] & 0x03ff;
608
609
0
        full_data[i * 2] = (uint8_t)(word >> 8);
610
0
        full_data[i * 2 + 1] = (uint8_t)word;
611
0
        payload_data[i] = (uint8_t)word;
612
0
    }
613
614
0
    udw->full_tvb = tvb_new_child_real_data(parent_tvb, full_data,
615
0
                                             udw_count * 2, udw_count * 2);
616
0
    udw->byte_tvb = tvb_new_child_real_data(parent_tvb, payload_data,
617
0
                                             udw_count, udw_count);
618
0
}
619
620
bool
621
st291_vanc_dissect_packet(const st291_vanc_packet_t *packet,
622
                          packet_info *pinfo, proto_tree *tree,
623
                          proto_item *payload_item _U_,
624
                          const st291_vanc_dissector_data_t *data)
625
0
{
626
0
    st291_vanc_udw_t udw;
627
0
    st291_vanc_dissector_data_t subdissector_data;
628
0
    uint8_t dispatch_sdid;
629
630
0
    DISSECTOR_ASSERT(packet != NULL);
631
0
    DISSECTOR_ASSERT(data != NULL);
632
633
0
    st291_vanc_create_udw_tvbs(packet->parent_tvb, pinfo, packet->words + 3,
634
0
                               packet->data_count, &udw);
635
0
    if (packet->data_count != 0)
636
0
        add_new_data_source(pinfo, udw.byte_tvb, "ST 291 UDW Array");
637
638
0
    subdissector_data = *data;
639
0
    subdissector_data.full_udw_tvb = udw.full_tvb;
640
0
    dispatch_sdid = (packet->did & 0x80U) != 0 ? 0x00 : packet->sdid_or_dbn;
641
0
    return dissector_try_uint_with_data(
642
0
        st291_did_sdid_table,
643
0
        ((uint32_t)packet->did << 8) | dispatch_sdid,
644
0
        udw.byte_tvb, pinfo, tree, true, &subdissector_data);
645
0
}
646
647
/* SMPTE ST 291-1:2011, Secs. 5.1-5.2 -- DID/SDID/DBN on-wire identity fields. */
648
proto_item *
649
st291_tree_add_did(proto_tree *tree, tvbuff_t *tvb,
650
                   int offset, int length, uint8_t did)
651
0
{
652
0
    return proto_tree_add_uint(tree, hf_st291_did, tvb, offset, length, did);
653
0
}
654
655
proto_item *
656
st291_tree_add_sdid(proto_tree *tree, tvbuff_t *tvb,
657
                    int offset, int length, uint8_t did _U_, uint8_t sdid)
658
0
{
659
0
    return proto_tree_add_uint(tree, hf_st291_sdid, tvb, offset, length, sdid);
660
0
}
661
662
/* SMPTE ST 291-1:2011, Sec. 5.1: bit b7 of the DID distinguishes the
663
 * Type 1 (DBN) and Type 2 (SDID) identity forms used for the lookup. */
664
void
665
st291_append_packet_description(proto_item *item, uint8_t did, uint8_t sdid_or_dbn)
666
0
{
667
0
    const char *description;
668
669
0
    if ((did & 0x80U) != 0)
670
0
        description = st291_lookup_did(did);
671
0
    else
672
0
        description = st291_lookup_did_sdid(did, sdid_or_dbn);
673
674
0
    if (description != NULL)
675
0
        proto_item_append_text(item, ": %s", description);
676
0
}
677
678
proto_item *
679
st291_tree_add_dbn(proto_tree *tree, tvbuff_t *tvb,
680
                   int offset, int length, uint8_t dbn)
681
0
{
682
0
    return proto_tree_add_uint(tree, hf_st291_dbn, tvb, offset, length, dbn);
683
0
}
684
685
/* SMPTE ST 291-1:2011, Secs. 5.1-5.2 define DID, SDID and DBN.
686
 * The st291.did_sdid table below is Wireshark-only dispatch metadata. */
687
void
688
proto_register_st291(void)
689
16
{
690
16
    static hf_register_info hf[] = {
691
16
        { &hf_st291_did,
692
16
          { "Data ID", "st291.did", FT_UINT8, BASE_HEX, NULL, 0x00, NULL, HFILL } },
693
16
        { &hf_st291_sdid,
694
16
          { "Secondary Data ID", "st291.sdid", FT_UINT8, BASE_HEX, NULL, 0x00, NULL, HFILL } },
695
16
        { &hf_st291_dbn,
696
16
          { "Data Block Number", "st291.dbn", FT_UINT8, BASE_HEX, NULL, 0x00, NULL, HFILL } },
697
16
    };
698
699
16
    proto_st291 = proto_register_protocol(
700
16
        "SMPTE ST 291 Ancillary Data", "ST 291", "st291");
701
702
16
    proto_register_field_array(proto_st291, hf, array_length(hf));
703
704
    /*
705
     * Public extension point for ST 291 application payload dissectors.
706
     * Native and Lua dissectors can register DID/SDID keys here for
707
     * additional VANC payload formats.
708
     */
709
16
    st291_did_sdid_table = register_dissector_table(
710
16
        "st291.did_sdid", "SMPTE ST 291 DID/SDID",
711
16
        proto_st291, FT_UINT16, BASE_HEX);
712
16
}
713
714
/*
715
 * SMPTE ST 12-2 time code in ancillary data
716
 */
717
718
719
/* SMPTE ST 12-2:2014, Sec. 6.2.1, Table 2 -- DBB1 payload type. */
720
static const value_string st12_2_payload_type_vals[] = {
721
    { 0x00, "Linear time code (ATC_LTC)" },
722
    { 0x01, "Vertical interval time code #1 (ATC_VITC1)" },
723
    { 0x02, "Vertical interval time code #2 (ATC_VITC2)" },
724
    { 0x03, "User defined" },
725
    { 0x04, "User defined" },
726
    { 0x05, "User defined" },
727
    { 0x06, "Film data block (transferred from reader)" },
728
    { 0x07, "Production data block (transferred from reader)" },
729
    { 0x7D, "Video tape data block (locally generated)" },
730
    { 0x7E, "Film data block (locally generated)" },
731
    { 0x7F, "Production data block (locally generated)" },
732
    { 0, NULL }
733
};
734
735
/* SMPTE ST 12-2:2014, Sec. 6.2.2, Tables 3 and 5 -- DBB2 validity/process bits. */
736
static const value_string st12_2_vitc_validity_vals[] = {
737
    { 0, "No time code error received or locally generated time code address" },
738
    { 1, "Transmitted time code interpolated from previous time code (received a time code error)" },
739
    { 0, NULL }
740
};
741
742
static const value_string st12_2_vitc_process_vals[] = {
743
    { 0, "Binary groups in time code data stream are processed to compensate for latency" },
744
    { 1, "Binary groups in time code data stream are only retransmitted (no delay compensation)" },
745
    { 0, NULL }
746
};
747
748
749
/*
750
 * SMPTE ST 12-2:2014, Sec. 6.3, Table 6 maps the 64 information bits
751
 * defined by SMPTE ST 12-1 into UDW 1 through UDW 16.  The time address
752
 * is BCD; the intervening nibbles are the eight binary groups.  The six
753
 * remaining positions are ST 12-1 flag bits whose meaning depends on the
754
 * television system/frame rate (ST 12-1:2014, Sec. 8.3 and Tables 1-3).
755
 */
756
static int
757
dissect_st12_2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
758
0
{
759
0
    const st291_vanc_dissector_data_t *st291_data =
760
0
        (const st291_vanc_dissector_data_t *)data;
761
0
    proto_tree *top_tree =
762
0
        st291_data && st291_data->top_tree ? st291_data->top_tree : tree;
763
0
    proto_item *ti;
764
0
    proto_tree *st12_tree;
765
0
    proto_tree *time_tree;
766
0
    proto_tree *vitc_tree;
767
0
    uint8_t dbb1 = 0;
768
0
    uint8_t dbb2 = 0;
769
0
    uint8_t frame_units;
770
0
    uint8_t frame_tens;
771
0
    uint8_t second_units;
772
0
    uint8_t second_tens;
773
0
    uint8_t minute_units;
774
0
    uint8_t minute_tens;
775
0
    uint8_t hour_units;
776
0
    uint8_t hour_tens;
777
0
    uint8_t frames;
778
0
    uint8_t seconds;
779
0
    uint8_t minutes;
780
0
    uint8_t hours;
781
0
    bool drop_frame;
782
0
    char time_str[16];
783
0
    unsigned x;
784
785
0
    ti = proto_tree_add_item(top_tree, proto_st12_2, tvb, 0,
786
0
                             tvb_captured_length(tvb), ENC_NA);
787
0
    st12_tree = proto_item_add_subtree(ti, ett_st12_2);
788
789
0
    if (tvb_captured_length(tvb) < 16) {
790
0
        expert_add_info_format(pinfo, ti, &ei_st12_2_bad_length,
791
0
                               "ST 12-2 requires at least 16 UDW bytes; packet contains %u",
792
0
                               tvb_captured_length(tvb));
793
0
        return tvb_captured_length(tvb);
794
0
    }
795
796
    /*
797
     * SMPTE ST 12-2:2014, Sec. 6.3, Table 6 maps the 64 information
798
     * bits defined by SMPTE ST 12-1 into UDW 1 through UDW 16.
799
     *
800
     * The time-address digits are BCD:
801
     *   UDW 1/3   -- frame units/tens
802
     *   UDW 5/7   -- second units/tens
803
     *   UDW 9/11  -- minute units/tens
804
     *   UDW 13/15 -- hour units/tens
805
     *
806
     * ST 12-2 Sec. 6.1.2 defines b4 as the least-significant bit of
807
     * each four-bit information group.
808
     */
809
0
    frame_units  = (tvb_get_uint8(tvb, 0)  >> 4) & 0x0f;
810
0
    frame_tens   = (tvb_get_uint8(tvb, 2)  >> 4) & 0x03;
811
0
    second_units = (tvb_get_uint8(tvb, 4)  >> 4) & 0x0f;
812
0
    second_tens  = (tvb_get_uint8(tvb, 6)  >> 4) & 0x07;
813
0
    minute_units = (tvb_get_uint8(tvb, 8)  >> 4) & 0x0f;
814
0
    minute_tens  = (tvb_get_uint8(tvb, 10) >> 4) & 0x07;
815
0
    hour_units   = (tvb_get_uint8(tvb, 12) >> 4) & 0x0f;
816
0
    hour_tens    = (tvb_get_uint8(tvb, 14) >> 4) & 0x03;
817
818
0
    frames  = frame_tens * 10 + frame_units;
819
0
    seconds = second_tens * 10 + second_units;
820
0
    minutes = minute_tens * 10 + minute_units;
821
0
    hours   = hour_tens * 10 + hour_units;
822
823
    /*
824
     * SMPTE ST 12-2:2014, Sec. 6.3, Table 6 maps ST 12-1 bit 10 to
825
     * UDW 3 b6.  SMPTE ST 12-1:2014, Table 3 identifies bit 10 as
826
     * the drop-frame flag for the applicable 30-frame systems.
827
     */
828
0
    drop_frame = (tvb_get_uint8(tvb, 2) & 0x40) != 0;
829
830
0
    snprintf(time_str, sizeof(time_str), "%02u:%02u:%02u%c%02u",
831
0
             hours, minutes, seconds, drop_frame ? ';' : ':', frames);
832
833
    /*
834
     * This row is a human-readable representation of the 64 information
835
     * bits below.  It spans the actual UDW bytes rather than being marked
836
     * generated, so selecting it highlights the complete ATC data block.
837
     */
838
0
    ti = proto_tree_add_string(st12_tree, hf_st12_2_timecode, tvb, 0, 16, time_str);
839
0
    time_tree = proto_item_add_subtree(ti, ett_st12_2_timecode);
840
841
    /*
842
     * The BCD digit fields below are the actual on-wire nibbles from
843
     * ST 12-2:2014, Sec. 6.3, Table 6.  Their hf masks select the
844
     * corresponding b4-b7 positions in each UDW byte.
845
     */
846
    /*
847
     * SMPTE ST 12-2:2014, Sec. 6.3, Table 6.  Present the fields in
848
     * UDW order so the protocol tree follows the packet layout directly.
849
     */
850
    /* UDW 1: units of frames */
851
0
    proto_tree_add_item(time_tree, hf_st12_2_frame_units, tvb, 0, 1, ENC_BIG_ENDIAN);
852
853
    /* UDW 2: binary group 1 */
854
0
    proto_tree_add_item(time_tree, hf_st12_2_binary_group_1, tvb, 1, 1, ENC_BIG_ENDIAN);
855
856
    /* UDW 3: tens of frames, ST 12-1 flag bits 10 and 11 */
857
0
    proto_tree_add_item(time_tree, hf_st12_2_frame_tens, tvb, 2, 1, ENC_BIG_ENDIAN);
858
0
    proto_tree_add_item(time_tree, hf_st12_2_flag_bit_10, tvb, 2, 1, ENC_BIG_ENDIAN);
859
0
    proto_tree_add_item(time_tree, hf_st12_2_flag_bit_11, tvb, 2, 1, ENC_BIG_ENDIAN);
860
861
    /* UDW 4: binary group 2 */
862
0
    proto_tree_add_item(time_tree, hf_st12_2_binary_group_2, tvb, 3, 1, ENC_BIG_ENDIAN);
863
864
    /* UDW 5: units of seconds */
865
0
    proto_tree_add_item(time_tree, hf_st12_2_second_units, tvb, 4, 1, ENC_BIG_ENDIAN);
866
867
    /* UDW 6: binary group 3 */
868
0
    proto_tree_add_item(time_tree, hf_st12_2_binary_group_3, tvb, 5, 1, ENC_BIG_ENDIAN);
869
870
    /* UDW 7: tens of seconds, ST 12-1 flag bit 27 */
871
0
    proto_tree_add_item(time_tree, hf_st12_2_second_tens, tvb, 6, 1, ENC_BIG_ENDIAN);
872
0
    proto_tree_add_item(time_tree, hf_st12_2_flag_bit_27, tvb, 6, 1, ENC_BIG_ENDIAN);
873
874
    /* UDW 8: binary group 4 */
875
0
    proto_tree_add_item(time_tree, hf_st12_2_binary_group_4, tvb, 7, 1, ENC_BIG_ENDIAN);
876
877
    /* UDW 9: units of minutes */
878
0
    proto_tree_add_item(time_tree, hf_st12_2_minute_units, tvb, 8, 1, ENC_BIG_ENDIAN);
879
880
    /* UDW 10: binary group 5 */
881
0
    proto_tree_add_item(time_tree, hf_st12_2_binary_group_5, tvb, 9, 1, ENC_BIG_ENDIAN);
882
883
    /* UDW 11: tens of minutes, ST 12-1 flag bit 43 */
884
0
    proto_tree_add_item(time_tree, hf_st12_2_minute_tens, tvb, 10, 1, ENC_BIG_ENDIAN);
885
0
    proto_tree_add_item(time_tree, hf_st12_2_flag_bit_43, tvb, 10, 1, ENC_BIG_ENDIAN);
886
887
    /* UDW 12: binary group 6 */
888
0
    proto_tree_add_item(time_tree, hf_st12_2_binary_group_6, tvb, 11, 1, ENC_BIG_ENDIAN);
889
890
    /* UDW 13: units of hours */
891
0
    proto_tree_add_item(time_tree, hf_st12_2_hour_units, tvb, 12, 1, ENC_BIG_ENDIAN);
892
893
    /* UDW 14: binary group 7 */
894
0
    proto_tree_add_item(time_tree, hf_st12_2_binary_group_7, tvb, 13, 1, ENC_BIG_ENDIAN);
895
896
    /* UDW 15: tens of hours, ST 12-1 flag bits 58 and 59 */
897
0
    proto_tree_add_item(time_tree, hf_st12_2_hour_tens, tvb, 14, 1, ENC_BIG_ENDIAN);
898
0
    proto_tree_add_item(time_tree, hf_st12_2_flag_bit_58, tvb, 14, 1, ENC_BIG_ENDIAN);
899
0
    proto_tree_add_item(time_tree, hf_st12_2_flag_bit_59, tvb, 14, 1, ENC_BIG_ENDIAN);
900
901
    /* UDW 16: binary group 8 */
902
0
    proto_tree_add_item(time_tree, hf_st12_2_binary_group_8, tvb, 15, 1, ENC_BIG_ENDIAN);
903
904
    /*
905
     * SMPTE ST 12-2:2014, Secs. 6.2.1-6.2.2, Tables 2-3.
906
     * DBB1 is assembled from b4 of UDW 1-8; DBB2 from b4 of UDW 9-16.
907
     * These bytes are logical fields spread across multiple UDWs, so they
908
     * are shown as generated aggregate values.
909
     */
910
0
    for (x = 0; x < 8; x++) {
911
0
        dbb1 |= tvb_get_bits8(tvb, (x) * 8 + 4, 1) << x;
912
0
        dbb2 |= tvb_get_bits8(tvb, (8 + x) * 8 + 4, 1) << x;
913
0
    }
914
915
0
    ti = proto_tree_add_uint(st12_tree, hf_st12_2_payload_type, tvb, 0, 0, dbb1);
916
0
    proto_item_set_generated(ti);
917
918
0
    ti = proto_tree_add_uint(st12_tree, hf_st12_2_vitc, tvb, 0, 0, dbb2);
919
0
    proto_item_set_generated(ti);
920
921
0
    if (dbb1 == 0x01 || dbb1 == 0x02) {
922
0
        vitc_tree = proto_item_add_subtree(ti, ett_st12_2_vitc);
923
924
0
        ti = proto_tree_add_uint(vitc_tree, hf_st12_2_vitc_line_sel, tvb, 0, 0, dbb2);
925
0
        proto_item_set_generated(ti);
926
0
        ti = proto_tree_add_uint(vitc_tree, hf_st12_2_vitc_line_dup, tvb, 0, 0, dbb2);
927
0
        proto_item_set_generated(ti);
928
0
        ti = proto_tree_add_uint(vitc_tree, hf_st12_2_vitc_validity, tvb, 0, 0, dbb2);
929
0
        proto_item_set_generated(ti);
930
0
        ti = proto_tree_add_uint(vitc_tree, hf_st12_2_vitc_process, tvb, 0, 0, dbb2);
931
0
        proto_item_set_generated(ti);
932
0
    }
933
934
0
    proto_item_append_text(proto_tree_get_parent(st12_tree), ": %s", time_str);
935
936
0
    return tvb_captured_length(tvb);
937
0
}
938
939
void
940
proto_register_st12_2(void)
941
16
{
942
16
    static hf_register_info hf[] = {
943
16
        { &hf_st12_2_timecode,
944
16
          { "Time Code", "st12_2.timecode", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } },
945
946
        /* SMPTE ST 12-2:2014, Sec. 6.3, Table 6. */
947
16
        { &hf_st12_2_frame_units,
948
16
          { "Frame Units", "st12_2.time.frames.units", FT_UINT8, BASE_DEC, NULL, 0xF0, NULL,
949
16
            HFILL } },
950
16
        { &hf_st12_2_frame_tens,
951
16
          { "Frame Tens", "st12_2.time.frames.tens", FT_UINT8, BASE_DEC, NULL, 0x30, NULL,
952
16
            HFILL } },
953
16
        { &hf_st12_2_second_units,
954
16
          { "Second Units", "st12_2.time.seconds.units", FT_UINT8, BASE_DEC, NULL, 0xF0, NULL,
955
16
            HFILL } },
956
16
        { &hf_st12_2_second_tens,
957
16
          { "Second Tens", "st12_2.time.seconds.tens", FT_UINT8, BASE_DEC, NULL, 0x70, NULL,
958
16
            HFILL } },
959
16
        { &hf_st12_2_minute_units,
960
16
          { "Minute Units", "st12_2.time.minutes.units", FT_UINT8, BASE_DEC, NULL, 0xF0, NULL,
961
16
            HFILL } },
962
16
        { &hf_st12_2_minute_tens,
963
16
          { "Minute Tens", "st12_2.time.minutes.tens", FT_UINT8, BASE_DEC, NULL, 0x70, NULL,
964
16
            HFILL } },
965
16
        { &hf_st12_2_hour_units,
966
16
          { "Hour Units", "st12_2.time.hours.units", FT_UINT8, BASE_DEC, NULL, 0xF0, NULL,
967
16
            HFILL } },
968
16
        { &hf_st12_2_hour_tens,
969
16
          { "Hour Tens", "st12_2.time.hours.tens", FT_UINT8, BASE_DEC, NULL, 0x30, NULL, HFILL } },
970
971
        /*
972
         * SMPTE ST 12-2:2014, Sec. 6.3, Table 6;
973
         * SMPTE ST 12-1:2014, Table 3.
974
         */
975
16
        { &hf_st12_2_flag_bit_10,
976
16
          { "ST 12-1 Flag Bit 10 (Drop Frame in 30-frame systems)", "st12_2.flag.bit10",
977
16
            FT_BOOLEAN, 8, NULL, 0x40, NULL, HFILL } },
978
16
        { &hf_st12_2_flag_bit_11,
979
16
          { "ST 12-1 Flag Bit 11 (Color Frame in 30/25-frame systems)", "st12_2.flag.bit11",
980
16
            FT_BOOLEAN, 8, NULL, 0x80, NULL, HFILL } },
981
16
        { &hf_st12_2_flag_bit_27,
982
16
          { "ST 12-1 Flag Bit 27", "st12_2.flag.bit27", FT_BOOLEAN, 8, NULL, 0x80, NULL, HFILL } },
983
16
        { &hf_st12_2_flag_bit_43,
984
16
          { "ST 12-1 Flag Bit 43", "st12_2.flag.bit43", FT_BOOLEAN, 8, NULL, 0x80, NULL, HFILL } },
985
16
        { &hf_st12_2_flag_bit_58,
986
16
          { "ST 12-1 Flag Bit 58", "st12_2.flag.bit58", FT_BOOLEAN, 8, NULL, 0x40, NULL, HFILL } },
987
16
        { &hf_st12_2_flag_bit_59,
988
16
          { "ST 12-1 Flag Bit 59", "st12_2.flag.bit59", FT_BOOLEAN, 8, NULL, 0x80, NULL, HFILL } },
989
990
        /* SMPTE ST 12-2:2014, Sec. 6.3, Table 6; ST 12-1 Secs. 8.4-8.5. */
991
16
        { &hf_st12_2_binary_group_1,
992
16
          { "Binary Group 1", "st12_2.binary_group.1", FT_UINT8, BASE_HEX, NULL, 0xF0, NULL,
993
16
            HFILL } },
994
16
        { &hf_st12_2_binary_group_2,
995
16
          { "Binary Group 2", "st12_2.binary_group.2", FT_UINT8, BASE_HEX, NULL, 0xF0, NULL,
996
16
            HFILL } },
997
16
        { &hf_st12_2_binary_group_3,
998
16
          { "Binary Group 3", "st12_2.binary_group.3", FT_UINT8, BASE_HEX, NULL, 0xF0, NULL,
999
16
            HFILL } },
1000
16
        { &hf_st12_2_binary_group_4,
1001
16
          { "Binary Group 4", "st12_2.binary_group.4", FT_UINT8, BASE_HEX, NULL, 0xF0, NULL,
1002
16
            HFILL } },
1003
16
        { &hf_st12_2_binary_group_5,
1004
16
          { "Binary Group 5", "st12_2.binary_group.5", FT_UINT8, BASE_HEX, NULL, 0xF0, NULL,
1005
16
            HFILL } },
1006
16
        { &hf_st12_2_binary_group_6,
1007
16
          { "Binary Group 6", "st12_2.binary_group.6", FT_UINT8, BASE_HEX, NULL, 0xF0, NULL,
1008
16
            HFILL } },
1009
16
        { &hf_st12_2_binary_group_7,
1010
16
          { "Binary Group 7", "st12_2.binary_group.7", FT_UINT8, BASE_HEX, NULL, 0xF0, NULL,
1011
16
            HFILL } },
1012
16
        { &hf_st12_2_binary_group_8,
1013
16
          { "Binary Group 8", "st12_2.binary_group.8", FT_UINT8, BASE_HEX, NULL, 0xF0, NULL,
1014
16
            HFILL } },
1015
1016
        /* SMPTE ST 12-2:2014, Sec. 6.2.1, Table 2. */
1017
16
        { &hf_st12_2_payload_type,
1018
16
          { "Payload Type", "st12_2.payload_type", FT_UINT8, BASE_HEX,
1019
16
            VALS(st12_2_payload_type_vals), 0x0, NULL, HFILL } },
1020
1021
        /* SMPTE ST 12-2:2014, Sec. 6.2.2, Tables 3-5. */
1022
16
        { &hf_st12_2_vitc,
1023
16
          { "VITC Data", "st12_2.vitc", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } },
1024
16
        { &hf_st12_2_vitc_line_sel,
1025
16
          { "Line Select", "st12_2.vitc.line_sel", FT_UINT8, BASE_DEC, NULL, 0x1F, NULL, HFILL } },
1026
16
        { &hf_st12_2_vitc_line_dup,
1027
16
          { "Duplication", "st12_2.vitc.line_dup", FT_UINT8, BASE_DEC, NULL, 0x20, NULL, HFILL } },
1028
16
        { &hf_st12_2_vitc_validity,
1029
16
          { "TC Validity", "st12_2.vitc.validity", FT_UINT8, BASE_DEC,
1030
16
            VALS(st12_2_vitc_validity_vals), 0x40, NULL, HFILL } },
1031
16
        { &hf_st12_2_vitc_process,
1032
16
          { "Process Bit", "st12_2.vitc.process", FT_UINT8, BASE_DEC,
1033
16
            VALS(st12_2_vitc_process_vals), 0x80, NULL, HFILL } },
1034
16
    };
1035
16
    static int *ett[] = {
1036
16
        &ett_st12_2,
1037
16
        &ett_st12_2_timecode,
1038
16
        &ett_st12_2_vitc,
1039
16
    };
1040
16
    static ei_register_info ei[] = {
1041
16
        { &ei_st12_2_bad_length,
1042
16
          { "st12_2.length.bad", PI_MALFORMED, PI_WARN,
1043
16
            "ST 12-2 payload contains fewer than 16 UDW bytes", EXPFILL } },
1044
16
    };
1045
16
    expert_module_t *expert_st12_2;
1046
1047
16
    proto_st12_2 = proto_register_protocol(
1048
16
        "SMPTE ST 12-2 Ancillary Time Code", "ST 12-2", "st12_2");
1049
16
    proto_register_field_array(proto_st12_2, hf, array_length(hf));
1050
16
    proto_register_subtree_array(ett, array_length(ett));
1051
1052
16
    expert_st12_2 = expert_register_protocol(proto_st12_2);
1053
16
    expert_register_field_array(expert_st12_2, ei, array_length(ei));
1054
1055
16
    st12_2_handle = register_dissector("st12_2", dissect_st12_2, proto_st12_2);
1056
16
}
1057
1058
void
1059
proto_reg_handoff_st12_2(void)
1060
16
{
1061
16
    dissector_add_uint("st291.did_sdid", ST12_2_DID_SDID_KEY, st12_2_handle);
1062
16
}
1063
1064
/*
1065
 * SMPTE ST 2010 SCTE-104 mapping
1066
 */
1067
1068
static const fragment_items st2010_frag_items = {
1069
    &ett_st2010_fragment,
1070
    &ett_st2010_fragments,
1071
    &hf_st2010_fragments,
1072
    &hf_st2010_fragment,
1073
    &hf_st2010_fragment_overlap,
1074
    &hf_st2010_fragment_overlap_conflict,
1075
    &hf_st2010_fragment_multiple_tails,
1076
    &hf_st2010_fragment_too_long_fragment,
1077
    &hf_st2010_fragment_error,
1078
    &hf_st2010_fragment_count,
1079
    &hf_st2010_reassembled_in,
1080
    &hf_st2010_reassembled_length,
1081
    &hf_st2010_reassembled_data,
1082
    "ST 2010 message fragments"
1083
};
1084
1085
static void
1086
call_st2010_payload(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1087
0
{
1088
0
    if (!dissector_try_uint(st2010_payload_table, ST2010_PAYLOAD_SCTE104,
1089
0
                            tvb, pinfo, tree)) {
1090
0
        call_data_dissector(tvb, pinfo, tree);
1091
0
    }
1092
0
}
1093
1094
/* SMPTE 2010-2008, Sec. 5.2, Tables 1-3; Sec. 5.4 for multi-packet reassembly. */
1095
static int
1096
dissect_st2010(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
1097
0
{
1098
0
    const st291_vanc_dissector_data_t *st291_data =
1099
0
        (const st291_vanc_dissector_data_t *)data;
1100
0
    proto_tree *payload_tree =
1101
0
        st291_data && st291_data->top_tree ? st291_data->top_tree : tree;
1102
0
    const unsigned len = tvb_captured_length(tvb);
1103
0
    uint8_t desc;
1104
0
    unsigned version;
1105
0
    bool continued_pkt;
1106
0
    bool following_pkt;
1107
0
    bool duplicate_msg;
1108
0
    proto_item *ti;
1109
0
    proto_tree *st2010_tree;
1110
0
    fragment_head *fd_head;
1111
0
    tvbuff_t *reassembled_tvb;
1112
0
    bool save_fragmented;
1113
1114
0
    if (len < 1)
1115
0
        return 0;
1116
1117
0
    desc = tvb_get_uint8(tvb, 0);
1118
0
    version = (desc & 0x18) >> 3;
1119
0
    continued_pkt = (desc & 0x04) != 0;
1120
0
    following_pkt = (desc & 0x02) != 0;
1121
0
    duplicate_msg = (desc & 0x01) != 0;
1122
1123
0
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "ST2010");
1124
1125
0
    ti = proto_tree_add_item(tree, proto_st2010, tvb, 0, -1, ENC_NA);
1126
0
    st2010_tree = proto_item_add_subtree(ti, ett_st2010);
1127
1128
0
    proto_tree_add_item(st2010_tree, hf_st2010_payload_descriptor, tvb, 0, 1, ENC_BIG_ENDIAN);
1129
0
    proto_tree_add_item(st2010_tree, hf_st2010_reserved, tvb, 0, 1, ENC_BIG_ENDIAN);
1130
0
    proto_tree_add_item(st2010_tree, hf_st2010_version, tvb, 0, 1, ENC_BIG_ENDIAN);
1131
0
    proto_tree_add_item(st2010_tree, hf_st2010_continued_pkt, tvb, 0, 1, ENC_BIG_ENDIAN);
1132
0
    proto_tree_add_item(st2010_tree, hf_st2010_following_pkt, tvb, 0, 1, ENC_BIG_ENDIAN);
1133
0
    proto_tree_add_item(st2010_tree, hf_st2010_duplicate_msg, tvb, 0, 1, ENC_BIG_ENDIAN);
1134
1135
0
    if ((desc & 0xE0) != 0)
1136
0
        expert_add_info(pinfo, ti, &ei_st2010_reserved_bits);
1137
0
    if (version != 1)
1138
0
        expert_add_info(pinfo, ti, &ei_st2010_bad_version);
1139
1140
0
    proto_item_append_text(ti, ": version %u%s%s%s",
1141
0
                           version,
1142
0
                           continued_pkt ? ", continued" : "",
1143
0
                           following_pkt ? ", following" : "",
1144
0
                           duplicate_msg ? ", duplicate" : "");
1145
1146
0
    if (len <= 1) {
1147
0
        expert_add_info(pinfo, ti, &ei_st2010_empty_payload);
1148
0
        return len;
1149
0
    }
1150
1151
0
    proto_tree_add_item(st2010_tree, hf_st2010_payload, tvb, 1, -1, ENC_NA);
1152
1153
    /* Single-packet SCTE-104 message. */
1154
0
    if (!continued_pkt && !following_pkt) {
1155
0
        tvbuff_t *msg_tvb = tvb_new_subset_remaining(tvb, 1);
1156
0
        call_st2010_payload(msg_tvb, pinfo, payload_tree);
1157
0
        return len;
1158
0
    }
1159
1160
    /*
1161
     * Fragmented ST 2010 message.  ST 2010 supplies no fragment number or
1162
     * message identifier, so fragments are appended in capture order.  The
1163
     * reassembly key is the enclosing flow (addresses + ports) plus ID 0.
1164
     * ST 2010 permits only one complete SCTE-104 message per video frame,
1165
     * so overlapping in-progress messages on one flow are malformed.
1166
     */
1167
0
    if (!PINFO_FD_VISITED(pinfo)) {
1168
0
        fragment_head *active = fragment_get(&st2010_reassembly_table, pinfo, 0, NULL);
1169
1170
0
        if (!following_pkt) {
1171
0
            if (active != NULL) {
1172
0
                expert_add_info(pinfo, ti, &ei_st2010_overlapping_message);
1173
0
                return len;
1174
0
            }
1175
0
        } else if (active == NULL) {
1176
0
            expert_add_info(pinfo, ti, &ei_st2010_orphan_fragment);
1177
0
            return len;
1178
0
        }
1179
0
    }
1180
1181
0
    save_fragmented = pinfo->fragmented;
1182
0
    pinfo->fragmented = true;
1183
0
    fd_head = fragment_add_seq_next(&st2010_reassembly_table,
1184
0
                                    tvb, 1, pinfo, 0, NULL,
1185
0
                                    len - 1, continued_pkt);
1186
1187
0
    reassembled_tvb = process_reassembled_data(tvb, 1, pinfo,
1188
0
                                                "Reassembled SCTE-104 Message",
1189
0
                                                fd_head, &st2010_frag_items,
1190
0
                                                NULL, st2010_tree);
1191
0
    pinfo->fragmented = save_fragmented;
1192
1193
0
    if (reassembled_tvb != NULL)
1194
0
        call_st2010_payload(reassembled_tvb, pinfo, payload_tree);
1195
1196
0
    return len;
1197
0
}
1198
1199
void
1200
proto_register_st2010(void)
1201
16
{
1202
16
    static hf_register_info hf[] = {
1203
16
        { &hf_st2010_payload_descriptor,
1204
16
          { "Payload Descriptor", "st2010.payload_descriptor", FT_UINT8, BASE_HEX, NULL, 0x00,
1205
16
            NULL, HFILL } },
1206
16
        { &hf_st2010_reserved,
1207
16
          { "Reserved", "st2010.reserved", FT_UINT8, BASE_HEX, NULL, 0xE0, NULL, HFILL } },
1208
16
        { &hf_st2010_version,
1209
16
          { "Mapping Version", "st2010.version", FT_UINT8, BASE_DEC, NULL, 0x18, NULL, HFILL } },
1210
16
        { &hf_st2010_continued_pkt,
1211
16
          { "Continued Packet", "st2010.continued_pkt", FT_BOOLEAN, 8, NULL, 0x04, NULL, HFILL } },
1212
16
        { &hf_st2010_following_pkt,
1213
16
          { "Following Packet", "st2010.following_pkt", FT_BOOLEAN, 8, NULL, 0x02, NULL, HFILL } },
1214
16
        { &hf_st2010_duplicate_msg,
1215
16
          { "Duplicate Message", "st2010.duplicate_msg", FT_BOOLEAN, 8, NULL, 0x01, NULL,
1216
16
            HFILL } },
1217
16
        { &hf_st2010_payload,
1218
16
          { "SCTE-104 Message Bytes", "st2010.payload", FT_BYTES, BASE_NONE, NULL, 0x00, NULL,
1219
16
            HFILL } },
1220
1221
16
        { &hf_st2010_fragments,
1222
1223
16
          { "Reassembled ST 2010 fragments", "st2010.fragments", FT_NONE, BASE_NONE, NULL,
1224
1225
16
            0x00, NULL, HFILL } },
1226
16
        { &hf_st2010_fragment,
1227
16
          { "ST 2010 fragment", "st2010.fragment", FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL,
1228
16
            HFILL } },
1229
16
        { &hf_st2010_fragment_overlap,
1230
16
          { "ST 2010 fragment overlap", "st2010.fragment.overlap", FT_BOOLEAN, BASE_NONE,
1231
16
            NULL, 0x00, NULL, HFILL } },
1232
16
        { &hf_st2010_fragment_overlap_conflict,
1233
16
          { "ST 2010 fragment overlap conflict", "st2010.fragment.overlap.conflict",
1234
16
            FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL } },
1235
16
        { &hf_st2010_fragment_multiple_tails,
1236
16
          { "ST 2010 multiple tail fragments", "st2010.fragment.multiple_tails", FT_BOOLEAN,
1237
16
            BASE_NONE, NULL, 0x00, NULL, HFILL } },
1238
16
        { &hf_st2010_fragment_too_long_fragment,
1239
16
          { "ST 2010 fragment too long", "st2010.fragment.too_long_fragment", FT_BOOLEAN,
1240
16
            BASE_NONE, NULL, 0x00, NULL, HFILL } },
1241
16
        { &hf_st2010_fragment_error,
1242
16
          { "ST 2010 reassembly error in frame", "st2010.fragment.error", FT_FRAMENUM,
1243
16
            BASE_NONE, NULL, 0x00, NULL, HFILL } },
1244
16
        { &hf_st2010_fragment_count,
1245
16
          { "ST 2010 fragment count", "st2010.fragment.count", FT_UINT32, BASE_DEC, NULL,
1246
16
            0x00, NULL, HFILL } },
1247
16
        { &hf_st2010_reassembled_in,
1248
16
          { "Reassembled in", "st2010.reassembled.in", FT_FRAMENUM, BASE_NONE, NULL, 0x00,
1249
16
            NULL, HFILL } },
1250
16
        { &hf_st2010_reassembled_length,
1251
16
          { "Reassembled length", "st2010.reassembled.length", FT_UINT32, BASE_DEC, NULL,
1252
16
            0x00, NULL, HFILL } },
1253
16
        { &hf_st2010_reassembled_data,
1254
16
          { "Reassembled SCTE-104 data", "st2010.reassembled.data", FT_BYTES, BASE_NONE, NULL,
1255
16
            0x00, NULL, HFILL } },
1256
16
    };
1257
1258
16
    static int *ett[] = {
1259
16
        &ett_st2010,
1260
16
        &ett_st2010_fragment,
1261
16
        &ett_st2010_fragments,
1262
16
    };
1263
1264
16
    static ei_register_info ei[] = {
1265
16
        { &ei_st2010_bad_version,
1266
16
          { "st2010.version.invalid", PI_PROTOCOL, PI_WARN,
1267
16
            "ST 2010 mapping version is not Version 1", EXPFILL } },
1268
16
        { &ei_st2010_reserved_bits,
1269
16
          { "st2010.reserved.nonzero", PI_PROTOCOL, PI_WARN,
1270
16
            "Reserved Payload Descriptor bits are non-zero", EXPFILL } },
1271
16
        { &ei_st2010_orphan_fragment,
1272
16
          { "st2010.fragment.orphan", PI_REASSEMBLE, PI_WARN,
1273
16
            "Following ST 2010 fragment seen without a preceding first fragment", EXPFILL } },
1274
16
        { &ei_st2010_overlapping_message,
1275
16
          { "st2010.fragment.overlap_message", PI_REASSEMBLE, PI_WARN,
1276
16
            "New ST 2010 message started while another message is still being reassembled",
1277
16
            EXPFILL } },
1278
16
        { &ei_st2010_empty_payload,
1279
16
          { "st2010.payload.empty", PI_MALFORMED, PI_WARN,
1280
16
            "ST 2010 packet contains a Payload Descriptor but no SCTE-104 bytes", EXPFILL } },
1281
16
    };
1282
1283
16
    expert_module_t *expert;
1284
1285
16
    proto_st2010 = proto_register_protocol("SMPTE ST 2010", "ST 2010", "st2010");
1286
16
    proto_register_field_array(proto_st2010, hf, array_length(hf));
1287
16
    proto_register_subtree_array(ett, array_length(ett));
1288
1289
16
    expert = expert_register_protocol(proto_st2010);
1290
16
    expert_register_field_array(expert, ei, array_length(ei));
1291
1292
16
    reassembly_table_register(&st2010_reassembly_table,
1293
16
                              &addresses_ports_reassembly_table_functions);
1294
1295
    /*
1296
     * Public payload table. Key 0 is the complete SCTE-104 message. A Lua
1297
     * dissector can register here after all compiled dissectors initialize.
1298
     */
1299
16
    st2010_payload_table = register_dissector_table(
1300
16
        "st2010.payload_type", "ST 2010 Payload Type", proto_st2010, FT_UINT8, BASE_DEC);
1301
1302
16
    st2010_handle = register_dissector("st2010", dissect_st2010, proto_st2010);
1303
16
}
1304
1305
void
1306
proto_reg_handoff_st2010(void)
1307
16
{
1308
16
    dissector_add_uint("st291.did_sdid", ST2010_DID_SDID_KEY, st2010_handle);
1309
16
}
1310
1311
/*
1312
 * SMPTE ST 2016-3 active format description and bar data
1313
 */
1314
1315
static const struct true_false_string st2016_3_tfs_afd_ar = {
1316
    "16:9 coded frame",
1317
    "4:3 coded frame"
1318
};
1319
1320
/* SMPTE ST 2016-1:2009, Sec. 5, Table 1 -- AFD code meaning depends on coded-frame AR. */
1321
static const char *
1322
st2016_3_afd_description(uint8_t afd, bool ar_16_9)
1323
0
{
1324
0
    static const char *const afd_4_3[16] = {
1325
0
        "Undefined",
1326
0
        "Reserved",
1327
0
        "Letterbox 16:9 image, at top of coded frame",
1328
0
        "Letterbox 14:9 image, at top of coded frame",
1329
0
        "Letterbox image with aspect ratio greater than 16:9, vertically centered",
1330
0
        "Reserved",
1331
0
        "Reserved",
1332
0
        "Reserved",
1333
0
        "Full frame 4:3 image, same as coded frame",
1334
0
        "Full frame 4:3 image, same as coded frame",
1335
0
        "Letterbox 16:9 image, vertically centered, all image areas protected",
1336
0
        "Letterbox 14:9 image, vertically centered",
1337
0
        "Reserved",
1338
0
        "Full frame 4:3 image, with alternative 14:9 center",
1339
0
        "Letterbox 16:9 image, with alternative 14:9 center",
1340
0
        "Letterbox 16:9 image, with alternative 4:3 center"
1341
0
    };
1342
0
    static const char *const afd_16_9[16] = {
1343
0
        "Undefined",
1344
0
        "Reserved",
1345
0
        "Full frame 16:9 image, same as coded frame",
1346
0
        "Pillarbox 14:9 image, horizontally centered",
1347
0
        "Letterbox image with aspect ratio greater than 16:9, vertically centered",
1348
0
        "Reserved",
1349
0
        "Reserved",
1350
0
        "Reserved",
1351
0
        "Full frame 16:9 image, same as coded frame",
1352
0
        "Pillarbox 4:3 image, horizontally centered",
1353
0
        "Full frame 16:9 image, all image areas protected",
1354
0
        "Pillarbox 14:9 image, horizontally centered",
1355
0
        "Reserved",
1356
0
        "Pillarbox 4:3 image, with alternative 14:9 center",
1357
0
        "Full frame 16:9 image, with alternative 14:9 center",
1358
0
        "Full frame 16:9 image, with alternative 4:3 center"
1359
0
    };
1360
1361
0
    return ar_16_9 ? afd_16_9[afd & 0x0f] : afd_4_3[afd & 0x0f];
1362
0
}
1363
1364
/* SMPTE ST 2016-1:2009, Secs. 6, 9.2.1-9.2.2, Tables 3, 5 and 6. */
1365
static const char *
1366
st2016_3_bar_value_meaning(unsigned value_index, bool top, bool bottom, bool left, bool right)
1367
0
{
1368
0
    if (value_index == 1) {
1369
0
        if (top)
1370
0
            return "Line number: end of top bar";
1371
0
        if (bottom)
1372
0
            return "Line number: start of bottom bar";
1373
0
        if (left)
1374
0
            return "Pixel number: end of left bar";
1375
0
        if (right)
1376
0
            return "Pixel number: start of right bar";
1377
0
    } else {
1378
0
        if (top && bottom)
1379
0
            return "Line number: start of bottom bar";
1380
0
        if (left && right)
1381
0
            return "Pixel number: start of right bar";
1382
0
    }
1383
1384
0
    return "No valid Bar Data value";
1385
0
}
1386
1387
static int
1388
dissect_st2016_3(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
1389
0
{
1390
0
    const st291_vanc_dissector_data_t *st291_data =
1391
0
        (const st291_vanc_dissector_data_t *)data;
1392
0
    proto_tree *top_tree =
1393
0
        st291_data && st291_data->top_tree ? st291_data->top_tree : tree;
1394
0
    proto_item *ti;
1395
0
    proto_item *root_ti;
1396
0
    proto_tree *st2016_tree;
1397
0
    proto_tree *afd_tree;
1398
0
    proto_tree *flags_tree;
1399
0
    proto_tree *value_tree;
1400
0
    unsigned len = tvb_captured_length(tvb);
1401
0
    uint8_t afd_byte;
1402
0
    uint8_t afd;
1403
0
    bool ar_16_9;
1404
0
    uint8_t flags;
1405
0
    bool top;
1406
0
    bool bottom;
1407
0
    bool left;
1408
0
    bool right;
1409
0
    uint16_t value1;
1410
0
    uint16_t value2;
1411
0
    const char *meaning1;
1412
0
    const char *meaning2;
1413
1414
0
    root_ti = proto_tree_add_item(top_tree, proto_st2016_3, tvb, 0, len, ENC_NA);
1415
0
    st2016_tree = proto_item_add_subtree(root_ti, ett_st2016_3);
1416
1417
0
    if (len != 8) {
1418
0
        expert_add_info_format(pinfo, root_ti, &ei_st2016_3_bad_length,
1419
0
                               "ST 2016-3 requires 8 UDW bytes; packet contains %u",
1420
0
                               len);
1421
0
        return len;
1422
0
    }
1423
1424
    /* SMPTE ST 2016-3:2009, Sec. 4.1, Table 1 maps UDW1 to the
1425
     * ST 2016-1 AFD byte; ST 2016-1:2009, Sec. 9.1, Table 4 defines
1426
     * reserved bits, active_format and coded_frame_aspect_ratio. */
1427
0
    afd_byte = tvb_get_uint8(tvb, 0);
1428
0
    afd = (afd_byte >> 3) & 0x0f;
1429
0
    ar_16_9 = (afd_byte & 0x04) != 0;
1430
1431
0
    ti = proto_tree_add_item(st2016_tree, hf_st2016_3_afd_byte, tvb, 0, 1, ENC_BIG_ENDIAN);
1432
0
    afd_tree = proto_item_add_subtree(ti, ett_st2016_3_afd);
1433
0
    proto_tree_add_item(afd_tree, hf_st2016_3_afd_reserved, tvb, 0, 1, ENC_BIG_ENDIAN);
1434
0
    proto_tree_add_uint_format_value(afd_tree, hf_st2016_3_afd_code, tvb, 0, 1, afd,
1435
0
                                     "%u (%s)", afd,
1436
0
                                     st2016_3_afd_description(afd, ar_16_9));
1437
0
    proto_tree_add_item(afd_tree, hf_st2016_3_afd_ar, tvb, 0, 1, ENC_BIG_ENDIAN);
1438
1439
0
    if ((afd_byte & 0x83) != 0)
1440
0
        expert_add_info(pinfo, ti, &ei_st2016_3_afd_reserved);
1441
1442
    /* SMPTE ST 2016-3:2009, Sec. 4.1, Table 1 -- UDW2 and UDW3 are reserved. */
1443
0
    ti = proto_tree_add_item(st2016_tree, hf_st2016_3_reserved_1, tvb, 1, 1, ENC_BIG_ENDIAN);
1444
0
    if (tvb_get_uint8(tvb, 1) != 0)
1445
0
        expert_add_info(pinfo, ti, &ei_st2016_3_reserved_udw);
1446
1447
0
    ti = proto_tree_add_item(st2016_tree, hf_st2016_3_reserved_2, tvb, 2, 1, ENC_BIG_ENDIAN);
1448
0
    if (tvb_get_uint8(tvb, 2) != 0)
1449
0
        expert_add_info(pinfo, ti, &ei_st2016_3_reserved_udw);
1450
1451
    /* SMPTE ST 2016-3:2009, Sec. 4.1, Table 1 maps UDW4 to Bar Data flags;
1452
     * SMPTE ST 2016-1:2009, Sec. 9.2.1, Table 5 defines top/bottom/left/right. */
1453
0
    flags = tvb_get_uint8(tvb, 3);
1454
0
    top = (flags & 0x80) != 0;
1455
0
    bottom = (flags & 0x40) != 0;
1456
0
    left = (flags & 0x20) != 0;
1457
0
    right = (flags & 0x10) != 0;
1458
1459
0
    ti = proto_tree_add_item(st2016_tree, hf_st2016_3_bar_flags, tvb, 3, 1, ENC_BIG_ENDIAN);
1460
0
    flags_tree = proto_item_add_subtree(ti, ett_st2016_3_bar_flags);
1461
0
    proto_tree_add_item(flags_tree, hf_st2016_3_bar_top, tvb, 3, 1, ENC_BIG_ENDIAN);
1462
0
    proto_tree_add_item(flags_tree, hf_st2016_3_bar_bottom, tvb, 3, 1, ENC_BIG_ENDIAN);
1463
0
    proto_tree_add_item(flags_tree, hf_st2016_3_bar_left, tvb, 3, 1, ENC_BIG_ENDIAN);
1464
0
    proto_tree_add_item(flags_tree, hf_st2016_3_bar_right, tvb, 3, 1, ENC_BIG_ENDIAN);
1465
0
    proto_tree_add_item(flags_tree, hf_st2016_3_bar_reserved, tvb, 3, 1, ENC_BIG_ENDIAN);
1466
1467
0
    if ((flags & 0x0f) != 0)
1468
0
        expert_add_info(pinfo, ti, &ei_st2016_3_bar_reserved);
1469
1470
0
    if ((top != bottom) || (left != right) || ((top || bottom) && (left || right)))
1471
0
        expert_add_info(pinfo, ti, &ei_st2016_3_bar_flags_invalid);
1472
1473
    /* SMPTE ST 2016-3:2009, Sec. 4.1, Table 1 maps UDW5-UDW8 to
1474
     * Bar Data Value 1/2; ST 2016-1:2009, Sec. 9.2.2, Table 6 defines
1475
     * marker bits and the 14-bit line/pixel values. */
1476
0
    value1 = tvb_get_ntohs(tvb, 4);
1477
0
    value2 = tvb_get_ntohs(tvb, 6);
1478
0
    meaning1 = st2016_3_bar_value_meaning(1, top, bottom, left, right);
1479
0
    meaning2 = st2016_3_bar_value_meaning(2, top, bottom, left, right);
1480
1481
0
    ti = proto_tree_add_item(st2016_tree, hf_st2016_3_bar_value_1, tvb, 4, 2, ENC_BIG_ENDIAN);
1482
0
    value_tree = proto_item_add_subtree(ti, ett_st2016_3_bar_value_1);
1483
0
    proto_tree_add_item(value_tree, hf_st2016_3_bar_value_1_marker, tvb, 4, 2, ENC_BIG_ENDIAN);
1484
0
    proto_tree_add_item(value_tree, hf_st2016_3_bar_value_1_data, tvb, 4, 2, ENC_BIG_ENDIAN);
1485
0
    ti = proto_tree_add_string(value_tree, hf_st2016_3_bar_value_1_meaning, tvb, 4, 0,
1486
0
                               meaning1);
1487
0
    proto_item_set_generated(ti);
1488
1489
0
    ti = proto_tree_add_item(st2016_tree, hf_st2016_3_bar_value_2, tvb, 6, 2, ENC_BIG_ENDIAN);
1490
0
    value_tree = proto_item_add_subtree(ti, ett_st2016_3_bar_value_2);
1491
0
    proto_tree_add_item(value_tree, hf_st2016_3_bar_value_2_marker, tvb, 6, 2, ENC_BIG_ENDIAN);
1492
0
    proto_tree_add_item(value_tree, hf_st2016_3_bar_value_2_data, tvb, 6, 2, ENC_BIG_ENDIAN);
1493
0
    ti = proto_tree_add_string(value_tree, hf_st2016_3_bar_value_2_meaning, tvb, 6, 0,
1494
0
                               meaning2);
1495
0
    proto_item_set_generated(ti);
1496
1497
0
    if (top || bottom || left || right) {
1498
0
        if ((value1 & 0xc000) != 0xc000)
1499
0
            expert_add_info(pinfo, ti, &ei_st2016_3_bar_marker);
1500
0
        if ((top && bottom) || (left && right)) {
1501
0
            if ((value2 & 0xc000) != 0xc000)
1502
0
                expert_add_info(pinfo, ti, &ei_st2016_3_bar_marker);
1503
0
        }
1504
0
    }
1505
1506
0
    proto_item_append_text(root_ti, ": AFD: %s in %s mode",
1507
0
                           st2016_3_afd_description(afd, ar_16_9),
1508
0
                           ar_16_9 ? "16:9" : "4:3");
1509
1510
0
    return len;
1511
0
}
1512
1513
void
1514
proto_register_st2016_3(void)
1515
16
{
1516
16
    static hf_register_info hf[] = {
1517
16
        { &hf_st2016_3_afd_byte,
1518
16
          { "AFD Information", "st2016_3.afd", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } },
1519
16
        { &hf_st2016_3_afd_code,
1520
16
          { "AFD Code", "st2016_3.afd.code", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } },
1521
16
        { &hf_st2016_3_afd_ar,
1522
16
          { "Coded Frame Aspect Ratio", "st2016_3.afd.ar", FT_BOOLEAN, 8,
1523
16
            TFS(&st2016_3_tfs_afd_ar), 0x04, NULL, HFILL } },
1524
16
        { &hf_st2016_3_afd_reserved,
1525
16
          { "Reserved", "st2016_3.afd.reserved", FT_UINT8, BASE_HEX, NULL, 0x83, NULL, HFILL } },
1526
16
        { &hf_st2016_3_reserved_1,
1527
16
          { "Reserved UDW 2", "st2016_3.reserved1", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } },
1528
16
        { &hf_st2016_3_reserved_2,
1529
16
          { "Reserved UDW 3", "st2016_3.reserved2", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } },
1530
16
        { &hf_st2016_3_bar_flags,
1531
16
          { "Bar Data Flags", "st2016_3.bar.flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } },
1532
16
        { &hf_st2016_3_bar_top,
1533
16
          { "Top Bar Present", "st2016_3.bar.top", FT_BOOLEAN, 8, NULL, 0x80, NULL, HFILL } },
1534
16
        { &hf_st2016_3_bar_bottom,
1535
16
          { "Bottom Bar Present", "st2016_3.bar.bottom", FT_BOOLEAN, 8, NULL, 0x40, NULL,
1536
16
            HFILL } },
1537
16
        { &hf_st2016_3_bar_left,
1538
16
          { "Left Bar Present", "st2016_3.bar.left", FT_BOOLEAN, 8, NULL, 0x20, NULL, HFILL } },
1539
16
        { &hf_st2016_3_bar_right,
1540
16
          { "Right Bar Present", "st2016_3.bar.right", FT_BOOLEAN, 8, NULL, 0x10, NULL, HFILL } },
1541
16
        { &hf_st2016_3_bar_reserved,
1542
16
          { "Reserved", "st2016_3.bar.reserved", FT_UINT8, BASE_HEX, NULL, 0x0f, NULL, HFILL } },
1543
16
        { &hf_st2016_3_bar_value_1,
1544
16
          { "Bar Data Value 1", "st2016_3.bar.value1", FT_UINT16, BASE_HEX, NULL, 0x0, NULL,
1545
16
            HFILL } },
1546
16
        { &hf_st2016_3_bar_value_1_marker,
1547
16
          { "Marker Bits", "st2016_3.bar.value1.marker", FT_UINT16, BASE_HEX, NULL, 0xc000,
1548
16
            NULL, HFILL } },
1549
16
        { &hf_st2016_3_bar_value_1_data,
1550
16
          { "Line/Pixel Number", "st2016_3.bar.value1.data", FT_UINT16, BASE_DEC, NULL,
1551
16
            0x3fff, NULL, HFILL } },
1552
16
        { &hf_st2016_3_bar_value_2,
1553
16
          { "Bar Data Value 2", "st2016_3.bar.value2", FT_UINT16, BASE_HEX, NULL, 0x0, NULL,
1554
16
            HFILL } },
1555
16
        { &hf_st2016_3_bar_value_2_marker,
1556
16
          { "Marker Bits", "st2016_3.bar.value2.marker", FT_UINT16, BASE_HEX, NULL, 0xc000,
1557
16
            NULL, HFILL } },
1558
16
        { &hf_st2016_3_bar_value_2_data,
1559
16
          { "Line/Pixel Number", "st2016_3.bar.value2.data", FT_UINT16, BASE_DEC, NULL,
1560
16
            0x3fff, NULL, HFILL } },
1561
16
        { &hf_st2016_3_bar_value_1_meaning,
1562
16
          { "Meaning", "st2016_3.bar.value1.meaning", FT_STRING, BASE_NONE, NULL, 0x0, NULL,
1563
16
            HFILL } },
1564
16
        { &hf_st2016_3_bar_value_2_meaning,
1565
16
          { "Meaning", "st2016_3.bar.value2.meaning", FT_STRING, BASE_NONE, NULL, 0x0, NULL,
1566
16
            HFILL } },
1567
16
    };
1568
1569
16
    static int *ett[] = {
1570
16
        &ett_st2016_3,
1571
16
        &ett_st2016_3_afd,
1572
16
        &ett_st2016_3_bar_flags,
1573
16
        &ett_st2016_3_bar_value_1,
1574
16
        &ett_st2016_3_bar_value_2,
1575
16
    };
1576
1577
16
    static ei_register_info ei[] = {
1578
16
        { &ei_st2016_3_bad_length,
1579
16
          { "st2016_3.length.bad", PI_MALFORMED, PI_WARN,
1580
16
            "ST 2016-3 payload length is not 8 bytes", EXPFILL } },
1581
16
        { &ei_st2016_3_afd_reserved,
1582
16
          { "st2016_3.afd.reserved.bad", PI_PROTOCOL, PI_WARN,
1583
16
            "Reserved AFD bits are not zero", EXPFILL } },
1584
16
        { &ei_st2016_3_reserved_udw,
1585
16
          { "st2016_3.reserved_udw.bad", PI_PROTOCOL, PI_WARN,
1586
16
            "Reserved ST 2016-3 UDW is not zero", EXPFILL } },
1587
16
        { &ei_st2016_3_bar_reserved,
1588
16
          { "st2016_3.bar.reserved.bad", PI_PROTOCOL, PI_WARN,
1589
16
            "Reserved Bar Data flag bits are not zero", EXPFILL } },
1590
16
        { &ei_st2016_3_bar_flags_invalid,
1591
16
          { "st2016_3.bar.flags.invalid", PI_PROTOCOL, PI_WARN,
1592
16
            "Bar Data flags must specify Top+Bottom, Left+Right, or no bars", EXPFILL } },
1593
16
        { &ei_st2016_3_bar_marker,
1594
16
          { "st2016_3.bar.marker.bad", PI_PROTOCOL, PI_WARN,
1595
16
            "Bar Data value marker bits are not binary '11'", EXPFILL } },
1596
16
    };
1597
1598
16
    expert_module_t *expert_st2016_3;
1599
1600
16
    proto_st2016_3 = proto_register_protocol(
1601
16
        "SMPTE ST 2016-3 AFD and Bar Data", "ST 2016-3", "st2016_3");
1602
1603
16
    proto_register_field_array(proto_st2016_3, hf, array_length(hf));
1604
16
    proto_register_subtree_array(ett, array_length(ett));
1605
1606
16
    expert_st2016_3 = expert_register_protocol(proto_st2016_3);
1607
16
    expert_register_field_array(expert_st2016_3, ei, array_length(ei));
1608
1609
16
    st2016_3_handle =
1610
16
        register_dissector("st2016_3", dissect_st2016_3, proto_st2016_3);
1611
16
}
1612
1613
void
1614
proto_reg_handoff_st2016_3(void)
1615
16
{
1616
16
    dissector_add_uint("st291.did_sdid", ST2016_3_DID_SDID_KEY, st2016_3_handle);
1617
16
}
1618
1619
/*
1620
 * SMPTE ST 334-2 Caption Distribution Packet
1621
 */
1622
1623
1624
/* SMPTE ST 334-2:2015, Sec. 5.2, Table 3 -- cdp_frame_rate values. */
1625
static const value_string st334_2_frame_rate_vals[] = {
1626
    { 0x0, "Forbidden" },
1627
    { 0x1, "24000/1001 (~23.976 fps)" },
1628
    { 0x2, "24 fps" },
1629
    { 0x3, "25 fps" },
1630
    { 0x4, "30000/1001 (~29.97 fps)" },
1631
    { 0x5, "30 fps" },
1632
    { 0x6, "50 fps" },
1633
    { 0x7, "60000/1001 (~59.94 fps)" },
1634
    { 0x8, "60 fps" },
1635
    { 0, NULL }
1636
};
1637
1638
/* SMPTE ST 334-2:2015, Sec. 5.1, Table 1; Secs. 5.3-5.7 -- CDP section IDs. */
1639
static const value_string st334_2_section_id_vals[] = {
1640
    { 0x71, "Time Code Section" },
1641
    { 0x72, "CC Data Section" },
1642
    { 0x73, "CC Service Information Section" },
1643
    { 0x74, "CDP Footer" },
1644
    { 0, NULL }
1645
};
1646
1647
/* SMPTE ST 334-2:2015, Sec. 5.4, Table 5; cc_type semantics are inherited from CEA-708. */
1648
static const value_string st334_2_cc_type_vals[] = {
1649
    { 0x0, "NTSC line 21 field 1 closed captions (CEA-608)" },
1650
    { 0x1, "NTSC line 21 field 2 closed captions (CEA-608)" },
1651
    { 0x2, "DTVCC channel packet data" },
1652
    { 0x3, "DTVCC channel packet start" },
1653
    { 0, NULL }
1654
};
1655
1656
static const struct true_false_string st334_2_tfs_present = {
1657
    "Present", "Not present"
1658
};
1659
1660
static const struct true_false_string st334_2_tfs_valid = {
1661
    "Valid", "Invalid"
1662
};
1663
1664
/* SMPTE ST 334-2:2015, Sec. 5.4, Table 5 -- required cc_count for each cdp_frame_rate. */
1665
static unsigned
1666
st334_2_expected_cc_count(uint8_t frame_rate)
1667
0
{
1668
0
    switch (frame_rate) {
1669
0
    case 0x1:
1670
0
    case 0x2:
1671
0
        return 25;
1672
0
    case 0x3:
1673
0
        return 24;
1674
0
    case 0x4:
1675
0
    case 0x5:
1676
0
        return 20;
1677
0
    case 0x6:
1678
0
        return 12;
1679
0
    case 0x7:
1680
0
    case 0x8:
1681
0
        return 10;
1682
0
    default:
1683
0
        return 0;
1684
0
    }
1685
0
}
1686
1687
/* SMPTE ST 334-2:2015, Sec. 5.6, Table 7 -- CDP checksum makes the modulo-256 packet sum zero. */
1688
static uint8_t
1689
st334_2_cdp_checksum(tvbuff_t *tvb, unsigned length)
1690
0
{
1691
0
    unsigned i;
1692
0
    uint8_t sum = 0;
1693
1694
0
    for (i = 0; i < length; i++)
1695
0
        sum = (uint8_t)(sum + tvb_get_uint8(tvb, i));
1696
1697
0
    return sum;
1698
0
}
1699
1700
/* SMPTE ST 334-2:2015, Sec. 5.1, Table 1 -- required CDP section ordering. */
1701
static unsigned
1702
st334_2_section_rank(uint8_t id)
1703
0
{
1704
0
    switch (id) {
1705
0
    case 0x71: return 1;
1706
0
    case 0x72: return 2;
1707
0
    case 0x73: return 3;
1708
0
    case 0x74: return 5;
1709
0
    default:
1710
0
        if (id >= 0x75 && id <= 0xef)
1711
0
            return 4;
1712
0
        return 0;
1713
0
    }
1714
0
}
1715
1716
/* SMPTE ST 334-2:2015, Sec. 5, Tables 1-8 -- complete CDP syntax. */
1717
static int
1718
dissect_st334_2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
1719
0
{
1720
0
    const st291_vanc_dissector_data_t *st291_data =
1721
0
        (const st291_vanc_dissector_data_t *)data;
1722
0
    proto_tree *top_tree = st291_data && st291_data->top_tree ?
1723
0
        st291_data->top_tree : tree;
1724
0
    proto_item *ti;
1725
0
    proto_item *root_ti;
1726
0
    proto_tree *cdp_tree;
1727
0
    proto_tree *header_tree;
1728
0
    unsigned captured_len = tvb_captured_length(tvb);
1729
0
    unsigned parse_len;
1730
0
    unsigned offset;
1731
0
    unsigned previous_rank = 0;
1732
0
    uint16_t identifier;
1733
0
    uint8_t declared_len;
1734
0
    uint8_t frame_rate;
1735
0
    uint8_t flags;
1736
0
    uint16_t header_sequence;
1737
0
    bool time_present;
1738
0
    bool cc_present;
1739
0
    bool svc_present;
1740
0
    bool seen_time = false;
1741
0
    bool seen_cc = false;
1742
0
    bool seen_svc = false;
1743
0
    bool seen_footer = false;
1744
1745
0
    ti = proto_tree_add_item(top_tree, proto_st334_2, tvb, 0, -1, ENC_NA);
1746
0
    cdp_tree = proto_item_add_subtree(ti, ett_st334_2);
1747
1748
0
    if (captured_len < 7) {
1749
0
        expert_add_info_format(pinfo, ti, &ei_st334_2_bad_length,
1750
0
                               "ST 334-2 requires at least 7 UDW bytes; packet contains %u",
1751
0
                               captured_len);
1752
0
        return captured_len;
1753
0
    }
1754
1755
0
    identifier = tvb_get_ntohs(tvb, 0);
1756
0
    declared_len = tvb_get_uint8(tvb, 2);
1757
0
    frame_rate = (tvb_get_uint8(tvb, 3) >> 4) & 0x0f;
1758
0
    flags = tvb_get_uint8(tvb, 4);
1759
0
    header_sequence = tvb_get_ntohs(tvb, 5);
1760
1761
0
    if (declared_len < 7 || declared_len > captured_len)
1762
0
        parse_len = captured_len;
1763
0
    else
1764
0
        parse_len = declared_len;
1765
1766
0
    root_ti = ti;
1767
0
    proto_item_set_len(ti, parse_len);
1768
0
    proto_item_append_text(ti, ", sequence %u", header_sequence);
1769
1770
    /* SMPTE ST 334-2:2015, Sec. 5.2, Tables 2-3 -- cdp_header(). */
1771
0
    header_tree = proto_tree_add_subtree(cdp_tree, tvb, 0, 7,
1772
0
                                         ett_st334_2_header, NULL, "CDP Header");
1773
1774
0
    ti = proto_tree_add_item(header_tree, hf_st334_2_cdp_identifier, tvb, 0, 2, ENC_BIG_ENDIAN);
1775
0
    if (identifier != ST334_2_CDP_IDENTIFIER)
1776
0
        expert_add_info_format(pinfo, ti, &ei_st334_2_bad_identifier,
1777
0
                               "CDP identifier is 0x%04x; expected 0x%04x",
1778
0
                               identifier, ST334_2_CDP_IDENTIFIER);
1779
1780
0
    ti = proto_tree_add_item(header_tree, hf_st334_2_cdp_length, tvb, 2, 1, ENC_BIG_ENDIAN);
1781
0
    if (declared_len != captured_len)
1782
0
        expert_add_info_format(pinfo, ti, &ei_st334_2_bad_length,
1783
0
                               "CDP length is %u bytes, but ST 291 UDW payload contains %u bytes",
1784
0
                               declared_len, captured_len);
1785
1786
0
    proto_tree_add_item(header_tree, hf_st334_2_frame_rate, tvb, 3, 1, ENC_BIG_ENDIAN);
1787
0
    ti = proto_tree_add_item(header_tree, hf_st334_2_header_reserved, tvb, 3, 1, ENC_BIG_ENDIAN);
1788
0
    if ((tvb_get_uint8(tvb, 3) & 0x0f) != 0x0f)
1789
0
        expert_add_info(pinfo, ti, &ei_st334_2_bad_reserved);
1790
1791
0
    proto_tree_add_item(header_tree, hf_st334_2_time_code_present, tvb, 4, 1, ENC_BIG_ENDIAN);
1792
0
    proto_tree_add_item(header_tree, hf_st334_2_ccdata_present, tvb, 4, 1, ENC_BIG_ENDIAN);
1793
0
    proto_tree_add_item(header_tree, hf_st334_2_svcinfo_present, tvb, 4, 1, ENC_BIG_ENDIAN);
1794
0
    proto_tree_add_item(header_tree, hf_st334_2_svc_info_start, tvb, 4, 1, ENC_BIG_ENDIAN);
1795
0
    proto_tree_add_item(header_tree, hf_st334_2_svc_info_change, tvb, 4, 1, ENC_BIG_ENDIAN);
1796
0
    proto_tree_add_item(header_tree, hf_st334_2_svc_info_complete, tvb, 4, 1, ENC_BIG_ENDIAN);
1797
0
    proto_tree_add_item(header_tree, hf_st334_2_caption_service_active, tvb, 4, 1, ENC_BIG_ENDIAN);
1798
0
    ti = proto_tree_add_item(header_tree, hf_st334_2_header_reserved_bit, tvb, 4, 1, ENC_BIG_ENDIAN);
1799
0
    if ((flags & 0x01) == 0)
1800
0
        expert_add_info(pinfo, ti, &ei_st334_2_bad_reserved);
1801
1802
0
    proto_tree_add_item(header_tree, hf_st334_2_header_sequence_counter, tvb, 5, 2, ENC_BIG_ENDIAN);
1803
1804
0
    time_present = (flags & 0x80) != 0;
1805
0
    cc_present = (flags & 0x40) != 0;
1806
0
    svc_present = (flags & 0x20) != 0;
1807
1808
0
    offset = 7;
1809
0
    while (offset < parse_len) {
1810
0
        uint8_t id;
1811
0
        unsigned rank;
1812
0
        unsigned section_len = 0;
1813
1814
0
        if (!tvb_bytes_exist(tvb, offset, 1))
1815
0
            break;
1816
1817
0
        id = tvb_get_uint8(tvb, offset);
1818
0
        rank = st334_2_section_rank(id);
1819
1820
0
        if (rank != 0 && rank < previous_rank) {
1821
0
            ti = proto_tree_add_item(cdp_tree, hf_st334_2_section_id, tvb, offset, 1, ENC_BIG_ENDIAN);
1822
0
            expert_add_info(pinfo, ti, &ei_st334_2_bad_section_order);
1823
0
        }
1824
0
        if (rank != 0 && rank > previous_rank)
1825
0
            previous_rank = rank;
1826
1827
        /* SMPTE ST 334-2:2015, Sec. 5.3, Table 4 -- time_code_section(). */
1828
0
        if (id == 0x71) {
1829
0
            proto_tree *section_tree;
1830
0
            uint8_t b1, b2, b3, b4;
1831
0
            unsigned hours, minutes, seconds, frames;
1832
0
            char time_str[48];
1833
1834
0
            if (!tvb_bytes_exist(tvb, offset, 5) || offset + 5 > parse_len) {
1835
0
                expert_add_info_format(pinfo, root_ti, &ei_st334_2_truncated,
1836
0
                                       "Truncated CDP time code section");
1837
0
                break;
1838
0
            }
1839
0
            section_len = 5;
1840
0
            section_tree = proto_tree_add_subtree(cdp_tree, tvb, offset, section_len,
1841
0
                                                  ett_st334_2_timecode, NULL, "Time Code Section");
1842
0
            ti = proto_tree_add_item(section_tree, hf_st334_2_section_id, tvb, offset, 1, ENC_BIG_ENDIAN);
1843
0
            if (seen_time)
1844
0
                expert_add_info(pinfo, ti, &ei_st334_2_duplicate_section);
1845
0
            seen_time = true;
1846
1847
0
            b1 = tvb_get_uint8(tvb, offset + 1);
1848
0
            b2 = tvb_get_uint8(tvb, offset + 2);
1849
0
            b3 = tvb_get_uint8(tvb, offset + 3);
1850
0
            b4 = tvb_get_uint8(tvb, offset + 4);
1851
1852
0
            hours = ((b1 >> 4) & 0x03) * 10 + (b1 & 0x0f);
1853
0
            minutes = ((b2 >> 4) & 0x07) * 10 + (b2 & 0x0f);
1854
0
            seconds = ((b3 >> 4) & 0x07) * 10 + (b3 & 0x0f);
1855
0
            frames = ((b4 >> 4) & 0x03) * 10 + (b4 & 0x0f);
1856
0
            snprintf(time_str, sizeof(time_str), "%02u:%02u:%02u:%02u",
1857
0
                       hours, minutes, seconds, frames);
1858
0
            ti = proto_tree_add_string(section_tree, hf_st334_2_timecode, tvb, offset + 1, 4, time_str);
1859
0
            proto_item_set_generated(ti);
1860
0
            proto_tree_add_item(section_tree, hf_st334_2_tc_field_flag, tvb, offset + 3, 1, ENC_BIG_ENDIAN);
1861
0
            proto_tree_add_item(section_tree, hf_st334_2_drop_frame_flag, tvb, offset + 4, 1, ENC_BIG_ENDIAN);
1862
0
        } else if (id == 0x72) {
1863
            /* SMPTE ST 334-2:2015, Sec. 5.4, Table 5 -- ccdata_section(). */
1864
0
            proto_tree *section_tree;
1865
0
            unsigned count;
1866
0
            unsigned expected;
1867
0
            unsigned i;
1868
0
            unsigned dtvcc_len = 0;
1869
0
            uint8_t *dtvcc_data;
1870
1871
0
            if (!tvb_bytes_exist(tvb, offset, 2) || offset + 2 > parse_len) {
1872
0
                expert_add_info_format(pinfo, root_ti, &ei_st334_2_truncated,
1873
0
                                       "Truncated CDP CC data section header");
1874
0
                break;
1875
0
            }
1876
0
            count = tvb_get_uint8(tvb, offset + 1) & 0x1f;
1877
0
            section_len = 2 + 3 * count;
1878
0
            if (!tvb_bytes_exist(tvb, offset, section_len) || offset + section_len > parse_len) {
1879
0
                expert_add_info_format(pinfo, root_ti, &ei_st334_2_truncated,
1880
0
                                       "CC data section requires %u bytes but packet ends early",
1881
0
                                       section_len);
1882
0
                break;
1883
0
            }
1884
1885
0
            section_tree = proto_tree_add_subtree(cdp_tree, tvb, offset, section_len,
1886
0
                                                  ett_st334_2_ccdata, NULL, "CC Data Section");
1887
0
            ti = proto_tree_add_item(section_tree, hf_st334_2_section_id, tvb, offset, 1, ENC_BIG_ENDIAN);
1888
0
            if (seen_cc)
1889
0
                expert_add_info(pinfo, ti, &ei_st334_2_duplicate_section);
1890
0
            seen_cc = true;
1891
1892
0
            ti = proto_tree_add_item(section_tree, hf_st334_2_cc_count, tvb, offset + 1, 1, ENC_BIG_ENDIAN);
1893
0
            if ((tvb_get_uint8(tvb, offset + 1) & 0xe0) != 0xe0)
1894
0
                expert_add_info(pinfo, ti, &ei_st334_2_bad_marker);
1895
1896
0
            expected = st334_2_expected_cc_count(frame_rate);
1897
0
            if (expected != 0 && count != expected)
1898
0
                expert_add_info_format(pinfo, ti, &ei_st334_2_cc_count,
1899
0
                                       "cc_count is %u; frame-rate code 0x%x requires %u",
1900
0
                                       count, frame_rate, expected);
1901
1902
0
            dtvcc_data = wmem_alloc(pinfo->pool, MAX(1U, count * 2));
1903
0
            for (i = 0; i < count; i++) {
1904
0
                unsigned c_off = offset + 2 + i * 3;
1905
0
                uint8_t type_byte = tvb_get_uint8(tvb, c_off);
1906
0
                uint8_t cc_type = type_byte & 0x03;
1907
0
                proto_tree *construct_tree;
1908
1909
0
                construct_tree = proto_tree_add_subtree_format(
1910
0
                    section_tree, tvb, c_off, 3, ett_st334_2_cc_construct, NULL,
1911
0
                    "CC Construct %u: %s", i + 1,
1912
0
                    val_to_str_const(cc_type, st334_2_cc_type_vals, "Unknown"));
1913
0
                ti = proto_tree_add_item(construct_tree, hf_st334_2_cc_marker_bits, tvb, c_off, 1, ENC_BIG_ENDIAN);
1914
0
                if ((type_byte & 0xf8) != 0xf8)
1915
0
                    expert_add_info(pinfo, ti, &ei_st334_2_bad_marker);
1916
0
                proto_tree_add_item(construct_tree, hf_st334_2_cc_valid, tvb, c_off, 1, ENC_BIG_ENDIAN);
1917
0
                proto_tree_add_item(construct_tree, hf_st334_2_cc_type, tvb, c_off, 1, ENC_BIG_ENDIAN);
1918
0
                proto_tree_add_item(construct_tree, hf_st334_2_cc_data_1, tvb, c_off + 1, 1, ENC_BIG_ENDIAN);
1919
0
                proto_tree_add_item(construct_tree, hf_st334_2_cc_data_2, tvb, c_off + 2, 1, ENC_BIG_ENDIAN);
1920
1921
0
                if ((type_byte & 0x04) != 0 && (cc_type == 2 || cc_type == 3)) {
1922
0
                    dtvcc_data[dtvcc_len++] = tvb_get_uint8(tvb, c_off + 1);
1923
0
                    dtvcc_data[dtvcc_len++] = tvb_get_uint8(tvb, c_off + 2);
1924
0
                }
1925
0
            }
1926
0
            if (dtvcc_len != 0) {
1927
0
                tvbuff_t *dtvcc_tvb;
1928
1929
0
                dtvcc_tvb = tvb_new_child_real_data(tvb, dtvcc_data,
1930
0
                                                     dtvcc_len, dtvcc_len);
1931
                /* ST 334-2:2015, Sec. 5.4, Table 5: concatenate valid cc_type 2/3 constructs for CEA-708 decoding. */
1932
0
                add_new_data_source(pinfo, dtvcc_tvb, "CEA-708 DTVCC Data");
1933
0
                ti = proto_tree_add_item(section_tree, hf_st334_2_dtvcc_data,
1934
0
                                         dtvcc_tvb, 0, dtvcc_len, ENC_NA);
1935
0
                proto_item_set_generated(ti);
1936
0
            }
1937
0
        } else if (id == 0x73) {
1938
            /* SMPTE ST 334-2:2015, Sec. 5.5, Table 6 -- ccsvcinfo_section(). */
1939
0
            proto_tree *section_tree;
1940
0
            uint8_t svc_flags;
1941
0
            unsigned count;
1942
0
            unsigned i;
1943
1944
0
            if (!tvb_bytes_exist(tvb, offset, 2) || offset + 2 > parse_len) {
1945
0
                expert_add_info_format(pinfo, root_ti, &ei_st334_2_truncated,
1946
0
                                       "Truncated CDP service information section header");
1947
0
                break;
1948
0
            }
1949
0
            svc_flags = tvb_get_uint8(tvb, offset + 1);
1950
0
            count = svc_flags & 0x0f;
1951
0
            section_len = 2 + 7 * count;
1952
0
            if (!tvb_bytes_exist(tvb, offset, section_len) || offset + section_len > parse_len) {
1953
0
                expert_add_info_format(pinfo, root_ti, &ei_st334_2_truncated,
1954
0
                                       "Service information section requires %u bytes but packet ends early",
1955
0
                                       section_len);
1956
0
                break;
1957
0
            }
1958
1959
0
            section_tree = proto_tree_add_subtree(cdp_tree, tvb, offset, section_len,
1960
0
                                                  ett_st334_2_svcinfo, NULL,
1961
0
                                                  "CC Service Information Section");
1962
0
            ti = proto_tree_add_item(section_tree, hf_st334_2_section_id, tvb, offset, 1, ENC_BIG_ENDIAN);
1963
0
            if (seen_svc)
1964
0
                expert_add_info(pinfo, ti, &ei_st334_2_duplicate_section);
1965
0
            seen_svc = true;
1966
1967
0
            ti = proto_tree_add_item(section_tree, hf_st334_2_svc_reserved, tvb, offset + 1, 1, ENC_BIG_ENDIAN);
1968
0
            if ((svc_flags & 0x80) == 0)
1969
0
                expert_add_info(pinfo, ti, &ei_st334_2_bad_reserved);
1970
0
            proto_tree_add_item(section_tree, hf_st334_2_svc_info_start_section, tvb, offset + 1, 1, ENC_BIG_ENDIAN);
1971
0
            proto_tree_add_item(section_tree, hf_st334_2_svc_info_change_section, tvb, offset + 1, 1, ENC_BIG_ENDIAN);
1972
0
            proto_tree_add_item(section_tree, hf_st334_2_svc_info_complete_section, tvb, offset + 1, 1, ENC_BIG_ENDIAN);
1973
0
            proto_tree_add_item(section_tree, hf_st334_2_svc_count, tvb, offset + 1, 1, ENC_BIG_ENDIAN);
1974
1975
0
            if (((flags >> 2) & 0x07) != ((svc_flags >> 4) & 0x07)) {
1976
0
                expert_add_info_format(pinfo, ti, &ei_st334_2_bad_reserved,
1977
0
                                       "Service-info start/change/complete flags do not match CDP header");
1978
0
            }
1979
1980
0
            for (i = 0; i < count; i++) {
1981
0
                unsigned s_off = offset + 2 + i * 7;
1982
0
                uint8_t first = tvb_get_uint8(tvb, s_off);
1983
0
                unsigned service_number;
1984
0
                uint8_t type_byte;
1985
0
                bool digital_cc;
1986
0
                proto_tree *service_tree;
1987
0
                proto_tree *data_tree;
1988
1989
0
                service_tree = proto_tree_add_subtree_format(
1990
0
                    section_tree, tvb, s_off, 7, ett_st334_2_service, NULL,
1991
0
                    "Caption Service %u", i + 1);
1992
0
                ti = proto_tree_add_item(service_tree, hf_st334_2_csn_reserved, tvb, s_off, 1, ENC_BIG_ENDIAN);
1993
0
                if ((first & 0x80) == 0)
1994
0
                    expert_add_info(pinfo, ti, &ei_st334_2_bad_reserved);
1995
0
                proto_tree_add_item(service_tree, hf_st334_2_csn_size, tvb, s_off, 1, ENC_BIG_ENDIAN);
1996
0
                if ((first & 0x40) != 0) {
1997
0
                    ti = proto_tree_add_item(service_tree, hf_st334_2_csn_reserved_2, tvb, s_off, 1, ENC_BIG_ENDIAN);
1998
0
                    if ((first & 0x20) == 0)
1999
0
                        expert_add_info(pinfo, ti, &ei_st334_2_bad_reserved);
2000
0
                    service_number = first & 0x1f;
2001
0
                } else {
2002
0
                    service_number = first & 0x3f;
2003
0
                }
2004
0
                proto_tree_add_uint(service_tree, hf_st334_2_caption_service_number,
2005
0
                                    tvb, s_off, 1, service_number);
2006
2007
                /*
2008
                 * SMPTE ST 334-2:2015, Sec. 5.5, Table 6 defines
2009
                 * svc_data_byte_1 through svc_data_byte_6 as one service
2010
                 * entry encoded according to the caption service descriptor
2011
                 * loop in ATSC A/65:2013, Sec. 6.9.2, Table 6.26.
2012
                 */
2013
0
                type_byte = tvb_get_uint8(tvb, s_off + 4);
2014
0
                digital_cc = (type_byte & 0x80) != 0;
2015
2016
0
                data_tree = proto_tree_add_subtree(
2017
0
                    service_tree, tvb, s_off + 1, 6,
2018
0
                    ett_st334_2_service_data, NULL, "Service Data");
2019
2020
0
                proto_tree_add_item(data_tree, hf_st334_2_service_language,
2021
0
                                    tvb, s_off + 1, 3, ENC_ASCII);
2022
0
                proto_tree_add_item(data_tree, hf_st334_2_service_digital_cc,
2023
0
                                    tvb, s_off + 4, 1, ENC_BIG_ENDIAN);
2024
2025
0
                if (digital_cc) {
2026
0
                    proto_tree_add_item(data_tree, hf_st334_2_service_digital_reserved,
2027
0
                                        tvb, s_off + 4, 1, ENC_BIG_ENDIAN);
2028
0
                    proto_tree_add_item(data_tree, hf_st334_2_service_descriptor_number,
2029
0
                                        tvb, s_off + 4, 1, ENC_BIG_ENDIAN);
2030
0
                } else {
2031
0
                    proto_tree_add_item(data_tree, hf_st334_2_service_line21_reserved,
2032
0
                                        tvb, s_off + 4, 1, ENC_BIG_ENDIAN);
2033
0
                    proto_tree_add_item(data_tree, hf_st334_2_service_line21_field,
2034
0
                                        tvb, s_off + 4, 1, ENC_BIG_ENDIAN);
2035
0
                }
2036
2037
0
                proto_tree_add_item(data_tree, hf_st334_2_service_easy_reader,
2038
0
                                    tvb, s_off + 5, 1, ENC_BIG_ENDIAN);
2039
0
                proto_tree_add_item(data_tree, hf_st334_2_service_wide_aspect_ratio,
2040
0
                                    tvb, s_off + 5, 1, ENC_BIG_ENDIAN);
2041
0
                ti = proto_tree_add_item(data_tree, hf_st334_2_service_reserved_14,
2042
0
                                         tvb, s_off + 5, 2, ENC_BIG_ENDIAN);
2043
0
                if ((tvb_get_ntohs(tvb, s_off + 5) & 0x3fff) != 0x3fff)
2044
0
                    expert_add_info(pinfo, ti, &ei_st334_2_bad_reserved);
2045
0
            }
2046
0
        } else if (id == 0x74) {
2047
            /* SMPTE ST 334-2:2015, Sec. 5.6, Table 7 -- cdp_footer(). */
2048
0
            proto_tree *section_tree;
2049
0
            uint16_t footer_sequence;
2050
0
            uint8_t sum;
2051
0
            proto_item *checksum_item;
2052
2053
0
            section_len = 4;
2054
0
            if (!tvb_bytes_exist(tvb, offset, section_len) || offset + section_len > parse_len) {
2055
0
                expert_add_info_format(pinfo, root_ti, &ei_st334_2_truncated,
2056
0
                                       "Truncated CDP footer");
2057
0
                break;
2058
0
            }
2059
2060
0
            section_tree = proto_tree_add_subtree(cdp_tree, tvb, offset, section_len,
2061
0
                                                  ett_st334_2_footer, NULL, "CDP Footer");
2062
0
            ti = proto_tree_add_item(section_tree, hf_st334_2_section_id, tvb, offset, 1, ENC_BIG_ENDIAN);
2063
0
            if (seen_footer)
2064
0
                expert_add_info(pinfo, ti, &ei_st334_2_duplicate_section);
2065
0
            seen_footer = true;
2066
2067
0
            footer_sequence = tvb_get_ntohs(tvb, offset + 1);
2068
0
            ti = proto_tree_add_item(section_tree, hf_st334_2_footer_sequence_counter,
2069
0
                                     tvb, offset + 1, 2, ENC_BIG_ENDIAN);
2070
0
            if (footer_sequence != header_sequence)
2071
0
                expert_add_info_format(pinfo, ti, &ei_st334_2_sequence_mismatch,
2072
0
                                       "Footer sequence %u does not match header sequence %u",
2073
0
                                       footer_sequence, header_sequence);
2074
2075
0
            checksum_item = proto_tree_add_item(section_tree, hf_st334_2_packet_checksum,
2076
0
                                                tvb, offset + 3, 1, ENC_BIG_ENDIAN);
2077
0
            if (parse_len == declared_len && offset + 4 == parse_len) {
2078
0
                sum = st334_2_cdp_checksum(tvb, parse_len);
2079
0
                ti = proto_tree_add_uint(section_tree, hf_st334_2_checksum_calculated,
2080
0
                                         tvb, 0, 0,
2081
0
                                         (uint8_t)(tvb_get_uint8(tvb, offset + 3) - sum));
2082
0
                proto_item_set_generated(ti);
2083
0
                if (sum != 0)
2084
0
                    expert_add_info_format(pinfo, checksum_item, &ei_st334_2_bad_checksum,
2085
0
                                           "CDP checksum does not make packet sum modulo 256 equal zero (sum 0x%02x)",
2086
0
                                           sum);
2087
0
            }
2088
            //offset += section_len;
2089
0
            break;
2090
0
        } else if (id >= 0x75 && id <= 0xef) {
2091
            /* SMPTE ST 334-2:2015, Sec. 5.7, Table 8 -- future_section(). */
2092
0
            proto_tree *section_tree;
2093
0
            unsigned future_len;
2094
2095
0
            if (!tvb_bytes_exist(tvb, offset, 2) || offset + 2 > parse_len) {
2096
0
                expert_add_info_format(pinfo, root_ti, &ei_st334_2_truncated,
2097
0
                                       "Truncated future CDP section header");
2098
0
                break;
2099
0
            }
2100
0
            future_len = tvb_get_uint8(tvb, offset + 1);
2101
0
            section_len = 2 + future_len;
2102
0
            if (!tvb_bytes_exist(tvb, offset, section_len) || offset + section_len > parse_len) {
2103
0
                expert_add_info_format(pinfo, root_ti, &ei_st334_2_truncated,
2104
0
                                       "Future CDP section requires %u bytes but packet ends early",
2105
0
                                       section_len);
2106
0
                break;
2107
0
            }
2108
0
            section_tree = proto_tree_add_subtree_format(
2109
0
                cdp_tree, tvb, offset, section_len, ett_st334_2_future, NULL,
2110
0
                "Unknown/Future CDP Section 0x%02x", id);
2111
0
            proto_tree_add_item(section_tree, hf_st334_2_section_id, tvb, offset, 1, ENC_BIG_ENDIAN);
2112
0
            proto_tree_add_item(section_tree, hf_st334_2_future_length, tvb, offset + 1, 1, ENC_BIG_ENDIAN);
2113
0
            if (future_len != 0)
2114
0
                proto_tree_add_item(section_tree, hf_st334_2_future_data, tvb, offset + 2,
2115
0
                                    future_len, ENC_NA);
2116
0
        } else {
2117
0
            ti = proto_tree_add_item(cdp_tree, hf_st334_2_section_id, tvb, offset, 1, ENC_BIG_ENDIAN);
2118
0
            expert_add_info_format(pinfo, ti, &ei_st334_2_bad_section_order,
2119
0
                                   "Unknown CDP section identifier 0x%02x cannot be safely skipped",
2120
0
                                   id);
2121
0
            break;
2122
0
        }
2123
2124
0
        offset += section_len;
2125
0
    }
2126
2127
0
    if (time_present != seen_time)
2128
0
        expert_add_info_format(pinfo, root_ti, &ei_st334_2_missing_section,
2129
0
                               "CDP header time_code_present=%u but time-code section %s",
2130
0
                               time_present, seen_time ? "is present" : "is absent");
2131
0
    if (cc_present != seen_cc)
2132
0
        expert_add_info_format(pinfo, root_ti, &ei_st334_2_missing_section,
2133
0
                               "CDP header ccdata_present=%u but CC-data section %s",
2134
0
                               cc_present, seen_cc ? "is present" : "is absent");
2135
0
    if (svc_present != seen_svc)
2136
0
        expert_add_info_format(pinfo, root_ti, &ei_st334_2_missing_section,
2137
0
                               "CDP header svcinfo_present=%u but service-info section %s",
2138
0
                               svc_present, seen_svc ? "is present" : "is absent");
2139
0
    if (!seen_footer)
2140
0
        expert_add_info_format(pinfo, root_ti, &ei_st334_2_missing_section,
2141
0
                               "Required CDP footer is absent");
2142
2143
0
    return captured_len;
2144
0
}
2145
2146
void
2147
proto_register_st334_2(void)
2148
16
{
2149
16
    static hf_register_info hf[] = {
2150
16
        { &hf_st334_2_cdp_identifier,
2151
16
          { "CDP Identifier", "st334_2.cdp.identifier", FT_UINT16, BASE_HEX, NULL, 0x0, NULL,
2152
16
            HFILL } },
2153
16
        { &hf_st334_2_cdp_length,
2154
16
          { "CDP Length", "st334_2.cdp.length", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } },
2155
16
        { &hf_st334_2_frame_rate,
2156
16
          { "CDP Frame Rate", "st334_2.cdp.frame_rate", FT_UINT8, BASE_HEX,
2157
16
            VALS(st334_2_frame_rate_vals), 0xf0, NULL, HFILL } },
2158
16
        { &hf_st334_2_header_reserved,
2159
16
          { "Reserved", "st334_2.cdp.header.reserved", FT_UINT8, BASE_HEX, NULL, 0x0f, NULL,
2160
16
            HFILL } },
2161
16
        { &hf_st334_2_time_code_present,
2162
16
          { "Time Code", "st334_2.cdp.time_code_present", FT_BOOLEAN, 8,
2163
16
            TFS(&st334_2_tfs_present), 0x80, NULL, HFILL } },
2164
16
        { &hf_st334_2_ccdata_present,
2165
16
          { "CC Data", "st334_2.cdp.ccdata_present", FT_BOOLEAN, 8, TFS(&st334_2_tfs_present),
2166
16
            0x40, NULL, HFILL } },
2167
16
        { &hf_st334_2_svcinfo_present,
2168
16
          { "Service Information", "st334_2.cdp.svcinfo_present", FT_BOOLEAN, 8,
2169
16
            TFS(&st334_2_tfs_present), 0x20, NULL, HFILL } },
2170
16
        { &hf_st334_2_svc_info_start,
2171
16
          { "Service Info Start", "st334_2.cdp.svc_info_start", FT_BOOLEAN, 8, NULL, 0x10,
2172
16
            NULL, HFILL } },
2173
16
        { &hf_st334_2_svc_info_change,
2174
16
          { "Service Info Change", "st334_2.cdp.svc_info_change", FT_BOOLEAN, 8, NULL, 0x08,
2175
16
            NULL, HFILL } },
2176
16
        { &hf_st334_2_svc_info_complete,
2177
16
          { "Service Info Complete", "st334_2.cdp.svc_info_complete", FT_BOOLEAN, 8, NULL,
2178
16
            0x04, NULL, HFILL } },
2179
16
        { &hf_st334_2_caption_service_active,
2180
16
          { "Caption Service Active", "st334_2.cdp.caption_service_active", FT_BOOLEAN, 8,
2181
16
            NULL, 0x02, NULL, HFILL } },
2182
16
        { &hf_st334_2_header_reserved_bit,
2183
16
          { "Reserved", "st334_2.cdp.header.reserved_bit", FT_BOOLEAN, 8, NULL, 0x01, NULL,
2184
16
            HFILL } },
2185
16
        { &hf_st334_2_header_sequence_counter,
2186
16
          { "Header Sequence Counter", "st334_2.cdp.header_sequence", FT_UINT16, BASE_DEC,
2187
16
            NULL, 0x0, NULL, HFILL } },
2188
16
        { &hf_st334_2_section_id,
2189
16
          { "Section ID", "st334_2.section.id", FT_UINT8, BASE_HEX,
2190
16
            VALS(st334_2_section_id_vals), 0x0, NULL, HFILL } },
2191
16
        { &hf_st334_2_timecode,
2192
16
          { "Time Code", "st334_2.timecode", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } },
2193
16
        { &hf_st334_2_tc_field_flag,
2194
16
          { "Field Flag", "st334_2.timecode.field_flag", FT_BOOLEAN, 8, NULL, 0x80, NULL,
2195
16
            HFILL } },
2196
16
        { &hf_st334_2_drop_frame_flag,
2197
16
          { "Drop Frame", "st334_2.timecode.drop_frame", FT_BOOLEAN, 8, NULL, 0x80, NULL,
2198
16
            HFILL } },
2199
16
        { &hf_st334_2_cc_count,
2200
16
          { "CC Count", "st334_2.ccdata.count", FT_UINT8, BASE_DEC, NULL, 0x1f, NULL, HFILL } },
2201
16
        { &hf_st334_2_cc_marker_bits,
2202
16
          { "Marker Bits", "st334_2.ccdata.marker", FT_UINT8, BASE_HEX, NULL, 0xf8, NULL,
2203
16
            HFILL } },
2204
16
        { &hf_st334_2_cc_valid,
2205
16
          { "CC Valid", "st334_2.ccdata.valid", FT_BOOLEAN, 8, TFS(&st334_2_tfs_valid), 0x04,
2206
16
            NULL, HFILL } },
2207
16
        { &hf_st334_2_cc_type,
2208
16
          { "CC Type", "st334_2.ccdata.type", FT_UINT8, BASE_DEC, VALS(st334_2_cc_type_vals),
2209
16
            0x03, NULL, HFILL } },
2210
16
        { &hf_st334_2_cc_data_1,
2211
16
          { "CC Data 1", "st334_2.ccdata.data1", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } },
2212
16
        { &hf_st334_2_cc_data_2,
2213
16
          { "CC Data 2", "st334_2.ccdata.data2", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } },
2214
16
        { &hf_st334_2_dtvcc_data,
2215
16
          { "DTVCC Data", "st334_2.ccdata.dtvcc", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
2216
16
        { &hf_st334_2_svc_reserved,
2217
16
          { "Reserved", "st334_2.svcinfo.reserved", FT_BOOLEAN, 8, NULL, 0x80, NULL, HFILL } },
2218
16
        { &hf_st334_2_svc_info_start_section,
2219
16
          { "Service Info Start", "st334_2.svcinfo.start", FT_BOOLEAN, 8, NULL, 0x40, NULL,
2220
16
            HFILL } },
2221
16
        { &hf_st334_2_svc_info_change_section,
2222
16
          { "Service Info Change", "st334_2.svcinfo.change", FT_BOOLEAN, 8, NULL, 0x20, NULL,
2223
16
            HFILL } },
2224
16
        { &hf_st334_2_svc_info_complete_section,
2225
16
          { "Service Info Complete", "st334_2.svcinfo.complete", FT_BOOLEAN, 8, NULL, 0x10,
2226
16
            NULL, HFILL } },
2227
16
        { &hf_st334_2_svc_count,
2228
16
          { "Service Count", "st334_2.svcinfo.count", FT_UINT8, BASE_DEC, NULL, 0x0f, NULL,
2229
16
            HFILL } },
2230
16
        { &hf_st334_2_csn_reserved,
2231
16
          { "Reserved", "st334_2.svcinfo.service.reserved", FT_BOOLEAN, 8, NULL, 0x80, NULL,
2232
16
            HFILL } },
2233
16
        { &hf_st334_2_csn_size,
2234
16
          { "Caption Service Number Size", "st334_2.svcinfo.service.csn_size", FT_BOOLEAN, 8,
2235
16
            NULL, 0x40, NULL, HFILL } },
2236
16
        { &hf_st334_2_csn_reserved_2,
2237
16
          { "Reserved", "st334_2.svcinfo.service.reserved_2", FT_BOOLEAN, 8, NULL, 0x20, NULL,
2238
16
            HFILL } },
2239
16
        { &hf_st334_2_caption_service_number,
2240
16
          { "Caption Service Number", "st334_2.svcinfo.service.number", FT_UINT8, BASE_DEC,
2241
16
            NULL, 0x0, NULL, HFILL } },
2242
2243
        /*
2244
         * SMPTE ST 334-2:2015, Sec. 5.5, Table 6;
2245
         * ATSC A/65:2013, Sec. 6.9.2, Table 6.26.
2246
         */
2247
16
        { &hf_st334_2_service_data,
2248
16
          { "Service Data", "st334_2.svcinfo.service.data", FT_BYTES, BASE_NONE, NULL, 0x0,
2249
16
            NULL, HFILL } },
2250
16
        { &hf_st334_2_service_language,
2251
16
          { "Language", "st334_2.svcinfo.service.language", FT_STRING, BASE_NONE, NULL, 0x0,
2252
16
            "ISO 639.2/B language code", HFILL } },
2253
16
        { &hf_st334_2_service_digital_cc,
2254
16
          { "Digital CC", "st334_2.svcinfo.service.digital_cc", FT_BOOLEAN, 8,
2255
16
            TFS(&tfs_yes_no), 0x80, "1 = CEA-708 digital captions; 0 = CEA-608/line 21", HFILL } },
2256
16
        { &hf_st334_2_service_digital_reserved,
2257
16
          { "Reserved", "st334_2.svcinfo.service.digital_reserved", FT_BOOLEAN, 8, NULL, 0x40,
2258
16
            NULL, HFILL } },
2259
16
        { &hf_st334_2_service_line21_reserved,
2260
16
          { "Reserved", "st334_2.svcinfo.service.line21_reserved", FT_UINT8, BASE_HEX, NULL,
2261
16
            0x7e, NULL, HFILL } },
2262
16
        { &hf_st334_2_service_line21_field,
2263
16
          { "Line 21 Field", "st334_2.svcinfo.service.line21_field", FT_BOOLEAN, 8, NULL,
2264
16
            0x01, "0 = field 1; 1 = field 2", HFILL } },
2265
16
        { &hf_st334_2_service_descriptor_number,
2266
16
          { "Caption Service Number", "st334_2.svcinfo.service.descriptor_number", FT_UINT8,
2267
16
            BASE_DEC, NULL, 0x3f, NULL, HFILL } },
2268
16
        { &hf_st334_2_service_easy_reader,
2269
16
          { "Easy Reader", "st334_2.svcinfo.service.easy_reader", FT_BOOLEAN, 8,
2270
16
            TFS(&tfs_yes_no), 0x80, NULL, HFILL } },
2271
16
        { &hf_st334_2_service_wide_aspect_ratio,
2272
16
          { "Wide Aspect Ratio", "st334_2.svcinfo.service.wide_aspect_ratio", FT_BOOLEAN, 8,
2273
16
            TFS(&tfs_yes_no), 0x40, "1 = 16:9; 0 = 4:3", HFILL } },
2274
16
        { &hf_st334_2_service_reserved_14,
2275
16
          { "Reserved", "st334_2.svcinfo.service.reserved_14", FT_UINT16, BASE_HEX, NULL,
2276
16
            0x3fff, NULL, HFILL } },
2277
16
        { &hf_st334_2_future_length,
2278
16
          { "Length", "st334_2.future.length", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } },
2279
16
        { &hf_st334_2_future_data,
2280
16
          { "Data", "st334_2.future.data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
2281
16
        { &hf_st334_2_footer_sequence_counter,
2282
16
          { "Footer Sequence Counter", "st334_2.cdp.footer_sequence", FT_UINT16, BASE_DEC,
2283
16
            NULL, 0x0, NULL, HFILL } },
2284
16
        { &hf_st334_2_packet_checksum,
2285
16
          { "Packet Checksum", "st334_2.cdp.checksum", FT_UINT8, BASE_HEX, NULL, 0x0, NULL,
2286
16
            HFILL } },
2287
16
        { &hf_st334_2_checksum_calculated,
2288
16
          { "Calculated Checksum", "st334_2.cdp.checksum_calculated", FT_UINT8, BASE_HEX,
2289
16
            NULL, 0x0, NULL, HFILL } },
2290
16
    };
2291
16
    static int *ett[] = {
2292
16
        &ett_st334_2,
2293
16
        &ett_st334_2_header,
2294
16
        &ett_st334_2_timecode,
2295
16
        &ett_st334_2_ccdata,
2296
16
        &ett_st334_2_cc_construct,
2297
16
        &ett_st334_2_svcinfo,
2298
16
        &ett_st334_2_service,
2299
16
        &ett_st334_2_service_data,
2300
16
        &ett_st334_2_future,
2301
16
        &ett_st334_2_footer,
2302
16
    };
2303
16
    static ei_register_info ei[] = {
2304
16
        { &ei_st334_2_bad_identifier, { "st334_2.bad_identifier", PI_PROTOCOL, PI_WARN, "Invalid CDP identifier", EXPFILL } },
2305
16
        { &ei_st334_2_bad_length, { "st334_2.bad_length", PI_MALFORMED, PI_WARN, "CDP length mismatch", EXPFILL } },
2306
16
        { &ei_st334_2_bad_reserved, { "st334_2.bad_reserved", PI_PROTOCOL, PI_WARN, "Invalid reserved bits or duplicated flags", EXPFILL } },
2307
16
        { &ei_st334_2_bad_section_order, { "st334_2.bad_section_order", PI_PROTOCOL, PI_WARN, "Invalid or unknown CDP section ordering", EXPFILL } },
2308
16
        { &ei_st334_2_duplicate_section, { "st334_2.duplicate_section", PI_PROTOCOL, PI_WARN, "Duplicate CDP section", EXPFILL } },
2309
16
        { &ei_st334_2_missing_section, { "st334_2.missing_section", PI_PROTOCOL, PI_WARN, "CDP section presence mismatch", EXPFILL } },
2310
16
        { &ei_st334_2_cc_count, { "st334_2.bad_cc_count", PI_PROTOCOL, PI_WARN, "CC count does not match frame rate", EXPFILL } },
2311
16
        { &ei_st334_2_bad_marker, { "st334_2.bad_marker", PI_PROTOCOL, PI_WARN, "Invalid CEA-708 marker bits", EXPFILL } },
2312
16
        { &ei_st334_2_sequence_mismatch, { "st334_2.sequence_mismatch", PI_SEQUENCE, PI_WARN, "CDP header/footer sequence mismatch", EXPFILL } },
2313
16
        { &ei_st334_2_bad_checksum, { "st334_2.bad_checksum", PI_CHECKSUM, PI_WARN, "Invalid CDP checksum", EXPFILL } },
2314
16
        { &ei_st334_2_truncated, { "st334_2.truncated", PI_MALFORMED, PI_ERROR, "Truncated CDP section", EXPFILL } },
2315
16
    };
2316
16
    expert_module_t *expert_st334_2;
2317
2318
16
    proto_st334_2 = proto_register_protocol(
2319
16
        "SMPTE ST 334-2 Caption Distribution Packet", "ST 334-2", "st334_2");
2320
16
    proto_register_field_array(proto_st334_2, hf, array_length(hf));
2321
16
    proto_register_subtree_array(ett, array_length(ett));
2322
2323
16
    expert_st334_2 = expert_register_protocol(proto_st334_2);
2324
16
    expert_register_field_array(expert_st334_2, ei, array_length(ei));
2325
2326
16
    st334_2_handle = register_dissector("st334_2", dissect_st334_2, proto_st334_2);
2327
16
}
2328
2329
void
2330
proto_reg_handoff_st334_2(void)
2331
16
{
2332
16
    dissector_add_uint("st291.did_sdid", ST334_2_DID_SDID_KEY, st334_2_handle);
2333
16
}
2334
2335
/*
2336
 * Common System B World System Teletext decoding used by ST 2031 and
2337
 * RDD 8 / OP-47. The protocols retain separate display-filter fields; this
2338
 * structure supplies the appropriate field IDs to the common parser.
2339
 */
2340
typedef struct {
2341
    int *magazine_hamming;
2342
    int *magazine;
2343
    int *packet_number_hamming;
2344
    int *packet_number;
2345
    int *page_units_hamming;
2346
    int *page_units;
2347
    int *page_tens_hamming;
2348
    int *page_tens;
2349
    int *data_string;
2350
    int *textdata_array;
2351
    int *erase_page;
2352
    int *newsflash;
2353
    int *subtitle;
2354
    int *suppress_header;
2355
    int *update_indicator;
2356
    int *interrupted_sequence;
2357
    int *inhibit_display;
2358
    int *magazine_serial;
2359
    int *character_set;
2360
    int *tt_control;
2361
} st291_wst_fields_t;
2362
2363
/* Rec. ITU-R BT.653-3, System B national-option character subsets. */
2364
static const value_string st291_wst_national_subset_vals[] = {
2365
    { 0x00, "English" },
2366
    { 0x01, "German" },
2367
    { 0x04, "Swedish/Finnish/Hungarian" },
2368
    { 0x05, "Italian" },
2369
    { 0x10, "French" },
2370
    { 0x11, "Portuguese/Spanish" },
2371
    { 0x14, "Czech/Slovak" },
2372
    { 0, NULL }
2373
};
2374
2375
static void
2376
st291_process_wst_packet(tvbuff_t *tvb, proto_tree *tree, const st291_wst_fields_t *fields)
2377
0
{
2378
0
    uint8_t text_data[40];
2379
0
    char data_string[41];
2380
0
    unsigned magazine, packet_number;
2381
0
    unsigned data_start_offset = 0, number_of_data_bytes = 0;
2382
0
    proto_item *ti;
2383
0
    unsigned i;
2384
2385
0
    if (tvb_captured_length(tvb) < 42)
2386
0
        return;
2387
2388
0
    proto_tree_add_item(tree, *fields->magazine_hamming, tvb, 0, 2, ENC_BIG_ENDIAN);
2389
0
    magazine = tvb_get_bits8(tvb, 1, 1)
2390
0
             + 2 * tvb_get_bits8(tvb, 3, 1)
2391
0
             + 4 * tvb_get_bits8(tvb, 5, 1);
2392
0
    if (magazine == 0)
2393
0
        magazine = 8;
2394
0
    ti = proto_tree_add_uint(tree, *fields->magazine, tvb, 0, 0, magazine);
2395
0
    proto_item_set_generated(ti);
2396
2397
0
    proto_tree_add_item(tree, *fields->packet_number_hamming, tvb, 0, 2, ENC_BIG_ENDIAN);
2398
0
    packet_number = tvb_get_bits8(tvb, 7, 1)
2399
0
                  + 2 * tvb_get_bits8(tvb, 9, 1)
2400
0
                  + 4 * tvb_get_bits8(tvb, 11, 1)
2401
0
                  + 8 * tvb_get_bits8(tvb, 13, 1)
2402
0
                  + 16 * tvb_get_bits8(tvb, 15, 1);
2403
0
    ti = proto_tree_add_uint(tree, *fields->packet_number, tvb, 0, 0, packet_number);
2404
0
    proto_item_set_generated(ti);
2405
2406
0
    if (packet_number == 0) {
2407
0
        unsigned page_units, page_tens, tt_page;
2408
2409
0
        data_start_offset = 10;
2410
0
        number_of_data_bytes = 32;
2411
2412
0
        page_units = tvb_get_bits8(tvb, 2 * 8 + 1, 1)
2413
0
                   + 2 * tvb_get_bits8(tvb, 2 * 8 + 3, 1)
2414
0
                   + 4 * tvb_get_bits8(tvb, 2 * 8 + 5, 1)
2415
0
                   + 8 * tvb_get_bits8(tvb, 2 * 8 + 7, 1);
2416
0
        page_tens = tvb_get_bits8(tvb, 3 * 8 + 1, 1)
2417
0
                  + 2 * tvb_get_bits8(tvb, 3 * 8 + 3, 1)
2418
0
                  + 4 * tvb_get_bits8(tvb, 3 * 8 + 5, 1)
2419
0
                  + 8 * tvb_get_bits8(tvb, 3 * 8 + 7, 1);
2420
2421
0
        proto_tree_add_item(tree, *fields->page_units_hamming, tvb, 2, 1, ENC_BIG_ENDIAN);
2422
0
        proto_tree_add_item(tree, *fields->page_tens_hamming, tvb, 3, 1, ENC_BIG_ENDIAN);
2423
0
        ti = proto_tree_add_uint(tree, *fields->page_units, tvb, 0, 0, page_units);
2424
0
        proto_item_set_generated(ti);
2425
0
        ti = proto_tree_add_uint(tree, *fields->page_tens, tvb, 0, 0, page_tens);
2426
0
        proto_item_set_generated(ti);
2427
2428
0
        tt_page = (magazine << 8) | (page_tens << 4) | page_units;
2429
0
        proto_tree_add_none_format(tree, *fields->tt_control, tvb, 0, 0,
2430
0
                                   "Control bits for TT Page 0x%x:", tt_page);
2431
2432
0
        proto_tree_add_item(tree, *fields->erase_page, tvb, 5, 1, ENC_BIG_ENDIAN);
2433
0
        proto_tree_add_item(tree, *fields->newsflash, tvb, 7, 1, ENC_BIG_ENDIAN);
2434
0
        proto_tree_add_item(tree, *fields->subtitle, tvb, 7, 1, ENC_BIG_ENDIAN);
2435
0
        proto_tree_add_item(tree, *fields->suppress_header, tvb, 8, 1, ENC_BIG_ENDIAN);
2436
0
        proto_tree_add_item(tree, *fields->update_indicator, tvb, 8, 1, ENC_BIG_ENDIAN);
2437
0
        proto_tree_add_item(tree, *fields->interrupted_sequence, tvb, 8, 1, ENC_BIG_ENDIAN);
2438
0
        proto_tree_add_item(tree, *fields->inhibit_display, tvb, 8, 1, ENC_BIG_ENDIAN);
2439
0
        proto_tree_add_item(tree, *fields->magazine_serial, tvb, 9, 1, ENC_BIG_ENDIAN);
2440
0
        proto_tree_add_item(tree, *fields->character_set, tvb, 9, 1, ENC_BIG_ENDIAN);
2441
0
    } else if (packet_number >= 1 && packet_number <= 25) {
2442
0
        data_start_offset = 2;
2443
0
        number_of_data_bytes = 40;
2444
0
    }
2445
2446
0
    if (number_of_data_bytes == 0)
2447
0
        return;
2448
2449
0
    for (i = 0; i < number_of_data_bytes; i++) {
2450
0
        uint8_t c = tvb_get_bits8(tvb, (data_start_offset + i) * 8, 7);
2451
0
        text_data[i] = c;
2452
0
        data_string[i] = (char)c;
2453
0
    }
2454
0
    data_string[number_of_data_bytes] = '\0';
2455
2456
0
    ti = proto_tree_add_string(tree, *fields->data_string, tvb, 0, 0, data_string);
2457
0
    proto_item_set_generated(ti);
2458
0
    ti = proto_tree_add_bytes_with_length(tree, *fields->textdata_array, tvb, 0, 0, text_data, number_of_data_bytes);
2459
0
    proto_item_set_generated(ti);
2460
0
}
2461
2462
/*
2463
 * SMPTE ST 2031 DVB/SCTE VBI data in VANC
2464
 */
2465
2466
static const struct true_false_string st2031_tfs_field_parity = {
2467
    "First field of a frame", "Second field of a frame"
2468
};
2469
2470
2471
static const st291_wst_fields_t st2031_wst_fields = {
2472
    &hf_st2031_magazine_hamming,
2473
    &hf_st2031_magazine,
2474
    &hf_st2031_packet_number_hamming,
2475
    &hf_st2031_packet_number,
2476
    &hf_st2031_page_units_hamming,
2477
    &hf_st2031_page_units,
2478
    &hf_st2031_page_tens_hamming,
2479
    &hf_st2031_page_tens,
2480
    &hf_st2031_data_string,
2481
    &hf_st2031_textdata_array,
2482
    &hf_st2031_erase_page,
2483
    &hf_st2031_newsflash,
2484
    &hf_st2031_subtitle,
2485
    &hf_st2031_suppress_header,
2486
    &hf_st2031_update_indicator,
2487
    &hf_st2031_interrupted_sequence,
2488
    &hf_st2031_inhibit_display,
2489
    &hf_st2031_magazine_serial,
2490
    &hf_st2031_character_set,
2491
    &hf_st2031_tt_control,
2492
};
2493
2494
/* Rec. ITU-R BT.653-3, System B national-option character subsets used by Teletext data units. */
2495
/* SMPTE ST 2031:2015, Sec. 6, Table 2; values originate in ETSI EN 301 775, Sec. 4.4. */
2496
static const range_string st2031_data_identifier_vals[] = {
2497
    { 0x10, 0x1F, "EBU Teletext/VPS/WSS/CC/VBI sample data" },
2498
    { 0x80, 0x98, "User defined" },
2499
    { 0x99, 0x9B, "EBU Teletext/VPS/WSS/CC/VBI sample data" },
2500
    { 0x9C, 0xFF, "User defined" },
2501
    { 0x00, 0xFF, "Reserved for future use" },
2502
    { 0, 0, NULL }
2503
};
2504
2505
/* SMPTE ST 2031:2015, Sec. 6, Table 2; data_unit_id values originate in ETSI EN 301 775, Sec. 4.5. */
2506
static const range_string st2031_data_unit_id_vals[] = {
2507
    { 0x00, 0x01, "DVB reserved" },
2508
    { 0x02, 0x02, "EBU Teletext non-subtitle data" },
2509
    { 0x03, 0x03, "EBU Teletext subtitle data" },
2510
    { 0x04, 0x7F, "DVB reserved" },
2511
    { 0x80, 0xBF, "User defined" },
2512
    { 0xC0, 0xC0, "Inverted Teletext" },
2513
    { 0xC1, 0xC2, "DVB reserved" },
2514
    { 0xC3, 0xC3, "VPS" },
2515
    { 0xC4, 0xC4, "WSS" },
2516
    { 0xC5, 0xC5, "CEA-608 Closed Captioning" },
2517
    { 0xC6, 0xC6, "monochrome 4:2:2 samples" },
2518
    { 0xC7, 0xCF, "User defined" },
2519
    { 0xD0, 0xD0, "AMOL48" },
2520
    { 0xD1, 0xD1, "AMOL96" },
2521
    { 0xDA, 0xE5, "SCTE reserved" },
2522
    { 0xE6, 0xFE, "SCTE user defined" },
2523
    { 0xFF, 0xFF, "MPEG stuffing" },
2524
    { 0x00, 0xFF, "Reserved or user defined" },
2525
    { 0, 0, NULL }
2526
};
2527
2528
/* ETSI EN 301 775, Sec. 4.5.2 carries a 42-byte Teletext data block;
2529
 * packet addressing, page/control bits and character data follow Rec. ITU-R BT.653-3 System B. */
2530
/* SMPTE ST 2031:2015, Secs. 5-6, Tables 1-2; ETSI EN 301 775 Sec. 4.5 for Teletext fields. */
2531
static int
2532
dissect_st2031(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data)
2533
0
{
2534
0
    const st291_vanc_dissector_data_t *st291_data = (const st291_vanc_dissector_data_t *)data;
2535
0
    proto_tree *top_tree = st291_data && st291_data->top_tree ? st291_data->top_tree : tree;
2536
0
    proto_item *ti;
2537
0
    proto_tree *st2031_tree;
2538
0
    uint8_t unit_id;
2539
0
    tvbuff_t *wst_tvb;
2540
2541
0
    if (tvb_captured_length(tvb) < 2)
2542
0
        return 0;
2543
2544
0
    ti = proto_tree_add_item(top_tree, proto_st2031, tvb, 0, -1, ENC_NA);
2545
0
    st2031_tree = proto_item_add_subtree(ti, ett_st2031);
2546
2547
    /* SMPTE ST 2031:2015, Sec. 6, Table 2 -- data_identifier,
2548
     * data_unit_id and data_unit_length. */
2549
0
    proto_tree_add_item(st2031_tree, hf_st2031_data_identifier, tvb, 0, 1, ENC_BIG_ENDIAN);
2550
0
    proto_tree_add_item_ret_uint8(st2031_tree, hf_st2031_data_unit_id, tvb, 1, 1, ENC_BIG_ENDIAN, &unit_id);
2551
2552
0
    if ((unit_id == 0x02 || unit_id == 0x03) && tvb_captured_length(tvb) >= 47) {
2553
0
        proto_tree_add_item(st2031_tree, hf_st2031_data_unit_length, tvb, 2, 1, ENC_BIG_ENDIAN);
2554
        /* ETSI EN 301 775, Secs. 4.5.1-4.5.2, Tables 4-5 --
2555
         * field_parity, line_offset, framing_code and Teletext data block. */
2556
0
        proto_tree_add_item(st2031_tree, hf_st2031_field_parity, tvb, 3, 1, ENC_BIG_ENDIAN);
2557
0
        proto_tree_add_item(st2031_tree, hf_st2031_line_offset, tvb, 3, 1, ENC_BIG_ENDIAN);
2558
0
        proto_tree_add_item(st2031_tree, hf_st2031_framing_code, tvb, 4, 1, ENC_BIG_ENDIAN);
2559
0
        wst_tvb = tvb_new_subset_length(tvb, 5, 42);
2560
0
        st291_process_wst_packet(wst_tvb, st2031_tree, &st2031_wst_fields);
2561
0
    }
2562
2563
0
    return tvb_captured_length(tvb);
2564
0
}
2565
2566
void
2567
proto_register_st2031(void)
2568
16
{
2569
16
    static hf_register_info hf[] = {
2570
16
        { &hf_st2031_data_identifier,
2571
16
          { "Data Identifier", "st2031.data_identifier", FT_UINT8,
2572
16
            BASE_HEX | BASE_RANGE_STRING, RVALS(st2031_data_identifier_vals), 0x0, NULL, HFILL } },
2573
16
        { &hf_st2031_data_unit_id,
2574
16
          { "Data Unit ID", "st2031.data_unit_id", FT_UINT8, BASE_HEX | BASE_RANGE_STRING,
2575
16
            RVALS(st2031_data_unit_id_vals), 0x0, NULL, HFILL } },
2576
16
        { &hf_st2031_data_unit_length,
2577
16
          { "Data Unit Length", "st2031.data_unit_length", FT_UINT8, BASE_DEC, NULL, 0x0,
2578
16
            NULL, HFILL } },
2579
16
        { &hf_st2031_field_parity,
2580
16
          { "Field Parity", "st2031.field_parity", FT_BOOLEAN, 8,
2581
16
            TFS(&st2031_tfs_field_parity), 0x20, NULL, HFILL } },
2582
16
        { &hf_st2031_line_offset,
2583
16
          { "Line Offset", "st2031.line_offset", FT_UINT8, BASE_DEC, NULL, 0x1F, NULL, HFILL } },
2584
16
        { &hf_st2031_framing_code,
2585
16
          { "Framing Code", "st2031.framing_code", FT_UINT8, BASE_HEX, NULL, 0xFF, NULL, HFILL } },
2586
16
        { &hf_st2031_magazine_hamming,
2587
16
          { "Magazine (Hamming 8/4)", "st2031.teletext.magazine_hamming", FT_UINT16, BASE_DEC,
2588
16
            NULL, 0xFC00, NULL, HFILL } },
2589
16
        { &hf_st2031_magazine,
2590
16
          { "Magazine", "st2031.teletext.magazine", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } },
2591
16
        { &hf_st2031_packet_number_hamming,
2592
16
          { "Packet Number (Hamming 8/4)", "st2031.teletext.packet_number_hamming", FT_UINT16,
2593
16
            BASE_DEC, NULL, 0x03FF, NULL, HFILL } },
2594
16
        { &hf_st2031_packet_number,
2595
16
          { "Packet Number", "st2031.teletext.packet_number", FT_UINT8, BASE_DEC, NULL, 0x0,
2596
16
            NULL, HFILL } },
2597
16
        { &hf_st2031_page_units_hamming,
2598
16
          { "Page Units (Hamming 8/4)", "st2031.teletext.page_units_hamming", FT_UINT8,
2599
16
            BASE_HEX, NULL, 0xFF, NULL, HFILL } },
2600
16
        { &hf_st2031_page_units,
2601
16
          { "Page Units", "st2031.teletext.page_units", FT_UINT8, BASE_HEX, NULL, 0x0, NULL,
2602
16
            HFILL } },
2603
16
        { &hf_st2031_page_tens_hamming,
2604
16
          { "Page Tens (Hamming 8/4)", "st2031.teletext.page_tens_hamming", FT_UINT8,
2605
16
            BASE_HEX, NULL, 0xFF, NULL, HFILL } },
2606
16
        { &hf_st2031_page_tens,
2607
16
          { "Page Tens", "st2031.teletext.page_tens", FT_UINT8, BASE_HEX, NULL, 0x0, NULL,
2608
16
            HFILL } },
2609
16
        { &hf_st2031_data_string,
2610
16
          { "Data String", "st2031.teletext.data_string", FT_STRING, BASE_NONE, NULL, 0x0,
2611
16
            NULL, HFILL } },
2612
16
        { &hf_st2031_textdata_array,
2613
16
          { "Text Data", "st2031.teletext.text_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL,
2614
16
            HFILL } },
2615
16
        { &hf_st2031_erase_page,
2616
16
          { "Erase Page", "st2031.teletext.erase_page", FT_BOOLEAN, 8, NULL, 0x01, NULL, HFILL } },
2617
16
        { &hf_st2031_newsflash,
2618
16
          { "Newsflash", "st2031.teletext.newsflash", FT_BOOLEAN, 8, NULL, 0x04, NULL, HFILL } },
2619
16
        { &hf_st2031_subtitle,
2620
16
          { "Subtitle", "st2031.teletext.subtitle", FT_BOOLEAN, 8, NULL, 0x01, NULL, HFILL } },
2621
16
        { &hf_st2031_suppress_header,
2622
16
          { "Suppress Header", "st2031.teletext.suppress_header", FT_BOOLEAN, 8, NULL, 0x40,
2623
16
            NULL, HFILL } },
2624
16
        { &hf_st2031_update_indicator,
2625
16
          { "Update Indicator", "st2031.teletext.update_indicator", FT_BOOLEAN, 8, NULL, 0x10,
2626
16
            NULL, HFILL } },
2627
16
        { &hf_st2031_interrupted_sequence,
2628
16
          { "Interrupted Sequence", "st2031.teletext.interrupted_sequence", FT_BOOLEAN, 8,
2629
16
            NULL, 0x04, NULL, HFILL } },
2630
16
        { &hf_st2031_inhibit_display,
2631
16
          { "Inhibit Display", "st2031.teletext.inhibit_display", FT_BOOLEAN, 8, NULL, 0x01,
2632
16
            NULL, HFILL } },
2633
16
        { &hf_st2031_magazine_serial,
2634
16
          { "Magazine Serial", "st2031.teletext.magazine_serial", FT_BOOLEAN, 8, NULL, 0x40,
2635
16
            NULL, HFILL } },
2636
16
        { &hf_st2031_character_set,
2637
16
          { "Character Subset", "st2031.teletext.character_set", FT_UINT8, BASE_DEC,
2638
16
            VALS(st291_wst_national_subset_vals), 0x15, NULL, HFILL } },
2639
16
        { &hf_st2031_tt_control,
2640
16
          { "Teletext Control", "st2031.teletext.control", FT_NONE, BASE_NONE, NULL, 0x0,
2641
16
            NULL, HFILL } },
2642
16
    };
2643
16
    static int *ett[] = { &ett_st2031 };
2644
2645
16
    proto_st2031 = proto_register_protocol(
2646
16
        "SMPTE ST 2031 VBI Data", "ST 2031", "st2031");
2647
16
    proto_register_field_array(proto_st2031, hf, array_length(hf));
2648
16
    proto_register_subtree_array(ett, array_length(ett));
2649
2650
16
    st2031_handle = register_dissector("st2031", dissect_st2031, proto_st2031);
2651
16
}
2652
2653
void
2654
proto_reg_handoff_st2031(void)
2655
16
{
2656
16
    dissector_add_uint("st291.did_sdid", ST2031_DID_SDID_KEY, st2031_handle);
2657
16
}
2658
2659
/*
2660
 * Free TV Australia OP-47 / SMPTE RDD 8 teletext
2661
 */
2662
2663
static const st291_wst_fields_t op47_wst_fields = {
2664
    &hf_op47_magazine_hamming,
2665
    &hf_op47_magazine,
2666
    &hf_op47_packet_number_hamming,
2667
    &hf_op47_packet_number,
2668
    &hf_op47_page_units_hamming,
2669
    &hf_op47_page_units,
2670
    &hf_op47_page_tens_hamming,
2671
    &hf_op47_page_tens,
2672
    &hf_op47_data_string,
2673
    &hf_op47_textdata_array,
2674
    &hf_op47_erase_page,
2675
    &hf_op47_newsflash,
2676
    &hf_op47_subtitle,
2677
    &hf_op47_suppress_header,
2678
    &hf_op47_update_indicator,
2679
    &hf_op47_interrupted_sequence,
2680
    &hf_op47_inhibit_display,
2681
    &hf_op47_magazine_serial,
2682
    &hf_op47_character_set,
2683
    &hf_op47_tt_control,
2684
};
2685
2686
/* Rec. ITU-R BT.653-3, System B national-option character subsets used by OP-47 WST data. */
2687
/* OP-47 Issue 6, Sec. 5.5.2 carries a System B WST packet; magazine,
2688
 * packet number, page address, control bits and text follow Rec. ITU-R BT.653-3. */
2689
/* Free TV Australia OP-47 Issue 6, Secs. 5.1, 5.4 and 5.5, Fig. 2. */
2690
static int
2691
dissect_op47(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
2692
0
{
2693
0
    const st291_vanc_dissector_data_t *st291_data = (const st291_vanc_dissector_data_t *)data;
2694
0
    proto_tree *top_tree = st291_data && st291_data->top_tree ? st291_data->top_tree : tree;
2695
0
    proto_item *ti;
2696
0
    proto_tree *op47_tree;
2697
0
    unsigned len = tvb_captured_length(tvb);
2698
0
    uint8_t format_code;
2699
0
    unsigned offset_a = 4, offset_b = 9, i;
2700
2701
0
    if (len < 4)
2702
0
        return 0;
2703
2704
0
    ti = proto_tree_add_item(top_tree, proto_op47, tvb, 0, -1, ENC_NA);
2705
0
    op47_tree = proto_item_add_subtree(ti, ett_op47);
2706
2707
    /* OP-47 Issue 6, Sec. 5.1 and Fig. 2 -- SDP identifier, length and format code. */
2708
0
    proto_tree_add_item(op47_tree, hf_op47_sdp_identifier, tvb, 0, 2, ENC_BIG_ENDIAN);
2709
0
    proto_tree_add_item(op47_tree, hf_op47_sdp_length, tvb, 2, 1, ENC_BIG_ENDIAN);
2710
0
    proto_tree_add_item_ret_uint8(op47_tree, hf_op47_sdp_format_code, tvb, 3, 1, ENC_BIG_ENDIAN, &format_code);
2711
0
    if (format_code != 0x02 || len < 9)
2712
0
        return len;
2713
2714
    /* OP-47 Issue 6, Sec. 5.4 -- Packet Descriptor Structure A / adaptation header. */
2715
0
    ti = proto_tree_add_item(op47_tree, hf_op47_sdp_adaption_header, tvb, 4, 5, ENC_NA);
2716
0
    proto_item_set_generated(ti);
2717
2718
0
    for (i = 0; i < 5; i++) {
2719
0
        uint8_t pkt_desc_a;
2720
0
        uint8_t *flipped;
2721
0
        tvbuff_t *wst_tvb;
2722
0
        proto_tree *wst_tree;
2723
2724
0
        if (offset_a >= len)
2725
0
            break;
2726
0
        pkt_desc_a = tvb_get_uint8(tvb, offset_a);
2727
0
        if (pkt_desc_a == 0)
2728
0
            break;
2729
0
        if (offset_b + 45 > len)
2730
0
            break;
2731
2732
        /* OP-47 Issue 6, Sec. 5.5 -- Packet Descriptor Structure B;
2733
         * Secs. 5.5.1-5.5.2 define clock run-in, framing code and WST data. */
2734
0
        ti = proto_tree_add_item(op47_tree, hf_op47_sdp_pkt_desc_b, tvb, offset_b, 45, ENC_NA);
2735
0
        proto_item_set_generated(ti);
2736
0
        wst_tree = proto_item_add_subtree(ti, ett_op47_wst);
2737
2738
0
        ti = proto_tree_add_item(wst_tree, hf_op47_clock_runin, tvb, offset_b, 2, ENC_BIG_ENDIAN);
2739
0
        proto_item_set_generated(ti);
2740
0
        ti = proto_tree_add_item(wst_tree, hf_op47_framing_code, tvb, offset_b + 2, 1, ENC_BIG_ENDIAN);
2741
0
        proto_item_set_generated(ti);
2742
2743
0
        flipped = wmem_alloc(pinfo->pool, 42);
2744
0
        tvb_memcpy(tvb, flipped, offset_b + 3, 42);
2745
0
        bitswap_buf_inplace(flipped, 42);
2746
2747
0
        wst_tvb = tvb_new_child_real_data(tvb, flipped, 42, 42);
2748
0
        add_new_data_source(pinfo, wst_tvb, "OP-47 WST data (bit reversed)");
2749
0
        st291_process_wst_packet(wst_tvb, wst_tree, &op47_wst_fields);
2750
2751
0
        offset_a++;
2752
0
        offset_b += 45;
2753
0
    }
2754
2755
0
    return len;
2756
0
}
2757
2758
void
2759
proto_register_op47(void)
2760
16
{
2761
16
    static hf_register_info hf[] = {
2762
16
        { &hf_op47_sdp_identifier,
2763
16
          { "Identifier", "op47.sdp.identifier", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL } },
2764
16
        { &hf_op47_sdp_length,
2765
16
          { "Length", "op47.sdp.length", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } },
2766
16
        { &hf_op47_sdp_format_code,
2767
16
          { "Format Code", "op47.sdp.format_code", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } },
2768
16
        { &hf_op47_sdp_adaption_header,
2769
16
          { "Adaption Header", "op47.sdp.adaption_header", FT_BYTES, BASE_NONE, NULL, 0x0,
2770
16
            NULL, HFILL } },
2771
16
        { &hf_op47_sdp_pkt_desc_b,
2772
16
          { "Packet Descriptor B", "op47.sdp.packet_descriptor_b", FT_BYTES, BASE_NONE, NULL,
2773
16
            0x0, NULL, HFILL } },
2774
16
        { &hf_op47_clock_runin,
2775
16
          { "Clock Run-In", "op47.wst.clock_runin", FT_UINT16, BASE_HEX, NULL, 0xFFFF, NULL,
2776
16
            HFILL } },
2777
16
        { &hf_op47_framing_code,
2778
16
          { "Framing Code", "op47.wst.framing_code", FT_UINT8, BASE_HEX, NULL, 0xFF, NULL,
2779
16
            HFILL } },
2780
16
        { &hf_op47_magazine_hamming,
2781
16
          { "Magazine (Hamming 8/4)", "op47.wst.magazine_hamming", FT_UINT16, BASE_DEC, NULL,
2782
16
            0xFC00, NULL, HFILL } },
2783
16
        { &hf_op47_magazine,
2784
16
          { "Magazine", "op47.wst.magazine", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } },
2785
16
        { &hf_op47_packet_number_hamming,
2786
16
          { "Packet Number (Hamming 8/4)", "op47.wst.packet_number_hamming", FT_UINT16,
2787
16
            BASE_DEC, NULL, 0x03FF, NULL, HFILL } },
2788
16
        { &hf_op47_packet_number,
2789
16
          { "Packet Number", "op47.wst.packet_number", FT_UINT8, BASE_DEC, NULL, 0x0, NULL,
2790
16
            HFILL } },
2791
16
        { &hf_op47_page_units_hamming,
2792
16
          { "Page Units (Hamming 8/4)", "op47.wst.page_units_hamming", FT_UINT8, BASE_HEX,
2793
16
            NULL, 0xFF, NULL, HFILL } },
2794
16
        { &hf_op47_page_units,
2795
16
          { "Page Units", "op47.wst.page_units", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } },
2796
16
        { &hf_op47_page_tens_hamming,
2797
16
          { "Page Tens (Hamming 8/4)", "op47.wst.page_tens_hamming", FT_UINT8, BASE_HEX, NULL,
2798
16
            0xFF, NULL, HFILL } },
2799
16
        { &hf_op47_page_tens,
2800
16
          { "Page Tens", "op47.wst.page_tens", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } },
2801
16
        { &hf_op47_data_string,
2802
16
          { "Data String", "op47.wst.data_string", FT_STRING, BASE_NONE, NULL, 0x0, NULL,
2803
16
            HFILL } },
2804
16
        { &hf_op47_textdata_array,
2805
16
          { "Text Data", "op47.wst.text_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
2806
16
        { &hf_op47_erase_page,
2807
16
          { "Erase Page", "op47.wst.erase_page", FT_BOOLEAN, 8, NULL, 0x01, NULL, HFILL } },
2808
16
        { &hf_op47_newsflash,
2809
16
          { "Newsflash", "op47.wst.newsflash", FT_BOOLEAN, 8, NULL, 0x04, NULL, HFILL } },
2810
16
        { &hf_op47_subtitle,
2811
16
          { "Subtitle", "op47.wst.subtitle", FT_BOOLEAN, 8, NULL, 0x01, NULL, HFILL } },
2812
16
        { &hf_op47_suppress_header,
2813
16
          { "Suppress Header", "op47.wst.suppress_header", FT_BOOLEAN, 8, NULL, 0x40, NULL,
2814
16
            HFILL } },
2815
16
        { &hf_op47_update_indicator,
2816
16
          { "Update Indicator", "op47.wst.update_indicator", FT_BOOLEAN, 8, NULL, 0x10, NULL,
2817
16
            HFILL } },
2818
16
        { &hf_op47_interrupted_sequence,
2819
16
          { "Interrupted Sequence", "op47.wst.interrupted_sequence", FT_BOOLEAN, 8, NULL,
2820
16
            0x04, NULL, HFILL } },
2821
16
        { &hf_op47_inhibit_display,
2822
16
          { "Inhibit Display", "op47.wst.inhibit_display", FT_BOOLEAN, 8, NULL, 0x01, NULL,
2823
16
            HFILL } },
2824
16
        { &hf_op47_magazine_serial,
2825
16
          { "Magazine Serial", "op47.wst.magazine_serial", FT_BOOLEAN, 8, NULL, 0x40, NULL,
2826
16
            HFILL } },
2827
16
        { &hf_op47_character_set,
2828
16
          { "Character Subset", "op47.wst.character_set", FT_UINT8, BASE_DEC,
2829
16
            VALS(st291_wst_national_subset_vals), 0x15, NULL, HFILL } },
2830
16
        { &hf_op47_tt_control,
2831
16
          { "Teletext Control", "op47.wst.control", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
2832
16
    };
2833
16
    static int *ett[] = {
2834
16
        &ett_op47,
2835
16
        &ett_op47_wst,
2836
16
    };
2837
2838
16
    proto_op47 = proto_register_protocol(
2839
16
        "RDD 8 / OP-47 Subtitle Distribution Packet", "OP-47", "op47");
2840
16
    proto_register_field_array(proto_op47, hf, array_length(hf));
2841
16
    proto_register_subtree_array(ett, array_length(ett));
2842
2843
16
    op47_handle = register_dissector("op47", dissect_op47, proto_op47);
2844
16
}
2845
2846
void
2847
proto_reg_handoff_op47(void)
2848
16
{
2849
16
    dissector_add_uint("st291.did_sdid", OP47_DID_SDID_KEY, op47_handle);
2850
16
}
2851
2852
/*
2853
 * Editor modelines - https://www.wireshark.org/tools/modelines.html
2854
 *
2855
 * Local variables:
2856
 * c-basic-offset: 4
2857
 * tab-width: 8
2858
 * indent-tabs-mode: nil
2859
 * End:
2860
 *
2861
 * vi: set shiftwidth=4 tabstop=8 expandtab:
2862
 * :indentSize=4:tabSize=8:noTabs=true:
2863
 */