/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 | | */ |