Huge thanks to our Platinum Members Endace and LiveAction,
and our Silver Member Veeam, for supporting the Wireshark Foundation and project.

Wireshark-dev: [Wireshark-dev] [PATCH 2/2] asn1: New MPEG dissector

From: "Shaun Jackman" <sjackman@xxxxxxxxx>
Date: Fri, 25 Aug 2006 17:11:24 -0600
This patch posts only the asn1 portion of the previous MPEG patch. It
omits the plugins/mpeg/* portion. It also adds a GPL license to the
two new files.

Cheers,
Shaun

Signed-off-by: Shaun Jackman <sjackman@xxxxxxxxx>

2006-08-25  Shaun Jackman  <sjackman@xxxxxxxxx>

	* asn1/mpeg/Makefile: New file.
	* asn1/mpeg/mpeg.asn: Ditto.
	* asn1/mpeg/packet-mpeg-template.c: Ditto.
	* epan/dissectors/packet-mpeg.c: Regenerate.
	* epan/dissectors/Makefile.in: Regenerate.

diff --unidirectional-new-file -urXX
wireshark-0.99.2.orig/asn1/mpeg/Makefile
wireshark-0.99.2/asn1/mpeg/Makefile
--- wireshark-0.99.2.orig/asn1/mpeg/Makefile	1969-12-31 17:00:00.000000000 -0700
+++ wireshark-0.99.2/asn1/mpeg/Makefile	2006-08-15 15:58:43.000000000 -0600
@@ -0,0 +1,14 @@
+DISSECTOR_FILES=packet-mpeg.c
+
+all: generate_dissector
+
+generate_dissector: $(DISSECTOR_FILES)
+
+$(DISSECTOR_FILES): ../../tools/asn2wrs.py mpeg.asn packet-mpeg-template.c
+	python ../../tools/asn2wrs.py -e -p mpeg -s packet-mpeg-template mpeg.asn
+
+clean:
+	rm -f parsetab.py parsetab.pyc $(DISSECTOR_FILES)
+
+copy_files: generate_dissector
+	cp $(DISSECTOR_FILES) ../../epan/dissectors
diff --unidirectional-new-file -urXX
wireshark-0.99.2.orig/asn1/mpeg/mpeg.asn
wireshark-0.99.2/asn1/mpeg/mpeg.asn
--- wireshark-0.99.2.orig/asn1/mpeg/mpeg.asn	1969-12-31 17:00:00.000000000 -0700
+++ wireshark-0.99.2/asn1/mpeg/mpeg.asn	2006-08-25 16:53:17.000000000 -0600
@@ -0,0 +1,42 @@
+-- ASN description of MPEG
+-- Written by Shaun Jackman <sjackman@xxxxxxxxx>
+-- Copyright 2006 Shaun Jackman
+--
+-- This program is free software; you can redistribute it and/or
+-- modify it under the terms of the GNU General Public License.
+
+MPEG DEFINITIONS ::= BEGIN
+
+Audio ::= SEQUENCE {
+	sync           BIT STRING (SIZE (11)),
+	version        ENUMERATED
+		{ mpeg-2-5(0), reserved(1), mpeg-2(2), mpeg-1(3) },
+	layer          ENUMERATED
+		{ reserved(0), layer-3(1), layer-2(2), layer-1(3) },
+	protection     ENUMERATED { crc(0), none(1) },
+	bitrate        INTEGER (0..15),
+	frequency      INTEGER (0..3),
+	padding        BOOLEAN,
+	private        BOOLEAN,
+	channel-mode   ENUMERATED
+		{ stereo(0), joint-stereo(1), dual-channel(2), single-channel(3) },
+	mode-extension INTEGER (0..3),
+	copyright      BOOLEAN,
+	original       BOOLEAN,
+	emphasis       ENUMERATED
+		{ none(0), em-50-15-ms(1), reserved(2), ccit-j-17(3) }
+}
+
+ID3v1 ::= SEQUENCE {
+	tag     OCTET STRING (SIZE (3)),
+	title   OCTET STRING (SIZE (30)),
+	artist  OCTET STRING (SIZE (30)),
+	album   OCTET STRING (SIZE (30)),
+	year    OCTET STRING (SIZE (4)),
+	comment OCTET STRING (SIZE (28)),
+	zero    INTEGER (0..255),
+	track   INTEGER (0..255),
+	genre   INTEGER (0..255)
+}
+
+END
diff --unidirectional-new-file -urXX
wireshark-0.99.2.orig/asn1/mpeg/packet-mpeg-template.c
wireshark-0.99.2/asn1/mpeg/packet-mpeg-template.c
--- wireshark-0.99.2.orig/asn1/mpeg/packet-mpeg-template.c	1969-12-31
17:00:00.000000000 -0700
+++ wireshark-0.99.2/asn1/mpeg/packet-mpeg-template.c	2006-08-25
16:51:34.000000000 -0600
@@ -0,0 +1,238 @@
+/* MPEG packet decoder.
+ * Written by Shaun Jackman <sjackman@xxxxxxxxx>.
+ * Copyright 2006 Shaun Jackman
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include <epan/packet.h>
+#include <epan/prefs.h>
+
+#include "packet-per.h"
+
+#include "packet-mpeg-hf.c"
+#include "packet-mpeg-ett.c"
+#include "packet-mpeg-fn.c"
+
+static int hf_mpeg_audio = -1;
+static int hf_mpeg_data = -1;
+static int hf_mpeg_padbytes = -1;
+static int hf_id3v1 = -1;
+static int hf_id3v2 = -1;
+
+struct header {
+	unsigned emphasis   :2;
+	unsigned original   :1;
+	unsigned copyright  :1;
+	unsigned mode_ext   :2;
+	unsigned mode       :2;
+	unsigned private    :1;
+	unsigned padding    :1;
+	unsigned frequency  :2;
+	unsigned bitrate    :4;
+	unsigned protection :1;
+	unsigned layer      :2;
+	unsigned version    :2;
+	unsigned sync       :11;
+};
+
+enum { SYNC = 0x7ff };
+static const int versions[4] = { 2, -1, 1, 0 };
+static const int layers[4] = { -1, 2, 1, 0 };
+
+static const unsigned samples_per_frame[3][3] = {
+	{ 384, 1152, 1152 },
+	{ 384, 1152, 576 },
+	{ 384, 1152, 576 },
+};
+
+static const unsigned bitrates[3][3][16] = { /* kb/s */
+  {
+	{ 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448 },
+	{ 0, 32, 48, 56,  64,  80,  96, 112, 128, 160, 192, 224, 256, 320, 384 },
+	{ 0, 32, 40, 48,  56,  64,  80,  96, 112, 128, 160, 192, 224, 256, 320 },
+  },
+  {
+	{ 0, 32, 48, 56,  64,  80,  96, 112, 128, 144, 160, 176, 192, 224, 256 },
+	{ 0,  8, 16, 24,  32,  40,  48,  56,  64,  80,  96, 112, 128, 144, 160 },
+	{ 0,  8, 16, 24,  32,  40,  48,  56,  64,  80,  96, 112, 128, 144, 160 },
+  },
+  {
+	{ 0, 32, 48, 56,  64,  80,  96, 112, 128, 144, 160, 176, 192, 224, 256 },
+	{ 0,  8, 16, 24,  32,  40,  48,  56,  64,  80,  96, 112, 128, 144, 160 },
+	{ 0,  8, 16, 24,  32,  40,  48,  56,  64,  80,  96, 112, 128, 144, 160 },
+  },
+};
+
+static const unsigned frequencies[3][4] = {
+	{ 44100, 48000, 32000 },
+	{ 22050, 24000, 16000 },
+	{ 11025, 12000, 8000 },
+};
+static const unsigned padding[3] = { 4, 1, 1 };
+
+static size_t
+read_header(tvbuff_t *tvb, packet_info *pinfo, struct header *header)
+{
+	size_t data_size = 0;
+	uint32_t h = tvb_get_ntohl(tvb, 0);
+	memcpy(header, &h, sizeof *header);
+	if (header->sync == SYNC) {
+		int version = versions[header->version];
+		int layer = layers[header->layer];
+		if (version >= 0 && layer >= 0) {
+			unsigned bitrate = bitrates[version][layer][header->bitrate] * 1000;
+			unsigned frequency = frequencies[version][header->frequency];
+			if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
+				static const char *version_names[] = { "1", "2", "2.5" };
+				col_add_fstr(pinfo->cinfo, COL_PROTOCOL,
+						"MPEG-%s", version_names[version]);
+			}
+			if (check_col(pinfo->cinfo, COL_INFO))
+				col_add_fstr(pinfo->cinfo, COL_INFO,
+						"Audio Layer %d", layer+1);
+			if (bitrate > 0 && frequency > 0) {
+				unsigned samples = samples_per_frame[version][layer];
+				data_size = bitrate * samples / frequency / 8 - sizeof header;
+				if (check_col(pinfo->cinfo, COL_DEF_SRC)) {
+					SET_ADDRESS(&pinfo->src, AT_NONE, 0, NULL);
+					col_add_fstr(pinfo->cinfo, COL_DEF_SRC,
+							"%d kb/s", bitrate / 1000);
+				}
+				if (check_col(pinfo->cinfo, COL_DEF_DST)) {
+					SET_ADDRESS(&pinfo->dst, AT_NONE, 0, NULL);
+					col_add_fstr(pinfo->cinfo, COL_DEF_DST,
+							"%g kHz", frequency / (float)1000);
+				}
+			}
+		} else {
+			if (check_col(pinfo->cinfo, COL_PROTOCOL))
+				col_add_str(pinfo->cinfo, COL_PROTOCOL, "MPEG");
+		}
+	}
+	return data_size;
+}
+
+static void
+dissect_mpa(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+	struct header header;
+	size_t data_size = read_header(tvb, pinfo, &header);
+	if (tree == NULL)
+		return;
+
+	if (header.sync != SYNC)
+		return;
+	asn1_ctx_t asn1_ctx;
+	asn1_ctx_init(&asn1_ctx, ASN1_ENC_PER, TRUE, pinfo);
+	int offset = 0;
+	offset = dissect_mpeg_Audio(tvb, offset, &asn1_ctx,
+			tree, hf_mpeg_audio);
+	if (data_size > 0) {
+		proto_tree_add_item(tree, hf_mpeg_data, tvb,
+				offset / 8, data_size, FALSE);
+		offset += data_size * 8;
+		if (header.padding)
+			proto_tree_add_item(tree, hf_mpeg_padbytes, tvb,
+					offset / 8, 1, FALSE);
+	}
+}
+
+static void
+dissect_id3v1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+	if (check_col(pinfo->cinfo, COL_PROTOCOL))
+		col_set_str(pinfo->cinfo, COL_PROTOCOL, "ID3v1");
+	if (tree == NULL)
+		return;
+	asn1_ctx_t asn1_ctx;
+	asn1_ctx_init(&asn1_ctx, ASN1_ENC_PER, TRUE, pinfo);
+	dissect_mpeg_ID3v1(tvb, 0, &asn1_ctx,
+			tree, hf_id3v1);
+}
+
+static void
+dissect_id3v2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+	if (check_col(pinfo->cinfo, COL_PROTOCOL))
+		col_set_str(pinfo->cinfo, COL_PROTOCOL, "ID3v2");
+	proto_tree_add_item(tree, hf_id3v2, tvb,
+			0, -1, FALSE);
+}
+
+static void
+dissect_mpeg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+	if (check_col(pinfo->cinfo, COL_PROTOCOL))
+		col_clear(pinfo->cinfo, COL_PROTOCOL);
+	if (check_col(pinfo->cinfo, COL_INFO))
+		col_clear(pinfo->cinfo, COL_INFO);
+
+	int magic = tvb_get_ntoh24(tvb, 0);
+	switch (magic) {
+		case 0x544147:
+			dissect_id3v1(tvb, pinfo, tree);
+			break;
+		case 0x494433:
+			dissect_id3v2(tvb, pinfo, tree);
+			break;
+		default:
+			dissect_mpa(tvb, pinfo, tree);
+	}
+}
+
+static int proto_mpeg = -1;
+
+void
+proto_register_mpeg(void)
+{
+	static hf_register_info hf[] = {
+#include "packet-mpeg-hfarr.c"
+		{ &hf_mpeg_audio,
+			{ "MPEG Audio", "mpeg.audio",
+				FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL }},
+		{ &hf_mpeg_data,
+			{ "Data", "mpeg.data",
+				FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
+		{ &hf_mpeg_padbytes,
+			{ "Padding", "mpeg.padbytes",
+				FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
+
+		{ &hf_id3v1,
+			{ "ID3v1", "id3v1",
+				FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL }},
+		{ &hf_id3v2,
+			{ "ID3v2", "id3v2",
+				FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL }},
+	};
+
+	static gint *ett[] = {
+#include "packet-mpeg-ettarr.c"
+	};
+
+	if (proto_mpeg != -1)
+		return;
+
+	proto_mpeg = proto_register_protocol(
+			"Moving Picture Experts Group", "MPEG", "mpeg");
+	proto_register_field_array(proto_mpeg, hf, array_length(hf));
+	proto_register_subtree_array(ett, array_length(ett));
+}
+
+void
+proto_reg_handoff_mpeg(void)
+{
+	dissector_handle_t mpeg_handle = create_dissector_handle(
+			dissect_mpeg, proto_mpeg);
+	dissector_add("wtap_encap", WTAP_ENCAP_MPEG, mpeg_handle);
+}
[PATCH 2/2] asn1: New MPEG dissector
Signed-off-by: Shaun Jackman <sjackman@xxxxxxxxx>

2006-08-25  Shaun Jackman  <sjackman@xxxxxxxxx>

	* asn1/mpeg/Makefile: New file.
	* asn1/mpeg/mpeg.asn: Ditto.
	* asn1/mpeg/packet-mpeg-template.c: Ditto.
	* epan/dissectors/packet-mpeg.c: Regenerate.

diff --unidirectional-new-file -urXX wireshark-0.99.2.orig/asn1/mpeg/Makefile wireshark-0.99.2/asn1/mpeg/Makefile
--- wireshark-0.99.2.orig/asn1/mpeg/Makefile	1969-12-31 17:00:00.000000000 -0700
+++ wireshark-0.99.2/asn1/mpeg/Makefile	2006-08-15 15:58:43.000000000 -0600
@@ -0,0 +1,14 @@
+DISSECTOR_FILES=packet-mpeg.c
+
+all: generate_dissector
+
+generate_dissector: $(DISSECTOR_FILES)
+
+$(DISSECTOR_FILES): ../../tools/asn2wrs.py mpeg.asn packet-mpeg-template.c
+	python ../../tools/asn2wrs.py -e -p mpeg -s packet-mpeg-template mpeg.asn
+
+clean:
+	rm -f parsetab.py parsetab.pyc $(DISSECTOR_FILES)
+
+copy_files: generate_dissector
+	cp $(DISSECTOR_FILES) ../../epan/dissectors
diff --unidirectional-new-file -urXX wireshark-0.99.2.orig/asn1/mpeg/mpeg.asn wireshark-0.99.2/asn1/mpeg/mpeg.asn
--- wireshark-0.99.2.orig/asn1/mpeg/mpeg.asn	1969-12-31 17:00:00.000000000 -0700
+++ wireshark-0.99.2/asn1/mpeg/mpeg.asn	2006-08-25 16:53:17.000000000 -0600
@@ -0,0 +1,42 @@
+-- ASN description of MPEG
+-- Written by Shaun Jackman <sjackman@xxxxxxxxx>
+-- Copyright 2006 Shaun Jackman
+--
+-- This program is free software; you can redistribute it and/or
+-- modify it under the terms of the GNU General Public License.
+
+MPEG DEFINITIONS ::= BEGIN
+
+Audio ::= SEQUENCE {
+	sync           BIT STRING (SIZE (11)),
+	version        ENUMERATED
+		{ mpeg-2-5(0), reserved(1), mpeg-2(2), mpeg-1(3) },
+	layer          ENUMERATED
+		{ reserved(0), layer-3(1), layer-2(2), layer-1(3) },
+	protection     ENUMERATED { crc(0), none(1) },
+	bitrate        INTEGER (0..15),
+	frequency      INTEGER (0..3),
+	padding        BOOLEAN,
+	private        BOOLEAN,
+	channel-mode   ENUMERATED
+		{ stereo(0), joint-stereo(1), dual-channel(2), single-channel(3) },
+	mode-extension INTEGER (0..3),
+	copyright      BOOLEAN,
+	original       BOOLEAN,
+	emphasis       ENUMERATED
+		{ none(0), em-50-15-ms(1), reserved(2), ccit-j-17(3) }
+}
+
+ID3v1 ::= SEQUENCE {
+	tag     OCTET STRING (SIZE (3)),
+	title   OCTET STRING (SIZE (30)),
+	artist  OCTET STRING (SIZE (30)),
+	album   OCTET STRING (SIZE (30)),
+	year    OCTET STRING (SIZE (4)),
+	comment OCTET STRING (SIZE (28)),
+	zero    INTEGER (0..255),
+	track   INTEGER (0..255),
+	genre   INTEGER (0..255)
+}
+
+END
diff --unidirectional-new-file -urXX wireshark-0.99.2.orig/asn1/mpeg/packet-mpeg-template.c wireshark-0.99.2/asn1/mpeg/packet-mpeg-template.c
--- wireshark-0.99.2.orig/asn1/mpeg/packet-mpeg-template.c	1969-12-31 17:00:00.000000000 -0700
+++ wireshark-0.99.2/asn1/mpeg/packet-mpeg-template.c	2006-08-25 16:51:34.000000000 -0600
@@ -0,0 +1,238 @@
+/* MPEG packet decoder.
+ * Written by Shaun Jackman <sjackman@xxxxxxxxx>.
+ * Copyright 2006 Shaun Jackman
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include <epan/packet.h>
+#include <epan/prefs.h>
+
+#include "packet-per.h"
+
+#include "packet-mpeg-hf.c"
+#include "packet-mpeg-ett.c"
+#include "packet-mpeg-fn.c"
+
+static int hf_mpeg_audio = -1;
+static int hf_mpeg_data = -1;
+static int hf_mpeg_padbytes = -1;
+static int hf_id3v1 = -1;
+static int hf_id3v2 = -1;
+
+struct header {
+	unsigned emphasis   :2;
+	unsigned original   :1;
+	unsigned copyright  :1;
+	unsigned mode_ext   :2;
+	unsigned mode       :2;
+	unsigned private    :1;
+	unsigned padding    :1;
+	unsigned frequency  :2;
+	unsigned bitrate    :4;
+	unsigned protection :1;
+	unsigned layer      :2;
+	unsigned version    :2;
+	unsigned sync       :11;
+};
+
+enum { SYNC = 0x7ff };
+static const int versions[4] = { 2, -1, 1, 0 };
+static const int layers[4] = { -1, 2, 1, 0 };
+
+static const unsigned samples_per_frame[3][3] = {
+	{ 384, 1152, 1152 },
+	{ 384, 1152, 576 },
+	{ 384, 1152, 576 },
+};
+
+static const unsigned bitrates[3][3][16] = { /* kb/s */
+  {
+	{ 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448 },
+	{ 0, 32, 48, 56,  64,  80,  96, 112, 128, 160, 192, 224, 256, 320, 384 },
+	{ 0, 32, 40, 48,  56,  64,  80,  96, 112, 128, 160, 192, 224, 256, 320 },
+  },
+  {
+	{ 0, 32, 48, 56,  64,  80,  96, 112, 128, 144, 160, 176, 192, 224, 256 },
+	{ 0,  8, 16, 24,  32,  40,  48,  56,  64,  80,  96, 112, 128, 144, 160 },
+	{ 0,  8, 16, 24,  32,  40,  48,  56,  64,  80,  96, 112, 128, 144, 160 },
+  },
+  {
+	{ 0, 32, 48, 56,  64,  80,  96, 112, 128, 144, 160, 176, 192, 224, 256 },
+	{ 0,  8, 16, 24,  32,  40,  48,  56,  64,  80,  96, 112, 128, 144, 160 },
+	{ 0,  8, 16, 24,  32,  40,  48,  56,  64,  80,  96, 112, 128, 144, 160 },
+  },
+};
+
+static const unsigned frequencies[3][4] = {
+	{ 44100, 48000, 32000 },
+	{ 22050, 24000, 16000 },
+	{ 11025, 12000, 8000 },
+};
+static const unsigned padding[3] = { 4, 1, 1 };
+
+static size_t
+read_header(tvbuff_t *tvb, packet_info *pinfo, struct header *header)
+{
+	size_t data_size = 0;
+	uint32_t h = tvb_get_ntohl(tvb, 0);
+	memcpy(header, &h, sizeof *header);
+	if (header->sync == SYNC) {
+		int version = versions[header->version];
+		int layer = layers[header->layer];
+		if (version >= 0 && layer >= 0) {
+			unsigned bitrate = bitrates[version][layer][header->bitrate] * 1000;
+			unsigned frequency = frequencies[version][header->frequency];
+			if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
+				static const char *version_names[] = { "1", "2", "2.5" };
+				col_add_fstr(pinfo->cinfo, COL_PROTOCOL,
+						"MPEG-%s", version_names[version]);
+			}
+			if (check_col(pinfo->cinfo, COL_INFO))
+				col_add_fstr(pinfo->cinfo, COL_INFO,
+						"Audio Layer %d", layer+1);
+			if (bitrate > 0 && frequency > 0) {
+				unsigned samples = samples_per_frame[version][layer];
+				data_size = bitrate * samples / frequency / 8 - sizeof header;
+				if (check_col(pinfo->cinfo, COL_DEF_SRC)) {
+					SET_ADDRESS(&pinfo->src, AT_NONE, 0, NULL);
+					col_add_fstr(pinfo->cinfo, COL_DEF_SRC,
+							"%d kb/s", bitrate / 1000);
+				}
+				if (check_col(pinfo->cinfo, COL_DEF_DST)) {
+					SET_ADDRESS(&pinfo->dst, AT_NONE, 0, NULL);
+					col_add_fstr(pinfo->cinfo, COL_DEF_DST,
+							"%g kHz", frequency / (float)1000);
+				}
+			}
+		} else {
+			if (check_col(pinfo->cinfo, COL_PROTOCOL))
+				col_add_str(pinfo->cinfo, COL_PROTOCOL, "MPEG");
+		}
+	}
+	return data_size;
+}
+
+static void
+dissect_mpa(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+	struct header header;
+	size_t data_size = read_header(tvb, pinfo, &header);
+	if (tree == NULL)
+		return;
+
+	if (header.sync != SYNC)
+		return;
+	asn1_ctx_t asn1_ctx;
+	asn1_ctx_init(&asn1_ctx, ASN1_ENC_PER, TRUE, pinfo);
+	int offset = 0;
+	offset = dissect_mpeg_Audio(tvb, offset, &asn1_ctx,
+			tree, hf_mpeg_audio);
+	if (data_size > 0) {
+		proto_tree_add_item(tree, hf_mpeg_data, tvb,
+				offset / 8, data_size, FALSE);
+		offset += data_size * 8;
+		if (header.padding)
+			proto_tree_add_item(tree, hf_mpeg_padbytes, tvb,
+					offset / 8, 1, FALSE);
+	}
+}
+
+static void
+dissect_id3v1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+	if (check_col(pinfo->cinfo, COL_PROTOCOL))
+		col_set_str(pinfo->cinfo, COL_PROTOCOL, "ID3v1");
+	if (tree == NULL)
+		return;
+	asn1_ctx_t asn1_ctx;
+	asn1_ctx_init(&asn1_ctx, ASN1_ENC_PER, TRUE, pinfo);
+	dissect_mpeg_ID3v1(tvb, 0, &asn1_ctx,
+			tree, hf_id3v1);
+}
+
+static void
+dissect_id3v2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+	if (check_col(pinfo->cinfo, COL_PROTOCOL))
+		col_set_str(pinfo->cinfo, COL_PROTOCOL, "ID3v2");
+	proto_tree_add_item(tree, hf_id3v2, tvb,
+			0, -1, FALSE);
+}
+
+static void
+dissect_mpeg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+	if (check_col(pinfo->cinfo, COL_PROTOCOL))
+		col_clear(pinfo->cinfo, COL_PROTOCOL);
+	if (check_col(pinfo->cinfo, COL_INFO))
+		col_clear(pinfo->cinfo, COL_INFO);
+
+	int magic = tvb_get_ntoh24(tvb, 0);
+	switch (magic) {
+		case 0x544147:
+			dissect_id3v1(tvb, pinfo, tree);
+			break;
+		case 0x494433:
+			dissect_id3v2(tvb, pinfo, tree);
+			break;
+		default:
+			dissect_mpa(tvb, pinfo, tree);
+	}
+}
+
+static int proto_mpeg = -1;
+
+void
+proto_register_mpeg(void)
+{
+	static hf_register_info hf[] = {
+#include "packet-mpeg-hfarr.c"
+		{ &hf_mpeg_audio,
+			{ "MPEG Audio", "mpeg.audio",
+				FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL }},
+		{ &hf_mpeg_data,
+			{ "Data", "mpeg.data",
+				FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
+		{ &hf_mpeg_padbytes,
+			{ "Padding", "mpeg.padbytes",
+				FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
+
+		{ &hf_id3v1,
+			{ "ID3v1", "id3v1",
+				FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL }},
+		{ &hf_id3v2,
+			{ "ID3v2", "id3v2",
+				FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL }},
+	};
+
+	static gint *ett[] = {
+#include "packet-mpeg-ettarr.c"
+	};
+
+	if (proto_mpeg != -1)
+		return;
+
+	proto_mpeg = proto_register_protocol(
+			"Moving Picture Experts Group", "MPEG", "mpeg");
+	proto_register_field_array(proto_mpeg, hf, array_length(hf));
+	proto_register_subtree_array(ett, array_length(ett));
+}
+
+void
+proto_reg_handoff_mpeg(void)
+{
+	dissector_handle_t mpeg_handle = create_dissector_handle(
+			dissect_mpeg, proto_mpeg);
+	dissector_add("wtap_encap", WTAP_ENCAP_MPEG, mpeg_handle);
+}