Bugfixes of ASTERIX I034
[metze/wireshark/wip.git] / wiretap / mp2t.c
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
13 #include <sys/types.h>
14
15 #ifdef HAVE_UNISTD_H
16 #include <unistd.h>
17 #endif
18
19 #include "mp2t.h"
20
21 #include "wtap-int.h"
22 #include <wsutil/buffer.h>
23 #include "file_wrappers.h"
24 #include <errno.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <time.h>
28
29 #define MP2T_SYNC_BYTE      0x47
30 #define MP2T_SIZE           188
31 #define MP2T_QAM64_BITRATE  26970350    /* bits per second */
32 #define MP2T_PCR_CLOCK      27000000    /* cycles per second - 27MHz */
33
34 /* we try to detect trailing data up to 40 bytes after each packet */
35 #define TRAILER_LEN_MAX 40
36
37 /* number of consecutive packets we must read to decide that a file
38    is actually an mpeg2 ts */
39 #define SYNC_STEPS   10
40
41
42 typedef struct {
43     guint32 start_offset;
44     guint64 bitrate;
45     /* length of trailing data (e.g. FEC) that's appended after each packet */
46     guint8  trailer_len;
47 } mp2t_filetype_t;
48
49 static gboolean
50 mp2t_read_packet(mp2t_filetype_t *mp2t, FILE_T fh, gint64 offset,
51                  wtap_rec *rec, Buffer *buf, int *err,
52                  gchar **err_info)
53 {
54     guint64 tmp;
55
56     /*
57      * MP2T_SIZE will always be less than WTAP_MAX_PACKET_SIZE_STANDARD, so
58      * we don't have to worry about the packet being too big.
59      */
60     ws_buffer_assure_space(buf, MP2T_SIZE);
61     if (!wtap_read_bytes_or_eof(fh, ws_buffer_start_ptr(buf), MP2T_SIZE, err, err_info))
62         return FALSE;
63
64     rec->rec_type = REC_TYPE_PACKET;
65
66     /* XXX - relative, not absolute, time stamps */
67     rec->presence_flags = WTAP_HAS_TS;
68
69     /*
70      * Every packet in an MPEG2-TS stream is has a fixed size of
71      * MP2T_SIZE plus the number of trailer bytes.
72      *
73      * We assume that the bits in the transport stream are supplied at
74      * a constant rate; is that guaranteed by all media that use
75      * MPEG2-TS?  If so, the time offset, from the beginning of the
76      * stream, of a given packet is the packet offset, in bits, divided
77      * by the bitrate.
78      *
79      * It would be really cool to be able to configure the bitrate, in
80      * case our attempt to guess it from the PCRs of one of the programs
81      * doesn't get the right answer.
82      */
83     tmp = ((guint64)(offset - mp2t->start_offset) * 8); /* offset, in bits */
84     rec->ts.secs = (time_t)(tmp / mp2t->bitrate);
85     rec->ts.nsecs = (int)((tmp % mp2t->bitrate) * 1000000000 / mp2t->bitrate);
86
87     rec->rec_header.packet_header.caplen = MP2T_SIZE;
88     rec->rec_header.packet_header.len = MP2T_SIZE;
89
90     return TRUE;
91 }
92
93 static gboolean
94 mp2t_read(wtap *wth, int *err, gchar **err_info, gint64 *data_offset)
95 {
96     mp2t_filetype_t *mp2t;
97
98     mp2t = (mp2t_filetype_t*) wth->priv;
99
100     *data_offset = file_tell(wth->fh);
101
102     if (!mp2t_read_packet(mp2t, wth->fh, *data_offset, &wth->rec,
103                           wth->rec_data, err, err_info)) {
104         return FALSE;
105     }
106
107     /* if there's a trailer, skip it and go to the start of the next packet */
108     if (mp2t->trailer_len!=0) {
109         if (!wtap_read_bytes(wth->fh, NULL, mp2t->trailer_len, err, err_info)) {
110             return FALSE;
111         }
112     }
113
114     return TRUE;
115 }
116
117 static gboolean
118 mp2t_seek_read(wtap *wth, gint64 seek_off, wtap_rec *rec,
119         Buffer *buf, int *err, gchar **err_info)
120 {
121     mp2t_filetype_t *mp2t;
122
123     if (-1 == file_seek(wth->random_fh, seek_off, SEEK_SET, err)) {
124         return FALSE;
125     }
126
127     mp2t = (mp2t_filetype_t*) wth->priv;
128
129     if (!mp2t_read_packet(mp2t, wth->random_fh, seek_off, rec, buf,
130                           err, err_info)) {
131         if (*err == 0)
132             *err = WTAP_ERR_SHORT_READ;
133         return FALSE;
134     }
135     return TRUE;
136 }
137
138 static guint64
139 mp2t_read_pcr(guint8 *buffer)
140 {
141     guint64 base;
142     guint64 ext;
143
144     base = pntoh40(buffer);
145     base >>= 7;
146
147     ext = pntoh16(&buffer[4]);
148     ext &= 0x01ff;
149
150     return (base * 300 + ext);
151 }
152
153 static gboolean
154 mp2t_find_next_pcr(wtap *wth, guint8 trailer_len,
155         int *err, gchar **err_info, guint32 *idx, guint64 *pcr, guint16 *pid)
156 {
157     guint8 buffer[MP2T_SIZE+TRAILER_LEN_MAX];
158     gboolean found;
159     guint8 afc;
160     guint timeout = 0;
161
162     found = FALSE;
163     while (FALSE == found && timeout++ < SYNC_STEPS * SYNC_STEPS) {
164         (*idx)++;
165         if (!wtap_read_bytes_or_eof(
166                     wth->fh, buffer, MP2T_SIZE+trailer_len, err, err_info)) {
167             /* Read error, short read, or EOF */
168             return FALSE;
169         }
170
171         if (MP2T_SYNC_BYTE != buffer[0]) {
172             continue;
173         }
174
175         /* Read out the AFC value. */
176         afc = 3 & (buffer[3] >> 4);
177         if (afc < 2) {
178             continue;
179         }
180
181         /* Check the length. */
182         if (buffer[4] < 7) {
183             continue;
184         }
185
186         /* Check that there is the PCR flag. */
187         if (0x10 != (0x10 & buffer[5])) {
188             continue;
189         }
190
191         /* We have a PCR value! */
192         *pcr = mp2t_read_pcr(&buffer[6]);
193         *pid = 0x01ff & pntoh16(&buffer[1]);
194         found = TRUE;
195     }
196
197     return found;
198 }
199
200 static wtap_open_return_val
201 mp2t_bits_per_second(wtap *wth, guint32 first, guint8 trailer_len,
202         guint64 *bitrate, int *err, gchar **err_info)
203 {
204     guint32 pn1, pn2;
205     guint64 pcr1, pcr2;
206     guint16 pid1, pid2;
207     guint32 idx;
208     guint64 pcr_delta, bits_passed;
209
210     /* Find the first PCR + PID.
211      * Then find another PCR in that PID.
212      * Take the difference and that's our bitrate.
213      * All the different PCRs in different PIDs 'should' be the same.
214      *
215      * XXX - is this assuming that the time stamps in the PCRs correspond
216      * to the time scale of the underlying transport stream?
217      */
218     idx = first;
219
220     if (!mp2t_find_next_pcr(wth, trailer_len, err, err_info, &idx, &pcr1, &pid1)) {
221         /* Read error, short read, or EOF */
222         if (*err == WTAP_ERR_SHORT_READ)
223             return WTAP_OPEN_NOT_MINE;    /* not a full frame */
224         if (*err != 0)
225             return WTAP_OPEN_ERROR;
226
227         /* We don't have any PCRs, so we can't guess the bit rate.
228          * Default to something reasonable.
229          */
230         *bitrate = MP2T_QAM64_BITRATE;
231         return WTAP_OPEN_MINE;
232     }
233
234     pn1 = idx;
235     pn2 = pn1;
236
237     while (pn1 == pn2) {
238         if (!mp2t_find_next_pcr(wth, trailer_len, err, err_info, &idx, &pcr2, &pid2)) {
239             /* Read error, short read, or EOF */
240             if (*err == WTAP_ERR_SHORT_READ)
241                 return WTAP_OPEN_NOT_MINE;    /* not a full frame */
242             if (*err != 0)
243                 return WTAP_OPEN_ERROR;
244
245             /* We don't have two PCRs for the same PID, so we can't guess
246              * the bit rate.
247              * Default to something reasonable.
248              */
249             *bitrate = MP2T_QAM64_BITRATE;
250             return WTAP_OPEN_MINE;
251         }
252
253         if (pid1 == pid2) {
254             pn2 = idx;
255         }
256     }
257
258     if (pcr2 <= pcr1) {
259         /* The PCRs for that PID didn't go forward; treat that as an
260          * indication that this isn't an MPEG-2 TS.
261          */
262         return WTAP_OPEN_NOT_MINE;
263     }
264     pcr_delta = pcr2 - pcr1;
265     /* cast one of the factors to guint64
266        otherwise, the multiplication would use guint32 and could
267        overflow before the result is assigned to the guint64 bits_passed */
268     bits_passed = (guint64)MP2T_SIZE * (pn2 - pn1) * 8;
269
270     *bitrate = ((MP2T_PCR_CLOCK * bits_passed) / pcr_delta);
271     if (*bitrate == 0) {
272         /* pcr_delta < MP2T_PCR_CLOCK * bits_passed (pn2 != pn1,
273          * as that's the test for the loop above, so bits_passed
274          * is non-zero).
275          *
276          * That will produce a fractional bitrate, which turns
277          * into zero, causing a zero divide later.
278          *
279          * XXX - should we report this as "not ours"?  A bitrate
280          * of less than 1 bit per second is not very useful for any
281          * form of audio/video, so presumably that's unlikely to
282          * be an MP2T file.
283          */
284         return WTAP_OPEN_ERROR;
285     }
286     return WTAP_OPEN_MINE;
287 }
288
289 wtap_open_return_val
290 mp2t_open(wtap *wth, int *err, gchar **err_info)
291 {
292     guint8 buffer[MP2T_SIZE+TRAILER_LEN_MAX];
293     guint8 trailer_len = 0;
294     guint sync_steps = 0;
295     guint i;
296     guint32 first = 0;
297     mp2t_filetype_t *mp2t;
298     wtap_open_return_val status;
299     guint64 bitrate;
300
301
302     if (!wtap_read_bytes(wth->fh, buffer, MP2T_SIZE, err, err_info)) {
303         if (*err != WTAP_ERR_SHORT_READ)
304             return WTAP_OPEN_ERROR;
305         return WTAP_OPEN_NOT_MINE;
306     }
307
308     for (i = 0; i < MP2T_SIZE; i++) {
309         if (MP2T_SYNC_BYTE == buffer[i]) {
310             first = i;
311             goto found;
312         }
313     }
314     /*
315      * No sync bytes found, so not an MPEG-2 Transport Stream file.
316      */
317     return WTAP_OPEN_NOT_MINE; /* wrong file type - not an mpeg2 ts file */
318
319 found:
320     if (-1 == file_seek(wth->fh, first, SEEK_SET, err)) {
321         return WTAP_OPEN_ERROR;
322     }
323
324     /* read some packets and make sure they all start with a sync byte */
325     do {
326        if (!wtap_read_bytes(wth->fh, buffer, MP2T_SIZE+trailer_len, err, err_info)) {
327           if (*err != WTAP_ERR_SHORT_READ)
328             return WTAP_OPEN_ERROR;  /* read error */
329           if(sync_steps<2) return WTAP_OPEN_NOT_MINE; /* wrong file type - not an mpeg2 ts file */
330           break;  /* end of file, that's ok if we're still in sync */
331        }
332        if (buffer[0] == MP2T_SYNC_BYTE) {
333                sync_steps++;
334        }
335        else {
336            /* no sync byte found, check if trailing data is appended
337               and we have to increase the packet size */
338
339            /* if we've already detected a trailer field, we must remain in sync
340               another mismatch means we have no mpeg2 ts file */
341            if (trailer_len>0)
342                return WTAP_OPEN_NOT_MINE;
343
344            /* check if a trailer is appended to the packet */
345            for (i=0; i<TRAILER_LEN_MAX; i++) {
346                if (buffer[i] == MP2T_SYNC_BYTE) {
347                    trailer_len = i;
348                    if (-1 == file_seek(wth->fh, first, SEEK_SET, err)) {
349                        return WTAP_OPEN_ERROR;
350                    }
351                    sync_steps = 0;
352                    break;
353                }
354            }
355            /* no sync byte found in the vicinity, this is no mpeg2 ts file */
356            if (i==TRAILER_LEN_MAX)
357                return WTAP_OPEN_NOT_MINE;
358        }
359     } while (sync_steps < SYNC_STEPS);
360
361     if (-1 == file_seek(wth->fh, first, SEEK_SET, err)) {
362         return WTAP_OPEN_ERROR;
363     }
364
365     /* Ensure there is a valid bitrate */
366     status = mp2t_bits_per_second(wth, first, trailer_len,
367             &bitrate, err, err_info);
368     if (status != WTAP_OPEN_MINE) {
369         return status;
370     }
371
372     if (-1 == file_seek(wth->fh, first, SEEK_SET, err)) {
373         return WTAP_OPEN_ERROR;
374     }
375
376     wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_MPEG_2_TS;
377     wth->file_encap = WTAP_ENCAP_MPEG_2_TS;
378     wth->file_tsprec = WTAP_TSPREC_NSEC;
379     wth->subtype_read = mp2t_read;
380     wth->subtype_seek_read = mp2t_seek_read;
381     wth->snapshot_length = 0;
382
383     mp2t = (mp2t_filetype_t*) g_malloc(sizeof(mp2t_filetype_t));
384
385     wth->priv = mp2t;
386     mp2t->start_offset = first;
387     mp2t->trailer_len = trailer_len;
388     mp2t->bitrate = bitrate;
389
390     return WTAP_OPEN_MINE;
391 }
392
393 /*
394  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
395  *
396  * Local variables:
397  * c-basic-offset: 4
398  * tab-width: 8
399  * indent-tabs-mode: nil
400  * End:
401  *
402  * vi: set shiftwidth=4 tabstop=8 expandtab:
403  * :indentSize=4:tabSize=8:noTabs=true:
404  */