#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define __USE_LARGEFILE64
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
char *progname;
int pack_num;
char *basename;
int audio_cut_flag = 0;
int print_offset = 0;
int pes_flag = 0;
int debug = 0;
#define QMAKESTR(x) #x
#define MAKESTR(x) QMAKESTR(x)
void usage (void)
{
fprintf (stderr, "usage:\n");
fprintf (stderr, "%s [options...] mpeg_program_stream [output_base_name]\n", progname);
fprintf (stderr, "options:\n");
fprintf (stderr, " -a discard any partial MPEG audio frame at the start of a stream\n");
fprintf (stderr, " -t print the offset (ms) between the first video and audio PTS timestamps\n");
fprintf (stderr, " -p output PES streams rather than Elementary Streams\n");
}
/* generate fatal error message to stderr, doesn't return */
void fatal (int ret, char *format, ...);// __attribute__ ((noreturn));
void fatal (int ret, char *format, ...)
{
va_list ap;
fprintf (stderr, "fatal error");
if (format)
{
fprintf (stderr, ": ");
if (ret >= 2)
fprintf (stderr, "pack num %d: ", pack_num);
va_start (ap, format);
vfprintf (stderr, format, ap);
va_end (ap);
}
else
fprintf (stderr, "\n");
if (ret == 1)
usage ();
exit (ret);
}
void hex_dump (FILE *f, unsigned char *p, int len)
{
int i, j;
for (i = 0; i < len; i += 16)
{
fprintf (f, "%04x:", i);
for (j = i; j < (i + 16); j++)
{
if (j < len)
fprintf (f, " %02x", p [j]);
else
fprintf (f, " ");
}
fprintf (f, "\n");
}
}
#define PRIVATE_STREAM_1 0xbd
#define PADDING_STREAM 0xbe
#define PRIVATE_STREAM_2 0xbf
#define FIRST_AUDIO_STREAM 0xc0
#define LAST_AUDIO_STREAM 0xdf
#define FIRST_VIDEO_STREAM 0xe0
#define LAST_VIDEO_STREAM 0xef
int open_output (int stream)
{
int fd;
char *extension;
char fn [200];
if ((stream >= FIRST_AUDIO_STREAM) && (stream <= LAST_AUDIO_STREAM))
{
stream -= 0xc0;
extension = "mpa";
}
else if ((stream >= FIRST_VIDEO_STREAM) && (stream <= LAST_VIDEO_STREAM))
{
stream -= 0xe0;
extension = "mpv";
}
else
extension = "str";
_snprintf (fn, sizeof (fn), "%s-%d.%s", basename, stream, extension);
// fd = open (fn, O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE,
// S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
fd = _open (fn, _O_BINARY | O_WRONLY | O_CREAT | O_TRUNC);
if (fd < 0)
fatal (2, "error opening output file %s\n", fn);
return (fd);
}
unsigned char * parse_system_header (unsigned char *p)
{
int header_length;
/* printf ("pack number %d has system header\n", pack_num); */
p += 4; /* skip start code */
header_length = (*(p++)) << 8;
header_length += *(p++);
p += header_length;
return (p);
}
unsigned long long parse_time_stamp (unsigned char *p, int marker)
{
int b;
unsigned long long val;
b = *p++;
val = (b & 0x0e) << 29;
b = (*(p++)) << 8;
b += *(p++);
val += ((b & 0xfffe) << 14);
b = (*(p++)) << 8;
b += *(p++);
val += ((b & 0xfffe) >> 1);
return (val);
}
int found_stream [256];
int out_fd [256];
unsigned char found_pts [256];
unsigned long long pts [256];
unsigned char found_dts [256];
unsigned long long dts [256];
int audio_state [256];
#define AS_LOOKING_FOR_FF 0
#define AS_LOOKING_FOR_FD 1
#define AS_HEADER_FOUND 2
unsigned char * audio_cut (int stream, unsigned char *p, int count)
{
unsigned char c;
while (count--)
{
c = *(p++);
switch (audio_state [stream])
{
case AS_LOOKING_FOR_FF:
if (c == 0xff)
audio_state [stream] = AS_LOOKING_FOR_FD;
break;
case AS_LOOKING_FOR_FD:
if (c == 0xfd)
{
audio_state [stream] = AS_HEADER_FOUND;
return (p);
}
else if (c == 0xff)
audio_state [stream] = AS_LOOKING_FOR_FD;
else
audio_state [stream] = AS_LOOKING_FOR_FF;
break;
default:
fatal (2, "error in audio_cut() state machine\n");
}
}
return (p);
}
void check_offset (void)
{
double a_pts, v_pts;
if (! (found_pts [FIRST_AUDIO_STREAM] && found_pts [FIRST_VIDEO_STREAM]))
return;
a_pts = ((double) pts [FIRST_AUDIO_STREAM]) / 90.0;
v_pts = ((double) pts [FIRST_VIDEO_STREAM]) / 90.0;
printf ("offset: %d ms\n", (int)(v_pts + 0.5 - a_pts));
print_offset = 0;
}
void write_stream (int stream, unsigned char *p, int count)
{
while (count)
{
int c2 = _write (out_fd [stream], p, count);
if (c2 < 0)
{
perror ("write error");
fatal (2, "write error on stream %02x\n", stream);
}
p += c2;
count -= c2;
}
}
unsigned char * parse_packet (int stream, unsigned char *p)
{
int length;
unsigned char *end;
unsigned char *data_start;
int count;
int flags, pes_header_data_length;
p += 4; /* skip start code including stream ID */
length = (*(p++)) << 8;
length += *(p++);
end = p + length;
/* hex_dump (stdout, p - 6, length + 6); */
if (stream == PADDING_STREAM)
goto done; /* ignore */
if (! found_stream [stream])
{
if (debug)
printf ("found stream %02x\n", stream);
found_stream [stream] = 1;
out_fd [stream] = open_output (stream);
}
if (pes_flag)
{
write_stream (stream, p - 6, length + 6);
goto done;
}
if (stream != PRIVATE_STREAM_2)
{
/* skip padding bytes */
int i = 0;
while (((*p) == 0xff) && (i++ < 16))
p++;
if (i)
printf ("%d bytes padding\n", i);
}
flags = (*(p++)) << 8;
flags += *(p++);
if ((flags >> 14) != 2)
fatal (2, "bad flags %04x\n", flags);
pes_header_data_length = *(p++);
/* printf ("PES header data length %d\n", pes_header_data_length); */
data_start = p + pes_header_data_length;
switch ((flags >> 6) & 3)
{
case 2:
if (! found_pts [stream])
{
found_pts [stream] = 1;
pts [stream] = parse_time_stamp (p, 2);
if (debug)
printf ("stream %d PTS: %llu, %f\n", stream, pts [stream], (double) pts [stream] / 90.0);
if (print_offset && ((stream == FIRST_AUDIO_STREAM) ||
(stream == FIRST_VIDEO_STREAM)))
check_offset ();
}
p += 5;
break;
case 3:
if (! found_pts [stream])
{
found_pts [stream] = 1;
pts [stream] = parse_time_stamp (p, 3);
if (debug)
printf ("stream %d PTS: %llu, %f\n", stream, pts [stream], (double) pts [stream] / 90.0);
if (print_offset && ((stream == FIRST_AUDIO_STREAM) ||
(stream == FIRST_VIDEO_STREAM)))
check_offset ();
}
p += 5;
if (! found_dts [stream])
{
found_dts [stream] = 1;
dts [stream] = parse_time_stamp (p, 1);
if (debug)
printf ("stream %d DTS: %llu, %f\n", stream, dts [stream], (double) dts [stream]/ 90.0);
}
p += 5;
break;
case 0:
break;
default:
fatal (2, "bad time stamp code\n");
}
p = data_start;
count = (end - p);
if ((stream >= FIRST_AUDIO_STREAM) && (stream <= LAST_AUDIO_STREAM) &&
audio_cut_flag && (audio_state [stream] != AS_HEADER_FOUND))
{
p = audio_cut (stream, p, count);
if (audio_state [stream] == AS_HEADER_FOUND)
{
/* Once we've found the header, the pointer has already been
advanced past it. We need to push it back into the stream.
Note that the first byte of the header might have been in
a previous packet, but it's OK to push it back anyhow because
we're guaranteed to have room in the buffer (possibly overwriting
the last byte of the packet header, which we no longer care
about. */
p -= 2;
p [0] = 0xff;
p [1] = 0xfd;
}
count = (end - p);
}
write_stream (stream, p, count);
done:
return (end);
}
unsigned char packet_start_code_prefix [3] = { 0x00, 0x00, 0x01 };
unsigned char end_code [4] = { 0x00, 0x00, 0x01, 0xb9 };
unsigned char pack_start_code [4] = { 0x00, 0x00, 0x01, 0xba };
unsigned char system_header_start_code [4] = { 0x00, 0x00, 0x01, 0xbb };
void parse_pack (unsigned char *buf, int size)
{
int stream;
unsigned char *p = buf;
p += sizeof (pack_start_code) + 10;
if (memcmp (p, system_header_start_code, sizeof (system_header_start_code)) == 0)
p = parse_system_header (p);
while (p < (buf + size))
{
if (memcmp (p, packet_start_code_pref
- 1
- 2
- 3
前往页