/src/wireshark/wiretap/mp2t.c
Line | Count | Source |
1 | | /* mp2t.c |
2 | | * |
3 | | * ISO/IEC 13818-1 MPEG2-TS file format decoder for the Wiretap library. |
4 | | * Written by Weston Schmidt <weston_schmidt@alumni.purdue.edu> |
5 | | * Copyright 2012 Weston Schmidt |
6 | | * |
7 | | * Wiretap Library |
8 | | * SPDX-License-Identifier: GPL-2.0-or-later |
9 | | */ |
10 | | |
11 | | #include "config.h" |
12 | | #include "mp2t.h" |
13 | | |
14 | | #include <sys/types.h> |
15 | | |
16 | | #ifdef HAVE_UNISTD_H |
17 | | #include <unistd.h> |
18 | | #endif |
19 | | |
20 | | #include "wtap_module.h" |
21 | | #include <wsutil/buffer.h> |
22 | | #include <wsutil/pint.h> |
23 | | #include "file_wrappers.h" |
24 | | #include <stdlib.h> |
25 | | #include <string.h> |
26 | | #include <time.h> |
27 | | |
28 | 0 | #define MP2T_SYNC_BYTE 0x47 |
29 | 0 | #define MP2T_SIZE 188 |
30 | 0 | #define MP2T_QAM64_BITRATE 26970350 /* bits per second */ |
31 | 0 | #define MP2T_PCR_CLOCK 27000000 /* cycles per second - 27MHz */ |
32 | | |
33 | | /* we try to detect trailing data up to 40 bytes after each packet */ |
34 | 0 | #define TRAILER_LEN_MAX 40 |
35 | | |
36 | | /* number of consecutive packets we must read to decide that a file |
37 | | is actually an mpeg2 ts */ |
38 | 0 | #define SYNC_STEPS 10 |
39 | | |
40 | | |
41 | | typedef struct { |
42 | | uint64_t bitrate; |
43 | | uint32_t start_offset; |
44 | | /* length of header data (e.g., TP_extra_header in BDAV m2ts files) before |
45 | | * each packet) */ |
46 | | uint8_t header_len; |
47 | | /* length of trailing data (e.g. FEC) that's appended after each packet */ |
48 | | uint8_t trailer_len; |
49 | | } mp2t_filetype_t; |
50 | | |
51 | | static int mp2t_file_type_subtype = -1; |
52 | | |
53 | | void register_mp2t(void); |
54 | | |
55 | | static bool |
56 | | mp2t_read_packet(wtap *wth, FILE_T fh, int64_t offset, wtap_rec *rec, int *err, |
57 | | char **err_info) |
58 | 0 | { |
59 | 0 | mp2t_filetype_t *mp2t; |
60 | 0 | uint64_t tmp; |
61 | |
|
62 | 0 | mp2t = (mp2t_filetype_t*) wth->priv; |
63 | | |
64 | | /* |
65 | | * MP2T_SIZE will always be less than WTAP_MAX_PACKET_SIZE_STANDARD, so |
66 | | * we don't have to worry about the packet being too big. |
67 | | */ |
68 | 0 | if (!wtap_read_bytes_or_eof_buffer(fh, &rec->data, MP2T_SIZE, err, err_info)) |
69 | 0 | return false; |
70 | | |
71 | 0 | wtap_setup_packet_rec(rec, wth->file_encap); |
72 | 0 | rec->block = wtap_block_create(WTAP_BLOCK_PACKET); |
73 | | |
74 | | /* XXX - relative, not absolute, time stamps */ |
75 | 0 | rec->presence_flags = WTAP_HAS_TS; |
76 | | |
77 | | /* |
78 | | * Every packet in an MPEG2-TS stream is has a fixed size of |
79 | | * MP2T_SIZE plus the number of trailer bytes. |
80 | | * |
81 | | * We assume that the bits in the transport stream are supplied at |
82 | | * a constant rate; is that guaranteed by all media that use |
83 | | * MPEG2-TS? If so, the time offset, from the beginning of the |
84 | | * stream, of a given packet is the packet offset, in bits, divided |
85 | | * by the bitrate. |
86 | | * |
87 | | * It would be really cool to be able to configure the bitrate, in |
88 | | * case our attempt to guess it from the PCRs of one of the programs |
89 | | * doesn't get the right answer. |
90 | | */ |
91 | 0 | tmp = ((uint64_t)(offset - mp2t->start_offset) * 8); /* offset, in bits */ |
92 | 0 | rec->ts.secs = (time_t)(tmp / mp2t->bitrate); |
93 | 0 | rec->ts.nsecs = (int)((tmp % mp2t->bitrate) * 1000000000 / mp2t->bitrate); |
94 | |
|
95 | 0 | rec->rec_header.packet_header.caplen = MP2T_SIZE; |
96 | 0 | rec->rec_header.packet_header.len = MP2T_SIZE; |
97 | |
|
98 | 0 | return true; |
99 | 0 | } |
100 | | |
101 | | static bool |
102 | | mp2t_read(wtap *wth, wtap_rec *rec, int *err, |
103 | | char **err_info, int64_t *data_offset) |
104 | 0 | { |
105 | 0 | mp2t_filetype_t *mp2t; |
106 | |
|
107 | 0 | mp2t = (mp2t_filetype_t*) wth->priv; |
108 | | |
109 | | /* if there's a header, skip it and go to the start of the packet */ |
110 | | /* XXX - Eventually we might want to process the header (and trailer?) in |
111 | | * packet-mp2t.c, in which case we would read it in mp2t_read_packet and |
112 | | * include header_len in the packet_header lengths. We'd probably want |
113 | | * pseudo-header information to indicate it to packet-mp2t.c |
114 | | */ |
115 | 0 | if (mp2t->header_len!=0) { |
116 | 0 | if (!wtap_read_bytes_or_eof(wth->fh, NULL, mp2t->header_len, err, err_info)) { |
117 | 0 | return false; |
118 | 0 | } |
119 | 0 | } |
120 | | |
121 | 0 | *data_offset = file_tell(wth->fh); |
122 | |
|
123 | 0 | if (!mp2t_read_packet(wth, wth->fh, *data_offset, rec, err, err_info)) { |
124 | 0 | return false; |
125 | 0 | } |
126 | | |
127 | | /* if there's a trailer, skip it and go to the start of the next packet */ |
128 | 0 | if (mp2t->trailer_len!=0) { |
129 | 0 | if (!wtap_read_bytes(wth->fh, NULL, mp2t->trailer_len, err, err_info)) { |
130 | 0 | return false; |
131 | 0 | } |
132 | 0 | } |
133 | | |
134 | 0 | return true; |
135 | 0 | } |
136 | | |
137 | | static bool |
138 | | mp2t_seek_read(wtap *wth, int64_t seek_off, wtap_rec *rec, |
139 | | int *err, char **err_info) |
140 | 0 | { |
141 | 0 | if (-1 == file_seek(wth->random_fh, seek_off, SEEK_SET, err)) { |
142 | 0 | return false; |
143 | 0 | } |
144 | | |
145 | 0 | if (!mp2t_read_packet(wth, wth->random_fh, seek_off, rec, err, err_info)) { |
146 | 0 | if (*err == 0) |
147 | 0 | *err = WTAP_ERR_SHORT_READ; |
148 | 0 | return false; |
149 | 0 | } |
150 | 0 | return true; |
151 | 0 | } |
152 | | |
153 | | static uint64_t |
154 | | mp2t_read_pcr(uint8_t *buffer) |
155 | 0 | { |
156 | 0 | uint64_t base; |
157 | 0 | uint64_t ext; |
158 | |
|
159 | 0 | base = pntohu40(buffer); |
160 | 0 | base >>= 7; |
161 | |
|
162 | 0 | ext = pntohu16(&buffer[4]); |
163 | 0 | ext &= 0x01ff; |
164 | |
|
165 | 0 | return (base * 300 + ext); |
166 | 0 | } |
167 | | |
168 | | static bool |
169 | | mp2t_find_next_pcr(wtap *wth, uint8_t trailer_len, |
170 | | int *err, char **err_info, uint32_t *idx, uint64_t *pcr, uint16_t *pid) |
171 | 0 | { |
172 | 0 | uint8_t buffer[MP2T_SIZE+TRAILER_LEN_MAX]; |
173 | 0 | bool found; |
174 | 0 | uint8_t afc; |
175 | 0 | unsigned timeout = 0; |
176 | |
|
177 | 0 | found = false; |
178 | 0 | while (false == found && timeout++ < SYNC_STEPS * SYNC_STEPS) { |
179 | 0 | (*idx)++; |
180 | 0 | if (!wtap_read_bytes_or_eof( |
181 | 0 | wth->fh, buffer, MP2T_SIZE+trailer_len, err, err_info)) { |
182 | | /* Read error, short read, or EOF */ |
183 | 0 | return false; |
184 | 0 | } |
185 | | |
186 | 0 | if (MP2T_SYNC_BYTE != buffer[0]) { |
187 | 0 | continue; |
188 | 0 | } |
189 | | |
190 | | /* Read out the AFC value. */ |
191 | 0 | afc = 3 & (buffer[3] >> 4); |
192 | 0 | if (afc < 2) { |
193 | 0 | continue; |
194 | 0 | } |
195 | | |
196 | | /* Check the length. */ |
197 | 0 | if (buffer[4] < 7) { |
198 | 0 | continue; |
199 | 0 | } |
200 | | |
201 | | /* Check that there is the PCR flag. */ |
202 | 0 | if (0x10 != (0x10 & buffer[5])) { |
203 | 0 | continue; |
204 | 0 | } |
205 | | |
206 | | /* We have a PCR value! */ |
207 | 0 | *pcr = mp2t_read_pcr(&buffer[6]); |
208 | 0 | *pid = 0x01ff & pntohu16(&buffer[1]); |
209 | 0 | found = true; |
210 | 0 | } |
211 | | |
212 | 0 | return found; |
213 | 0 | } |
214 | | |
215 | | static wtap_open_return_val |
216 | | mp2t_bits_per_second(wtap *wth, uint32_t first, uint8_t trailer_len, |
217 | | uint64_t *bitrate, int *err, char **err_info) |
218 | 0 | { |
219 | 0 | uint32_t pn1, pn2; |
220 | 0 | uint64_t pcr1, pcr2; |
221 | 0 | uint16_t pid1, pid2; |
222 | 0 | uint32_t idx; |
223 | 0 | uint64_t pcr_delta, bits_passed; |
224 | | |
225 | | /* Find the first PCR + PID. |
226 | | * Then find another PCR in that PID. |
227 | | * Take the difference and that's our bitrate. |
228 | | * All the different PCRs in different PIDs 'should' be the same. |
229 | | * |
230 | | * XXX - is this assuming that the time stamps in the PCRs correspond |
231 | | * to the time scale of the underlying transport stream? |
232 | | */ |
233 | 0 | idx = first; |
234 | |
|
235 | 0 | if (!mp2t_find_next_pcr(wth, trailer_len, err, err_info, &idx, &pcr1, &pid1)) { |
236 | | /* Read error, short read, or EOF */ |
237 | 0 | if (*err == WTAP_ERR_SHORT_READ) |
238 | 0 | return WTAP_OPEN_NOT_MINE; /* not a full frame */ |
239 | 0 | if (*err != 0) |
240 | 0 | return WTAP_OPEN_ERROR; |
241 | | |
242 | | /* We don't have any PCRs, so we can't guess the bit rate. |
243 | | * Default to something reasonable. |
244 | | */ |
245 | 0 | *bitrate = MP2T_QAM64_BITRATE; |
246 | 0 | return WTAP_OPEN_MINE; |
247 | 0 | } |
248 | | |
249 | 0 | pn1 = idx; |
250 | 0 | pn2 = pn1; |
251 | |
|
252 | 0 | while (pn1 == pn2) { |
253 | 0 | if (!mp2t_find_next_pcr(wth, trailer_len, err, err_info, &idx, &pcr2, &pid2)) { |
254 | | /* Read error, short read, or EOF */ |
255 | 0 | if (*err == WTAP_ERR_SHORT_READ) |
256 | 0 | return WTAP_OPEN_NOT_MINE; /* not a full frame */ |
257 | 0 | if (*err != 0) |
258 | 0 | return WTAP_OPEN_ERROR; |
259 | | |
260 | | /* We don't have two PCRs for the same PID, so we can't guess |
261 | | * the bit rate. |
262 | | * Default to something reasonable. |
263 | | */ |
264 | 0 | *bitrate = MP2T_QAM64_BITRATE; |
265 | 0 | return WTAP_OPEN_MINE; |
266 | 0 | } |
267 | | |
268 | 0 | if (pid1 == pid2) { |
269 | 0 | pn2 = idx; |
270 | 0 | } |
271 | 0 | } |
272 | | |
273 | 0 | if (pcr2 <= pcr1) { |
274 | | /* The PCRs for that PID didn't go forward; treat that as an |
275 | | * indication that this isn't an MPEG-2 TS. |
276 | | */ |
277 | 0 | return WTAP_OPEN_NOT_MINE; |
278 | 0 | } |
279 | 0 | pcr_delta = pcr2 - pcr1; |
280 | | /* cast one of the factors to uint64_t |
281 | | otherwise, the multiplication would use uint32_t and could |
282 | | overflow before the result is assigned to the uint64_t bits_passed */ |
283 | 0 | bits_passed = (uint64_t)MP2T_SIZE * (pn2 - pn1) * 8; |
284 | |
|
285 | 0 | *bitrate = ((MP2T_PCR_CLOCK * bits_passed) / pcr_delta); |
286 | 0 | if (*bitrate == 0) { |
287 | | /* pcr_delta < MP2T_PCR_CLOCK * bits_passed (pn2 != pn1, |
288 | | * as that's the test for the loop above, so bits_passed |
289 | | * is non-zero). |
290 | | * |
291 | | * That will produce a fractional bitrate, which turns |
292 | | * into zero, causing a zero divide later. |
293 | | * |
294 | | * XXX - should we report this as "not ours"? A bitrate |
295 | | * of less than 1 bit per second is not very useful for any |
296 | | * form of audio/video, so presumably that's unlikely to |
297 | | * be an MP2T file. |
298 | | */ |
299 | 0 | return WTAP_OPEN_ERROR; |
300 | 0 | } |
301 | 0 | return WTAP_OPEN_MINE; |
302 | 0 | } |
303 | | |
304 | | wtap_open_return_val |
305 | | mp2t_open(wtap *wth, int *err, char **err_info) |
306 | 0 | { |
307 | 0 | uint8_t buffer[MP2T_SIZE+TRAILER_LEN_MAX]; |
308 | 0 | uint8_t trailer_len = 0; |
309 | 0 | uint8_t header_len = 0; |
310 | 0 | unsigned sync_steps = 0; |
311 | 0 | unsigned i; |
312 | 0 | uint32_t first = 0; |
313 | 0 | mp2t_filetype_t *mp2t; |
314 | 0 | wtap_open_return_val status; |
315 | 0 | uint64_t bitrate; |
316 | | |
317 | |
|
318 | 0 | if (!wtap_read_bytes(wth->fh, buffer, MP2T_SIZE, err, err_info)) { |
319 | 0 | if (*err != WTAP_ERR_SHORT_READ) |
320 | 0 | return WTAP_OPEN_ERROR; |
321 | 0 | return WTAP_OPEN_NOT_MINE; |
322 | 0 | } |
323 | | |
324 | 0 | for (i = 0; i < MP2T_SIZE; i++) { |
325 | 0 | if (MP2T_SYNC_BYTE == buffer[i]) { |
326 | 0 | first = i; |
327 | 0 | goto found; |
328 | 0 | } |
329 | 0 | } |
330 | | /* |
331 | | * No sync bytes found, so not an MPEG-2 Transport Stream file. |
332 | | */ |
333 | 0 | return WTAP_OPEN_NOT_MINE; /* wrong file type - not an mpeg2 ts file */ |
334 | | |
335 | 0 | found: |
336 | 0 | if (-1 == file_seek(wth->fh, first, SEEK_SET, err)) { |
337 | 0 | return WTAP_OPEN_ERROR; |
338 | 0 | } |
339 | | |
340 | | /* read some packets and make sure they all start with a sync byte */ |
341 | 0 | do { |
342 | 0 | if (!wtap_read_bytes(wth->fh, buffer, MP2T_SIZE+trailer_len, err, err_info)) { |
343 | 0 | if (*err != WTAP_ERR_SHORT_READ) |
344 | 0 | return WTAP_OPEN_ERROR; /* read error */ |
345 | 0 | if(sync_steps<2) return WTAP_OPEN_NOT_MINE; /* wrong file type - not an mpeg2 ts file */ |
346 | 0 | break; /* end of file, that's ok if we're still in sync */ |
347 | 0 | } |
348 | 0 | if (buffer[0] == MP2T_SYNC_BYTE) { |
349 | 0 | sync_steps++; |
350 | 0 | } |
351 | 0 | else { |
352 | | /* no sync byte found, check if trailing data is appended |
353 | | and we have to increase the packet size */ |
354 | | |
355 | | /* if we've already detected a trailer field, we must remain in sync |
356 | | another mismatch means we have no mpeg2 ts file */ |
357 | 0 | if (trailer_len>0) { |
358 | | /* check for header with spurious sync byte in header */ |
359 | 0 | if (first < trailer_len) { |
360 | 0 | first += 1; |
361 | 0 | trailer_len -= 1; |
362 | 0 | if (-1 == file_seek(wth->fh, first, SEEK_SET, err)) { |
363 | 0 | return WTAP_OPEN_ERROR; |
364 | 0 | } |
365 | | /* Shouldn't fail, we just read this */ |
366 | 0 | if (!wtap_read_bytes(wth->fh, buffer, MP2T_SIZE, err, err_info)) { |
367 | 0 | if (*err != WTAP_ERR_SHORT_READ) |
368 | 0 | return WTAP_OPEN_ERROR; |
369 | 0 | return WTAP_OPEN_NOT_MINE; |
370 | 0 | } |
371 | 0 | for (i = 0; i < trailer_len; i++) { |
372 | 0 | if (MP2T_SYNC_BYTE == buffer[i]) { |
373 | 0 | first += i; |
374 | 0 | trailer_len -= i; |
375 | 0 | goto found; |
376 | 0 | } |
377 | 0 | } |
378 | 0 | } |
379 | 0 | return WTAP_OPEN_NOT_MINE; |
380 | 0 | } |
381 | | |
382 | | /* check if a trailer is appended to the packet */ |
383 | 0 | for (i=0; i<TRAILER_LEN_MAX; i++) { |
384 | 0 | if (buffer[i] == MP2T_SYNC_BYTE) { |
385 | 0 | trailer_len = i; |
386 | 0 | if (-1 == file_seek(wth->fh, first, SEEK_SET, err)) { |
387 | 0 | return WTAP_OPEN_ERROR; |
388 | 0 | } |
389 | 0 | sync_steps = 0; |
390 | 0 | break; |
391 | 0 | } |
392 | 0 | } |
393 | | /* no sync byte found in the vicinity, this is no mpeg2 ts file */ |
394 | 0 | if (i==TRAILER_LEN_MAX) |
395 | 0 | return WTAP_OPEN_NOT_MINE; |
396 | 0 | } |
397 | 0 | } while (sync_steps < SYNC_STEPS); |
398 | | |
399 | 0 | if (-1 == file_seek(wth->fh, first, SEEK_SET, err)) { |
400 | 0 | return WTAP_OPEN_ERROR; |
401 | 0 | } |
402 | | |
403 | | /* Ensure there is a valid bitrate */ |
404 | 0 | status = mp2t_bits_per_second(wth, first, trailer_len, |
405 | 0 | &bitrate, err, err_info); |
406 | 0 | if (status != WTAP_OPEN_MINE) { |
407 | 0 | return status; |
408 | 0 | } |
409 | | |
410 | | /* If the packet didn't start on a sync byte, the "trailer" might |
411 | | * be a header. At least BDAV M2TS does this with a four byte header. */ |
412 | 0 | header_len = MIN(first, trailer_len); |
413 | 0 | first -= header_len; |
414 | 0 | trailer_len -= header_len; |
415 | |
|
416 | 0 | if (-1 == file_seek(wth->fh, first, SEEK_SET, err)) { |
417 | 0 | return WTAP_OPEN_ERROR; |
418 | 0 | } |
419 | | |
420 | 0 | wth->file_type_subtype = mp2t_file_type_subtype; |
421 | 0 | wth->file_encap = WTAP_ENCAP_MPEG_2_TS; |
422 | 0 | wth->file_tsprec = WTAP_TSPREC_NSEC; |
423 | 0 | wth->subtype_read = mp2t_read; |
424 | 0 | wth->subtype_seek_read = mp2t_seek_read; |
425 | 0 | wth->snapshot_length = 0; |
426 | |
|
427 | 0 | mp2t = g_new(mp2t_filetype_t, 1); |
428 | |
|
429 | 0 | wth->priv = mp2t; |
430 | 0 | mp2t->start_offset = first; |
431 | 0 | mp2t->trailer_len = trailer_len; |
432 | 0 | mp2t->header_len = header_len; |
433 | 0 | mp2t->bitrate = bitrate; |
434 | |
|
435 | 0 | return WTAP_OPEN_MINE; |
436 | 0 | } |
437 | | |
438 | | static int mp2t_dump_can_write_encap(int encap) |
439 | 0 | { |
440 | | /* Per-packet encapsulations aren't supported. */ |
441 | 0 | if (encap == WTAP_ENCAP_PER_PACKET) { |
442 | 0 | return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED; |
443 | 0 | } |
444 | | |
445 | | /* This is the only encapsulation type we write. */ |
446 | 0 | if (encap != WTAP_ENCAP_MPEG_2_TS) { |
447 | 0 | return WTAP_ERR_UNWRITABLE_ENCAP; |
448 | 0 | } |
449 | | |
450 | 0 | return 0; |
451 | 0 | } |
452 | | |
453 | | /* Write a record for a packet to a dump file. |
454 | | Returns true on success, false on failure. */ |
455 | | static bool mp2t_dump(wtap_dumper *wdh, const wtap_rec *rec, |
456 | | int *err, char **err_info _U_) |
457 | 0 | { |
458 | | /* We can only write packet records. */ |
459 | 0 | if (rec->rec_type != REC_TYPE_PACKET) { |
460 | 0 | *err = WTAP_ERR_UNWRITABLE_REC_TYPE; |
461 | 0 | *err_info = wtap_unwritable_rec_type_err_string(rec); |
462 | 0 | return false; |
463 | 0 | } |
464 | | |
465 | | /* |
466 | | * Make sure this packet doesn't have a link-layer type that |
467 | | * differs from the one for the file. |
468 | | */ |
469 | 0 | if (wdh->file_encap != rec->rec_header.packet_header.pkt_encap) { |
470 | 0 | *err = WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED; |
471 | 0 | return false; |
472 | 0 | } |
473 | | |
474 | | /* A MPEG-2 Transport Stream is just the packet bytes, with no header. |
475 | | * The sync byte is supposed to identify where packets start. |
476 | | * Note this drops existing headers and trailers currently, since we |
477 | | * don't include them in the record. |
478 | | */ |
479 | 0 | if (!wtap_dump_file_write(wdh, ws_buffer_start_ptr(&rec->data), rec->rec_header.packet_header.caplen, err)) { |
480 | 0 | return false; |
481 | 0 | } |
482 | | |
483 | 0 | return true; |
484 | 0 | } |
485 | | |
486 | | /* Returns true on success, false on failure; sets "*err" to an error code on |
487 | | failure */ |
488 | | static bool mp2t_dump_open(wtap_dumper *wdh, int *err _U_, char **err_info _U_) |
489 | 0 | { |
490 | | /* There is no header, so we just always return true. */ |
491 | 0 | wdh->subtype_write = mp2t_dump; |
492 | |
|
493 | 0 | return true; |
494 | 0 | } |
495 | | |
496 | | static const struct supported_block_type mp2t_blocks_supported[] = { |
497 | | /* |
498 | | * We support packet blocks, with no comments or other options. |
499 | | */ |
500 | | { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED } |
501 | | }; |
502 | | |
503 | | static const struct file_type_subtype_info mp2t_info = { |
504 | | "MPEG2 transport stream", "mp2t", "mp2t", "ts;m2ts;mpg", |
505 | | false, BLOCKS_SUPPORTED(mp2t_blocks_supported), |
506 | | mp2t_dump_can_write_encap, mp2t_dump_open, NULL |
507 | | }; |
508 | | |
509 | | void register_mp2t(void) |
510 | 15 | { |
511 | 15 | mp2t_file_type_subtype = wtap_register_file_type_subtype(&mp2t_info); |
512 | | |
513 | | /* |
514 | | * Register name for backwards compatibility with the |
515 | | * wtap_filetypes table in Lua. |
516 | | */ |
517 | 15 | wtap_register_backwards_compatibility_lua_name("MPEG_2_TS", |
518 | 15 | mp2t_file_type_subtype); |
519 | 15 | } |
520 | | |
521 | | /* |
522 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
523 | | * |
524 | | * Local variables: |
525 | | * c-basic-offset: 4 |
526 | | * tab-width: 8 |
527 | | * indent-tabs-mode: nil |
528 | | * End: |
529 | | * |
530 | | * vi: set shiftwidth=4 tabstop=8 expandtab: |
531 | | * :indentSize=4:tabSize=8:noTabs=true: |
532 | | */ |