Doxygen Source Code Documentation
Main Page Alphabetical List Data Structures File List Data Fields Globals Search
extract_mpeg2.c
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "config.h"
00025
00026 #include <stdio.h>
00027 #include <stdlib.h>
00028 #include <string.h>
00029 #include <errno.h>
00030 #include <getopt.h>
00031 #ifdef HAVE_IO_H
00032 #include <fcntl.h>
00033 #include <io.h>
00034 #endif
00035 #include <inttypes.h>
00036
00037 #define BUFFER_SIZE 4096
00038 static uint8_t buffer[BUFFER_SIZE];
00039 static FILE * in_file;
00040 static int demux_track = 0xe0;
00041 static int demux_pid = 0;
00042 static int demux_pva = 0;
00043
00044 static void print_usage (char ** argv)
00045 {
00046 fprintf (stderr, "usage: %s [-s <track>] [-t <pid>] [-p] <file>\n"
00047 "\t-s\tset track number (0-15 or 0xe0-0xef)\n"
00048 "\t-t\tuse transport stream demultiplexer, pid 0x10-0x1ffe\n"
00049 "\t-p\tuse pva demultiplexer\n",
00050 argv[0]);
00051
00052 exit (1);
00053 }
00054
00055 static void handle_args (int argc, char ** argv)
00056 {
00057 int c;
00058 char * s;
00059
00060 while ((c = getopt (argc, argv, "s:t:p")) != -1)
00061 switch (c) {
00062 case 's':
00063 demux_track = strtol (optarg, &s, 0);
00064 if (demux_track < 0xe0)
00065 demux_track += 0xe0;
00066 if ((demux_track < 0xe0) || (demux_track > 0xef) || (*s)) {
00067 fprintf (stderr, "Invalid track number: %s\n", optarg);
00068 print_usage (argv);
00069 }
00070 break;
00071
00072 case 't':
00073 demux_pid = strtol (optarg, &s, 0);
00074 if ((demux_pid < 0x10) || (demux_pid > 0x1ffe) || (*s)) {
00075 fprintf (stderr, "Invalid pid: %s\n", optarg);
00076 print_usage (argv);
00077 }
00078 break;
00079
00080 case 'p':
00081 demux_pva = 1;
00082 break;
00083
00084 default:
00085 print_usage (argv);
00086 }
00087
00088 if (optind < argc) {
00089 in_file = fopen (argv[optind], "rb");
00090 if (!in_file) {
00091 fprintf (stderr, "%s - could not open file %s\n", strerror (errno),
00092 argv[optind]);
00093 exit (1);
00094 }
00095 } else
00096 in_file = stdin;
00097 }
00098
00099 #define DEMUX_PAYLOAD_START 1
00100 static int demux (uint8_t * buf, uint8_t * end, int flags)
00101 {
00102 static int mpeg1_skip_table[16] = {
00103 0, 0, 4, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
00104 };
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122 #define DEMUX_HEADER 0
00123 #define DEMUX_DATA 1
00124 #define DEMUX_SKIP 2
00125 static int state = DEMUX_SKIP;
00126 static int state_bytes = 0;
00127 static uint8_t head_buf[264];
00128
00129 uint8_t * header;
00130 int bytes;
00131 int len;
00132
00133 #define NEEDBYTES(x) \
00134 do { \
00135 int missing; \
00136 \
00137 missing = (x) - bytes; \
00138 if (missing > 0) { \
00139 if (header == head_buf) { \
00140 if (missing <= end - buf) { \
00141 memcpy (header + bytes, buf, missing); \
00142 buf += missing; \
00143 bytes = (x); \
00144 } else { \
00145 memcpy (header + bytes, buf, end - buf); \
00146 state_bytes = bytes + end - buf; \
00147 return 0; \
00148 } \
00149 } else { \
00150 memcpy (head_buf, header, bytes); \
00151 state = DEMUX_HEADER; \
00152 state_bytes = bytes; \
00153 return 0; \
00154 } \
00155 } \
00156 } while (0)
00157
00158 #define DONEBYTES(x) \
00159 do { \
00160 if (header != head_buf) \
00161 buf = header + (x); \
00162 } while (0)
00163
00164 if (flags & DEMUX_PAYLOAD_START)
00165 goto payload_start;
00166 switch (state) {
00167 case DEMUX_HEADER:
00168 if (state_bytes > 0) {
00169 header = head_buf;
00170 bytes = state_bytes;
00171 goto continue_header;
00172 }
00173 break;
00174 case DEMUX_DATA:
00175 if (demux_pid || (state_bytes > end - buf)) {
00176 fwrite (buf, end - buf, 1, stdout);
00177 state_bytes -= end - buf;
00178 return 0;
00179 }
00180 fwrite (buf, state_bytes, 1, stdout);
00181 buf += state_bytes;
00182 break;
00183 case DEMUX_SKIP:
00184 if (demux_pid || (state_bytes > end - buf)) {
00185 state_bytes -= end - buf;
00186 return 0;
00187 }
00188 buf += state_bytes;
00189 break;
00190 }
00191
00192 while (1) {
00193 if (demux_pid) {
00194 state = DEMUX_SKIP;
00195 return 0;
00196 }
00197 payload_start:
00198 header = buf;
00199 bytes = end - buf;
00200 continue_header:
00201 NEEDBYTES (4);
00202 if (header[0] || header[1] || (header[2] != 1)) {
00203 if (demux_pid) {
00204 state = DEMUX_SKIP;
00205 return 0;
00206 } else if (header != head_buf) {
00207 buf++;
00208 goto payload_start;
00209 } else {
00210 header[0] = header[1];
00211 header[1] = header[2];
00212 header[2] = header[3];
00213 bytes = 3;
00214 goto continue_header;
00215 }
00216 }
00217 if (demux_pid) {
00218 if ((header[3] >= 0xe0) && (header[3] <= 0xef))
00219 goto pes;
00220 fprintf (stderr, "bad stream id %x\n", header[3]);
00221 exit (1);
00222 }
00223 switch (header[3]) {
00224 case 0xb9:
00225
00226
00227 return 1;
00228 case 0xba:
00229 NEEDBYTES (12);
00230 if ((header[4] & 0xc0) == 0x40) {
00231 NEEDBYTES (14);
00232 len = 14 + (header[13] & 7);
00233 NEEDBYTES (len);
00234 DONEBYTES (len);
00235
00236 } else if ((header[4] & 0xf0) == 0x20) {
00237 DONEBYTES (12);
00238
00239 } else {
00240 fprintf (stderr, "weird pack header\n");
00241 exit (1);
00242 }
00243 break;
00244 default:
00245 if (header[3] == demux_track) {
00246 pes:
00247 NEEDBYTES (7);
00248 if ((header[6] & 0xc0) == 0x80) {
00249 NEEDBYTES (9);
00250 len = 9 + header[8];
00251 NEEDBYTES (len);
00252
00253 } else {
00254 len = 7;
00255 while ((header-1)[len] == 0xff) {
00256 len++;
00257 NEEDBYTES (len);
00258 if (len > 23) {
00259 fprintf (stderr, "too much stuffing\n");
00260 break;
00261 }
00262 }
00263 if (((header-1)[len] & 0xc0) == 0x40) {
00264 len += 2;
00265 NEEDBYTES (len);
00266 }
00267 len += mpeg1_skip_table[(header - 1)[len] >> 4];
00268 NEEDBYTES (len);
00269
00270 }
00271 DONEBYTES (len);
00272 bytes = 6 + (header[4] << 8) + header[5] - len;
00273 if (demux_pid || (bytes > end - buf)) {
00274 fwrite (buf, end - buf, 1, stdout);
00275 state = DEMUX_DATA;
00276 state_bytes = bytes - (end - buf);
00277 return 0;
00278 } else if (bytes <= 0)
00279 continue;
00280 fwrite (buf, bytes, 1, stdout);
00281 buf += bytes;
00282 } else if (header[3] < 0xb9) {
00283 fprintf (stderr,
00284 "looks like a video stream, not system stream\n");
00285 DONEBYTES (4);
00286 } else {
00287 NEEDBYTES (6);
00288 DONEBYTES (6);
00289 bytes = (header[4] << 8) + header[5];
00290 if (bytes > end - buf) {
00291 state = DEMUX_SKIP;
00292 state_bytes = bytes - (end - buf);
00293 return 0;
00294 }
00295 buf += bytes;
00296 }
00297 }
00298 }
00299 }
00300
00301 static void ps_loop (void)
00302 {
00303 uint8_t * end;
00304
00305 do {
00306 end = buffer + fread (buffer, 1, BUFFER_SIZE, in_file);
00307 if (demux (buffer, end, 0))
00308 break;
00309 } while (end == buffer + BUFFER_SIZE);
00310 }
00311
00312 static int pva_demux (uint8_t * buf, uint8_t * end)
00313 {
00314 static int state = DEMUX_SKIP;
00315 static int state_bytes = 0;
00316 static uint8_t head_buf[12];
00317
00318 uint8_t * header;
00319 int bytes;
00320 int len;
00321
00322 switch (state) {
00323 case DEMUX_HEADER:
00324 if (state_bytes > 0) {
00325 header = head_buf;
00326 bytes = state_bytes;
00327 goto continue_header;
00328 }
00329 break;
00330 case DEMUX_DATA:
00331 if (state_bytes > end - buf) {
00332 fwrite (buf, end - buf, 1, stdout);
00333 state_bytes -= end - buf;
00334 return 0;
00335 }
00336 fwrite (buf, state_bytes, 1, stdout);
00337 buf += state_bytes;
00338 break;
00339 case DEMUX_SKIP:
00340 if (state_bytes > end - buf) {
00341 state_bytes -= end - buf;
00342 return 0;
00343 }
00344 buf += state_bytes;
00345 break;
00346 }
00347
00348 while (1) {
00349 payload_start:
00350 header = buf;
00351 bytes = end - buf;
00352 continue_header:
00353 NEEDBYTES (2);
00354 if (header[0] != 0x41 || header[1] != 0x56) {
00355 if (header != head_buf) {
00356 buf++;
00357 goto payload_start;
00358 } else {
00359 header[0] = header[1];
00360 bytes = 1;
00361 goto continue_header;
00362 }
00363 }
00364 NEEDBYTES (8);
00365 if (header[2] != 1) {
00366 DONEBYTES (8);
00367 bytes = (header[6] << 8) + header[7];
00368 if (bytes > end - buf) {
00369 state = DEMUX_SKIP;
00370 state_bytes = bytes - (end - buf);
00371 return 0;
00372 }
00373 buf += bytes;
00374 } else {
00375 len = 8;
00376 if (header[5] & 0x10) {
00377 len = 12;
00378 NEEDBYTES (len);
00379 }
00380 DONEBYTES (len);
00381 bytes = (header[6] << 8) + header[7] + 8 - len;
00382 if (bytes > end - buf) {
00383 fwrite (buf, end - buf, 1, stdout);
00384 state = DEMUX_DATA;
00385 state_bytes = bytes - (end - buf);
00386 return 0;
00387 } else if (bytes > 0) {
00388 fwrite (buf, bytes, 1, stdout);
00389 buf += bytes;
00390 }
00391 }
00392 }
00393 }
00394
00395 static void pva_loop (void)
00396 {
00397 uint8_t * end;
00398
00399 do {
00400 end = buffer + fread (buffer, 1, BUFFER_SIZE, in_file);
00401 pva_demux (buffer, end);
00402 } while (end == buffer + BUFFER_SIZE);
00403 }
00404
00405 static void ts_loop (void)
00406 {
00407 #define PACKETS (BUFFER_SIZE / 188)
00408 uint8_t * buf;
00409 uint8_t * data;
00410 uint8_t * end;
00411 int packets;
00412 int i;
00413 int pid;
00414
00415 do {
00416 packets = fread (buffer, 188, PACKETS, in_file);
00417 for (i = 0; i < packets; i++) {
00418 buf = buffer + i * 188;
00419 end = buf + 188;
00420 if (buf[0] != 0x47) {
00421 fprintf (stderr, "bad sync byte\n");
00422 exit (1);
00423 }
00424 pid = ((buf[1] << 8) + buf[2]) & 0x1fff;
00425 if (pid != demux_pid)
00426 continue;
00427 data = buf + 4;
00428 if (buf[3] & 0x20) {
00429 data = buf + 5 + buf[4];
00430 if (data > end)
00431 continue;
00432 }
00433 if (buf[3] & 0x10)
00434 demux (data, end, (buf[1] & 0x40) ? DEMUX_PAYLOAD_START : 0);
00435 }
00436 } while (packets == PACKETS);
00437 }
00438
00439 int main (int argc, char ** argv)
00440 {
00441 #ifdef HAVE_IO_H
00442 setmode (fileno (stdout), O_BINARY);
00443 #endif
00444
00445 handle_args (argc, argv);
00446
00447 if (demux_pva)
00448 pva_loop ();
00449 if (demux_pid)
00450 ts_loop ();
00451 else
00452 ps_loop ();
00453
00454 return 0;
00455 }