Wireshark-dev: [Wireshark-dev] [PATCH 2/2] asn1: New MPEG dissector
From: "Shaun Jackman" <sjackman@xxxxxxxxx>
Date: Thu, 15 Mar 2007 18:13:17 -0600
On 8/25/06, Shaun Jackman <sjackman@xxxxxxxxx> wrote:
> 2, dont read straight into a bitfield struct.
> c does not define the packing order or padding of fields in a bitfield
> and this would be nonportable.
> please change to read into an array of char and then add code to
> manually unmarshall it into the fields of the bitfield

Not yet done.

Fixed now! The updated patch is attached. The decoder now dissects
both MPEG audio and MPEG video! So, for example, it's possible to see
the interleaving of MPEG video I, P, and B frames with MPEG audio.

Cheers,
Shaun

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

	* asn1/Makefile.am (EXTRA_DIST): Add mpeg.
	* asn1/mpeg/Makefile: New file.
	* asn1/mpeg/mpeg-audio.asn: Ditto.
	* asn1/mpeg/mpeg-audio.cnf: Ditto.
	* asn1/mpeg/mpeg-pes.asn: Ditto.
	* asn1/mpeg/mpeg-pes.cnf: Ditto.
	* asn1/mpeg/packet-mpeg-audio-template.c: Ditto.
	* asn1/mpeg/packet-mpeg-pes-template.c: Ditto.
	* epan/dissectors/Makefile.common (DISSECTOR_SRC):
	Add packet-mpeg-audio.c and packet-mpeg-pes.c.
2006-08-25  Shaun Jackman  <sjackman@xxxxxxxxx>

	* asn1/Makefile.am (EXTRA_DIST): Add mpeg.
	* asn1/mpeg/Makefile: New file.
	* asn1/mpeg/mpeg-audio.asn: Ditto.
	* asn1/mpeg/mpeg-audio.cnf: Ditto.
	* asn1/mpeg/mpeg-pes.asn: Ditto.
	* asn1/mpeg/mpeg-pes.cnf: Ditto.
	* asn1/mpeg/packet-mpeg-audio-template.c: Ditto.
	* asn1/mpeg/packet-mpeg-pes-template.c: Ditto.
	* epan/dissectors/Makefile.common (DISSECTOR_SRC):
	Add packet-mpeg-audio.c and packet-mpeg-pes.c.

Index: asn1/mpeg/mpeg-pes.cnf
===================================================================
--- asn1/mpeg/mpeg-pes.cnf	(revision 0)
+++ asn1/mpeg/mpeg-pes.cnf	(revision 0)
@@ -0,0 +1,5 @@
+#.TYPE_ATTR
+PES/stream TYPE=FT_UINT8 DISPLAY=BASE_HEX
+Pack/program-mux-rate TYPE=FT_UINT32 DISPLAY=BASE_DEC
+Stream/length TYPE=FT_UINT16 DISPLAY=BASE_DEC
+#.END
Index: asn1/mpeg/packet-mpeg-audio-template.c
===================================================================
--- asn1/mpeg/packet-mpeg-audio-template.c	(revision 0)
+++ asn1/mpeg/packet-mpeg-audio-template.c	(revision 0)
@@ -0,0 +1,186 @@
+/* MPEG audio packet decoder.
+ * Written by Shaun Jackman <sjackman@xxxxxxxxx>.
+ * Copyright 2007 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 <wiretap/mpeg-audio.h>
+
+#include "packet-per.h"
+
+#include "packet-mpeg-audio-hf.c"
+#include "packet-mpeg-audio-ett.c"
+#include "packet-mpeg-audio-fn.c"
+
+static int hf_mpeg_audio = -1;
+static int hf_mpeg_audio_data = -1;
+static int hf_mpeg_audio_padbytes = -1;
+static int hf_id3v1 = -1;
+static int hf_id3v2 = -1;
+
+static size_t
+read_header(tvbuff_t *tvb, packet_info *pinfo, struct mpa *mpa)
+{
+	size_t data_size = 0;
+	uint32_t h = tvb_get_ntohl(tvb, 0);
+	MPA_MARSHAL(mpa, h);
+	if (MPA_SYNC_VALID(mpa)) {
+		if (MPA_VERSION_VALID(mpa) && MPA_LAYER_VALID(mpa)) {
+			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[MPA_VERSION(mpa)]);
+			}
+			if (check_col(pinfo->cinfo, COL_INFO))
+				col_add_fstr(pinfo->cinfo, COL_INFO,
+						"Audio Layer %d", MPA_LAYER(mpa) + 1);
+			if (MPA_BITRATE_VALID(mpa) && MPA_FREQUENCY_VALID(mpa)) {
+				data_size = MPA_DATA_BYTES(mpa) - sizeof mpa;
+				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", MPA_BITRATE(mpa) / 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", MPA_FREQUENCY(mpa) / (float)1000);
+				}
+			}
+		} else {
+			if (check_col(pinfo->cinfo, COL_PROTOCOL))
+				col_add_str(pinfo->cinfo, COL_PROTOCOL, "MPEG");
+		}
+	}
+	return data_size;
+}
+
+static gboolean
+dissect_mpeg_audio_frame(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+	struct mpa mpa;
+	size_t data_size = read_header(tvb, pinfo, &mpa);
+	if (!MPA_SYNC_VALID(&mpa))
+		return FALSE;
+
+	if (tree == NULL)
+		return TRUE;
+	asn1_ctx_t asn1_ctx;
+	asn1_ctx_init(&asn1_ctx, ASN1_ENC_PER, TRUE, pinfo);
+	int offset = 0;
+	offset = dissect_mpeg_audio_Audio(tvb, offset, &asn1_ctx,
+			tree, hf_mpeg_audio);
+	if (data_size > 0) {
+		proto_tree_add_item(tree, hf_mpeg_audio_data, tvb,
+				offset / 8, data_size, FALSE);
+		offset += data_size * 8;
+		unsigned padding = MPA_PADDING(&mpa);
+		if (padding > 0) {
+			proto_tree_add_item(tree, hf_mpeg_audio_padbytes, tvb,
+					offset / 8, padding, FALSE);
+			offset += padding * 8;
+		}
+	}
+	return TRUE;
+}
+
+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_audio_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 gboolean
+dissect_mpeg_audio(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: /* TAG */
+			dissect_id3v1(tvb, pinfo, tree);
+			return TRUE;
+		case 0x494433: /* ID3 */
+			dissect_id3v2(tvb, pinfo, tree);
+			return TRUE;
+		default:
+			return dissect_mpeg_audio_frame(tvb, pinfo, tree);
+	}
+}
+
+static int proto_mpeg_audio = -1;
+
+void
+proto_register_mpeg_audio(void)
+{
+	static hf_register_info hf[] = {
+#include "packet-mpeg-audio-hfarr.c"
+		{ &hf_mpeg_audio,
+			{ "MPEG Audio", "mpeg.audio",
+				FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL }},
+		{ &hf_mpeg_audio_data,
+			{ "Data", "mpeg.audio.data",
+				FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
+		{ &hf_mpeg_audio_padbytes,
+			{ "Padding", "mpeg.audio.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-audio-ettarr.c"
+	};
+
+	if (proto_mpeg_audio != -1)
+		return;
+
+	proto_mpeg_audio = proto_register_protocol(
+			"Moving Picture Experts Group Audio", "MPEG Audio", "mpeg.audio");
+	proto_register_field_array(proto_mpeg_audio, hf, array_length(hf));
+	proto_register_subtree_array(ett, array_length(ett));
+}
+
+void
+proto_reg_handoff_mpeg_audio(void)
+{
+	heur_dissector_add("mpeg", dissect_mpeg_audio, proto_mpeg_audio);
+}
Index: asn1/mpeg/mpeg-audio.asn
===================================================================
--- asn1/mpeg/mpeg-audio.asn	(revision 0)
+++ asn1/mpeg/mpeg-audio.asn	(revision 0)
@@ -0,0 +1,75 @@
+-- ASN description of MPEG Audio
+-- Written by Shaun Jackman <sjackman@xxxxxxxxx>
+-- Copyright 2007 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)),
+	must-be-zero INTEGER (0..255),
+	track INTEGER (0..255),
+	genre INTEGER {
+		blues(0), classic-rock(1), country(2), dance(3), disco(4),
+		funk(5), grunge(6), hip-hop(7), jazz(8), metal(9),
+		new-age(10), oldies(11), other(12), pop(13), r-and-b(14),
+		rap(15), reggae(16), rock(17), techno(18), industrial(19),
+		alternative(20), ska(21), death-metal(22), pranks(23),
+		soundtrack(24), euro-techno(25), ambient(26), trip-hop(27),
+		vocal(28), jazz-and-funk(29), fusion(30), trance(31),
+		classical(32), instrumental(33), acid(34), house(35),
+		game(36), sound-clip(37), gospel(38), noise(39),
+		alternative-rock(40), bass(41), soul(42), punk(43), space(44),
+		meditative(45), instrumental-pop(46), instrumental-rock(47),
+		ethnic(48), gothic(49), darkwave(50), techno-industrial(51),
+		electronic(52), pop-folk(53), eurodance(54), dream(55),
+		southern-rock(56), comedy(57), cult(58), gangsta(59),
+		top-40(60), christian-rap(61), pop-funk(62), jungle(63),
+		native-american(64), cabaret(65), new-wave(66),
+		psychadelic(67), rave(68), showtunes(69), trailer(70),
+		lo-fi(71), tribal(72), acid-punk(73), acid-jazz(74),
+		polka(75), retro(76), musical(77), rock-and-roll(78),
+		hard-rock(79), folk(80), folk-rock(81), national-folk(82),
+		swing(83), fast-fusion(84), bebob(85), latin(86), revival(87),
+		celtic(88), bluegrass(89), avantgarde(90), gothic-rock(91),
+		progressive-rock(92), psychedelic-rock(93),
+		symphonic-rock(94), slow-rock(95), big-band(96), chorus(97),
+		easy-listening(98), acoustic(99), humour(100), speech(101),
+		chanson(102), opera(103), chamber-music(104), sonata(105),
+		symphony(106), booty-bass(107), primus(108), porn-groove(109),
+		satire(110), slow-jam(111), club(112), tango(113), samba(114),
+		folklore(115), ballad(116), power-ballad(117),
+		rhythmic-soul(118), freestyle(119), duet(120), punk-rock(121),
+		drum-solo(122), a-cappella(123), euro-house(124),
+		dance-hall(125)
+	} (0..255)
+}
+
+END
Index: asn1/mpeg/mpeg-audio.cnf
===================================================================
--- asn1/mpeg/mpeg-audio.cnf	(revision 0)
+++ asn1/mpeg/mpeg-audio.cnf	(revision 0)
@@ -0,0 +1,8 @@
+#.TYPE_ATTR
+ID3v1/tag TYPE=FT_STRING
+ID3v1/title TYPE=FT_STRING
+ID3v1/artist TYPE=FT_STRING
+ID3v1/album TYPE=FT_STRING
+ID3v1/year TYPE=FT_STRING
+ID3v1/comment TYPE=FT_STRING
+#.END
Index: asn1/mpeg/packet-mpeg-pes-template.c
===================================================================
--- asn1/mpeg/packet-mpeg-pes-template.c	(revision 0)
+++ asn1/mpeg/packet-mpeg-pes-template.c	(revision 0)
@@ -0,0 +1,262 @@
+/* MPEG Packetized Elementary Stream (PES) packet decoder.
+ * Written by Shaun Jackman <sjackman@xxxxxxxxx>.
+ * Copyright 2007 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-pes-hf.c"
+#include "packet-mpeg-pes-ett.c"
+#include "packet-mpeg-pes-fn.c"
+
+static int proto_mpeg = -1;
+static int proto_mpeg_pes = -1;
+static int hf_mpeg_pes_pack_header = -1;
+static int hf_mpeg_pes_stuffing = -1;
+static int hf_mpeg_pes_extension = -1;
+static int hf_mpeg_pes_header_data = -1;
+static int hf_mpeg_pes_padding = -1;
+
+static int hf_mpeg_pes_data = -1;
+
+static int hf_mpeg_video_sequence_header = -1;
+static int hf_mpeg_video_sequence_extension = -1;
+static int hf_mpeg_video_group_of_pictures = -1;
+static int hf_mpeg_video_picture = -1;
+static int hf_mpeg_video_quantization_matrix = -1;
+static int hf_mpeg_video_data = -1;
+
+enum { PES_PREFIX = 1 };
+enum {
+	STREAM_PICTURE = 0x00,
+	STREAM_SEQUENCE = 0xb3,
+	STREAM_SEQUENCE_EXTENSION = 0xb5,
+	STREAM_GOP = 0xb8,
+	STREAM_END = 0xb9,
+	STREAM_PACK = 0xba,
+	STREAM_SYSTEM = 0xbb,
+	STREAM_PROGRAM = 0xbc,
+	STREAM_PRIVATE1 = 0xbd,
+	STREAM_PADDING = 0xbe,
+	STREAM_PRIVATE2 = 0xbf,
+	STREAM_AUDIO = 0xc0,
+	STREAM_VIDEO = 0xe0,
+};
+
+void
+dissect_mpeg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
+
+static gboolean
+dissect_mpeg_pes(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+	int prefix = tvb_get_ntoh24(tvb, 0);
+	if (prefix != PES_PREFIX)
+		return FALSE;
+	if (check_col(pinfo->cinfo, COL_PROTOCOL))
+		col_set_str(pinfo->cinfo, COL_PROTOCOL, "MPEG PES");
+
+	int stream = tvb_get_guint8(tvb, 3);
+	if (check_col(pinfo->cinfo, COL_INFO)) {
+		const char *s = match_strval(stream, mpeg_pes_T_stream_vals);
+		if (s != NULL)
+			col_set_str(pinfo->cinfo, COL_INFO, s);
+	}
+
+#if 0
+	if (tree == NULL)
+		return TRUE;
+#endif
+	asn1_ctx_t asn1_ctx;
+	asn1_ctx_init(&asn1_ctx, ASN1_ENC_PER, TRUE, pinfo);
+	int offset = 0;
+	offset = dissect_mpeg_pes_PES(tvb, offset, &asn1_ctx,
+			tree, proto_mpeg_pes);
+
+	if (stream == STREAM_PICTURE) {
+		int frame_type = tvb_get_guint8(tvb, 5) >> 3 & 0x07;
+		if (check_col(pinfo->cinfo, COL_INFO)) {
+			const char *s = match_strval(frame_type,
+					mpeg_pes_T_frame_type_vals);
+			if (s != NULL)
+				col_set_str(pinfo->cinfo, COL_INFO, s);
+		}
+
+		offset = dissect_mpeg_pes_Picture(tvb, offset, &asn1_ctx,
+				tree, hf_mpeg_video_picture);
+		proto_tree_add_item(tree, hf_mpeg_video_data, tvb,
+				offset / 8, -1, FALSE);
+	} else if (stream == STREAM_SEQUENCE) {
+		offset = dissect_mpeg_pes_Sequence_header(tvb, offset, &asn1_ctx,
+				tree, hf_mpeg_video_sequence_header);
+
+		proto_tree_add_item(tree, hf_mpeg_video_quantization_matrix, tvb,
+				offset / 8, 64, FALSE);
+		offset += 64 * 8;
+
+		tvbuff_t *es = tvb_new_subset(tvb, offset / 8, -1, -1);
+		dissect_mpeg_pes(es, pinfo, tree);
+	} else if (stream == STREAM_SEQUENCE_EXTENSION) {
+		offset = dissect_mpeg_pes_Sequence_extension(tvb, offset, &asn1_ctx,
+				tree, hf_mpeg_video_sequence_extension);
+
+		tvbuff_t *es = tvb_new_subset(tvb, offset / 8, -1, -1);
+		dissect_mpeg_pes(es, pinfo, tree);
+	} else if (stream == STREAM_GOP) {
+		offset = dissect_mpeg_pes_Group_of_pictures(tvb, offset, &asn1_ctx,
+				tree, hf_mpeg_video_group_of_pictures);
+
+		tvbuff_t *es = tvb_new_subset(tvb, offset / 8, -1, -1);
+		dissect_mpeg_pes(es, pinfo, tree);
+	} else if (stream == STREAM_PACK) {
+		int length;
+		switch (tvb_get_guint8(tvb, 4) >> 6) {
+			case 1:
+				length = tvb_get_guint8(tvb, 13) & 0x07;
+				offset = dissect_mpeg_pes_Pack(tvb, offset, &asn1_ctx,
+						tree, hf_mpeg_pes_pack_header);
+				if (length > 0)
+					proto_tree_add_item(tree, hf_mpeg_pes_stuffing, tvb,
+							offset / 8, length, FALSE);
+				break;
+			default:
+				length = 8;
+				proto_tree_add_item(tree, hf_mpeg_pes_data, tvb,
+						offset / 8, length, FALSE);
+		}
+		offset += length * 8;
+	} else if (stream == STREAM_SYSTEM) {
+		offset = dissect_mpeg_pes_Stream(tvb, offset, &asn1_ctx,
+				tree, hf_mpeg_pes_extension);
+		proto_tree_add_item(tree, hf_mpeg_pes_data, tvb,
+				offset / 8, -1, FALSE);
+	} else if (stream == STREAM_PADDING) {
+		int padding_length = tvb_get_ntohs(tvb, 4);
+		proto_tree_add_item(tree, hf_mpeg_pes_length, tvb,
+				offset / 8, 2, FALSE);
+		offset += 2 * 8;
+
+		proto_tree_add_item(tree, hf_mpeg_pes_padding, tvb,
+				offset / 8, padding_length, FALSE);
+	} else if (stream == STREAM_PRIVATE1
+			|| stream >= STREAM_AUDIO) {
+		int length = tvb_get_ntohs(tvb, 4);
+
+		offset = dissect_mpeg_pes_Stream(tvb, offset, &asn1_ctx,
+				tree, hf_mpeg_pes_extension);
+		length -= 5 * 8;
+
+		int header_length = tvb_get_guint8(tvb, 8);
+		if (header_length > 0) {
+			proto_tree_add_item(tree, hf_mpeg_pes_header_data, tvb,
+					offset / 8, header_length, FALSE);
+			offset += header_length * 8;
+			length -= header_length * 8;
+		}
+
+		tvbuff_t *es = tvb_new_subset(tvb, offset / 8, -1, length / 8);
+		if (tvb_get_ntoh24(es, 0) == PES_PREFIX)
+			dissect_mpeg_pes(es, pinfo, tree);
+		else if (tvb_get_guint8(es, 0) == 0xff)
+			dissect_mpeg(es, pinfo, tree);
+		else
+			proto_tree_add_item(tree, hf_mpeg_pes_data, es,
+					0, -1, FALSE);
+	} else {
+		proto_tree_add_item(tree, hf_mpeg_pes_data, tvb,
+				offset / 8, -1, FALSE);
+	}
+	return TRUE;
+}
+
+static heur_dissector_list_t heur_subdissector_list;
+
+void
+dissect_mpeg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+    dissector_try_heuristic(heur_subdissector_list, tvb, pinfo, tree);
+}
+
+void
+proto_register_mpeg_pes(void)
+{
+	proto_mpeg = proto_register_protocol(
+			"Moving Picture Experts Group", "MPEG", "mpeg");
+	register_heur_dissector_list("mpeg", &heur_subdissector_list);
+
+	static hf_register_info hf[] = {
+#include "packet-mpeg-pes-hfarr.c"
+		{ &hf_mpeg_pes_pack_header,
+			{ "Pack header", "mpeg-pes.pack",
+				FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL }},
+		{ &hf_mpeg_pes_stuffing,
+			{ "PES stuffing bytes", "mpeg-pes.stuffing",
+				FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
+		{ &hf_mpeg_pes_extension,
+			{ "PES extension", "mpeg-pes.extension",
+				FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL }},
+		{ &hf_mpeg_pes_header_data,
+			{ "PES header data", "mpeg-pes.header-data",
+				FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
+		{ &hf_mpeg_pes_padding,
+			{ "PES padding", "mpeg-pes.padding",
+				FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
+		{ &hf_mpeg_pes_data,
+			{ "PES data", "mpeg-pes.data",
+				FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
+		{ &hf_mpeg_video_sequence_header,
+			{ "MPEG sequence header", "mpeg-video.sequence",
+				FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL }},
+		{ &hf_mpeg_video_sequence_extension,
+			{ "MPEG sequence extension", "mpeg-video.sequence-ext",
+				FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL }},
+		{ &hf_mpeg_video_group_of_pictures,
+			{ "MPEG group of pictures", "mpeg-video.gop",
+				FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL }},
+		{ &hf_mpeg_video_picture,
+			{ "MPEG picture", "mpeg-video.picture",
+				FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL }},
+		{ &hf_mpeg_video_quantization_matrix,
+			{ "MPEG quantization matrix", "mpeg-video.quant",
+				FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
+		{ &hf_mpeg_video_data,
+			{ "MPEG picture data", "mpeg-video.data",
+				FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
+	};
+
+	static gint *ett[] = {
+#include "packet-mpeg-pes-ettarr.c"
+	};
+
+	if (proto_mpeg_pes != -1)
+		return;
+
+	proto_mpeg_pes = proto_register_protocol(
+			"Packetized Elementary Stream", "MPEG PES", "mpeg-pes");
+	proto_register_field_array(proto_mpeg_pes, hf, array_length(hf));
+	proto_register_subtree_array(ett, array_length(ett));
+}
+
+void
+proto_reg_handoff_mpeg_pes(void)
+{
+	dissector_handle_t mpeg_handle = create_dissector_handle(
+			dissect_mpeg, proto_mpeg);
+	dissector_add("wtap_encap", WTAP_ENCAP_MPEG, mpeg_handle);
+
+	heur_dissector_add("mpeg", dissect_mpeg_pes, proto_mpeg_pes);
+}
Index: asn1/mpeg/Makefile
===================================================================
--- asn1/mpeg/Makefile	(revision 0)
+++ asn1/mpeg/Makefile	(revision 0)
@@ -0,0 +1,14 @@
+DISSECTOR_FILES=packet-mpeg-audio.c packet-mpeg-pes.c
+
+all: $(DISSECTOR_FILES)
+
+clean:
+	rm -f parsetab.py parsetab.pyc $(DISSECTOR_FILES)
+
+copy_files: all
+	cp $(DISSECTOR_FILES) ../../epan/dissectors
+
+.PHONY: all clean copy_files
+
+packet-%.c: ../../tools/asn2wrs.py %.asn %.cnf packet-%-template.c
+	python ../../tools/asn2wrs.py -e -p $* -c $*.cnf -s packet-$*-template $*.asn
Index: asn1/mpeg/mpeg-pes.asn
===================================================================
--- asn1/mpeg/mpeg-pes.asn	(revision 0)
+++ asn1/mpeg/mpeg-pes.asn	(revision 0)
@@ -0,0 +1,135 @@
+-- ASN description of MPEG Packetized Elementary Stream (PES)
+-- Written by Shaun Jackman <sjackman@xxxxxxxxx>
+-- Copyright 2007 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
+
+PES ::= SEQUENCE {
+	prefix OCTET STRING (SIZE (3)),
+	stream INTEGER {
+		picture (0),
+		sequence-header (179),
+		sequence-header-extension (181),
+		group-of-pictures (184),
+		program-end (185),
+		pack-header (186),
+		system-header (187),
+		program-stream-map (188),
+		private-stream-1 (189),
+		padding-stream (190),
+		private-stream-2 (191),
+		audio-stream (192),
+		video-stream (224)
+	} (0..255)
+}
+
+Pack ::= SEQUENCE {
+	must-be-zero BOOLEAN,
+	must-be-one0 BOOLEAN,
+	scr30 BIT STRING (SIZE (3)),
+	must-be-one1 BOOLEAN,
+	scr15 BIT STRING (SIZE (15)),
+	must-be-one2 BOOLEAN,
+	scr0 BIT STRING (SIZE (15)),
+	must-be-one3 BOOLEAN,
+	scr-ext BIT STRING (SIZE (9)),
+	must-be-one4 BOOLEAN,
+	program-mux-rate BIT STRING (SIZE (22)),
+	must-be-one5 BOOLEAN,
+	must-be-one6 BOOLEAN,
+	reserved BIT STRING (SIZE (5)),
+	stuffing-length INTEGER (0..7)
+}
+
+Stream ::= SEQUENCE {
+	length INTEGER (0..65535),
+	must-be-one BOOLEAN,
+	must-be-zero BOOLEAN,
+	scrambling-control INTEGER {
+		not-scrambled (0)
+	} (0..3),
+	priority BOOLEAN,
+	data-alignment BOOLEAN,
+	copyright BOOLEAN,
+	original BOOLEAN,
+	pts-flag BOOLEAN,
+	dts-flag BOOLEAN,
+	escr-flag BOOLEAN,
+	es-rate-flag BOOLEAN,
+	dsm-trick-mode-flag BOOLEAN,
+	additional-copy-info-flag BOOLEAN,
+	crc-flag BOOLEAN,
+	extension-flag BOOLEAN,
+	header-data-length INTEGER (0..255)
+}
+
+Sequence-header ::= SEQUENCE {
+	horizontal-size BIT STRING (SIZE (12)),
+	vertical-size BIT STRING (SIZE (12)),
+	aspect-ratio INTEGER {
+		aspect-1to1 (1),
+		aspect-4to3 (2),
+		aspect-16to9 (3),
+		aspect-2-21to1 (4)
+	} (0..15),
+	frame-rate ENUMERATED {
+		reserved (0),
+		fr (23976),
+		fr (24000),
+		fr (25000),
+		fr (29970),
+		fr (30000),
+		fr (50000),
+		fr (59940),
+		fr (60000)
+	},
+	bit-rate BIT STRING (SIZE (18)),
+	must-be-one BOOLEAN,
+	vbv-buffer-size BIT STRING (SIZE (10)),
+	constrained-parameters-flag BOOLEAN,
+	load-intra-quantiser-matrix BOOLEAN,
+	load-non-intra-quantiser-matrix BOOLEAN
+}
+
+Sequence-extension ::= SEQUENCE {
+	must-be-0001 BIT STRING (SIZE (4)),
+	profile-and-level INTEGER (0..255),
+	progressive-sequence BOOLEAN,
+	chroma-format INTEGER (0..3),
+	horizontal-size-extension INTEGER (0..3),
+	vertical-size-extension INTEGER (0..3),
+	bit-rate-extension BIT STRING (SIZE (12)),
+	must-be-one BOOLEAN,
+	vbv-buffer-size-extension INTEGER (0..255),
+	low-delay BOOLEAN,
+	frame-rate-extension-n INTEGER (0..3),
+	frame-rate-extension-d INTEGER (0..3)
+}
+
+Group-of-pictures ::= SEQUENCE {
+	drop-frame-flag BOOLEAN,
+	hour INTEGER (0..32),
+	minute INTEGER (0..64),
+	must-be-one BOOLEAN,
+	second INTEGER (0..64),
+	frame INTEGER (0..64),
+	closed-gop BOOLEAN,
+	broken-gop BOOLEAN,
+	must-be-zero BIT STRING (SIZE (5))
+}
+
+Picture ::= SEQUENCE {
+	temporal-sequence-number BIT STRING (SIZE (10)),
+	frame-type INTEGER {
+		i-frame (1),
+		p-frame (2),
+		b-frame (3),
+		d-frame (4)
+	} (0..7),
+	vbv-delay BIT STRING (SIZE (16))
+}
+
+END
Index: asn1/Makefile.am
===================================================================
--- asn1/Makefile.am	(revision 21033)
+++ asn1/Makefile.am	(working copy)
@@ -203,6 +203,13 @@
 	mms/mms-exp.cnf	\
 	mms/packet-mms-template.c	\
 	mms/packet-mms-template.h	\
+	mpeg/Makefile \
+	mpeg/mpeg-audio.asn \
+	mpeg/mpeg-audio.cnf \
+	mpeg/mpeg-pes.asn \
+	mpeg/mpeg-pes.cnf \
+	mpeg/packet-mpeg-audio-template.c \
+	mpeg/packet-mpeg-pes-template.c \
 	nbap/Makefile	\
 	nbap/Makefile.nmake	\
 	nbap/nbap.asn	\
Index: epan/dissectors/Makefile.common
===================================================================
--- epan/dissectors/Makefile.common	(revision 21033)
+++ epan/dissectors/Makefile.common	(working copy)
@@ -463,6 +463,8 @@
 	packet-mount.c	\
 	packet-mp2t.c	\
 	packet-mpeg1.c	\
+	packet-mpeg-audio.c	\
+	packet-mpeg-pes.c	\
 	packet-mpls.c	\
 	packet-mpls-echo.c   \
 	packet-mq.c		\