dcerpc-nt: add UNION_ALIGN_TO... helpers
[wireshark-sm.git] / wiretap / mpeg.c
blob6eb9bfdf79d1156e9f1b0ee5ebe6730e47d94a9a
1 /* mpeg.c
3 * MPEG-1/2 file format decoder for the Wiretap library.
4 * Written by Shaun Jackman <sjackman@gmail.com>
5 * Copyright 2007 Shaun Jackman
7 * MPEG-1/2 Program Streams (ISO/IEC 11172-1, ISO/IEC 13818-1 / ITU-T H.220.0)
8 * MPEG-1/2 Video bitstream (ISO/IEC 11172-2, ISO/IEC 13818-2 / ITU-T H.262)
9 * MPEG-1/2 Audio files (ISO/IEC 11172-3, ISO/IEC 13818-3)
11 * Does not handle other MPEG-2 container formats such as Transport Streams
12 * (also ISO/IEC 13818-1 / ITU-T H.222.0) or MPEG-4 containers such as
13 * MPEG-4 Part 14 / MP4 (ISO/IEC 14496-14). Support in wiretap for those
14 * two formats is provided in mp2t.c and mp4.c, respectively.
16 * Wiretap Library
17 * SPDX-License-Identifier: GPL-2.0-or-later
20 #include "config.h"
21 #include "mpeg.h"
23 #include <sys/types.h>
25 #ifdef HAVE_UNISTD_H
26 #include <unistd.h>
27 #endif
29 #include "wsutil/mpeg-audio.h"
31 #include "wtap-int.h"
32 #include <wsutil/buffer.h>
33 #include "file_wrappers.h"
34 #include <stdlib.h>
35 #include <string.h>
36 #include <time.h>
38 #define PES_PREFIX 1
39 #define PES_VALID(n) (((n) >> 8 & 0xffffff) == PES_PREFIX)
41 typedef struct {
42 nstime_t now;
43 time_t t0;
44 bool is_audio;
45 } mpeg_t;
47 static int mpeg_file_type_subtype = -1;
49 void register_mpeg(void);
51 static int
52 mpeg_resync(FILE_T fh, int *err)
54 int64_t offset = file_tell(fh);
55 int count = 0;
56 int byte = file_getc(fh);
58 while (byte != EOF) {
59 if (byte == 0xff && count > 0) {
60 byte = file_getc(fh);
61 if (byte != EOF && (byte & 0xe0) == 0xe0)
62 break;
63 } else
64 byte = file_getc(fh);
65 count++;
67 if (file_seek(fh, offset, SEEK_SET, err) == -1)
68 return 0;
69 return count;
72 #define SCRHZ 27000000
74 static unsigned int
75 mpeg_read_audio_packet(wtap *wth, FILE_T fh, bool is_random, int *err, char **err_info)
77 mpeg_t *mpeg = (mpeg_t *)wth->priv;
78 unsigned int packet_size;
79 uint32_t n;
80 if (!wtap_read_bytes_or_eof(fh, &n, sizeof n, err, err_info))
81 return 0;
82 if (file_seek(fh, -(int64_t)(sizeof n), SEEK_CUR, err) == -1)
83 return 0;
84 n = g_ntohl(n);
85 struct mpa mpa;
87 MPA_UNMARSHAL(&mpa, n);
88 if (MPA_VALID(&mpa)) {
89 packet_size = MPA_BYTES(&mpa);
90 if (!is_random) {
91 mpeg->now.nsecs += MPA_DURATION_NS(&mpa);
92 if (mpeg->now.nsecs >= 1000000000) {
93 mpeg->now.secs++;
94 mpeg->now.nsecs -= 1000000000;
97 } else {
98 if ((n & 0xffffff00) == 0x49443300) {
99 /* We have an ID3v2 header; read the size */
100 if (file_seek(fh, 6, SEEK_CUR, err) == -1)
101 return 0;
102 if (!wtap_read_bytes_or_eof(fh, &n, sizeof n, err, err_info))
103 return 0;
104 if (file_seek(fh, -(int64_t)(6+sizeof(n)), SEEK_CUR, err) == -1)
105 return 0;
106 n = g_ntohl(n);
108 /* ID3v2 size does not include the 10-byte header */
109 packet_size = decode_synchsafe_int(n) + 10;
110 } else {
111 packet_size = mpeg_resync(fh, err);
114 return packet_size;
117 static unsigned int
118 mpeg_read_pes_packet(wtap *wth, FILE_T fh, bool is_random, int *err, char **err_info)
120 mpeg_t *mpeg = (mpeg_t *)wth->priv;
121 unsigned int packet_size = 0;
122 uint32_t n;
123 while (1) {
124 if (!wtap_read_bytes_or_eof(fh, &n, sizeof n, err, err_info))
125 return 0;
126 if (file_seek(fh, -(int64_t)(sizeof n), SEEK_CUR, err) == -1)
127 return 0;
128 n = g_ntohl(n);
129 if (PES_VALID(n)) {
130 break;
131 } else if (n == PES_PREFIX) {
132 if (!wtap_read_bytes(fh, NULL, 1, err, err_info))
133 return 0;
134 break;
135 } else if (n != 0) {
136 /* XXX: We could try to recover from errors and
137 * resynchronize to the next start code.
139 *err = WTAP_ERR_BAD_FILE;
140 *err_info = ws_strdup("mpeg: Non-zero stuffing bytes before start code");
141 return 0;
143 if (!wtap_read_bytes(fh, NULL, 2, err, err_info))
144 return 0;
147 int64_t offset = file_tell(fh);
148 uint8_t stream;
150 if (!wtap_read_bytes(fh, NULL, 3, err, err_info))
151 return 0;
153 if (!wtap_read_bytes(fh, &stream, sizeof stream, err, err_info))
154 return 0;
156 if (stream == 0xba) {
157 uint32_t pack1;
158 uint32_t pack0;
159 uint64_t pack;
160 uint8_t stuffing;
162 if (!wtap_read_bytes(fh, &pack1, sizeof pack1, err, err_info))
163 return 0;
164 if (!wtap_read_bytes(fh, &pack0, sizeof pack0, err, err_info))
165 return 0;
166 pack = (uint64_t)g_ntohl(pack1) << 32 | g_ntohl(pack0);
168 switch (pack >> 62) {
169 case 1:
170 if (!wtap_read_bytes(fh, NULL, 1, err,
171 err_info))
172 return false;
173 if (!wtap_read_bytes(fh, &stuffing,
174 sizeof stuffing, err, err_info))
175 return false;
176 stuffing &= 0x07;
177 packet_size = 14 + stuffing;
179 if (!is_random) {
180 uint64_t bytes = pack >> 16;
181 uint64_t ts_val =
182 (bytes >> 43 & 0x0007) << 30 |
183 (bytes >> 27 & 0x7fff) << 15 |
184 (bytes >> 11 & 0x7fff) << 0;
185 unsigned ext = (unsigned)((bytes >> 1) & 0x1ff);
186 uint64_t cr = 300 * ts_val + ext;
187 unsigned rem = (unsigned)(cr % SCRHZ);
188 mpeg->now.secs
189 = mpeg->t0 + (time_t)(cr / SCRHZ);
190 mpeg->now.nsecs
191 = (int)(INT64_C(1000000000) * rem / SCRHZ);
193 break;
194 default:
195 packet_size = 12;
197 } else if (stream == 0xb9) {
198 /* MPEG_program_end_code */
199 packet_size = 4;
200 } else {
201 uint16_t length;
202 if (!wtap_read_bytes(fh, &length, sizeof length, err, err_info))
203 return false;
204 length = g_ntohs(length);
205 packet_size = 6 + length;
208 if (file_seek(fh, offset, SEEK_SET, err) == -1)
209 return 0;
211 return packet_size;
214 static bool
215 mpeg_read_packet(wtap *wth, FILE_T fh, wtap_rec *rec, Buffer *buf,
216 bool is_random, int *err, char **err_info)
218 mpeg_t *mpeg = (mpeg_t *)wth->priv;
219 unsigned int packet_size;
220 nstime_t ts = mpeg->now;
222 if (mpeg->is_audio) {
223 /* mpeg_read_audio_packet calculates the duration of this
224 * packet to determine an updated relative timestamp for the
225 * next packet, if possible.
227 packet_size = mpeg_read_audio_packet(wth, fh, is_random, err, err_info);
228 } else {
229 /* mpeg_read_pes_packet uses the System Clock Reference counter
230 * to produce a relative timestamp for this packet, if possible.
232 packet_size = mpeg_read_pes_packet(wth, fh, is_random, err, err_info);
235 if (packet_size == 0)
236 return false;
238 if (!wtap_read_packet_bytes(fh, buf, packet_size, err, err_info))
239 return false;
241 rec->rec_type = REC_TYPE_PACKET;
242 rec->block = wtap_block_create(WTAP_BLOCK_PACKET);
244 rec->presence_flags = 0; /* we may or may not have a time stamp */
245 if (!is_random) {
246 /* XXX - relative, not absolute, time stamps */
247 rec->presence_flags = WTAP_HAS_TS;
248 rec->ts = ts;
250 rec->rec_header.packet_header.caplen = packet_size;
251 rec->rec_header.packet_header.len = packet_size;
253 return true;
256 static bool
257 mpeg_read(wtap *wth, wtap_rec *rec, Buffer *buf, int *err,
258 char **err_info, int64_t *data_offset)
260 *data_offset = file_tell(wth->fh);
262 return mpeg_read_packet(wth, wth->fh, rec, buf, false, err, err_info);
265 static bool
266 mpeg_seek_read(wtap *wth, int64_t seek_off,
267 wtap_rec *rec, Buffer *buf,
268 int *err, char **err_info)
270 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
271 return false;
273 if (!mpeg_read_packet(wth, wth->random_fh, rec, buf, true, err,
274 err_info)) {
275 if (*err == 0)
276 *err = WTAP_ERR_SHORT_READ;
277 return false;
279 return true;
282 struct _mpeg_magic {
283 size_t len;
284 const char* match;
285 bool is_audio;
286 } magic[] = {
287 { 3, "TAG", true }, /* ID3v1 */
288 /* XXX: ID3v1 tags come at the end of MP3 files, so in practice the
289 * untagged magic number is used instead.
291 { 3, "ID3", true }, /* ID3v2 */
292 { 3, "\0\0\1", false }, /* MPEG PES */
293 { 2, "\xff\xfb", true }, /* MP3 (MPEG-1 Audio Layer 3, no CRC), taken from https://en.wikipedia.org/wiki/MP3#File_structure */
294 #if 0
295 /* XXX: The value above is for MPEG-1 Audio Layer 3 with no CRC.
296 * Only the first three nibbles are the guaranteed sync byte.
297 * For the fourth nibble, the first bit is '1' for MPEG-1 and
298 * '0' for MPEG-2 (i.e., extension to lower sampling rates),
299 * the next two bits indicate the layer (1 for layer 3, 2 for
300 * layer 2, 3 for layer 1, 0 reserved), and the last ("protection")
301 * bit is 1 if there is no CRC and 0 if there is a CRC.
303 * The mpeg-audio dissector handles these, so wiretap should open
304 * them. Including all of them might increase false positives though.
306 { 2, "\xff\xf2", true }, /* MPEG-2 Audio Layer 3, CRC */
307 { 2, "\xff\xf3", true }, /* MPEG-2 Audio Layer 3, No CRC */
308 { 2, "\xff\xf4", true }, /* MPEG-2 Audio Layer 2, CRC */
309 { 2, "\xff\xf5", true }, /* MPEG-2 Audio Layer 2, No CRC */
310 { 2, "\xff\xf6", true }, /* MPEG-2 Audio Layer 1, CRC */
311 { 2, "\xff\xf7", true }, /* MPEG-2 Audio Layer 1, No CRC */
312 { 2, "\xff\xfa", true }, /* MPEG-1 Audio Layer 3, CRC */
313 { 2, "\xff\xfc", true }, /* MPEG-1 Audio Layer 2, CRC */
314 { 2, "\xff\xfd", true }, /* MPEG-1 Audio Layer 2, No CRC */
315 { 2, "\xff\xfe", true }, /* MPEG-1 Audio Layer 1, CRC */
316 { 2, "\xff\xff", true }, /* MPEG-1 Audio Layer 1, No CRC */
317 #endif
318 { 0, NULL, false }
322 * Even though this dissector uses magic numbers, it is registered in
323 * file_access.c as OPEN_INFO_HEURISTIC because the magic numbers are
324 * short and prone to false positives.
326 * XXX: There's room for improvement in detection if needed. A Program Stream
327 * starts with the pack_start_code, \x00\x00\x01\xba, and an uncontainered
328 * Video bitstream starts with the sequence_header_code, \x00\x00\x01\xb3.
329 * We could use those instead of matching any PES packet, which would greatly
330 * reduce false positives with e.g. PacketLogger files. (Unlike Transport
331 * Streams, unaligned file starts are unlikely with PS.)
333 * Untagged MPEG Audio files would still have to be heuristics, though.
335 wtap_open_return_val
336 mpeg_open(wtap *wth, int *err, char **err_info)
338 char magic_buf[16];
339 struct _mpeg_magic* m;
340 mpeg_t *mpeg;
342 if (!wtap_read_bytes(wth->fh, magic_buf, sizeof magic_buf,
343 err, err_info)) {
344 if (*err != WTAP_ERR_SHORT_READ)
345 return WTAP_OPEN_ERROR;
346 return WTAP_OPEN_NOT_MINE;
349 for (m=magic; m->match; m++) {
350 if (memcmp(magic_buf, m->match, m->len) == 0)
351 goto good_magic;
354 return WTAP_OPEN_NOT_MINE;
356 good_magic:
357 /* This appears to be a file with MPEG data. */
358 if (file_seek(wth->fh, 0, SEEK_SET, err) == -1)
359 return WTAP_OPEN_ERROR;
361 wth->file_type_subtype = mpeg_file_type_subtype;
362 wth->file_encap = WTAP_ENCAP_MPEG;
363 wth->file_tsprec = WTAP_TSPREC_NSEC;
364 wth->subtype_read = mpeg_read;
365 wth->subtype_seek_read = mpeg_seek_read;
366 wth->snapshot_length = 0;
368 mpeg = g_new(mpeg_t, 1);
369 wth->priv = (void *)mpeg;
370 mpeg->now.secs = 0;
371 mpeg->now.nsecs = 0;
372 mpeg->t0 = mpeg->now.secs;
373 mpeg->is_audio = m->is_audio;
375 return WTAP_OPEN_MINE;
378 static const struct supported_block_type mpeg_blocks_supported[] = {
380 * This file format divides the file up into a "packet" for
381 * each frame, and doesn't support any options.
383 { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
386 static const struct file_type_subtype_info mpeg_info = {
387 "MPEG", "mpeg", "mpeg", "mpg;mp3",
388 false, BLOCKS_SUPPORTED(mpeg_blocks_supported),
389 NULL, NULL, NULL
392 void register_mpeg(void)
394 mpeg_file_type_subtype = wtap_register_file_type_subtype(&mpeg_info);
397 * Register name for backwards compatibility with the
398 * wtap_filetypes table in Lua.
400 wtap_register_backwards_compatibility_lua_name("MPEG",
401 mpeg_file_type_subtype);
405 * Editor modelines - https://www.wireshark.org/tools/modelines.html
407 * Local variables:
408 * c-basic-offset: 8
409 * tab-width: 8
410 * indent-tabs-mode: t
411 * End:
413 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
414 * :indentSize=8:tabSize=8:noTabs=false: