File: | mpeg2desc.c |
Location: | line 765, column 33 |
Description: | Value stored to 'eptr' is never read |
1 | /* |
2 | Utility to extract audio/video streams and dump information about |
3 | packetes in an MPEG stream. |
4 | */ |
5 | /* |
6 | * Copyright (C) 2002 Scott Smith (trckjunky@users.sourceforge.net) |
7 | * |
8 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License as published by |
10 | * the Free Software Foundation; either version 2 of the License, or (at |
11 | * your option) any later version. |
12 | * |
13 | * This program is distributed in the hope that it will be useful, but |
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
16 | * General Public License for more details. |
17 | * |
18 | * You should have received a copy of the GNU General Public License |
19 | * along with this program; if not, write to the Free Software |
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
21 | * MA 02110-1301 USA. |
22 | */ |
23 | |
24 | #include "config.h" |
25 | |
26 | #include "compat.h" |
27 | |
28 | #include <setjmp.h> |
29 | #include <assert.h> |
30 | #include <errno(*__errno_location ()).h> |
31 | #include <fcntl.h> |
32 | |
33 | // this is needed for FreeBSD and Windows |
34 | #include <sys/time.h> |
35 | |
36 | #include "common.h" |
37 | |
38 | // #define SHOWDATA |
39 | |
40 | static unsigned int |
41 | inputpos = 0, /* position in stdin */ |
42 | queuedlen = 0; /* total nr bytes awaiting writing to output files */ |
43 | |
44 | const char * const frametype = "0IPB4567"; |
45 | |
46 | #define SCRTIME27000000 27000000 |
47 | #define PTSTIME90000 90000 |
48 | |
49 | #define WAITLEN(256*1024) (256*1024) |
50 | |
51 | #define BUFLEN(65536) (65536) |
52 | |
53 | struct fdbuf |
54 | { |
55 | int pos,len; |
56 | struct fdbuf *next; |
57 | unsigned char buf[BUFLEN(65536)]; |
58 | }; |
59 | |
60 | #define MAX_FILES256 256 |
61 | /* how many output files I can write at once -- can't have |
62 | more than this number of MPEG streams anyway */ |
63 | |
64 | /* values for ofd.fd: */ |
65 | #define FD_TOOPEN(-2) (-2) /* open file named ofd.fname on first write */ |
66 | #define FD_CLOSED(-1) (-1) |
67 | |
68 | struct ofd |
69 | { |
70 | int fd; |
71 | char *fname; |
72 | struct fdbuf *firstbuf,**lastbufptr; /* queue of buffers awaiting writing */ |
73 | int len; |
74 | bool_Bool isvalid; |
75 | } outputfds[256]; /* files to write, indexed by stream id */ |
76 | |
77 | static int |
78 | ofdlist[MAX_FILES256], /* indexes of used entries in outputfds */ |
79 | numofd; /* contiguous used size of ofdlist */ |
80 | |
81 | static int firstpts[256]; /* indexed by stream id */ |
82 | |
83 | static bool_Bool |
84 | outputenglish = true1, |
85 | nounknown = false0, |
86 | closing = false0, |
87 | outputmplex = false0; |
88 | static int |
89 | audiodrop = 0; |
90 | |
91 | static fd_set |
92 | /* should be local to dowork routine */ |
93 | rfd, wfd; |
94 | |
95 | static int64_t readpts(const unsigned char *buf) |
96 | { |
97 | return |
98 | (int64_t)((buf[0] & 0xf) >> 1) << 30 |
99 | | |
100 | ((int64_t)buf[1] << 8 | buf[2]) >> 1 << 15 |
101 | | |
102 | ((int64_t)buf[3] << 8 | buf[4]) >> 1; |
103 | } /*readpts*/ |
104 | |
105 | static bool_Bool hasbecomevalid(int stream, const struct ofd *o) |
106 | /* checks if there is a valid packet header at the start of the data to be |
107 | written to the specified output stream. Assumes there is at least 4 bytes |
108 | of data waiting to be written. */ |
109 | { |
110 | bool_Bool valid = false0; |
111 | unsigned int realquad; |
112 | const struct fdbuf * const f1 = o->firstbuf; |
113 | if (f1 != 0) |
114 | { |
115 | unsigned char quad[4]; |
116 | int i; |
117 | const struct fdbuf * const f2 = f1->next; |
118 | valid = true1; /* next assumption */ |
119 | for (i = 0; valid && i < 4; i++) |
120 | { |
121 | if (f1->len - f1->pos - i > 0) |
122 | quad[i] = f1->buf[f1->pos + i]; |
123 | else if (f2 != 0) |
124 | quad[i] = f2->buf[f2->pos + i - (f1->len - f1->pos)]; |
125 | else |
126 | valid = false0; |
127 | } /*for*/ |
128 | if (valid) |
129 | { |
130 | realquad = |
131 | quad[0] << 24 |
132 | | |
133 | quad[1] << 16 |
134 | | |
135 | quad[2] << 8 |
136 | | |
137 | quad[3]; |
138 | } /*if*/ |
139 | } /*if*/ |
140 | return |
141 | valid |
142 | && |
143 | ( |
144 | stream >= MPID_AUDIO_FIRST |
145 | && |
146 | stream <= MPID_AUDIO_LAST |
147 | && |
148 | (realquad & 0xFFE00000) == 0xFFE00000 |
149 | || |
150 | stream >= MPID_VIDEO_FIRST |
151 | && |
152 | stream <= MPID_VIDEO_LAST |
153 | && |
154 | realquad == 0x100 + MPID_SEQUENCE |
155 | ); |
156 | } /*hasbecomevalid*/ |
157 | |
158 | static bool_Bool dowork |
159 | ( |
160 | bool_Bool checkin /* whether to check if bytes are available to be read from stdin */ |
161 | ) |
162 | /* writes pending packets to output streams. This is done concurrently to allow |
163 | for use with pipes. Returns true iff stdin has input available. */ |
164 | { |
165 | int highestfd = -1; |
166 | struct timeval tv; |
167 | if (!numofd) |
168 | return checkin; |
169 | if (checkin) |
170 | { |
171 | FD_SET(STDIN_FILENO, &rfd)((void) (((&rfd)->fds_bits)[((0) / (8 * (int) sizeof ( __fd_mask)))] |= ((__fd_mask) 1 << ((0) % (8 * (int) sizeof (__fd_mask)))))); |
172 | highestfd = STDIN_FILENO0; |
173 | } |
174 | else |
175 | { |
176 | FD_CLR(STDIN_FILENO, &rfd)((void) (((&rfd)->fds_bits)[((0) / (8 * (int) sizeof ( __fd_mask)))] &= ~((__fd_mask) 1 << ((0) % (8 * (int ) sizeof (__fd_mask)))))); |
177 | } /*if*/ |
178 | while (true1) |
179 | { |
180 | int i, minq = -1; |
181 | for (i = 0; i < numofd; i++) |
182 | { |
183 | struct ofd *o = &outputfds[ofdlist[i]]; |
184 | if (o->fd != FD_CLOSED(-1)) |
185 | { |
186 | if (o->fd == FD_TOOPEN(-2)) |
187 | { |
188 | int fd; |
189 | fd = open(o->fname, O_CREAT0100 | O_WRONLY01 | O_NONBLOCK04000, 0666); |
190 | if (fd == -1 && errno(*__errno_location ()) == ENXIO6) |
191 | { |
192 | continue; /* try again later, in case pipe not created yet */ |
193 | } /*if*/ |
194 | if (fd == -1) |
195 | { |
196 | fprintf(stderrstderr,"Cannot open %s: %s\n",o->fname,strerror(errno(*__errno_location ()))); |
197 | exit(1); |
198 | } /*if*/ |
199 | o->fd = fd; |
200 | } /*if*/ |
201 | // at this point, fd >= 0 |
202 | if (minq == -1 || o->len < minq) |
203 | { |
204 | minq = o->len; |
205 | } /*if*/ |
206 | if ((o->len > 0 && o->isvalid) || o->len >= 4) |
207 | { |
208 | if (o->fd > highestfd) |
209 | highestfd = o->fd; |
210 | FD_SET(o->fd, &wfd)((void) (((&wfd)->fds_bits)[((o->fd) / (8 * (int) sizeof (__fd_mask)))] |= ((__fd_mask) 1 << ((o->fd) % (8 * (int) sizeof (__fd_mask)))))); |
211 | } |
212 | else |
213 | { |
214 | FD_CLR(o->fd, &wfd)((void) (((&wfd)->fds_bits)[((o->fd) / (8 * (int) sizeof (__fd_mask)))] &= ~((__fd_mask) 1 << ((o->fd) % (8 * (int) sizeof (__fd_mask)))))); |
215 | if (closing) |
216 | { |
217 | close(o->fd); |
218 | o->fd = FD_CLOSED(-1); |
219 | } /*if*/ |
220 | } /*if*/ |
221 | } /*if*/ |
222 | } /*for*/ |
223 | // if all the open files have more then WAITLEN bytes of data |
224 | // queued up, then don't process anymore |
225 | if (minq >= WAITLEN(256*1024)) |
226 | { |
227 | FD_CLR(STDIN_FILENO, &rfd)((void) (((&rfd)->fds_bits)[((0) / (8 * (int) sizeof ( __fd_mask)))] &= ~((__fd_mask) 1 << ((0) % (8 * (int ) sizeof (__fd_mask)))))); |
228 | break; |
229 | } |
230 | else if (minq >= 0 || outputmplex) // as long as one file is open, continue |
231 | break; |
232 | sleep(1); |
233 | } /*while*/ |
234 | if (highestfd == -1) |
235 | return false0; /* nothing to do */ |
236 | tv.tv_sec = 1; // set timeout to 1 second just in case any files need to be opened |
237 | tv.tv_usec = 0; |
238 | if (select(highestfd + 1, &rfd, &wfd, NULL((void*)0), &tv) > 0) |
239 | { |
240 | int i; |
241 | for (i = 0; i < numofd; i++) |
242 | { |
243 | struct ofd * const o = &outputfds[ofdlist[i]]; |
244 | if (o->fd >= 0 && FD_ISSET(o->fd, &wfd)((((&wfd)->fds_bits)[((o->fd) / (8 * (int) sizeof ( __fd_mask)))] & ((__fd_mask) 1 << ((o->fd) % (8 * (int) sizeof (__fd_mask))))) != 0)) |
245 | { |
246 | struct fdbuf * const f = o->firstbuf; |
247 | int written; |
248 | if (!o->isvalid && hasbecomevalid(ofdlist[i], o)) |
249 | o->isvalid = true1; |
250 | if (o->isvalid) |
251 | written = write(o->fd, f->buf + f->pos, f->len - f->pos); |
252 | else if (f->len - f->pos > 0) |
253 | written = 1; /* discard one byte while waiting for valid packet */ |
254 | else |
255 | written = 0; |
256 | if (written == -1) |
257 | { |
258 | fprintf(stderrstderr,"Error writing to fifo: %s\n",strerror(errno(*__errno_location ()))); |
259 | exit(1); |
260 | } /*if*/ |
261 | queuedlen -= written; |
262 | f->pos += written; |
263 | if (f->pos == f->len) |
264 | { |
265 | /* finished writing buffer at head of queue */ |
266 | o->firstbuf = f->next; |
267 | if (o->lastbufptr == &f->next) |
268 | o->lastbufptr = &o->firstbuf; |
269 | free(f); |
270 | } /*if*/ |
271 | o->len -= written; |
272 | } /*if*/ |
273 | } /*for*/ |
274 | if (FD_ISSET(STDIN_FILENO, &rfd)((((&rfd)->fds_bits)[((0) / (8 * (int) sizeof (__fd_mask )))] & ((__fd_mask) 1 << ((0) % (8 * (int) sizeof ( __fd_mask))))) != 0)) |
275 | return true1; |
276 | } /*if*/ |
277 | return false0; |
278 | } /*dowork*/ |
279 | |
280 | static void flushwork(void) |
281 | /* flushes the work queue. */ |
282 | { |
283 | closing = true1; |
284 | while (queuedlen) |
285 | dowork(false0); |
286 | } /*flushwork*/ |
287 | |
288 | static void forceread(void *ptr, int len, bool_Bool required) |
289 | /* reads the specified number of bytes from standard input, finishing processing |
290 | if EOF is reached. */ |
291 | { |
292 | int nrbytes; |
293 | while (!dowork(true1)) |
294 | /* flush output queues while waiting for more input */; |
295 | nrbytes = fread(ptr, 1, len, stdinstdin); |
296 | if (nrbytes != len) |
297 | { |
298 | bool_Bool success = true1; |
299 | if (nrbytes < 0) |
300 | { |
301 | fprintf(stderrstderr, "Error %d reading: %s\n", errno(*__errno_location ()), strerror(errno(*__errno_location ()))); |
302 | success = false0; |
303 | } |
304 | else if (nrbytes < len && required) |
305 | { |
306 | fprintf(stderrstderr, "Unexpected read EOF\n"); |
307 | success = false0; |
308 | } /*if*/ |
309 | flushwork(); |
310 | exit(success ? 0 : 1); |
311 | } /*if*/ |
312 | inputpos += len; |
313 | } /*forceread*/ |
314 | |
315 | static void writetostream(int stream, unsigned char *buf, int len) |
316 | /* queues more data to be written to the output file for the specified stream id, |
317 | if I am writing it. */ |
318 | { |
319 | struct ofd * const o = &outputfds[stream]; |
320 | if (o->fd == FD_CLOSED(-1)) /* not extracting this stream */ |
321 | return; |
322 | while (len > 0) |
323 | { |
324 | int thislen; |
325 | struct fdbuf *fb; |
326 | if (!o->lastbufptr[0]) |
327 | { |
328 | o->lastbufptr[0] = malloc(sizeof(struct fdbuf)); |
329 | o->lastbufptr[0]->pos = 0; |
330 | o->lastbufptr[0]->len = 0; |
331 | o->lastbufptr[0]->next = 0; |
332 | } /*if*/ |
333 | fb = o->lastbufptr[0]; |
334 | thislen = BUFLEN(65536) - fb->len; |
335 | if (!thislen) |
336 | { |
337 | o->lastbufptr = &fb->next; |
338 | continue; |
339 | } /*if*/ |
340 | if (thislen > len) |
341 | thislen = len; |
342 | o->len += thislen; |
343 | memcpy(fb->buf + fb->len, buf, thislen); |
344 | fb->len += thislen; |
345 | len -= thislen; |
346 | buf += thislen; |
347 | queuedlen += thislen; |
348 | } /*while*/ |
349 | } /*writetostream*/ |
350 | |
351 | static void process_packets |
352 | ( |
353 | void (*readinput)(void *ptr, int len, bool_Bool required), |
354 | bool_Bool recursed |
355 | ) |
356 | { |
357 | unsigned char hdr[4]; |
358 | unsigned char buf[200]; |
359 | bool_Bool fetchhdr = true1; |
360 | while (true1) |
361 | { |
362 | const int disppos = fetchhdr ? inputpos : inputpos - 4; /* where packet actually started */ |
363 | bool_Bool handled = true1; |
364 | int hdrid; |
365 | if (fetchhdr) |
366 | { |
367 | readinput(hdr, 4, false0); |
368 | } /*if*/ |
369 | fetchhdr = true1; /* initial assumption */ |
370 | hdrid = |
371 | hdr[0] << 24 |
372 | | |
373 | hdr[1] << 16 |
374 | | |
375 | hdr[2] << 8 |
376 | | |
377 | hdr[3]; |
378 | switch (hdrid) |
379 | { |
380 | // start codes: |
381 | case 0x100 + MPID_PICTURE: // picture header |
382 | readinput(buf, 4, true1); |
383 | if (outputenglish) |
384 | printf |
385 | ( |
386 | "%08x: picture hdr, frametype=%c, temporal=%d\n", |
387 | disppos, |
388 | frametype[buf[1] >> 3 & 7], |
389 | buf[0] << 2 | buf[1] >> 6 |
390 | ); |
391 | break; |
392 | |
393 | case 0x100 + MPID_SEQUENCE: // sequence header |
394 | readinput(buf, 8, true1); |
395 | if (outputenglish) |
396 | printf |
397 | ( |
398 | "%08x: sequence hdr: %dx%d, a/f:%02x, bitrate=%d\n", |
399 | disppos, |
400 | buf[0] << 4 | buf[1] >> 4, |
401 | buf[1] << 8 & 0xf00 | buf[2], |
402 | buf[3], |
403 | buf[4] << 10 | buf[5] << 2 | buf[6] >> 6 |
404 | ); |
405 | if (buf[7] & 2) |
406 | readinput(buf + 8, 64, true1); |
407 | if (buf[7] & 1) |
408 | readinput(buf + 8, 64, true1); |
409 | break; |
410 | |
411 | case 0x100 + MPID_EXTENSION: // extension header |
412 | readinput(buf, 1, true1); |
413 | switch (buf[0] >> 4) |
414 | { |
415 | case 1: |
416 | if (outputenglish) |
417 | printf("%08x: sequence extension hdr\n", disppos); |
418 | readinput(buf + 1, 5, true1); |
419 | break; |
420 | case 2: |
421 | if (outputenglish) |
422 | printf("%08x: sequence display extension hdr\n", disppos); |
423 | readinput(buf + 1, (buf[0] & 1) ? 7 : 3, true1); |
424 | break; |
425 | case 7: |
426 | if (outputenglish) |
427 | printf("%08x: picture display extension hdr\n", disppos); |
428 | break; |
429 | case 8: |
430 | readinput(buf + 1, 4, true1); |
431 | if (buf[4] & 64) |
432 | readinput(buf + 5, 2, true1); |
433 | if (outputenglish) |
434 | { |
435 | printf |
436 | ( |
437 | "%08x: picture coding extension hdr%s%s\n", |
438 | disppos, |
439 | (buf[3] & 0x80) ? ", top" : ", bottom", |
440 | (buf[3] & 2) ? ", repeat" : "" |
441 | ); |
442 | } /*if*/ |
443 | break; |
444 | default: |
445 | if (outputenglish) |
446 | printf("%08x: extension hdr %x\n", disppos, buf[0] >> 4); |
447 | break; |
448 | } /*switch*/ |
449 | break; |
450 | |
451 | case 0x100 + MPID_SEQUENCE_END: // end of sequence |
452 | if (outputenglish) |
453 | printf("%08x: end of sequence\n", disppos); |
454 | break; |
455 | |
456 | case 0x100 + MPID_GOP: // group of pictures |
457 | readinput(buf, 4, true1); |
458 | if (outputenglish) |
459 | { |
460 | printf |
461 | ( |
462 | "%08x: GOP: %s%d:%02d:%02d.%02d, %s%s\n", |
463 | disppos, |
464 | buf[0] & 128 ? "drop, " : "", |
465 | buf[0] >> 2 & 31, |
466 | (buf[0] << 4 | buf[1] >> 4) & 63, |
467 | (buf[1] << 3 | buf[2] >> 5) & 63, |
468 | (buf[2] << 1 | buf[3] >> 7) & 63, |
469 | buf[3] & 64 ? "closed" : "open", |
470 | buf[3] & 32 ? ", broken" : "" |
471 | ); |
472 | } /*if*/ |
473 | break; |
474 | |
475 | case 0x100 + MPID_PROGRAM_END: // end of program stream |
476 | if (outputenglish) |
477 | printf("%08x: end of program stream\n", disppos); |
478 | break; |
479 | |
480 | case 0x100 + MPID_PACK: // mpeg_pack_header |
481 | { |
482 | uint32_t scr,scrhi,scrext; |
483 | int64_t fulltime; |
484 | bool_Bool mpeg2 = true1; |
485 | readinput(buf, 8, true1); |
486 | if ((buf[0] & 0xC0) == 0x40) |
487 | { |
488 | readinput(buf + 8, 2, true1); |
489 | scrhi = (buf[0] & 0x20) >> 5; |
490 | scr = |
491 | (buf[0] & 0x18) << 27 |
492 | | |
493 | (buf[0] & 3) << 28 |
494 | | |
495 | buf[1] << 20 |
496 | | |
497 | (buf[2] & 0xf8) << 12 |
498 | | |
499 | (buf[2] & 3) << 13 |
500 | | |
501 | buf[3] << 5 |
502 | | |
503 | (buf[4] & 0xf8) >> 3; |
504 | scrext = |
505 | (buf[4] & 3) << 7 |
506 | | |
507 | buf[5] >> 1; |
508 | if (scrext >= 300 && outputenglish) |
509 | { |
510 | printf("WARN: scrext in pack hdr > 300: %u\n", scrext); |
511 | } /*if*/ |
512 | fulltime = (int64_t)scrhi << 32 | (int64_t)scr; |
513 | fulltime *= 300; |
514 | fulltime += scrext; |
515 | mpeg2 = true1; |
516 | } |
517 | else if ((buf[0] & 0xF0) == 0x20) |
518 | { |
519 | mpeg2 = false0; |
520 | fulltime = readpts(buf); |
521 | fulltime *= 300; |
522 | } |
523 | else |
524 | { |
525 | if (outputenglish) |
526 | printf("WARN: unknown pack header version\n"); |
527 | fulltime = 0; |
528 | } /*if*/ |
529 | if (outputenglish) |
530 | printf |
531 | ( |
532 | "%08x: mpeg%c pack hdr, %" PRId64"l" "d" ".%03" PRId64"l" "d" " sec\n", |
533 | disppos, |
534 | mpeg2 ? '2' : '1', |
535 | fulltime / SCRTIME27000000, |
536 | (fulltime % SCRTIME27000000) / (SCRTIME27000000 / 1000) |
537 | ); |
538 | } |
539 | break; |
540 | default: |
541 | handled = false0; |
542 | break; |
543 | } /*switch*/ |
544 | if |
545 | ( |
546 | !handled |
547 | && |
548 | !recursed |
549 | && |
550 | ( |
551 | hdrid == 0x100 + MPID_SYSTEM |
552 | || |
553 | hdrid == 0x100 + MPID_PRIVATE1 |
554 | || |
555 | hdrid == 0x100 + MPID_PAD |
556 | || |
557 | hdrid == 0x100 + MPID_PRIVATE2 |
558 | || |
559 | hdrid >= 0x100 + MPID_AUDIO_FIRST && hdrid <= 0x100 + MPID_AUDIO_LAST |
560 | || |
561 | hdrid >= 0x100 + MPID_VIDEO_FIRST && hdrid <= 0x100 + MPID_VIDEO_LAST |
562 | ) |
563 | ) |
564 | { |
565 | bool_Bool has_extension = false0; |
566 | unsigned int headerlen, packetlen, contentoffs; |
567 | int readlen; |
568 | bool_Bool dowrite = !recursed; |
569 | const int packetid = hdrid & 255; |
570 | if (outputenglish) |
571 | printf("%08x: ", disppos); |
572 | if (packetid == MPID_SYSTEM) |
573 | { |
574 | if (outputenglish) |
575 | printf("system header"); |
576 | } |
577 | else if (packetid == MPID_PRIVATE1) |
578 | { |
579 | if (outputenglish) |
580 | printf("pes private1"); |
581 | has_extension = true1; |
582 | } |
583 | else if (packetid == MPID_PAD) |
584 | { |
585 | if (outputenglish) |
586 | printf("pes padding"); |
587 | } |
588 | else if (packetid == MPID_PRIVATE2) |
589 | { |
590 | if (outputenglish) |
591 | printf("pes private2"); |
592 | } |
593 | else if (packetid >= MPID_AUDIO_FIRST && packetid <= MPID_AUDIO_LAST) |
594 | { |
595 | if (outputenglish) |
596 | printf("pes audio %d", packetid - MPID_AUDIO_FIRST); |
597 | if (audiodrop) |
598 | { |
599 | dowrite = false0; |
600 | audiodrop--; |
601 | } /*if*/ |
602 | has_extension = true1; |
603 | } |
604 | else if (packetid >= MPID_VIDEO_FIRST && packetid <= MPID_VIDEO_LAST) |
605 | { |
606 | if (outputenglish) |
607 | printf("pes video %d", packetid - MPID_VIDEO_FIRST); |
608 | has_extension = true1; |
609 | } /*if*/ |
610 | readinput(buf, 2, true1); // pes packet length |
611 | packetlen = buf[0] << 8 | buf[1]; |
612 | readlen = packetlen > sizeof buf ? sizeof buf : packetlen; |
613 | readinput(buf, readlen, true1); |
614 | packetlen -= readlen; |
615 | headerlen = buf[2]; /* length of packet header */ |
616 | contentoffs = 3 + headerlen; /* beginning of packet content */ |
617 | if (outputenglish) |
618 | { |
619 | if (packetid == MPID_PRIVATE1) // private stream 1 |
620 | { |
621 | const int sid = buf[contentoffs]; /* substream ID is first byte after header */ |
622 | switch (sid & 0xf8) |
623 | { |
624 | case 0x20: |
625 | case 0x28: |
626 | case 0x30: |
627 | case 0x38: |
628 | printf(", subpicture %d", sid & 0x1f); |
629 | break; |
630 | case 0x80: |
631 | printf(", AC3 audio %d", sid & 7); |
632 | break; |
633 | case 0x88: |
634 | printf(", DTS audio %d", sid & 7); |
635 | case 0xa0: |
636 | printf(", LPCM audio %d", sid & 7); |
637 | break; |
638 | default: |
639 | printf(", substream id 0x%02x", sid); |
640 | break; |
641 | } /*switch*/ |
642 | } |
643 | else if (packetid == MPID_PRIVATE2) // private stream 2 |
644 | { |
645 | const int sid = buf[0]; |
646 | switch (sid) |
647 | { |
648 | case 0: |
649 | printf(", PCI"); |
650 | break; |
651 | case 1: |
652 | printf(", DSI"); |
653 | break; |
654 | default: |
655 | printf(", substream id 0x%02x", sid); |
656 | break; |
657 | } /*switch*/ |
658 | } /*if*/ |
659 | printf("; length=%d", packetlen + readlen); |
660 | if (has_extension) |
661 | { |
662 | int eptr; |
663 | bool_Bool has_std = false0, has_pts, has_dts; |
664 | int hdroffs, std=0, std_scale=0; |
665 | const bool_Bool mpeg2 = (buf[0] & 0xC0) == 0x80; |
666 | if (mpeg2) |
667 | { |
668 | hdroffs = contentoffs; |
669 | eptr = 3; |
670 | has_pts = (buf[1] & 128) != 0; |
671 | has_dts = (buf[1] & 64) != 0; |
672 | } |
673 | else |
674 | { |
675 | hdroffs = 0; |
676 | while (buf[hdroffs] == 0xff && hdroffs < sizeof(buf)) |
677 | hdroffs++; |
678 | if ((buf[hdroffs] & 0xC0) == 0x40) |
679 | { |
680 | has_std = true1; |
681 | std_scale = (buf[hdroffs] & 32) ? 1024 : 128; |
682 | std = ((buf[hdroffs] & 31) * 256 + buf[hdroffs + 1]) * std_scale; |
683 | hdroffs += 2; |
684 | } /*if*/ |
685 | eptr = hdroffs; |
686 | has_pts = (buf[hdroffs] & 0xE0) == 0x20; |
687 | has_dts = (buf[hdroffs] & 0xF0) == 0x30; |
688 | } /*if*/ |
689 | printf("; hdr=%d", hdroffs); |
690 | if (has_pts) |
691 | { |
692 | int64_t pts; |
693 | pts = readpts(buf + eptr); |
694 | eptr += 5; |
695 | printf |
696 | ( |
697 | "; pts %" PRId64"l" "d" ".%03" PRId64"l" "d" " sec", |
698 | pts / PTSTIME90000, |
699 | (pts % PTSTIME90000) / (PTSTIME90000 / 1000) |
700 | ); |
701 | } /*if*/ |
702 | if (has_dts) |
703 | { |
704 | int64_t dts; |
705 | dts = readpts(buf + eptr); |
706 | eptr += 5; |
707 | printf |
708 | ( |
709 | "; dts %" PRId64"l" "d" ".%03" PRId64"l" "d" " sec", |
710 | dts / PTSTIME90000, |
711 | (dts % PTSTIME90000) / (PTSTIME90000 / 1000) |
712 | ); |
713 | } /*if*/ |
714 | if (mpeg2) |
715 | { |
716 | if (buf[1] & 32) |
717 | { |
718 | printf("; escr"); |
719 | eptr += 6; |
720 | } /*if*/ |
721 | if (buf[1] & 16) |
722 | { |
723 | printf("; es"); |
724 | eptr += 2; |
725 | } /*if*/ |
726 | if (buf[1] & 4) |
727 | { |
728 | printf("; ci"); |
729 | eptr++; |
730 | } /*if*/ |
731 | if (buf[1] & 2) |
732 | { |
733 | printf("; crc"); |
734 | eptr += 2; |
735 | } /*if*/ |
736 | if (buf[1] & 1) |
737 | { |
738 | int pef = buf[eptr]; |
739 | eptr++; |
740 | printf("; (pext)"); |
741 | if (pef & 128) |
742 | { |
743 | printf("; user"); |
744 | eptr += 16; |
745 | } /*if*/ |
746 | if (pef & 64) |
747 | { |
748 | printf("; pack"); |
749 | eptr++; |
750 | } /*if*/ |
751 | if (pef & 32) |
752 | { |
753 | printf("; ppscf"); |
754 | eptr += 2; |
755 | } /*if*/ |
756 | if (pef & 16) |
757 | { |
758 | std_scale = (buf[eptr] & 32) ? 1024 : 128; |
759 | printf |
760 | ( |
761 | "; pstd=%d (scale=%d)", |
762 | ((buf[eptr] & 31) * 256 + buf[eptr + 1]) * std_scale, |
763 | std_scale |
764 | ); |
765 | eptr += 2; |
Value stored to 'eptr' is never read | |
766 | } /*if*/ |
767 | if (pef & 1) |
768 | { |
769 | printf("; (pext2)"); |
770 | /* eptr += 2; */ /* not further used */ |
771 | } /*if*/ |
772 | } /*if*/ |
773 | } |
774 | else |
775 | { |
776 | if (has_std) |
777 | printf("; pstd=%d (scale=%d)", std, std_scale); |
778 | } /*if*/ |
779 | } /*if*/ |
780 | printf("\n"); |
781 | } /*if*/ |
782 | if (outputmplex && has_extension) |
783 | { |
784 | if ((buf[1] & 128) != 0 && firstpts[packetid] == -1) |
785 | firstpts[packetid] = readpts(buf + 3); |
786 | if (firstpts[MPID_AUDIO_FIRST] != -1 && firstpts[MPID_VIDEO_FIRST] != -1) |
787 | { |
788 | printf("%d\n", firstpts[MPID_VIDEO_FIRST] - firstpts[MPID_AUDIO_FIRST]); |
789 | fflush(stdoutstdout); |
790 | close(1); |
791 | outputmplex = false0; |
792 | if (!numofd) |
793 | exit(0); |
794 | } /*if*/ |
795 | } /*if*/ |
796 | #ifdef SHOWDATA |
797 | if (has_extension && outputenglish) |
798 | { |
799 | int j; |
800 | printf(" "); |
801 | for (j=0; j<16; j++) |
802 | printf(" %02x", buf[j + contentoffs]); |
803 | printf("\n"); |
804 | } /*if*/ |
805 | #endif |
806 | if (!recursed) |
807 | { |
808 | if (has_extension && dowrite) |
809 | { |
810 | writetostream(packetid, buf + contentoffs, readlen - contentoffs); |
811 | } /*if*/ |
812 | #if defined(HAVE_NESTED_ROUTINES) |
813 | if (outputenglish && packetid >= MPID_VIDEO_FIRST && packetid <= MPID_VIDEO_LAST) |
814 | { |
815 | /* look inside PES packet to report on details of video packets */ |
816 | unsigned int remaining = readlen; |
817 | jmp_buf resume; |
818 | /* GCC extension! nested routine */ |
819 | void bufread(void *ptr, int len, bool_Bool required) |
820 | { |
821 | const unsigned int tocopy = remaining > len ? len : remaining; |
822 | if (tocopy != 0) |
823 | { |
824 | memcpy(ptr, buf + contentoffs, tocopy); |
825 | ptr = (unsigned char *)ptr + tocopy; |
826 | len -= tocopy; |
827 | contentoffs += tocopy; |
828 | remaining -= tocopy; |
829 | inputpos += tocopy; |
830 | } /*if*/ |
831 | if (len != 0) |
832 | { |
833 | /* read more of packet */ |
834 | const unsigned int toread = packetlen < len ? packetlen : len; |
835 | readinput(ptr, toread, required); |
836 | if (dowrite) |
837 | { |
838 | writetostream(packetid, ptr, toread); |
839 | } /*if*/ |
840 | packetlen -= toread; |
841 | len -= toread; |
842 | if (len != 0) |
843 | { |
844 | if (false0 /*required*/) |
845 | { |
846 | fprintf(stderrstderr, "Unexpected nested read EOF\n"); |
847 | } /*if*/ |
848 | longjmp(resume, 1); |
849 | } /*if*/ |
850 | } /*if*/ |
851 | } /*bufread*/ |
852 | inputpos -= remaining; /* rewind to start of packet content */ |
853 | if (!setjmp(resume)_setjmp (resume)) |
854 | { |
855 | process_packets(bufread, true1); |
856 | } /*if*/ |
857 | } |
858 | else |
859 | #endif |
860 | { |
861 | while (packetlen != 0) |
862 | { |
863 | readlen = packetlen > sizeof buf ? sizeof(buf) : packetlen; |
864 | readinput(buf, readlen, true1); |
865 | if (dowrite) |
866 | { |
867 | writetostream(packetid, buf, readlen); |
868 | } /*if*/ |
869 | packetlen -= readlen; |
870 | } /*while*/ |
871 | } /*if*/ |
872 | } /*if*/ |
873 | handled = true1; |
874 | } /*if*/ |
875 | if (!handled) |
876 | { |
877 | do |
878 | { |
879 | if (!recursed && outputenglish && !nounknown) |
880 | printf("%08x: unknown hdr: %08x\n", disppos, hdrid); |
881 | hdr[0] = hdr[1]; |
882 | hdr[1] = hdr[2]; |
883 | hdr[2] = hdr[3]; |
884 | readinput(hdr + 3, 1, false0); |
885 | hdrid = |
886 | hdr[0] << 24 |
887 | | |
888 | hdr[1] << 16 |
889 | | |
890 | hdr[2] << 8 |
891 | | |
892 | hdr[3]; |
893 | } |
894 | while ((hdrid & 0xffffff00) != 0x100); |
895 | fetchhdr = false0; /* already got it */ |
896 | } /*if*/ |
897 | } /*while*/ |
898 | } /*process_packets*/ |
899 | |
900 | int main(int argc,char **argv) |
901 | { |
902 | bool_Bool skiptohdr = false0; |
903 | fputs(PACKAGE_HEADER("mpeg2desc")"DVDAuthor" "::" "mpeg2desc" ", version " "0.7.1+" ".\nBuild options:" " gnugetopt" " graphicsmagick" " iconv" " freetype" " fribidi" " fontconfig" "\nSend bug reports to <" "dvdauthor-users@lists.sourceforge.net" ">\n\n", stderrstderr); |
904 | { |
905 | int outputstream = 0, oc, i; |
906 | for (oc = 0; oc < 256; oc++) |
907 | outputfds[oc].fd = FD_CLOSED(-1); |
908 | while (-1 != (oc = getopt(argc,argv,"ha:v:o:msd:u"))) |
909 | { |
910 | switch (oc) |
911 | { |
912 | case 'd': |
913 | audiodrop = strtounsigned(optarg, "audio drop count"); |
914 | break; |
915 | case 'a': |
916 | case 'v': |
917 | if (outputstream) |
918 | { |
919 | fprintf(stderrstderr,"can only output one stream to stdout at a time\n; use -o to output more than\none stream\n"); |
920 | exit(1); |
921 | } /*if*/ |
922 | outputstream = (oc == 'a' ? MPID_AUDIO_FIRST : MPID_VIDEO_FIRST) + strtounsigned(optarg, "stream id"); |
923 | break; |
924 | case 'm': |
925 | outputmplex = true1; |
926 | break; |
927 | case 's': |
928 | skiptohdr = true1; |
929 | break; |
930 | case 'o': |
931 | if (!outputstream) |
932 | { |
933 | fprintf(stderrstderr,"no stream selected for '%s'\n",optarg); |
934 | exit(1); |
935 | } /*if*/ |
936 | outputfds[outputstream].fd = FD_TOOPEN(-2); |
937 | outputfds[outputstream].fname = optarg; |
938 | outputstream = 0; |
939 | break; |
940 | case 'u': |
941 | nounknown = true1; |
942 | break; |
943 | // case 'h': |
944 | default: |
945 | fprintf(stderrstderr, |
946 | "usage: mpeg2desc [options] < movie.mpg\n" |
947 | "\t-a #: output audio stream # to stdout\n" |
948 | "\t-v #: output video stream # to stdout\n" |
949 | "\t-o FILE: output previous stream to FILE instead of stdout\n" |
950 | "\t-s: skip to first valid header -- ensures mplex can handle output\n" |
951 | "\t-m: output mplex offset to stdout\n" |
952 | "\t-u: ignore unknown hdrs\n" |
953 | "\t-h: help\n" |
954 | ); |
955 | exit(1); |
956 | break; |
957 | } /*switch*/ |
958 | } /*while*/ |
959 | if (outputstream) |
960 | { |
961 | outputenglish = false0; |
962 | outputfds[outputstream].fd = STDOUT_FILENO1; |
963 | } /*if*/ |
964 | if (outputmplex) |
965 | { |
966 | if (!outputenglish) |
967 | { |
968 | fprintf(stderrstderr,"Cannot output a stream and the mplex offset at the same time\n"); |
969 | exit(1); |
970 | } /*if*/ |
971 | outputenglish = false0; |
972 | } /*if*/ |
973 | numofd = 0; |
974 | for (oc = 0; oc < MAX_FILES256; oc++) |
975 | if (outputfds[oc].fd != -1) |
976 | { |
977 | ofdlist[numofd++] = oc; |
978 | outputfds[oc].firstbuf = 0; |
979 | outputfds[oc].lastbufptr = &outputfds[oc].firstbuf; |
980 | outputfds[oc].len = 0; |
981 | outputfds[oc].isvalid = !skiptohdr; |
982 | } /*if; for*/ |
983 | FD_ZERO(&rfd)do { int __d0, __d1; __asm__ __volatile__ ("cld; rep; " "stosq" : "=c" (__d0), "=D" (__d1) : "a" (0), "0" (sizeof (fd_set) / sizeof (__fd_mask)), "1" (&((&rfd)->fds_bits)[0]) : "memory"); } while (0); |
984 | FD_ZERO(&wfd)do { int __d0, __d1; __asm__ __volatile__ ("cld; rep; " "stosq" : "=c" (__d0), "=D" (__d1) : "a" (0), "0" (sizeof (fd_set) / sizeof (__fd_mask)), "1" (&((&wfd)->fds_bits)[0]) : "memory"); } while (0); |
985 | for (i = 0; i < 256; i++) |
986 | { |
987 | firstpts[i] = -1; |
988 | } /*for*/ |
989 | } |
990 | process_packets(forceread, false0); |
991 | } /*main*/ |