3 * MPEG file format decoder for the Wiretap library.
4 * Written by Shaun Jackman <sjackman@gmail.com>
5 * Copyright 2007 Shaun Jackman
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29 #ifdef HAVE_SYS_TYPES_H
30 #include <sys/types.h>
38 #include "mpeg-audio.h"
42 #include "file_wrappers.h"
50 #define PES_VALID(n) (((n) >> 8 & 0xffffff) == PES_PREFIX)
53 mpeg_resync(wtap *wth, int *err, gchar **err_info _U_)
55 gint64 offset = file_tell(wth->fh);
57 int sync = file_getc(wth->fh);
60 if (sync == 0xff && count > 0) {
61 sync = file_getc(wth->fh);
62 if (sync != EOF && (sync & 0xe0) == 0xe0)
65 sync = file_getc(wth->fh);
68 file_seek(wth->fh, offset, SEEK_SET, err);
73 mpeg_read_header(wtap *wth, int *err, gchar **err_info _U_,
78 errno = WTAP_ERR_CANT_READ;
79 bytes_read = file_read(n, 1, sizeof *n, wth->fh);
80 if (bytes_read != sizeof *n) {
81 *err = file_error(wth->fh);
82 if (*err == 0 && bytes_read != 0)
83 *err = WTAP_ERR_SHORT_READ;
87 if (file_seek(wth->fh, -(gint64)(sizeof *n), SEEK_CUR, err) == -1)
93 mpeg_read_rec_data(FILE_T fh, guchar *pd, int length, int *err)
97 errno = WTAP_ERR_CANT_READ;
98 bytes_read = file_read(pd, 1, length, fh);
100 if (bytes_read != length) {
101 *err = file_error(fh);
103 *err = WTAP_ERR_SHORT_READ;
110 mpeg_read(wtap *wth, int *err, gchar **err_info _U_,
114 int bytes_read = mpeg_read_header(wth, err, err_info, &n);
115 unsigned packet_size;
116 struct wtap_nstime ts = wth->capture.mpeg->now;
118 if (bytes_read == -1)
121 gint64 offset = file_tell(wth->fh);
127 if (file_seek(wth->fh, 3, SEEK_CUR, err) == -1)
130 bytes_read = file_read(&stream, 1, sizeof stream, wth->fh);
131 if (bytes_read != sizeof stream) {
132 *err = file_error(wth->fh);
136 if (stream == 0xba) {
146 bytes_read = file_read(&pack1, 1, sizeof pack1, wth->fh);
147 if (bytes_read != sizeof pack1) {
148 *err = file_error(wth->fh);
149 if (*err == 0 && bytes_read != 0)
150 *err = WTAP_ERR_SHORT_READ;
153 bytes_read = file_read(&pack0, 1, sizeof pack0, wth->fh);
154 if (bytes_read != sizeof pack0) {
155 *err = file_error(wth->fh);
156 if (*err == 0 && bytes_read != 0)
157 *err = WTAP_ERR_SHORT_READ;
160 pack = (guint64)g_ntohl(pack1) << 32 | g_ntohl(pack0);
162 switch (pack >> 62) {
164 if (file_seek(wth->fh, 1, SEEK_CUR, err) == -1)
166 bytes_read = file_read(&stuffing,
167 1, sizeof stuffing, wth->fh);
168 if (bytes_read != sizeof stuffing) {
169 *err = file_error(wth->fh);
173 packet_size = 14 + stuffing;
176 ((pack >> 59 & 0x0007) << 30 |
177 (pack >> 43 & 0x7fff) << 15 |
178 (pack >> 27 & 0x7fff) << 0);
179 scr_ext = (guint16)(pack >> 17 & 0x1ff);
180 t = wth->capture.mpeg->t0 + scr / 90e3 + scr_ext / 27e6;
182 wth->capture.mpeg->now.nsecs = (int)(modf(t, &secs) * 1e9);
183 wth->capture.mpeg->now.secs = (time_t)secs;
184 ts = wth->capture.mpeg->now;
191 bytes_read = file_read(&length, 1, sizeof length, wth->fh);
192 if (bytes_read != sizeof length) {
193 *err = file_error(wth->fh);
194 if (*err == 0 && bytes_read != 0)
195 *err = WTAP_ERR_SHORT_READ;
198 length = g_ntohs(length);
199 packet_size = 6 + length;
202 if (file_seek(wth->fh, offset, SEEK_SET, err) == -1)
207 MPA_UNMARSHAL(&mpa, n);
208 if (MPA_VALID(&mpa)) {
209 packet_size = MPA_BYTES(&mpa);
210 wth->capture.mpeg->now.nsecs += MPA_DURATION_NS(&mpa);
211 if (wth->capture.mpeg->now.nsecs >= 1000000000) {
212 wth->capture.mpeg->now.secs++;
213 wth->capture.mpeg->now.nsecs -= 1000000000;
216 packet_size = mpeg_resync(wth, err, err_info);
217 if (packet_size == 0)
221 *data_offset = wth->data_offset;
223 buffer_assure_space(wth->frame_buffer, packet_size);
224 if (!mpeg_read_rec_data(wth->fh, buffer_start_ptr(wth->frame_buffer),
227 wth->data_offset += packet_size;
229 wth->phdr.caplen = packet_size;
230 wth->phdr.len = packet_size;
235 mpeg_seek_read(wtap *wth, gint64 seek_off,
236 union wtap_pseudo_header *pseudo_header _U_, guchar *pd, int length,
237 int *err, gchar **err_info _U_)
239 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
241 return mpeg_read_rec_data(wth->random_fh, pd, length, err);
245 mpeg_close(wtap *wth)
247 g_free(wth->capture.mpeg);
250 /* XXX We probably need more magic to open more types */
261 mpeg_open(wtap *wth, int *err, gchar **err_info _U_)
265 struct _mpeg_magic* m;
267 errno = WTAP_ERR_CANT_READ;
268 bytes_read = file_read(magic_buf, 1, sizeof magic_buf, wth->fh);
269 if (bytes_read != (int) sizeof magic_buf) {
270 *err = file_error(wth->fh);
276 for (m=magic;m->match;m++) {
277 if (memcmp(magic_buf,m->match,m->len) == 0)
284 /* This appears to be a file with MPEG data. */
285 if (file_seek(wth->fh, 0, SEEK_SET, err) == -1)
288 wth->file_type = WTAP_FILE_MPEG;
289 wth->file_encap = WTAP_ENCAP_MPEG;
290 wth->tsprecision = WTAP_FILE_TSPREC_NSEC;
291 wth->subtype_read = mpeg_read;
292 wth->subtype_seek_read = mpeg_seek_read;
293 wth->subtype_close = mpeg_close;
294 wth->snapshot_length = 0;
296 wth->capture.mpeg = g_malloc(sizeof(libpcap_t));
297 wth->capture.mpeg->now.secs = time(NULL);
298 wth->capture.mpeg->now.nsecs = 0;
299 wth->capture.mpeg->t0 = (double) wth->capture.mpeg->now.secs;