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
34 ATSC Transport Stream Container Utility
35 Copyright (c) 2004-2008 by inkling@users.sourceforge.net
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 \
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
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.
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.
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
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
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
228 #define _FILE_OFFSET_BITS 64
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>
247 #ifndef PLATFORM_NAME
248 #define PLATFORM_NAME "Linux"
254 #include <sys/types.h>
255 #include <sys/stat.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 */
266 #define PGZ (VCZ * EIZ * PEZ)
273 // transport stream packet size
275 // 21 packets is almost 4k
276 #define TSBUFZ (21 * TSPZ)
278 // sync byte value (not always unique in the stream)
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
325 /////////////////////////////// globals ///////////////////////////////////
326 static unsigned char *usage
=
328 " %s [options] file.ts\n"
330 " file.ts ATSC/ATSC+MPEG2/MPEG2-only Transport Stream file\n"
334 " Packet extraction control (PIDs are given in hexadecimal):\n"
336 " -p path Output path. Default is .\n"
338 " -o name Use this output basename instead of input basename.\n"
340 " -e integer Extract single Program from full stream capture.\n"
341 " Program numbers are 1-65534, not 0 or 65535.\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"
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"
353 " -d integer Duty cycle %% e.g. -d95. Default 100, no sleeping.\n"
354 " Lower CPU usage prevents pchdtvr capture dropout.\n"
357 " -y PID Extract specified Video PID as ES to basename-pid.es.\n"
360 " -n NULLs: keeps the bitrate same as source file\n"
362 "\n -r file.ts replace Progam Association Table 188 byte file.ts\n"
363 " single program stream only\n"
365 "\n -f forge PAT + PMT to one video + one audio, see -e\n"
367 " -h Help. You're looking at it.\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"
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"
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"
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 */
385 " -g dump ATSC PSIP Event Program Guide, if any.\n"
386 " Guide dump requires full stream capture.\n"
388 " -q quiet, redux stdout to only version changes + PES\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;
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; */
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.
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 */
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 */
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 */
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
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
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
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
574 int seqend
; // count sequence end codes (commercial breaks?)
578 /* program association has list of program numbers and pmt pids */
586 /* generic payload structure */
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
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 */
624 static struct stt_s stt
;
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.
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
;
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
];
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
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
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,
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 **********************************/
1074 static buf_t
*in_buf
;
1075 static buf_t
*es_buf
;
1076 static buf_t
*out_buf
;
1079 /********************************************************************** CRC32
1084 calc_crc32( unsigned char *data
, unsigned int len
)
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
++) ];
1096 /******************************************************************** CRC32 */
1099 /************************************************************** HUFFMAN DECODE
1100 * huffman title and description text decode.
1101 * d destination needs 512 bytes in case source is 255 bytes
1105 huffman_decode( unsigned char *d
, unsigned char *s
, int dlen
, int slen
, int comp
)
1107 unsigned char p
, c
, o
, r
;
1110 unsigned int to
, zo
, z
;
1111 unsigned int i
, j
, k
;
1116 // dprintf2( stdout, "\n Huffman L%02X C%02X\n", slen, comp );
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
1137 // should be pointing to correct tables now
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
);
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
);
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
1165 if (0 == (128 & o
)) {
1166 fprintf(stdout
, "BRANCH s[%02X].%d %d pchr %02X toff %03X "
1168 "delta %d+%02X<<1 = [%02X]\n",
1169 i
>> 3, ~i
& 7, b
, p
, to
,
1170 (b
==0)?"LEFT ":"RIGHT",
1175 if (0 != (128 & o
) )
1181 fprintf( stdout
,"LEAF s[%02X].%d %d pchr %02X toff %03X "
1183 i
>> 3, ~i
& 7, b
, p
, to
, c
, (c
<32)?' ':c
);
1187 // handle Escape to 8 bit mode
1188 i
++; // point to msb of bytes
1196 b
= s
[ (i
>> 3) + 1];
1200 i
+= 7; // skip past lsb of byte
1203 fprintf( stdout
, "ESCAPE s[%02X].%d j %d k %d chr %02X [%c] ",
1204 i
>>3, ~i
& 7, j
, k
, c
, c
);
1209 p
= c
; // c leaf becomes new index for order-1 tree root offset
1210 o
= 0; // clear offset to order-1 tree
1216 } // out of space gets nul term
1218 t
++; // else move to next char
1220 // nul term stops loop
1223 fprintf( stdout
, "TERM\n");
1228 fprintf( stdout
, "\n");
1233 fprintf( stdout
, "Huffman done: [%s]\n", d
);
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.
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 */
1259 mprintf4( stdout
, "Closed Caption\n ");
1261 for (i
= 0; i
<63; ) { /* 63 bytes, 21 triplets */
1262 b
= (p
[i
]<<16) | (p
[i
+1]<<8) | p
[i
+2];
1266 mprintf4( stdout
, "%06X ", b
);
1268 if (0 == (i
%8)) mprintf4( stdout
, "\n " );
1270 mprintf4( stdout
, "\n" );
1273 // letter/pillar box settings is in bar data if exists
1275 mprintf4( stdout
, "Bar Data\n" );
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] ) {
1292 gopx
= 0xFFFF & ((r
[1]<<8) | r
[2]);
1293 mprintf4( stdout
, "GOPX: %5d\n", gopx
);
1297 /* no, full cap or different origin than atscap/pchdtvr */
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));
1308 mprintf4( stdout
, " TC HMSP: %02d:%02d:%02d:%02d\n",
1310 mprintf4( stdout
, " Drop flag %d Closed GOP %d Broken Link %d\n",
1314 /* returns picture type index */
1317 test_mpeg2_picture( unsigned char *r
)
1319 unsigned short tr
, vbvd
;
1320 unsigned char pct
; /* picture type */
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 ? */
1334 memset( ipb
, 0, sizeof(ipb
));
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
1346 // reset to avoid overflow
1347 if (sumrate
> 1500000000) {
1348 sumrate
= sumrate
/ iframe
;
1351 // set for next delta
1352 pkt
.pcount
= pkt
.count
;
1364 pt
= "D?"; // mpeg1 only
1367 mprintf4( stdout
, " %s Temporal %2u VBVd %5u\n", pt
, tr
, vbvd
);
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
);
1379 /* tally up the slices */
1382 test_mpeg2_slice( unsigned char *r
)
1384 /* does nothing for now */
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 */
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
,
1399 unsigned short ppl
; // spec needs to make this 32 bits and use it
1401 unsigned long long pts
;
1402 unsigned long long dts
;
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
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");
1425 ptsf
= 3 & (*r
>>6); // r[7] b7:6
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");
1451 // check pts marker bits
1452 if ( (0x21 == (0xF1 & r
[0])) && (1 & r
[2]) && (1 & r
[4]) ) {
1454 pts
|= (7 & (*r
>> 1)) << 30; // 32..30
1456 pts
|= *r
<< 22; // 29..22
1458 pts
|= (*r
>>1) << 15; // 21..15
1460 pts
|= *r
<< 7; // 14..7
1462 pts
|= *r
>>1; // 6..0
1464 pts
&= 0x1FFFFFFFFLL
;
1468 m
= ( rts
/ 60 ) % 60;
1469 h
= ( rts
/ 3600) % 24;
1471 mprintf4( stdout
, " PTS %01d:%02u:%02u:%02u.%llu\n",
1472 d
, h
, m
, s
, pts
% 90000 );
1479 // check pts marker bits
1480 if ( (0x31 == (0xF1 & r
[0])) && (1 & r
[2]) && (1 & r
[4]) ) {
1482 pts
|= (7 & (*r
>> 1)) << 30; // 32..30
1484 pts
|= *r
<< 22; // 29..22
1486 pts
|= (*r
>>1) << 15; // 21..15
1488 pts
|= *r
<< 7; // 14..7
1490 pts
|= *r
>>1; // 6..0
1492 pts
&= 0x1FFFFFFFFLL
;
1496 m
= ( rts
/ 60 ) % 60;
1497 h
= ( rts
/ 3600) % 24;
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]) ) {
1505 dts
|= (7 & (*r
>> 1)) << 30; // 32..30
1507 dts
|= *r
<< 22; // 29..22
1509 dts
|= (*r
>>1) << 15; // 21..15
1511 dts
|= *r
<< 7; // 14..7
1513 dts
|= *r
>>1; // 6..0
1515 dts
&= 0x1FFFFFFFFLL
;
1519 m
= ( rts
/ 60 ) % 60;
1520 h
= ( rts
/ 3600) % 24;
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 */
1536 test_mpeg2_video_seq( unsigned char *p
, int len
)
1541 // for (i = 0; i < vid.payoff; i++ )
1542 for (i
=0; i
< len
; i
++) /* only first packet, after AFC to save cycles */
1548 /* Sequence Start code means this payload has:
1549 [optional GOP] and I-Frame
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
) {
1560 "\n FATAL: sequence_idx exceeds SEQUENCE_MAX.\n"
1561 "Recompile with larger FRAME_MAX.\n");
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
;
1572 if (frame_idx
>= FRAME_MAX
) {
1574 "\n FATAL: frame_idx exceeds FRAME_MAX.\n"
1575 "Recompile with larger FRAME_MAX.\n");
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 */
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.
1594 /* save cycles, Intra frame already counted */
1596 frames
[ frame_idx
].pct
= pct
;
1597 frames
[ frame_idx
].vpn
= pkt
.vid
;
1599 if (frame_idx
>= FRAME_MAX
) {
1601 "\n FATAL: frame_idx exceeds FRAME_MAX.\n"
1602 "Recompile with larger FRAME_MAX.\n");
1606 /* save cycles by not looking past picture start */
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. */
1624 test_mpeg2_video_es ( void )
1628 unsigned char *frt
, *art
, *xidt
, *p
, c
;
1629 unsigned short hz
, vz
, vbvz
;
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?","","","" };
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 */
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
++) {
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 */
1667 "Sequence Start # %5d [below has last IPB]\n",
1670 if (0 == (0x20 & p
[i
+6])) {
1671 mprintf4( stdout
, "Marker bit not set, skipping\n");
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
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
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
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
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
);
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
);
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
1776 xid
= p
[i
+1]>>4; // 1-A see 13818-2 table 6-2
1777 mprintf4( stdout
, "Extension ID (%1X): ", 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
1788 mprintf4( stdout
, "%s\n", xidt
);
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";
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
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) );
1818 frn
= 3 & p
[i
+5] >> 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
);
1831 unsigned char vf
, cd
, cp
, tc
, mc
;
1832 unsigned short dhz
, dvz
;
1834 xidt
= "Sequence Display";
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
);
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
);
1865 mprintf4( stdout
, " Color Primaries %02X, Transfer Chars %02X, Matrix Co-effs %02X\n", cp
, tc
, mc
);
1867 mprintf4( stdout
, " Colors, Transfer, and Matrix Coefficients follow ITU-R BT.709\n");
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
);
1910 xidt
= "Sequence Scalable";
1914 xidt
= "Picture Display";
1918 unsigned char fh
, fv
, bh
, bv
, idcp
, ps
, tff
, fpfd
;
1919 unsigned char cmv
, qst
, ivf
, as
, rff
, c420
, pf
, cdf
;
1921 xidt
= "Picture Coding";
1922 mprintf4( stdout
, "%s\n", xidt
);
1929 idcp
= 3 & p
[i
+2]>>2;
1933 if (1 == ps
) pst
= "Top Field";
1934 if (2 == ps
) pst
= "Bottom Field";
1935 if (3 == ps
) pst
= "Frame";
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;
1949 rff
= 1 & p
[i
+3]>>1;
1953 cdf
= 1 & p
[i
+4]>>6;
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
1965 // v_axis:1 field_seq:3 sub_carrier:1 burst_amplitude:7 sub_carrier_phase:8
1971 if (9 == xid
) xidt
= "Picture Spatial Scalable";
1972 if (10== xid
) xidt
= "Picture Temporal Scalable";
1973 mprintf4( stdout
, "%s: NOT PARSED\n", xidt
);
1975 continue; // find next start code
1976 } // end of sequence extensions
1979 /* Group Of Pictures */
1981 mprintf4( stdout
, "Group Of Pictures: ");
1982 test_mpeg2_group_of_pictures( p
+ i
+ 1 );
1983 continue; // find next start code
1986 /* picture start? */
1988 mprintf4( stdout
, "Picture ");
1989 pti
= test_mpeg2_picture( p
+ i
+ 1 );
1990 memset( sc
, 0, sizeof(sc
) ); /* clear slice checklist */
1995 /* ATSC User Data, Closed Caption or Bar data, only seeing CC */
1997 test_ap_user_data( p
+ i
+ 1 );
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
)) {
2005 "MPEG Video PES Header, stream ID %02X\n", p
[i
]);
2006 test_mpeg2_video_pes( p
);
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
);
2019 "Slice %02X Macroblock Pixel Rows %u - %u\n",
2020 sn
, (sn
- 1) << 4, 15 + ((sn
- 1) << 4) );
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");
2038 if (0 != sm
) { /* seq sets sm, pic clears sc[] */
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 */
2048 mprintf5( stdout
, "Missing slices: ");
2049 for (j
= 1; j
<= sm
; j
++)
2051 mprintf5( stdout
, "%u ", j
);
2052 mprintf5( stdout
, "\n");
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
);
2065 /* Sequence End. Have seen it trigger on network to local bug,
2066 but it's not reliable enough to use for cutting
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
2090 test_mpeg2_adaptation_field( unsigned char *p
)
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
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
2113 r
++; // adaptation field length is always first byte after cc
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
2149 // these should be done in the right order
2150 // program clock reference, main mpeg system clock
2154 // bad reserved should abort?
2155 if ( (0 == rb
) || (0x7E == rb
) ) // reserved can be 1 or 0? very odd
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
2174 /* make 42 bit PCR as a 27 mhz clock value (300 * 90kc) */
2175 pcr
= (300 * pcrb
) + pcrx
;
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?)
2186 // normal pcr increment behaviour is default
2189 if (0 == first_pcr
) first_pcr
= pcr
;
2193 // print if mpeg video info asked for
2195 " %cPCR %01dd:%02dh:%02dm:%02ds %05uc %3llux diff %10lld\n",
2196 (pcrd
< 27000000) ? ' ':'*', pd
, ph
, pm
, ps
, pr
, px
, pcrd
2200 mprintf7( stdout
, " PCR reserved bits not set %02X\n", rb
);
2204 // original program clock reference, from previous multiplex or source?
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
++;
2224 pm
= (pw
/ 60) % 60;
2225 ph
= (pw
/ 3600) % 24;
2229 mprintf7( stdout
, " OPCR %01d:%02d:%02d:%02d.%05d ext %3d\n",
2230 pd
, ph
, pm
, ps
, pr
, opcrx
);
2233 mprintf7( stdout
, " OPCR Reserved bits not set %02X\n", rb
);
2240 sc
= *r
++; // 8 bit signed
2243 // transport private data, skips and does not keep private data bytes
2247 for (i
= 0; i
< tpdl
; i
++) pdb
= *r
++;
2250 // adaptation field extension
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
2260 ltwv
= 1 & (*r
>> 7); // 1 bit ltw valid
2261 ltwo
= (0x7F & *r
++) << 8; // 15 bit ltw offset
2262 ltwo
|= 0xFF & *r
++;
2265 if (0xC0 == (0xC0 & *r
)) { // reserved
2266 pwr
= 0x3F & *r
++; // 22 bit piecewise rate
2267 pwr
|= (*r
++) << 16;
2274 // seamless splice, Decoder Time Stamp next access unit
2276 if ( (1 == (1 & r
[0])) // marker bits
2277 || (1 == (1 & r
[2]))
2278 || (1 == (1 & r
[4]))
2282 st
= 0xF & (*r
>>4); // blech spec mess
2284 // dts next access unit
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;
2298 dtsnau
|= 0x3F & (*r
++ >> 1);
2300 pr
= dtsnau
% 90000;
2301 pw
= dtsnau
/ 90000;
2303 pm
= (pw
/ 60) % 60;
2304 ph
= (pw
/ 3600) % 24;
2307 mprintf4( stdout
, "\n DTS NAU %01d:%02d:%02d:%02d.%05d",
2308 pd
, ph
, pm
, ps
, pr
);
2314 if ( 0 != afb
) mprintf4( stdout
, "\n");
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
2327 build_payload(char *p
, struct payload_s
*s
, char *n
)
2333 psi
= 1 & ( p
[1] >> 6);
2335 /* payload start indicator yes */
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);
2341 memcpy( s
->payload
, r
, s
->payoff
);
2342 if ( s
->payoff
> s
->sl
+3 ) {
2347 /* payload start indicator no */
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);
2361 if ( s
->payoff
> s
->sl
+3 ) {
2362 return 0; // payload is done
2367 return 1; // payload not handled
2372 ////////////////////////////////////////////////////////////////// MPEG2 PAT
2373 // payload assembly for PAT, not needed, all ATSC PATs are 188 bytes or less
2376 build_pat_payload( unsigned char *p
)
2384 psi
= 1 & ( p
[1] >> 6);
2387 // handle payload start packet by copying start to PAT payload buffer
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];
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");
2415 // additional non start payloads append to PAT payload buffer
2417 memcpy( &pat
.payload
[pat
.payoff
], r
, 184);
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");
2430 aprintf6( stdout
, "PAT not parsed\n");
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
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);
2462 unsigned short pgn
, pmtpid
;
2463 pgn
= new_pat
[13] << 8; /* 16 bit program number */
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
;
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);
2494 fprintf( stdout
, "%s chk_crc %08X", __FUNCTION__
, chk_crc
);
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
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;
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 */
2539 /* only copy and increment if program info len non zero */
2545 for ( i
= 0; i
< c
; ) {
2546 if (0xAA == *s
) *s
= 0x80; /* stuff the RC */
2548 s
+= s
[1]+2; /* step thru descriptors */
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)) ) {
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 */
2571 /* preamble 5 bytes, copy this much at least, es info len may be zero */
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 */
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 */
2589 /* no reserved bits stops loop */
2590 fprintf( stdout
, "%s %04X no reserved bits\n",
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);
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);
2618 fprintf( stdout
, "%s %04X chk_crc %08X\n",
2619 __FUNCTION__
, pid
, chk_crc
);
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.
2634 test_pat ( unsigned char *p
)
2638 unsigned char vn
, cni
, sn
, lsn
;
2639 unsigned short tsid
, pgn
, netpid
, pmtpid
, pid
;
2640 unsigned int pat_crc
, pat_crc0
;
2647 if (arg_epn
> 0) keep_pids
[0] = ~0; /* always keep pat */
2649 // point to table id
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",
2657 if ( 0xC0 != (0xC0 & r
[5]) )
2658 mprintf1( stdout
, " PAT reserved bits not set r[5] != C0 is %02X\n",
2661 sl
= ((0xF & r
[1])<<8) | r
[2]; // 12 bit section length
2664 // pat_crc = calc_crc32( r, sl+3 ); // only want crc to validate it
2667 pat_crc0
= calc_crc32( r
, sl
-1 );
2669 /* received CRC32 */
2670 pat_crc
= r
[ sl
- 1 ];
2674 pat_crc
|= r
[ sl
+ 1 ];
2676 pat_crc
|= r
[ sl
+ 2 ];
2678 if (pat_crc
!= pat_crc0
) {
2681 "PAT CRC ERROR PID %04X CALC %08X RCVD %08X\n",
2682 0, pat_crc0
, pat_crc
);
2684 for (i
= 0; i
< 188; i
++) {
2685 if (old_pat
[i
] != p
[i
])
2687 "p[%d] %02X != %02X\n", i
, old_pat
[i
], p
[i
] );
2693 memcpy( old_pat
, p
, 188);
2698 // too short for cable? no is ok for the 16 programs seen in cable
2699 memcpy( pat
.payload
, p
, 188 );
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);
2710 if ( (0 != arg_redux
) && (vn
== pid_vn
[pid
]) ) return;
2713 if (pat_crc
== pat_crc0
) mprintf1( stdout
, "PAT CRC %08X OK", pat_crc
);
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
);
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];
2730 netpid
= 0x1FFF & ( (r
[2]<<8) | r
[3] );
2731 mprintf1( stdout
, " Program %04X Network PID %04X\n",
2733 // don't keep network PID's, they should be obsoleted by now
2735 pmtpid
= 0x1FFF & ( (r
[2]<<8) | r
[3] );
2736 mprintf1( stdout
, " Program %04X PMT PID %04X\n",
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 */
2747 build_new_pat( p
, vcn
);
2751 r
+= 4; // skip to next program number and PID
2754 mprintf1( stdout
, "\n");
2758 //////////////////////////////////////////////////////////////////// MPEG PMT
2759 // payload assembly for PMT, this one is needed for KQED-HD PMT
2762 build_pmt_payload( unsigned char *p
, int pan
)
2764 struct payload_s
*pmp
;
2772 psi
= 1 & ( p
[1] >> 6);
2774 // handle payload start packet by copying start to PMT payload buffer
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];
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");
2798 /* otherwise needs more packets */
2804 // additional non start payloads append to PMT payload buffer
2806 if (0 == pmp
->payoff
) return 1;
2807 memcpy( &pmp
->payload
[pmp
->payoff
], r
, 184);
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");
2820 aprintf6( stdout
, "PMT not parsed\n");
2826 //////////////////////////////////////////////////////////////////// MPEG PMT
2827 // A/65b Table 6.38 Multiple String Structure
2828 // does do huffman decomp
2831 test_pmt_mss( unsigned char *r
)
2833 unsigned int nstr
, nseg
, comp
, mode
, nchr
;
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
));
2842 for (i
= 0; i
< nstr
; i
++) {
2843 memcpy(lang
, &r
[1], 3);
2847 for (j
= 0; j
< nseg
; j
++) {
2851 // mprintf2( stdout, "LEN %02X: ", nchr);
2852 for (k
= 0; k
< nchr
; k
++) {
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
2864 // (mode == 0xFF) && // spec requires, KPXB ignores
2869 huffman_decode( d
, s
, sizeof(d
), nchr
, comp
);
2870 mprintf2( stdout
, "[%s] [%-s] ", lang
, d
);
2872 // show as unknown compress
2874 mprintf2( stdout
, "[%s] [L%02X C%02X M%02X]",
2875 lang
, nchr
, comp
, mode
);
2879 mprintf2( stdout
, "\n");
2883 //////////////////////////////////////////////////////////////////// MPEG PMT
2886 test_pmt_descriptor( unsigned char *r
) {
2889 unsigned short i
, k
;
2894 // r += 2; // bytes start here
2895 // mprintf2( stdout, "desc %s tag# %u len %u\n", t, n, l);
2896 /////////////////////////////////////////////////////////////// MPEG specific
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);
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";
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",
2940 // not likely for terrestrial ATSC but who knows what's on cable
2942 // check reserved bits
2943 if (0x1F == (0x1F & r
[4])) {
2944 unsigned char pli
, cf
, fre
;
2947 fre
= 1 & (r
[4]>>5);
2948 mprintf2( stdout
," MPEG1 Profile and Level %02X Chroma Format %01X Frate Rate Ext %1X",
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]);
2970 mprintf2( stdout
, " add'l id info exists but not parsed\n");
2975 t
= "Stream Alignment";
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",
2992 t
= "Target Background Grid";
2993 break; // write me if needed
2997 break; // write me if needed
3000 t
= "Conditional Access";
3001 if ( 0xE0 == (0xE0 & r
[4] ) ) { // reserved bits check
3002 unsigned short casid
, capid
;
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
3013 mprintf2( stdout
, " CA descriptor private data: "
3015 for ( i
= 0; i
< k
; i
++ ) {
3016 mprintf2( stdout
, "%02X ", r
[i
]);
3018 mprintf2( stdout
, "\n");
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
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 );
3039 mprintf2( stdout
, "[%s] ", lang
);
3041 // mprintf2( stdout, "\n");
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
);
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
;
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",
3073 t
= "Multiplex Buffer Utilization";
3076 unsigned short ltwl
, ltwu
;
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
3092 mprintf2( stdout
, " Legal Time Window Lower Bound %u Upper Bound %u\n",
3100 t
= "Copyright"; // lucky 13?
3104 t
= "Maximum Bitrate";
3105 if ( 0xC0 == (0xC0 & r
[2]) ) {
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
);
3117 t
= "Private Data Indicator";
3120 // smoothing buffer, not in 13818-1 draft 1994 jun 10, but in nov 13
3122 t
= "Smoothing Buffer";
3124 unsigned int sblr
, sbz
;
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",
3140 //////////////////////////////////////////////////////////////// ATSC specific
3142 t
= "SCTE 35 Cue ID";
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");
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
;
3160 src
= 0x07 & (r
[0]>>5);
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";
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
3179 if (0x20 == (0x20 & brc
)) brt1
= "Maximum";
3180 brc
&= 0x1F; // limit it now brt1 has been extracted
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!
3205 if (0 == sm
) smt
= "Not Indicated";
3206 if (1 == sm
) smt
= "NOT Dolby";
3207 if (2 == sm
) smt
= "Dolby";
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";
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
);
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
);
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
;
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);
3268 // don't care about EIA/CEA-608-B. that's NTSC
3269 if ( 0x3E == (0x3E & r
[0]) ) { // reserved
3271 mprintf2( stdout
, " [%s] Type %s Line21 %s Field ",
3272 lang
, cctt
, (l21f
== 0) ? "Even" : " Odd" );
3275 // might be EIA-708-A ATVCC spec, not testing this
3277 mprintf2( stdout
, " [%s] Type %s Service Number %02X ",
3280 if ( (0x3F == (0x3F & r
[1])) && (0xFF == r
[2]) ) {
3282 war
= 1 & (r
[1]>>6);
3283 mprintf2( stdout
, "Easy Reader %u Wide Aspect Ratio %u",
3288 mprintf2( stdout
, "\n");
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
);
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
3309 " Region %u Dimensions %u:%s",
3310 rr
, rd
, (rd
> 1) ? "\n":"");
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
] );
3322 rdl
= r
[0]; // rating descriptor length
3325 mprintf2( stdout
, " Description: ");
3334 t
= "Component Name";
3336 mprintf2( stdout
, " Tag %02X DLen %02X %s: ", n
, k
, t
);
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");
3348 /***************************************************************************/
3350 // handle 0-1, 16-63, 64-255
3352 // these have nothing to parse
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");
3363 /****************************************************************** MPEG PMT */
3367 /***************************************************************** MPEG2 CAT */
3370 test_cat_descriptor( unsigned char *r
)
3374 /***************************************************************** MPEG2 CAT */
3377 test_cat( unsigned char *p
)
3381 unsigned char vn
, cni
, sn
, lsn
;
3382 unsigned int cat_crc
= 0;
3386 // point to table id
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
3404 mprintf1( stdout
, " CAT has CRC error\n");
3408 vn
= 0x1F & (r
[5]>>1);
3413 mprintf1( stdout
, " PID 0001 Conditional Access: SLen %03X VN %02X CNI %01X SN %02X LSN %02X\n",
3414 sl
, vn
, cni
, sn
, lsn
);
3418 if ( r
< (p
+sl
+4) ) {
3419 test_cat_descriptor( r
);
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 */
3431 add_aud_pid( short pid
)
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
] )
3441 // fprintf( stdout, "added aud_pid[%d] %04X\n", aud_pidx, pid);
3442 aud_pids
[ aud_pidx
] = pid
;
3446 /* return zero if pid if on audio list */
3449 test_aud_pid( short pid
)
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);
3460 // fprintf( stdout, "audio pid %04X not found\n", pid);
3464 /* if vpid list has room, add Video PID to list */
3467 add_vid_pid( short pid
)
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
] )
3477 // fprintf( stdout, "added vid_pids[%d] %04X\n", vid_pidx, pid);
3478 vid_pids
[ vid_pidx
] = pid
;
3482 /* return zero if pid is on video list */
3485 test_vid_pid( short pid
)
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);
3495 // fprintf( stdout, "video pid %04X not found\n", pid);
3500 /**************************************************************** MPEG2 PMT */
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
;
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 */
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 */
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 */
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",
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];
3563 pmt_crc0
= calc_crc32( r
, sl
-1 );
3565 /* received CRC32 */
3566 pmt_crc
= r
[ sl
- 1 ];
3570 pmt_crc
|= r
[ sl
+ 1 ];
3572 pmt_crc
|= r
[ sl
+ 2 ];
3574 if (pmt_crc
!= pmt_crc0
) {
3577 "PMT CRC ERROR PID %04X CALC %08X RCVD %08X\n",
3578 pid
, pmt_crc0
, pmt_crc
);
3580 for (i
= 0; i
< 188; i
++) {
3581 if (old_pmt
[i
] != p
[i
])
3583 "p[%d] %02X != %02X\n", i
, old_pmt
[i
], p
[i
] );
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
);
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 */
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
;
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
;
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
;
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 */
3650 mprintf2( stdout
, " Now Tag %02X CRC32 %08X New %08X %s\n",
3651 r1
[0], pmt_crc
, pmt_crc0
, (0 == pmt_crc1
) ? "OK":"BAD" );
3654 test_pmt_descriptor( r
);
3661 memset( apids
, 0, sizeof(apids
));
3663 mprintf2( stdout
, "\n PROGRAM MAP STREAM TYPES AND DESCRIPTORS:\n\n");
3665 b
= pmp
->payload
+ (sl
-1);
3669 /* break out if these reserved bits are not set */
3670 if ( (0xE0 == (0xE0 & r
[1]))
3671 && (0xF0 == (0xF0 & r
[3])) )
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 */
3680 add_vid_pid( espid
); /* counting video separate */
3684 /* check for audio pids against list and add if missing */
3686 add_aud_pid( espid
); /* counting audio separate */
3687 apids
[acn
++] = espid
;
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";
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 */
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 */
3745 /* rebuild PMT for one video one audio */
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
3759 build_audio_payload( unsigned char *p
)
3761 unsigned int psi
, pid
;
3763 // unsigned char afl;
3764 unsigned char *r
, pl
;
3765 // unsigned char i, j;
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
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!
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
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
) {
3794 ok
= write_buffer(es_buf
, r
, pl
); /* fast */
3796 ok
= write(out_file
, r
, pl
);
3799 /* writes should always pass */
3801 fprintf(stdout
, "%s ES write %s failed\n", WHO
, es_name
);
3811 // only if no continuity counter error
3812 if (0 == pid_cc
[ pid
])
3815 " DONE A/52 Audio PID %04X Payload %05X bytes\n",
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
3824 mprintf6( stdout
, " *DROP previous discontinuous A/52 payload\n");
3828 mprintf6( stdout
, " START A/52 Audio PID %04X Payload\n", pid
);
3831 memset( aud
.payload
, 0, sizeof(aud
.payload
) );
3832 memcpy( aud
.payload
, r
, pl
);
3835 if (0 == aud
.payoff
) {
3836 mprintf6( stdout
, " *DROP A/52 Audio PID %04X w/o psi\n", pid
);
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
) );
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
);
3851 " COPY A/52 Audio PID %04X Payload offset %05X\n",
3857 " *DROP A/52 Audio PID %04X continuity error\n", pid
);
3866 /**************************************************************** A/52 Audio */
3867 /*no afc on these, should be PES AC-3 only. could extract by itself. */
3870 test_a52_audio( unsigned char *p
)
3874 pkt
.aud
++; // total audio, have to use pid lut for individual audio
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
3883 build_audio_payload( p
);
3887 /****************************************************************************/
3890 /**************************************************************** MPEG2 Video */
3891 /* build video payload adjusts for AFC at start of payload */
3894 build_video_payload( unsigned char *p
)
3897 unsigned int psi
, pid
, afc
, afl
;
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
3909 fprintf( stdout
, "\n PSI ");
3910 for( i
= 0 ; i
< 20; i
++) fprintf( stdout
, "%02X ", p
[i
] );
3911 fprintf( stdout
, "AFC%d\n", afc
);
3915 r
= p
+4; // skip transport header
3917 /* AFC can occur in the middle of any payload? */
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
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
) {
3935 ok
= write_buffer(es_buf
, r
, pl
);
3937 ok
= write(es_file
, r
, pl
);
3940 /* writes should always pass */
3942 fprintf(stdout
, "%s ES write %s failed\n", WHO
, es_name
);
3948 /* payload start indicator set */
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 */
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
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();
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
);
3992 // clear it so zero detect works
3993 memset( vid
.payload
, 0, sizeof(vid
.payload
) );
3994 memcpy( vid
.payload
, r
, pl
);
3997 // payload start indicator not set
3998 if (0 == vid
.payoff
) {
3999 mprintf6( stdout
, " *DROP MPEG Video PID %04X w/o psi\n", pid
);
4002 if ( (vid
.payoff
+pl
) >= sizeof(vid
.payload
) ) {
4004 "\n MPEG PID %04X payoff %d is over %d bytes\n",
4005 pid
, vid
.payoff
+pl
, sizeof( vid
.payload
) );
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
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 ] )
4024 memcpy( &vid
.payload
[ vid
.payoff
], r
, pl
);
4026 " COPY MPEG Video PID %04X Payload offset %05X %s\n",
4027 pid
, vid
.payoff
, (j
==0)?"ZERO":"");
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 */
4054 test_mpeg2_video ( unsigned char *p
)
4058 psi
= 1 & (p
[1]>>6);
4062 // if (0 != arg_redux) return;
4065 if (0 == pkt
.pmt
) /* wait until first PMT for this program */
4068 if (0 != arg_espid
) {
4069 build_video_payload( p
);
4072 /* -s option needs to generate sequence byte offset and picture type if psi */
4073 if (0 != arg_seqwr
) {
4075 build_video_payload( p
);
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 /****************************************************************************/
4089 find_pa_pid( unsigned int pid
)
4092 for (i
= 0; i
< pat_ncs
; i
++)
4093 if (pid
== pa
[i
].pmtpid
)
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
4106 test_mpeg2_packet( unsigned char *p
)
4108 unsigned int psi
, pid
, afc
;
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
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?
4123 test_pat( p
); // crc check at least
4127 // Conditional Access Table, could be multiple packet?
4129 test_cat( p
); // crc check at least
4133 /* is the pmt on the pa list? will force pmt parse to after first PAT */
4134 pan
= find_pa_pid( pid
);
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
))
4149 if (0 == test_vid_pid( pid
)) {
4150 test_mpeg2_video( p
);
4152 if (0 == test_aud_pid( pid
)) {
4153 test_a52_audio( p
);
4158 return; // match returns
4160 //////////////////////////////////////////////////////////////////// MPEG2 PES
4164 /////////////////////////////////////////////////////////////////////// VCT
4166 // A/65b Table 6.29 Service Location Descriptor
4169 test_vct_svloc( unsigned char *r
)
4171 unsigned short pcpid
;
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
);
4181 for (i
= 0; i
< nelm
; i
++) {
4182 if (0xE0 == (0xE0 & r
[1])) {
4183 unsigned short epid
;
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
4194 memcpy( lang
, 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
4202 " Stream Type (%02X) %s ES PID %04X [%s]\n",
4203 strt
, strx
, epid
, lang
);
4211 // A/65b Table 6.38 Multiple String Structure
4212 // does do huffman decomp
4215 test_vct_mss( unsigned char *r
)
4217 unsigned int nstr
, nseg
, comp
, mode
, nchr
;
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
));
4227 nstr
= 1; /* force to one */
4228 for (i
= 0; i
< nstr
; i
++) {
4229 memcpy(lang
, &r
[1], 3);
4234 nseg
= 1; /* force to one */
4235 for (j
= 0; j
< nseg
; j
++) {
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
4248 // (mode == 0xFF) && // spec requires, KPXB ignores
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
4269 test_vct_descriptor( unsigned char *p
, unsigned int len
)
4271 unsigned char dtag
, dlen
;
4272 unsigned char *r
, *t
;
4283 // aprintf2( stdout, " VCT DESCRIPTORS:\n");
4286 // extended channel name descriptor is mulitple string structure
4288 t
= "Extended Channel Name:\n ";
4289 aprintf2( stdout
, " VCT Tag %02X DLen %02X %s", dtag
, dlen
, t
);
4293 // service location descriptor
4295 t
= "Service Location";
4296 aprintf2( stdout
, " VCT Tag %02X DLen %02X %s: ", dtag
, dlen
, t
);
4300 // time shifted service descriptor
4302 t
= "Time Shifted Service";
4303 aprintf2( stdout
, " VCT Tag %02X DLen %02X %s: ", dtag
, dlen
, t
);
4306 // got some weird ones showing up here need to parse?
4309 aprintf2( stdout
, " VCT *Tag %02X DLen %02X: %s\n", dtag
, dlen
, t
);
4318 // not going to implement. verify top bits and count only
4321 test_dccsct( unsigned char *p
)
4327 // not going to implement. verify top bits and count only
4330 test_dcct( unsigned char *p
)
4338 // A/65b Table 6.38 Multiple String Structure
4339 // does do huffman decomp
4342 test_rrt_mss( unsigned char *r
)
4344 unsigned int nstr
, nseg
, comp
, mode
, nchr
;
4346 unsigned char lang
[4];
4347 unsigned char s
[256];
4348 unsigned char d
[512];
4350 memset( s
, 0, sizeof(s
));
4352 for (i
= 0; i
< nstr
; i
++) {
4353 memcpy(lang
, &r
[1], 3);
4357 for (j
= 0; j
< nseg
; j
++) {
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
4370 // (mode == 0xFF) && // spec requires, KPXB ignores
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
4390 build_rrt_payload( unsigned char *p
)
4398 psi
= 1 & ( p
[1] >> 6);
4400 // handle payload start packet by copying start to RRT payload buffer
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];
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");
4429 // additional non start payloads append to RRT payload buffer
4431 memcpy( &rrt
.payload
[rrt
.payoff
], r
, 184);
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");
4444 aprintf6( stdout
, "RRT not parsed\n");
4450 // Content Advisory description text in EIT makes this redundant.
4451 // but has to be parsed for completeness for stations w/o description
4454 test_rrt( unsigned char *p
)
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
) {
4467 if ((0xCA != r
[0]) || (0xFF != r
[3]) ) {
4468 aprintf5( stdout
, " RRT has bad TT/RB\n");
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
4478 aprintf5( stdout
, " RRT CRC ERROR\n");
4479 //rrt_crc, r[sl], r[sl+1], r[sl+2], r[sl+3]);
4483 aprintf5( stdout
, "RRT CRC OK\n");
4484 vn
= 0x1F & (r
[5]>>1);
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: ");
4500 aprintf5( stdout
, "\n");
4507 for (i
= 0; i
< dd
; i
++) {
4510 aprintf5( stdout
, " Dimension Index %d Name: ", i
);
4512 aprintf5( stdout
, "\n");
4514 if (0xE0 == (0xE0 & r
[0])) {
4515 gs
= 1 & (r
[0] >> 4);
4518 aprintf5( stdout
, " %sRating Values %d:\n",
4519 ( 0 == gs
) ? "":"Graduated ", vd
);
4520 for (j
= 0; j
< vd
; j
++) {
4523 aprintf5( stdout
, " Index %d ", j
);
4524 // abbreviated rating values
4529 aprintf5( stdout
, "\t");
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 */
4554 /* look up vc# 0-n by program number */
4557 find_vc_pgm( unsigned short pn
)
4560 if (vct_ncs
< 1) return -1;
4562 for (i
=0; i
< vct_ncs
; i
++)
4563 if (pn
== vc
[i
].pgm
)
4569 /* Return VC index 0-n from source id (top 16 bits of ETMID), or return -1. */
4572 find_vc_src( unsigned short sr
)
4575 if (vct_ncs
< 1) return -1;
4577 for (i
=0; i
< vct_ncs
; i
++)
4578 if (sr
== vc
[i
].src
)
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.
4590 find_pgm_etmid( unsigned int etmid
)
4592 int i
, j
, z
, vcn
, sr
;
4595 vcn
= find_vc_src( sr
);
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
;
4607 /* A/65b Table 6.38 Multiple String Structure */
4608 /* does do huffman decomp */
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 */
4621 nstr
= 1; /* override */
4623 sr
= 0x7 & (etmid
>>16);
4627 for (i
= 0; i
< nstr
; i
++) {
4628 memcpy(lang
, &r
[1], 3);
4633 nseg
= 1; /* override */
4635 for (j
= 0; j
< nseg
; j
++) {
4644 /* each seg n has chars n */
4645 memset( s
, 0, PDZ
); /* clear old */
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 */
4662 /* (mode == 0xFF) && spec requires, KPXB ignores */
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 */
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 */
4681 "\n *ignored ETT-%02X ETMID %08X, no EIT pgm[] match",
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 */
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 */
4705 build_ett_payload( unsigned char *p
, unsigned int n
)
4707 unsigned int psi
, tei
;
4710 psi
= 1 & (p
[1]>>6);
4711 tei
= 1 & (p
[1]>>7);
4712 if (tei
!= 0) return 1;
4715 /* handle payload start packet by copying start to ETT payload buffer */
4717 /* ett[n].payoff = 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);
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
);
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
);
4758 aprintf6( stdout
, " ETT-%02X not parsed\n", n
);
4763 /* process ett packet based on payload start indicator */
4766 test_ett ( unsigned char *p
, unsigned int n
)
4769 unsigned short sl
, etidx
, sr
;
4770 unsigned char vn
, cni
, sn
, lsn
, pv
;
4772 unsigned int ett_crc
= 0;
4776 p.1 is 3 bits tei psi pri, 5 high bits pid
4777 p.2 is 8 bits low bits pid
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;
4789 aprintf4( stdout
, " Table ID not ETT 0xCC but 0x%02X\n", r
[0]);
4793 sl
= ((0xF & r
[1])<<8) | r
[2]; /* section len */
4794 ett_crc
= calc_crc32( r
, sl
+3); /* crc check */
4797 aprintf4( stdout
, " ETT-%02X CRC ERROR\n", n
);
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
4814 "\n ETT-%02X table id extension %04X is not 0\n", n, etidx);
4819 vn
= (0x3E & r
[5]) >> 1;
4825 etmid
= (r
[9]<<24) | (r
[10]<<16) | (r
[11]<<8) | r
[12];
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
);
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");
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 */
4868 test_eit_rr_mss ( unsigned char *r
)
4870 unsigned int nstr
, nseg
, comp
, mode
, nchr
;
4872 unsigned char lang
[4];
4873 unsigned char s
[256];
4874 unsigned char d
[512];
4875 /* unsigned char *t; */
4878 // aprintf3( stdout, "%s nstr %d\n", __FUNCTION__, nstr); // debug
4880 /* ATSC constrained to 1 string, 1 segment */
4882 for (i
= 0; i
< nstr
; i
++) {
4883 memcpy(lang
, &r
[1], 3);
4890 /* ATSC constrained to 1 string, 1 segment */
4892 for (j
= 0; j
< nseg
; j
++) {
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))
4907 /* show non-compressed */
4908 if ( (0 == comp
) && (0 == mode
) ) {
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) */
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 */
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 */
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 */
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
;
4948 unsigned char lang
[4];
4949 unsigned char s
[PNZ
*2];
4950 unsigned char d
[PNZ
];
4953 memset( s
, 0, sizeof(s
));
4955 for (i
= 0; i
< nstr
; i
++) {
4956 memcpy(lang
, &r
[1], 3);
4961 for (j
= 0; j
< nseg
; j
++) {
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))
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 ",
4983 aprintf3( stdout
, "[L%02X C%02X M%02X] ",
4988 /* show non-compressed */
4989 if ( (0 == comp
) && (0 == mode
) ) {
4990 aprintf3( stdout
, "[%s]\n [%-s] ", lang
, s
);
4993 /* show huffman compressed */
4995 /* (mode == 0xFF) && spec requires, KPXB ignores */
5001 huffman_decode( d
, s
, sizeof(d
), nchr
, comp
);
5002 aprintf3( stdout
, "[%s] Huffman\n [%-s] ", lang
, d
);
5004 /* show as unknown compress */
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 */
5022 aprintf3( stdout
, "\n");
5026 /* r points to start of descriptors */
5027 /* do until len exhausted */
5030 test_eit_descriptors( unsigned char *p
, unsigned int len
)
5032 unsigned char *q
, *r
, *t
;
5033 unsigned char n
, l
, i
, j
;
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;
5050 while ( dlen
> 2 ) {
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]);
5065 " add'l reg info exists but not parsed\n");
5066 aprintf3( stdout
, "\n");
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");
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.
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);
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 */
5113 if (0x20 == (0x20 & brc
)) brt1
= "Maximum";
5114 brc
&= 0x1F; /* limit it now brt1 has been extracted */
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! */
5138 if (0 == sm
) smt
= "Not Indicated";
5139 if (1 == sm
) smt
= "NOT Dolby";
5140 if (2 == sm
) smt
= "Dolby";
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";
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";
5173 " EIT Tag %02X DLen %02X %s: Sample Rate %s, "
5174 "bsid %02X langcod %02X\n",
5175 n
, l
, t
, srt
, bsid
, lc
);
5177 " %s Bit Rate %s (%02X) Surround %s (%02X)\n",
5178 brt1
, brt
, brc
, smt
, sm
);
5180 " Service %s (%d), Channels %s%s (%d), Full Service %u\n",
5181 bsmt
, bsm
, nct
, lft
, nc
, fs
);
5183 aprintf3( stdout
, "\n");
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];
5195 aprintf3(stdout
," EIT Tag %02X DLen %02X %s: ",n
, l
, t
);
5196 nos
= 0x1F & q
[0]; /* number of services */
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
;
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); */
5210 /* don't care about EIA/CEA-608-B. that's NTSC */
5212 if ( 0x3E == (0x3E & q
[0]) ) { /* reserved */
5215 " [%s] Type %s Line21 %s Field ",
5217 (l21f
== 0) ? "Even" : " Odd" );
5220 /* might be EIA-708-A ATVCC spec, not testing */
5221 csn
= 0x3F & q
[0]; /* caption svc number */
5223 " [%s] Type %s Service Number %02X ",
5226 if ( (0x3F == (0x3F & q
[1])) && (0xFF == q
[2]) ) {
5228 war
= 1 & (q
[1]>>6);
5230 "Easy Reader %u Wide Aspect Ratio %u",
5234 // q += 3; /* was here but may be wrong */
5236 aprintf3( stdout
, "\n");
5238 aprintf3( stdout
, "\n");
5243 t
= "Content Advisory";
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
);
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 */
5257 /* one dimension will try to print on one line */
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 */
5267 aprintf3( stdout
, " Dimension j %u Value %u Abbrev [%s]\n",
5268 rdj
, rv
, ratings
[ (rdj
* 10) + rv
+ 1] );
5274 /* need at least 8 bytes of header for 1 byte string */
5277 aprintf3( stdout
, " mss dlen %d: ",
5279 test_eit_rr_mss( q
);
5282 aprintf3( stdout
, "\n");
5286 /* this one was struck down by the judge, but some stations still sending it */
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");
5294 /* needs parsing if shows up here */
5296 aprintf3( stdout
, " EIT *Tag %02X len %02X ignored\n", n
, l
);
5297 aprintf3( stdout
, "\n");
5308 /* add to eit payload. returns 0 if done, or 1 if not done */
5311 build_eit_payload( unsigned char *p
, unsigned int n
)
5316 psi
= 1 & (p
[1]>>6);
5319 /* handle payload start packet by copying start to EIT payload buffer */
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;
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
);
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
);
5366 aprintf6( stdout
, " *ignored*\n");
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[]
5376 sort_eit_pgm( unsigned int pgo
, unsigned int nev
) {
5377 unsigned int i
, j
, a
, b
;
5380 // fprintf( stdout, "%s %u %u\n", __FUNCTION__, pgo & 0x1FF8, nev);
5382 /* only sorting 8, at offset pgo & ~8 */
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 */
5412 test_eit ( unsigned char *p
, unsigned int n
)
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 */
5425 p.1 is 3 bits tei psi pri, 5 high bits pid
5426 p.2 is 8 bits low bits pid
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;
5440 aprintf3( stdout
, " EIT-%02X bad table type %02X\n", n
, r
[0]);
5444 sl
= ((0xF & r
[1])<<8) | r
[2]; /* section length */
5446 eit_crc
= calc_crc32( r
, sl
+3 );
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]);
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
);
5462 /* holds down EIT display until VCT seen */
5463 if (vcn
< 0) return;
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
);
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 */
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 */
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 */
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];
5524 /* recalibrate for unix time */
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 */
5538 /* make index match atscap epg [n] key numbers */
5540 pgo
= (so
<<10) | (n
<<3) | (7 & i
);
5541 /* KPXB fix for their stupid idiotic source numbers above 8 */
5544 pgo
= (vcn
<<10) | (n
<<3) | (7 &i
);
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
);
5561 if ( 0xF0 == (0xF0 & r
[0]) )
5565 dlen
= ((0xF & r
[0])<<8) | r
[1];
5567 test_eit_descriptors( 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 */
5587 test_channel_ett_mss( unsigned char *r
)
5589 unsigned int nstr
, nseg
, comp
, mode
, nchr
;
5591 unsigned char lang
[4];
5592 unsigned char s
[512];
5594 memset( s
, 0, sizeof(s
));
5597 nstr
= 1; /* force to one */
5598 for (i
= 0; i
< nstr
; i
++) {
5599 memcpy(lang
, &r
[1], 3);
5604 nseg
= 1; /* force to one */
5605 for (j
= 0; j
< nseg
; j
++) {
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
);
5615 aprintf8( stdout
, "[%s] [*COMPRESSED*]\n", lang
);
5623 test_channel_ett( unsigned char *p
)
5625 unsigned int sl
, idx
, vn
, etmid
;
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];
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
5652 build_vct_payload( unsigned char *p
)
5655 unsigned char psi
, vn
;
5659 psi
= 1 & ( p
[1] >> 6);
5660 // handle payload start packet by copying start to VCT payload buffer
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);
5671 vct
.sl
= ((0xF & r
[1])<<8) | r
[2];
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");
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);
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");
5706 aprintf6( stdout
, " VCT not parsed\n");
5713 /**************************************** Terrestrial Virtual Channel Table */
5714 /* This gives information on which PIDs are in use for this Channel */
5717 test_tvct ( unsigned char *p
)
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" );
5743 /* r = p + 5; / * still have to check sl */
5745 sl
= ((0xF & r
[1]) <<8) | r
[2]; /* section length may not be > 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 );
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 */
5768 return; /* don't update until vn changes */
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 */
5779 aprintf2( stdout
, "TVCT Protocol not 0\n");
5780 return; /* only protocol 0 */
5782 ncs
= r
[9]; /* number of channels in section */
5786 aprintf2( stdout
, "TVCT NCS limit exceeded, %d\n", ncs
);
5787 return; /* sanity limit do not process further */
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
] = ' ';
5812 vc
[i
].major
= ((0xF & r
[0]) << 6) | ((0xFC & r
[1]) >> 2);
5813 vc
[i
].minor
= ((0x3 & r
[1]) << 8) | r
[2];
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
);
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);
5840 strncpy( t
, "DISABLED", sizeof(t
)-1);
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
);
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];
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. */
5891 test_cvct( unsigned char *p
)
5894 unsigned short sl
, tsi
, adl
;
5895 unsigned char vn
, cni
, sn
, lsn
, pv
, ncs
, i
, j
;
5898 "Rsvd", "NTSC TV", "ATSC DTV", "ATSC Audio", "ATSC Data"
5900 /* modulation modes */
5902 "Rsvd", "Analog", "QAM64", "QAM256", "VSB8", "VSB16"
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" );
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
);
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 );
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 */
5952 return; /* don't update until vn changes */
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 */
5961 aprintf2( stdout
, "CVCT Protocol not 0\n");
5962 return; /* only protocol 0 */
5964 ncs
= r
[9]; /* number of channels in section */
5967 aprintf2( stdout
, "CVCT NCS limit exceeded, %d\n", ncs
);
5968 return; /* sanity limit do not process further */
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];
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]);
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
] = ' ';
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? */
6003 if (0x3F0 == (0x3F0 & vc
[i
].major
)) {
6004 opn
= (0x0F & vc
[i
].major
) << 10;
6006 fprintf(stdout
, "OPN %d\n", vc
[i
].minor
);
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
);
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);
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;
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
);
6057 aprintf2( stdout
, "M.n %d.%d\n", vc
[i
].major
, vc
[i
].minor
);
6061 " Modulation %s (%d) Symbol Rate %d Frequency %d\n",
6062 mt
[vc
[i
].mode
], vc
[i
].mode
, msr
, vc
[i
].freq
);
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
);
6067 " Access Control %d Hidden %d Hide Guide %d\n",
6068 vc
[i
].actrl
, vc
[i
].hide
, vc
[i
].hideg
);
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
);
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];
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 */
6112 build_mgt_payload( unsigned char *p
)
6115 unsigned char psi
; /*, vn; */
6119 psi
= 1 & ( p
[1] >> 6);
6121 /* handle payload start packet by copying start to MGT payload buffer */
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);
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");
6151 // additional non start packet payloads append to MGT payload buffer
6153 memcpy( &mgt
.payload
[mgt
.payoff
], r
, 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");
6164 aprintf1( stdout
, " MGT not parsed\n");
6171 test_mgt ( unsigned char *p
)
6173 unsigned short sl
, tidx
, td
, dl
, i
; /* j; */
6174 unsigned char vn
, cni
, sn
, lsn
, pv
;
6177 // fprintf(stdout, "MGT\n");
6179 mgt
.payok
= build_mgt_payload( p
);
6180 if (0 != mgt
.payok
) return;
6182 // fprintf(stdout, "MGT OK\n");
6186 aprintf1( stdout
, "table id not MGT 0xC7 but 0x%02X\n", r
[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 */
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 */
6204 aprintf1(stdout
, "MGT SLen > 4093\n");
6205 return; /* if sl > 4093, ignore packet */
6207 mgt_crc
= calc_crc32( r
, sl
+3);
6211 aprintf1( stdout
, "MGT CRC32 ERROR\n");
6217 tidx
= (r
[3]<<8) | r
[4];
6219 vn
= (0x3E & r
[5]) >> 1; /* 5 bit version number */
6224 return; /* don't update until vn changes */
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 */
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
) );
6254 for (i
=0; i
<td
; i
++)
6256 if ( ( 0xE0 == (0xE0 & r
[2]))
6257 && ( 0xE0 == (0xE0 & r
[4]))
6258 && ( 0xF0 == (0xF0 & r
[9]))
6262 unsigned short ttpid
;
6265 unsigned short ttdl
;
6266 unsigned char tx
[8];
6268 tt
= (r
[0]<<8) | r
[1];
6269 ttpid
= ((0x1F & r
[2])<<8) | r
[3];
6271 nb
= (r
[5]<<24) | (r
[6]<<16) | (r
[7]<<8) | r
[8];
6272 ttdl
= ((0xF & r
[9])<<8) | r
[10];
6275 /* 0000-1FFF table types EIT 100-17F ETT 200-27F,
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 */
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);
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);
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];
6321 aprintf1( stdout
, " Additional Descriptor Len %03X\n", dl
);
6323 /* spec indicates it should be one descriptor only, no additional */
6325 for (j
=0; j
<dl
; j
++) {
6326 test_mgt_descriptor( r
, dl
);
6330 aprintf1( stdout
, "\n");
6333 /* return -1 if pid is not in mgt_tt_pid table, else return index */
6336 test_mgt_tt_pid( unsigned int pid
)
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
;
6347 /* packets that match MGT table */
6350 test_mgt_tt_packet( unsigned char *p
, unsigned int pid
)
6352 int ttidx
, ttpid
, tt
;
6354 ttidx
= test_mgt_tt_pid( pid
);
6356 aprintf1( stdout
, "PID %04X table not found in MGT\n", pid
);
6357 return; // no match found
6360 ttpid
= 0x1FFF & mg
[ ttidx
].ttpid
; /* pid ranges len coincidental to */
6361 tt
= 0x1FFF & mg
[ ttidx
].tt
; /* table ranges. dont get confused */
6364 dprintf6( stdout
, " PID %04X Table Type %04X Terrestrial VCT CNI1\n", ttpid
, tt
);
6368 dprintf6( stdout
, " PID %04X Table Type %04X Terrestrial VCT CNI0\n", ttpid
, tt
);
6372 dprintf6( stdout
, " PID %04X Table Type %04X Cable VCT CNI1\n", ttpid
, tt
);
6376 dprintf6( stdout
, " PID %04X Table Type %04X Cable VCT CNI0\n", ttpid
, tt
);
6380 dprintf6( stdout
, " PID %04X Table Type %04X Channel ETT ", ttpid
, tt
);
6381 test_channel_ett( p
);
6385 dprintf6( stdout
, " PID %04X Table Type %04X DCCSCT\n", ttpid
, tt
);
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 );
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
);
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);
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);
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 */
6425 test_stt ( unsigned char *p
)
6427 static unsigned int stt_prev
;
6429 char e
= ' '; /* error flag */
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 );
6449 aprintf0( stdout
, "STT CRC ERROR\n");
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
;
6464 /* DST ctl reserved bits not set */
6469 /* GPS UTC offset correction, Bureau of Standards sets + / - */
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
;
6481 /* fill stt_tm structure with corrected time */
6482 /* FIXME: DST not handled yet? */
6483 localtime_r( &stt
.st
, &stt_tm
);
6487 /* ouput redux, but actually want this one as speedometer */
6488 /* if (0 == (stt.st % 60)) */
6489 /* if (stt_prev != stt.st) */
6492 struct tm lt
; /* local time */
6493 char ds1
[32]; /* date string */
6497 localtime_r( &tt
, <
);
6498 asctime_r( &stt_tm
, stt_text
);
6499 asctime_r( &stt_tm
, ds1
);
6500 asctime_r( <
, ds2
);
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,
6511 e
, stt
.guo
, stt
.ds
, stt
.dss
, stt
.dsd
, stt
.dsh
);
6516 /* aprintf0( stdout, "\n"); */
6519 /* handle PID 1FFB, single or multi-packet payload */
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]);
6530 // payload start indicator?
6533 // pkt.atsctid = p[5]; // save last tid that got payload unit start bit
6534 // switch( pkt.atsctid ) {
6536 switch( psit
[ pid
] ) {
6566 aprintf0( stdout
, " unknown ATSC table id %02X*\n", p
[5]);
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.
6578 // switch( pkt.atsctid ) {
6579 switch( psit
[ pid
] ) {
6610 test_packet( unsigned char *p
)
6612 unsigned int tei
, psi
, pid
, pri
, cc
, tsc
, afc
, tid
, i
;
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
;
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
);
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
6649 if (0 != *arg_newpat
) {
6651 memcpy( p
, newpat
, 188 );
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
6665 dprintf4(stdout
, "PKT # %8u TEI\n", pkt
.count
);
6669 // ignore scramble control non zero packets
6673 dprintf4(stdout
, "PKT # %8u scramble bits = %u\n", pkt
.count
, tsc
);
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
]) {
6682 // cc doesnt change for afc 2
6683 if (cc
!= last_cc
[ pid
]) {
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))) {
6706 last_cc
[ pid
] = cc
; // for next time thru
6708 pids
[pid
]++; // count pid's of good non null packets
6711 if (arg_pids
!= 0) {
6713 if (0 != keep_pids
[pid
]) {
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) {
6722 if (0 != arg_nulls
) keep_pids
[pid
] = ~0;
6726 /* + means on PID list, - is not on list, # is not checking */
6727 /* also masking START NO unless -v bit 4 (16 val) set */
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");
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
6750 if (pid
== 0x1FFB) { // handle 1FFB PID PSIP types
6751 test_atsc_packet( p
); // handles MGT TVCT STT, not RRT CVCT
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:
6766 if (0 != keep_pids
[pid
]) /* in the lookup table? */
6768 write_buffer( out_buf
, p
, TSPZ
);
6770 write( out_file
, p
, TSPZ
);
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");
6791 fprintf( stdout
, "Extracting Frames to %sx\n",
6794 fprintf( stdout
, "Extracting PIDS for MPEG Program number %d\n",
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");
6816 len
= read_buffer( in_buf
, ts_buf
, TSPZ
);
6818 len
= read( in_file
, ts_buf
, TSPZ
);
6821 fprintf(stdout
, "Could not read %s\n", in_name
);
6826 fprintf( stdout
, "EOF\n");
6832 /* packet traffic director */
6833 test_packet( ts_buf
);
6836 /* Could use as a packet hash for unique ID but has multiple solutions. */
6837 /* Perhaps could be useful for future stream-restoration project. */
6839 crc
= calc_crc32( ts_buf
, TSPZ
);
6840 fprintf( stdout
, "%08X\n", crc
);
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
6857 struct tm as
= {0,0,0,6,0,80,0,0,0}; // Jan 6, 1980 00:00:00 UTC
6859 unsigned char d
[32];
6861 utd
= (unsigned int)mktime( &as
);
6862 snprintf( d
, sizeof(d
)-1, "%s", asctime(localtime( &utd
)) );
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
;
6875 parse_args( int argc
, char **argv
)
6879 int arg_idx
; // copy of argc, decremented
6881 int sr
, ok
; // stat returns
6882 int adump
, mdump
, vdump
;
6883 char inz
[32], inp
[32];
6888 arg_adump
= arg_mdump
= arg_verbose
= 0;
6891 fprintf(stdout
, usage
, argv
[0]);
6895 while ((c
= getopt( argc
, argv
, "cfghnqs" "a:d:e:k:m:o:p:r:v:y:")) != EOF
)
6904 arg_forge
= ~arg_forge
;
6908 arg_redux
= ~arg_redux
;
6914 sscanf( optarg
, "%s", arg_newpat
);
6915 npf
= open( arg_newpat
, RD_MODE
);
6917 ok
= read( npf
, newpat
, 188);
6919 fprintf(stderr
, "%s < 188 bytes\n", optarg
);
6933 fprintf(stdout
, usage
, argv
[0]);
6938 arg_guide
= ~arg_guide
;
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 */
6959 sscanf( optarg
, "%x", &arg_espid
);
6960 arg_espid
&= 0x1FFF;
6961 fprintf( stdout
, "Extracting ES PID %04X\n", arg_espid
);
6964 // duty cycle from 1 to 100
6966 sscanf( optarg
, "%d", &arg_duty
);
6967 if (arg_duty
< 1) arg_duty
= 1;
6968 if (arg_duty
> 100) arg_duty
= 100;
6971 // ATSC detail level
6974 if (NULL
!= optarg
) adump
= atoi( optarg
);
6978 // MPEG detail level
6981 if (NULL
!= optarg
) mdump
= atoi( optarg
);
6985 // verbose and packet assembly detail level
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
;
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
6998 if (optarg
!= NULL
) {
7002 // -k mgt option to keep all ATSC Master Guide
7003 if ( 0 == strncasecmp(optarg
, "mgt", strlen(optarg
)) ) {
7006 sscanf( optarg
, "%x", &pid
);
7007 // fprintf( stdout, "-k %d option\n", pid);
7008 keep_pids
[ 0x1FFF & pid
] = ~0;
7014 if (optarg
!= NULL
) {
7015 snprintf( arg_name
, sizeof(arg_name
)-1, "%s", optarg
);
7017 /* null extraction needs to trigger file write somehow */
7022 /* output path, tests for IFDIR */
7024 if (optarg
!= NULL
) {
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
);
7037 snprintf( out_path
, sizeof(out_path
)-1, "%s", arg_path
);
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]);
7067 fprintf( stderr
, "\nMissing a parameter? See %s -h\n\n", argv
[0]);
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
);
7079 fprintf( stderr
, "%s ", in_name
);
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
);
7094 fprintf( stderr
, "\nerror opening file %s: ", in_name
);
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
);
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 */
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 */
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 */
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
);
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
);
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
);
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
);
7177 fprintf( stdout
, "PID %04X ES output to %s\n", arg_espid
, es_name
);
7184 // xenoterms word wrapper, could be used for long description display...
7187 word_wrap_tab( unsigned char *s
, int cl
)
7190 unsigned char tab
[80];
7192 int ts
, ns
, cc
, cl
, i
, len
;
7196 t
= strchr( s
, '|'); // first | is tab stop
7197 if (t
!= NULL
) ts
= t
- s
;
7198 memset( tab
, 0, sizeof(tab
));
7200 memset( tab
, ' ', ts
);
7202 fprintf( stdout
, "\n");
7203 for (i
= 0; i
< len
; i
++) {
7204 // if this char not a space, find next space
7206 t
= strchr( &s
[i
], ' ');
7211 fprintf( stdout
, "\n%s", tab
);
7216 fprintf( stdout
, "%c", s
[i
]);
7229 // first make pg list of unsorted entries and count pgm_idx
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
);
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?
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
) {
7246 pg
[j
] = pg
[i
]; // old sort of sort
7247 pg
[i
] = k
; // do not need anything faster
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",
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 */
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
);
7280 short pn
, sr
, ap
; // atsc program number lookup from source id
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;
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
);
7301 " pg ETMID Pgm# Date Time Len Name"
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
++) {
7309 if (0xFFFF == k
) continue; /* skip removed */
7310 if (0 == pgm
[k
].etmid
) continue; /* skip empty */
7314 // only bother with pgm entry if etmid set
7315 // if (0 != pgm[k].etmid)
7319 sr
= pgm
[k
].etmid
>>16;
7320 ap
= find_vc_src( sr
);
7326 localtime_r( &st
, &stm
);
7327 asctime_r( &stm
, d
);
7331 if (strlen(pgm
[k
].name
) > 30) {
7332 pgm
[k
].name
[30]='>';
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,
7359 // if (strlen(s) > 78) {
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
;
7379 unsigned char p1
[32], p2
[32], p3
[32];
7383 // sum up transport errors
7384 pkt
.errors
= pkt
.errsyn
+ pkt
.errtei
+ pkt
.errscr
+ pkt
.errcce
;
7386 pkt
.errors
+= pkt
.crcstt
+ pkt
.crcmgt
+ pkt
.crctvct
+ pkt
.crceit
7387 + pkt
.crcett
+ pkt
.crcrrt
+ pkt
.crcdcct
+ pkt
.crcdccsct
;
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
]);
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
]);
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
;
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
;
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:");
7461 for (i
= 0; i
< 0x1000; i
++) {
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; }
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
) {
7479 fprintf( stdout
, "ATSC PID counts:\n");
7480 for (i
= 0x1000; i
< 0x1FFF; i
++) {
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; }
7489 fprintf(stdout
, "%s%04X #%9d", s
, i
, pids
[i
]);
7492 fprintf( stdout
, "\n");
7493 fprintf( stdout
, "ATSC PID total: %8d\n\n", k
);
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.
7506 dump_sequences( void )
7508 unsigned char n
[256];
7509 unsigned char o
[256];
7512 long long m1
= -1LL;
7516 if (0 == arg_seqwr
) return;
7517 // if (0 == arg_write) return;
7518 if (0 == frame_idx
) return;
7519 if (0 == sequence_idx
) return;
7522 filebase( n
, in_name
, F_PFILE
);
7524 snprintf( o
, sizeof(o
), "%s.tsx", n
);
7528 fprintf( stderr
, "error opening %s ", o
);
7530 /* error on open returns */
7534 // fprintf( stdout, "writing sequence indices to %s\n", o);
7537 /* terminate list with -1LL */
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 );
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
);
7566 dump_elapsed( void )
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
;
7585 lltoasc( bt
, bytes_total
);
7587 fprintf( stdout
, "\n");
7589 "processed %s bytes in %.2f seconds, %.2f MB/s\n",
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) {
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;
7609 "ATSC Stream Elapsed %u Seconds from STT, Rate: %.2fx\n",
7610 last_stt
- first_stt
, flf
/etf
);
7619 memset( &cap_start
, 0, sizeof(cap_start
)); /* w/o librt, start is 0 */
7622 clock_gettime( clock_method
, &cap_start
);
7631 cap_stop
.tv_sec
= 1; /* w/o librt, ET is 1s */
7634 clock_gettime( clock_method
, &cap_stop
);
7636 memcpy( &cap_et
, &cap_stop
, sizeof(cap_et
) );
7638 // if nanos subtracts borrow
7639 if (cap_start
.tv_nsec
> cap_stop
.tv_nsec
) {
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;
7652 alloc_frames( void )
7654 frames
= malloc( FRAME_MAX
* sizeof(struct frame_s
) );
7655 sequences
= malloc( SEQUENCE_MAX
* sizeof(long long) );
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
)
7701 test_clock_res(); /* find most accurate clock for clock_gettime */
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 */
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 */
7724 read_loop(); /* reads until EOF */
7729 reset_buffer( in_buf
);
7730 free_buffer( in_buf
);
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
);
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
);
7758 if (0 != arg_seqwr
) {
7759 dump_sequences(); /* -s option writes frames/sequences */
7761 dump_counts(); /* counts will not be valid without read loop */
7762 dump_guide(); /* guide will not be valid unless ATSC PSIP */
7770 fprintf( stdout
, "\n");