summaryrefslogtreecommitdiffstats
path: root/wiretap/mp2t.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--wiretap/mp2t.c285
1 files changed, 193 insertions, 92 deletions
diff --git a/wiretap/mp2t.c b/wiretap/mp2t.c
index a0f3f611..14189970 100644
--- a/wiretap/mp2t.c
+++ b/wiretap/mp2t.c
@@ -9,6 +9,7 @@
*/
#include "config.h"
+#include "mp2t.h"
#include <sys/types.h>
@@ -16,8 +17,6 @@
#include <unistd.h>
#endif
-#include "mp2t.h"
-
#include "wtap-int.h"
#include <wsutil/buffer.h>
#include "file_wrappers.h"
@@ -39,22 +38,25 @@
typedef struct {
- guint32 start_offset;
- guint64 bitrate;
+ uint64_t bitrate;
+ uint32_t start_offset;
+ /* length of header data (e.g., TP_extra_header in BDAV m2ts files) before
+ * each packet) */
+ uint8_t header_len;
/* length of trailing data (e.g. FEC) that's appended after each packet */
- guint8 trailer_len;
+ uint8_t trailer_len;
} mp2t_filetype_t;
static int mp2t_file_type_subtype = -1;
void register_mp2t(void);
-static gboolean
-mp2t_read_packet(mp2t_filetype_t *mp2t, FILE_T fh, gint64 offset,
+static bool
+mp2t_read_packet(mp2t_filetype_t *mp2t, FILE_T fh, int64_t offset,
wtap_rec *rec, Buffer *buf, int *err,
- gchar **err_info)
+ char **err_info)
{
- guint64 tmp;
+ uint64_t tmp;
/*
* MP2T_SIZE will always be less than WTAP_MAX_PACKET_SIZE_STANDARD, so
@@ -62,7 +64,7 @@ mp2t_read_packet(mp2t_filetype_t *mp2t, FILE_T fh, gint64 offset,
*/
ws_buffer_assure_space(buf, MP2T_SIZE);
if (!wtap_read_bytes_or_eof(fh, ws_buffer_start_ptr(buf), MP2T_SIZE, err, err_info))
- return FALSE;
+ return false;
rec->rec_type = REC_TYPE_PACKET;
rec->block = wtap_block_create(WTAP_BLOCK_PACKET);
@@ -84,49 +86,61 @@ mp2t_read_packet(mp2t_filetype_t *mp2t, FILE_T fh, gint64 offset,
* case our attempt to guess it from the PCRs of one of the programs
* doesn't get the right answer.
*/
- tmp = ((guint64)(offset - mp2t->start_offset) * 8); /* offset, in bits */
+ tmp = ((uint64_t)(offset - mp2t->start_offset) * 8); /* offset, in bits */
rec->ts.secs = (time_t)(tmp / mp2t->bitrate);
rec->ts.nsecs = (int)((tmp % mp2t->bitrate) * 1000000000 / mp2t->bitrate);
rec->rec_header.packet_header.caplen = MP2T_SIZE;
rec->rec_header.packet_header.len = MP2T_SIZE;
- return TRUE;
+ return true;
}
-static gboolean
+static bool
mp2t_read(wtap *wth, wtap_rec *rec, Buffer *buf, int *err,
- gchar **err_info, gint64 *data_offset)
+ char **err_info, int64_t *data_offset)
{
mp2t_filetype_t *mp2t;
mp2t = (mp2t_filetype_t*) wth->priv;
+ /* if there's a header, skip it and go to the start of the packet */
+ /* XXX - Eventually we might want to process the header (and trailer?) in
+ * packet-mp2t.c, in which case we would read it in mp2t_read_packet and
+ * include header_len in the packet_header lengths. We'd probably want
+ * pseudo-header information to indicate it to packet-mp2t.c
+ */
+ if (mp2t->header_len!=0) {
+ if (!wtap_read_bytes_or_eof(wth->fh, NULL, mp2t->header_len, err, err_info)) {
+ return false;
+ }
+ }
+
*data_offset = file_tell(wth->fh);
if (!mp2t_read_packet(mp2t, wth->fh, *data_offset, rec, buf, err,
err_info)) {
- return FALSE;
+ return false;
}
/* if there's a trailer, skip it and go to the start of the next packet */
if (mp2t->trailer_len!=0) {
if (!wtap_read_bytes(wth->fh, NULL, mp2t->trailer_len, err, err_info)) {
- return FALSE;
+ return false;
}
}
- return TRUE;
+ return true;
}
-static gboolean
-mp2t_seek_read(wtap *wth, gint64 seek_off, wtap_rec *rec,
- Buffer *buf, int *err, gchar **err_info)
+static bool
+mp2t_seek_read(wtap *wth, int64_t seek_off, wtap_rec *rec,
+ Buffer *buf, int *err, char **err_info)
{
mp2t_filetype_t *mp2t;
if (-1 == file_seek(wth->random_fh, seek_off, SEEK_SET, err)) {
- return FALSE;
+ return false;
}
mp2t = (mp2t_filetype_t*) wth->priv;
@@ -135,16 +149,16 @@ mp2t_seek_read(wtap *wth, gint64 seek_off, wtap_rec *rec,
err, err_info)) {
if (*err == 0)
*err = WTAP_ERR_SHORT_READ;
- return FALSE;
+ return false;
}
- return TRUE;
+ return true;
}
-static guint64
-mp2t_read_pcr(guint8 *buffer)
+static uint64_t
+mp2t_read_pcr(uint8_t *buffer)
{
- guint64 base;
- guint64 ext;
+ uint64_t base;
+ uint64_t ext;
base = pntoh40(buffer);
base >>= 7;
@@ -155,22 +169,22 @@ mp2t_read_pcr(guint8 *buffer)
return (base * 300 + ext);
}
-static gboolean
-mp2t_find_next_pcr(wtap *wth, guint8 trailer_len,
- int *err, gchar **err_info, guint32 *idx, guint64 *pcr, guint16 *pid)
+static bool
+mp2t_find_next_pcr(wtap *wth, uint8_t trailer_len,
+ int *err, char **err_info, uint32_t *idx, uint64_t *pcr, uint16_t *pid)
{
- guint8 buffer[MP2T_SIZE+TRAILER_LEN_MAX];
- gboolean found;
- guint8 afc;
- guint timeout = 0;
+ uint8_t buffer[MP2T_SIZE+TRAILER_LEN_MAX];
+ bool found;
+ uint8_t afc;
+ unsigned timeout = 0;
- found = FALSE;
- while (FALSE == found && timeout++ < SYNC_STEPS * SYNC_STEPS) {
+ found = false;
+ while (false == found && timeout++ < SYNC_STEPS * SYNC_STEPS) {
(*idx)++;
if (!wtap_read_bytes_or_eof(
wth->fh, buffer, MP2T_SIZE+trailer_len, err, err_info)) {
/* Read error, short read, or EOF */
- return FALSE;
+ return false;
}
if (MP2T_SYNC_BYTE != buffer[0]) {
@@ -196,21 +210,21 @@ mp2t_find_next_pcr(wtap *wth, guint8 trailer_len,
/* We have a PCR value! */
*pcr = mp2t_read_pcr(&buffer[6]);
*pid = 0x01ff & pntoh16(&buffer[1]);
- found = TRUE;
+ found = true;
}
return found;
}
static wtap_open_return_val
-mp2t_bits_per_second(wtap *wth, guint32 first, guint8 trailer_len,
- guint64 *bitrate, int *err, gchar **err_info)
+mp2t_bits_per_second(wtap *wth, uint32_t first, uint8_t trailer_len,
+ uint64_t *bitrate, int *err, char **err_info)
{
- guint32 pn1, pn2;
- guint64 pcr1, pcr2;
- guint16 pid1, pid2;
- guint32 idx;
- guint64 pcr_delta, bits_passed;
+ uint32_t pn1, pn2;
+ uint64_t pcr1, pcr2;
+ uint16_t pid1, pid2;
+ uint32_t idx;
+ uint64_t pcr_delta, bits_passed;
/* Find the first PCR + PID.
* Then find another PCR in that PID.
@@ -267,10 +281,10 @@ mp2t_bits_per_second(wtap *wth, guint32 first, guint8 trailer_len,
return WTAP_OPEN_NOT_MINE;
}
pcr_delta = pcr2 - pcr1;
- /* cast one of the factors to guint64
- otherwise, the multiplication would use guint32 and could
- overflow before the result is assigned to the guint64 bits_passed */
- bits_passed = (guint64)MP2T_SIZE * (pn2 - pn1) * 8;
+ /* cast one of the factors to uint64_t
+ otherwise, the multiplication would use uint32_t and could
+ overflow before the result is assigned to the uint64_t bits_passed */
+ bits_passed = (uint64_t)MP2T_SIZE * (pn2 - pn1) * 8;
*bitrate = ((MP2T_PCR_CLOCK * bits_passed) / pcr_delta);
if (*bitrate == 0) {
@@ -292,16 +306,17 @@ mp2t_bits_per_second(wtap *wth, guint32 first, guint8 trailer_len,
}
wtap_open_return_val
-mp2t_open(wtap *wth, int *err, gchar **err_info)
+mp2t_open(wtap *wth, int *err, char **err_info)
{
- guint8 buffer[MP2T_SIZE+TRAILER_LEN_MAX];
- guint8 trailer_len = 0;
- guint sync_steps = 0;
- guint i;
- guint32 first = 0;
+ uint8_t buffer[MP2T_SIZE+TRAILER_LEN_MAX];
+ uint8_t trailer_len = 0;
+ uint8_t header_len = 0;
+ unsigned sync_steps = 0;
+ unsigned i;
+ uint32_t first = 0;
mp2t_filetype_t *mp2t;
wtap_open_return_val status;
- guint64 bitrate;
+ uint64_t bitrate;
if (!wtap_read_bytes(wth->fh, buffer, MP2T_SIZE, err, err_info)) {
@@ -328,39 +343,61 @@ found:
/* 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)) {
- if (*err != WTAP_ERR_SHORT_READ)
- return WTAP_OPEN_ERROR; /* read error */
- if(sync_steps<2) return WTAP_OPEN_NOT_MINE; /* wrong file type - not an mpeg2 ts file */
- break; /* end of file, that's ok if we're still in sync */
- }
- if (buffer[0] == MP2T_SYNC_BYTE) {
- sync_steps++;
- }
- else {
- /* no sync byte found, check if trailing data is appended
- and we have to increase the packet size */
-
- /* if we've already detected a trailer field, we must remain in sync
- another mismatch means we have no mpeg2 ts file */
- if (trailer_len>0)
- return WTAP_OPEN_NOT_MINE;
-
- /* check if a trailer is appended to the packet */
- for (i=0; i<TRAILER_LEN_MAX; i++) {
- if (buffer[i] == MP2T_SYNC_BYTE) {
- trailer_len = i;
- if (-1 == file_seek(wth->fh, first, SEEK_SET, err)) {
- return WTAP_OPEN_ERROR;
- }
- sync_steps = 0;
- break;
- }
- }
- /* no sync byte found in the vicinity, this is no mpeg2 ts file */
- if (i==TRAILER_LEN_MAX)
- return WTAP_OPEN_NOT_MINE;
- }
+ if (!wtap_read_bytes(wth->fh, buffer, MP2T_SIZE+trailer_len, err, err_info)) {
+ if (*err != WTAP_ERR_SHORT_READ)
+ return WTAP_OPEN_ERROR; /* read error */
+ if(sync_steps<2) return WTAP_OPEN_NOT_MINE; /* wrong file type - not an mpeg2 ts file */
+ break; /* end of file, that's ok if we're still in sync */
+ }
+ if (buffer[0] == MP2T_SYNC_BYTE) {
+ sync_steps++;
+ }
+ else {
+ /* no sync byte found, check if trailing data is appended
+ and we have to increase the packet size */
+
+ /* if we've already detected a trailer field, we must remain in sync
+ another mismatch means we have no mpeg2 ts file */
+ if (trailer_len>0) {
+ /* check for header with spurious sync byte in header */
+ if (first < trailer_len) {
+ first += 1;
+ trailer_len -= 1;
+ if (-1 == file_seek(wth->fh, first, SEEK_SET, err)) {
+ return WTAP_OPEN_ERROR;
+ }
+ /* Shouldn't fail, we just read this */
+ if (!wtap_read_bytes(wth->fh, buffer, MP2T_SIZE, err, err_info)) {
+ if (*err != WTAP_ERR_SHORT_READ)
+ return WTAP_OPEN_ERROR;
+ return WTAP_OPEN_NOT_MINE;
+ }
+ for (i = 0; i < trailer_len; i++) {
+ if (MP2T_SYNC_BYTE == buffer[i]) {
+ first += i;
+ trailer_len -= i;
+ goto found;
+ }
+ }
+ }
+ return WTAP_OPEN_NOT_MINE;
+ }
+
+ /* check if a trailer is appended to the packet */
+ for (i=0; i<TRAILER_LEN_MAX; i++) {
+ if (buffer[i] == MP2T_SYNC_BYTE) {
+ trailer_len = i;
+ if (-1 == file_seek(wth->fh, first, SEEK_SET, err)) {
+ return WTAP_OPEN_ERROR;
+ }
+ sync_steps = 0;
+ break;
+ }
+ }
+ /* no sync byte found in the vicinity, this is no mpeg2 ts file */
+ if (i==TRAILER_LEN_MAX)
+ return WTAP_OPEN_NOT_MINE;
+ }
} while (sync_steps < SYNC_STEPS);
if (-1 == file_seek(wth->fh, first, SEEK_SET, err)) {
@@ -374,6 +411,12 @@ found:
return status;
}
+ /* If the packet didn't start on a sync byte, the "trailer" might
+ * be a header. At least BDAV M2TS does this with a four byte header. */
+ header_len = MIN(first, trailer_len);
+ first -= header_len;
+ trailer_len -= header_len;
+
if (-1 == file_seek(wth->fh, first, SEEK_SET, err)) {
return WTAP_OPEN_ERROR;
}
@@ -390,11 +433,69 @@ found:
wth->priv = mp2t;
mp2t->start_offset = first;
mp2t->trailer_len = trailer_len;
+ mp2t->header_len = header_len;
mp2t->bitrate = bitrate;
return WTAP_OPEN_MINE;
}
+static int mp2t_dump_can_write_encap(int encap)
+{
+ /* Per-packet encapsulations aren't supported. */
+ if (encap == WTAP_ENCAP_PER_PACKET) {
+ return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
+ }
+
+ /* This is the only encapsulation type we write. */
+ if (encap != WTAP_ENCAP_MPEG_2_TS) {
+ return WTAP_ERR_UNWRITABLE_ENCAP;
+ }
+
+ return 0;
+}
+
+/* Write a record for a packet to a dump file.
+ Returns true on success, false on failure. */
+static bool mp2t_dump(wtap_dumper *wdh, const wtap_rec *rec,
+ const uint8_t *pd, int *err, char **err_info _U_)
+{
+ /* We can only write packet records. */
+ if (rec->rec_type != REC_TYPE_PACKET) {
+ *err = WTAP_ERR_UNWRITABLE_REC_TYPE;
+ return false;
+ }
+
+ /*
+ * Make sure this packet doesn't have a link-layer type that
+ * differs from the one for the file.
+ */
+ if (wdh->file_encap != rec->rec_header.packet_header.pkt_encap) {
+ *err = WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
+ return false;
+ }
+
+ /* A MPEG-2 Transport Stream is just the packet bytes, with no header.
+ * The sync byte is supposed to identify where packets start.
+ * Note this drops existing headers and trailers currently, since we
+ * don't include them in the record.
+ */
+ if (!wtap_dump_file_write(wdh, pd, rec->rec_header.packet_header.caplen, err)) {
+ return false;
+ }
+
+ return true;
+}
+
+/* Returns true on success, false on failure; sets "*err" to an error code on
+ failure */
+static bool mp2t_dump_open(wtap_dumper *wdh, int *err _U_, char **err_info _U_)
+{
+ /* There is no header, so we just always return true. */
+ wdh->subtype_write = mp2t_dump;
+
+ return true;
+}
+
static const struct supported_block_type mp2t_blocks_supported[] = {
/*
* We support packet blocks, with no comments or other options.
@@ -403,9 +504,9 @@ static const struct supported_block_type mp2t_blocks_supported[] = {
};
static const struct file_type_subtype_info mp2t_info = {
- "MPEG2 transport stream", "mp2t", "mp2t", "ts;mpg",
- FALSE, BLOCKS_SUPPORTED(mp2t_blocks_supported),
- NULL, NULL, NULL
+ "MPEG2 transport stream", "mp2t", "mp2t", "ts;m2ts;mpg",
+ false, BLOCKS_SUPPORTED(mp2t_blocks_supported),
+ mp2t_dump_can_write_encap, mp2t_dump_open, NULL
};
void register_mp2t(void)