aboutsummaryrefslogtreecommitdiffstats
path: root/wiretap/mp2t.c
diff options
context:
space:
mode:
authorWeston Schmidt <weston_schmidt@alumni.purdue.edu>2015-03-18 21:51:03 -0700
committerMartin Kaiser <wireshark@kaiser.cx>2015-04-04 09:02:40 +0000
commit7253ee7611fb2e62f2a9326689e48f8d2177aed9 (patch)
treecb6d4dfe21d5c1428b5ce063ed4dcfb8267d736d /wiretap/mp2t.c
parentf031fafdcc5792ba5011e2fcd7a33cbea450148c (diff)
Add PCR based stream times for MPEG ts files.
Change-Id: Ie1308829c3ad44d842bf12c7ebc5c200c942d8cc Reviewed-on: https://code.wireshark.org/review/7750 Reviewed-by: Martin Kaiser <wireshark@kaiser.cx>
Diffstat (limited to 'wiretap/mp2t.c')
-rw-r--r--wiretap/mp2t.c120
1 files changed, 117 insertions, 3 deletions
diff --git a/wiretap/mp2t.c b/wiretap/mp2t.c
index f7d7f26920..3d111e5517 100644
--- a/wiretap/mp2t.c
+++ b/wiretap/mp2t.c
@@ -42,8 +42,8 @@
#define MP2T_SYNC_BYTE 0x47
#define MP2T_SIZE 188
-#define MP2T_QAM256_BITRATE 38810700 /* bits per second */
#define MP2T_QAM64_BITRATE 26970350 /* bits per second */
+#define MP2T_PCR_CLOCK 27000000 /* cycles per second - 27MHz */
/* we try to detect trailing data up to 40 bytes after each packet */
#define TRAILER_LEN_MAX 40
@@ -55,6 +55,7 @@
typedef struct {
int start_offset;
+ guint64 bitrate;
/* length of trailing data (e.g. FEC) that's appended after each packet */
guint8 trailer_len;
} mp2t_filetype_t;
@@ -86,8 +87,8 @@ mp2t_read_packet(mp2t_filetype_t *mp2t, FILE_T fh, gint64 offset,
* It would be really cool to be able to configure the bitrate...
*/
tmp = ((guint64)(offset - mp2t->start_offset) * 8); /* offset, in bits */
- phdr->ts.secs = (time_t)(tmp / MP2T_QAM256_BITRATE);
- phdr->ts.nsecs = (int)((tmp % MP2T_QAM256_BITRATE) * 1000000000 / MP2T_QAM256_BITRATE);
+ phdr->ts.secs = (time_t)(tmp / mp2t->bitrate);
+ phdr->ts.nsecs = (int)((tmp % mp2t->bitrate) * 1000000000 / mp2t->bitrate);
phdr->caplen = MP2T_SIZE;
phdr->len = MP2T_SIZE;
@@ -140,6 +141,104 @@ mp2t_seek_read(wtap *wth, gint64 seek_off, struct wtap_pkthdr *phdr,
return TRUE;
}
+static guint64
+mp2t_read_pcr(guint8 *buffer)
+{
+ guint64 base;
+ guint64 ext;
+
+ base = pntoh40(buffer);
+ base >>= 7;
+
+ ext = pntoh16(&buffer[4]);
+ ext &= 0x01ff;
+
+ return (base * 300 + ext);
+}
+
+static gboolean
+mp2t_find_next_pcr(wtap *wth, int *err, gchar **err_info, guint32 *index, guint64 *pcr, guint16 *pid)
+{
+ guint8 buffer[MP2T_SIZE];
+ gboolean found;
+ guint8 afc;
+
+ found = FALSE;
+ while (FALSE == found) {
+ (*index)++;
+ if (!wtap_read_bytes(wth->fh, buffer, MP2T_SIZE, err, err_info)) {
+ return FALSE;
+ }
+
+ if (MP2T_SYNC_BYTE != buffer[0]) {
+ continue;
+ }
+
+ /* Read out the AFC value. */
+ afc = 3 & (buffer[3] >> 4);
+ if (afc < 2) {
+ continue;
+ }
+
+ /* Check the length. */
+ if (buffer[4] < 7) {
+ continue;
+ }
+
+ /* Check that there is the PCR flag. */
+ if (0x10 != (0x10 & buffer[5])) {
+ continue;
+ }
+
+ /* We have a PCR value! */
+ *pcr = mp2t_read_pcr(&buffer[6]);
+ *pid = 0x01ff & pntoh16(&buffer[1]);
+ found = TRUE;
+ }
+
+ return TRUE;
+}
+
+static guint64
+mp2t_bits_per_second(wtap *wth, int *err, gchar **err_info)
+{
+ guint32 pn1, pn2;
+ guint64 pcr1, pcr2;
+ guint16 pid1, pid2;
+ guint32 index;
+ guint64 pcr_delta, bits_passed;
+
+ /* Find the first PCR + PID.
+ * Then find another PCR in that PID.
+ * Take the difference and that's our bitrate.
+ * All the different PCRs in different PIDs 'should' be the same.
+ */
+
+ index = 0;
+
+ if (FALSE == mp2t_find_next_pcr(wth, err, err_info, &index, &pcr1, &pid1)) {
+ return 0;
+ }
+
+ pn1 = index;
+ pn2 = pn1;
+
+ while (pn1 == pn2) {
+ if (FALSE == mp2t_find_next_pcr(wth, err, err_info, &index, &pcr2, &pid2)) {
+ return 0;
+ }
+
+ if (pid1 == pid2) {
+ pn2 = index;
+ }
+ }
+
+ pcr_delta = pcr2 - pcr1;
+ bits_passed = MP2T_SIZE * (pn2 - pn1) * 8;
+
+ return ((MP2T_PCR_CLOCK * bits_passed) / pcr_delta);
+}
+
wtap_open_return_val
mp2t_open(wtap *wth, int *err, gchar **err_info)
{
@@ -149,6 +248,7 @@ mp2t_open(wtap *wth, int *err, gchar **err_info)
int i;
int first;
mp2t_filetype_t *mp2t;
+ guint64 bitrate;
if (!wtap_read_bytes(wth->fh, buffer, MP2T_SIZE, err, err_info)) {
@@ -171,6 +271,7 @@ mp2t_open(wtap *wth, int *err, gchar **err_info)
if (-1 == file_seek(wth->fh, first, SEEK_SET, err)) {
return WTAP_OPEN_ERROR;
}
+
/* read some packets and make sure they all start with a sync byte */
do {
if (!wtap_read_bytes(wth->fh, buffer, MP2T_SIZE+trailer_len, err, err_info)) {
@@ -212,6 +313,18 @@ mp2t_open(wtap *wth, int *err, gchar **err_info)
return WTAP_OPEN_ERROR;
}
+ /* Ensure there is a valid bitrate */
+ bitrate = mp2t_bits_per_second(wth, err, err_info);
+
+ if (-1 == file_seek(wth->fh, first, SEEK_SET, err)) {
+ return WTAP_OPEN_ERROR;
+ }
+
+ if (0 == bitrate) {
+ /* We don't have a real bitrate, so we'll default to something reasonable. */
+ bitrate = MP2T_QAM64_BITRATE;
+ }
+
wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_MPEG_2_TS;
wth->file_encap = WTAP_ENCAP_MPEG_2_TS;
wth->file_tsprec = WTAP_TSPREC_NSEC;
@@ -224,6 +337,7 @@ mp2t_open(wtap *wth, int *err, gchar **err_info)
wth->priv = mp2t;
mp2t->start_offset = first;
mp2t->trailer_len = trailer_len;
+ mp2t->bitrate = bitrate;
return WTAP_OPEN_MINE;
}