Set the cut path properly when a non-default output path is specified
[atscap.git] / atscut.c
blobbc1e1443c959baff449d965df2f8b051a06ce12c
1 #define NAME "atscut"
2 #define AUTHOR "inkling"
3 #define EMAIL "inkling@users.sourceforge.net"
4 #define WEBPAGE "http://atscap.sourceforge.net"
5 #define COPYRIGHT "Copyright (C) 2004-2008"
6 #define LICENSE "GNU General Public License Version 2"
7 #define LASTEDIT "20080101"
8 #define VERSION "1.1.7"
10 #warning README is first 180 lines of this file
12 * atscut.c (c) Copyright 2004-2008 by inkling@users.sourceforge.net
13 * ATSC Transport Stream dumper/cutter utility.
14 * The Sledge-O-Matic for ATSC (apologies to Gallagher)
16 * atscut is free software; you may only redistribute it and/or modify
17 * it under the terms of the GNU General Public License, Version 2 or later,
18 * as published by the Free Software Foundation.
20 * atscut is distributed to you in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License Version 2
26 * along with this program; if not, write the Free Software Foundation, Inc.,
27 * at 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
32 ATSCut.c version 1.1.7
33 January 1, 2008
34 ATSC Transport Stream Container Utility
35 Copyright (c) 2004-2008 by inkling@users.sourceforge.net
39 Goals:
40 Show all the details in a Transport Stream sent over ATSC broadcast.
41 Cut a single VC capture using a simple X visual editor interface.
42 Extract PIDs by number or grouping.
46 * Corporations or individuals who wish to use any part of this program with
47 * their product(s), but do not wish to be bound by the GPL, must contact
48 * the author to arrange suitable licensing for your product(s).
52 * Compile with (when xtscut is included):
54 * gcc -Wall -O3 -lrt -lImlib -lmpeg2 -lmpeg2convert -lX11 \
55 * (optional) -L/usr/lib/X11R6 or -L/usr/X11R6/lib \
56 * -o atscut atscut.c
58 * Dependencies:
59 * librt real time clock for timing file i/o
60 * libImlib ImageMagick package handles X images
61 * tested with version 1.9.14
62 * libmpeg2 mpeg2dec package
63 * libmpeg2convert mpeg2dec package
64 * tested with version 0.4.0b
65 * libX11 Xlib generic interface
70 /* HELP!
71 atscut -h
74 /* TODO:
75 Provide extract function for copy/paste of PDF A/65 Huffman:
76 It's possible the Huffman tables may change some day and may
77 need a way to regenerate the table from the new specification.
79 BUG:
80 KHCW has the TUBE on program 4, but PAT has 4,3 order instead of
81 3,4 order. atscap doesn't cap it, and atscut crashes on the stream
82 PAT/VCT abstraction is supposed to handle this gracefully.
85 /* CREDITS:
86 The CRC32 table and routine are from ffmpeg.
87 The Huffman decode tables are from the A/65b spec, reformatted.
88 The MPEG2 display code is modified from mpeg2dec sample2.c
93 MODIFICATION HISTORY:
94 // initial version, not much more than head/tail/cut with different cli
95 0.1 Mar-01-2004, first cutter, used integers, wasn't very precise.
96 Was actually more irritating than useful.
98 // finally had a chance to get back to working on this again
99 // sync and cuts added, tweaked to work during capture
100 0.2 Jan-12-2005, works with floats to find cut point
101 0.2.1 Jan-15-2005, new try at find sync code added
102 0.2.2 Jan-20-2005, multiple cuts from command line
103 0.2.3 Jan-21-2005, xine time adjusts, works for full cap only
104 0.3 Feb-08-2005, duty cycle allows concurrent pchdtvr cap, -d95
105 0.3.1 Feb-10-2005, tweaking sync code to find the right trick
106 0.4 Feb-16-2005, more command line options -p -t -r
107 0.4.1 Feb-17-2005, fixed sync, skip offset bytes, works! simple! doh!
109 // ATSC dump for some tables
110 0.5 Feb-18-2005, initial ATSC traffic director
111 0.5.1 Feb-19-2005, added STT
112 0.5.2 Feb-20-2005, added CRC32
113 0.5.3 Feb-24-2005, added VCT single packet parse
114 0.5.4 Feb-28-2005, added MGT single packet parse
115 0.5.5 Mar-01-2005, added EIT multi-packet parse
116 0.5.6 Mar-02-2005, added ETT multi-packet parse
117 0.5.7 Mar-03-2005, added MGT multi-packet parse
118 0.5.8 Mar-04-2005, added guide dump at end, working code to pchdtvr
119 0.5.9 Apr-12-2005, added multiple -k options to extract PIDs as PES
121 // MPEG2 dump for some tables
122 0.6 Apr-20-2005, added mpeg2 PAT CAT PMT and few descriptors
123 0.6.1 Apr-30-2005, added more descriptors for PMT, -v macros
124 0.6.2 May-03-2005, added test mpeg2 video, build video payload
125 0.6.3 May-04-2005, added mpeg2 video start code dump
126 0.6.4 May-05-2005, added test seq end cut function, fixed -d default
127 0.6.5 May-08-2005, added more mpeg2 video header dump
128 0.6.6 May-13-2005, changed EIT reserved bits not set? cni chk only
129 0.6.7 May-14-2005, all packet counters in pkt struct. better stats.
130 0.6.8 May-17-2005, changed mss display to show mode too
131 0.6.9 May-20-2005, added VCT multi-packet parse, KPXB has BIG VCT!
133 // final table parse and other finishing touches
134 0.7.0 May-24-2005, added parse EIT descriptors
135 0.7.1 May-31-2005, added -u option, changed -r -s -t
136 0.7.2 Jun-02-2005, added -e option, re-arrange parse mpeg, bugfixes
137 0.7.3 Jun-08-2005, fixed PAT and PMT to always keep if -k mgt
138 0.7.4 Jun-12-2005, added Huffman decode tables and decoder
139 0.7.5 Jun-14-2005, ignores mss mode for KPXB broken Huffman :/
140 0.7.6 Jun-16-2005, GOP parsed
141 0.7.7 Jun-17-2005, -y option, i frame rate calc
142 0.7.8 Jun-18-2005, -a -m options for detail control, bad ATSC CRC
143 0.7.9 Jun-21-2005, forgot r += rdl after test eit ca mss
145 // touch-ups to the paint
146 0.8.0 Jul-13-2005, gcc 2.96 says *t++ wrong in huffman; -s -t tested
147 0.8.1 Aug-03-2005, -z PID rip video ES. but loses the PCR data
148 0.8.2 Aug-04-2005, add video PES header parse PTS DTS; fix sync align
150 // trying to make an auto-cutter to cut at every black frame
151 0.9.0 Nov-08-2005, sequence header scan with -i
152 0.9.1 Nov-17-2005, sync removed, block size 188 for better cuts
153 0.9.2 Nov-20-2005, -i cuts at sequence before low B frame
154 0.9.3 Nov-25-2005, more stringent PMT PID lookup for audio video
155 0.9.4 Dec-01-2005, -i It:Pt:Bt threshold cuts via low IPB frame
156 0.9.5 Dec-04-2005, -i load/save frames+sequences speeds up next -i
157 0.9.6 Dec-05-2005, changes exported to pchdtvr to match .tsf .tss
158 0.9.7 Dec-06-2005, -w for -i no cut write, but does gen .tsf .tss
160 // gave up on auto-cutter for new xtscut idea. xtscut is much easier.
161 0.9.8 Jan-10-2006, imported xtscut
162 Jan-18-2006, backed out xtscut, not ready yet
163 Jan-19-2006, FILE_?MODE FILE_PERMS for norm
164 Feb-21-2006, posted to nop.org, hope it isn't broken
165 Feb-25-2006, add buffered i/o from xtscut
166 Mar-06-2006, removed obsoleted cut methods & scale options;
167 Mar-07-2006, tested -kX -kmgt to make sure unbroken;
168 Mar-14-2006, cc error breakdown by PID
169 Mar-15-2006, tupari reported WPIX huffman crash, added sanity
170 Apr-28-2006, -o output name override requested by users
171 May-02-2006, -e extracts specific program,audio from full cap
173 0.9.9 Jun-13-2006 -r to replace program association table from file
175 testing and bug shakedown to 1.0.0
177 1.0.0 Jul-01-2006, performance changes (these hold down -m8 output):
178 -s outputs single tsx file for xtscut,
179 -s does not process video packets after PSI1,
180 -q does not process video packets at all?
181 -s is about 4x faster now, more if fully cached
182 Jul-06-2006, cleaned up MGT display a little bit
183 Jul-07-2006, added more STT info to see if dst bits work.
185 1.0.1 Sep-04-2006, reduce gcc pre-processor million item frames list.
186 added calloc and free code.
187 Sep-05-2006, replaced frame_idx index wrap with limit check.
188 two hour wrap was breaking .tsx for large caps
190 1.0.2 Sep-17-2006, -q reduces output to table version changes only
191 NOTE: This causes problems with missing data
192 because rest of packet processing is skipped
193 1.0.3 Sep-18-2006, test pmt can handle 2 packet pmt now
194 1.0.4 Sep-19-2006, test pmt using pmt[] instead of pmt.
195 1.0.5 Sep-20-2006, test pmt did not get section length correct
196 1.0.6 Sep-30-2006, test eit did not show MPEG program number
197 1.0.7 Nov-06-2006, changes for -g: sort and dup removal
198 1.0.8 Dec-12-2006, show bytecount on I frame slice checklist.
199 mpeg payload 128K, fits in CPU cache, faster
200 1.0.9 Jan-12-2007, -q fixups for system() call from xtscut
201 1.1.0 Feb-02-2007, mpeg video payload size is a little bit larger
203 1.1.1 Jul-02-2007, -a8 -g -q holds down output if no ETMID match
204 1.1.2 Aug-17-2007, -n -N -o handling for nulls and output
205 1.1.3 Aug-24-2007, test eit incomplete desc parse; [_rr]_mss bugs
206 1.1.4 Nov-20-2007, disabled -y -z due to lack of use
207 1.1.5 Nov-27-2007, added USE_LIBRT define for clock gettime
208 1.1.6 Dec-05-2007, fix -y ES extract for mpeg2dec and xtscut test
209 1.1.7 Dec-13-2007, use common.h header for code sharing
213 TODO:
215 Put xtscut in, with -X option to use it. Could make it conditional
216 compile so atscut can be used to generate .tsf + .tss without Xlib.
218 Fix -m8 Quantizer Table parse. It's off by a bit or two.
221 /////////////////////////////// definitions ////////////////////////////////
223 #define USE_ES_EXTRACT
224 #define WHO (char *) __FUNCTION__
226 // #warning using _GNU_SOURCE _FILE_OFFSET_BITS 64
227 #define GNULINUX
228 #define _FILE_OFFSET_BITS 64
229 #define _GNU_SOURCE
231 #define FILE_RMODE O_RDONLY
232 #define FILE_WMODE O_CREAT | O_TRUNC | O_RDWR
233 /* umask 022 makes this 0644 */
234 #define FILE_PERMS 0666
236 #define RD_MODE O_RDONLY
237 // | O_DIRECT broken?
239 #include <features.h>
241 #ifdef USE_PLATFORM_H
242 #ifndef PLATFORM_NAME
243 #include <platform.h>
244 #endif
245 #endif
247 #ifndef PLATFORM_NAME
248 #define PLATFORM_NAME "Linux"
249 #endif
251 #include <stdio.h>
252 #include <stdlib.h>
253 #include <unistd.h>
254 #include <sys/types.h>
255 #include <sys/stat.h>
256 #include <fcntl.h>
257 #include <string.h>
258 #include <time.h>
261 /* 16 VC * 128 EIT * 8 EVENTS PER EIT, 16384 events possible in 8 VCs */
262 /* use 16 vct's for cable. inefficient memory use is ok */
263 #define VCZ 16
264 #define PEZ 8
265 #define EIZ 128
266 #define PGZ (VCZ * EIZ * PEZ)
268 // name limit
269 #define PNZ 512
270 // desc limit
271 #define PDZ 512
273 // transport stream packet size
274 #define TSPZ 188
275 // 21 packets is almost 4k
276 #define TSBUFZ (21 * TSPZ)
278 // sync byte value (not always unique in the stream)
279 #define SYNC 0x47
280 // sequence header start code (should be unique in the stream)
281 #define SEQ 0x000001B3
283 /* -v bit 4 (16 value) is used to turn on display of START NO packets */
284 #define dprintf8 if (0 != (arg_verbose & 128)) fprintf
285 #define dprintf7 if (0 != (arg_verbose & 64)) fprintf
286 #define dprintf6 if (0 != (arg_verbose & 32)) fprintf
287 #define dprintf5 if (0 != (arg_verbose & 16)) fprintf
288 #define dprintf4 if (0 != (arg_verbose & 8)) fprintf
289 #define dprintf3 if (0 != (arg_verbose & 4)) fprintf
290 #define dprintf2 if (0 != (arg_verbose & 2)) fprintf
291 #define dprintf1 if (0 != (arg_verbose & 1)) fprintf
293 // atsc detail control bits
294 #define aprintf8 if (0 != (arg_adump & 128)) fprintf
295 #define aprintf7 if (0 != (arg_adump & 64)) fprintf
296 #define aprintf6 if (0 != (arg_adump & 32)) fprintf
297 #define aprintf5 if (0 != (arg_adump & 16)) fprintf
298 #define aprintf4 if (0 != (arg_adump & 8)) fprintf
299 #define aprintf3 if (0 != (arg_adump & 4)) fprintf
300 #define aprintf2 if (0 != (arg_adump & 2)) fprintf
301 #define aprintf1 if (0 != (arg_adump & 1)) fprintf
302 #define aprintf0 if (0 != arg_adump ) fprintf
304 // mpeg detail control bits
305 #define mprintf9 if (0 != (arg_mdump & 256)) fprintf
306 #define mprintf8 if (0 != (arg_mdump & 128)) fprintf
307 #define mprintf7 if (0 != (arg_mdump & 64)) fprintf
308 #define mprintf6 if (0 != (arg_mdump & 32)) fprintf
309 #define mprintf5 if (0 != (arg_mdump & 16)) fprintf
310 #define mprintf4 if (0 != (arg_mdump & 8)) fprintf
311 #define mprintf3 if (0 != (arg_mdump & 4)) fprintf
312 #define mprintf2 if (0 != (arg_mdump & 2)) fprintf
313 #define mprintf1 if (0 != (arg_mdump & 1)) fprintf
314 #define mprintf0 if (0 != arg_mdump ) fprintf
316 // how many unix seconds between jan 1, 1970 and jan 6, 1980
317 #define ATSC_UNIX_TIME 315986400
319 // some slight amount of cursor control for progress indicator via pcr
320 // pcr is a bad choice for progress indicator, especially for full stream
321 #define CR "\015"
322 #define LF "\012"
323 #define CEL "\033[K"
325 /////////////////////////////// globals ///////////////////////////////////
326 static unsigned char *usage =
327 "\nUsage:\n"
328 " %s [options] file.ts\n"
329 "\n"
330 " file.ts ATSC/ATSC+MPEG2/MPEG2-only Transport Stream file\n"
331 "\n"
332 "Options:\n"
333 "\n"
334 " Packet extraction control (PIDs are given in hexadecimal):\n"
335 "\n"
336 " -p path Output path. Default is .\n"
337 "\n"
338 " -o name Use this output basename instead of input basename.\n"
339 "\n"
340 " -e integer Extract single Program from full stream capture.\n"
341 " Program numbers are 1-65534, not 0 or 65535.\n"
342 "\n"
343 " -s Generate frame/sequence files for xtscut/atscut -X.\n"
344 " This requires single VC capture/extract to work.\n"
345 " Use pchdtvr -m option to generate during single VC\n"
346 " capture, to prevent having to do it here.\n"
347 "\n"
348 " -k PID Extract the hexadecimal PID from the stream.\n"
349 " You may use multiple -k PID to get more than one.\n"
350 " \042MGT\042 for PID keeps only ATSC PSIP PIDs.\n"
351 " MGT extract requires full stream capture.\n"
352 "\n"
353 " -d integer Duty cycle %% e.g. -d95. Default 100, no sleeping.\n"
354 " Lower CPU usage prevents pchdtvr capture dropout.\n"
355 "\n"
357 " -y PID Extract specified Video PID as ES to basename-pid.es.\n"
358 "\n"
360 " -n NULLs: keeps the bitrate same as source file\n"
361 "\n"
362 "\n -r file.ts replace Progam Association Table 188 byte file.ts\n"
363 " single program stream only\n"
364 "\n"
365 "\n -f forge PAT + PMT to one video + one audio, see -e\n"
366 "\n"
367 " -h Help. You're looking at it.\n"
368 "\n"
369 " Packet dump detail control. Default is to give summary counts at end.\n"
370 " NOTE: You can specify these multiple times to avoid the addition.\n"
371 " xxx is don't care, no code or ideas for the bit usage yet.\n"
372 "\n"
373 " -v integer Verbose bits, global enables: see -m -a\n"
374 " 1:PKT 2:ATSC 4:MPEG 8: SYN\n"
375 " 16:PSI0 32:xxx 64:xxx 128:xxxx\n"
376 "\n"
377 " -m integer MPEG detail level bits:\n"
378 " 1:PAT 2:PMT 4:AUD 8:VID\n"
379 " 16:SMB 32:PAY 64:PCR 128:IPB\n"
380 "\n"
381 " -a integer ATSC detail level bits (only for full streams):\n"
382 " 1:MGT 2:VCT 4:EIT 8:ETT\n"
383 " 16:RRT 32:PAY 64:STT 128:xxx\n" /* 128:CVCT */
384 "\n"
385 " -g dump ATSC PSIP Event Program Guide, if any.\n"
386 " Guide dump requires full stream capture.\n"
387 "\n"
388 " -q quiet, redux stdout to only version changes + PES\n"
389 "\n"
390 "\n";
392 /* args for above help */
393 static int arg_verbose = 0; /* verbose and payload assembly detail control */
394 static int arg_mdump = 0; /* mpeg detail control */
395 static int arg_adump = 0; /* atsc detail control */
396 static int arg_guide = 0; /* not zero is dump program guide dump at end */
397 static int arg_redux = 0; /* limits table dump to version changes */
398 static char arg_path[256] = "/dtv/cut/"; /* -p default output path */
399 static char arg_name[256]; /* -o output name override */
400 static char arg_newpat[256]; /* -r replace PAT with first 188 bytes this file */
401 static int arg_seqwr = 0; /* nz if generating frame and sequence files */
402 static int arg_pids = 0; /* nz if -k used at least once */
403 static int arg_mgtpids = 0; /* nz if -k mgt used to build PID list from MGT */
404 static int arg_duty = 100; /* 100 is default, no sleep, else 1-99. */
405 static int arg_espid = 0; /* extract one PID as ES */
406 static int arg_nulls = 0; /* -n inserts nulls to replace -e removed packets */
407 static int arg_epn = 0; /* -e sets program number to extract */
408 static int arg_ean = 0; /* -e3,1 sets this to 1 */
409 static int arg_forge = 0; /* forge new PAT + PMT, only for -e option */
410 static int arg_crc = 0; /* generate list of crc32s for each packet */
412 static unsigned long long pcr = 0; /* current pcr */
413 static unsigned long long ppcr = 0; /* previous pcr */
415 static unsigned long long first_pcr = 0; /* MPEG clock reference */
416 static unsigned long long last_pcr = 0;
417 static unsigned int first_stt = 0; /* ATSC system time */
418 static unsigned int last_stt = 0;
420 #define FILE_MAX 512
421 static unsigned char in_name[ FILE_MAX ];
422 static unsigned char es_name[ FILE_MAX ];
423 static unsigned char base_name[ FILE_MAX ];
424 static unsigned char out_name[ FILE_MAX ];
425 static unsigned char out_path[ FILE_MAX ] = ".";
427 long long in_size = 0; /* input file size */
428 static int in_file = 0; /* normal TS input file */
429 static int out_file; /* normal TS output file */
430 static int es_file = 0; /* -y ES output file */
432 static unsigned char ts_buf[ TSPZ ];
433 static unsigned char newpat[ TSPZ ];
435 static char ipb[256]; /* text display of last frames seen */
436 static unsigned char ipbx = 0; /* index to above */
438 static unsigned int keep_pids[0x2000]; /* lots of pids to keep, -k options */
439 /* -m and -e options use as well */
440 /* counts from the stream */
441 static unsigned char last_cc[0x2000]; /* last continuity counter, by PID */
442 static unsigned char pid_cc[0x2000]; /* error flags, by PID */
443 static unsigned char pid_vn[0x2000]; /* version numbers, by PID */
444 static unsigned char psit[0x2000]; /* payload start table types, by PID */
445 static unsigned int pids[0x2000]; /* packet counts, by PID */
446 static unsigned int cc_err[0x2000]; /* cc error by pid */
448 static int vct_ncs; /* number of channels in vct */
449 static int pat_ncs; /* number of channels in pat */
451 /* is the current packet to be kept? 0 is no. *using keep_pids[] now* */
452 /* static unsigned int keep_pkt = 0; */
454 static struct {
455 unsigned int tt;
456 unsigned int ttpid;
457 unsigned int ttvn;
458 unsigned int nb;
459 unsigned int ttdl;
460 } mg[0x2000];
462 static unsigned int mgt_tt_pidx = 0; /* increments with new list entries */
463 static unsigned int mgt_eit = 0;
465 /* static unsigned int last_pid = -1; */
467 /* static int tsprate = TSPRATE; / / default, integer arg_rate */
469 static int sumrate = 0;
470 static int iframe = 0;
471 static int iframen = 0;
473 /* align is forcing unsigned char store as 32 bits, might as well use int
474 1.8m output for 1 hour 60fps.
476 struct frame_s {
477 int pct; /* picture type I P or B (1 2 or 3) */
478 int vpn; /* video pkt# for picture: 4 hours is < 200 million */
481 /* 24hrs at 60fps */
482 #define FRAME_MAX 5184000
483 //static struct frame_s frames[ FRAME_MAX ];
484 static struct frame_s *frames;
485 /* increments every I P or B frame header */
486 static int frame_idx;
488 /* pick the larger of 1/15th or 1/30th total frame count */
489 #define SEQUENCE_MAX (FRAME_MAX / 15)
490 //static long long sequences[ SEQUENCE_MAX ];
491 static long long *sequences;
492 /* increments every sequence header */
493 static int sequence_idx = 0;
495 static long long bytes_in = 0;
496 static long long bytes_out = 0;
497 static long long bytes_total = 0;
498 static long long ppsbytes_in = 0; /* previous payload start bytes in */
499 static long long psbytes_in = 0; /* payload start bytes in */
501 static unsigned int duty_cycle_sleep = 0;
502 static unsigned int duty_cycle_packet = 0;
504 static long long file_size;
506 struct timespec cap_start, cap_stop, cap_et;
509 /* ATSC packet counters in an easy to clear structure */
510 static
511 struct {
512 int keep; /* want keep to be at zero so optimizer will see no index */
514 /* NOTE: packet count should be supplemented by table count for Table entries */
515 /* remember that Table counts are packet counts not table counts */
516 int count; // total count */
517 int pcount; // previous count from last I frame */
518 int errors; // total of all errors found */
520 // transport errors
521 int errsyn; // packet error
522 int errtei; // transport error indicator
523 int errscr; // any scramble bits set as another error indicator
524 int errcce; // countinuity counter error
526 int atsc; // ATSC PID packet count count
527 int atscce; // ATSC countinuity counter errors
528 int null; // NULL PID packet count
530 int psi; // payload start indicator for current packet
531 int atsctid; // atsc payload table id
532 int mpegtid; // mpeg payload table id
534 // ATSC table types
535 int stt; // System Time Table packet count
536 int mgt; // Master Guide Table packet count
537 int tvct; // Terrestrial Virtual Channel Table packet count
538 int cvct; // Cable Virtual Channel Table packet count
539 int eit; // Event Information Table packet count
540 int ett; // Extended Text Table packet count
541 int rrt; // Region Rating Table packet count
542 int dcct; // Directed Channel Change Table packet count
543 int dccsct; // Directed Channel Change Selection Code Table packet count
545 // CRC error counts for each ATSC table type
546 int crcstt;
547 int crcmgt;
548 int crctvct;
549 int crccvct;
550 int crceit;
551 int crcett;
552 int crcrrt;
553 int crcdcct;
554 int crcdccsct;
556 int mpeg2; // number of mpeg2 packets, pat cat pmt aud vid
557 int mpegce; // number of continuity counter errors for mpeg
558 int pcrdi; // number of pcr discontinuity errors (pcr in video usually)
559 int pes; // aud + vid count
560 int vid; // number of video packets
561 int aud; // number of audio packets
563 // MPEG table types
564 int pat; // Program Association Table packet count
565 int cat; // Conditional Access Table packet count
566 int pmt; // Program Map Table packet count
568 // CRC error counts for each MPEG table type
569 int crcpat;
570 int crccat;
571 int crcpmt;
573 // MPEG headers
574 int seqend; // count sequence end codes (commercial breaks?)
575 int iframe;
576 } pkt;
578 /* program association has list of program numbers and pmt pids */
579 static
580 struct {
581 unsigned int pn;
582 unsigned int pmtpid;
583 } pa[VCZ];
586 /* generic payload structure */
587 struct payload_s {
588 unsigned int sl;
589 unsigned int vn;
590 unsigned int payoff;
591 unsigned int crc;
592 unsigned int payok;
593 char payload[4096];
597 /* generic payload structures */
598 static struct payload_s rrt; // 4k
599 static struct payload_s mgt; // 4k
600 static struct payload_s vct; // 4k
601 static struct payload_s pat; // 4k
602 static struct payload_s pmt[ VCZ ]; // 4k * 16
603 static struct payload_s eit[ EIZ ]; // 512k
604 static struct payload_s ett[ EIZ ]; // 512k
607 /* not seen yet */
608 /* static struct payload_s cat; // 4k */
610 /* see ATSC A/65b Table 6.1 System Time Table */
611 /* aside from the system time, it has dst status that may work */
612 struct stt_s {
613 unsigned short sl;
614 unsigned char pv;
615 unsigned long st;
616 unsigned char guo;
617 unsigned short ds;
618 unsigned char dss;
619 unsigned char dsd;
620 unsigned char dsh;
621 unsigned int crc;
624 static struct stt_s stt;
626 struct vid_s {
627 unsigned int payoff; // video payload offset
628 unsigned int payok; // video payload o
629 unsigned char payload[300 << 10]; // video payload buffer 300k
632 static struct vid_s vid;
634 #ifdef USE_A52_PAYLOAD
635 /* each payload should be 8 packets, with padding, for 40ms of audio.
636 This might be per channel, so multiply by 8 to handle 7.1 audio.
637 Gives around 300kbit/s, which is a little bit lower than 448kbit/s.
639 struct aud_s {
640 unsigned int payoff; // section payload offset
641 unsigned int payok; // section ok
642 unsigned char payload[64 * 188]; // section payload buffer
645 static struct aud_s aud;
647 #endif
650 struct vc_s {
651 unsigned char name[16]; // 7 unicode 16 bit words for vc name, lsb
652 unsigned short major; // 10 bit major channel number for vc
653 unsigned short minor; // 10 bit minor channel number for vc
654 unsigned char mode; // modulation mode: see A/65b table 6.5
655 unsigned int freq; // frequency, obsolete, 0 after jan 1 2010
656 unsigned short ctsid; // TSID to match against PAT TSID
657 unsigned int pn; // program number for PAT and PMT
658 unsigned char etm; // extended text message location, 0 if none
660 /* next few get ignored, but stored */
661 unsigned char actrl; // 1 bit access is not controlled if 0
662 unsigned char hide; // 1 bit surf skip if not 0
663 unsigned char path; // CVCT path select, rsvd in TVCT
664 unsigned char oob; // CVCT out of band, rsvd in TVCT
665 unsigned char hideg; // if hidden set, hide the guide too
667 /* the rest of these may or may not be useful */
668 unsigned char svct; // service type
669 unsigned short src; // source id, for EPG ETMID lookup
670 unsigned short dlen; // descriptor length, descriptor is skipped
672 /* additional descriptors have not been seen */
673 unsigned short adl; // additional descriptor length
676 /* 8 vc's is more than terrestrial uses, but less than cable uses */
677 static struct vc_s vc[ VCZ ];
679 struct pgm_s {
680 unsigned int pn; /* MPEG program number */
681 unsigned int st; // 32 bit start time
682 unsigned int ls; // 20 bit length seconds
683 unsigned int etmid; // 16 bit src, 14 bit event, 2 bit '10'
684 unsigned char name[PNZ]; // bytes of program title
685 unsigned char desc[PDZ]; // ETT description
688 struct pgm_s pgm[ PGZ ]; // whopping usage
689 struct pgm_s pgm1;
691 /* need sort indices, int faster than short */
692 static unsigned int pg[ PGZ ]; // unsorted index of existing
693 static unsigned int pg1[ PGZ ]; // copy of above, then sorted by ETMID
694 static unsigned int pgm_idx; // inc by new EIT with new ETMID, may be stale
695 static unsigned int pg_idx; // first level of freshening the stale
696 static unsigned int pg1_idx; // sorted level of fresh stale tv
699 RRT delivers same information that is in this list of strings
700 but this list doesn't need huffman decode to use.
701 If the list ever changes, this needs to be fixed, too.
702 This is V-Chip, in case you were wondering.
704 static unsigned char *ratings[] = {
705 "Audience", "", "None", "TV-G", "TV-PG", "TV-14", "TV-MA","","","",
706 "Dialogue", "", "D","","","","","","","",
707 "Language", "", "L","","","","","","","",
708 "Sex", "", "S","","","","","","","",
709 "Violence", "", "V","","","","","","","",
710 "Children", "", "TV-Y","TV-Y7","","","","","","",
711 "Fantasy Violence", "", "FV","","","","","","","",
712 "MPAA", "", "N/A","G", "PG", "PG-13","R","NC-17","X","NR",
715 //static time_t stt_t = 0;
716 static struct tm stt_tm;
717 static unsigned char stt_text[32];
718 //static unsigned int stt_crc;
719 static unsigned int utc_offset;
721 static unsigned int mgt_crc;
722 static unsigned int vct_crc;
723 static unsigned int rrt_crc;
725 static unsigned char mgt_vn = 0xFF;
726 static unsigned char vct_vn = 0xFF;
727 static unsigned char eit_vn = 0xFF;
728 static unsigned char ett_vn = 0xFF;
729 static unsigned char rrt_vn = 0xFF;
730 static unsigned char eitvn[ VCZ * EIZ ];
731 static unsigned char ettvn[ VCZ * EIZ ];
733 /* last pat/pmt with good crc */
734 static unsigned char old_pat[188];
735 static unsigned char old_pmt[188];
737 /* so far 5 PMT PIDs seen for, at most, 5 Terrestrial VCs */
738 static int vid_pids[ 8 ]; /* PMT supplied Video ES PIDs */
739 static int vid_pidx = 0;
740 static int aud_pids[ 32 ]; /* PMT supplied Audio ES PIDs */
741 static int aud_pidx = 0;
744 //static unsigned short vidpid;
745 //static unsigned short audpid;
748 /*********************************************************************** CRC32
749 from ffmpeg
751 static const unsigned int crc_lut[256] = {
752 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
753 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
754 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
755 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
756 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
757 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
758 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
759 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
760 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
761 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
762 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
763 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
764 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4,
765 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
766 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
767 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
768 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
769 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
770 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
771 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
772 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
773 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
774 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
775 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
776 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
777 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
778 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
779 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
780 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
781 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
782 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
783 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
784 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
785 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
786 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
787 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
788 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
789 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
790 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
791 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
792 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
793 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
794 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
797 /***************************************************************** ATSC HUFFMAN
798 A/65b Table C5 Huffman Title Decode Tree (c) 1997 General Instruments Corp.
799 The following, according to ATSC specs, is royalty free for ATSC use.
801 not exact table, but a faster, more usable version of it,
802 since exact table is big endian but x86 isn't.
804 byte offsets of character i tree root
806 Non-compliant stations crash this so need limits
808 static unsigned int huffman1bo[128] = {
809 0x0000, 0x003A, 0x003C, 0x003E, 0x0040, 0x0042, 0x0044, 0x0046,
810 0x0048, 0x004A, 0x004C, 0x004E, 0x0050, 0x0052, 0x0054, 0x0056,
811 0x0058, 0x005A, 0x005C, 0x005E, 0x0060, 0x0062, 0x0064, 0x0066,
812 0x0068, 0x006A, 0x006C, 0x006E, 0x0070, 0x0072, 0x0074, 0x0076,
813 0x0078, 0x00CE, 0x00D2, 0x00D4, 0x00D6, 0x00D8, 0x00DA, 0x00DC,
814 0x00E6, 0x00E8, 0x00EA, 0x00F0, 0x00F2, 0x00F4, 0x0106, 0x0112,
815 0x0114, 0x011C, 0x0128, 0x0130, 0x0134, 0x0136, 0x0138, 0x013A,
816 0x013C, 0x013E, 0x0146, 0x0148, 0x014A, 0x014C, 0x014E, 0x0150,
817 0x0152, 0x0154, 0x017E, 0x0192, 0x01AC, 0x01BA, 0x01D2, 0x01E4,
818 0x01FA, 0x0206, 0x021E, 0x0226, 0x0232, 0x023E, 0x0252, 0x0264,
819 0x027A, 0x0294, 0x0298, 0x02A4, 0x02C8, 0x02DE, 0x02E6, 0x02F4,
820 0x0304, 0x0306, 0x030C, 0x0310, 0x0312, 0x0314, 0x0316, 0x0318,
821 0x031A, 0x031C, 0x0352, 0x036A, 0x038E, 0x03AE, 0x03EE, 0x0406,
822 0x0428, 0x0444, 0x0472, 0x0476, 0x0490, 0x04BE, 0x04D6, 0x050A,
823 0x0544, 0x0564, 0x0566, 0x059A, 0x05D0, 0x05FC, 0x0622, 0x062C,
824 0x0646, 0x0654, 0x067C, 0x068A, 0x068C, 0x068E, 0x0690, 0x0692
827 #define TITLE_COZ 1683
828 /* character i order-1 trees */
829 static unsigned char huffman1co[1684] = {
830 0x1B,0x1C,0xB4,0xA4,0xB2,0xB7,0xDA,0x01,0xD1,0x02,0x03,0x9B,0x04,0xD5,0xD9,0x05,
831 0xCB,0xD6,0x06,0xCF,0x07,0x08,0xCA,0x09,0xC9,0xC5,0xC6,0x0A,0xD2,0xC4,0xC7,0xCC,
832 0xD0,0xC8,0xD7,0xCE,0x0B,0xC1,0x0C,0xC2,0xCD,0xC3,0x0D,0x0E,0x0F,0x10,0xD3,0x11,
833 0xD4,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,
834 0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,
835 0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,
836 0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,
837 0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x29,0x2A,0xD8,0xE5,0xB9,0x01,0xA7,0xB1,
838 0xEC,0xD1,0x02,0xAD,0xB2,0xDA,0xE3,0xB3,0x03,0xE4,0xE6,0x04,0x9B,0xE2,0x05,0x06,
839 0x07,0x08,0x09,0xD5,0x0A,0xD6,0x0B,0xD9,0x0C,0xA6,0xE9,0xCB,0xC5,0xCF,0x0D,0x0E,
840 0xCA,0xC9,0x0F,0xC7,0x10,0x11,0xE1,0x12,0x13,0xC6,0xD2,0xC8,0xCE,0xC1,0xC4,0xD0,
841 0xCC,0x14,0x15,0xEF,0xC2,0xD7,0x16,0xCD,0x17,0xF4,0xD4,0x18,0x19,0x1A,0xC3,0xD3,
842 0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x01,0x80,
843 0xA0,0x9B,0x9B,0x9B,0x9B,0x9B,0xB1,0x9B,0x9B,0x9B,0x9B,0xA0,0x04,0xF3,0xE4,0xB9,
844 0x01,0xF4,0xA0,0x9B,0x02,0x03,0x9B,0x9B,0x9B,0x9B,0x01,0x02,0x9B,0xC1,0xC8,0xD3,
845 0x9B,0x9B,0x9B,0xA0,0x07,0x08,0xB1,0xD2,0xD3,0xD4,0xD5,0xAD,0xCD,0xC1,0x01,0x02,
846 0x03,0xA0,0x04,0x9B,0x05,0x06,0xA0,0x05,0xC9,0xD7,0xD3,0x01,0x02,0x9B,0xAE,0x80,
847 0x03,0x04,0x9B,0x9B,0x02,0x03,0xAD,0x9B,0x01,0x80,0xA0,0xB0,0x04,0x05,0x80,0x9B,
848 0xB1,0xB2,0xA0,0xB0,0xB9,0x01,0x02,0x03,0x02,0x03,0xB1,0xBA,0x01,0xB0,0x9B,0x80,
849 0x80,0x01,0xB0,0x9B,0x9B,0xB8,0x9B,0x9B,0x9B,0x9B,0x9B,0xB0,0x9B,0xA0,0x02,0x03,
850 0xB1,0xB3,0xB9,0xB0,0x01,0x9B,0x9B,0xA0,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,
851 0x9B,0x80,0x9B,0x9B,0x13,0x14,0xAA,0xAD,0xAE,0xF6,0xE7,0xF4,0xE2,0xE9,0x01,0x02,
852 0xC2,0xF0,0x9B,0xF3,0xE3,0xE6,0xF7,0x03,0xF5,0x04,0x05,0x06,0xF2,0x07,0x08,0x09,
853 0x0A,0x0B,0x0C,0xE4,0xA0,0x0D,0xEC,0xEE,0x0E,0xED,0x0F,0x10,0x11,0x12,0x08,0x09,
854 0xC1,0xD3,0x9B,0x01,0xC3,0x02,0xE9,0xEC,0x03,0xF2,0xF5,0x04,0xEF,0xE1,0x05,0xE5,
855 0x06,0x07,0x0B,0x0C,0xC1,0xF9,0x01,0xC2,0xCF,0xE5,0xF5,0x9B,0xE9,0x02,0xA0,0x03,
856 0x04,0x05,0xF2,0x06,0xEC,0x07,0xE1,0x08,0x09,0xE8,0x0A,0xEF,0x05,0x06,0xF9,0x9B,
857 0x01,0xF5,0x02,0xF2,0xE9,0xE5,0xEF,0x03,0xE1,0x04,0x0A,0x0B,0xF1,0xF5,0xF3,0x01,
858 0xED,0xF9,0xC3,0x02,0xEC,0xEE,0xE4,0xF8,0x03,0x9B,0xF6,0x04,0x05,0xE1,0x06,0x07,
859 0x08,0x09,0x07,0x08,0xA0,0x9B,0xCC,0x01,0xE5,0x02,0xEC,0xF5,0xEF,0x03,0xE9,0xF2,
860 0x04,0x05,0xE1,0x06,0x09,0x0A,0xAE,0xEC,0xF9,0xC1,0xE8,0x01,0x9B,0x02,0x03,0x04,
861 0xE1,0xF5,0xE9,0x05,0xE5,0x06,0xF2,0xEF,0x07,0x08,0xEF,0x05,0x80,0x9B,0xF5,0x01,
862 0x02,0xE9,0xE1,0x03,0xE5,0x04,0xEE,0x0B,0xBA,0xD4,0xAE,0xF2,0xE3,0x01,0xA0,0x02,
863 0x80,0x9B,0xED,0x03,0xC9,0xF3,0xF4,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x02,0x03,
864 0x9B,0xF5,0x01,0xE1,0xEF,0xE5,0x05,0xE9,0xE1,0xEF,0xF5,0xEE,0x9B,0xE5,0x01,0x02,
865 0x03,0x04,0x04,0x05,0xA0,0x9B,0x01,0xF5,0x02,0xE5,0xEF,0x03,0xE1,0xE9,0x08,0x09,
866 0xAA,0xD4,0x01,0x9B,0xE3,0x02,0xF2,0x03,0xE5,0x04,0xF5,0xF9,0xE9,0x05,0xEF,0x06,
867 0x07,0xE1,0xE5,0x08,0xCE,0xA0,0xC6,0xF5,0x01,0x02,0x9B,0xC2,0x03,0xE1,0x04,0xEF,
868 0x05,0xE9,0x06,0x07,0x09,0x0A,0xE4,0xF3,0xE6,0xF6,0xF7,0xF0,0xF2,0x01,0xEC,0x02,
869 0x03,0xA0,0x9B,0x04,0x05,0xF5,0x06,0x07,0xEE,0x08,0x0B,0x0C,0xA0,0xF3,0xF9,0xAE,
870 0xD2,0xC7,0x01,0x9B,0x02,0xF5,0x03,0x04,0x05,0xE9,0xEC,0x06,0xE5,0x07,0xEF,0x08,
871 0xE1,0x09,0xF2,0x0A,0x01,0xF5,0x9B,0xD6,0x04,0x05,0xE8,0x9B,0x01,0xF5,0x02,0xE1,
872 0xE9,0xEF,0x03,0xE5,0x10,0x11,0xAA,0xEC,0xF1,0xAE,0xA0,0xF7,0xED,0xEE,0x01,0x02,
873 0x9B,0xEB,0x03,0x04,0x05,0x06,0xE3,0x07,0xEF,0x08,0xE9,0xF5,0x09,0xE1,0xE5,0xF0,
874 0xE8,0x0A,0x0B,0x0C,0x0D,0xF4,0x0E,0x0F,0xE8,0x0A,0xAD,0xCE,0x9B,0x01,0xD6,0x02,
875 0xF5,0xF7,0x03,0x04,0xE1,0xE5,0xE9,0x05,0xF2,0x06,0xEF,0x07,0x08,0x09,0xEE,0x03,
876 0xEC,0xAE,0x01,0x9B,0x02,0xF0,0x06,0xE9,0xA0,0xC3,0xEF,0x9B,0xE5,0x01,0x80,0x02,
877 0x03,0xE1,0x04,0x05,0x06,0x07,0xC6,0xD7,0x01,0x9B,0xF2,0x02,0x03,0xE8,0xE5,0xE1,
878 0x04,0xE9,0xEF,0x05,0x9B,0x9B,0x02,0xEF,0xE1,0x9B,0x01,0xE5,0x01,0xEF,0x9B,0xE1,
879 0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x19,0x1A,0x9B,0xBA,
880 0xE5,0xEA,0xF8,0x01,0x02,0xE6,0xA7,0x03,0xFA,0xE8,0x04,0xF7,0x05,0xF5,0xE2,0x06,
881 0xEB,0x07,0xF0,0x08,0x80,0xF6,0xE7,0x09,0xE4,0x0A,0xA0,0xE9,0x0B,0xE3,0xF9,0x0C,
882 0x0D,0xED,0x0E,0x0F,0xF3,0x10,0x11,0xEC,0x12,0xF4,0xF2,0x13,0xEE,0x14,0x15,0x16,
883 0x17,0x18,0x0A,0x0B,0xF3,0x9B,0xF5,0xE2,0x01,0x80,0xA0,0x02,0xE5,0xF2,0xE9,0x03,
884 0xEC,0x04,0xF9,0x05,0xEF,0x06,0xE1,0x07,0x08,0x09,0x10,0x11,0xC3,0xCC,0xC7,0x9B,
885 0xE3,0x01,0x80,0xEC,0xF9,0x02,0xF3,0x03,0xF5,0x04,0x05,0xF2,0x06,0xE9,0xA0,0x07,
886 0x08,0xEF,0xF4,0x09,0x0A,0xE1,0x0B,0xE8,0xEB,0xE5,0x0C,0x0D,0x0E,0x0F,0x0E,0x0F,
887 0xAE,0xF5,0xF7,0x01,0xEC,0x02,0xE4,0xE7,0xF2,0x03,0x9B,0xEF,0x04,0xF6,0x05,0x06,
888 0xF9,0xF3,0x07,0xE9,0xE1,0x08,0x09,0x80,0x0A,0x0B,0xE5,0x0C,0x0D,0xA0,0x1E,0x1F,
889 0x9B,0xA1,0xAD,0xE8,0xEA,0xF1,0xF5,0xFA,0x01,0x02,0x03,0x04,0xBA,0xF8,0xA7,0xE2,
890 0xE9,0x05,0x06,0x07,0xE6,0xED,0xE7,0xEB,0x08,0x09,0xF6,0xF0,0x0A,0xEF,0x0B,0xE3,
891 0x0C,0x0D,0x0E,0xF9,0x0F,0xE4,0xEC,0x10,0xE5,0x11,0xF4,0xF7,0x12,0x13,0xE1,0x14,
892 0x15,0x16,0xEE,0xF3,0x17,0x80,0x18,0x19,0xF2,0x1A,0x1B,0xA0,0x1C,0x1D,0xA0,0x0B,
893 0xF5,0x9B,0x01,0xEC,0xF3,0xF2,0x80,0xE1,0x02,0x03,0xF4,0xE9,0xEF,0xE6,0x04,0x05,
894 0x06,0x07,0xE5,0x08,0x09,0x0A,0x0F,0x10,0xBA,0xF9,0xA7,0xF4,0x9B,0x01,0xE7,0xEC,
895 0x02,0xEE,0x03,0xEF,0xF5,0x04,0xF2,0x05,0x06,0xE9,0x07,0xF3,0xE1,0x08,0x09,0x0A,
896 0x0B,0xE5,0x80,0x0C,0xE8,0xA0,0x0D,0x0E,0xE5,0x0D,0xE2,0xF5,0xF7,0x9B,0xEC,0x01,
897 0xF9,0xEE,0x02,0x03,0x04,0xF2,0x05,0x80,0x06,0xA0,0xE1,0xEF,0x07,0xF4,0xE9,0x08,
898 0x09,0x0A,0x0B,0x0C,0x15,0x16,0xA1,0xF8,0xE9,0xEB,0x01,0x80,0x9B,0xFA,0xE2,0x02,
899 0x03,0x04,0xA0,0xF0,0x05,0x06,0x07,0xE1,0x08,0xE6,0xF2,0xED,0xF6,0x09,0xE4,0x0A,
900 0xEF,0xF4,0xEC,0xF3,0xE7,0xE5,0x0B,0xE3,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,
901 0xEE,0x14,0xEF,0x01,0x9B,0xE1,0x0B,0x0C,0xD4,0xEF,0xE6,0xEC,0xF7,0xE1,0x01,0xBA,
902 0x02,0x9B,0xF9,0x03,0x04,0x05,0xF3,0x06,0x07,0x08,0xE9,0xA0,0x09,0x80,0xE5,0x0A,
903 0x15,0x16,0xA7,0xBA,0xE3,0xF7,0xF2,0xAD,0xE2,0x01,0x02,0x9B,0xE6,0x03,0xED,0xF6,
904 0x04,0xEB,0x05,0xF4,0x06,0x07,0x08,0xF3,0x09,0xF5,0x0A,0xEF,0x0B,0x0C,0x80,0xF9,
905 0xE1,0x0D,0xE4,0xE9,0xA0,0x0E,0x0F,0xEC,0xE5,0x10,0x11,0x12,0x13,0x14,0x0A,0x0B,
906 0xF9,0x9B,0xF5,0xF3,0x01,0x02,0xE2,0xED,0x80,0x03,0xF0,0xEF,0x04,0xA0,0x05,0xE9,
907 0x06,0xE1,0x07,0x08,0x09,0xE5,0x18,0x19,0xE2,0xEA,0xF2,0xE8,0xEC,0xED,0xFA,0x9B,
908 0x01,0xF5,0x02,0x03,0xF6,0x04,0xBA,0xE6,0x05,0x06,0xEB,0xEF,0x07,0xA7,0xF9,0x08,
909 0x09,0x0A,0x0B,0xE3,0x0C,0xEE,0xE1,0x0D,0xF3,0x0E,0xE9,0x0F,0x10,0xF4,0x80,0xE4,
910 0xE5,0x11,0x12,0xE7,0xA0,0x13,0x14,0x15,0x16,0x17,0x1B,0x1C,0xAE,0xFA,0xBF,0x01,
911 0xA7,0x9B,0x02,0xE9,0xF8,0xF9,0x03,0xE5,0xE8,0x04,0xE1,0xEB,0x05,0xE2,0x06,0x07,
912 0xE3,0x08,0xE7,0xF4,0x09,0x80,0xF6,0xF0,0x0A,0xE4,0x0B,0xF3,0xF7,0x0C,0x0D,0xEF,
913 0xEC,0xA0,0x0E,0x0F,0xED,0xE6,0x10,0xF5,0x11,0x12,0x13,0x14,0x15,0xF2,0x16,0xEE,
914 0x17,0x18,0x19,0x1A,0x0E,0x0F,0xED,0xA7,0x9B,0xE4,0x01,0xF9,0xF3,0xF2,0xF4,0x02,
915 0xE8,0x03,0xEC,0xF0,0x04,0xE1,0xE9,0x05,0x06,0x80,0xA0,0x07,0x08,0x09,0x0A,0xE5,
916 0xEF,0x0B,0x0C,0x0D,0x9B,0xF5,0x18,0x19,0xBA,0xAC,0xF6,0x9B,0xF0,0xE2,0x01,0xE6,
917 0x02,0xA7,0xAE,0xE7,0x03,0xE3,0xF5,0x04,0xED,0x05,0x06,0x07,0xEB,0x08,0x09,0xEE,
918 0xF2,0x0A,0xE4,0x0B,0xF9,0xEC,0x0C,0x0D,0xF4,0x80,0x0E,0xEF,0xF3,0xA0,0xE1,0x0F,
919 0xE9,0x10,0x11,0xE5,0x12,0x13,0x14,0x15,0x16,0x17,0x19,0x1A,0xA7,0xAC,0xBF,0xC3,
920 0xC8,0xE4,0xE6,0xED,0xF2,0xAE,0xEC,0xEE,0xF9,0x01,0x02,0x03,0x04,0xBA,0x05,0x9B,
921 0xF5,0x06,0x07,0x08,0x09,0xEB,0xF0,0x0A,0x0B,0x0C,0xE1,0xE3,0x0D,0xE8,0x0E,0x0F,
922 0xEF,0x10,0x11,0xF3,0x12,0xE9,0x13,0xE5,0x14,0x15,0xF4,0x16,0x17,0xA0,0x18,0x80,
923 0x14,0x15,0xBA,0xBF,0xE4,0xF7,0x9B,0xA7,0x01,0xEE,0x02,0x03,0x04,0xE3,0xE2,0xED,
924 0x05,0xF9,0x06,0xF4,0x07,0xEC,0x08,0xF5,0xF2,0x09,0xE1,0xF3,0x0A,0xEF,0x0B,0x0C,
925 0x0D,0xE9,0x80,0xE5,0x0E,0xA0,0x0F,0xE8,0x10,0x11,0x12,0x13,0x11,0x12,0xEB,0xFA,
926 0x80,0xE6,0x9B,0x01,0xA0,0x02,0x03,0xE9,0xE1,0x04,0xE4,0xF0,0xED,0xE2,0xE3,0xE7,
927 0xEC,0x05,0xE5,0x06,0x07,0x08,0x09,0xF4,0x0A,0x0B,0x0C,0xF3,0xEE,0x0D,0x0E,0xF2,
928 0x0F,0x10,0x04,0xE5,0xF3,0xEF,0x9B,0x01,0xE1,0x02,0x03,0xE9,0x0B,0x0C,0xA7,0xE2,
929 0xEC,0xE3,0xF2,0x01,0x9B,0x02,0x03,0x04,0xE9,0xEF,0xEE,0xE5,0xE1,0x80,0x05,0xA0,
930 0x06,0x07,0x08,0x09,0xF3,0x0A,0x05,0x06,0x9B,0xA0,0xE1,0xE5,0xE9,0x01,0x80,0xF0,
931 0x02,0xF4,0x03,0x04,0xA0,0x13,0xE3,0xAD,0xE4,0xE9,0xEE,0xEF,0xF0,0xF4,0xF6,0xA1,
932 0xE1,0xED,0x01,0xE2,0x02,0x03,0x04,0xA7,0x05,0x06,0xF7,0x07,0x9B,0xEC,0x08,0xE5,
933 0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0xF3,0x0F,0x10,0x11,0x80,0x12,0x05,0x06,0xE5,0xFA,
934 0xA0,0xF9,0x9B,0x01,0x80,0xE9,0x02,0xE1,0x03,0x04,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,
935 0x9B,0x9B,0x9B,0x9B
938 A/65b Table C7 Huffman Description Decode Tree (c) General Instruments Corp.
939 The following, according to ATSC specs, is royalty free for ATSC use.
941 not exact table, but a faster, more usable version of it,
942 since exact table is big endian but x86 isn't.
944 byte offsets of character i tree root
946 static unsigned int huffman2bo[128] = {
947 0x0000, 0x002C, 0x002E, 0x0030, 0x0032, 0x0034, 0x0036, 0x0038,
948 0x003A, 0x003C, 0x003E, 0x0040, 0x0042, 0x0044, 0x0046, 0x0048,
949 0x004A, 0x004C, 0x004E, 0x0050, 0x0052, 0x0054, 0x0056, 0x0058,
950 0x005A, 0x005C, 0x005E, 0x0060, 0x0062, 0x0064, 0x0066, 0x0068,
951 0x006A, 0x00DE, 0x00E0, 0x00EA, 0x00EC, 0x00EE, 0x00F0, 0x00F2,
952 0x00F8, 0x00FA, 0x00FC, 0x00FE, 0x0100, 0x0104, 0x0116, 0x0120,
953 0x0122, 0x012C, 0x0132, 0x0138, 0x013C, 0x0140, 0x0144, 0x0146,
954 0x014A, 0x014C, 0x0154, 0x0156, 0x0158, 0x015A, 0x015C, 0x015E,
955 0x0160, 0x0162, 0x0176, 0x0184, 0x0194, 0x01A2, 0x01B2, 0x01BA,
956 0x01C8, 0x01D2, 0x01DE, 0x01EA, 0x01F2, 0x01FC, 0x0208, 0x0210,
957 0x021A, 0x0228, 0x022A, 0x0234, 0x024A, 0x025A, 0x025E, 0x0264,
958 0x026E, 0x0270, 0x0272, 0x0274, 0x0276, 0x0278, 0x027A, 0x027C,
959 0x027E, 0x0280, 0x02B4, 0x02CE, 0x02F0, 0x031A, 0x0358, 0x036E,
960 0x038E, 0x03AC, 0x03D8, 0x03E0, 0x03F4, 0x0424, 0x0440, 0x0476,
961 0x04AE, 0x04CE, 0x04D0, 0x0506, 0x0534, 0x0560, 0x0586, 0x0592,
962 0x05AA, 0x05B8, 0x05DC, 0x05EC, 0x05EE, 0x05F0, 0x05F2, 0x05F4,
965 #define DESCR_COZ 1525
966 /* character i order-1 trees */
967 static unsigned char huffman2co[1526] = {
968 0x14,0x15,0x9B,0xD6,0xC9,0xCF,0xD7,0xC7,0x01,0xA2,0xCE,0xCB,0x02,0x03,0xC5,0xCC,
969 0xC6,0xC8,0x04,0xC4,0x05,0xC2,0x06,0xC3,0xD2,0x07,0xD3,0x08,0xCA,0xD4,0x09,0xCD,
970 0xD0,0x0A,0xC1,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x9B,0x9B,0x9B,0x9B,
971 0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,
972 0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,
973 0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,
974 0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x38,0x39,0xAD,0xAF,0xB7,0xDA,
975 0xA8,0xB3,0xB5,0x01,0x02,0x9B,0xB4,0xF1,0xA2,0xD5,0xD6,0xD9,0x03,0x04,0x05,0xCF,
976 0x06,0xC9,0xF9,0xEA,0xEB,0xF5,0xF6,0x07,0x08,0x09,0xB2,0xC5,0xC6,0xB1,0x0A,0xEE,
977 0xCB,0x0B,0xD4,0x0C,0xC4,0xC8,0xD2,0x0D,0x0E,0x0F,0xC7,0xCA,0xCE,0xD0,0xD7,0x10,
978 0xC2,0x11,0xCC,0xEC,0xE5,0xE7,0x12,0xCD,0x13,0x14,0xC3,0x15,0x16,0x17,0xED,0x18,
979 0x19,0xF2,0x1A,0xD3,0x1B,0x1C,0xE4,0x1D,0xC1,0xE3,0x1E,0xE9,0xF0,0xE2,0xF7,0x1F,
980 0xF3,0xE6,0x20,0x21,0x22,0xE8,0xEF,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0xF4,
981 0x2B,0x2C,0x2D,0x2E,0x2F,0xE1,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x9B,0x9B,
982 0x03,0x04,0x80,0xAE,0xC8,0xD4,0x01,0x02,0x9B,0xA0,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,
983 0x9B,0x9B,0x02,0xF3,0xA0,0xF4,0x9B,0x01,0x9B,0x9B,0xAC,0x9B,0x9B,0x9B,0x9B,0x9B,
984 0x01,0xA0,0x9B,0xA2,0x07,0x08,0xE2,0xE4,0xE5,0xE6,0xA0,0xF2,0xE1,0x01,0x02,0xF3,
985 0xE3,0x03,0x04,0x05,0x9B,0x06,0x04,0x80,0xCA,0xD3,0xA2,0x01,0x9B,0x02,0x03,0xA0,
986 0x9B,0xA0,0x03,0x04,0x9B,0xB7,0xF4,0xA0,0xB0,0xF3,0x01,0x02,0xB9,0x02,0xB8,0x9B,
987 0xA0,0x01,0xAE,0x02,0xB6,0x9B,0x01,0xA0,0xA0,0x01,0x9B,0xB0,0xAE,0x01,0x9B,0xA0,
988 0xAE,0x01,0xA0,0x9B,0x9B,0x9B,0x9B,0x01,0xAC,0xAE,0x9B,0x9B,0x02,0x03,0x9B,0xA0,
989 0xB5,0xB6,0xB8,0x01,0x9B,0xA0,0x9B,0xA0,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0xA0,
990 0x9B,0x9B,0x08,0x09,0xE6,0xF5,0xF3,0xF4,0x9B,0xE4,0x01,0xED,0x02,0x03,0x04,0xF2,
991 0x05,0x06,0xEC,0xEE,0x07,0xA0,0x05,0x06,0x9B,0xEC,0xF5,0x01,0x02,0xE1,0xEF,0xE5,
992 0xE9,0xF2,0x03,0x04,0x06,0x07,0x9B,0xE9,0xF9,0xF2,0xF5,0x01,0x02,0x03,0xEC,0xEF,
993 0xE1,0x04,0xE8,0x05,0x05,0x06,0xF9,0xF2,0xF5,0x9B,0xE5,0xEF,0x01,0x02,0xE9,0xE1,
994 0x03,0x04,0x06,0x07,0xE1,0xE9,0xEE,0xF6,0xE4,0xEC,0xF3,0x01,0x02,0xF2,0x03,0x04,
995 0x9B,0x05,0x02,0x03,0xE5,0xEC,0x9B,0xEF,0x01,0xF2,0x05,0x06,0xF5,0xEF,0x9B,0xEC,
996 0xE9,0x01,0xE1,0xF2,0x02,0xE5,0x03,0x04,0x03,0x04,0x9B,0xE5,0xE9,0xF5,0xE1,0x01,
997 0xEF,0x02,0x04,0x05,0xA0,0xC9,0xF3,0x9B,0xAE,0xF2,0x01,0x02,0x03,0xEE,0xEF,0x05,
998 0x9B,0xAE,0xE9,0xE5,0x01,0xF5,0x02,0xE1,0x03,0x04,0xE5,0x03,0xE1,0xE9,0xF2,0x9B,
999 0x01,0x02,0x03,0x04,0x9B,0xE9,0xF5,0x01,0xE5,0x02,0xEF,0xE1,0xE1,0x05,0x9B,0xE3,
1000 0xEF,0x01,0xF5,0xE5,0x02,0x03,0xE9,0x04,0xE5,0x03,0x9B,0xE9,0x01,0xE1,0xEF,0x02,
1001 0x03,0x04,0xA7,0xEE,0xEC,0xF2,0xF3,0x01,0x9B,0x02,0xE1,0x06,0x9B,0xE8,0xE9,0x01,
1002 0xF2,0xEC,0x02,0xEF,0x03,0xE5,0x04,0x05,0x9B,0x9B,0x03,0x04,0x9B,0xAE,0x01,0xE9,
1003 0x02,0xE1,0xE5,0xEF,0x09,0x0A,0xF6,0xF9,0x01,0xAE,0xE3,0xE9,0xF5,0x9B,0xE5,0xEF,
1004 0x02,0x03,0xE1,0x04,0xE8,0x05,0x06,0xF4,0x07,0x08,0xE8,0x07,0xE5,0xF7,0xD6,0xE1,
1005 0x9B,0xE9,0xF2,0x01,0x02,0x03,0x04,0xEF,0x05,0x06,0xAE,0x01,0x9B,0xEE,0xE9,0x02,
1006 0xE5,0x9B,0xA0,0x01,0x03,0x04,0x9B,0xE8,0xE5,0xE1,0xEF,0x01,0xE9,0x02,0x9B,0x9B,
1007 0x9B,0xEF,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,
1008 0x18,0x19,0xE8,0xEF,0xF8,0x9B,0xA7,0xF7,0xFA,0x01,0x02,0x03,0x04,0xE5,0xAE,0x05,
1009 0xE6,0xE2,0x06,0xF6,0xEB,0xF5,0xE9,0x07,0xF0,0xF9,0xE7,0x08,0x09,0xE4,0x0A,0xE3,
1010 0x0B,0xED,0x0C,0xF3,0x0D,0x0E,0x0F,0xEC,0x10,0xF4,0x11,0x12,0xF2,0xA0,0x13,0x14,
1011 0x15,0xEE,0x16,0x17,0x0B,0x0C,0xE4,0xF3,0x9B,0xAE,0xE2,0x01,0x02,0x03,0xEC,0xA0,
1012 0x04,0xE9,0xF2,0xF5,0x05,0xF9,0xE1,0x06,0xEF,0x07,0xE5,0x08,0x09,0x0A,0x0F,0x10,
1013 0xF1,0xAE,0xC4,0xF9,0xAC,0x01,0xE3,0x02,0x9B,0xF2,0x03,0x04,0xA0,0xEC,0xF5,0x05,
1014 0x06,0xE9,0x07,0xEB,0x08,0xF4,0x09,0xE5,0x0A,0xEF,0xE1,0xE8,0x0B,0x0C,0x0D,0x0E,
1015 0x13,0x14,0xA7,0xBB,0xE6,0xED,0xF7,0xE7,0xF6,0x01,0x02,0x9B,0xEE,0x03,0x04,0xEC,
1016 0x05,0xF5,0x06,0xAC,0xE4,0xF9,0xF2,0x07,0x08,0x09,0xAE,0x0A,0xEF,0x0B,0xE1,0xF3,
1017 0x0C,0xE9,0x0D,0x0E,0x0F,0x10,0xE5,0x11,0x12,0xA0,0x1D,0x1E,0xA9,0xE8,0xF5,0x9B,
1018 0x01,0xAD,0xBB,0xEB,0xFA,0x02,0xA7,0xE6,0xE2,0xE7,0x03,0x04,0x05,0x06,0xE9,0xF8,
1019 0x07,0xAC,0xEF,0xF0,0x08,0xED,0xF6,0xF9,0x09,0xF7,0x0A,0x0B,0xAE,0x0C,0xE3,0x0D,
1020 0xE5,0xF4,0x0E,0x0F,0xE4,0x10,0xEC,0x11,0xE1,0x12,0x13,0x14,0x15,0x16,0xEE,0xF3,
1021 0x17,0x18,0xF2,0xA0,0x19,0x1A,0x1B,0x1C,0x09,0x0A,0xAE,0x9B,0xEC,0x01,0xF5,0x02,
1022 0xF4,0xE6,0x03,0xE1,0xE5,0xE9,0x04,0xF2,0xEF,0x05,0x06,0x07,0xA0,0x08,0x0E,0x0F,
1023 0xAD,0xE7,0x9B,0xA7,0xF9,0x01,0xEC,0x02,0xAC,0xF2,0x03,0xAE,0xF3,0xF5,0x04,0x05,
1024 0xEF,0x06,0x07,0xE9,0xE1,0x08,0x09,0xE8,0x0A,0x0B,0xE5,0x0C,0xA0,0x0D,0x0D,0x0E,
1025 0xA7,0xAC,0xF3,0xAD,0x01,0x02,0x9B,0xF9,0xF5,0xAE,0x03,0xEE,0x04,0xF2,0x05,0x06,
1026 0xF4,0x07,0x08,0x09,0xEF,0xE1,0xA0,0x0A,0xE9,0x0B,0x0C,0xE5,0x14,0x15,0xAC,0xE2,
1027 0xF8,0x9B,0xAE,0xFA,0x01,0xEB,0x02,0xA0,0x03,0x04,0xF0,0x05,0x06,0xE6,0xF6,0x07,
1028 0xE4,0xED,0xE7,0x08,0xE1,0xEF,0xF2,0x09,0x0A,0x0B,0xEC,0x0C,0xE5,0xE3,0x0D,0xF4,
1029 0x0E,0xF3,0x0F,0x10,0x11,0xEE,0x12,0x13,0x03,0xEF,0x9B,0xE1,0xE5,0xF5,0x01,0x02,
1030 0x08,0x09,0xEC,0xF9,0xA7,0xEE,0x01,0xAC,0x9B,0xAE,0x02,0x03,0x04,0xF3,0x05,0xE9,
1031 0x06,0xA0,0x07,0xE5,0x16,0x17,0xA7,0xAD,0xEE,0xE3,0xEB,0xF2,0x9B,0xE2,0x01,0x02,
1032 0xF5,0x03,0xF4,0xAC,0x04,0x05,0xE6,0xED,0xF6,0x06,0xAE,0xF0,0x07,0x08,0xF3,0x09,
1033 0x0A,0xE4,0x0B,0x0C,0xF9,0x0D,0xEF,0x0E,0xE1,0x0F,0x10,0xE9,0xEC,0x11,0xA0,0xE5,
1034 0x12,0x13,0x14,0x15,0x0C,0x0D,0xA7,0xBB,0x9B,0x01,0xF9,0xAE,0xE2,0x02,0xED,0xF3,
1035 0x03,0xF5,0xEF,0xF0,0x04,0x05,0xE9,0x06,0x07,0x08,0x09,0xA0,0xE1,0xE5,0x0A,0x0B,
1036 0x19,0x1A,0xAD,0xBB,0xE2,0xEA,0xED,0xF2,0xFA,0xE6,0xEC,0x01,0x02,0x03,0x9B,0xF5,
1037 0x04,0xA7,0xF6,0xF9,0x05,0x06,0xEB,0xEF,0x07,0x08,0x09,0x0A,0xAC,0x0B,0x0C,0xE3,
1038 0xAE,0x0D,0xEE,0xE9,0x0E,0xE1,0x0F,0xF3,0x10,0x11,0xF4,0x12,0xE7,0xE5,0x13,0x14,
1039 0xE4,0x15,0x16,0x17,0xA0,0x18,0x1A,0x1B,0xC2,0x9B,0xAD,0xAC,0xF8,0x01,0xAE,0x02,
1040 0x03,0xE5,0xE7,0xE8,0xF9,0xE9,0xEB,0x04,0xE3,0xE1,0x05,0xF6,0x06,0xE4,0x07,0xE2,
1041 0xF0,0x08,0x09,0xF3,0xF4,0xF7,0xEF,0x0A,0x0B,0x0C,0x0D,0xEC,0x0E,0x0F,0x10,0xF5,
1042 0xED,0x11,0xE6,0xA0,0x12,0xF2,0x13,0x14,0x15,0xEE,0x16,0x17,0x18,0x19,0x0E,0x0F,
1043 0xAD,0xED,0xF9,0x9B,0xAE,0x01,0xF3,0x02,0x03,0xF5,0xF4,0xF0,0x04,0xEF,0x05,0xE9,
1044 0x06,0xE8,0xA0,0xE1,0xEC,0x07,0xF2,0x08,0xE5,0x09,0x0A,0x0B,0x0C,0x0D,0x9B,0xF5,
1045 0x19,0x1A,0xA9,0xBB,0xF6,0xE6,0x01,0x9B,0xAD,0xE2,0xF0,0x02,0xA7,0x03,0x04,0x05,
1046 0xF5,0xE3,0xAC,0xE7,0xF2,0x06,0xEB,0x07,0xEC,0xED,0xEE,0xF9,0x08,0xAE,0x09,0x0A,
1047 0xE4,0x0B,0x0C,0xF4,0x0D,0xF3,0x0E,0x0F,0x10,0xE1,0xEF,0x11,0xE9,0x12,0x13,0xE5,
1048 0x14,0xA0,0x15,0x16,0x17,0x18,0xA0,0x16,0xA2,0xA7,0xE2,0xEB,0xED,0xEE,0x9B,0xF7,
1049 0x01,0x02,0x03,0xBB,0xF9,0xF0,0x04,0x05,0xEC,0x06,0x07,0x08,0xF5,0xE1,0x09,0xAC,
1050 0xE3,0x0A,0xE8,0x0B,0xE9,0x0C,0xEF,0xF3,0xAE,0x0D,0x0E,0xE5,0x0F,0x10,0x11,0xF4,
1051 0x12,0x13,0x14,0x15,0x14,0x15,0xBB,0xE2,0xAD,0xED,0x01,0x9B,0xA7,0xE3,0xAC,0xEC,
1052 0xEE,0x02,0xF7,0x03,0x04,0xF9,0x05,0x06,0x07,0x08,0xF4,0xAE,0xF5,0x09,0x0A,0xF2,
1053 0xE1,0xF3,0x0B,0x0C,0x0D,0xE9,0x0E,0x0F,0xEF,0xE5,0x10,0xA0,0xE8,0x11,0x12,0x13,
1054 0x11,0x12,0xEF,0xF6,0x9B,0xEB,0xF9,0x01,0xA0,0xE2,0x02,0xE1,0x03,0xED,0x04,0xE3,
1055 0xE9,0x05,0xE4,0xE5,0xE7,0x06,0xEC,0xF0,0x07,0x08,0x09,0x0A,0x0B,0xF3,0x0C,0xF4,
1056 0xEE,0x0D,0xF2,0x0E,0x0F,0x10,0x05,0xE5,0xF3,0xF9,0x9B,0x01,0xEF,0x02,0x03,0xE1,
1057 0x04,0xE9,0x0A,0x0B,0xAE,0x9B,0xEC,0xED,0x01,0x02,0xF3,0xEE,0xF2,0x03,0xE5,0x04,
1058 0xE8,0xA0,0xE1,0x05,0xEF,0x06,0x07,0x08,0xE9,0x09,0x05,0x06,0xA0,0xAC,0xAD,0xF4,
1059 0xE9,0x01,0x02,0xE1,0xE5,0x03,0x9B,0x04,0x11,0xA0,0xBF,0xE1,0xE2,0xE6,0xED,0xE4,
1060 0xE9,0xF7,0xA7,0x01,0x02,0xBB,0x03,0x04,0xEC,0x05,0x9B,0xEE,0x06,0xEF,0x07,0xAC,
1061 0xE5,0xF3,0x08,0x09,0x0A,0xAE,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x06,0x07,0xA0,0xAE,
1062 0xE1,0xE5,0xEC,0xFA,0x9B,0xEF,0xE9,0x01,0x02,0x03,0x04,0x05,0x9B,0x9B,0x9B,0x9B,
1063 0x9B,0x9B,0x9B,0x9B,0x9B,0x9B,
1065 /************************************************************** ATSC HUFFMAN */
1067 /***************************** globals end **********************************/
1070 #include "common.h"
1072 #ifdef USE_BUFFER
1073 #include "buffer.h"
1074 static buf_t *in_buf;
1075 static buf_t *es_buf;
1076 static buf_t *out_buf;
1077 #endif
1079 /********************************************************************** CRC32
1080 * from ffmpeg
1082 static
1083 unsigned int
1084 calc_crc32( unsigned char *data, unsigned int len )
1086 unsigned int i;
1087 unsigned int crc = 0xffffffff;
1089 if (len > 4096) return ~0;
1091 for (i=0; i<len; i++)
1092 crc = (crc << 8) ^ crc_lut[ 0xFF & ((crc >> 24) ^ *data++) ];
1094 return crc;
1096 /******************************************************************** CRC32 */
1099 /************************************************************** HUFFMAN DECODE
1100 * huffman title and description text decode.
1101 * d destination needs 512 bytes in case source is 255 bytes
1103 static
1104 void
1105 huffman_decode( unsigned char *d, unsigned char *s, int dlen, int slen, int comp)
1107 unsigned char p, c, o, r;
1108 unsigned int *bo;
1109 unsigned char *co;
1110 unsigned int to, zo, z;
1111 unsigned int i, j, k;
1112 unsigned char b;
1113 unsigned char *t;
1115 t = d;
1116 // dprintf2( stdout, "\n Huffman L%02X C%02X\n", slen, comp );
1118 // sanity check
1119 if ((NULL == d) || (NULL == s)) { fprintf( stdout, "bad null\n"); return; }
1120 // if ((slen < 1) || (slen > 255)) { fprintf( stdout, "bad slen\n"); return; }
1121 // if ((dlen < 1) || (dlen > 255)) { fprintf( stdout, "bad dlen\n"); return; }
1122 if ((comp < 1) || (comp > 2))
1123 { fprintf( stdout, "bad compression mode %d\n", comp); return; }
1125 p = c = 0; // first char assumed to be NUL or term char
1127 bo = huffman1bo; // byte offset of char p tree root
1128 co = huffman1co; // char p order-1 tree
1129 z = TITLE_COZ; // table limit
1131 if (comp == 2) {
1132 bo = huffman2bo;
1133 co = huffman2co;
1134 z = DESCR_COZ;
1137 // should be pointing to correct tables now
1138 o = 0;
1139 for (i=0; i < (slen<<3); i++)
1141 // if (0 == (i%8)) dprintf2( stdout, "\ns[%d] = %02X\n", i>>3, s[i>>3] );
1142 // get tree offset for char p from order-1 tree byte offset table
1143 if (p > 127) { /* fault detection, don't stray outside table */
1144 fprintf( stdout, "BAD Huffman tree offset %02X\n", p);
1145 return;
1147 to = bo[ p ];
1148 // direction in tree from bit in compressed string
1149 // bit sets o to left(0) or right(1) for next branch or leaf
1150 b = s[ i >> 3 ] & (1 << (~i & 7));
1151 if (b != 0) b = 1; // force comparison result in b0
1152 // minimum of two linked-list lookups for shortest first order entry
1153 // such as common following letters, but most will be multiple lookups
1155 zo = to + (o<<1) + b;
1156 if (zo > z) { /* fault detection, don't stray outside table */
1157 fprintf( stdout, "BAD Huffman branch offset %04X\n", zo);
1158 return;
1160 // first entry has tree lookup to first order left/right choice tree
1161 o = co[ zo ]; // tree root offset is anchor for branches
1162 r = co[ zo ]; // o has branch, r has leaf or branch
1164 #ifdef DEMOTH
1165 if (0 == (128 & o)) {
1166 fprintf(stdout, "BRANCH s[%02X].%d %d pchr %02X toff %03X "
1167 "%s "
1168 "delta %d+%02X<<1 = [%02X]\n",
1169 i >> 3, ~i & 7, b, p, to,
1170 (b==0)?"LEFT ":"RIGHT",
1171 b, o, r );
1173 #endif
1175 if (0 != (128 & o) )
1177 c = 0x7F & o;
1179 #ifdef DEMOTH
1180 if ( c != 27)
1181 fprintf( stdout,"LEAF s[%02X].%d %d pchr %02X toff %03X "
1182 "chr %02X [%c] ",
1183 i >> 3, ~i & 7, b, p, to, c, (c<32)?' ':c);
1184 #endif
1185 if ( c == 27 )
1187 // handle Escape to 8 bit mode
1188 i++; // point to msb of bytes
1189 j = i & 7;
1190 k = 8 - j;
1191 // get current byte
1192 c = s[ i >> 3 ];
1193 // shift needed?
1194 if (0 != j) {
1195 c <<= j;
1196 b = s[ (i >> 3) + 1];
1197 b >>= k;
1198 c |= b;
1200 i += 7; // skip past lsb of byte
1202 #ifdef DEMOTH
1203 fprintf( stdout, "ESCAPE s[%02X].%d j %d k %d chr %02X [%c] ",
1204 i>>3, ~i & 7, j, k, c, c );
1205 #endif
1209 p = c; // c leaf becomes new index for order-1 tree root offset
1210 o = 0; // clear offset to order-1 tree
1211 *t = c;
1212 dlen--;
1213 if (dlen < 1) {
1214 *d = 0;
1215 break;
1216 } // out of space gets nul term
1218 t++; // else move to next char
1220 // nul term stops loop
1221 if ( c == 0 ) {
1222 #ifdef DEMOTH
1223 fprintf( stdout, "TERM\n");
1224 #endif
1225 break;
1227 #ifdef DEMOTH
1228 fprintf( stdout, "\n");
1229 #endif
1232 #ifdef DEMOTH
1233 fprintf( stdout, "Huffman done: [%s]\n", d );
1234 #endif
1238 // atsc picture user data embedded into MPEG video stream
1239 // has cc data and bar data only according to a53c_amend1
1240 // bar data has letter/pillar box settings, but haven't seen bar data yet.
1241 // cc data is seen in at least some, if not most, streams.
1243 static
1244 void
1245 test_ap_user_data( unsigned char *p )
1247 if ((3 != p[4]) && (6 != p[4])) {
1248 mprintf4( stdout, "ATSC user data type %02X unknown\n", p[4]);
1249 return; // other types ?
1252 mprintf4( stdout, "ATSC User Data ID [%c%c%c%c] Type %02X: ",
1253 p[0], p[1], p[2], p[3], p[4]);
1255 /* cc data does exist in some streams. */
1256 /* looks like 24bits in a list terminated by 0x0000FF */
1257 if (3 == p[4]) {
1258 unsigned int i, b;
1259 mprintf4( stdout, "Closed Caption\n ");
1260 p += 5;
1261 for (i = 0; i<63; ) { /* 63 bytes, 21 triplets */
1262 b = (p[i]<<16) | (p[i+1]<<8) | p[i+2];
1264 /* start code? */
1265 if (1 == b) break;
1266 mprintf4( stdout, "%06X ", b );
1267 i += 3;
1268 if (0 == (i%8)) mprintf4( stdout, "\n " );
1270 mprintf4( stdout, "\n" );
1273 // letter/pillar box settings is in bar data if exists
1274 if (6 == p[4]) {
1275 mprintf4( stdout, "Bar Data\n" );
1280 static
1281 void
1282 test_mpeg2_group_of_pictures( unsigned char *r )
1284 unsigned char df, h, m, s, p, cg, bl;
1286 df = h = m = s = p = cg = bl = 0;
1288 /* did atscap vc cap subvert timecode into sequence start counter? */
1289 if ( 0xFF == r[0] ) {
1290 int gopx = 0;
1291 /* yes */
1292 gopx = 0xFFFF & ((r[1]<<8) | r[2]);
1293 mprintf4( stdout, "GOPX: %5d\n", gopx);
1294 return;
1297 /* no, full cap or different origin than atscap/pchdtvr */
1298 if (r[1] & 8) {
1299 df = r[0] >> 7; // 1 bit drop flag
1300 h = 0x1F & (r[0] >> 2); // 5 bits hours
1301 m = 0x3F & ((r[0] << 4) | (r[1] >> 4)); // 6 bits minutes
1302 s = 0x3F & ((r[1] << 3) | (r[2] >> 5)); // 6 bits seconds
1303 p = 0x3F & ((r[2] << 1) | (r[3] >> 7));
1305 cg = 1 & (r[3]>>6);
1306 bl = 1 & (r[3]>>5);
1308 mprintf4( stdout, " TC HMSP: %02d:%02d:%02d:%02d\n",
1309 h,m,s,p);
1310 mprintf4( stdout, " Drop flag %d Closed GOP %d Broken Link %d\n",
1311 df, cg, bl);
1314 /* returns picture type index */
1315 static
1317 test_mpeg2_picture( unsigned char *r )
1319 unsigned short tr, vbvd;
1320 unsigned char pct; /* picture type */
1321 unsigned char *pt;
1322 unsigned int br;
1324 br = 0;
1325 pt = "Reserved"; // picture text
1326 tr = (r[0]<<2) | (r[1]>>6); // 10 bits temporal reference
1327 pct = 7 & (r[1]>>3); // picture type
1328 vbvd = ((7 & r[1])<<13) | (r[2]<<5) | (r[3]>>3); // vbv delta
1329 if (0 == pct) pt = "Forbidden";
1331 /* is Intra frame ? */
1332 if (1 == pct) {
1334 memset( ipb, 0, sizeof(ipb));
1335 ipbx = 0;
1336 ipb[ipbx++] = 'I';
1338 pt = "I";
1339 // check delta to compute bit rate
1340 // 2 I-frames per second, 8 bits in 188 byte packets
1341 br = 3008 * (pkt.count - pkt.pcount); // 2 * 8 * 188 * pkt diff
1342 sumrate += br;
1343 iframe++;
1344 iframen++;
1346 // reset to avoid overflow
1347 if (sumrate > 1500000000) {
1348 sumrate = sumrate / iframe;
1349 iframe = 1;
1351 // set for next delta
1352 pkt.pcount = pkt.count;
1354 if (2 == pct) {
1355 ipb[ipbx++] = 'P';
1356 pt = "P";
1358 if (3 == pct) {
1359 ipb[ipbx++] = 'B';
1360 pt = "B";
1363 if (4 == pct) {
1364 pt = "D?"; // mpeg1 only
1367 mprintf4( stdout, " %s Temporal %2u VBVd %5u\n", pt, tr, vbvd);
1369 if (1 == pct) {
1370 unsigned char brt[32];
1371 lltoasc( brt, br ); // dont forget to free()
1372 mprintf4( stdout, " I Frame # %5d Rate is %s bits/second, avg %d\n",
1373 iframen, brt, sumrate/iframe);
1376 return pct;
1379 /* tally up the slices */
1380 static
1381 void
1382 test_mpeg2_slice( unsigned char *r )
1384 /* does nothing for now */
1385 return;
1388 /* PES Packetized Elementary Stream info, where are found PTS and DTS.
1389 Presentation Time Stamp is when data is to be displayed.
1390 Deccoder Time Stamp is when data is to be ready for display.
1391 These are related to PCR in the AFC */
1392 static
1393 void
1394 test_mpeg2_video_pes( unsigned char *p )
1396 unsigned char *r, pscf, ppri, daif, crif, oocf,
1397 ptsf, escf, esrf, dtmf, acif, pcrf, pexf,
1398 peshl, d, h, m, s;
1399 unsigned short ppl; // spec needs to make this 32 bits and use it
1401 unsigned long long pts;
1402 unsigned long long dts;
1403 unsigned int rts;
1405 ppl = (p[4]<<8) | p[5]; // always 0?
1407 r = p + 6; // skip header ID and always 0 len, already shown
1408 pscf = 3 & (*r>>4); // r[6] b5:4
1409 ppri = 1 & (*r>>3);
1410 daif = 1 & (*r>>2);
1411 crif = 1 & (*r>>1);
1412 oocf = 1 & *r;
1414 mprintf4( stdout, " PES plen %04X, dlen %02X, flags %04X:\n ",
1415 ppl, r[2], (r[0]<<8) | r[1]);
1417 if ( 0 != pscf ) mprintf4( stdout, "Scramble%d, ", pscf);
1418 if ( 0 != ppri ) mprintf4( stdout, "Priority, ");
1419 if ( 0 != daif ) mprintf4( stdout, "Align, " );
1420 if ( 0 != crif ) mprintf4( stdout, "(c), " );
1421 if ( 0 != oocf ) mprintf4( stdout, "Original, ");
1422 // mprintf4( stdout, "\n");
1424 r++;
1425 ptsf = 3 & (*r>>6); // r[7] b7:6
1426 escf = 1 & (*r>>5);
1427 esrf = 1 & (*r>>4);
1428 dtmf = 1 & (*r>>3);
1429 acif = 1 & (*r>>2);
1430 pcrf = 1 & (*r>>1);
1431 pexf = 1 & *r;
1433 if (2 == ptsf) mprintf4( stdout, "PTS " );
1434 if (3 == ptsf) mprintf4( stdout, "PTS DTS ");
1436 if (0 != escf) mprintf4( stdout, "ESCR, " );
1437 if (0 != esrf) mprintf4( stdout, "ESRate, ");
1438 if (0 != dtmf) mprintf4( stdout, "DSM, " );
1439 if (0 != acif) mprintf4( stdout, "(c)+, " );
1440 if (0 != pcrf) mprintf4( stdout, "CRC, " );
1441 if (0 != pexf) mprintf4( stdout, "EXT, " );
1442 mprintf4( stdout, "\n");
1444 r++;
1445 peshl = *r;
1447 r++;
1449 // pts only?
1450 if (2 == ptsf) {
1451 // check pts marker bits
1452 if ( (0x21 == (0xF1 & r[0])) && (1 & r[2]) && (1 & r[4]) ) {
1453 pts = 0;
1454 pts |= (7 & (*r >> 1)) << 30; // 32..30
1455 r++;
1456 pts |= *r << 22; // 29..22
1457 r++;
1458 pts |= (*r>>1) << 15; // 21..15
1459 r++;
1460 pts |= *r << 7; // 14..7
1461 r++;
1462 pts |= *r>>1; // 6..0
1463 r++;
1464 pts &= 0x1FFFFFFFFLL;
1466 rts = pts / 90000;
1467 s = rts % 60;
1468 m = ( rts / 60 ) % 60;
1469 h = ( rts / 3600) % 24;
1470 d = ( rts / 86400);
1471 mprintf4( stdout, " PTS %01d:%02u:%02u:%02u.%llu\n",
1472 d, h, m, s, pts % 90000 );
1477 // pts and dts?
1478 if (3 == ptsf) {
1479 // check pts marker bits
1480 if ( (0x31 == (0xF1 & r[0])) && (1 & r[2]) && (1 & r[4]) ) {
1481 pts = 0;
1482 pts |= (7 & (*r >> 1)) << 30; // 32..30
1483 r++;
1484 pts |= *r << 22; // 29..22
1485 r++;
1486 pts |= (*r>>1) << 15; // 21..15
1487 r++;
1488 pts |= *r << 7; // 14..7
1489 r++;
1490 pts |= *r>>1; // 6..0
1491 r++;
1492 pts &= 0x1FFFFFFFFLL;
1494 rts = pts / 90000;
1495 s = rts % 60;
1496 m = ( rts / 60 ) % 60;
1497 h = ( rts / 3600) % 24;
1498 d = ( rts / 86400);
1499 mprintf4( stdout, " PTS %01d:%02u:%02u:%02u.%llu",
1500 d, h, m, s, pts % 90000 );
1502 // check dts marker bits
1503 if ( (0x11 == (0xF1 & r[0])) && (1 & r[2]) && (1 & r[4]) ) {
1504 dts = 0;
1505 dts |= (7 & (*r >> 1)) << 30; // 32..30
1506 r++;
1507 dts |= *r << 22; // 29..22
1508 r++;
1509 dts |= (*r>>1) << 15; // 21..15
1510 r++;
1511 dts |= *r << 7; // 14..7
1512 r++;
1513 dts |= *r>>1; // 6..0
1514 r++;
1515 dts &= 0x1FFFFFFFFLL;
1517 rts = dts / 90000;
1518 s = rts % 60;
1519 m = ( rts / 60 ) % 60;
1520 h = ( rts / 3600) % 24;
1521 d = ( rts / 86400);
1522 mprintf4( stdout, " DTS %01d:%02u:%02u:%02u.%llu",
1523 d, h, m, s, dts % 90000 );
1527 mprintf4( stdout, "\n");
1530 mprintf4( stdout, "\n");
1533 /* tests up to vid.payoff only, p is payload */
1534 static
1535 void
1536 test_mpeg2_video_seq( unsigned char *p, int len )
1538 unsigned int b, i;
1539 b = 0xFFFFFFFF;
1541 // for (i = 0; i < vid.payoff; i++ )
1542 for (i=0; i < len; i++) /* only first packet, after AFC to save cycles */
1544 unsigned char pct;
1545 b = (b<<8) | p[i];
1546 switch (b) {
1548 /* Sequence Start code means this payload has:
1549 [optional GOP] and I-Frame
1551 case 0x1B3:
1552 // fprintf( stdout, "Sequence header @ %llX\n", bytes_in-188);
1554 /* what about pkt.vid * 188 ? not as fast... */
1555 sequences[ sequence_idx++ ] = bytes_in - 188;
1557 /* NOTE, if running out of sequences, probably running out of frames, too */
1558 if (sequence_idx >= SEQUENCE_MAX) {
1559 fprintf( stderr,
1560 "\n FATAL: sequence_idx exceeds SEQUENCE_MAX.\n"
1561 "Recompile with larger FRAME_MAX.\n");
1562 exit(1);
1565 /* in case quantizer table(s) (+256 bytes possible) pork up first packet,
1566 bump frame counter for Intra frame type and consider it counted,
1567 because we don't want to spend a lot of cycles looking for it.
1569 frames[ frame_idx ].pct = 1;
1570 frames[ frame_idx ].vpn = pkt.vid;
1571 frame_idx++;
1572 if (frame_idx >= FRAME_MAX) {
1573 fprintf( stderr,
1574 "\n FATAL: frame_idx exceeds FRAME_MAX.\n"
1575 "Recompile with larger FRAME_MAX.\n");
1576 exit(1);
1578 break;
1580 /* some stations send a few quantizer tables in the sequence header.
1581 have seen where this test will fail on good Intra frame because it's not
1582 in 1st packet, or only has a few bytes of start code in 1st packet.
1584 /* Picture Start code means this is I P or B frame */
1585 case 0x100:
1586 pct = 7 & (p[i+2] >> 3);
1588 /* Intra frame treated above in case too far to find in first packet.
1589 P and B frames won't have quantizer table(s) porking up the first packet,
1590 so ok to check for them.
1592 if (1 == pct)
1593 return;
1594 /* save cycles, Intra frame already counted */
1596 frames[ frame_idx ].pct = pct;
1597 frames[ frame_idx ].vpn = pkt.vid;
1598 frame_idx++;
1599 if (frame_idx >= FRAME_MAX) {
1600 fprintf( stderr,
1601 "\n FATAL: frame_idx exceeds FRAME_MAX.\n"
1602 "Recompile with larger FRAME_MAX.\n");
1603 exit(1);
1606 /* save cycles by not looking past picture start */
1607 return;
1610 break;
1612 default:
1613 break;
1618 /**************************************************** MPEG2 ELEMENTARY VIDEO */
1619 /* this is full parse/display of video es, truncated by arg_mdump bits */
1620 /* NOTE: vid.payload needs to be large enough to handle the largest I-frames,
1621 but small enough to fit in CPU cache for performance reasons. */
1622 static
1623 void
1624 test_mpeg2_video_es ( void )
1626 int i, j, k;
1627 unsigned int b;
1628 unsigned char *frt, *art, *xidt, *p, c;
1629 unsigned short hz, vz, vbvz;
1630 unsigned int brv;
1631 unsigned char ari, frc, cpf, iqm, niqm, xid, qmf;
1632 unsigned long long iqr, niqr;
1634 unsigned char sn, sm, sp; /* slice number, slice max Vsize/16 */
1635 unsigned char sc[176]; /* slice checklist up to slice 0xB0 */
1637 char *ptt[8] = { "Forbidden","I","P","B","D?","","","" };
1638 int pti = 0;
1640 sn = sm = sp = 0;
1641 memset( sc, 0, sizeof(sc));
1642 /* unsigned long long ciqr, cniqr; / / quantizer matrix row value */
1644 b = 0xFFFFFFFF; /* zeros could give false start indication */
1645 p = vid.payload;
1647 frt = "*unparsed*";
1649 k = vid.payoff;
1651 /* speed up header search, but needs to be 256 for quantizer table max,
1652 plus anticipated size of other headers, maybe 384 is enough.
1653 otherwise, don't call this at all to speed it up even more.
1655 for (i = 0; i < k; i++) {
1656 c = p[i];
1657 b = (b << 8) | p[i];
1658 /* valid start code? */
1659 if (0x00000100 == (0xFFFFFF00 & b)) {
1661 // mprintf4( stdout, " STC %09llX: %08X ", (ppsbytes_in-184) + (i-3), b);
1663 /* Sequence Header */
1664 if (0xB3 == c) {
1665 i++;
1666 mprintf4( stdout,
1667 "Sequence Start # %5d [below has last IPB]\n",
1668 sequence_idx-1 );
1670 if (0 == (0x20 & p[i+6])) {
1671 mprintf4( stdout, "Marker bit not set, skipping\n");
1672 continue;
1675 ipb[64] = 0;
1676 if (0 != ipb[0])
1677 mprintf8( stdout, "SEQ # %5d [%-64s]\n",
1678 sequence_idx-2, ipb );
1680 /* mprintf4( stdout, "\n"); */
1682 hz = 0xFFF & ( (p[i+0] << 4) | (p[i+1] >> 4) ); // 3 nybs
1683 vz = 0xFFF & ( (p[i+1] << 8) | p[i+2] ); // 3 nybs
1685 sm = vz / 16; /* slice max is vsize / 16 */
1687 ari = p[i+3] >> 4; // hi nyb
1688 art = "Reserved";
1689 if (0 == ari) art = "Forbidden";
1690 if (1 == ari) art = "Square";
1691 if (2 == ari) art = "4:3";
1692 if (3 == ari) art = "16:9";
1693 if (4 == ari) art = "2.21:1";
1696 frc = 15 & p[i+3]; // low nyb
1697 frt = "Reserved";
1698 if (0 == frc) frt = "Forbidden";
1699 if (1 == frc) frt = "23.976 FPS";
1700 if (2 == frc) frt = "24 FPS";
1701 if (3 == frc) frt = "25 FPS";
1702 if (4 == frc) frt = "29.97 FPS";
1703 if (5 == frc) frt = "30 FPS";
1704 if (6 == frc) frt = "50 FPS";
1705 if (7 == frc) frt = "59.94 FPS";
1706 if (8 == frc) frt = "60 FPS";
1708 // sanity limit silly shifter tricks for 18 bit number
1709 brv = 0x3FFFF & ( (p[i+4]<<10) | (p[i+5]<<2) | (p[i+6]>>6) );
1710 // more oddball offsets
1711 vbvz = 0x3FF & ( (p[i+6]<< 5) | ( p[i+7]>> 3) );
1712 // quantizer matrices load offset 1 bit left
1713 // spec looks to allow intra and/or non intra load
1714 // so last bit of intra for non-intra flag makes it even
1715 cpf = 1 & (p[i+7] >> 2); // constrained parameters flag
1717 i += 7; // skip to byte with first bit of quantizer table
1718 mprintf4( stdout,
1719 " Horizontal %u Vertical %u Aspect %s Frame Rate %s\n"
1720 " Bit Rate %u VBVz %u CPF %u\n",
1721 hz, vz, art, frt, brv * 400, vbvz * 2048, cpf );
1723 iqm = 1 & (p[i] >> 1); // intra quantizer matrix present
1724 // may have bit shifts wrong for both of these
1725 if (1 == iqm) {
1726 mprintf4( stdout, " Intra Quantizer Matrix\n");
1727 // don't care about the values particularly
1728 // but could show what a pain in the ass it is
1729 for (j=0; j < 8; j++) {
1730 iqr = (long long)(1 & p[i])<< 63; // 63
1731 iqr |= (long long)p[i+1]<<55; // 62 61 60 59 . 58 57 56 55
1732 iqr |= (long long)p[i+2]<<47; // 54 53 52 51 . 50 49 48 47
1733 iqr |= (long long)p[i+3]<<39; // 46 45 44 43 . 42 41 40 39
1734 iqr |= (long long)p[i+4]<<31; // 38 37 36 35 . 34 33 32 31
1736 iqr |= (long long)p[i+5]<<23; // 30 29 28 27 . 26 25 24 23
1737 iqr |= (long long)p[i+6]<<15; // 22 21 20 19 . 18 19 16 15
1738 iqr |= (long long)p[i+7]<<7; // 14 13 12 11 . 10 9 8 7
1739 iqr |= (long long)p[i+8]>>1; // 6 5 4 3 2 1 0
1741 mprintf4( stdout, " %016llX\n", iqr);
1742 i += 8;
1746 niqm = 1 & p[i];
1747 if (1 == niqm) {
1748 mprintf4( stdout, " Non-intra Quantizer Matrix\n");
1749 // don't care about the values particularly
1750 // this one is easier because the bits line up
1751 for (j=0; j < 8; j++) {
1752 niqr = (long long)(1 & p[i]) << 56; // 63-56
1753 niqr |= (long long)p[i+1] << 48; // 55-48
1754 niqr |= (long long)p[i+2] << 40; // 47-40
1755 niqr |= (long long)p[i+3] << 32; // 39-32
1756 niqr |= (long long)p[i+4] << 24; // 31-24
1757 niqr |= (long long)p[i+5] << 16; // 23-16
1758 niqr |= (long long)p[i+6] << 8; // 15-8
1759 niqr |= (long long)p[i+7]; // 7-0
1760 mprintf4( stdout, " %016llX\n", niqr);
1761 i += 8;
1763 }; // p was adjusted above
1765 if (0 == (iqm | niqm)) {
1766 mprintf4( stdout, " ERROR: No Quantizer Matrix\n");
1768 // it's a bit convoluted after this, see mscan.c
1769 continue; // find next start code
1772 // Extension Start Code for Sequence or Picture extensions
1773 if (0xB5 == c)
1775 xidt = "Reserved";
1776 xid = p[i+1]>>4; // 1-A see 13818-2 table 6-2
1777 mprintf4( stdout, "Extension ID (%1X): ", xid);
1779 if (1 == xid)
1781 unsigned char prid, lvid, vbze; // 3,4,8 bits
1782 unsigned char cf, hze, vze, frn, frd; // 2 bits
1783 unsigned short bre; // 12 bits
1784 unsigned char lod, ps; // 1 bit
1785 unsigned char *cft, *prit, *lvit; // chroma profile lvl
1786 i++;
1787 xidt = "Sequence";
1788 mprintf4( stdout, "%s\n", xidt);
1789 if (1 & p[i+3]) {
1790 prid = 0x7 & p[i];
1791 prit = "Reserved";
1792 if (1 == prid) prit = "High";
1793 if (2 == prid) prit = "Spatially Scalable";
1794 if (3 == prid) prit = "SNR Scalable";
1795 if (4 == prid) prit = "Main";
1796 if (5 == prid) prit = "Simple";
1798 lvid = p[i+1] >> 4;
1799 lvit = "Reserved";
1800 if ( 4 == lvid) lvit = "High";
1801 if ( 6 == lvid) lvit = "High 1440";
1802 if ( 8 == lvid) lvit = "Main";
1803 if (10 == lvid) lvit = "Low";
1805 ps = 1 & (p[i+1] >> 3); // 1 bit progressive sequence
1807 cft = "Reserved";
1808 cf = 3 & (p[i+1] >> 1); // 2 bits chroma format
1809 if (1 == cf) cft = "4:2:0";
1810 if (2 == cf) cft = "4:2:2";
1811 if (3 == cf) cft = "4:4:4";
1813 hze = ((1 & p[i+1]) << 1) | (p[i+2] >> 7);
1814 vze = 3 & (p[i+2] >> 5);
1815 bre = 0xFFF & ( (p[i+2] << 7) | (p[i+3] >> 1) );
1816 vbze = p[i+4];
1817 lod = p[i+5] >> 7;
1818 frn = 3 & p[i+5] >> 5;
1819 frd = 31 & p[i+5];
1820 mprintf4( stdout, " Profile %s, Level %s, Progressive %0X, Chroma %s\n",
1821 prit, lvit, ps, cft);
1822 mprintf4( stdout, " HX %0X, VX %0X, BRX %03X, VBVZX %02X Low delay %0X FRXn %0X, FRXd %02X\n",
1823 hze, vze, bre, vbze, lod, frn, frd);
1824 i += 5;
1826 continue;
1829 if (2 == xid)
1831 unsigned char vf, cd, cp, tc, mc;
1832 unsigned short dhz, dvz;
1833 unsigned char *vft;
1834 xidt = "Sequence Display";
1835 i++;
1837 cp = tc = mc = 0;
1839 vf = 7 & (p[i]>>1);
1840 vft = "Reserved";
1841 if (0 == vf) vft = "Component";
1842 if (1 == vf) vft = "PAL";
1843 if (2 == vf) vft = "NTSC";
1844 if (3 == vf) vft = "SECAM";
1845 if (4 == vf) vft = "MAC";
1846 if (5 == vf) vft = "Unspecified";
1847 mprintf4( stdout, "%s\n", xidt);
1848 mprintf4( stdout, " Video Format %s ", vft );
1850 cd = 1 & p[i];
1851 i++;
1853 if (1 == cd) {
1854 cp = p[i++];
1855 tc = p[i++];
1856 mc = p[i++];
1858 if (2 == (2 & p[i+1])) {
1859 dhz = (p[i]<<6) | (p[i+1]>>2);
1860 dvz = ((1 & p[i+1]) << 13) | (p[i+2]<<5) | (31 & p[i+3]>>3);
1861 mprintf4( stdout, "Horizontal %u Vertical %u\n", dhz, dvz);
1864 if (1 == cd) {
1865 mprintf4( stdout, " Color Primaries %02X, Transfer Chars %02X, Matrix Co-effs %02X\n", cp, tc, mc);
1866 } else {
1867 mprintf4( stdout, " Colors, Transfer, and Matrix Coefficients follow ITU-R BT.709\n");
1870 i += 4;
1871 continue;
1874 if (3 == xid) {
1875 i++;
1876 xidt = "None";
1877 qmf = 0x0F & p[i];
1878 if ( 0 != (8 & qmf)) xidt = "Intra";
1879 if ( 0 != (4 & qmf)) xidt = "Non-Intra";
1880 if ( 0 != (2 & qmf)) xidt = "Chroma Intra";
1881 if ( 0 != (1 & qmf)) xidt = "Chroma Non-Intra";
1883 mprintf4( stdout, "Quantizer Matrix Type %d:\n", qmf);
1885 if (qmf == 0) continue;
1887 mprintf4( stdout, " %s:\n", xidt);
1888 for (j=0; j<8; j++) {
1889 iqr = (long long)(7 & p[i])<< 60; // 63 62 61
1890 iqr |= (long long)p[i+1]<<52; // 60 . 59 58 57 56 . 55 54 53
1891 iqr |= (long long)p[i+2]<<44; // 52 . 51 50 49 48 . 47 46 45
1892 iqr |= (long long)p[i+3]<<36; // 44 . 43 42 41 40 . 39 38 37
1893 iqr |= (long long)p[i+4]<<28; // 36 . 35 34 33 32 . 31 30 29
1895 iqr |= (long long)p[i+5]<<20; // 28 . 27 26 25 24 . 23 22 21
1896 iqr |= (long long)p[i+6]<<12; // 20 . 19 18 19 16 . 15 14 13
1897 iqr |= (long long)p[i+7]<<4; // 12 . 11 10 9 8 . 7 6 5
1898 iqr |= (long long)p[i+8]>>3; // 4 . 3 2 1 0
1899 mprintf4( stdout, " %016llX\n", iqr);
1900 i += 9;
1902 continue;
1905 if (4 == xid) {
1906 xidt = "Copyright";
1909 if (5 == xid) {
1910 xidt = "Sequence Scalable";
1913 if (7 == xid) {
1914 xidt = "Picture Display";
1917 if (8 == xid) {
1918 unsigned char fh, fv, bh, bv, idcp, ps, tff, fpfd;
1919 unsigned char cmv, qst, ivf, as, rff, c420, pf, cdf;
1920 unsigned char *pst;
1921 xidt = "Picture Coding";
1922 mprintf4( stdout, "%s\n", xidt);
1923 i++;
1924 fh = 0x0F & p[i];
1925 fv = p[i+1]>>4;
1926 bh = 0x0F & p[i+1];
1927 bv = p[i+2]>>4;
1929 idcp = 3 & p[i+2]>>2;
1931 ps = 3 & p[i+2];
1932 pst = "Reserved";
1933 if (1 == ps) pst = "Top Field";
1934 if (2 == ps) pst = "Bottom Field";
1935 if (3 == ps) pst = "Frame";
1937 mprintf4( stdout,
1938 " Forward Horizontal %2d Forward Vertical %2d\n"
1939 " Backward Horizontal %2d Backward Vertical %2d\n"
1940 " Intra DC Precision %d bits, Picture Structure %s\n",
1941 fh, fv, bh, bv, idcp+8, pst);
1943 tff = 1 & p[i+3]>>7;
1944 fpfd = 1 & p[i+3]>>6;
1945 cmv = 1 & p[i+3]>>5;
1946 qst = 1 & p[i+3]>>4;
1947 ivf = 1 & p[i+3]>>3;
1948 as = 1 & p[i+3]>>2;
1949 rff = 1 & p[i+3]>>1;
1950 c420 = 1 & p[i+3];
1952 pf = 1 & p[i+4]>>7;
1953 cdf = 1 & p[i+4]>>6;
1955 mprintf4( stdout,
1956 " Top Field First %d Frame Predict DCT %d Concealment Vectors %d\n"
1957 " Quantizer scale %d Intra-vlc format %d Alternate Scan %d\n"
1958 " Repeat First Field %d Chroma420 %d Progressive %d Composite %d\n",
1959 tff, fpfd, cmv, qst, ivf, as, rff, c420, pf, cdf
1963 // don't see these
1964 if (cdf != 0) {
1965 // v_axis:1 field_seq:3 sub_carrier:1 burst_amplitude:7 sub_carrier_phase:8
1967 i += 5;
1968 continue;
1971 if (9 == xid) xidt = "Picture Spatial Scalable";
1972 if (10== xid) xidt = "Picture Temporal Scalable";
1973 mprintf4( stdout, "%s: NOT PARSED\n", xidt);
1974 i++;
1975 continue; // find next start code
1976 } // end of sequence extensions
1979 /* Group Of Pictures */
1980 if (0xB8 == c) {
1981 mprintf4( stdout, "Group Of Pictures: ");
1982 test_mpeg2_group_of_pictures( p + i + 1 );
1983 continue; // find next start code
1986 /* picture start? */
1987 if (0 == c) {
1988 mprintf4( stdout, "Picture ");
1989 pti = test_mpeg2_picture( p + i + 1 );
1990 memset( sc, 0, sizeof(sc) ); /* clear slice checklist */
1991 sp = 0;
1992 continue;
1995 /* ATSC User Data, Closed Caption or Bar data, only seeing CC */
1996 if (0xB2 == c) {
1997 test_ap_user_data( p + i + 1 );
1998 i += 6;
1999 continue; // find next start code, dont parse two above
2002 /* MPEG video starts with E0 to E7 or EF? */
2003 if (0xE0 == (0xF0 & c)) {
2004 mprintf4( stdout,
2005 "MPEG Video PES Header, stream ID %02X\n", p[i]);
2006 test_mpeg2_video_pes( p );
2007 i++;
2008 continue;
2011 // slice macroblocks? only if arg_mdump & 4
2012 if ( (c > 0) && (c < 0xB0) ) {
2013 sn = c; /* slice number */
2015 if (0 != (16 &arg_mdump)) {
2016 mprintf5( stdout, " STC %09llX: %08X ",
2017 (ppsbytes_in-184) + (i-3), b);
2018 mprintf5( stdout,
2019 "Slice %02X Macroblock Pixel Rows %u - %u\n",
2020 sn, (sn - 1) << 4, 15 + ((sn - 1) << 4) );
2021 } else {
2022 if (1 == sn) mprintf4( stdout,
2023 " Slice Macroblocks follow\n");
2026 /* doesn't do much, not doing video decoder here */
2027 test_mpeg2_slice( p + i + 1 );
2029 /* TESTME: how do you know the slices are over if last few missing? */
2030 /* also, there could be multiple slices per macroblock row */
2032 if ((sn != sp+1) && (sn != sp)){
2033 /* slice sequence error */
2034 mprintf5( stdout, " Slice not in sequence\n");
2036 sp = sn;
2038 if (0 != sm) { /* seq sets sm, pic clears sc[] */
2039 sc[sn] = sn;
2040 if (sn == sm) { /* last slice found, are any missing? */
2042 sc[0] = 0; /* reset tally */
2043 for (j = 1; j <= sm; j++) {
2044 if (0 != sc[j]) sc[0]++;
2046 /* print list of missing slices, if any missing */
2047 if (sc[0] != sm) {
2048 mprintf5( stdout, "Missing slices: ");
2049 for (j = 1; j <= sm; j++)
2050 if (0 == sc[j])
2051 mprintf5( stdout, "%u ", j );
2052 mprintf5( stdout, "\n");
2053 } else {
2054 char *t = "";
2055 if (vid.payoff > (128 << 20)) t = "*";
2056 mprintf5( stdout, "Slice checklist OK %s-Frame "
2057 "payload size %d %s\n",
2058 ptt[pti], vid.payoff, t );
2062 continue;
2065 /* Sequence End. Have seen it trigger on network to local bug,
2066 but it's not reliable enough to use for cutting
2068 if (0xB7 == c) {
2069 pkt.seqend++;
2070 mprintf4( stdout, "Sequence End #%d\n", pkt.seqend);
2071 continue; // find next start code
2074 mprintf4( stdout, " STC %09llX: %08X NOT PARSED\n",
2075 ppsbytes_in + (i-3), b);
2078 mprintf4( stdout, "\n");
2081 /////////////////////////////////////////////////////////////////// MPEG2
2082 // MPEG2 payload related, usefulness yet to be determined.
2083 // afc 2 is afc only
2084 // afc 3 is afc, then payload afterwards
2085 // should precede payload on any packet with afc 3
2086 // ATSC packets should not see these, as there is no need
2087 // all of this is Too Much Information For This Application
2088 static
2089 void
2090 test_mpeg2_adaptation_field( unsigned char *p )
2092 unsigned char *r;
2093 unsigned char afl, di, rai, espi, sp, tpd;
2094 unsigned char afx = 0;
2095 unsigned long long npcr, opcr, pcrb, opcrb, pwr, dtsnau;
2096 unsigned long long pcrd, px, py;
2097 // unsigned long long pcrt;
2098 unsigned short pcrx, opcrx;
2099 char sc; // splice countdown is signed
2100 unsigned char tpdl;
2101 unsigned char afb, afxl, ltw, pwrf, ssf, ltwv, ltwo, st;
2103 unsigned char pd, ph, pm, ps; // pcr d h m s
2104 unsigned int pr, pw; // pcr remainder, pcr wall time
2106 pcrb = opcrb = pwr = dtsnau = pcrx = opcrx = 0;
2108 ph = pm = ps = pr = pw = 0;
2110 r = p + 4; // adaptation field starts immediately after continuity counter
2112 afl = *r;
2113 r++; // adaptation field length is always first byte after cc
2114 afb = *r;
2116 if (afl == 0) return; // nothing to do
2118 di = 0x80 & afb; // discontinuity if set
2119 rai = 0x40 & afb; // random access if set
2120 espi = 0x20 & afb; // elementary stream priority if set
2122 npcr = 0x10 & afb; // has new program clock reference
2123 opcr = 0x08 & afb; // has original program clock reference
2125 sp = 0x04 & afb; // has splicing point
2126 tpd = 0x02 & afb; // has transport private data
2127 afx = 0x01 & afb; // has adaptation field extension (decoder time stamps)
2130 // besides pcr, main reason for parsing down this far
2131 // random access indicator may be smoothest cut-in/out point
2132 mprintf4( stdout, "\n MPEG Adaptation Field (%02X) FLAGS:", afb);
2133 if (0 == afb) mprintf4( stdout, " NONE");
2134 if (0 != di) mprintf4( stdout, " DI");
2135 if (0 != rai) mprintf4( stdout, " RAI");
2136 if (0 != espi) mprintf4( stdout, " ESPI");
2137 if (0 != npcr) mprintf4( stdout, " PCR");
2138 if (0 != opcr) mprintf4( stdout, " OPCR");
2139 if (0 != sp) mprintf4( stdout, " SP");
2140 if (0 != tpd) mprintf4( stdout, " TPD");
2141 if (0 != afx) mprintf4( stdout, " AFX");
2143 mprintf4( stdout, "\n");
2145 // parsing some but not keeping anything but pcr and opcr
2146 // r steps forward with each section done, in spec order
2147 r++;
2149 // these should be done in the right order
2150 // program clock reference, main mpeg system clock
2151 if (0 != npcr) {
2152 unsigned int rb;
2153 rb = 0x7E & r[4];
2154 // bad reserved should abort?
2155 if ( (0 == rb) || (0x7E == rb) ) // reserved can be 1 or 0? very odd
2157 // 33 bit PCR bits
2158 pcrb = (*r++)<<25; // bits 32 . 31 30 29 28 . 27 26 25
2159 pcrb |= (*r++)<<17; // bits 24 . 23 22 21 20 . 19 18 17
2160 pcrb |= (*r++)<<9; // bits 16 . 15 14 13 12 . 11 10 9
2161 pcrb |= (*r++)<<1; // bits 8 . 7 6 5 4 3 2 1
2162 pcrb |= 1 & (*r>>7); // bit 0
2163 pcrb &= 0x1FFFFFFFFULL;
2166 // 9 bit PCR extension
2167 // 300 * (90kc pcrb % 90000) + pcrx
2168 // to make pcrx / 27,000,000
2169 pcrx = (1 & *r++) << 8; // bit 9
2170 pcrx |= 0xFF & *r++;
2171 // limit pcrx to 0-299
2172 pcrx %= 300;
2174 /* make 42 bit PCR as a 27 mhz clock value (300 * 90kc) */
2175 pcr = (300 * pcrb) + pcrx;
2176 pcrd = pcr - ppcr;
2178 px = pcr % 300;
2179 py = pcr / 300; // pcr extension
2180 pr = py % 90000; // save 90kc clock
2181 pw = py / 90000; // strip 90kc clock to total seconds
2182 ps = pw % 60; // limit to 0-59 seconds
2183 pm = (pw / 60) % 60; // limit to 0-59 minutes
2184 ph = (pw / 3600) % 24; // limit to 24 hours (should be 26?)
2185 pd = (pw / 86400);
2186 // normal pcr increment behaviour is default
2187 ppcr = pcr;
2189 if (0 == first_pcr) first_pcr = pcr;
2190 last_pcr = pcr;
2193 // print if mpeg video info asked for
2194 mprintf7( stdout,
2195 " %cPCR %01dd:%02dh:%02dm:%02ds %05uc %3llux diff %10lld\n",
2196 (pcrd < 27000000) ? ' ':'*', pd, ph, pm, ps, pr, px, pcrd
2199 } else {
2200 mprintf7( stdout, " PCR reserved bits not set %02X\n", rb);
2204 // original program clock reference, from previous multiplex or source?
2205 if (0 != opcr) {
2206 unsigned int rb;
2207 rb = 0x7E & r[4];
2208 if ( (0 == rb) || (0x7E == rb) ) // reserved can be 1 or 0?
2209 { // bad reserved should abort?
2210 // 33 bit Original PCR
2211 opcrb = (*r++)<<25; // bits 32 . 31 30 29 28 . 27 26 25
2212 opcrb |= (*r++)<<17; // bits 24 . 23 22 21 20 . 19 18 17
2213 opcrb |= (*r++)<<9; // bits 16 . 15 14 13 12 . 11 10 9
2214 opcrb |= (*r++)<<1; // bits 8 . 7 6 5 4 3 2 1
2215 opcrb |= 1 & (*r>>7); // bit 0
2216 opcrb &= 0x1FFFFFFFFULL;
2217 // 9 bit Original PCR extension
2218 opcrx = (1 & *r++) << 8; // bit 9
2219 opcrx |= 0xFF & *r++;
2221 pr = opcrb % 90000;
2222 pw = opcrb / 90000;
2223 ps = pw % 60;
2224 pm = (pw / 60) % 60;
2225 ph = (pw / 3600) % 24;
2226 pd = (pw / 86400);
2229 mprintf7( stdout, " OPCR %01d:%02d:%02d:%02d.%05d ext %3d\n",
2230 pd, ph, pm, ps, pr, opcrx);
2232 } else {
2233 mprintf7( stdout, " OPCR Reserved bits not set %02X\n", rb);
2237 // splicing point
2238 if (0 != sp) {
2240 sc = *r++; // 8 bit signed
2243 // transport private data, skips and does not keep private data bytes
2244 if (0 != tpd) {
2245 int i, pdb;
2246 tpdl = *r++;
2247 for (i = 0; i < tpdl; i++) pdb = *r++;
2250 // adaptation field extension
2251 if (0 != afx) {
2252 afxl = *r++;
2253 if ( 0x1F == (0x1F & *r) ) { // reserved
2254 ltw = 1 & (*r >> 7); // ltw flag
2255 pwrf = 1 & (*r >> 6); // piecewise rate flag
2256 ssf = 1 & (*r >> 5); // seamless splice flag
2257 r++;
2259 if (0 != ltw) {
2260 ltwv = 1 & (*r >> 7); // 1 bit ltw valid
2261 ltwo = (0x7F & *r++) << 8; // 15 bit ltw offset
2262 ltwo |= 0xFF & *r++;
2264 if (0 != pwrf) {
2265 if (0xC0 == (0xC0 & *r)) { // reserved
2266 pwr = 0x3F & *r++; // 22 bit piecewise rate
2267 pwr |= (*r++) << 16;
2268 pwr |= (*r++) << 8;
2269 pwr |= *r++;
2274 // seamless splice, Decoder Time Stamp next access unit
2275 if (0 != ssf) {
2276 if ( (1 == (1 & r[0])) // marker bits
2277 || (1 == (1 & r[2]))
2278 || (1 == (1 & r[4]))
2281 // splice type
2282 st = 0xF & (*r>>4); // blech spec mess
2284 // dts next access unit
2285 // 32 31 30
2286 dtsnau = (7 & (*r++ >> 1 )) << 30;
2288 // 29 28 27 26 . 25 24 23 22
2289 dtsnau |= *r++ << 22;
2291 // 21 20 19 18 . 17 16 15 14
2292 dtsnau |= (0x7F & (*r++ >> 1)) << 14;
2294 // 13 12 11 10 . 9 8 7 6
2295 dtsnau |= *r++ << 6;
2297 // 5 4 3 2 . 1 0
2298 dtsnau |= 0x3F & (*r++ >> 1);
2300 pr = dtsnau % 90000;
2301 pw = dtsnau / 90000;
2302 ps = pw % 60;
2303 pm = (pw / 60) % 60;
2304 ph = (pw / 3600) % 24;
2305 pd = (pw / 86400);
2307 mprintf4( stdout, "\n DTS NAU %01d:%02d:%02d:%02d.%05d",
2308 pd, ph, pm, ps, pr );
2314 if ( 0 != afb) mprintf4( stdout, "\n");
2317 #if 0
2318 /* for atscap, not here. atscut needs the various printfs for info output */
2320 /* generic build payload: p is packet, s is payload structure, n is name.
2321 this only works for payloads with section lengths, not mpeg or a52.
2322 also, to be generic, all payloads are allocated 4096 bytes.
2323 returns 0 if done, 1 if not done
2325 static
2327 build_payload(char *p, struct payload_s *s, char *n)
2329 char *r;
2330 char psi;
2332 r = p + 5;
2333 psi = 1 & ( p[1] >> 6);
2335 /* payload start indicator yes */
2336 if (0 != psi) {
2337 /* save header parts that are not part of payload */
2338 s->sl = ((0xF & r[1])<<8) | r[2];
2339 s->vn = 0x1F & ( r[5] >> 1);
2340 s->payoff = 183;
2341 memcpy( s->payload, r, s->payoff );
2342 if ( s->payoff > s->sl+3 ) {
2343 return 0;
2345 return 1;
2347 /* payload start indicator no */
2348 r = p+4;
2349 if (0 == psi) {
2350 // first time, or last payload was good?
2351 if (0 == s->payoff) { // last valid payload clears s->payoff
2352 return 1; // drop payload, it is out of order
2354 if (s->payoff+184 > 4095) {
2355 return 1; // drop payload, it will over-run buffer
2358 memcpy( &s->payload[s->payoff], r, 184);
2359 s->payoff += 184;
2361 if ( s->payoff > s->sl+3 ) {
2362 return 0; // payload is done
2364 return 1;
2367 return 1; // payload not handled
2369 #endif
2371 #if 0
2372 ////////////////////////////////////////////////////////////////// MPEG2 PAT
2373 // payload assembly for PAT, not needed, all ATSC PATs are 188 bytes or less
2374 static
2375 unsigned int
2376 build_pat_payload( unsigned char *p )
2378 unsigned char *r;
2379 unsigned char psi;
2380 //, vn;
2383 r = p + 5;
2384 psi = 1 & ( p[1] >> 6);
2387 // handle payload start packet by copying start to PAT payload buffer
2388 if (psi != 0)
2390 if ( (0x02 == r[0]) // table id PAT
2391 && (0xB0 == (0xF0 & r[1]) ) // syntax,private,reserved bits
2394 pat.vn = 0x1F & ( r[5] >> 1);
2395 pat.sl = ((0xF & r[1])<<8) | r[2];
2397 pat.payoff = 183;
2398 aprintf6( stdout,
2399 " START PAT Version %02X SLen %03X Payoff %03X\n",
2400 pat.vn, pat.sl, pat.payoff);
2402 memset( pat.payload, 0, sizeof(pat.payload) );
2403 memcpy( pat.payload, r, pat.payoff );
2405 if ( pat.payoff > pat.sl+3 ) {
2406 aprintf6( stdout, " DONE PAT\n");
2407 return 0;
2410 return 1;
2413 r = p+4;
2415 // additional non start payloads append to PAT payload buffer
2416 if ( psi == 0 ) {
2417 memcpy( &pat.payload[pat.payoff], r, 184);
2418 pat.payoff += 184;
2419 aprintf6( stdout,
2420 " COPY PAT Version %02X SLen %03X Payoff %03X\n",
2421 pat.vn, pat.sl, pat.payoff);
2423 if ( pat.payoff > pat.sl+3 ) {
2424 aprintf6( stdout, " DONE PAT\n");
2425 return 0;
2427 return 1;
2430 aprintf6( stdout, "PAT not parsed\n");
2431 return 1;
2433 #endif
2435 /* from atscap cross pollinated to atscut */
2436 /****************************************************************** MPEG2 PAT
2437 * rebuild PAT to single Program Map Table entry. called by test pat.
2438 * vc is the loop index for the program lookup from test pat.
2439 * p is pointer to the current PAT, new_pat is built here, and is
2440 * copied over current PAT at p.
2441 * arg_epn is the user supplied program number
2443 static
2444 void
2445 build_new_pat ( unsigned char *p, int vcn )
2447 unsigned int new_crc;
2448 unsigned short sl = 13;
2449 unsigned char new_pat[188];
2451 if (arg_epn < 1) return;
2453 memset( new_pat, 0, 188 );
2454 /* copy section control header portion */
2455 memcpy( &new_pat[0], p, 13 );
2457 /* copy section data portion for a specific VC */
2458 memcpy( &new_pat[13], p + 13 + (vcn*4), 4);
2460 /* debug */
2462 unsigned short pgn, pmtpid;
2463 pgn = new_pat[13] << 8; /* 16 bit program number */
2464 pgn |= new_pat[14];
2465 pmtpid = (0x1F & new_pat[15]) << 8; /* 13 bit PID number */
2466 pmtpid |= new_pat[16];
2467 // fprintf( stdout, "%s %04X new PAT sl %03X p %04X m %04X\n",
2468 // __FUNCTION__, 0, sl, pgm, pmtpid);
2472 /* set new pat section length, is overcorrect: 0xf0 is enough */
2473 /* is over-correct because sl will always be well under 256 bytes */
2474 new_pat[6] = (0xF0 & new_pat[6]) | (0x0F & (sl>>8));
2475 /* 1 offset byte from payload start, 8 byte section header, 4 byte data */
2476 new_pat[7] = 0xFF & sl;
2479 /* compute new pat crc */
2480 new_crc = calc_crc32( &new_pat[5], sl-1 );
2482 /* store crc at end of new pat */
2483 new_pat[ sl+4 ] = 0xFF & (new_crc>>24);
2484 new_pat[ sl+5 ] = 0xFF & (new_crc>>16);
2485 new_pat[ sl+6 ] = 0xFF & (new_crc>>8);
2486 new_pat[ sl+7 ] = 0xFF & new_crc;
2488 #if 0
2489 /* only needed for debugging, remove from production for one less crc32 */
2491 unsigned int chk_crc;
2492 chk_crc = calc_crc32( &new_pat[5], sl+3);
2493 if (0 != chk_crc)
2494 fprintf( stdout, "%s chk_crc %08X", __FUNCTION__, chk_crc);
2496 #endif
2498 memcpy( p, new_pat, 188 ); /* copy it back on top of old one */
2501 /**************************************************************** MPEG2 PMT
2502 * rebuild PMT to single Program entry. called by test pmt
2503 * p is pointer to the current PMT, new_pmt is built here, and is
2504 * copied over current PMT at p.
2505 * arg_epn is the user supplied program number
2506 * arg_epa is the user supplied audio number
2508 static
2509 void
2510 build_new_pmt ( unsigned char *p, unsigned short vpid, unsigned short apid )
2512 unsigned char *r, *d;
2513 unsigned short c, sl, osl, pid;
2514 unsigned int new_crc;
2515 unsigned char new_pmt[188];
2517 if (arg_epn < 1) return;
2519 d = new_pmt;
2520 memset( d, 0, 188 );
2521 memcpy( d, p, 17); /* 4 byte header, 13 byte control data */
2522 d += 17; /* new pmt */
2523 sl = 13; /* does not count header */
2524 r = p + 17; /* old pmt */
2526 /* pcr pid is copied. should have been set correctly elsewhere */
2528 pid = ( (0x1F & p[1]) << 8) | p[2]; /* pid for this pmt packet */
2529 osl = ( (0x0F & p[6]) << 8) | p[7]; /* old section len for comparison */
2531 /* 4 byte TS header, 4 bytes to sl, then sl bytes data and 4 byte crc */
2532 if (sl > 179) return;
2534 c = ( ( 0x0F & p[15]) << 8) | p[16]; /* program info len 12 bottom bits */
2536 /* ATSC further restricts this to 10 bits, i think */
2537 // c &= 0x3FF;
2539 /* only copy and increment if program info len non zero */
2540 if (0 != c) {
2541 int i;
2542 unsigned char *s;
2543 i = c;
2544 s = r;
2545 for ( i = 0; i < c; ) {
2546 if (0xAA == *s) *s = 0x80; /* stuff the RC */
2547 i += s[1]+2;
2548 s += s[1]+2; /* step thru descriptors */
2550 memcpy( d, r, c );
2551 r += c; /* next place in old pmt */
2552 sl += c; /* section len in new pmt */
2555 // fprintf( stdout, "%s %04X PMT pilen %03X newsl %03X\n",
2556 // __FUNCTION__, pid, c, sl );
2558 /* ok to add zero, not ok to memcpy size 0 */
2559 d += c; /* next place in new pmt */
2561 while (r < (p + (osl-1)) ) {
2562 unsigned int e;
2564 /* reserved bits set ? */
2565 if ( (0xE0 == (0xE0 & r[1])) && (0xF0 == (0xF0 & r[3])) ) {
2566 e = ((0x1F & r[1]) << 8 ) | r[2]; /* es pid bottom 13 bits */
2567 c = ((0x0F & r[3]) << 8 ) | r[4]; /* es info len 12 bottom bits */
2568 /* ATSC limits this to 10 bits I think */
2569 // c &= 0x3FF;
2571 /* preamble 5 bytes, copy this much at least, es info len may be zero */
2572 c += 5;
2574 /* if es pid matches program number and audio number, copy entry to new pmt */
2575 if ( (e == vpid) || (e == apid) ) {
2577 /* FIXME: needs a strict boundary check. the while above is not enough */
2578 memcpy( d, r, c );
2580 d += c; /* next place in new pmt */
2581 sl += c; /* section len in new pmt */
2583 // fprintf( stdout, "%s %04X PMT pid %04X esi %03X newsl %03X\n",
2584 // __FUNCTION__, pid, e, c, sl);
2586 r += c; /* next place in old pmt */
2588 } else {
2589 /* no reserved bits stops loop */
2590 fprintf( stdout, "%s %04X no reserved bits\n",
2591 __FUNCTION__, pid);
2592 break;
2596 /* set new pmt section length */
2597 new_pmt[6] = (0xF0 & new_pmt[6]) | (0x0F & (sl>>8));
2598 new_pmt[7] = 0xFF & sl;
2600 /* compute new pmt crc */
2601 new_crc = calc_crc32( &new_pmt[5], sl-1 );
2603 /* store crc at end of new pmt */
2604 new_pmt[ sl+4 ] = 0xFF & (new_crc>>24);
2605 new_pmt[ sl+5 ] = 0xFF & (new_crc>>16);
2606 new_pmt[ sl+6 ] = 0xFF & (new_crc>>8);
2607 new_pmt[ sl+7 ] = 0xFF & new_crc;
2609 // fprintf( stdout, "%s %04X PMT oldsl %03X newsl %03X\n",
2610 // __FUNCTION__, pid, osl, sl);
2612 #if 0
2613 /* only needed for debugging, remove from production for one less crc32 */
2615 unsigned int chk_crc;
2616 chk_crc = calc_crc32( &new_pmt[5], sl+3);
2617 if (0 != chk_crc)
2618 fprintf( stdout, "%s %04X chk_crc %08X\n",
2619 __FUNCTION__, pid, chk_crc);
2621 #endif
2623 memcpy( p, new_pmt, 188 ); /* copy it back on top of old one */
2628 /////////////////////////////////////////////////////////////////// MPEG2 PAT
2629 // so far, all these show no PSI = 0 for PID matching PAT or PMT
2630 // so processing in place as single packet. maybe a bad shortcut later?
2631 // there's not a lot interesting until/unless have to modify it.
2632 static
2633 void
2634 test_pat ( unsigned char *p )
2636 unsigned char *r;
2637 unsigned short sl;
2638 unsigned char vn, cni, sn, lsn;
2639 unsigned short tsid, pgn, netpid, pmtpid, pid;
2640 unsigned int pat_crc, pat_crc0;
2641 int vcn;
2642 // int i;
2644 pat.payok = ~0;
2645 pid = 0;
2647 if (arg_epn > 0) keep_pids[0] = ~0; /* always keep pat */
2649 // point to table id
2650 r = p+5;
2652 // check reserved and report any errors
2653 if ( 0x30 != (0x30 & r[1]))
2654 mprintf1( stdout, " PAT reserved bits not set r[1] != 30 is %02X\n",
2655 0x30 & r[1]);
2657 if ( 0xC0 != (0xC0 & r[5]) )
2658 mprintf1( stdout, " PAT reserved bits not set r[5] != C0 is %02X\n",
2659 0xC0 & r[5]);
2661 sl = ((0xF & r[1])<<8) | r[2]; // 12 bit section length
2662 pat.sl = sl;
2664 // pat_crc = calc_crc32( r, sl+3 ); // only want crc to validate it
2666 /* compute CRC32 */
2667 pat_crc0 = calc_crc32( r, sl-1 );
2669 /* received CRC32 */
2670 pat_crc = r[ sl - 1 ];
2671 pat_crc <<= 8;
2672 pat_crc |= r[ sl ];
2673 pat_crc <<= 8;
2674 pat_crc |= r[ sl + 1 ];
2675 pat_crc <<= 8;
2676 pat_crc |= r[ sl + 2 ];
2678 if (pat_crc != pat_crc0) {
2679 pkt.crcpat++;
2680 mprintf1( stdout,
2681 "PAT CRC ERROR PID %04X CALC %08X RCVD %08X\n",
2682 0, pat_crc0, pat_crc);
2683 #if 0
2684 for (i = 0; i < 188; i++) {
2685 if (old_pat[i] != p[i])
2686 mprintf1( stdout,
2687 "p[%d] %02X != %02X\n", i, old_pat[i], p[i] );
2689 #endif
2690 return;
2691 } else {
2692 if (sl < 180)
2693 memcpy( old_pat, p, 188);
2696 pkt.pat++;
2698 // too short for cable? no is ok for the 16 programs seen in cable
2699 memcpy( pat.payload, p, 188 );
2700 pat.payoff = 188;
2701 pat.payok = 0;
2703 if (arg_mgtpids != 0) keep_pids[0] = ~0; // -k mgt keeps PAT
2705 tsid = (r[3]<<8) | r[4];
2706 vn = 0x1F & (r[5]>>1);
2707 pat.vn = vn;
2709 /* OUTPUT REDUX: */
2710 if ( (0 != arg_redux) && (vn == pid_vn[pid]) ) return;
2711 pid_vn[pid] = vn;
2713 if (pat_crc == pat_crc0) mprintf1( stdout, "PAT CRC %08X OK", pat_crc);
2715 cni = 1 & r[5];
2716 sn = r[6];
2717 lsn = r[7];
2718 mprintf1( stdout, "\n MPEG PAT PID 0000: SLen %03X TSID %04X VN %02X "
2719 "CNI %01X SN %02X LSN %02X\n",
2720 sl, tsid, vn, cni, sn, lsn );
2721 r += 8;
2723 vcn = 0;
2725 // start the program loop, not sure when to stop. p+5+sl?
2726 for ( ; r < p+4+sl; ) {
2727 if ( 0xC0 != (0xC0 & r[2]) ) break; // stop if no reserved bits too
2728 pgn = ( r[0]<<8 ) | r[1];
2729 if (pgn == 0) {
2730 netpid = 0x1FFF & ( (r[2]<<8) | r[3] );
2731 mprintf1( stdout, " Program %04X Network PID %04X\n",
2732 pgn, netpid);
2733 // don't keep network PID's, they should be obsoleted by now
2734 } else {
2735 pmtpid = 0x1FFF & ( (r[2]<<8) | r[3] );
2736 mprintf1( stdout, " Program %04X PMT PID %04X\n",
2737 pgn, pmtpid );
2739 pa[vcn].pn = pgn;
2740 pa[vcn].pmtpid = pmtpid;
2742 if (arg_epn == pgn) { /* -e keeps PAT if program matches */
2743 keep_pids[0] = ~0; /* program is in PAT */
2745 /* -e rebuilds PAT as a single program entry */
2746 if (0 != arg_forge)
2747 build_new_pat( p, vcn );
2750 vcn++;
2751 r += 4; // skip to next program number and PID
2753 pat_ncs = vcn;
2754 mprintf1( stdout, "\n");
2757 #if 1
2758 //////////////////////////////////////////////////////////////////// MPEG PMT
2759 // payload assembly for PMT, this one is needed for KQED-HD PMT
2760 static
2761 unsigned int
2762 build_pmt_payload( unsigned char *p, int pan )
2764 struct payload_s *pmp;
2765 unsigned char *r;
2766 unsigned char psi;
2768 pmp = &pmt[ pan ];
2770 r = p+5;
2772 psi = 1 & ( p[1] >> 6);
2774 // handle payload start packet by copying start to PMT payload buffer
2775 if (0 != psi)
2777 if ( (0x02 == r[0]) // table id PMT
2778 // && (0xB0 == (0xF0 & r[1])) // syntax,private,rsvd bits
2781 pmp->vn = 0x1F & ( r[5] >> 1);
2782 pmp->sl = ((0xF & r[1])<<8) | r[2];
2784 pmp->payoff = 183;
2785 mprintf6( stdout,
2786 " START PMT Version %02X SLen %03X Payoff %03X\n",
2787 pmp->vn, pmp->sl, pmp->payoff);
2789 memset( pmp->payload, 0, sizeof(pmp->payload) );
2790 memcpy( pmp->payload, r, pmp->payoff );
2792 /* if it fit within first packet, get out with 0 code */
2793 if ( pmp->payoff > pmp->sl+3 ) {
2794 mprintf6( stdout, " DONE PMT\n");
2795 return 0;
2798 /* otherwise needs more packets */
2799 return 1;
2802 r = p+4;
2804 // additional non start payloads append to PMT payload buffer
2805 if ( psi == 0 ) {
2806 if (0 == pmp->payoff) return 1;
2807 memcpy( &pmp->payload[pmp->payoff], r, 184);
2808 pmp->payoff += 184;
2809 aprintf6( stdout,
2810 " COPY PMT Version %02X SLen %03X Payoff %03X\n",
2811 pmp->vn, pmp->sl, pmp->payoff);
2813 if ( pmp->payoff > pmp->sl+3 ) {
2814 aprintf6( stdout, " DONE PMT\n");
2815 return 0;
2817 return 1;
2820 aprintf6( stdout, "PMT not parsed\n");
2821 return 1;
2823 #endif
2826 //////////////////////////////////////////////////////////////////// MPEG PMT
2827 // A/65b Table 6.38 Multiple String Structure
2828 // does do huffman decomp
2829 static
2830 void
2831 test_pmt_mss( unsigned char *r )
2833 unsigned int nstr, nseg, comp, mode, nchr;
2834 unsigned int i,j,k;
2835 unsigned char lang[4];
2836 unsigned char s[256];
2837 unsigned char d[512];
2838 // unsigned char *t;
2840 memset( s, 0, sizeof(s));
2841 nstr = r[0];
2842 for (i = 0; i < nstr; i++) {
2843 memcpy(lang, &r[1], 3);
2844 lang[3] = 0;
2845 r += 4; // 3?
2846 nseg = *r++;
2847 for (j = 0; j < nseg; j++) {
2848 comp = *r++;
2849 mode = *r++;
2850 nchr = *r++;
2851 // mprintf2( stdout, "LEN %02X: ", nchr);
2852 for (k = 0; k < nchr; k++) {
2853 s[k] = *r++;
2854 // mprintf2( stdout, "%02X ", s[k]);
2856 // mprintf2( stdout, "\n");
2858 // show non-compressed
2859 if ( (0 == comp) && (0 == mode) ) {
2860 mprintf2( stdout, "[%s] [%-s] ", lang, s);
2862 // show huffman compressed
2863 if (
2864 // (mode == 0xFF) && // spec requires, KPXB ignores
2865 (comp > 0) &&
2866 (comp < 3)
2869 huffman_decode( d, s, sizeof(d), nchr, comp);
2870 mprintf2( stdout, "[%s] [%-s] ", lang, d);
2872 // show as unknown compress
2873 if (comp > 2)
2874 mprintf2( stdout, "[%s] [L%02X C%02X M%02X]",
2875 lang, nchr, comp, mode);
2879 mprintf2( stdout, "\n");
2883 //////////////////////////////////////////////////////////////////// MPEG PMT
2884 static
2885 void
2886 test_pmt_descriptor( unsigned char *r ) {
2887 unsigned char *t;
2888 unsigned char n, j;
2889 unsigned short i, k;
2890 t = "FUBAR";
2891 n = r[0];
2892 k = 0xFF & r[1];
2894 // r += 2; // bytes start here
2895 // mprintf2( stdout, "desc %s tag# %u len %u\n", t, n, l);
2896 /////////////////////////////////////////////////////////////// MPEG specific
2897 switch ( n ) {
2899 case 2:
2900 t = "Video Stream";
2902 unsigned char mfr, frc, m1o, cpf, spf;
2903 unsigned char *frct, *mfrt;
2904 mprintf2( stdout, " Tag %02X DLen %02X %s: ", n, k, t);
2905 mfr = 1 & (r[2]>>7);
2906 frc = 15 & (r[2]>>3);
2907 m1o = 1 & (r[2]>>2);
2908 cpf = 1 & (r[2]>>1);
2909 spf = 1 & r[2];
2911 frct = "Reserved";
2912 if (0 == mfr) {
2913 mfrt = "Single";
2914 if (0 == frc) frct = "Forbidden";
2915 if (1 == frc) frct = "23.976";
2916 if (2 == frc) frct = "24";
2917 if (3 == frc) frct = "25";
2918 if (4 == frc) frct = "29.97";
2919 if (5 == frc) frct = "30";
2920 if (6 == frc) frct = "50";
2921 if (7 == frc) frct = "59.94";
2922 if (8 == frc) frct = "60";
2923 } else {
2924 mfrt = "Multiple";
2925 if (0 == frc) frct = "Forbidden";
2926 if (1 == frc) frct = "23.976";
2927 if (2 == frc) frct = "24/23.976";
2928 if (3 == frc) frct = "25";
2929 if (4 == frc) frct = "29.97/23.976";
2930 if (5 == frc) frct = "30/23.976/24/29.97";
2931 if (6 == frc) frct = "50 25";
2932 if (7 == frc) frct = "59.94/23.976/29.97";
2933 if (8 == frc) frct = "60/23.976/24/29.97/30/59.94";
2936 mprintf2( stdout, " %s Frame Rate %s\n", mfrt, frct);
2937 mprintf2( stdout, " MPEG1 Only %u Constrained %u Still Picture %u\n",
2938 m1o, cpf, spf);
2940 // not likely for terrestrial ATSC but who knows what's on cable
2941 if (0 != m1o) {
2942 // check reserved bits
2943 if (0x1F == (0x1F & r[4])) {
2944 unsigned char pli, cf, fre;
2945 pli = r[3];
2946 cf = 3 & (r[4]>>6);
2947 fre = 1 & (r[4]>>5);
2948 mprintf2( stdout," MPEG1 Profile and Level %02X Chroma Format %01X Frate Rate Ext %1X",
2949 pli, cf, fre);
2952 // return;
2954 break;
2956 case 3:
2957 t = "Audio Stream";
2958 break;
2960 case 4:
2961 t = "Hierarchy";
2962 break;
2964 case 5:
2965 t = "Registration";
2966 mprintf2( stdout, " Tag %02X DLen %02X %s: ", n, k, t);
2967 mprintf2( stdout, "Format ID [%c%c%c%c]\n",
2968 r[2],r[3],r[4],r[5]);
2969 if (k != 4)
2970 mprintf2( stdout, " add'l id info exists but not parsed\n");
2971 // return;
2972 break;
2974 case 6:
2975 t = "Stream Alignment";
2977 unsigned char *s;
2978 unsigned char at;
2979 s = "Reserved";
2980 at = r[2];
2981 if (1 == at) s = "SLI, PIC, GOP or SEQ";
2982 if (2 == at) s = "PIC, GOP or SEQ";
2983 if (3 == at) s = "GOP or SEQ";
2984 if (4 == at) s = "SEQ";
2985 mprintf2( stdout, " Tag %02X DLen %02X %s: %s\n",
2986 n, k, t, s);
2987 // return;
2989 break;
2991 case 7:
2992 t = "Target Background Grid";
2993 break; // write me if needed
2995 case 8:
2996 t = "Video Window";
2997 break; // write me if needed
2999 case 9:
3000 t = "Conditional Access";
3001 if ( 0xE0 == (0xE0 & r[4] ) ) { // reserved bits check
3002 unsigned short casid, capid;
3003 r += 2;
3004 mprintf2( stdout, " Tag %02X DLen %02X %s: ", n, k, t);
3005 casid = (r[0]<<8) | r[1];
3006 capid = 0x1FFF & ( (r[2]<<8) | r[3] );
3007 mprintf2( stdout, " CA system ID %04X CA PID %04X\n", casid, capid);
3008 r += 4; // skip to private data
3009 k -= 4;
3011 if (k > 0)
3013 mprintf2( stdout, " CA descriptor private data: "
3014 " ");
3015 for ( i = 0; i < k; i++ ) {
3016 mprintf2( stdout, "%02X ", r[i]);
3018 mprintf2( stdout, "\n");
3020 // return;
3022 break;
3024 case 10:
3025 t = "ISO 639 Language(s)";
3027 // no reserved bits to check so balls it out
3028 unsigned char lang[4];
3029 unsigned char at; // audio type
3030 unsigned char *s;
3031 r += 2;
3032 mprintf2( stdout, " Tag %02X DLen %02X %s: ", n, k, t);
3033 // spec mentions can be multiple audios, whee!
3034 for (i = 0; i < (k - 1); ) { // manually bump i
3035 memcpy( lang, r, 3 );
3036 lang[3] = 0;
3037 r += 3;
3038 i += 3;
3039 mprintf2( stdout, "[%s] ", lang);
3041 // mprintf2( stdout, "\n");
3043 // audio type
3044 at = r[0];
3045 s = "ATSC Normal";
3046 if (1 == at) s = "Clean Effects";
3047 if (2 == at) s = "Hearing Impaired";
3048 if (3 == at) s = "Visual Impaired Commentary";
3049 if (4 <= at) s = "Reserved";
3050 mprintf2( stdout, " Audio Type %02X %s\n", at, s);
3051 // return;
3053 break;
3055 case 11:
3056 // reserved bits must be set to qualify for rest
3057 if ( (0x40 == (0x40 & r[2]))
3058 && (0x1F == (0x1F & r[3])) ) {
3059 unsigned char ecri, cai, cae;
3060 t = "System Clock";
3061 ecri = 1 & (r[2]>>7); // external clock reference indicator
3062 cai = 0x3F & r[2]; // clock accuracy integer
3063 cae = 7 & (r[3]>>5); // clock accuracy exponent
3064 mprintf2( stdout, " Tag %02X DLen %02X %s: ", n, k, t);
3065 mprintf2( stdout, "External Clock %u ", ecri);
3066 mprintf2( stdout, "Accuracy is %u^%u\n",
3067 cai, cae);
3068 // return;
3070 break;
3072 case 12:
3073 t = "Multiplex Buffer Utilization";
3075 unsigned char bv;
3076 unsigned short ltwl, ltwu;
3078 ltwl = ltwu = 0;
3080 bv = 1 & (r[2] >> 7); // bound valid flag
3082 // valid and reserved set?
3083 if ( (1 == bv) && (0x80 == (0x80 & r[4])) ) {
3084 ltwl = 0x7FFF & ( (r[2]<<8) | r[3] );
3085 ltwu = 0x7FFF & ( (r[4]<<8) | r[5] );
3087 mprintf2( stdout, " Tag %02X DLen %02X %s: ", n, k, t);
3088 mprintf2( stdout, "Valid %u\n", bv);
3090 // don't bother if not valid
3091 if (1 == bv) {
3092 mprintf2( stdout, " Legal Time Window Lower Bound %u Upper Bound %u\n",
3093 ltwl, ltwu);
3095 // return;
3097 break;
3099 case 13:
3100 t = "Copyright"; // lucky 13?
3101 break;
3103 case 14:
3104 t = "Maximum Bitrate";
3105 if ( 0xC0 == (0xC0 & r[2]) ) {
3106 unsigned int mbr;
3107 unsigned char m[32];
3108 mbr = 0x3FFFFF & ( ( r[2] << 8 ) | r[3] );
3109 mprintf2( stdout, " Tag %02X DLen %02X %s: ", n, k, t);
3110 lltoasc( m, (long long) mbr * 400 );
3111 mprintf2( stdout, "%s bits/second\n", m);
3112 // return;
3114 break;
3116 case 15:
3117 t = "Private Data Indicator";
3118 break;
3120 // smoothing buffer, not in 13818-1 draft 1994 jun 10, but in nov 13
3121 case 0x10:
3122 t = "Smoothing Buffer";
3124 unsigned int sblr, sbz;
3125 r+=2;
3126 if ( (0xC0 == (0xC0 & r[0]))
3127 && (0xC0 == (0xC0 & r[3])) ) {
3128 mprintf2( stdout, " Tag %02X DLen %02X %s: ", n, k, t);
3129 // mprintf2( stdout, " %02X %02X %02X %02X %02X %02X\n", r[0], r[1], r[2], r[3], r[4], r[5]);
3131 sblr = 0x3FFFFF & ( (r[0]<<16) | (r[1]<<8) | r[2] );
3132 sbz = 0x3FFFFF & ( (r[3]<<16) | (r[4]<<8) | r[5] );
3133 mprintf2( stdout, "Leak Rate %u bits/s Size %u\n",
3134 sblr*400, sbz);
3135 // return;
3138 break;
3140 //////////////////////////////////////////////////////////////// ATSC specific
3141 case 0x52:
3142 t = "SCTE 35 Cue ID";
3143 break;
3145 case 0x80:
3146 t = "Stuffing";
3147 mprintf2( stdout, " Tag %02X DLen %02X %s: ", r[0], k, t);
3148 for (i=0; i < k; i++) mprintf2( stdout, "%02X ", r[ 2 + i ] );
3149 mprintf2( stdout, "\n");
3150 // return;
3151 break;
3153 case 0x81:
3154 t = "A/52 Audio";
3156 // unsigned char lc, lc2, mid, asvcf, tl, tc, tb; //??
3157 unsigned char src, bsid, brc, sm, bsm, nc, fs;
3158 unsigned char *srt, *brt, *brt1, *smt, *nct, *lft, *bsmt;
3159 r += 2;
3160 src = 0x07 & (r[0]>>5);
3161 srt = "Reserved";
3162 if (0 == src) srt = "48 kHz";
3163 if (1 == src) srt = "44.1 kHz";
3164 if (2 == src) srt = "32 kHz";
3165 // must be the can't decide section nyuk
3166 if (4 == src) srt = "48 or 44.1 kHz";
3167 if (5 == src) srt = "48 or 32 kHz";
3168 if (6 == src) srt = "44.1 or 32 kHz";
3169 if (7 == src) srt = "48, 44.1 or 32 kHz";
3171 bsid= 0x1F & r[0];
3172 brc = 0x3F & (r[1]>>2); // bit rate code
3173 sm = 0x03 & r[1]; // surround mode, docs also name it dsumod?
3174 bsm = 0x07 & (r[2]>>5); // bsmod
3175 nc = 0x0F & (r[2]>>4); // number of channels
3176 fs = 0x01 & r[2];
3178 brt1 = "Exact";
3179 if (0x20 == (0x20 & brc)) brt1 = "Maximum";
3180 brc &= 0x1F; // limit it now brt1 has been extracted
3182 brt = "Reserved";
3183 if ( 0 == brc) brt = " 32 kbits/second";
3184 if ( 1 == brc) brt = " 40 kbits/second";
3185 if ( 2 == brc) brt = " 48 kbits/second";
3186 if ( 3 == brc) brt = " 56 kbits/second";
3187 if ( 4 == brc) brt = " 64 kbits/second";
3188 if ( 5 == brc) brt = " 80 kbits/second";
3189 if ( 6 == brc) brt = " 96 kbits/second";
3190 if ( 7 == brc) brt = "112 kbits/second";
3191 if ( 8 == brc) brt = "128 kbits/second";
3192 if ( 9 == brc) brt = "160 kbits/second";
3193 if (10 == brc) brt = "192 kbits/second";
3194 if (11 == brc) brt = "224 kbits/second";
3195 if (12 == brc) brt = "256 kbits/second";
3196 if (13 == brc) brt = "320 kbits/second";
3197 if (14 == brc) brt = "384 kbits/second";
3198 if (15 == brc) brt = "448 kbits/second";
3199 if (16 == brc) brt = "512 kbits/second";
3200 if (17 == brc) brt = "576 kbits/second";
3201 if (18 == brc) brt = "640 kbits/second"; // like to hear that!
3204 smt = "Reserved";
3205 if (0 == sm) smt = "Not Indicated";
3206 if (1 == sm) smt = "NOT Dolby";
3207 if (2 == sm) smt = "Dolby";
3209 nct = "Reserved";
3210 lft = "";
3211 if ( 8 == (8 & nc)) lft = " + LFE";
3212 if ( 0 == nc) nct = "1+1";
3213 if ( 1 == nc) nct = "1/0";
3214 if ( 2 == nc) nct = "2/0";
3215 if ( 3 == nc) nct = "3/0";
3216 if ( 4 == nc) nct = "2/1";
3217 if ( 5 == nc) nct = "3/1";
3218 if ( 6 == nc) nct = "2/2";
3219 if ( 7 == nc) nct = "3/2";
3220 // lfe is extra channel but not in the text count
3221 if ( 8 == nc) nct = "1";
3222 if ( 9 == nc) nct = "<=2";
3223 if (10 == nc) nct = "<=3";
3224 if (11 == nc) nct = "<=4";
3225 if (12 == nc) nct = "<=5";
3226 if (13 == nc) nct = "<=6";
3228 bsmt = "Reserved";
3229 if ( 0 == bsm) bsmt = "Main Audio: Complete Main";
3230 if ( 1 == bsm) bsmt = "Main Audio: Music and Effects";
3231 if ( 2 == bsm) bsmt = "Associated: Visually Impaired";
3232 if ( 3 == bsm) bsmt = "Associated: Hearing Impaired";
3233 if ( 4 == bsm) bsmt = "Associated: Dialogue";
3234 if ( 5 == bsm) bsmt = "Associated: Commentary";
3235 if ( 6 == bsm) bsmt = "Associated: Emergency";
3236 if ( 7 == bsm) bsmt = "Associated: Voice Over";
3238 mprintf2( stdout, " Tag %02X DLen %02X %s: Sample Rate %s, bsid %02X\n",
3239 n, k, t, srt, bsid);
3240 mprintf2( stdout, " %s Bit Rate %s (%02X) Surround %s (%02X)\n",
3241 brt1, brt, brc, smt, sm);
3242 mprintf2( stdout, " Service %s, Channels %s %s Full Service %u\n",
3243 bsmt, nct, lft, fs);
3244 // return;
3246 break;
3248 case 0x86:
3249 t = "Caption Service";
3250 if ( 0xC0 == (0xC0 & r[2]) ) { // reserved bits check
3251 unsigned char nos, cct, l21f, csn, er, war;
3252 unsigned char lang[4];
3254 mprintf2(stdout," Tag %02X DLen %02X %s: ",n, k, t);
3255 nos = 0x1F & r[2];
3256 r += 3; // skip parsed
3257 mprintf2( stdout, "Number of Services %u\n", nos);
3258 for (i = 0; i < nos; i++) {
3259 if ( 0x40 == (0x40 & r[3]) ) {
3260 unsigned char *cctt;
3261 cctt = "ATVCC";
3262 memcpy( lang, r, 3 );
3263 lang[3] = 0; // 3 char lang code per ISO 639.2/B
3264 r += 3; // skip lang
3265 cct = 1 & (r[0]>>7);
3266 if (0 == cct) {
3267 cctt = "NTSC CC";
3268 // don't care about EIA/CEA-608-B. that's NTSC
3269 if ( 0x3E == (0x3E & r[0]) ) { // reserved
3270 l21f = 1 & r[0];
3271 mprintf2( stdout, " [%s] Type %s Line21 %s Field ",
3272 lang, cctt, (l21f == 0) ? "Even" : " Odd" );
3274 } else {
3275 // might be EIA-708-A ATVCC spec, not testing this
3276 csn = 0x3F & r[0];
3277 mprintf2( stdout, " [%s] Type %s Service Number %02X ",
3278 lang, cctt, csn);
3280 if ( (0x3F == (0x3F & r[1])) && (0xFF == r[2]) ) {
3281 er = 1 & (r[1]>>7);
3282 war = 1 & (r[1]>>6);
3283 mprintf2( stdout, "Easy Reader %u Wide Aspect Ratio %u",
3284 er, war);
3285 r += 3;
3288 mprintf2( stdout, "\n");
3290 // return;
3292 break;
3294 case 0x87:
3295 t = "Content Advisory";
3296 if ( 0xC0 == (0xC0 & r[2]) ) {
3297 unsigned char rrc, rr, rd, rdj, rv, rdl;
3299 mprintf2(stdout," Tag %02X DLen %02X %s: ",n, k, t);
3300 rrc = 0x3F & r[2];
3301 mprintf2( stdout, " Rating Region Count %u\n", rrc);
3302 r += 3; // skip to loop vals
3303 for (i = 0; i < rrc; i++) {
3304 rr = r[0]; // rating region
3305 rd = r[1]; // rated dimensions
3307 // one dimension will try to print on one line
3308 mprintf2( stdout,
3309 " Region %u Dimensions %u:%s",
3310 rr, rd, (rd > 1) ? "\n":"");
3312 r += 2;
3313 for (j = 0; j < rd; j++) {
3314 if ( 0xF0 == (0xF0 & r[1]) ) {
3315 rdj = r[0]; // rating dimension j
3316 rv = 0xF & r[1]; // rating value
3317 mprintf2( stdout, " Dimension j %u Value %u Abbrev %s\n",
3318 rdj, rv, ratings[ (10 * rdj) + rv ] );
3319 r += 2;
3322 rdl = r[0]; // rating descriptor length
3323 r++;
3324 if (rdl != 0) {
3325 mprintf2( stdout, " Description: ");
3326 test_pmt_mss( r );
3329 // return;
3331 break;
3333 case 0xA3:
3334 t = "Component Name";
3335 r += 2;
3336 mprintf2( stdout, " Tag %02X DLen %02X %s: ", n, k, t);
3337 test_pmt_mss( r );
3338 // return;
3339 break;
3341 case 0xAA:
3342 t = "Redistribution Control";
3343 mprintf2( stdout, " Tag %02X DLen %02X %s: ", r[0], k, t);
3344 for (i=0; i < k; i++) mprintf2( stdout, "%02X ", r[ 2 + i ] );
3345 mprintf2( stdout, "\n");
3346 break;
3347 // return;
3348 /***************************************************************************/
3350 // handle 0-1, 16-63, 64-255
3351 default:
3352 // these have nothing to parse
3353 t = "ignored";
3354 if (n < 2) t = "Reserved";
3355 if ((n >= 16) && (n <= 63)) t = "ISO/IEC 13818-1 Reserved";
3356 if (n >= 64) t = "User Private";
3357 mprintf2( stdout, " *Tag %02X DLen %02X %s: ", n, k, t);
3358 for (i = 0; i < k+2; i++) mprintf2( stdout, "%02X ", r[i] );
3359 mprintf2( stdout, "\n");
3360 break;
3363 /****************************************************************** MPEG PMT */
3367 /***************************************************************** MPEG2 CAT */
3368 static
3369 void
3370 test_cat_descriptor( unsigned char *r )
3374 /***************************************************************** MPEG2 CAT */
3375 static
3376 void
3377 test_cat( unsigned char *p )
3379 unsigned char *r;
3380 unsigned short sl;
3381 unsigned char vn, cni, sn, lsn;
3382 unsigned int cat_crc = 0;
3384 pkt.cat++;
3386 // point to table id
3387 r = p+5;
3389 // check reserved first, before crc to save time
3390 if ( ( 0x30 != (0x30 & r[1]) )
3391 || ( 0xFF != r[3] ) // reserved must be set
3392 || ( 0xFF != r[4] ) // reserved
3393 || ( 0xC0 != (0xC0 & r[5]) )
3396 mprintf1( stdout, " CAT reserved bits not set\n");
3397 return; // ignore if all reserved bits not set
3400 sl = ((0xF & r[1])<<8) | r[2]; // 12 bit section length
3401 cat_crc = calc_crc32( r, sl+3 ); // only want crc to validate it
3402 if (cat_crc != 0) {
3403 pkt.crccat++;
3404 mprintf1( stdout, " CAT has CRC error\n");
3405 return;
3407 pkt.cat++;
3408 vn = 0x1F & (r[5]>>1);
3409 cni = 1 & r[5];
3410 sn = r[6];
3411 lsn = r[7];
3413 mprintf1( stdout, " PID 0001 Conditional Access: SLen %03X VN %02X CNI %01X SN %02X LSN %02X\n",
3414 sl, vn, cni, sn, lsn );
3416 r += 8;
3418 if ( r < (p+sl+4) ) {
3419 test_cat_descriptor( r );
3420 } else {
3421 mprintf1( stdout, " Descriptor(s) 0\n");
3424 mprintf1( stdout, "\n");
3427 /***************************************************************** MPEG2 PID */
3428 /* if apid list has room, add Audio PID to list */
3429 static
3430 void
3431 add_aud_pid( short pid )
3433 int i;
3434 /* needs #define AUD_PID_MAX */
3435 if (aud_pidx >= 32) return;
3437 for (i=0; i < aud_pidx; i++)
3438 if ( pid == aud_pids[ i ] )
3439 return;
3441 // fprintf( stdout, "added aud_pid[%d] %04X\n", aud_pidx, pid);
3442 aud_pids[ aud_pidx ] = pid;
3443 aud_pidx++;
3446 /* return zero if pid if on audio list */
3447 static
3449 test_aud_pid( short pid )
3451 int i;
3452 for (i=0; i < aud_pidx; i++) {
3453 // fprintf( stdout, "testing audio pid %04X aud_pids[%d] %04X\n", pid, i, aud_pids[i]);
3454 if ( pid == aud_pids[ i ] ) {
3455 // fprintf( stdout, "audio pid %04X found\n", pid);
3456 return 0;
3460 // fprintf( stdout, "audio pid %04X not found\n", pid);
3461 return ~0;
3464 /* if vpid list has room, add Video PID to list */
3465 static
3466 void
3467 add_vid_pid( short pid )
3469 int i;
3470 /* needs #define VID_PID_MAX */
3471 if (vid_pidx >= 8) return;
3473 for (i=0; i < vid_pidx; i++)
3474 if ( pid == vid_pids[ i ] )
3475 return;
3477 // fprintf( stdout, "added vid_pids[%d] %04X\n", vid_pidx, pid);
3478 vid_pids[ vid_pidx ] = pid;
3479 vid_pidx++;
3482 /* return zero if pid is on video list */
3483 static
3485 test_vid_pid( short pid )
3487 int i;
3488 for (i=0; i < vid_pidx; i++) {
3489 // fprintf( stdout, "testing video pid %04X vid_pids[%d] %04X\n", pid, i, vid_pids[i]);
3490 if ( pid == vid_pids[ i ] ) {
3491 // fprintf( stdout, "video pid %04X found\n", pid);
3492 return 0;
3495 // fprintf( stdout, "video pid %04X not found\n", pid);
3496 return ~0;
3500 /**************************************************************** MPEG2 PMT */
3501 static
3502 void
3503 test_pmt ( unsigned char *p, int pan )
3505 struct payload_s *pmp;
3506 unsigned char *r, *b, t;
3507 unsigned short sl, pgn, pcrpid, pilen, espid, esilen, pid, i;
3508 unsigned short vpid, acn, apid, apids[8];
3509 unsigned char vn, cni, sn, lsn, st;
3510 unsigned int pmt_crc, pmt_crc0;
3512 pkt.pmt++;
3514 pmp = &pmt[ pan ];
3516 pid = 0x1FFF & ((p[1]<<8)|p[2]);
3518 if (0 != arg_mgtpids) keep_pids[pid] = ~0; /* -k mgt keeps all PMT */
3520 /* -e keeps PMT if program number matches */
3521 if (0 < arg_epn) {
3523 /* TESTME: hold down until PAT seen */
3524 // if (0 == pkt.pat) return;
3526 if (pa[pan].pn == arg_epn) {
3527 keep_pids[ pid ] = ~0;
3531 pmp->payok = build_pmt_payload( p, pan );
3532 if (0 != pmp->payok) return; /* payload is not done yet */
3534 /* point to table id */
3535 r = pmp->payload;
3537 /* check reserved first, before crc to save time */
3538 if (2 != r[0]) return; /* table id is always 2 */
3540 if ( 0xB0 != (0xF0 & r[1]) ) { /* check for syntax and zero bit after */
3541 t = 0xF0 & r[1];
3542 if (0 == (0x80 & t))
3543 mprintf2( stdout, "PMT r[1] syntax bit 7 not set: %02X\n", t);
3544 if (0 == (0x30 & t))
3545 mprintf9( stdout, "PMT r[1] reserved bits 4 & 5 are: %02X\n",
3546 0x30 & t);
3549 if ( ( 0xC0 != (0xC0 & r[5]) )
3550 || ( 0xE0 != (0xE0 & r[8]) )
3551 || ( 0xF0 != (0xF0 & r[10]) )
3554 mprintf2( stdout, "PMT reserved bits not set: ");
3555 mprintf2( stdout, "%02X %02X %02X %02X\n",
3556 0xF0 & r[1], 0xC0 & r[5], 0xE0 & r[8], 0xF0 & r[10] );
3557 // return; /* ignore if all reserved bits not set */
3560 sl = ((0xF & r[1])<<8) | r[2];
3562 /* compute CRC32 */
3563 pmt_crc0 = calc_crc32( r, sl-1 );
3565 /* received CRC32 */
3566 pmt_crc = r[ sl - 1 ];
3567 pmt_crc <<= 8;
3568 pmt_crc |= r[ sl ];
3569 pmt_crc <<= 8;
3570 pmt_crc |= r[ sl + 1 ];
3571 pmt_crc <<= 8;
3572 pmt_crc |= r[ sl + 2 ];
3574 if (pmt_crc != pmt_crc0) {
3575 pkt.crcpmt++;
3576 mprintf2( stdout,
3577 "PMT CRC ERROR PID %04X CALC %08X RCVD %08X\n",
3578 pid, pmt_crc0, pmt_crc);
3579 #if 0
3580 for (i = 0; i < 188; i++) {
3581 if (old_pmt[i] != p[i])
3582 mprintf2( stdout,
3583 "p[%d] %02X != %02X\n", i, old_pmt[i], p[i] );
3585 #endif
3586 return;
3587 } else {
3588 if (sl < 180)
3589 memcpy( old_pmt, p, 188);
3593 pgn = (r[3] << 8) | r[4];
3594 vn = 0x1F & (r[5] >> 1);
3596 /* -q OUTPUT REDUX: FIXME: should? fall thru or else -f doesn't work */
3597 if ((0 != arg_redux) && (vn == pid_vn[pid])) return;
3598 pid_vn[pid] = vn; /* multi-VC issue */
3600 /* crc displays after version check */
3601 if (pmt_crc == pmt_crc0) mprintf2( stdout, "PMT CRC %08X OK\n", pmt_crc);
3603 cni = 1 & r[5];
3604 sn = r[6];
3605 lsn = r[7];
3607 mprintf2( stdout, " MPEG PMT PID %04X: SLen %03X VN %02X CNI %01X SN %02X LSN %02X\n",
3608 pid, sl, vn, cni, sn, lsn );
3610 pcrpid = 0x1FFF & ( (r[ 8] << 8) | r[ 9] ); /* PID of stream with PCR */
3611 pilen = 0xFFF & ( (r[10] << 8) | r[11] ); /* program info len */
3612 r += 12;
3614 mprintf2( stdout, " Program %04X PCRPID %04X Program Info Len %03X\n",
3615 pgn, pcrpid, pilen);
3617 mprintf2( stdout, " PROGRAM MAP DESCRIPTORS:\n");
3619 b = pmp->payload + 11 + pilen;
3621 for ( ; r < b; ) {
3624 #if 0
3625 /* this is broken now, use -f option to build_new_pmt instead */
3626 /* only single packet PMTs can be rewritten */
3627 if ((sl < 180) && (0xAA == *r)) {
3628 unsigned int pmt_crc1;
3629 unsigned char *r1;
3631 /* BROKEN: do not know why this construct does not work. Errors are: */
3632 /* invalid operand to binary - */
3633 /* invalid operand to binary + */
3634 /* I can't explain why the operation on the pointer is wrong. use -f. */
3635 r1 = r - pmp->payload;
3636 r1 += p + 5;
3638 mprintf2( stdout, " Tag %02X Dlen %02x RC ", r1[0], r1[1]);
3640 /* FIXME: r is pointing to pmp->payload instead of p+12+desc */
3641 *r1 = 0x80; /* change to stuffing */
3642 pmt_crc0 = calc_crc32( p+5, sl-1 ); /* recompute CRC */
3643 p[ sl+4 ] = 0xFF & (pmt_crc0 >> 24);
3644 p[ sl+5 ] = 0xFF & (pmt_crc0 >> 16);
3645 p[ sl+6 ] = 0xFF & (pmt_crc0 >> 8);
3646 p[ sl+7 ] = 0xFF & pmt_crc0; /* store CRC */
3647 pmt_crc1 = calc_crc32( p+5, sl+3 ); /* extra verify */
3649 /* mprintf2 */
3650 mprintf2( stdout, " Now Tag %02X CRC32 %08X New %08X %s\n",
3651 r1[0], pmt_crc, pmt_crc0, (0 == pmt_crc1) ? "OK":"BAD" );
3653 #endif
3654 test_pmt_descriptor( r );
3655 r += r[1]+2;
3658 acn = 0;
3659 vpid = 0;
3660 apid = 0;
3661 memset( apids, 0, sizeof(apids));
3663 mprintf2( stdout, "\n PROGRAM MAP STREAM TYPES AND DESCRIPTORS:\n\n");
3665 b = pmp->payload + (sl-1);
3667 for ( ; r < b; ) {
3669 /* break out if these reserved bits are not set */
3670 if ( (0xE0 == (0xE0 & r[1]))
3671 && (0xF0 == (0xF0 & r[3])) )
3673 unsigned char *s;
3674 st = r[0];
3675 espid = 0x1FFF & ( (r[1] << 8) | r[2] );
3676 esilen = 0x0FFF & ( (r[3] << 8) | r[4] );
3678 /* check for video pids against list and add if missing */
3679 if (0x02 == st) {
3680 add_vid_pid( espid ); /* counting video separate */
3681 vpid = espid;
3684 /* check for audio pids against list and add if missing */
3685 if (0x81 == st) {
3686 add_aud_pid( espid ); /* counting audio separate */
3687 apids[acn++] = espid;
3690 s = "Reserved";
3691 if (0x7F < st) s = "User Private";
3692 if (0x01 == st) s = "MPEG1 Video";
3693 if (0x02 == st) s = "MPEG2 Video";
3694 if (0x03 == st) s = "MPEG1 Audio";
3695 if (0x04 == st) s = "MPEG2 Audio";
3696 if (0x05 == st) s = "MPEG2 Private";
3698 /* if ( 6 == st) s = "MPEG2 PES Private"; / 13818-1 has this */
3700 if (0x06 == st) s = "A/90 PES sync";
3702 /* rest are not used */
3703 if (0x07 == st) s = "MHEG";
3704 if (0x08 == st) s = "DSM CC";
3705 if (0x09 == st) s = "H.222.1";
3706 if (0x0A == st) s = "13818-6 A";
3707 /* if (11 == st) s = "13818-6 B"; / 13818-1 has this */
3708 if (0x0B == st) s = "A/90 DSM-CC async";
3709 if (0x0C == st) s = "13818-6 C";
3710 /* if (13 == st) s = "13818-6 D"; / 13818-1 has this */
3711 if (0x0D == st) s = "A/90 DSM-CC addressable";
3712 if (0x0E == st) s = "13818-1 Auxiliary";
3713 if (0x81 == st) s = "A/53b Audio"; /* spec says A/53b */
3714 if (0x95 == st) s = "A/90 Data Service Table";
3715 if (0xC2 == st) s = "A/90 PES sync";
3717 mprintf2( stdout,
3718 " Stream Type (%02X) %s ES PID %04X ES Info Len %04X\n",
3719 st, s, espid, esilen);
3721 r += 5; /* skip 5 bytes to get to descriptors */
3723 /* might be multiple descriptors, so do til reach esilen */
3724 if (0 < esilen) mprintf2( stdout, " STREAM DESCRIPTORS\n");
3725 for (i=0; i < esilen; ) { /* bump i manually here */
3726 test_pmt_descriptor( r );
3727 i += r[1]+2; /* add header + data len to i */
3728 r += r[1]+2; /* add header + data len to r */
3730 mprintf2( stdout, "\n");
3731 } else break; /* out of reserved bits */
3734 if (0 != arg_epn) {
3735 if (pgn == arg_epn) {
3736 if (arg_ean < acn) {
3737 apid = apids[ 7 & arg_ean ];
3738 if (0 == apid) apid = apids[0]; /* main if wrong audio */
3739 if (0 != apid) keep_pids[ apid ] = ~0;
3741 if (0 != vpid) keep_pids[ vpid ] = ~0;
3743 /* can only rewrite single packet PMT at this time */
3744 if (sl < 180)
3745 /* rebuild PMT for one video one audio */
3746 if (0 != arg_forge)
3747 build_new_pmt( p, vpid, apid );
3751 /****************************************************************************/
3754 #ifdef USE_A52_PAYLOAD
3755 /************************************************************** A/52 Audio */
3756 // build audio payload may have to adjust for AFC in middle of payload
3757 static
3758 void
3759 build_audio_payload( unsigned char *p )
3761 unsigned int psi, pid;
3762 unsigned char afc;
3763 // unsigned char afl;
3764 unsigned char *r, pl;
3765 // unsigned char i, j;
3766 int ok;
3768 pid = 0x1FFF & ( (p[1] << 8) | p[2] ); // packet id
3769 psi = 1 & (p[1]>>6); // payload start indicator
3770 afc = 3 & (p[3]>>4); // adaptation field control
3772 r = p+4; // skip transport header
3774 #if 0
3775 // won't be needed unless somehow audio is the clock ref PID
3776 // KTRK is sending AFC 3 on audio and AFC 3 on video. Yikes!
3778 if (afc > 1) {
3779 afl = *r; // adaptation field length
3780 if (afl > 0) // afc=2 = afl=0xB7 says spec
3781 test_mpeg2_adaptation_field( p ); // parse the field
3782 if (2 == afc) return; // no payload follows
3783 r++; // skip field length byte
3784 r += afl; // skip past entire field
3786 #endif
3788 pl = (p+188) - r; // wouldnt 184 be easier? oh adaptation header above...
3790 #ifdef USE_ES_EXTRACT
3791 // FIXME: broken elsewhere, -y option should extract ES to .es file
3792 if (pid == arg_espid) {
3793 #ifdef USE_BUFFER
3794 ok = write_buffer(es_buf, r, pl); /* fast */
3795 #else
3796 ok = write(out_file, r, pl);
3797 #endif
3799 /* writes should always pass */
3800 if (ok != pl) {
3801 fprintf(stdout, "%s ES write %s failed\n", WHO, es_name);
3802 exit(1);
3805 #endif
3807 if (1 == psi)
3809 if (1 == aud.payok)
3811 // only if no continuity counter error
3812 if (0 == pid_cc[ pid ])
3814 mprintf6( stdout,
3815 " DONE A/52 Audio PID %04X Payload %05X bytes\n",
3816 pid, aud.payoff );
3818 mprintf3( stdout, "\n A/52 Audio # %8d PID %04X # %8d\n\n",
3819 pkt.aud, pid, pids[ pid ]);
3821 // do these BEFORE it gets overwritten by next packet
3823 } else {
3824 mprintf6( stdout, " *DROP previous discontinuous A/52 payload\n");
3828 mprintf6( stdout, " START A/52 Audio PID %04X Payload\n", pid);
3829 aud.payok = 0;
3830 aud.payoff = 0;
3831 memset( aud.payload, 0, sizeof(aud.payload) );
3832 memcpy( aud.payload, r, pl);
3833 aud.payoff += pl;
3834 } else {
3835 if (0 == aud.payoff) {
3836 mprintf6( stdout, " *DROP A/52 Audio PID %04X w/o psi\n", pid);
3837 } else {
3838 aud.payok = 0;
3839 if ( (aud.payoff+pl) >= sizeof(aud.payload) ) {
3840 mprintf3( stdout, "\n A/52 Audio PID %04X payoff %d is over %d bytes\n",
3841 pid, aud.payoff+pl, sizeof( aud.payload ) );
3842 return;
3845 // j = 0; // zero detect not needed for A/52
3846 // for (i=0; i<pl; i++) j |= r[i];
3848 if (0 == pid_cc[ pid ] ) {
3849 memcpy( &aud.payload[ aud.payoff ], r, pl );
3850 mprintf6( stdout,
3851 " COPY A/52 Audio PID %04X Payload offset %05X\n",
3852 pid, aud.payoff);
3853 aud.payoff += pl;
3854 aud.payok = 1;
3855 } else {
3856 mprintf6( stdout,
3857 " *DROP A/52 Audio PID %04X continuity error\n", pid);
3858 aud.payoff = 0;
3859 aud.payok = 0;
3864 #endif
3866 /**************************************************************** A/52 Audio */
3867 /*no afc on these, should be PES AC-3 only. could extract by itself. */
3868 static
3869 void
3870 test_a52_audio( unsigned char *p )
3872 unsigned short pid;
3874 pkt.aud++; // total audio, have to use pid lut for individual audio
3876 if (0 != arg_epn) {
3877 if (0 == pkt.pmt) return; /* no audio until pmtpid found */
3878 if (0 == pkt.vid) return; /* no audio until first video */
3880 pid = 0x1FFF & ( (p[1] << 8) | p[2] ); // packet id
3882 #if USE_A52_PAYLOAD
3883 build_audio_payload( p );
3884 #endif
3887 /****************************************************************************/
3890 /**************************************************************** MPEG2 Video */
3891 /* build video payload adjusts for AFC at start of payload */
3892 static
3893 void
3894 build_video_payload( unsigned char *p )
3896 int ok, pl;
3897 unsigned int psi, pid, afc, afl;
3898 unsigned char *r;
3899 unsigned int i;
3900 unsigned int j;
3901 // unsigned char *t;
3903 pid = 0x1FFF & ( (p[1] << 8) | p[2] ); // packet id
3904 psi = 1 & (p[1]>>6); // payload start indicator
3905 afc = 3 & (p[3]>>4); // adaptation field control
3907 #if 0
3908 if (0 != psi) {
3909 fprintf( stdout, "\n PSI ");
3910 for( i= 0 ; i < 20; i++) fprintf( stdout, "%02X ", p[i] );
3911 fprintf( stdout, "AFC%d\n", afc);
3913 #endif
3915 r = p+4; // skip transport header
3917 /* AFC can occur in the middle of any payload? */
3918 if (afc > 1) {
3919 afl = *r; // adaptation field length
3920 if (afl > 0) // afc=2 = afl=0xB7 says spec
3921 test_mpeg2_adaptation_field( p ); // parse the field (PCR)
3922 if (2 == afc) return; // no payload follows
3923 r++; // skip field length byte
3924 r += afl; // skip past entire field
3926 // return;
3928 pl = (p+188) - r; // payload count after ts and adaptation headers
3930 #ifdef USE_ES_EXTRACT
3931 // WORKS: -y option extracts Video ES to .es file, no TS header or AFC
3932 // It does leave some PES data that confuses Xine, but not mpeg2dec
3933 if (pid == arg_espid) {
3934 #ifdef USE_BUFFER
3935 ok = write_buffer(es_buf, r, pl);
3936 #else
3937 ok = write(es_file, r, pl);
3938 #endif
3940 /* writes should always pass */
3941 if (ok != pl) {
3942 fprintf(stdout, "%s ES write %s failed\n", WHO, es_name);
3943 exit(1);
3946 #endif
3948 /* payload start indicator set */
3949 if (1 == psi)
3951 ppsbytes_in = psbytes_in;
3952 psbytes_in = bytes_in;
3954 /* look for sequence header in first packet, after AFC */
3955 test_mpeg2_video_seq( r, pl );
3956 if (0 != arg_seqwr) return; /* -s option doesn't need more */
3958 /* TESTME: vid.payok is 0 first time through? should be 1 */
3959 if (1 == vid.payok)
3961 if (0 == pid_cc[ pid ])
3962 { // but only if no CC error
3963 for (i = vid.payoff; i > 0; i-- ) {
3964 if (0 != vid.payload[i]) break; // non zero is non stuffing
3966 if ( (i + 4) < vid.payoff) i += 4; // point forwards a bit
3967 j = vid.payoff - i; // stuffing count
3968 mprintf6( stdout,
3969 " DONE MPEG Video PID %04X Payload %05X, data %05X, zeroes %5X %c\n",
3970 // pid, vid.payoff, i, j, (( j<<1) < vid.payoff) ? ' ':'*');
3971 pid, vid.payoff, i, j, (j < 188) ? ' ':'*');
3973 mprintf4( stdout, "\n MPEG Video # %8d PID %04X # %8d\n\n",
3974 pkt.vid, pid, pids[ pid ]);
3976 /* -s and -q options do not fully parse video headers */
3978 /* -m8 option needed to parse rest of payload */
3979 if (0 != (8 & arg_mdump))
3980 test_mpeg2_video_es();
3983 } else {
3984 mprintf6( stdout, " *DROP previous MPEG2 payload\n" );
3985 } // but still have to copy current new start payload
3988 mprintf6( stdout, "\n START MPEG Video PID %04X Payload\n", pid);
3989 vid.payok = 0;
3990 vid.payoff = 0;
3992 // clear it so zero detect works
3993 memset( vid.payload, 0, sizeof(vid.payload) );
3994 memcpy( vid.payload, r, pl);
3995 vid.payoff += pl;
3996 } else {
3997 // payload start indicator not set
3998 if (0 == vid.payoff) {
3999 mprintf6( stdout, " *DROP MPEG Video PID %04X w/o psi\n", pid);
4000 } else {
4001 vid.payok = 0;
4002 if ( (vid.payoff+pl) >= sizeof(vid.payload) ) {
4003 mprintf4( stdout,
4004 "\n MPEG PID %04X payoff %d is over %d bytes\n",
4005 pid, vid.payoff+pl, sizeof( vid.payload ) );
4006 return;
4009 /* -m8 to keep building payload, otherwise skip all the cycles */
4010 if (0 == (8 & arg_mdump)) return;
4013 // zero detect to end payload early
4014 // will have 0-187 bytes of 0 stuffing per payload
4015 j = 0;
4016 for (i=0; i < pl; i++) j |= r[i];
4018 // now cc error here in middle of payload is bad news,
4019 // so will drop entire payload to wait for next psi.
4020 // make this optional. decoder might have a few tricks.
4021 // if ( 0 == pid_cc[ pid ] )
4022 if (1)
4024 memcpy( &vid.payload[ vid.payoff ], r, pl );
4025 mprintf6( stdout,
4026 " COPY MPEG Video PID %04X Payload offset %05X %s\n",
4027 pid, vid.payoff, (j==0)?"ZERO":"");
4028 vid.payoff += pl;
4029 vid.payok = 1;
4030 } else {
4031 mprintf6( stdout,
4032 " *DROP MPEG Video PID %04X continuity error\n", pid);
4033 vid.payoff = 0; // will inhibit this until next psi
4034 vid.payok = 0; // will inhibit previous bad payload write
4041 no crc available as far as i know. mpeg2 has a provision for it,
4042 but ATSC spec claims it should be 0 (not used?)
4043 or didn't understand what i was reading.
4044 these two not sure how to handle, can't do CRC on them.
4045 CABLE: these have a very good chance of being scrambled eggs useless.
4046 adaptation field might have interesting values in it and there may be
4047 some mpeg2 letterbox/pillarbox indicators too, but none seen so far
4050 /* gprof: reduce number of calls if not doing slice level */
4052 static
4053 void
4054 test_mpeg2_video ( unsigned char *p )
4056 int psi;
4058 psi = 1 & (p[1]>>6);
4060 pkt.vid++;
4062 // if (0 != arg_redux) return;
4064 if (0 < arg_epn)
4065 if (0 == pkt.pmt) /* wait until first PMT for this program */
4066 return;
4068 if (0 != arg_espid) {
4069 build_video_payload( p );
4070 return;
4072 /* -s option needs to generate sequence byte offset and picture type if psi */
4073 if (0 != arg_seqwr) {
4074 if (0 != psi) {
4075 build_video_payload( p );
4077 } else {
4078 /* -q option is quick scan, doesn't need build payload */
4079 if (0 != (8 & arg_mdump))
4080 build_video_payload( p );
4083 // pkt.vid++; /* count all */
4085 /****************************************************************************/
4087 static
4089 find_pa_pid( unsigned int pid )
4091 int i;
4092 for (i = 0; i < pat_ncs; i++)
4093 if (pid == pa[i].pmtpid)
4094 return i;
4095 return -1;
4099 /**************************************************************** MPEG2 PID */
4100 /*ATSC parsed out, whats left is PAT, CAT, PMT, MPEG Video and A/52 Audio ES
4101 tei should have been checked in test packet. control PID are PAT CAT PMT
4102 no need to explore MPEG2 here, check CRC of control PID and log result
4104 static
4105 void
4106 test_mpeg2_packet( unsigned char *p )
4108 unsigned int psi, pid, afc;
4109 int pan;
4111 pid = 0x1FFF & ( (p[1] << 8) | p[2] ); // packet id
4112 psi = 1 & (p[1]>>6); // payload start indicator
4113 afc = 3 & (p[3]>>4); // adaptation field control
4115 // update counters
4116 pkt.mpeg2++;
4118 //////////////////////////////////////////////////////////// MPEG2 PAT PMT
4119 // first two table type pids for mpeg2 transport. cat is ignored
4121 // Program Association Table, should always be single packet?
4122 if (pid == 0) {
4123 test_pat( p ); // crc check at least
4124 return;
4127 // Conditional Access Table, could be multiple packet?
4128 if (pid == 1) {
4129 test_cat( p ); // crc check at least
4130 return;
4133 /* is the pmt on the pa list? will force pmt parse to after first PAT */
4134 pan = find_pa_pid( pid );
4135 if (-1 < pan) {
4136 test_pmt( p, pan );
4137 return;
4141 /////////////////////////////////////////////////////////// MPEG2 PAT & CAT
4143 /////////////////////////////////////////////////////////////////// MPEG2 PES
4144 /* -q output redux option doesn't need MPEG data */
4145 // if ( (0 == (8 & arg_mdump)) && (0 == arg_seqwr) ) return;
4146 if ( (0 != arg_redux) && (0 == arg_seqwr) && (0 == arg_espid))
4147 return;
4149 if (0 == test_vid_pid( pid )) {
4150 test_mpeg2_video( p );
4151 } else {
4152 if (0 == test_aud_pid( pid )) {
4153 test_a52_audio( p );
4157 pkt.pes++;
4158 return; // match returns
4160 //////////////////////////////////////////////////////////////////// MPEG2 PES
4164 /////////////////////////////////////////////////////////////////////// VCT
4166 // A/65b Table 6.29 Service Location Descriptor
4167 static
4168 void
4169 test_vct_svloc( unsigned char *r)
4171 unsigned short pcpid;
4172 unsigned char nelm;
4173 unsigned char i;
4175 if ( 0xE0 == (r[0] & 0xE0))
4177 pcpid = ((0x1F & r[0])<<8) | r[1]; // PCR PID
4178 nelm = r[2]; // number of elementary streams
4179 aprintf2( stdout, "PCR PID %04X, num ES %02X\n", pcpid, nelm);
4180 r += 3;
4181 for (i = 0; i < nelm; i++) {
4182 if (0xE0 == (0xE0 & r[1])) {
4183 unsigned short epid;
4184 unsigned char strt;
4185 unsigned char *strx;
4186 unsigned char lang[4];
4188 strx = "*unparsed*";
4190 memset(lang, 0, sizeof(lang));
4191 strt = *r++; // stream type
4192 epid = ((0x1F & r[0])<<8) | r[1]; // elementary program id
4193 r += 2;
4194 memcpy( lang, r, 3 );
4195 r += 3;
4196 lang[4] = 0; // language
4197 if (strt == 0x02) strx = "MPEG Video";
4198 if (strt == 0x81) strx = "A/52 Audio";
4199 // rest is all A/90 spec that isn't used
4201 aprintf2( stdout,
4202 " Stream Type (%02X) %s ES PID %04X [%s]\n",
4203 strt, strx, epid, lang);
4204 // fflush(stdout);
4211 // A/65b Table 6.38 Multiple String Structure
4212 // does do huffman decomp
4213 static
4214 void
4215 test_vct_mss( unsigned char *r)
4217 unsigned int nstr, nseg, comp, mode, nchr;
4218 unsigned int i,j,k;
4219 unsigned char lang[4];
4220 unsigned char s[256];
4221 unsigned char d[512];
4222 // unsigned char *t;
4224 memset( s, 0, sizeof(s));
4225 nstr = r[0];
4227 nstr = 1; /* force to one */
4228 for (i = 0; i < nstr; i++) {
4229 memcpy(lang, &r[1], 3);
4230 lang[3] = 0;
4231 r += 4; // 3?
4232 nseg = *r++;
4234 nseg = 1; /* force to one */
4235 for (j = 0; j < nseg; j++) {
4236 comp = *r++;
4237 mode = *r++;
4238 nchr = *r++;
4239 for (k = 0; k < nchr; k++) s[k] = *r++;
4241 // show non-compressed
4242 if ( (0 == comp) && (0 == mode) ) {
4243 aprintf2( stdout, "[%s] [%-s]", lang, s);
4246 // show huffman compressed
4247 if (
4248 // (mode == 0xFF) && // spec requires, KPXB ignores
4249 (comp > 0) &&
4250 (comp < 3)
4253 huffman_decode( d, s, sizeof(d), nchr, comp);
4254 aprintf2( stdout, "[%s] [%-s]", lang, d);
4256 // show as unknown compress
4257 if (comp > 2) aprintf2( stdout, "[%s] [L%02X C%02X M%02X]",
4258 lang, nchr, comp, mode);
4261 aprintf2( stdout, "\n");
4265 // r points to start of descriptors
4266 // do until len exhausted
4267 static
4268 void
4269 test_vct_descriptor( unsigned char *p, unsigned int len )
4271 unsigned char dtag, dlen;
4272 unsigned char *r, *t;
4274 r = p;
4275 dtag = dlen = 0;
4277 t = "*unknown*";
4279 while ( len > 0 ) {
4280 dtag = *r++;
4281 dlen = *r++;
4282 len -= 2;
4283 // aprintf2( stdout, " VCT DESCRIPTORS:\n");
4284 switch( dtag ) {
4286 // extended channel name descriptor is mulitple string structure
4287 case 0xA0:
4288 t = "Extended Channel Name:\n ";
4289 aprintf2( stdout, " VCT Tag %02X DLen %02X %s", dtag, dlen, t);
4290 test_vct_mss(r);
4291 break;
4293 // service location descriptor
4294 case 0xA1:
4295 t = "Service Location";
4296 aprintf2( stdout, " VCT Tag %02X DLen %02X %s: ", dtag, dlen, t);
4297 test_vct_svloc(r);
4298 break;
4300 // time shifted service descriptor
4301 case 0xA2:
4302 t = "Time Shifted Service";
4303 aprintf2( stdout, " VCT Tag %02X DLen %02X %s: ", dtag, dlen, t);
4304 break;
4306 // got some weird ones showing up here need to parse?
4307 default:
4308 t = "ignored";
4309 aprintf2( stdout, " VCT *Tag %02X DLen %02X: %s\n", dtag, dlen, t);
4310 break;
4312 r += dlen;
4313 len -= dlen;
4318 // not going to implement. verify top bits and count only
4319 static
4320 void
4321 test_dccsct( unsigned char *p )
4323 pkt.dccsct++;
4324 return;
4327 // not going to implement. verify top bits and count only
4328 static
4329 void
4330 test_dcct( unsigned char *p )
4332 pkt.dcct++;
4333 return;
4338 // A/65b Table 6.38 Multiple String Structure
4339 // does do huffman decomp
4340 static
4341 void
4342 test_rrt_mss( unsigned char *r)
4344 unsigned int nstr, nseg, comp, mode, nchr;
4345 unsigned int i,j,k;
4346 unsigned char lang[4];
4347 unsigned char s[256];
4348 unsigned char d[512];
4350 memset( s, 0, sizeof(s));
4351 nstr = r[0];
4352 for (i = 0; i < nstr; i++) {
4353 memcpy(lang, &r[1], 3);
4354 lang[3] = 0;
4355 r += 4; // 3?
4356 nseg = *r++;
4357 for (j = 0; j < nseg; j++) {
4358 comp = *r++;
4359 mode = *r++;
4360 nchr = *r++;
4361 for (k = 0; k < nchr; k++) s[k] = *r++;
4363 // aprintf5( stdout, "\n RRT L%02X C%02X M%02X ", nchr, comp, mode);
4364 // show non-compressed
4365 if ( (0 == comp) && (0 == mode) ) {
4366 aprintf5( stdout, "[%s] [%-s] ", lang, s);
4368 // show huffman compressed
4369 if (
4370 // (mode == 0xFF) && // spec requires, KPXB ignores
4371 (comp > 0) &&
4372 (comp < 3)
4375 huffman_decode( d, s, sizeof(d), nchr, comp);
4376 aprintf5( stdout, "[%s] [%-s] ", lang, d);
4378 // show as unknown compress
4379 if (comp > 2) aprintf5( stdout, "[%s] [L%02X C%02X M%02X]",
4380 lang, nchr, comp, mode);
4387 // payload assembly for RRT
4388 static
4389 unsigned int
4390 build_rrt_payload( unsigned char *p )
4392 unsigned char *r;
4393 unsigned char psi;
4394 //, vn;
4396 r = p+5;
4398 psi = 1 & ( p[1] >> 6);
4400 // handle payload start packet by copying start to RRT payload buffer
4401 if (psi != 0)
4403 if ( (0xCA == r[0]) // table id RRT
4404 && (0xF0 == (0xF0 & r[1]) ) // syntax,private,reserved bits
4405 && (0xC1 == (0xC1 & r[5]) ) // reserved bits
4408 rrt_vn = 0x1F & ( r[5] >> 1);
4409 rrt.sl = ((0xF & r[1])<<8) | r[2];
4411 rrt.payoff = 183;
4412 aprintf6( stdout,
4413 " START RRT Version %02X SLen %03X Payoff %03X\n",
4414 rrt_vn, rrt.sl, rrt.payoff);
4416 memset( rrt.payload, 0, sizeof(rrt.payload) );
4417 memcpy( rrt.payload, r, rrt.payoff );
4419 if ( rrt.payoff > rrt.sl+3 ) {
4420 aprintf6( stdout, " DONE RRT\n");
4421 return 0;
4424 return 1;
4427 r = p+4;
4429 // additional non start payloads append to RRT payload buffer
4430 if ( psi == 0 ) {
4431 memcpy( &rrt.payload[rrt.payoff], r, 184);
4432 rrt.payoff += 184;
4433 aprintf6( stdout,
4434 " COPY RRT Version %02X SLen %03X Payoff %03X\n",
4435 rrt_vn, rrt.sl, rrt.payoff);
4437 if ( rrt.payoff > rrt.sl+3 ) {
4438 aprintf6( stdout, " DONE RRT\n");
4439 return 0;
4441 return 1;
4444 aprintf6( stdout, "RRT not parsed\n");
4445 return 1;
4450 // Content Advisory description text in EIT makes this redundant.
4451 // but has to be parsed for completeness for stations w/o description
4452 static
4453 void
4454 test_rrt( unsigned char *p )
4456 unsigned char *r;
4457 unsigned short sl, dl;
4458 unsigned char vn, cni, sn, lsn, pv;
4459 unsigned char i, j, rr, rrnl, dd, ddnl, arvl, rvl, gs, vd;
4461 rrt.payok = build_rrt_payload( p );
4462 if (0 == rrt.payok) {
4464 pkt.rrt++;
4465 r = rrt.payload;
4467 if ((0xCA != r[0]) || (0xFF != r[3]) ) {
4468 aprintf5( stdout, " RRT has bad TT/RB\n");
4469 return;
4472 sl = 0xFFF & ((r[1]<<8) | r[2]); // section len
4473 if (sl > 1021) return; // not allowed
4475 rrt_crc = calc_crc32( r, sl+3); // crc check
4476 if (0 != rrt_crc) {
4477 pkt.crcrrt++;
4478 aprintf5( stdout, " RRT CRC ERROR\n");
4479 //rrt_crc, r[sl], r[sl+1], r[sl+2], r[sl+3]);
4480 return;
4483 aprintf5( stdout, "RRT CRC OK\n");
4484 vn = 0x1F & (r[5]>>1);
4485 cni = 1 & r[5];
4486 sn = r[6];
4487 lsn = r[7];
4488 pv = r[8];
4490 rr = r[4];
4492 r += 9; // skip parsed
4493 aprintf5( stdout, " RRT # %d SLen %03X Ver %02X CNI %d SN %02X LSN %02X PV %02X\n",
4494 pkt.rrt, sl, vn, cni, sn, lsn, pv);
4496 aprintf5( stdout, " Rating Region: ");
4497 rrnl = r[0];
4498 r++;
4499 test_rrt_mss( r );
4500 aprintf5( stdout, "\n");
4502 r += rrnl;
4504 dd = r[0];
4505 r++;
4506 // dimension names
4507 for (i = 0; i < dd; i++) {
4508 ddnl = r[0];
4509 r++;
4510 aprintf5( stdout, " Dimension Index %d Name: ", i);
4511 test_rrt_mss( r );
4512 aprintf5( stdout, "\n");
4513 r += ddnl;
4514 if (0xE0 == (0xE0 & r[0])) {
4515 gs = 1 & (r[0] >> 4);
4516 vd = 0xF & r[0];
4517 r++;
4518 aprintf5( stdout, " %sRating Values %d:\n",
4519 ( 0 == gs) ? "":"Graduated ", vd );
4520 for (j = 0; j < vd; j++) {
4521 arvl = r[0];
4522 r++;
4523 aprintf5( stdout, " Index %d ", j);
4524 // abbreviated rating values
4525 test_rrt_mss( r );
4526 r += arvl;
4527 rvl = r[0];
4528 r++;
4529 aprintf5( stdout, "\t");
4530 // rating value
4531 test_rrt_mss( r );
4532 r += rvl;
4533 aprintf5( stdout, "\n");
4535 // aprintf5( stdout, "\n" );
4539 // final descriptors
4540 if ( 0xFC == r[0] ) {
4541 dl = 0x3FF & ( ( r[0]<<8) | r[1] );
4542 aprintf5( stdout, "RRT DESCRIPTORS LEN %03X\n", dl);
4543 // rrt descriptors, not sure what kind they are
4547 aprintf5( stdout, "\n");
4551 /***************************************************************** ATSC ETT */
4553 #if 0
4554 /* look up vc# 0-n by program number */
4555 static
4557 find_vc_pgm( unsigned short pn )
4559 int i;
4560 if (vct_ncs < 1) return -1;
4562 for (i=0; i < vct_ncs; i++)
4563 if (pn == vc[i].pgm)
4564 return i;
4565 return -1;
4567 #endif
4569 /* Return VC index 0-n from source id (top 16 bits of ETMID), or return -1. */
4570 static
4572 find_vc_src( unsigned short sr )
4574 int i;
4575 if (vct_ncs < 1) return -1;
4577 for (i=0; i < vct_ncs; i++)
4578 if (sr == vc[i].src)
4579 return i;
4580 return -1;
4584 /* Extract source id from etmid to limit search length to events on this VC.
4585 * Return pgm[] index of matching etmid found or return -1.
4586 * TODO: Export this change to atscap, it can save some CPU.
4588 static
4590 find_pgm_etmid( unsigned int etmid )
4592 int i, j, z, vcn, sr;
4594 sr = etmid>>16;
4595 vcn = find_vc_src( sr );
4597 z = EIZ * PEZ;
4598 j = vcn * z;
4600 /* 0 to 1024 search, could be reduced to 0-768 search. 769-1023 are blanks */
4601 for (i = 0; i < z; i++)
4602 if (etmid == pgm[ i + j ].etmid) return i;
4603 return -1;
4607 /* A/65b Table 6.38 Multiple String Structure */
4608 /* does do huffman decomp */
4609 /* n is ETT n */
4610 static
4611 void
4612 test_ett_mss( unsigned char *r, unsigned int n, unsigned int etmid, int pgo)
4614 unsigned int nstr, nseg, comp, mode, nchr, onchr, sr, i, j;
4615 unsigned char lang[4];
4616 unsigned char s[PDZ];
4617 unsigned char d[PDZ];
4618 unsigned char *t; /* points to uncompressed */
4620 nstr = r[0];
4621 nstr = 1; /* override */
4623 sr = 0x7 & (etmid>>16);
4625 n &= 0x7f;
4627 for (i = 0; i < nstr; i++) {
4628 memcpy(lang, &r[1], 3);
4629 lang[3] = 0;
4630 r += 4; /* 3? */
4631 nseg = *r++;
4633 nseg = 1; /* override */
4635 for (j = 0; j < nseg; j++) {
4637 comp = *r++;
4638 mode = *r++;
4639 nchr = *r++;
4641 onchr = nchr;
4644 /* each seg n has chars n */
4645 memset( s, 0, PDZ); /* clear old */
4646 memset( d, 0, PDZ);
4647 onchr = nchr;
4649 memcpy( s, r, nchr); /* keep last nul */
4651 t = s; /* point to source, it may be uncompressed */
4652 aprintf4( stdout, " ETT-%02X pg[%04X] ETMID %08X ", n, pgo, etmid);
4653 aprintf4( stdout, "[L%02X C%02X M%02X] ", onchr, comp, mode);
4655 /* non-compressed */
4656 if ( (0 == comp) && (0 == mode) ) {
4657 aprintf4( stdout, "[%s]\n [%-s]", lang, s);
4660 /* huffman compressed */
4661 if (
4662 /* (mode == 0xFF) && spec requires, KPXB ignores */
4663 (comp > 0) &&
4664 (comp < 3)
4667 t = d; /* point to decomp text */
4668 huffman_decode( d, s, sizeof(d), onchr, comp);
4669 aprintf4( stdout, "[%s] Huffman\n [%-s]", lang, d);
4671 /* unknown compression as numeric detail */
4672 if (comp > 2) {
4673 t = d; /* point to detail */
4674 snprintf( d, sizeof(d)-1, "[%s] [L%02X C%02X M%02X]",
4675 lang, onchr, comp, mode);
4678 /* if pgo was not found, can't update the description */
4679 if (-1 == pgo) {
4680 aprintf4( stdout,
4681 "\n *ignored ETT-%02X ETMID %08X, no EIT pgm[] match",
4682 n, etmid);
4684 /* FIXME: -q version redux needs to clear saved version if no EIT pgm match */
4685 // this is not enough
4686 // if (vcn >= 0) ettvn[ (vcn << 7) + n ] = 0xFF; /* vcn * 128 */
4688 } else {
4690 /* copy uncompressed description to program guide */
4691 memcpy( pgm[ pgo ].desc, t, PDZ );
4692 /* fprintf( stdout, "\npgo %04X ETMID %08X %s <- %s", */
4693 /* pgo, pgm[pgo].etmid, pgm[pgo].name, pgm[pgo].desc); */
4695 r += onchr; /* got chars n, get next seg */
4698 aprintf4( stdout, "\n");
4702 /* add to ett payload. returns 0 if done, or 1 if not done */
4703 static
4704 unsigned int
4705 build_ett_payload( unsigned char *p, unsigned int n )
4707 unsigned int psi, tei;
4708 unsigned char *r;
4710 psi = 1 & (p[1]>>6);
4711 tei = 1 & (p[1]>>7);
4712 if (tei != 0) return 1;
4714 r = p+5;
4715 /* handle payload start packet by copying start to ETT payload buffer */
4716 if (psi != 0) {
4717 /* ett[n].payoff = 0; */
4718 if ( (0xCC == r[0])
4719 && (0xF0 == (0xF0 & r[1]) )
4720 && (0xC1 == (0xC1 & r[5]) )
4723 ett[n].sl = ((0xF & r[1])<<8) | r[2];
4724 ett[n].payoff = 183;
4725 ett_vn = 0x1F & (r[5]>>1);
4727 aprintf6( stdout,
4728 " START ETT-%02X Version %02X SLen %03X Payoff %03X\n",
4729 n, ett_vn, ett[n].sl, ett[n].payoff);
4730 memset( ett[n].payload, 0, sizeof(ett[n].payload) ); /* reset */
4731 memcpy( ett[n].payload, r, ett[n].payoff);
4733 if ( ett[n].payoff > ett[n].sl+3 ) {
4734 aprintf6( stdout, " DONE ETT-%02X\n", n);
4735 return 0;
4737 return 1;
4741 r = p+4;
4743 /* additional non start payloads append to ETT payload buffer */
4744 if ( (ett[n].sl > 179) && (0 == psi) ) {
4745 memcpy( &ett[n].payload[ett[n].payoff], r, 184);
4747 ett[n].payoff += 184;
4749 aprintf6( stdout, " COPY ETT-%02X Version %02X SLen %03X Payoff %03X\n",
4750 n, ett[n].vn, ett[n].sl, ett[n].payoff );
4752 if ( ett[n].payoff > ett[n].sl+3 ) {
4753 aprintf6( stdout, " DONE ETT-%02X\n", n);
4754 return 0;
4756 return 1;
4758 aprintf6( stdout, " ETT-%02X not parsed\n", n);
4759 return -1;
4763 /* process ett packet based on payload start indicator */
4764 static
4765 void
4766 test_ett ( unsigned char *p, unsigned int n )
4768 unsigned char *r;
4769 unsigned short sl, etidx, sr;
4770 unsigned char vn, cni, sn, lsn, pv;
4771 unsigned int etmid;
4772 unsigned int ett_crc = 0;
4773 int vcn, pgo;
4775 p.0 is 0x47 sync
4776 p.1 is 3 bits tei psi pri, 5 high bits pid
4777 p.2 is 8 bits low bits pid
4778 p.3 is tsc afc cc
4779 p.4 is 0 if table and payload start indicator 1 else data
4780 p.5 is table id if payload start indicator 1 else data
4782 /* returns 0 if payload complete, else nz */
4783 ett[n].payok = build_ett_payload( p, n );
4784 if (0 != ett[n].payok) return;
4786 r = ett[n].payload;
4788 if (0xCC != r[0]) {
4789 aprintf4( stdout, " Table ID not ETT 0xCC but 0x%02X\n", r[0]);
4790 return;
4793 sl = ((0xF & r[1])<<8) | r[2]; /* section len */
4794 ett_crc = calc_crc32( r, sl+3); /* crc check */
4795 if (0 != ett_crc) {
4796 pkt.crcett++;
4797 aprintf4( stdout, " ETT-%02X CRC ERROR\n", n);
4798 return;
4801 pv = r[8];
4802 if (pv != 0) {
4803 aprintf4( stdout, " ETT-%02X Protocol %02X not 0\n", n, pv);
4804 return; /* protocol 0 only */
4806 etidx = (r[3] << 8) | r[4]; /* should be 0 */
4809 dont treat as fatal to packet processing
4810 CBS KHOU seems to use table id extension bits and is allowed by spec
4812 if (etidx != 0) {
4813 aprintf4( stdout,
4814 "\n ETT-%02X table id extension %04X is not 0\n", n, etidx);
4815 return;
4819 vn = (0x3E & r[5]) >> 1;
4821 cni = 1 & r[5];
4822 sn = r[6];
4823 lsn = r[7];
4825 etmid = (r[9]<<24) | (r[10]<<16) | (r[11]<<8) | r[12];
4826 sr = etmid>>16;
4828 pkt.ett++;
4830 vcn = find_vc_src( sr ); /* get 0-n index for VC # from source # */
4832 /* holds down ETT display until VCT seen */
4833 if (vcn < 0) return;
4834 pgo = find_pgm_etmid( etmid );
4836 /* OUTPUT REDUX: */
4837 if (0 != arg_redux) {
4838 /* do nothing if no ETMID from previously reeived EIT */
4839 if (pgo < 0) return;
4840 /* do nothing if version stays the same */
4841 if (vn == ettvn[ (vcn << 7) + n ]) return;
4844 /* only update version if previous etmid found, -g -q missing desc fix */
4845 ettvn[ (vcn << 7) + n ] = vn; /* vcn * 128 */
4847 aprintf4( stdout, "ETT-%02X CRC OK\n", n);
4849 aprintf4( stdout," ETT-%02X VER %02X SLen %03X CNI %d "
4850 "SecN %02X LSecN %02X etmID %08X pgo %d\n",
4851 n, vn, sl, cni, sn, lsn, etmid, pgo );
4853 r += 13; /* skip parsed */
4855 test_ett_mss( r, n, etmid, pgo );
4857 aprintf4( stdout, "\n");
4858 return;
4862 /***************************************************************** ATSC EIT */
4863 /* Event Information Table Content Advisory (Rating Region Table text) */
4864 /* A/65b Table 6.38 Multiple String Structure */
4865 /* does do huffman decomp */
4866 static
4867 void
4868 test_eit_rr_mss ( unsigned char *r )
4870 unsigned int nstr, nseg, comp, mode, nchr;
4871 unsigned int i,j,k;
4872 unsigned char lang[4];
4873 unsigned char s[256];
4874 unsigned char d[512];
4875 /* unsigned char *t; */
4877 nstr = r[0];
4878 // aprintf3( stdout, "%s nstr %d\n", __FUNCTION__, nstr); // debug
4880 /* ATSC constrained to 1 string, 1 segment */
4881 // nstr = 1;
4882 for (i = 0; i < nstr; i++) {
4883 memcpy(lang, &r[1], 3);
4884 lang[3] = 0;
4886 r += 4;
4887 nseg = *r;
4888 r++;
4890 /* ATSC constrained to 1 string, 1 segment */
4891 // nseg = 1;
4892 for (j = 0; j < nseg; j++) {
4893 comp = *r++;
4894 mode = *r++;
4895 nchr = *r++;
4898 /* if no characters in this segment, loop until out of segments */
4899 if (nchr < 1 ) continue;
4901 memset( s, 0, sizeof(s));
4902 /* copy string but keep nul term */
4903 for (k = 0; k < nchr; k++)
4904 if (k < (sizeof(s)-1))
4905 s[k] = r[k];
4907 /* show non-compressed */
4908 if ( (0 == comp) && (0 == mode) ) {
4909 aprintf3( stdout,
4910 "[%02X][%02X] L%02X C%02X M%02X [%s] [%-s] ",
4911 nstr, nseg, nchr, comp, mode, lang, s);
4913 /* huffman compressed, comp 1 or 2 only (should be 1, title comp only) */
4914 if ( (comp > 0) &&
4915 (comp < 3)
4916 /* KPXB ignores the mode == 0xFF at least a year ago */
4917 /* && (mode == 0xFF) */
4920 huffman_decode( d, s, sizeof(d), nchr, comp);
4921 aprintf3( stdout, "[%s] huff [%-s] ", lang, d);
4924 /* show as unknown compress */
4925 if (comp > 2)
4926 aprintf3( stdout, "[%s] unk [L%02X C%02X M%02X]",
4927 lang, nchr, comp, mode);
4929 /* unused in ATSC; multi segment string would need this with nseg > 1 */
4930 r+= nchr;
4933 aprintf3( stdout, "\n");
4938 /* A/65b Table 6.38 Multiple String Structure */
4939 /* does do huffman decomp */
4940 /* program index is computed by caller, stores result in pgm[] struct */
4941 static
4942 void
4943 test_eit_mss ( unsigned char *r, unsigned int pgo, unsigned int etmid,
4944 unsigned int est, unsigned int els, unsigned char n )
4946 unsigned int nstr, nseg, comp, mode, nchr;
4947 unsigned int i,j,k;
4948 unsigned char lang[4];
4949 unsigned char s[PNZ*2];
4950 unsigned char d[PNZ];
4951 unsigned char *t;
4953 memset( s, 0, sizeof(s));
4954 nstr = r[0];
4955 for (i = 0; i < nstr; i++) {
4956 memcpy(lang, &r[1], 3);
4957 lang[3] = 0;
4958 r += 4;
4959 nseg = *r++;
4961 for (j = 0; j < nseg; j++) {
4962 comp = *r++;
4963 mode = *r++;
4964 nchr = *r++;
4966 /* don't show blank entry? */
4967 if (nchr < 1) continue;
4969 memset( s, 0, sizeof(s));
4970 /* copy string but keep nul term */
4971 for (k = 0; k < nchr; k++)
4972 if (k < (sizeof(s)-1))
4973 s[k] = r[k];
4975 /* don't store last duplicate in pgm? will only be 1 string?
4976 if (i == (nstr-1)) continue;
4980 /* only show if no compression */
4981 aprintf3( stdout, " EIT-%02X pg[%04X] ETMID %08X ",
4982 n, pgo, etmid);
4983 aprintf3( stdout, "[L%02X C%02X M%02X] ",
4984 nchr, comp, mode);
4986 t = s;
4988 /* show non-compressed */
4989 if ( (0 == comp) && (0 == mode) ) {
4990 aprintf3( stdout, "[%s]\n [%-s] ", lang, s);
4993 /* show huffman compressed */
4994 if (
4995 /* (mode == 0xFF) && spec requires, KPXB ignores */
4996 (comp > 0) &&
4997 (comp < 3)
5000 t = d;
5001 huffman_decode( d, s, sizeof(d), nchr, comp);
5002 aprintf3( stdout, "[%s] Huffman\n [%-s] ", lang, d);
5004 /* show as unknown compress */
5005 if (comp > 2) {
5006 t = d;
5007 snprintf( d, sizeof(d)-1, "[%s] [L%02X C%02X M%02X]",
5008 lang, nchr, comp, mode);
5011 pgm[ pgo ].st = est;
5012 pgm[ pgo ].ls = els;
5013 pgm[ pgo ].etmid = etmid;
5014 memset( pgm[ pgo ].name, 0, PNZ);
5015 memcpy( pgm[ pgo ].name, t, PNZ);
5017 /* unused in ATSC; multi segment string would need this with nseg > 1 */
5018 r+= nchr;
5022 aprintf3( stdout, "\n");
5026 /* r points to start of descriptors */
5027 /* do until len exhausted */
5028 static
5029 void
5030 test_eit_descriptors( unsigned char *p, unsigned int len )
5032 unsigned char *q, *r, *t;
5033 unsigned char n, l, i, j;
5034 unsigned int dlen;
5036 r = p;
5038 aprintf3( stdout, " EIT DLen %03X:\n\n", len);
5039 if (len == 0) aprintf3( stdout, "\n");
5041 for (i = 0; i<len; i++) aprintf3(stdout, "%02X ", r[i]);
5042 if (len !=0 ) aprintf3( stdout, "\n\n");
5044 if (len > 160) return; /*len = 160; */
5046 if (len < 2) return;
5048 dlen = len;
5050 while ( dlen > 2 ) {
5052 n = *r++;
5053 l = *r++;
5054 dlen -= 2;
5056 switch( n ) {
5058 case 5:
5059 t = "Registration";
5060 aprintf3( stdout, " EIT Tag %02X DLen %02X %s: ", n, l, t);
5061 aprintf3( stdout, "Format ID [%c%c%c%c]\n",
5062 r[0],r[1],r[2],r[3]);
5063 if (l != 4)
5064 aprintf3( stdout,
5065 " add'l reg info exists but not parsed\n");
5066 aprintf3( stdout, "\n");
5067 break;
5069 case 0x80:
5070 t = "Stuffing";
5071 aprintf3( stdout, " EIT Tag %02X DLen %02X %s: ", n, l, t);
5072 for (i=0; i < l; i++) aprintf3( stdout, "%02X ", r[i] );
5073 aprintf3( stdout, "\n");
5074 break;
5076 /* REMINDER: Don't get too excited about this descriptor. It's probably not
5077 going to have the information necessary to determine the actual stream
5078 info, such as how many channels will be in use at the time of this event.
5080 Very few stations send it in the EIT and the ones that do send it, set
5081 it to the exact same values as live VCT/PMT version of this descriptor.
5082 This means no future EPG 5.1 indicator for anyone until bcasters get it
5083 right. About all that can be done is show current cap 5.1 from ac3 parse.
5085 case 0x81:
5086 t = "A/52 Audio";
5088 /* unsigned char lc, lc2, mid, asvcf, tl, tc, tb; ?? */
5089 unsigned char src, bsid, brc, sm, bsm, nc, fs, lc;
5090 unsigned char *srt, *brt, *brt1, *smt, *nct, *lft, *bsmt;
5092 src = 0x07 & (r[0]>>5);
5093 srt = "Reserved";
5094 if (0 == src) srt = "48 kHz";
5095 if (1 == src) srt = "44.1 kHz";
5096 if (2 == src) srt = "32 kHz";
5098 /* must be the can't decide section nyuk */
5099 if (4 == src) srt = "48 or 44.1 kHz";
5100 if (5 == src) srt = "48 or 32 kHz";
5101 if (6 == src) srt = "44.1 or 32 kHz";
5102 if (7 == src) srt = "48, 44.1 or 32 kHz";
5104 bsid= 0x1F & r[0]; /* bsid */
5105 brc = 0x3F & (r[1]>>2); /* bit rate code */
5106 sm = 0x03 & r[1]; /* dsurmod */
5107 bsm = 0x07 & (r[2]>>5); /* bsmod */
5108 nc = 0x0F & (r[2]>>4); /* num chans */
5109 fs = 0x01 & r[2]; /* full service */
5110 lc = r[3]; /* langcode */
5112 brt1 = "Exact";
5113 if (0x20 == (0x20 & brc)) brt1 = "Maximum";
5114 brc &= 0x1F; /* limit it now brt1 has been extracted */
5116 brt = "Reserved";
5117 if ( 0 == brc) brt = " 32 kbits/second";
5118 if ( 1 == brc) brt = " 40 kbits/second";
5119 if ( 2 == brc) brt = " 48 kbits/second";
5120 if ( 3 == brc) brt = " 56 kbits/second";
5121 if ( 4 == brc) brt = " 64 kbits/second";
5122 if ( 5 == brc) brt = " 80 kbits/second";
5123 if ( 6 == brc) brt = " 96 kbits/second";
5124 if ( 7 == brc) brt = "112 kbits/second";
5125 if ( 8 == brc) brt = "128 kbits/second";
5126 if ( 9 == brc) brt = "160 kbits/second";
5127 if (10 == brc) brt = "192 kbits/second";
5128 if (11 == brc) brt = "224 kbits/second";
5129 if (12 == brc) brt = "256 kbits/second";
5130 if (13 == brc) brt = "320 kbits/second";
5131 if (14 == brc) brt = "384 kbits/second";
5132 if (15 == brc) brt = "448 kbits/second";
5133 if (16 == brc) brt = "512 kbits/second";
5134 if (17 == brc) brt = "576 kbits/second";
5135 if (18 == brc) brt = "640 kbits/second"; /* hear that! */
5137 smt = "Reserved";
5138 if (0 == sm) smt = "Not Indicated";
5139 if (1 == sm) smt = "NOT Dolby";
5140 if (2 == sm) smt = "Dolby";
5142 nct = "Reserved";
5143 lft = "";
5144 if ( 8 == (8 & nc)) lft = " + LFE";
5145 if ( 0 == nc) nct = "1+1";
5146 if ( 1 == nc) nct = "1/0";
5147 if ( 2 == nc) nct = "2/0";
5148 if ( 3 == nc) nct = "3/0";
5149 if ( 4 == nc) nct = "2/1";
5150 if ( 5 == nc) nct = "3/1";
5151 if ( 6 == nc) nct = "2/2";
5152 if ( 7 == nc) nct = "3/2";
5154 /* LFE (Low Frequency Effects aka subwoofer) is +1 channel in the count. */
5155 if ( 8 == nc) nct = "1";
5156 if ( 9 == nc) nct = "<=2";
5157 if (10 == nc) nct = "<=3";
5158 if (11 == nc) nct = "<=4";
5159 if (12 == nc) nct = "<=5";
5160 if (13 == nc) nct = "<=6";
5162 bsmt = "Reserved";
5163 if ( 0 == bsm) bsmt = "Main Audio: Complete Main";
5164 if ( 1 == bsm) bsmt = "Main Audio: Music and Effects";
5165 if ( 2 == bsm) bsmt = "Associated: Visually Impaired";
5166 if ( 3 == bsm) bsmt = "Associated: Hearing Impaired";
5167 if ( 4 == bsm) bsmt = "Associated: Dialogue";
5168 if ( 5 == bsm) bsmt = "Associated: Commentary";
5169 if ( 6 == bsm) bsmt = "Associated: Emergency";
5170 if ( 7 == bsm) bsmt = "Associated: Voice Over";
5172 aprintf3( stdout,
5173 " EIT Tag %02X DLen %02X %s: Sample Rate %s, "
5174 "bsid %02X langcod %02X\n",
5175 n, l, t, srt, bsid, lc);
5176 aprintf3( stdout,
5177 " %s Bit Rate %s (%02X) Surround %s (%02X)\n",
5178 brt1, brt, brc, smt, sm);
5179 aprintf3( stdout,
5180 " Service %s (%d), Channels %s%s (%d), Full Service %u\n",
5181 bsmt, bsm, nct, lft, nc, fs);
5183 aprintf3( stdout, "\n");
5186 break;
5188 case 0x86:
5189 t = "Caption Service";
5190 if ( 0xC0 == (0xC0 & r[0]) ) { /* reserved bits check */
5191 unsigned char nos, cct, l21f, csn, er, war;
5192 unsigned char lang[4];
5194 q = r;
5195 aprintf3(stdout," EIT Tag %02X DLen %02X %s: ",n, l, t);
5196 nos = 0x1F & q[0]; /* number of services */
5197 /* skip parsed */
5198 q++;
5199 aprintf3( stdout, "Number of Services %u\n", nos);
5200 for (i = 0; i < nos; i++) {
5201 if ( 0x40 == (0x40 & q[3]) ) { /* reserved bit */
5202 unsigned char *cctt;
5203 cctt = "ATSC CC";
5204 memcpy( lang, q, 3 );
5205 lang[3] = 0; /* 3 char lang code per ISO 639.2/B */
5206 q += 3; /* skip lang */
5207 cct = 1 & (q[0]>>7); /* caption type */
5208 /* aprintf3( stdout, "cct %d\n", cct); */
5209 if (0 == cct) {
5210 /* don't care about EIA/CEA-608-B. that's NTSC */
5211 cctt = "NTSC CC";
5212 if ( 0x3E == (0x3E & q[0]) ) { /* reserved */
5213 l21f = 1 & q[0];
5214 aprintf3( stdout,
5215 " [%s] Type %s Line21 %s Field ",
5216 lang, cctt,
5217 (l21f == 0) ? "Even" : " Odd" );
5219 } else {
5220 /* might be EIA-708-A ATVCC spec, not testing */
5221 csn = 0x3F & q[0]; /* caption svc number */
5222 aprintf3( stdout,
5223 " [%s] Type %s Service Number %02X ",
5224 lang, cctt, csn);
5226 if ( (0x3F == (0x3F & q[1])) && (0xFF == q[2]) ) {
5227 er = 1 & (q[1]>>7);
5228 war = 1 & (q[1]>>6);
5229 aprintf3( stdout,
5230 "Easy Reader %u Wide Aspect Ratio %u",
5231 er, war);
5232 q += 3;
5234 // q += 3; /* was here but may be wrong */
5236 aprintf3( stdout, "\n");
5238 aprintf3( stdout, "\n");
5240 break;
5242 case 0x87:
5243 t = "Content Advisory";
5244 q = r;
5245 if ( 0xC0 == (0xC0 & q[0]) ) {
5246 unsigned char rrc, rr, rd, rdj, rv, rdl;
5248 aprintf3(stdout," EIT Tag %02X DLen %02X %s: ",n, l, t);
5249 rrc = 0x3F & q[0];
5250 q++; /* skip parsed */
5251 aprintf3( stdout, " Rating Region Count %u\n", rrc);
5252 for (i = 0; i < rrc; i++) {
5253 rr = q[0]; /* rating region */
5254 rd = q[1]; /* rated dimensions */
5255 q += 2;
5257 /* one dimension will try to print on one line */
5258 aprintf3( stdout,
5259 " Region %u Dimensions %u:%s",
5260 rr, rd, (rd > 1) ? "\n":"");
5262 for (j = 0; j < rd; j++) {
5263 if ( 0xF0 == (0xF0 & q[1]) ) {
5264 rdj = q[0]; /* rating dimension j */
5265 rv = 0xF & q[1]; /* rating value */
5266 q += 2;
5267 aprintf3( stdout, " Dimension j %u Value %u Abbrev [%s]\n",
5268 rdj, rv, ratings[ (rdj * 10) + rv + 1] );
5271 rdl = q[0];
5272 q++;
5273 // if (rdl != 0)
5274 /* need at least 8 bytes of header for 1 byte string */
5275 if (rdl > 8)
5277 aprintf3( stdout, " mss dlen %d: ",
5278 rdl );
5279 test_eit_rr_mss( q );
5282 aprintf3( stdout, "\n");
5284 break;
5286 /* this one was struck down by the judge, but some stations still sending it */
5287 case 0xAA:
5288 t = "Redistribution Control";
5289 aprintf3( stdout, " EIT Tag %02X DLen %02X %s: ", n, l, t);
5290 for (i=0; i<l; i++) aprintf3( stdout, "%02X ", r[ i ] );
5291 aprintf3( stdout, "\n");
5292 break;
5294 /* needs parsing if shows up here */
5295 default:
5296 aprintf3( stdout, " EIT *Tag %02X len %02X ignored\n", n, l);
5297 aprintf3( stdout, "\n");
5298 break;
5301 /* skip parsed */
5302 r += l;
5303 dlen -= l;
5308 /* add to eit payload. returns 0 if done, or 1 if not done */
5309 static
5310 unsigned int
5311 build_eit_payload( unsigned char *p, unsigned int n )
5313 unsigned char *r;
5314 unsigned int psi;
5316 psi = 1 & (p[1]>>6);
5317 r = p + 5;
5319 /* handle payload start packet by copying start to EIT payload buffer */
5320 if (psi != 0) {
5321 if ( (0xCB == r[0])
5322 && (0xF0 == (0xF0 & r[1]) ) /* syntax,private,reserved */
5323 && (0x01 == (0x01 & r[5]) ) /* check cni only, reserved is broken? */
5326 /* top two are reserved see A/65b page 41 */
5327 if (0xC0 != (0xC0 & r[5]) ) {
5328 aprintf6( stdout, " ERROR EIT-%02X *** ignoring reserved bits 0xC0 not set %02X\n", n, 0xC0 & r[5]);
5331 eit[n].sl = ((0xF & r[1])<<8) | r[2];
5332 eit_vn = 0x1F & (r[5])>>1;
5334 eit[n].payoff = 183;
5335 aprintf6( stdout,
5336 " START EIT-%02X Version %02X SLen %03X Payoff %03X\n",
5337 n, eit_vn, eit[n].sl, eit[n].payoff);
5339 memset( eit[n].payload, 0, sizeof(eit[n].payload) ); /* reset */
5340 memcpy( eit[n].payload, r, eit[n].payoff);
5341 if ( eit[n].payoff > eit[n].sl+3 ) {
5342 aprintf6( stdout, " DONE EIT-%02X\n",n);
5343 return 0;
5345 return 1;
5349 r = p + 4;
5351 /* additional non start payloads append to eit payload buffer */
5352 if ( (eit[n].sl > 179) && (pkt.psi == 0) ) {
5353 memcpy( &eit[n].payload[eit[n].payoff], r, 184);
5355 eit[n].payoff += 184;
5357 aprintf6( stdout, " COPY EIT-%02X Version %02X SLen %03X Payoff %03X\n",
5358 n, eit_vn, eit[n].sl, eit[n].payoff);
5359 if ( eit[n].payoff > eit[n].sl+3 ) {
5360 aprintf6( stdout, " DONE EIT-%02X\n", n);
5361 return 0;
5364 return 1;
5366 aprintf6( stdout, " *ignored*\n");
5367 return -1;
5370 /* FOX fix: put the received EIT in chronological order.
5371 A65/b mentions it should be. Guess FOX didn't read that part.
5372 Called by test eit after reading the entries into pgm[]
5374 static
5375 void
5376 sort_eit_pgm( unsigned int pgo, unsigned int nev ) {
5377 unsigned int i, j, a, b;
5378 struct pgm_s c;
5380 // fprintf( stdout, "%s %u %u\n", __FUNCTION__, pgo & 0x1FF8, nev);
5382 /* only sorting 8, at offset pgo & ~8 */
5383 a = pgo & 0x1FF8;
5384 b = a + nev;
5386 /* FIXME: will move all the 0 start times to the top, want them at bottom */
5387 for (i = a; i < (b-1); i++) {
5388 if (0 == pgm[i].st) break; /* stop at first zero start time */
5389 for (j = i+1; j < b; j++) {
5390 if (0 == pgm[j].st) break;
5391 if ( pgm[j].st < pgm[i].st) {
5392 // fprintf( stdout, "swapped %d %d (%u %u)\n", i, j, pgm[i].st, pgm[j].st );
5394 /* would be much faster to swap pointers */
5395 memcpy( &c, &pgm[i], sizeof(c));
5396 memcpy( &pgm[i], &pgm[j], sizeof(c));
5397 memcpy( &pgm[j], &c, sizeof(c));
5402 /* erase stale entries at end, 8 is PEZ */
5403 for (i = b; i < (a+8); i++) memset( &pgm[i], 0, sizeof(c) );
5405 /* debug sort output */
5406 // for (i = a; i < b; i++) fprintf( stdout, "pgo[%04X] st %u\n", i, pgm[i].st);
5409 /* process eit[n] packet based on payload start indicator */
5410 static
5411 void
5412 test_eit ( unsigned char *p, unsigned int n )
5414 unsigned char *r;
5415 unsigned char vn, sn, lsn, pv, numevs, cni;
5416 unsigned short sl, sr, pn;
5417 unsigned int eit_crc = 0;
5418 unsigned int pgo; /* program guide offset */
5419 int i, vcn; /* , j; */
5421 n &= 0x7f; /* limit EIT-n to 0-127 */
5422 r = p;
5424 p.0 is 0x47 sync
5425 p.1 is 3 bits tei psi pri, 5 high bits pid
5426 p.2 is 8 bits low bits pid
5427 p.3 is tsc afc cc
5428 p.4 is 0 if table and payload start indicator 1 else data
5429 p.5 is table id if payload start indicator 1 else data
5431 /* returns 0 if done, else 1 */
5432 eit[n].payok = build_eit_payload( r, n );
5434 /* if payok is nz, eit payload is not done yet */
5435 if (eit[n].payok != 0) return;
5437 r = eit[n].payload;
5439 if (0xCB != r[0]) {
5440 aprintf3( stdout, " EIT-%02X bad table type %02X\n", n, r[0]);
5441 return;
5444 sl = ((0xF & r[1])<<8) | r[2]; /* section length */
5446 eit_crc = calc_crc32( r, sl+3 );
5447 if (eit_crc != 0) {
5448 pkt.crceit++;
5449 aprintf3( stdout, " EIT-%02X CRC ERROR "
5450 "CALC %08X RCVD %02X%02X%02X%02X\n",
5451 n, eit_crc, r[sl], r[sl+1],r[sl+2],r[sl+3]);
5452 /* return; */
5455 sr = r[3]<<8 | r[4]; /* source id */
5456 vn = (0x3E & r[5])>>1;
5457 eit[n].vn = vn; /* not used */
5459 vcn = find_vc_src( sr );
5460 pn = 0;
5462 /* holds down EIT display until VCT seen */
5463 if (vcn < 0) return;
5465 pn = vc[vcn].pn;
5467 /* OUTPUT REDUX: */
5468 if (0 != arg_redux)
5469 if (vn == eitvn[ (vcn << 7) + n ])
5470 return; /* only if version changes */
5471 eitvn[ (vcn << 7) + n ] = vn;
5473 aprintf3( stdout, "EIT-%02X CRC OK\n", n);
5475 pkt.eit++;
5477 cni = 1 & r[5]; /* current/next indicator */
5478 sn = r[6]; /* section number */
5479 lsn = r[7]; /* last section number */
5480 pv = r[8]; /* eats cycles, more bits */
5481 if (pv != 0) {
5482 aprintf3( stdout, " EIT Protocol %02X not 0\n", pv);
5483 return; /* protocol version 0 only */
5486 numevs = r[9]; /* number of events in section */
5487 r += 10; /* skip parsed for loop */
5489 aprintf3( stdout,
5490 "\n EIT-%02X VER %02X SLen %03X Src %d "
5491 "CNI %d SN %d LSN %d NumEv %d Program %04X\n\n",
5492 n, vn, sl, sr, cni, sn, lsn, numevs, pn );
5494 /* event 0 is link to previous event, always it seems. no ETT either */
5495 /* only keep event zero if it is EIT-00 */
5496 /* NOTE: FOX has nationwide broken EPG so event is might not be previous */
5498 pgo = ~0;
5500 for (i=0; i<(numevs); i++)
5502 if ( (0xC0 == (0xC0 & r[0])) && (0xC0 == (0xC0 & r[6])) )
5504 unsigned short eid; /* event id */
5505 unsigned char etmloc; /* etm location */
5506 unsigned int els; /* length in seconds */
5507 unsigned char tlen; /* title length */
5508 unsigned char d[32]; /* date string */
5509 unsigned int etmid; /* extended text message id */
5510 struct tm dtm; /* date in tm format */
5511 time_t est; /* event start time */
5513 eid = ((0x3F & r[0]) << 8) | r[1];
5515 /* SEE A/65b Table 6.14 EIT ETM ID */
5516 etmid = (sr<<16) | (eid<<2) | 2;
5518 est = (r[2] << 24) | (r[3] << 16) | (r[4] << 8) | r[5];
5519 etmloc = (0x30 & r[6]) >> 4;
5520 els = ((0xF & r[6]) << 16) | (r[7] << 8) | r[8];
5521 tlen = r[9];
5522 r += 10;
5524 /* recalibrate for unix time */
5525 est += utc_offset;
5527 n &= 0x7f;
5529 /* compute program offset, should look like this: */
5530 /* F E D| C B A| 9 8 7 6 5 4 3| 2 1 0 */
5531 /* 0 0 0| SRC | EIT-N | EVN */
5533 /* sr 0 is NTSC. This code doesn't care about NTSC, so skip it. */
5534 if (0 == sr) continue;
5536 /* WRONG: can ignore source id or program # only need vc offset, see below */
5537 #if 0
5538 /* make index match atscap epg [n] key numbers */
5539 so = sr - 1;
5540 pgo = (so<<10) | (n<<3) | (7 & i);
5541 /* KPXB fix for their stupid idiotic source numbers above 8 */
5542 pgo %= PGZ;
5543 #endif
5544 pgo = (vcn<<10) | (n<<3) | (7 &i);
5545 pgm[pgo].pn = pn;
5547 /* don't worry about overwriting anything */
5548 /* any new data should overwrite and be near where it belongs */
5549 /* sort will clean up what is left if MGT changes during cap */
5551 /* make event start time tm structure from it */
5552 localtime_r( &est, &dtm );
5553 /* make string from tm structure */
5554 asctime_r( &dtm, d);
5555 d[19] = 0; /* strip year+nl from start time text */
5556 test_eit_mss( r, pgo, etmid, est, els, n );
5557 aprintf3( stdout, " %s %02d:%02d EID %04X ",
5558 d, els/60, els%60, eid);
5559 r += tlen;
5561 if ( 0xF0 == (0xF0 & r[0]) )
5563 unsigned int dlen;
5565 dlen = ((0xF & r[0])<<8) | r[1];
5566 r += 2;
5567 test_eit_descriptors( r, dlen );
5568 r += dlen;
5573 /* pgm[] has been updated but the (up to 8) new entries need sorting */
5574 /* they should all be based around (pgo & 0x3F8), sort by time */
5575 if (~0 != pgo) sort_eit_pgm( pgo, numevs );
5577 /* aprintf3( stdout, "\n"); */
5579 /***************************************************************** ATSC EIT */
5582 /***************************************************************** ATSC ETM */
5583 /* A/65b Table 6.38 Multiple String Structure */
5584 /* does not do huffman decomp, but should */
5585 static
5586 void
5587 test_channel_ett_mss( unsigned char *r )
5589 unsigned int nstr, nseg, comp, mode, nchr;
5590 unsigned int i,j,k;
5591 unsigned char lang[4];
5592 unsigned char s[512];
5594 memset( s, 0, sizeof(s));
5595 nstr = r[0];
5597 nstr = 1; /* force to one */
5598 for (i = 0; i < nstr; i++) {
5599 memcpy(lang, &r[1], 3);
5600 lang[3] = 0;
5601 r += 4; // 3?
5602 nseg = *r++;
5604 nseg = 1; /* force to one */
5605 for (j = 0; j < nseg; j++) {
5606 comp = *r++;
5607 mode = *r++;
5608 nchr = *r++;
5609 for (k = 0; k < nchr; k++) s[k] = *r++;
5611 /* only show if no compression */
5612 if ( (0 == comp) && (0 == mode) ) {
5613 aprintf8( stdout, "[%s] [%-s]\n", lang, s);
5614 } else {
5615 aprintf8( stdout, "[%s] [*COMPRESSED*]\n", lang);
5621 static
5622 void
5623 test_channel_ett( unsigned char *p )
5625 unsigned int sl, idx, vn, etmid;
5626 unsigned char *r;
5628 r = p+5;
5630 if (0xF0 != (0xF0 & r[1])) return;
5631 if (0xC1 != (0xC1 & r[5])) return;
5633 sl = ((0xF & r[1]) << 8) | r[2];
5634 idx = (r[3] << 8) | r[4];
5635 vn = (0x3E & r[5]) >> 1;
5636 if (r[6] != 0) return; //sn
5637 if (r[7] != 0) return; //lsn
5638 if (r[8] != 0) return; //pv
5639 etmid = r[9]<<24 | r[10]<<16 | r[11]<<8 | r[12];
5640 r += 13;
5641 aprintf8( stdout, "Channel ETM SLen %03X ", sl);
5642 test_channel_ett_mss( r );
5644 /////////////////////////////////////////////////////////////////////////////
5648 //////////////////////////////////////////////////////////////// VCT Payload
5649 // add to vct payload. returns 0 if done, or 1 if not done
5650 static
5651 unsigned int
5652 build_vct_payload( unsigned char *p )
5654 unsigned char *r;
5655 unsigned char psi, vn;
5657 r = p+5;
5659 psi = 1 & ( p[1] >> 6);
5660 // handle payload start packet by copying start to VCT payload buffer
5661 if (psi != 0)
5663 if ( (0xC8 == (0xFE & r[0] )) // C8 (TVCT) or C9 (CVCT)
5664 // && (0xF0 == (0xF0 & r[1]) ) // syntax,private,reserved bits
5665 && (0xC0 == (0xC0 & r[1]) ) // syntax,private
5666 && (0xC1 == (0xC1 & r[5]) ) // reserved top 2 bits, cni = 1
5669 vn = 0x1F & ( r[5] >> 1);
5670 vct.vn = vn;
5671 vct.sl = ((0xF & r[1])<<8) | r[2];
5673 vct.payoff = 183;
5675 aprintf6( stdout,
5676 " START VCT Version %02X SLen %03X Payoff %03X\n",
5677 vct.vn, vct.sl, vct.payoff);
5678 memset( vct.payload, 0, sizeof(vct.payload) ); // reset
5679 memcpy( vct.payload, r, vct.payoff );
5681 if ( vct.payoff > vct.sl+3 ) {
5682 aprintf6( stdout, " DONE VCT\n");
5683 return 0;
5686 return 1;
5689 r = p+4;
5691 // additional non start payloads append to VCT payload buffer
5692 if ( (vct.sl > 179) && (psi == 0) ) {
5693 memcpy( &vct.payload[vct.payoff], r, 184);
5695 vct.payoff += 184;
5697 aprintf6( stdout, " COPY VCT Version %02X SLen %03X Payoff %03X\n",
5698 vct.vn, vct.sl, vct.payoff);
5700 if ( vct.payoff > vct.sl+3 ) {
5701 aprintf6( stdout, " DONE VCT\n");
5702 return 0;
5704 return 1;
5706 aprintf6( stdout, " VCT not parsed\n");
5707 return -1;
5713 /**************************************** Terrestrial Virtual Channel Table */
5714 /* This gives information on which PIDs are in use for this Channel */
5715 static
5716 void
5717 test_tvct ( unsigned char *p )
5719 unsigned char *r;
5720 unsigned short sl, tsi, adl;
5721 unsigned char vn, cni, sn, lsn, pv, ncs, i, j;
5723 // fprintf(stdout, "TVCT\n");
5725 vct.payok = build_vct_payload( p );
5726 if (0 != vct.payok) return; /* payload is not done yet */
5728 // fprintf(stdout, "TVCT OK\n");
5729 r = vct.payload; /* section pointed to by r now */
5731 /* all these values have to be true or nothing done */
5732 if ( (0xC8 != r[0]) /* table id */
5733 // || (0xF0 != (r[1] & 0xFC)) /* reserved,syntax,private all 1 */
5734 || (0xC0 != (r[1] & 0xC0)) /* reserved,syntax,private all 1 */
5735 || (0xC1 != (r[5] & 0xC1)) /* reserved top 2 bits, cni = 1 */
5736 || (0x00 != r[8]) /* protocol version must be 0 */
5739 aprintf2( stdout, "TVCT bad TT/RB\n" );
5740 return;
5743 /* r = p + 5; / * still have to check sl */
5745 sl = ((0xF & r[1]) <<8) | r[2]; /* section length may not be > 1021 */
5747 if (sl > 1021) {
5748 aprintf2( stdout, "TVCT too large %d\n", sl);
5749 return; /* if it is > 1021, ignore packet */
5752 /* crc check to qualify before doing anything else */
5753 vct_crc = calc_crc32( r, sl+3 );
5754 if (vct_crc != 0) {
5755 pkt.crctvct++;
5756 aprintf2( stdout, "TVCT CRC ERROR\n");
5757 return; /* bad packet do not process further */
5759 pkt.tvct++; /* good packet gets counted */
5761 tsi = (r[3] <<8) | r[4]; /* transport stream id */
5763 vn = (0x3E & r[5]) >> 1; /* version number */
5765 /* OUTPUT REDUX: */
5766 if (0 != arg_redux)
5767 if (vn == vct_vn)
5768 return; /* don't update until vn changes */
5769 vct_vn = vn;
5771 aprintf2( stdout, "TVCT CRC OK\n");
5773 cni = r[5] & 1; /* current/next indicator */
5774 sn = r[6]; /* section number */
5775 lsn = r[7]; /* last section number */
5777 pv = r[8]; /* protocol version */
5778 if (pv != 0) {
5779 aprintf2( stdout, "TVCT Protocol not 0\n");
5780 return; /* only protocol 0 */
5782 ncs = r[9]; /* number of channels in section */
5783 vct_ncs = ncs;
5785 if (ncs > 7) {
5786 aprintf2( stdout, "TVCT NCS limit exceeded, %d\n", ncs);
5787 return; /* sanity limit do not process further */
5790 r += 10;
5792 aprintf2( stdout,
5793 " TVCT #%d SLen %03X TSID %04X Ver# %02X CNI %d Sec# %02X "
5794 "LSec# %02X Chan/Sect %02X\n",
5795 pkt.tvct, sl, tsi, vn, cni, sn, lsn, ncs);
5797 for (i=0; i < ncs; i++)
5799 unsigned char t[256];
5801 /* all these reseved bits have to be set or nothing done */
5802 if ( (0xF0 == (0xF0 & r[14] )) /* after short name */
5803 && (0x0D == (0x0D & r[26] )) /* +12 more */
5804 && (0xC0 == (0xC0 & r[27] )) /* +1 more */
5807 memcpy( &vc[i].name, r, 14); /* 7 chars unicode */
5808 for (j=1;j<14;j++) {
5809 if (0 == vc[i].name[j]) vc[i].name[j] = ' ';
5811 r += 14;
5812 vc[i].major = ((0xF & r[0]) << 6) | ((0xFC & r[1]) >> 2);
5813 vc[i].minor = ((0x3 & r[1]) << 8) | r[2];
5814 vc[i].mode = r[3];
5815 vc[i].freq = (r[4]<<24) | (r[5]<<16) | (r[6]<<8) | r[7];
5816 vc[i].ctsid = (r[8]<<8) | r[9];
5817 vc[i].pn = (r[10]<<8) | r[11];
5818 vc[i].etm = (0xC0 & r[12]) >> 6;
5819 vc[i].actrl = (0x20 & r[12]) >> 5;
5820 vc[i].hide = (0x10 & r[12]) >> 4;
5821 vc[i].hideg = (0x02 & r[12]) >> 1;
5822 vc[i].svct = (0x3F & r[13]);
5823 vc[i].src = (r[14]<<8) | r[15];
5824 vc[i].dlen = ((0x3 & r[16])<<8) | r[17];
5825 r += 18; /* skip parsed */
5827 /* show channel name */
5828 aprintf2( stdout, "\n VC%02d [", i);
5829 for (j=0; j<14;) {
5830 aprintf2( stdout, "%c", vc[i].name[j+1] );
5831 j += 2; /* the low byte is the one that's ASCII */
5833 aprintf2( stdout, "] ");
5835 /* default is ATSC type, change if necessary */
5836 snprintf( t, sizeof(t)-1, "ATSC DTV %d.%d", vc[i].major, vc[i].pn);
5837 if (vc[i].pn == 0xFFFF)
5838 strncpy( t, "NTSC", sizeof(t)-1);
5839 if (vc[i].pn == 0)
5840 strncpy( t, "DISABLED", sizeof(t)-1);
5841 aprintf2( stdout,
5842 "%d.%d Modulation %d TSID %04X Program %s\n"
5843 " ETM Location %d Access Control %d Hidden %d Hide Guide %d\n"
5844 " Service Type %d Source %d Program %d DLen %02X\n",
5845 vc[i].major, vc[i].minor, vc[i].mode,
5846 vc[i].ctsid, t, vc[i].etm, vc[i].actrl,
5847 vc[i].hide, vc[i].hideg, vc[i].svct,
5848 vc[i].src, vc[i].pn, vc[i].dlen
5851 /* test the descriptor */
5852 if (vc[i].dlen != 0) {
5853 aprintf2( stdout, " TVCT DESCRIPTORS: DLen %02X\n", vc[i].dlen);
5854 /* use test vct descriptor because of different output control */
5855 test_vct_descriptor( r, vc[i].dlen );
5857 r += vc[i].dlen;
5862 /* look for additional descriptors, spec says may be 0
5863 spec said it may be a single descriptor?
5864 doesn't seem to fit in with the other descriptors if so
5866 if (0xFC == (r[0] & 0xFC)) {
5867 adl = ((0x3 & r[0]) << 8) | r[1];
5868 r++;
5869 r++;
5871 if (adl != 0) {
5872 aprintf2( stdout, " TVCT add'l desc: ");
5873 for (j=0; j < adl; j++) {
5875 aprintf2( stdout, "%02X", *r );
5876 r++; /* skip descriptor to get to crc */
5878 aprintf2( stdout, "\n");
5882 aprintf2( stdout, "\n");
5887 /******************************************** Cable Virtual Channel Table */
5888 /* This gives information on which PIDs are in use for this Channel. */
5889 static
5890 void
5891 test_cvct( unsigned char *p )
5893 unsigned char *r;
5894 unsigned short sl, tsi, adl;
5895 unsigned char vn, cni, sn, lsn, pv, ncs, i, j;
5896 /* service type */
5897 char *st[5] = {
5898 "Rsvd", "NTSC TV", "ATSC DTV", "ATSC Audio", "ATSC Data"
5900 /* modulation modes */
5901 char *mt[6] = {
5902 "Rsvd", "Analog", "QAM64", "QAM256", "VSB8", "VSB16"
5904 int msr;
5906 fprintf(stdout, "CVCT\n");
5907 vct.payok = build_vct_payload( p );
5908 if (0 != vct.payok) return; /* payload is not done yet */
5910 fprintf(stdout, "CVCT OK\n");
5911 r = vct.payload; /* section pointed to by r now */
5913 /* all these must test true or nothing is done */
5914 if ( (0xC9 != r[0]) /* table id */
5915 // || (0xF0 != (r[1] & 0xFC)) /* reserved,syntax,private all 1 */
5916 || (0xC0 != (r[1] & 0xC0)) /* reserved,syntax,private all 1 */
5917 || (0xC1 != (r[5] & 0xC1)) /* reserved 1 */
5918 || (0x00 != r[8]) /* protocol version must be 0 */
5921 aprintf2( stdout, "CVCT bad TT/RB\n" );
5922 return;
5925 /* r = p + 5; / * still need section length */
5927 sl = ((0xF & r[1]) <<8) | r[2]; /* section len may not be > 1021 */
5928 fprintf(stdout, "CVCT SL %03X\n", sl);
5930 if (sl > 1021) {
5931 aprintf2( stdout, "CVCT too large %d\n", sl);
5932 return; /* if it is > 1021, ignore packet */
5935 /* crc check to qualify before doing anything else */
5936 vct_crc = calc_crc32( r, sl+3 );
5937 if (vct_crc != 0) {
5938 pkt.crccvct++;
5939 aprintf2( stdout, "CVCT CRC ERROR\n");
5940 return; /* bad packet do not process further */
5942 aprintf2( stdout, "CVCT CRC OK\n");
5943 pkt.cvct++; /* good packet gets counted */
5945 tsi = (r[3] <<8) | r[4]; /* transport stream id */
5947 vn = (0x3E & r[5]) >> 1; /* version number */
5949 /* OUTPUT REDUX: */
5950 if (0 != arg_redux)
5951 if (vn == vct_vn)
5952 return; /* don't update until vn changes */
5953 vct_vn = vn;
5955 cni = r[5] & 1; /* current/next indicator */
5956 sn = r[6]; /* section number */
5957 lsn = r[7]; /* last section number */
5959 pv = r[8]; /* protocol version */
5960 if (pv != 0) {
5961 aprintf2( stdout, "CVCT Protocol not 0\n");
5962 return; /* only protocol 0 */
5964 ncs = r[9]; /* number of channels in section */
5966 if (ncs > 7) {
5967 aprintf2( stdout, "CVCT NCS limit exceeded, %d\n", ncs);
5968 return; /* sanity limit do not process further */
5971 r += 10;
5973 aprintf2( stdout,
5974 " CVCT #%d SLen %03X TSID %04X Ver# %02X CNI %d Sec# %02X "
5975 "LSec# %02X Chan/Sect %02X\n",
5976 pkt.tvct, sl, tsi, vn, cni, sn, lsn, ncs);
5978 for (i=0; i < ncs; i++)
5980 unsigned char t[256];
5981 unsigned short opn;
5983 /* all these reseved bits have to be set or nothing done */
5984 if ( (0xF0 != (0xF0 & r[14] )) /* after short name 14 bytes */
5985 // || (0x0D != (0x0D & r[26] )) /* +12 more bytes */
5986 || (0xC0 != (0xC0 & r[27] )) /* +1 more byte */
5988 fprintf( stdout, "CVCT VC %d has bad RB %02X %02X %02X\n",
5989 i, r[14], r[26], r[27]);
5990 break;
5994 memcpy( &vc[i].name, r, 14); /* 7 chars unicode */
5995 for (j=1;j<14;j++) {
5996 if (0 == vc[i].name[j]) vc[i].name[j] = ' ';
5998 r += 14;
5999 vc[i].major = ((0xF & r[0]) << 6) | ((0xFC & r[1]) >> 2);
6000 vc[i].minor = ((0x3 & r[1]) << 8) | r[2];
6001 /* one part number? */
6002 opn = 0;
6003 if (0x3F0 == (0x3F0 & vc[i].major)) {
6004 opn = (0x0F & vc[i].major) << 10;
6005 opn |= vc[i].minor;
6006 fprintf(stdout, "OPN %d\n", vc[i].minor);
6008 vc[i].mode = r[3];
6009 vc[i].freq = (r[4]<<24) | (r[5]<<16) | (r[6]<<8) | r[7];
6010 vc[i].ctsid = (r[8]<<8) | r[9];
6011 vc[i].pn = (r[10]<<8) | r[11];
6012 vc[i].etm = (0xC0 & r[12]) >> 6;
6013 vc[i].actrl = (0x20 & r[12]) >> 5;
6014 vc[i].hide = (0x10 & r[12]) >> 4;
6015 vc[i].path = (0x08 & r[12]) >> 3;
6016 vc[i].oob = (0x04 & r[12]) >> 2; /* rsvd in TVCT */
6017 vc[i].hideg = (0x02 & r[12]) >> 1; /* rsvd in TVCT */
6018 vc[i].svct = (0x3F & r[13]);
6019 vc[i].src = (r[14]<<8) | r[15];
6020 vc[i].dlen = ((0x3 & r[16])<<8) | r[17];
6021 r += 18; /* skip parsed */
6022 /* look for descriptors, spec says may be 0 */
6024 { int k; for (k=0; k< vc[i].dlen; k++) aprintf2(stdout, "%02X ", r[k]);}
6025 aprintf2( stdout, "\n"); fflush(stdout);
6027 /* show channel name */
6028 aprintf2( stdout, " VC%d [", i);
6029 for (j=0; j<14;) {
6030 aprintf2( stdout, "%c", vc[i].name[j+1] );
6031 j += 2; /* the low byte is the one that's ASCII */
6033 aprintf2( stdout, "] ");
6035 /* default is ATSC type, change if necessary */
6036 // snprintf( t, sizeof(t)-1, "ATSC DTV %d.%d", vc[i].major, vc[i].pn);
6037 snprintf( t, sizeof(t)-1, "ATSC .%d", vc[i].pn);
6038 if (vc[i].pn == 0xFFFF)
6039 strncpy( t, "NTSC", sizeof(t)-1);
6040 if (vc[i].pn == 0)
6041 strncpy( t, "DISABLED", sizeof(t)-1);
6042 if (vc[i].mode > 5) vc[i].mode = 0;
6043 if (vc[i].svct > 4) vc[i].svct = 0;
6045 msr = 0;
6046 /* qam is around 5 megasymbols */
6047 if (2 == vc[i].mode) msr = 5056941;
6048 if (3 == vc[i].mode) msr = 5360637;
6050 /* vsb is around 10 megasymbols */
6051 if (4 == vc[i].mode) msr = 10762237;
6052 if (5 == vc[i].mode) msr = 10762237;
6054 if (0x3F0 == (0x3F0 & vc[i].major)) {
6055 aprintf2( stdout, "OPN %d\n", opn);
6056 } else {
6057 aprintf2( stdout, "M.n %d.%d\n", vc[i].major, vc[i].minor);
6060 aprintf2( stdout,
6061 " Modulation %s (%d) Symbol Rate %d Frequency %d\n",
6062 mt[vc[i].mode], vc[i].mode, msr, vc[i].freq);
6063 aprintf2( stdout,
6064 " TSID %04X Program %s ETM Location %d Path %d OOB %d\n",
6065 vc[i].ctsid, t, vc[i].etm, vc[i].path, vc[i].oob );
6066 aprintf2( stdout,
6067 " Access Control %d Hidden %d Hide Guide %d\n",
6068 vc[i].actrl, vc[i].hide, vc[i].hideg );
6069 aprintf2( stdout,
6070 " Service Type %s Source %d DLen %02X\n",
6071 st[vc[i].svct], vc[i].src, vc[i].dlen );
6073 /* test the descriptor */
6074 if (vc[i].dlen != 0) {
6075 aprintf2( stdout, " VCT DESCRIPTORS: DLen %02X\n", vc[i].dlen);
6076 /* use test vct descriptor because different output control */
6077 test_vct_descriptor( r, vc[i].dlen );
6079 r += vc[i].dlen;
6084 /* look for additional descriptors, spec says may be 0 */
6085 /* spec said something about this, it may be a single descriptor? */
6086 /* doesn't seem to fit the other descriptors if so */
6087 if (0xFC == (r[0] & 0xFC)) {
6088 adl = ((0x3 & r[0]) << 8) | r[1];
6089 r++;
6090 r++;
6092 if (adl != 0) {
6093 aprintf2( stdout, " TVCT add'l desc: ");
6094 for (j=0; j < adl; j++) {
6096 aprintf2( stdout, "%02X", *r );
6097 r++; /* skip descriptor to get to crc */
6099 aprintf2( stdout, "\n");
6103 aprintf2( stdout, "\n");
6108 /************************************************************** MGT Payload */
6109 /* add to mgt payload. returns 0 if done, or 1 if not done */
6110 static
6111 unsigned int
6112 build_mgt_payload( unsigned char *p )
6114 unsigned char *r;
6115 unsigned char psi; /*, vn; */
6117 r = p+5;
6119 psi = 1 & ( p[1] >> 6);
6121 /* handle payload start packet by copying start to MGT payload buffer */
6122 if (psi != 0)
6124 if ( (0xC7 == r[0])
6125 // && (0xF0 == (0xF0 & r[1]) ) // syntax,private,reserved bits
6126 && (0xC0 == (0xC0 & r[1]) ) // syntax,private
6127 && (0xC1 == (0xC1 & r[5]) ) // reserved bits top 2, cni=1
6130 mgt.sl = ((0xF & r[1])<<8) | r[2];
6131 mgt.vn = 0x1F & ( r[5] >> 1);
6133 mgt.payoff = 183;
6135 aprintf6( stdout,
6136 " START MGT Version %02X SLen %03X Payoff %03X\n",
6137 mgt.vn, mgt.sl, mgt.payoff);
6138 memset( mgt.payload, 0, sizeof(mgt.payload) ); // reset
6139 memcpy( mgt.payload, r, mgt.payoff);
6141 if ( mgt.payoff > mgt.sl+3 ) {
6142 aprintf6( stdout, " DONE MGT\n");
6143 return 0;
6146 return 1;
6149 r = p+4;
6151 // additional non start packet payloads append to MGT payload buffer
6152 if (psi == 0) {
6153 memcpy( &mgt.payload[mgt.payoff], r, 184);
6154 mgt.payoff += 184;
6155 aprintf6( stdout, " COPY MGT Version %02X SLen %03X Payoff %03X\n",
6156 mgt.vn, mgt.sl, mgt.payoff);
6158 if ( mgt.payoff > mgt.sl+3 ) {
6159 aprintf6( stdout, " DONE MGT\n");
6160 return 0;
6162 return 1;
6164 aprintf1( stdout, " MGT not parsed\n");
6165 return -1;
6169 static
6170 void
6171 test_mgt ( unsigned char *p )
6173 unsigned short sl, tidx, td, dl, i; /* j; */
6174 unsigned char vn, cni, sn, lsn, pv;
6175 unsigned char *r;
6177 // fprintf(stdout, "MGT\n");
6179 mgt.payok = build_mgt_payload( p );
6180 if (0 != mgt.payok) return;
6182 // fprintf(stdout, "MGT OK\n");
6184 r = mgt.payload;
6185 if (0xC7 != r[0]) {
6186 aprintf1( stdout, "table id not MGT 0xC7 but 0x%02X\n", r[0]);
6187 return;
6190 #if 0
6191 if ( (0xF0 != (0xF0 & r[1])) || (0xC1 != (0xC1 & r[5])) ) {
6192 aprintf1(stdout, "MGT has bad TT/RB\n");
6193 return; /* reserved must be set */
6195 #endif
6196 if ( (0xC0 != (0xC0 & r[1])) || (0xC1 != (0xC1 & r[5])) ) {
6197 aprintf1(stdout, "MGT has bad TT/RB\n");
6198 return; /* reserved must be set */
6201 sl = ((0xF & r[1]) <<8) | r[2]; /* 12 bit section length */
6202 if (sl > 4093)
6204 aprintf1(stdout, "MGT SLen > 4093\n");
6205 return; /* if sl > 4093, ignore packet */
6207 mgt_crc = calc_crc32( r, sl+3);
6209 if (mgt_crc != 0) {
6210 pkt.crcmgt++;
6211 aprintf1( stdout, "MGT CRC32 ERROR\n");
6212 return;
6215 pkt.mgt++;
6217 tidx = (r[3]<<8) | r[4];
6219 vn = (0x3E & r[5]) >> 1; /* 5 bit version number */
6221 /* OUTPUT REDUX: */
6222 if (0 != arg_redux)
6223 if (vn == mgt_vn)
6224 return; /* don't update until vn changes */
6225 mgt_vn = vn;
6228 aprintf1( stdout, "MGT CRC OK\n");
6230 cni = 1 & r[5]; /* current/next indicator */
6231 sn = r[6]; /* 8 bit section number */
6232 lsn = r[7]; /* 8 bit last section number */
6234 pv = r[8]; /* 8 bit protocol version */
6235 if (pv != 0) {
6236 aprintf1( stdout, "MGT Protocol Version not 0\n");
6237 return; /* should always be zero */
6239 td = r[9]<<8 | r[10]; /* 16 bit tables defined */
6240 r += 11; /* skip parsed */
6242 aprintf1(stdout, " MGT C7 VER %02X SLen %03X Tables %d CNI %d SN %d LSN %d\n",
6243 vn, sl, td, cni, sn, lsn );
6245 /* version staying same should skip all the rest */
6246 memset( mg, 0, sizeof( mg ) );
6248 /* new mgt should reset pg */
6249 memset( pg, 0, sizeof( pg ) );
6251 mgt_tt_pidx = 0;
6252 mgt_eit = 0;
6254 for (i=0; i<td; i++)
6256 if ( ( 0xE0 == (0xE0 & r[2]))
6257 && ( 0xE0 == (0xE0 & r[4]))
6258 && ( 0xF0 == (0xF0 & r[9]))
6261 unsigned short tt;
6262 unsigned short ttpid;
6263 unsigned char ttvn;
6264 unsigned int nb;
6265 unsigned short ttdl;
6266 unsigned char tx[8];
6268 tt = (r[0]<<8) | r[1];
6269 ttpid = ((0x1F & r[2])<<8) | r[3];
6270 ttvn = 0x1F & r[4];
6271 nb = (r[5]<<24) | (r[6]<<16) | (r[7]<<8) | r[8];
6272 ttdl = ((0xF & r[9])<<8) | r[10];
6273 r += 11;
6275 /* 0000-1FFF table types EIT 100-17F ETT 200-27F,
6276 1500-1FFF reserved
6278 mg[ mgt_tt_pidx ].tt = tt; /* table type */
6280 /* 0-1FFF PID range. coincidentally near same size as tt */
6281 mg[ mgt_tt_pidx ].ttpid = ttpid; /* table type PID */
6283 mg[ mgt_tt_pidx ].ttvn = ttvn; /* version */
6284 mg[ mgt_tt_pidx ].nb = nb; /* bytes in table */
6285 mg[ mgt_tt_pidx ].ttdl = ttdl; /* bytes in descriptor */
6286 mgt_tt_pidx++;
6288 strncpy( tx, "RESERV", sizeof(tx));
6289 /* see A/65b Table 6.3 page 26 */
6290 if (tt == 0) strncpy( tx, "TVCT-C1", sizeof(tx)-1);
6291 if (tt == 1) strncpy( tx, "TVCT-C0", sizeof(tx)-1);
6292 if (tt == 2) strncpy( tx, "CVCT-C1", sizeof(tx)-1);
6293 if (tt == 3) strncpy( tx, "CVCT-C0", sizeof(tx)-1);
6294 if (tt == 4) strncpy( tx, "PTC ETT", sizeof(tx)-1);
6295 if (tt == 5) strncpy( tx, "DCCSCT ", sizeof(tx)-1);
6296 if ( (tt >= 0x100) && (tt <= 0x17f) ) {
6297 snprintf( tx, sizeof(tx)-1, "EIT-%02X ", tt & 255);
6298 mgt_eit = 1;
6300 if ( (tt >= 0x200) && (tt <= 0x27f) )
6301 snprintf( tx, sizeof(tx)-1, "ETT-%02X ", tt & 255);
6302 if ( (tt >= 0x301) && (tt <= 0x3ff) )
6303 snprintf( tx, sizeof(tx)-1, "RRT-%02X ", tt & 255);
6304 if ( (tt >= 0x1400) && (tt <= 0x14ff) )
6305 snprintf( tx, sizeof(tx)-1, "DCC-%02X ", tt & 255);
6307 aprintf1( stdout,
6308 " Table #%3d Type %-7s %04X PID %04X Ver %02X NumB %06X TTDLen %d\n",
6309 i+1, tx, tt, ttpid, ttvn, nb, ttdl);
6311 /* -k mgt specified, so keep all PIDs listed in MGT */
6312 if (arg_mgtpids != 0) keep_pids[ ttpid ] = ~0;
6316 /* more reserved bit validate */
6317 if (0xF0 != (0xF0 & r[0])) return;
6319 dl = ((0xF & r[0])<<8) | r[1];
6320 r += 2;
6321 aprintf1( stdout, " Additional Descriptor Len %03X\n", dl);
6323 /* spec indicates it should be one descriptor only, no additional */
6324 #if 0
6325 for (j=0; j<dl; j++) {
6326 test_mgt_descriptor( r, dl );
6328 #endif
6329 r += dl;
6330 aprintf1( stdout, "\n");
6333 /* return -1 if pid is not in mgt_tt_pid table, else return index */
6334 static
6336 test_mgt_tt_pid( unsigned int pid )
6338 int i;
6339 for (i=0; i<mgt_tt_pidx; i++) {
6340 // aprintf1( stdout, "test mgt pid %04X ttpid %04X\n", pid, mg[i].ttpid );
6341 if ( pid == (0x1FFF & mg[i].ttpid ) ) return i;
6343 return -1;
6347 /* packets that match MGT table */
6348 static
6349 void
6350 test_mgt_tt_packet( unsigned char *p, unsigned int pid )
6352 int ttidx, ttpid, tt;
6354 ttidx = test_mgt_tt_pid( pid );
6355 if (ttidx == -1) {
6356 aprintf1( stdout, "PID %04X table not found in MGT\n", pid);
6357 return; // no match found
6359 pkt.atsc++;
6360 ttpid = 0x1FFF & mg[ ttidx ].ttpid; /* pid ranges len coincidental to */
6361 tt = 0x1FFF & mg[ ttidx ].tt; /* table ranges. dont get confused */
6363 if (tt == 0) {
6364 dprintf6( stdout, " PID %04X Table Type %04X Terrestrial VCT CNI1\n", ttpid, tt);
6365 return;
6367 if (tt == 1) {
6368 dprintf6( stdout, " PID %04X Table Type %04X Terrestrial VCT CNI0\n", ttpid, tt);
6369 return;
6371 if (tt == 2) {
6372 dprintf6( stdout, " PID %04X Table Type %04X Cable VCT CNI1\n", ttpid, tt);
6373 return;
6375 if (tt == 3) {
6376 dprintf6( stdout, " PID %04X Table Type %04X Cable VCT CNI0\n", ttpid, tt);
6377 return;
6379 if (tt == 4) {
6380 dprintf6( stdout, " PID %04X Table Type %04X Channel ETT ", ttpid, tt);
6381 test_channel_ett( p );
6382 return;
6384 if (tt == 5) {
6385 dprintf6( stdout, " PID %04X Table Type %04X DCCSCT\n", ttpid, tt);
6386 return;
6389 /* Event Information Table */
6390 if ( (tt > 0xFF) && (tt < 0x180) ) {
6391 dprintf1( stdout, " PID %04X Table Type %04X EIT-%02X\n", ttpid, tt, tt-0x100);
6392 test_eit( p, tt & 0x7F );
6393 return;
6396 /* Extended Text Table */
6397 if ( (tt > 0x1FF) && (tt < 0x280) ) {
6398 dprintf1( stdout, " PID %04X Table Type %04X ETT-%02X\n", ttpid, tt, tt-0x200);
6399 test_ett( p, 0x7F & tt );
6400 return;
6403 /* Rating Region Table */
6404 if ( (tt > 0x2FF) && (tt < 0x400) ) {
6405 dprintf1( stdout, " PID %04X Table Type %04X RRT-%02X\n", ttpid, tt, tt-0x300);
6406 test_rrt( p );
6407 return;
6410 /* Directed Channel Change Table */
6411 if ( (tt > 0x13FF) && (tt < 0x1500) ) {
6412 dprintf1( stdout, " PID %04X Table Type %04X DCCT-%02X\n", ttpid, tt, tt-0x1400);
6413 test_dcct( p );
6414 return;
6417 /* see A/65b Table 6.3 Table Types */
6418 dprintf1( stdout, " PID %04X RESERVED TT %04X\n", ttpid, tt);
6420 /****************************************************************************/
6422 /******************************************************** System Time Table */
6423 static
6424 void
6425 test_stt ( unsigned char *p )
6427 static unsigned int stt_prev;
6428 unsigned char *r;
6429 char e = ' '; /* error flag */
6431 r = p+5;
6433 /* all these have to be true or nothing happens */
6434 if ( (0xCD == r[0]) /* table_id is STT table = 0xCD */
6435 && (0xF0 == (r[1] & 0xF0)) /* syntax,private,reserved = 1 */
6436 && (0x00 == r[3]) /* table_id_extension msB = 0 */
6437 && (0x00 == r[4]) /* table_id_extension lsB = 0 */
6438 && (0xC1 == r[5]) /* rsvd, current_next = 1, ver = 0 */
6439 && (0x00 == r[6]) /* section number = 0 */
6440 && (0x00 == r[7]) /* last section number = 0 */
6443 stt.sl = ((0xF & r[1]) <<8) | r[2];
6445 /* don't process any further if the CRC is bad */
6446 stt.crc = calc_crc32( r, stt.sl+3 );
6447 if (stt.crc != 0) {
6448 pkt.crcstt++;
6449 aprintf0( stdout, "STT CRC ERROR\n");
6450 return;
6453 stt.st = (p[14]<<24) | (p[15]<<16) | (p[16]<<8) | p[17];
6454 stt.guo = p[18]; /* gps utc offset */
6456 stt.ds = (p[19]<<8) | p[20]; /* unused for now? always 06D0 */
6458 /* daylight savings status A/65b Annex A pp 84-85 */
6459 if (0x60 == (0x60 & p[19])) {
6460 stt.dss = 1 & (stt.ds >> 15);
6461 stt.dsd = 0x1F & (stt.ds >> 8 );
6462 stt.dsh = 0x1F & stt.ds;
6463 } else {
6464 /* DST ctl reserved bits not set */
6465 stt.dss = 0;
6466 stt.dsd = 0;
6467 stt.dsh = 0;
6469 /* GPS UTC offset correction, Bureau of Standards sets + / - */
6470 stt.st -= stt.guo;
6472 /* add 10 years + 5 days for ATSC epoch starting at Jan 6 1980 */
6473 /* is really 10 years + 7 days counting 1972 & 1976 leap years */
6474 stt.st += utc_offset;
6476 if (last_stt > stt.st) e = '*';
6478 if (0 == first_stt) first_stt = stt.st;
6479 last_stt = stt.st;
6481 /* fill stt_tm structure with corrected time */
6482 /* FIXME: DST not handled yet? */
6483 localtime_r( &stt.st, &stt_tm );
6485 pkt.stt++;
6487 /* ouput redux, but actually want this one as speedometer */
6488 /* if (0 == (stt.st % 60)) */
6489 /* if (stt_prev != stt.st) */
6491 time_t tt;
6492 struct tm lt; /* local time */
6493 char ds1[32]; /* date string */
6494 char ds2[32];
6496 tt = time( NULL );
6497 localtime_r( &tt, &lt);
6498 asctime_r( &stt_tm, stt_text );
6499 asctime_r( &stt_tm, ds1 );
6500 asctime_r( &lt, ds2);
6501 ds1[24] = 0;
6502 ds2[24] = 0;
6503 aprintf7( stdout,
6504 "STT %04d%02d%02d %02d:%02d:%02d %c o%d ds%04X s%d d%d h%d\n",
6505 stt_tm.tm_year + 1900,
6506 stt_tm.tm_mon + 1,
6507 stt_tm.tm_mday,
6508 stt_tm.tm_hour,
6509 stt_tm.tm_min,
6510 stt_tm.tm_sec,
6511 e, stt.guo, stt.ds, stt.dss, stt.dsd, stt.dsh );
6514 stt_prev = stt.st;
6516 /* aprintf0( stdout, "\n"); */
6519 /* handle PID 1FFB, single or multi-packet payload */
6520 static
6521 void
6522 test_atsc_packet( unsigned char *p )
6524 unsigned int psi, pid;
6526 psi = 1 & (p[1]>>6);
6527 pid = 0x1FFF & ((p[1]<<8) | p[2]);
6528 pkt.atsc++;
6530 // payload start indicator?
6531 if (psi != 0)
6533 // pkt.atsctid = p[5]; // save last tid that got payload unit start bit
6534 // switch( pkt.atsctid ) {
6535 psit[ pid ] = p[5];
6536 switch( psit[ pid ] ) {
6537 case 0xCD:
6538 test_stt( p );
6539 break;
6541 case 0xC7:
6542 test_mgt( p );
6543 break;
6545 case 0xC8:
6546 test_tvct( p );
6547 break;
6549 case 0xC9:
6550 test_cvct( p );
6551 break;
6553 case 0xCA:
6554 test_rrt( p );
6555 break;
6557 case 0xD3:
6558 test_dcct( p );
6559 break;
6561 case 0xD4:
6562 test_dccsct( p );
6563 break;
6565 default:
6566 aprintf0( stdout, " unknown ATSC table id %02X*\n", p[5]);
6567 break;
6569 return;
6572 // if psi indicates rest of payload, see what last pkt.tid needs payload
6573 // this pretty much requires the ATSC packets be sequential, so that
6574 // no other ATSC PID comes down before last PID in current table done.
6575 // not sure if spec spells it out. maybe left to the implementation.
6576 if (psi == 0)
6578 // switch( pkt.atsctid ) {
6579 switch( psit[ pid ] ) {
6580 case 0xCD:
6581 test_stt( p );
6582 break;
6584 case 0xC7:
6585 test_mgt( p );
6586 break;
6588 case 0xC8:
6589 test_tvct( p );
6590 break;
6592 case 0xC9:
6593 test_cvct( p );
6594 break;
6596 case 0xCA:
6597 test_rrt( p );
6598 break;
6600 default:
6601 break;
6604 return;
6608 static
6609 void
6610 test_packet( unsigned char *p )
6612 unsigned int tei, psi, pid, pri, cc, tsc, afc, tid, i;
6613 unsigned char c;
6614 unsigned char cct;
6616 cct = ' ';
6618 /* -d option duty cycle control, limits bandwidth used by program
6619 this tries to force the program data transfer rate down
6620 to prevent problems with any in-progress captures
6621 -d50 looks to write near same speed as broadcast rate, on my system.
6624 if (arg_duty != 100)
6626 i = pkt.count % duty_cycle_packet;
6628 // sleeps at begin
6629 //if (i == 0) usleep( duty_cycle_sleep );
6631 // sleeps at end until ideal packet rate expired
6632 if ( i == (duty_cycle_packet-1) ) usleep( duty_cycle_sleep );
6635 pkt.count++;
6636 tei = 1 & (p[1] >> 7); // transport error indicate
6638 psi = 1 & (p[1] >> 6); // payload start indicator
6639 pkt.psi = psi; // use for multi-packet table
6641 pri = 1 & (p[1] >> 5); // transport priority
6642 pid = 0x1FFF & ( (p[1] << 8) | p[2] ); // program id
6643 tsc = 3 & (p[3]>>6); // transport scramble control
6644 afc = 3 & (p[3]>>4); // adaptation field control
6645 cc = 15 & p[3]; // continuity counter
6646 tid = p[5];
6649 if (0 != *arg_newpat) {
6650 if (0 == pid)
6651 memcpy( p, newpat, 188 );
6652 p[3] &= 0xF0;
6653 p[3] |= cc; /* keep the continuity counter */
6658 // ignore reserved AFC packets
6659 if (afc == 0) return;
6661 // ignore transport error indicator set packets
6662 if (tei != 0) {
6663 pkt.errtei++;
6664 // keep_pkt = 0;
6665 dprintf4(stdout, "PKT # %8u TEI\n", pkt.count);
6666 return;
6669 // ignore scramble control non zero packets
6670 if (tsc != 0) {
6671 pkt.errscr++;
6672 // keep_pkt = 0;
6673 dprintf4(stdout, "PKT # %8u scramble bits = %u\n", pkt.count, tsc);
6674 return;
6677 // continuity counter finally works. looks simple but wasn't obvious
6678 pid_cc[ pid ] = 0; // payload process will use to see if drop time
6679 if (pid != 0x1FFF) {
6680 if (0xFF != last_cc[ pid ]) {
6681 if (afc == 2) {
6682 // cc doesnt change for afc 2
6683 if (cc != last_cc[ pid ]) {
6684 pkt.errcce++;
6685 cct = '!';
6686 pid_cc[ pid ] = ~0;
6688 } else {
6689 // cc should change for everything else except NULLs
6690 // no duplicates seen in local ATSC broadcasts
6691 if (cc != (0xF & (last_cc[ pid ]+1))) {
6692 pkt.errcce++;
6693 cct = '!';
6694 pid_cc[ pid ] = ~0;
6695 cc_err[ pid ]++;
6696 if (pid < 0x1000) {
6697 pkt.mpegce++;
6698 } else {
6699 pkt.atscce++;
6706 last_cc[ pid ] = cc; // for next time thru
6708 pids[pid]++; // count pid's of good non null packets
6710 c = '#';
6711 if (arg_pids != 0) {
6712 c = '-';
6713 if (0 != keep_pids[pid]) {
6714 c = '+';
6718 // full stream cut to full stream should keep NULLs
6719 // but most times doing full stream cut to 1 video and 1 audio
6720 if (pid == 0x1FFF) {
6721 pkt.null++;
6722 if (0 != arg_nulls) keep_pids[pid] = ~0;
6723 return;
6726 /* + means on PID list, - is not on list, # is not checking */
6727 /* also masking START NO unless -v bit 4 (16 val) set */
6728 if ( 0 == psi ) {
6729 /* bit 4 of -v option makes START NO appear */
6730 if (0 != (16 & arg_verbose)) {
6731 dprintf1(stdout, "PKT %c %8d PID %04X SC %d AF %d CC %01X%c START NO ",
6732 c, pkt.count-1, pid, tsc, afc, cc, cct );
6733 for (i = 4; i < 12; i++) dprintf1(stdout, "%02X ", p[i]);
6734 dprintf1( stdout, "\n");
6736 } else {
6737 dprintf1(stdout, "PKT %c %8d PID %04X SC %d AF %d CC %01X%c START YES ",
6738 c, pkt.count-1, pid, tsc, afc, cc, cct );
6739 for (i = 4; i < 12; i++) dprintf1(stdout, "%02X ", p[i]);
6740 dprintf1( stdout, "\n");
6743 /* count pes packet type but don't do anything with it yet */
6744 if ( pid < 0x1000 ) {
6745 test_mpeg2_packet( p );
6748 // ATSC PSIP always has AFC=1
6749 if (afc == 1) {
6750 if (pid == 0x1FFB) { // handle 1FFB PID PSIP types
6751 test_atsc_packet( p ); // handles MGT TVCT STT, not RRT CVCT
6752 } else {
6753 // >= 0x1000 is possible ATSC PSIP packet
6754 if ( (pid > 0xFFF) && (pid < 0x1FFF)) // handle non 1FFB/1FFF PID
6755 test_mgt_tt_packet ( p, pid ); // from MGT PSIP lut
6759 /* write buffer used for:
6760 -k PID extract
6761 -e program extract
6762 -r pat replacement
6763 -t pmt replacement
6765 if (0 != arg_pids)
6766 if (0 != keep_pids[pid]) /* in the lookup table? */
6767 #ifdef USE_BUFFER
6768 write_buffer( out_buf, p, TSPZ);
6769 #else
6770 write( out_file, p, TSPZ);
6771 #endif
6772 return;
6776 static
6777 void
6778 read_loop( void )
6780 int len, ok, i;
6782 len = TSBUFZ;
6783 ok = 0;
6785 fprintf( stdout, "Testing packets in %s\n", in_name);
6786 if (0 != *arg_newpat)
6787 fprintf( stdout, "Replacing PAT packets with %s\n", arg_newpat);
6788 if (0 != arg_mgtpids)
6789 fprintf( stdout, "Extracting PIDs for ATSC and MPEG tables\n");
6790 if (0 != arg_seqwr)
6791 fprintf( stdout, "Extracting Frames to %sx\n",
6792 in_name);
6793 if (0 != arg_epn)
6794 fprintf( stdout, "Extracting PIDS for MPEG Program number %d\n",
6795 arg_epn);
6797 if ( (0 == arg_epn)
6798 && (0 == arg_epn)
6799 && (0 != arg_pids)
6800 && (0 == arg_mgtpids) ) {
6801 fprintf( stdout, "Extracting by this PID list: ");
6802 for (i=0; i<0x2000; i++)
6803 if (0 != keep_pids[i])
6804 fprintf( stdout, "%04X ", i);
6805 fprintf( stdout, "\n");
6808 fprintf( stdout, "\n");
6810 bytes_out = 0;
6812 while ( 0 != len )
6814 // read a packet
6815 #ifdef USE_BUFFER
6816 len = read_buffer( in_buf, ts_buf, TSPZ);
6817 #else
6818 len = read( in_file, ts_buf, TSPZ);
6819 #endif
6820 if (len < 0) {
6821 fprintf(stdout, "Could not read %s\n", in_name);
6822 perror("");
6823 exit(1);
6825 if (0 == len) {
6826 fprintf( stdout, "EOF\n");
6827 break;
6830 bytes_in += len;
6832 /* packet traffic director */
6833 test_packet( ts_buf );
6834 #if 0
6835 if (0 != arg_crc) {
6836 /* Could use as a packet hash for unique ID but has multiple solutions. */
6837 /* Perhaps could be useful for future stream-restoration project. */
6838 unsigned int crc;
6839 crc = calc_crc32( ts_buf, TSPZ );
6840 fprintf( stdout, "%08X\n", crc );
6842 #endif
6846 return;
6849 /* ATSC uses 32 bit unsigned from 00:00:00 UTC, Jan 6, 1980
6850 unix uses 32 bit unsigned from 00:00:00 UTC, Jan 1, 1970
6851 difference is saved in global utc_offset
6853 static
6854 void
6855 calc_epoch( void )
6857 struct tm as = {0,0,0,6,0,80,0,0,0}; // Jan 6, 1980 00:00:00 UTC
6858 unsigned long utd;
6859 unsigned char d[32];
6861 utd = (unsigned int)mktime( &as );
6862 snprintf( d, sizeof(d)-1, "%s", asctime(localtime( &utd )) );
6864 d[24] = 0;
6865 if (utd != -1)
6866 fprintf( stdout, "ATSC timebase %s: unix diff %u TZ diff %ld\n",
6867 d, (unsigned int)utd, as.tm_gmtoff );
6869 utc_offset = utd + as.tm_gmtoff;
6873 static
6874 void
6875 parse_args( int argc, char **argv)
6877 struct stat fs;
6878 char bn[256];
6879 int arg_idx; // copy of argc, decremented
6880 int c;
6881 int sr, ok; // stat returns
6882 int adump, mdump, vdump;
6883 char inz[32], inp[32];
6885 in_size = 0;
6886 arg_idx = 0;
6888 arg_adump = arg_mdump = arg_verbose = 0;
6890 if (argc == 1) {
6891 fprintf(stdout, usage, argv[0]);
6892 exit(0);
6895 while ((c = getopt( argc, argv, "cfghnqs" "a:d:e:k:m:o:p:r:v:y:")) != EOF)
6897 switch(c)
6899 case 'c':
6900 arg_crc = ~arg_crc;
6901 break;
6903 case 'f':
6904 arg_forge = ~arg_forge;
6905 break;
6907 case 'q':
6908 arg_redux = ~arg_redux;
6909 break;
6911 case 'r':
6913 int npf;
6914 sscanf( optarg, "%s", arg_newpat );
6915 npf = open( arg_newpat, RD_MODE );
6916 if (npf > 2) {
6917 ok = read( npf, newpat, 188);
6918 if (188 != ok) {
6919 fprintf(stderr, "%s < 188 bytes\n", optarg);
6920 close(npf);
6921 exit(0);
6923 close( npf );
6925 } else {
6926 *arg_newpat = 0;
6930 break;
6932 case 'h':
6933 fprintf(stdout, usage, argv[0]);
6934 exit(0);
6935 break;
6937 case 'g':
6938 arg_guide = ~arg_guide;
6939 break;
6941 case 's':
6942 arg_seqwr = ~0;
6943 break;
6945 case 'n':
6946 arg_nulls = ~0;
6947 break;
6949 case 'e':
6950 arg_pids = ~0;
6951 sscanf( optarg, "%d,%d", &arg_epn, &arg_ean);
6952 if (arg_epn < 1) arg_epn = 0; /* ignore bogus */
6953 if (arg_epn > 65534) arg_epn = 0; /* program number */
6954 arg_ean &= 7;
6956 break;
6958 case 'y':
6959 sscanf( optarg, "%x", &arg_espid);
6960 arg_espid &= 0x1FFF;
6961 fprintf( stdout, "Extracting ES PID %04X\n", arg_espid);
6962 break;
6964 // duty cycle from 1 to 100
6965 case 'd':
6966 sscanf( optarg, "%d", &arg_duty);
6967 if (arg_duty < 1) arg_duty = 1;
6968 if (arg_duty > 100) arg_duty = 100;
6969 break;
6971 // ATSC detail level
6972 case 'a':
6973 adump = 0;
6974 if (NULL != optarg) adump = atoi( optarg);
6975 arg_adump |= adump;
6976 break;
6978 // MPEG detail level
6979 case 'm':
6980 mdump = 0;
6981 if (NULL != optarg) mdump = atoi( optarg );
6982 arg_mdump |= mdump;
6983 break;
6985 // verbose and packet assembly detail level
6986 case 'v':
6987 vdump = 0;
6988 if (optarg != NULL) vdump = atoi( optarg );
6989 if (vdump & 2) arg_adump = 0xFF;
6990 if (vdump & 4) arg_mdump = 0xFF;
6991 arg_verbose |= vdump;
6992 break;
6994 // add a PID to the list to test for keeping
6995 // -k mgt will keep all PIDs from Master Guide Table
6996 // without the audio and video, for testing ATSC PSIP only
6997 case 'k':
6998 if (optarg != NULL) {
6999 int pid;
7000 arg_pids = ~0;
7002 // -k mgt option to keep all ATSC Master Guide
7003 if ( 0 == strncasecmp(optarg, "mgt", strlen(optarg)) ) {
7004 arg_mgtpids = ~0;
7005 } else {
7006 sscanf( optarg, "%x", &pid);
7007 // fprintf( stdout, "-k %d option\n", pid);
7008 keep_pids[ 0x1FFF & pid ] = ~0;
7011 break;
7013 case 'o':
7014 if (optarg != NULL) {
7015 snprintf( arg_name, sizeof(arg_name)-1, "%s", optarg);
7017 /* null extraction needs to trigger file write somehow */
7020 break;
7022 /* output path, tests for IFDIR */
7023 case 'p':
7024 if (optarg != NULL) {
7025 struct stat s;
7026 snprintf( arg_path, sizeof(arg_path)-1, "%s", optarg);
7028 // remove trailing slash if any
7029 if (arg_path[strlen(arg_path)-1] == '/')
7030 arg_path[strlen(arg_path)-1] = 0;
7032 stat( arg_path, &s );
7033 if ( (s.st_mode & S_IFDIR) == 0 ) {
7034 fprintf(stderr, "\n%s is not a directory\n", arg_path);
7035 exit(1);
7037 snprintf( out_path, sizeof(out_path)-1, "%s", arg_path);
7039 break;
7042 default:
7043 break;
7048 // duty cycle packet is % of packets per ideal second
7049 duty_cycle_packet = (12898 * arg_duty) / 100;
7051 // FIXME: don't use constant pktrate
7052 // duty cycle sleep is how long until end of ideal second
7053 // see notes in test packet for usage
7055 duty_cycle_sleep = 12898 - duty_cycle_packet;
7056 duty_cycle_sleep *= 77; // 77 microseconds/packet
7059 // fprintf( stderr, "optind %d argc %d\n", optind, argc);
7061 arg_idx = argc - optind;
7062 arg_idx = (arg_idx < 0) ? 0 : arg_idx;
7064 // fprintf( stderr, "arg_idx %d argv[optind] %s\n",arg_idx, argv[optind]);
7066 if (arg_idx < 1) {
7067 fprintf( stderr, "\nMissing a parameter? See %s -h\n\n", argv[0]);
7068 exit(1);
7071 // filename is first on list after options, optind stays pointing to it
7072 snprintf( in_name, sizeof(in_name)-1, "%s", argv[optind]);
7074 memset( &fs, 0, sizeof( fs ) ); // clear stat struct
7076 // get file size of input file
7077 sr = stat( in_name, &fs);
7078 if (sr != 0) {
7079 fprintf( stderr, "%s ", in_name);
7080 perror("stat");
7081 exit(1);
7084 in_size = fs.st_size; // file size, used for packet rate compute
7086 lltoasc( inz, in_size );
7087 lltoasc( inp, in_size / 188 );
7089 fprintf( stdout, "Input file name %s\nInput size %s bytes, %s packets\n",
7090 in_name, inz, inp );
7092 in_file = open( in_name, FILE_RMODE );
7093 if (in_file < 3) {
7094 fprintf( stderr, "\nerror opening file %s: ", in_name );
7095 perror("");
7096 exit(1);
7099 #ifdef USE_BUFFER
7100 in_buf = init_buffer( in_file, 4096, in_name );
7101 if (NULL == in_buf) {
7102 fprintf(stderr, "\nCan't allocate buffer for %s\n\n", in_name);
7103 exit(1);
7105 #endif
7107 file_size = fs.st_size;
7108 // fprintf( stdout, "%s has %lld bytes\n", in_name, file_size);
7110 // create basename for the cut(s)
7111 strncpy( bn, argv[optind], sizeof(bn) );
7113 /* -o output name override, but only overrides base name */
7114 if (0 != *arg_name)
7115 strncpy( bn, arg_name, sizeof(arg_name) );
7116 filebase( base_name, bn, F_TFILE );
7118 arg_idx--; // filename done
7120 /* -k numeric extract is -x.ts */
7121 if (0 != arg_pids) {
7122 snprintf( out_name, sizeof(out_name)-1, "%s/%s-x.ts",
7123 out_path, base_name);
7124 /* -k mgt subset extract is -mgt.ts */
7125 if (0 != arg_mgtpids) {
7126 snprintf( out_name, sizeof(out_name)-1, "%s/%s-mgt.ts",
7127 out_path, base_name);
7130 /* -e program subset extract is .p.ts */
7131 if (0 != arg_epn) {
7132 if (0 == arg_ean) {
7133 snprintf( out_name, sizeof(out_name)-1, "%s/%s.%d.ts",
7134 out_path, base_name, arg_epn);
7135 /* with non-main audio is .p,a.ts */
7136 } else {
7137 snprintf( out_name, sizeof(out_name)-1, "%s/%s.%d,%d.ts",
7138 out_path, base_name, arg_epn, arg_ean);
7142 out_file = open( out_name, FILE_WMODE, FILE_PERMS );
7143 if (out_file < 3) {
7144 perror("");
7145 exit(1);
7148 #ifdef USE_BUFFER
7149 out_buf = init_buffer( out_file, 4096, out_name );
7150 if (NULL == out_buf) {
7151 fprintf(stderr, "\nCan't allocate buffer for %s\n\n", out_name);
7152 exit(1);
7154 #endif
7156 fprintf( stdout, "PIDs will be extracted to %s\n", out_name);
7159 /* -y Video Elementary Stream extract, (still has a PES header @ SEQ) */
7160 if (0 != arg_espid) {
7161 snprintf( es_name, sizeof(es_name)-1, "%s/%s-%02X.es",
7162 out_path, base_name, arg_espid);
7164 es_file = open( es_name, FILE_WMODE, FILE_PERMS );
7165 if (es_file < 3) {
7166 perror("");
7167 exit(1);
7170 #ifdef USE_BUFFER
7171 es_buf = init_buffer( es_file, 4096, es_name );
7172 if (NULL == es_buf) {
7173 fprintf(stderr, "\nCan't allocate buffer for %s\n\n", es_name);
7174 exit(1);
7176 #endif
7177 fprintf( stdout, "PID %04X ES output to %s\n", arg_espid, es_name);
7183 #if 0
7184 // xenoterms word wrapper, could be used for long description display...
7185 static
7186 void
7187 word_wrap_tab( unsigned char *s, int cl )
7189 unsigned char *t;
7190 unsigned char tab[80];
7192 int ts, ns, cc, cl, i, len;
7194 ts = cc = ns = 0;
7196 t = strchr( s, '|'); // first | is tab stop
7197 if (t != NULL) ts = t - s;
7198 memset( tab, 0, sizeof(tab));
7199 ts += 2;
7200 memset( tab, ' ', ts);
7201 len = strlen(s);
7202 fprintf( stdout, "\n");
7203 for (i = 0; i < len; i++) {
7204 // if this char not a space, find next space
7205 if (s[i] != ' ') {
7206 t = strchr( &s[i], ' ');
7207 if (t != NULL) {
7208 ns = t - &s[i];
7209 if ((ns + cc) > cl)
7211 fprintf( stdout, "\n%s", tab);
7212 cc = ts;
7216 fprintf( stdout, "%c", s[i]);
7217 cc++;
7220 #endif
7223 static
7224 void
7225 remove_dups( void )
7227 unsigned int i, j;
7229 // first make pg list of unsorted entries and count pgm_idx
7230 pgm_idx = 0;
7231 for (i = 0; i < PGZ; i++) if (pgm[ i ].etmid != 0) pg[ pgm_idx++ ] = i;
7232 fprintf( stdout, "pgm idx %d\n", pgm_idx);
7234 pg_idx = pgm_idx;
7236 // if the EIT and ETT are parsed correctly you wont need to sort
7237 // however, sort makes duplicate removal a lot easier, if less efficient
7238 // sort by VC# and time, since sort by ETMID is broken?
7240 #if 0
7241 for (i = 0; i < (pg_idx-1); i++) {
7242 for (j = (i+1); j < pg_idx; j++) {
7243 if ( pgm[ pg[ j ] ].etmid < pgm[ pg[ i ] ].etmid ) {
7244 int k;
7245 k = pg[j];
7246 pg[j] = pg[i]; // old sort of sort
7247 pg[i] = k; // do not need anything faster
7251 #endif
7253 // now can remove dups
7254 /* sieve method of removal, more accurate, less efficient */
7255 for (i = 0; i < (pg_idx-1); i++) {
7256 if (0xFFFF == pg[ i ]) continue; /* skip already removed */
7257 for (j = (i+1); j <pg_idx; j++) {
7258 if (0xFFFF == pg[ j ]) continue; /* skip already removed */
7259 if ( pgm[ pg[ i ] ].etmid == pgm[ pg[ j ] ].etmid ) {
7260 fprintf( stdout, "Remove DUP of pgm[%04X] @ pgm[%04X]\n",
7261 pg[ i ], pg[ j ] );
7262 memset( &pgm[ pg[ j ]], 0, sizeof( pgm1 ) ); // clear it
7263 pg[ j ] = 0xFFFF; /* mark it inactive */
7268 /* create pg1 index list, will be modified by [sort and?] dup removal */
7269 // pg1_idx = 0;
7270 // for (i = 0; i < pg_idx; i++) if (0xFFFF != pg[i]) pg1[pg1_idx++] = pg[i];
7272 // dump guide uses pg1[ 0...pg1_idx-1 ] for sorted with no dups
7273 fprintf( stdout, "Old pg %u new no-DUP pg1 %d\n\n", pg_idx, pg1_idx);
7276 static
7277 void
7278 dump_guide( void )
7280 short pn, sr, ap; // atsc program number lookup from source id
7281 int i, j, k;
7282 unsigned int lpt;
7283 unsigned int cpt; // last program time+len
7284 unsigned char s[1024];
7285 unsigned char d[32]; // date string
7286 unsigned char td; // to do
7287 struct tm stm; // start time as tm
7288 time_t st; // start time as time_t
7290 if (arg_guide == 0) return;
7292 i = j = k = 0;
7293 lpt = cpt = 0;
7295 // sort guide by etmid. it gets unruly otherwise.
7296 // various PSIP generators do various things differently
7297 remove_dups(); // sets pg1_idx
7299 fprintf( stdout, "PSIP guide dump, last STT %s\n", stt_text);
7300 fprintf( stdout,
7301 " pg ETMID Pgm# Date Time Len Name"
7302 " Description\n");
7304 // for (i = 0; i < pg1_idx; i++) {
7305 // k = pg1[i]; // shorthand for sorted no-dup pg1 index
7307 for (i = 0; i < pg_idx; i++) {
7308 k = pg[i];
7309 if (0xFFFF == k) continue; /* skip removed */
7310 if (0 == pgm[k].etmid) continue; /* skip empty */
7312 td = ' ';
7314 // only bother with pgm entry if etmid set
7315 // if (0 != pgm[k].etmid)
7318 pn = 0;
7319 sr = pgm[k].etmid>>16;
7320 ap = find_vc_src( sr );
7321 if (ap >= 0) {
7322 pn = vc[ap].pn;
7324 st = pgm[k].st;
7326 localtime_r( &st, &stm);
7327 asctime_r( &stm, d);
7329 d[16] = 0;
7331 if (strlen(pgm[k].name) > 30) {
7332 pgm[k].name[30]='>';
7333 pgm[k].name[31]=0;
7335 cpt = pgm[k].st;
7337 // first one doesn't get a star, but rest out of sync do
7338 if ( (i != 0) && (cpt != lpt) ) td = '*';
7340 snprintf( s, sizeof(s)-1,
7341 "%c"
7342 " %04X "
7343 "%08X "
7344 "%04X "
7345 "%s "
7346 "%4d "
7347 "%-32s "
7348 "%s ",
7351 pgm[k].etmid,
7354 pgm[k].ls / 60,
7355 pgm[k].name,
7356 pgm[k].desc
7359 // if (strlen(s) > 78) {
7360 // s[78] = '>';
7361 // s[79] = 0;
7362 // }
7364 // output line of text
7365 fprintf( stdout, "%s\n", s);
7366 // word_wrap_tab( s );
7367 // fix last program time to current + len
7368 lpt = cpt + pgm[k].ls;
7374 static
7375 void
7376 dump_counts( void )
7378 int i, j, k;
7379 unsigned char p1[32], p2[32], p3[32];
7381 j = 0;
7383 // sum up transport errors
7384 pkt.errors = pkt.errsyn + pkt.errtei + pkt.errscr + pkt.errcce;
7385 // then atsc errors
7386 pkt.errors += pkt.crcstt + pkt.crcmgt + pkt.crctvct + pkt.crceit
7387 + pkt.crcett + pkt.crcrrt + pkt.crcdcct + pkt.crcdccsct;
7388 // then mpeg errors
7389 pkt.errors += pkt.crcpat + pkt.crccat + pkt.crcpmt;
7391 lltoasc(p1, pkt.count);
7392 lltoasc(p2, pkt.pes);
7393 lltoasc(p3, pkt.errors);
7395 fprintf( stdout, "\nPackets %s, PES packet %s, Errors %s\n", p1, p2, p3);
7397 fprintf( stdout, "Transport Errors: %d: Sync %d Scrambled %d Continuity %d\n\n",
7398 pkt.errtei, pkt.errsyn, pkt.errscr, pkt.errcce);
7400 if (0 != pkt.errcce) {
7401 if (0 != pkt.mpegce) {
7402 fprintf( stdout, "MPEG Continuity errors %d, PIDs:\n", pkt.mpegce);
7403 for (i = 0; i < 0x1000; i++) {
7404 if (0 == cc_err[i]) continue;
7405 fprintf( stdout, " %04X # %8d", i, cc_err[i]);
7406 j++;
7407 j &= 3;
7408 if (0 == j) fprintf( stdout, "\n");
7410 fprintf( stdout, "\n");
7412 if (0 != pkt.atscce) {
7413 fprintf( stdout, "ATSC Continuity errors %d, PIDs:\n", pkt.atscce);
7414 for (i = 0x1000; i < 0x2000; i++) {
7415 if (0 == cc_err[i]) continue;
7416 fprintf( stdout, " %04X # %8d", i, cc_err[i]);
7417 j++;
7418 j &= 3;
7419 if (0 == j) fprintf( stdout, "\n");
7421 fprintf( stdout, "\n");
7423 fprintf( stdout, "\n");
7426 if (0 != pkt.mpeg2) {
7427 fprintf( stdout, "MPEG PIDs by Table Type:\n");
7428 fprintf( stdout, "MPEG---- -----PAT -----CAT -----PMT -----VID -----AUD ----NULL\n");
7429 fprintf( stdout, "%8d %8d %8d %8d %8d %8d %8d\n",
7430 pkt.mpeg2+pkt.null, pkt.pat, pkt.cat, pkt.pmt,
7431 pkt.vid, pkt.aud, pkt.null );
7433 k = pkt.crcpat + pkt.crccat + pkt.crcpmt;
7434 if (0 != k)
7435 fprintf( stdout, "CRC32ERR %8d %8d %8d\n",
7436 pkt.crcpat, pkt.crccat, pkt.crcpmt);
7437 fprintf( stdout, "\n");
7440 if (0 != pkt.atsc) {
7441 fprintf( stdout, "ATSC PIDs by Table Type:\n");
7442 fprintf( stdout, "ATSC---- -----MGT -----VCT -----EIT -----ETT -----RRT -----STT\n");
7443 fprintf( stdout, "%8d %8d %8d %8d %8d %8d %8d\n",
7444 pkt.atsc, pkt.mgt, pkt.tvct, pkt.eit,
7445 pkt.ett, pkt.rrt, pkt.stt);
7447 k = pkt.crcmgt + pkt.crctvct + pkt.crceit + pkt.crcett + pkt.crcrrt + pkt.crcstt;
7448 if (0 != k)
7449 fprintf( stdout, "CRC32ERR %8d %8d %8d %8d %8d %8d\n",
7450 pkt.crcmgt, pkt.crctvct, pkt.crceit, pkt.crcett,
7451 pkt.crcrrt, pkt.crcstt);
7452 fprintf( stdout, "\n");
7455 // if (0 == arg_pids) return;
7457 if (0 != pkt.mpeg2) {
7458 fprintf( stdout, "MPEG PID counts:");
7459 j = 0;
7460 k = pkt.null;
7461 for (i = 0; i < 0x1000; i++) {
7462 if (pids[i] > 0) {
7463 char *s;
7464 k += pids[i];
7465 s = " ";
7466 if (i > 0x1FF0) { s = "\n "; j = 0; }
7467 if (0 == (0xF & i)) { s = "\n "; j = 0; }
7468 if (3 == (3 & j)) { s = "\n\\ "; j = 0; }
7469 j++;
7470 fprintf(stdout, "%s%04X #%9d", s, i, pids[i]);
7473 fprintf( stdout, "\n");
7474 fprintf( stdout, "MPEG PID total: %8d\n\n", k);
7477 if (0 != pkt.atsc) {
7478 k = 0;
7479 fprintf( stdout, "ATSC PID counts:\n");
7480 for (i = 0x1000; i < 0x1FFF; i++) {
7481 if (pids[i] > 0) {
7482 char *s;
7483 k += pids[i];
7484 s = " ";
7485 if (i > 0x1FF0) { s = "\n "; j = 0; }
7486 if (0 == (0xF & i)) { s = "\n "; j = 0; }
7487 if (3 == (3 & j)) { s = "\n\\ "; j = 0; }
7488 j++;
7489 fprintf(stdout, "%s%04X #%9d", s, i, pids[i]);
7492 fprintf( stdout, "\n");
7493 fprintf( stdout, "ATSC PID total: %8d\n\n", k);
7497 /* write .tsx file:
7498 sequence[] long long byte offsets, list terminated by -1LL,
7499 frames[] picture types and packet counts per picture
7501 FIXME: seems to choke on files > 2hr long. spews out bad frame data.
7504 static
7505 void
7506 dump_sequences( void )
7508 unsigned char n[256];
7509 unsigned char o[256];
7510 ssize_t x, y;
7511 FILE *f;
7512 long long m1 = -1LL;
7514 printf( "\n");
7516 if (0 == arg_seqwr) return;
7517 // if (0 == arg_write) return;
7518 if (0 == frame_idx) return;
7519 if (0 == sequence_idx) return;
7521 /* truncate name */
7522 filebase( n, in_name, F_PFILE );
7523 /* add .tsx */
7524 snprintf( o, sizeof(o), "%s.tsx", n);
7525 /* open file */
7526 f = fopen( o, "w");
7527 if (NULL == f) {
7528 fprintf( stderr, "error opening %s ", o);
7529 perror("");
7530 /* error on open returns */
7531 return;
7534 // fprintf( stdout, "writing sequence indices to %s\n", o);
7535 x = sequence_idx;
7537 /* terminate list with -1LL */
7538 sequences[x] = m1;
7540 /* FIXME: should check return to write the rest if it didn't finish it */
7541 y = fwrite( sequences, sizeof(m1), x+1, f);
7543 fprintf( stdout, "Wrote %lld out of %lld sequences to %s\n",
7544 (long long)y-1, (long long)x, o );
7545 bytes_out += y * sizeof( m1 );
7548 // fprintf( stdout, "Writing frame packet indices to %s\n", o );
7549 x = frame_idx;
7551 /* FIXME: should check return to write the rest if it didn't finish it */
7552 y = fwrite( frames, sizeof(struct frame_s), x, f);
7554 fprintf( stdout, "Wrote %lld out of %lld frames to %s\n",
7555 (long long)y, (long long)x, o );
7557 bytes_out += y * sizeof( struct frame_s );
7558 fflush( f );
7559 fclose( f );
7560 printf( "\n");
7564 static
7565 void
7566 dump_elapsed( void )
7568 double etf;
7569 double tpf;
7570 double flf;
7571 char bt[32];
7573 fprintf( stdout, " IN %11lld bytes\n", bytes_in);
7574 fprintf( stdout, "OUT %11lld bytes\n", bytes_out);
7576 bytes_total = bytes_in + bytes_out;
7578 etf = (double)cap_et.tv_sec;
7579 etf += ((double)cap_et.tv_nsec / 1000000000.0);
7581 tpf = (double)bytes_total;
7582 tpf /= etf;
7583 tpf /= 1000000.0;
7585 lltoasc( bt, bytes_total );
7587 fprintf( stdout, "\n");
7588 fprintf( stdout,
7589 "processed %s bytes in %.2f seconds, %.2f MB/s\n",
7590 bt, etf, tpf );
7592 ap_et.tv_sec, cap_et.tv_nsec,
7593 (long long)( (bytes_total / (long long)cap_et.tv_sec) >> 20) );
7596 if (last_pcr != 0) {
7597 fprintf( stdout,
7598 "MPEG Stream Elapsed %llu %llu/90000 Seconds from AFC PCR\n",
7599 (last_pcr - first_pcr) / 90000ULL,
7600 (last_pcr - first_pcr) % 90000ULL );
7603 if (last_stt != 0) {
7604 flf = (double)last_stt - (double)first_stt;
7606 if (etf < 0.1) etf = 0.1;
7608 fprintf( stdout,
7609 "ATSC Stream Elapsed %u Seconds from STT, Rate: %.2fx\n",
7610 last_stt - first_stt, flf/etf);
7615 static
7616 void
7617 start_timer( void )
7619 memset( &cap_start, 0, sizeof(cap_start)); /* w/o librt, start is 0 */
7621 #ifdef USE_LIBRT
7622 clock_gettime( clock_method, &cap_start);
7623 #endif
7627 static
7628 void
7629 stop_timer( void )
7631 cap_stop.tv_sec = 1; /* w/o librt, ET is 1s */
7633 #ifdef USE_LIBRT
7634 clock_gettime( clock_method, &cap_stop);
7635 #endif
7636 memcpy( &cap_et, &cap_stop, sizeof(cap_et) );
7638 // if nanos subtracts borrow
7639 if (cap_start.tv_nsec > cap_stop.tv_nsec) {
7640 cap_et.tv_sec--;
7641 cap_et.tv_nsec += 1000000000;
7643 cap_et.tv_sec -= cap_start.tv_sec;
7644 cap_et.tv_nsec -= cap_start.tv_nsec;
7646 // minimum is always one second, bypass short cut /0 moth
7647 if (cap_et.tv_sec < 1) cap_et.tv_sec = 1;
7650 static
7651 void
7652 alloc_frames( void )
7654 frames = malloc( FRAME_MAX * sizeof(struct frame_s) );
7655 sequences = malloc( SEQUENCE_MAX * sizeof(long long) );
7658 static
7659 void
7660 free_frames( void )
7662 free(frames);
7663 free(sequences);
7667 static
7668 void
7669 init_arrays( void )
7671 int i;
7673 /* initialize some arrays */
7674 memset( pgm, 0, sizeof( pgm ) );
7675 memset( pg, 0, sizeof( pg ) );
7676 memset( pg1, 0, sizeof( pg1 ) );
7678 memset( &pkt, 0, sizeof( pkt ) );
7679 memset( pids, 0, sizeof( pids ) );
7680 memset( pid_cc, 0xFF, sizeof( pid_cc ) );
7681 memset( pid_vn, 0xFF, sizeof( pid_cc ) );
7682 memset( cc_err, 0, sizeof( cc_err ) );
7684 memset( psit, 0xFF, sizeof( psit ) );
7685 memset( keep_pids, 0, sizeof( keep_pids ) );
7687 /* EIT/ETT version numbers set invalid for update */
7688 memset( eitvn, 0xFF, sizeof(eitvn));
7689 memset( ettvn, 0xfF, sizeof(ettvn));
7691 /* continuity counters set invalid for update */
7692 for (i=0; i < 0x2000; i++) last_cc[i] = 0xFF;
7697 main( int argc, char **argv)
7700 #ifdef USE_LIBRT
7701 test_clock_res(); /* find most accurate clock for clock_gettime */
7702 #endif
7704 start_timer();
7706 fprintf( stdout, "\n"NAME" "VERSION" "LASTEDIT" "COPYRIGHT" "EMAIL"\n");
7707 fprintf( stdout, "Released under the %s\n", LICENSE);
7708 fprintf( stdout, "This software is supplied AS-IS, with NO WARRANTY.\n");
7709 fprintf( stdout, "Compiled on %s at %s for %s\n",
7710 __DATE__, __TIME__, PLATFORM_NAME );
7712 calc_epoch(); /* ATSC vs Unix epoch */
7714 init_allocs();
7716 alloc_frames(); /* -s uses this */
7718 init_arrays(); /* clear the baffles */
7720 parse_args( argc, argv ); /* hey homer, have a powdered jelly doh-nut */
7722 show_allocs();
7724 read_loop(); /* reads until EOF */
7726 if (in_file > 2) {
7727 close( in_file );
7728 #ifdef USE_BUFFER
7729 reset_buffer( in_buf );
7730 free_buffer( in_buf );
7731 #endif
7734 if (es_file > 2) {
7735 close( es_file );
7736 es_file = 0;
7737 #ifdef USE_BUFFER
7738 flush_buffer( es_buf, 1 ); /* sync */
7739 bytes_out += es_buf->num;
7740 fprintf(stdout, "\n ES->num %lld\n", es_buf->num);
7741 free_buffer( es_buf );
7742 #endif
7745 if (out_file > 2) {
7746 close( out_file );
7747 out_file = 0;
7748 #ifdef USE_BUFFER
7749 flush_buffer( out_buf, 1 ); /* sync */
7750 bytes_out += out_buf->num;
7751 fprintf(stdout, "\n TS->num %lld\n", out_buf->num);
7752 free_buffer( out_buf );
7753 #endif
7756 stop_timer();
7758 if (0 != arg_seqwr) {
7759 dump_sequences(); /* -s option writes frames/sequences */
7760 } else {
7761 dump_counts(); /* counts will not be valid without read loop */
7762 dump_guide(); /* guide will not be valid unless ATSC PSIP */
7765 free_frames();
7767 dump_elapsed();
7769 show_allocs();
7770 fprintf( stdout, "\n");
7772 fflush( stdout );
7774 return 0;