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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 #ifdef HAVE_SYS_TYPES_H
28 #include <sys/types.h>
36 #include "wsutil/mpeg-audio.h"
40 #include "file_wrappers.h"
47 #define PES_VALID(n) (((n) >> 8 & 0xffffff) == PES_PREFIX)
55 mpeg_resync(wtap
*wth
, int *err
, gchar
**err_info _U_
)
57 gint64 offset
= file_tell(wth
->fh
);
59 int byte
= file_getc(wth
->fh
);
62 if (byte
== 0xff && count
> 0) {
63 byte
= file_getc(wth
->fh
);
64 if (byte
!= EOF
&& (byte
& 0xe0) == 0xe0)
67 byte
= file_getc(wth
->fh
);
70 if (file_seek(wth
->fh
, offset
, SEEK_SET
, err
) == -1)
76 mpeg_read_header(wtap
*wth
, int *err
, gchar
**err_info
, guint32
*n
)
80 errno
= WTAP_ERR_CANT_READ
;
81 bytes_read
= file_read(n
, sizeof *n
, wth
->fh
);
82 if (bytes_read
!= sizeof *n
) {
83 *err
= file_error(wth
->fh
, err_info
);
84 if (*err
== 0 && bytes_read
!= 0)
85 *err
= WTAP_ERR_SHORT_READ
;
89 if (file_seek(wth
->fh
, -(gint64
)(sizeof *n
), SEEK_CUR
, err
) == -1)
94 #define SCRHZ 27000000
97 mpeg_read(wtap
*wth
, int *err
, gchar
**err_info
, gint64
*data_offset
)
99 mpeg_t
*mpeg
= (mpeg_t
*)wth
->priv
;
101 int bytes_read
= mpeg_read_header(wth
, err
, err_info
, &n
);
102 unsigned int packet_size
;
103 nstime_t ts
= mpeg
->now
;
105 if (bytes_read
== -1)
108 gint64 offset
= file_tell(wth
->fh
);
113 if (file_seek(wth
->fh
, 3, SEEK_CUR
, err
) == -1)
116 bytes_read
= file_read(&stream
, sizeof stream
, wth
->fh
);
117 if (bytes_read
!= sizeof stream
) {
118 *err
= file_error(wth
->fh
, err_info
);
122 if (stream
== 0xba) {
128 bytes_read
= file_read(&pack1
, sizeof pack1
, wth
->fh
);
129 if (bytes_read
!= sizeof pack1
) {
130 *err
= file_error(wth
->fh
, err_info
);
131 if (*err
== 0 && bytes_read
!= 0)
132 *err
= WTAP_ERR_SHORT_READ
;
135 bytes_read
= file_read(&pack0
, sizeof pack0
, wth
->fh
);
136 if (bytes_read
!= sizeof pack0
) {
137 *err
= file_error(wth
->fh
, err_info
);
138 if (*err
== 0 && bytes_read
!= 0)
139 *err
= WTAP_ERR_SHORT_READ
;
142 pack
= (guint64
)g_ntohl(pack1
) << 32 | g_ntohl(pack0
);
144 switch (pack
>> 62) {
146 if (file_seek(wth
->fh
, 1, SEEK_CUR
, err
) == -1)
148 bytes_read
= file_read(&stuffing
,
149 sizeof stuffing
, wth
->fh
);
150 if (bytes_read
!= sizeof stuffing
) {
151 *err
= file_error(wth
->fh
, err_info
);
155 packet_size
= 14 + stuffing
;
158 guint64 bytes
= pack
>> 16;
160 (bytes
>> 43 & 0x0007) << 30 |
161 (bytes
>> 27 & 0x7fff) << 15 |
162 (bytes
>> 11 & 0x7fff) << 0;
163 guint ext
= (guint
)((bytes
>> 1) & 0x1ff);
164 guint64 cr
= 300 * ts_val
+ ext
;
165 guint rem
= (guint
)(cr
% SCRHZ
);
167 = mpeg
->t0
+ (time_t)(cr
/ SCRHZ
);
169 = (int)(G_GINT64_CONSTANT(1000000000) * rem
/ SCRHZ
);
178 bytes_read
= file_read(&length
, sizeof length
, wth
->fh
);
179 if (bytes_read
!= sizeof length
) {
180 *err
= file_error(wth
->fh
, err_info
);
181 if (*err
== 0 && bytes_read
!= 0)
182 *err
= WTAP_ERR_SHORT_READ
;
185 length
= g_ntohs(length
);
186 packet_size
= 6 + length
;
189 if (file_seek(wth
->fh
, offset
, SEEK_SET
, err
) == -1)
194 MPA_UNMARSHAL(&mpa
, n
);
195 if (MPA_VALID(&mpa
)) {
196 packet_size
= MPA_BYTES(&mpa
);
197 mpeg
->now
.nsecs
+= MPA_DURATION_NS(&mpa
);
198 if (mpeg
->now
.nsecs
>= 1000000000) {
200 mpeg
->now
.nsecs
-= 1000000000;
203 packet_size
= mpeg_resync(wth
, err
, err_info
);
204 if (packet_size
== 0)
208 *data_offset
= file_tell(wth
->fh
);
210 if (!wtap_read_packet_bytes(wth
->fh
, wth
->frame_buffer
,
211 packet_size
, err
, err_info
))
213 /* XXX - relative, not absolute, time stamps */
214 wth
->phdr
.presence_flags
= WTAP_HAS_TS
;
216 wth
->phdr
.caplen
= packet_size
;
217 wth
->phdr
.len
= packet_size
;
222 mpeg_seek_read(wtap
*wth
, gint64 seek_off
,
223 struct wtap_pkthdr
*phdr _U_
, Buffer
*buf
, int length
,
224 int *err
, gchar
**err_info
)
226 if (file_seek(wth
->random_fh
, seek_off
, SEEK_SET
, err
) == -1)
228 return wtap_read_packet_bytes(wth
->random_fh
, buf
, length
, err
, err_info
);
235 { 3, "TAG" }, /* ID3v1 */
236 { 3, "ID3" }, /* ID3v2 */
237 { 3, "\0\0\1" }, /* MPEG PES */
238 { 2, "\xff\xfb" }, /* MP3, taken from http://en.wikipedia.org/wiki/MP3#File_structure */
243 mpeg_open(wtap
*wth
, int *err
, gchar
**err_info
)
247 struct _mpeg_magic
* m
;
250 errno
= WTAP_ERR_CANT_READ
;
251 bytes_read
= file_read(magic_buf
, sizeof magic_buf
, wth
->fh
);
252 if (bytes_read
!= (int) sizeof magic_buf
) {
253 *err
= file_error(wth
->fh
, err_info
);
254 if (*err
!= 0 && *err
!= WTAP_ERR_SHORT_READ
)
259 for (m
=magic
; m
->match
; m
++) {
260 if (memcmp(magic_buf
, m
->match
, m
->len
) == 0)
267 /* This appears to be a file with MPEG data. */
268 if (file_seek(wth
->fh
, 0, SEEK_SET
, err
) == -1)
271 wth
->file_type_subtype
= WTAP_FILE_TYPE_SUBTYPE_MPEG
;
272 wth
->file_encap
= WTAP_ENCAP_MPEG
;
273 wth
->tsprecision
= WTAP_FILE_TSPREC_NSEC
;
274 wth
->subtype_read
= mpeg_read
;
275 wth
->subtype_seek_read
= mpeg_seek_read
;
276 wth
->snapshot_length
= 0;
278 mpeg
= (mpeg_t
*)g_malloc(sizeof(mpeg_t
));
279 wth
->priv
= (void *)mpeg
;
282 mpeg
->t0
= mpeg
->now
.secs
;