LogoopenSUSE Build Service > Projects
Sign Up | Log In

View File transport-stream.patch of Package tivodecode (Project multimedia:apps)

From: moyekj@yahoo.com
References: http://code.google.com/p/kmttg/wiki/linux_installation
Upstream: submitted

Adds support for TiVo files in mpeg2 Transport Stream container.

diff -urN tivodecode-0.2pre4/ChangeLog tivodecode-0.3pre4/ChangeLog
--- tivodecode-0.2pre4/ChangeLog	2007-04-10 19:34:30.000000000 -0500
+++ tivodecode-0.3pre4/ChangeLog	2010-02-16 10:18:10.000000000 -0600
@@ -1,3 +1,12 @@
+0.3pre1:
+        * add support for TS files.
+
+        * known bug :
+        Packet N of PID XX starts a new series of PES headers, which spill over into
+        packet N+1 of PID XX, which has an encrypted payload.  The problem is how to
+        cleanly make that "continuation" from packet N to N+1, such that the offset
+        into Packet N+1 can be determined where the decrypt needs to start.
+
 0.2pre3:
 
 	* add an option to not process video - handy if all you want is to
diff -urN tivodecode-0.2pre4/Makefile.am tivodecode-0.3pre4/Makefile.am
--- tivodecode-0.2pre4/Makefile.am	2007-08-28 00:19:38.000000000 -0500
+++ tivodecode-0.3pre4/Makefile.am	2009-12-22 10:57:15.000000000 -0600
@@ -10,4 +10,3 @@
 tdcat_LDADD=$(LIBOBJS) -L. -ltivodecode
 tdcat_DEPENDENCIES=$(LIBOBJS) libtivodecode.a
 EXTRA_DIST=libtivodecode.vcproj libtdcommon.vcproj tdcat.vcproj tdconfig.h.win32 tivodecode.rules tivodecode.sln tivodecode.vcproj
-
diff -urN tivodecode-0.2pre4/README tivodecode-0.3pre4/README
--- tivodecode-0.2pre4/README	2007-04-10 19:37:03.000000000 -0500
+++ tivodecode-0.3pre4/README	2010-03-25 12:08:11.000000000 -0500
@@ -1,5 +1,5 @@
 tivodecode (c) 2006-2007, Jeremy Drake
-Version 0.2pre3
+Version 0.3pre4
 See COPYING for license terms.
 
 This project now uses autoconf for its build system.  See the INSTALL file for
@@ -29,9 +29,8 @@
 
   --mak, -m          media access key (required)
   --out, -o          output file (default stdout)
-  --verbose, -v      verbose
+  --verbose, -v      verbose (add more v's for more verbosity)
   --no-verify, -n    do not verify MAK while decoding
-  --dump-metadata,-D dump metadata from TiVo file to xml files (development)
   --no-video, -x     don't decode video, exit after metadata
   --version, -V      print the version information and exit
   --help, -h         print this help and exit
diff -urN tivodecode-0.2pre4/TiVo-Decrypt-Notes.txt tivodecode-0.3pre4/TiVo-Decrypt-Notes.txt
--- tivodecode-0.2pre4/TiVo-Decrypt-Notes.txt	1969-12-31 18:00:00.000000000 -0600
+++ tivodecode-0.3pre4/TiVo-Decrypt-Notes.txt	2010-02-16 07:44:32.000000000 -0600
@@ -0,0 +1,232 @@
+
+TiVo TS header structure
+========================
+
+The TS file maintains the same overall file layout as the PS files.
+There is a small header, followed by three "chunks" of info at the 
+beginning of the TS .TiVo file.   
+
+The header : 
+
+    struct {
+        char           filetype[4];
+        /* all fields are in network byte order */
+        unsigned short dummy_0004;
+        unsigned short dummy_0006;
+        unsigned short dummy_0008;
+        unsigned char  mpeg_offset[4]; /* unsigned int */
+        unsigned short chunks;
+    } raw_tivo_header;
+   
+    Points of interest :
+        "filetype" is always "TiVo".
+        dummy_0004 is unknown, at the moment.
+        dummy_0006 :
+
+            Bit 1 is always 0
+            
+            Bit 2 is always 0 for US TiVo files and 1 for NZ/AUS files. 
+            
+            	This does NOT seem to indicate H.264 vs MPEG-2 as I have one 
+            	of each from a NZ TiVo and they both have it set to 1.
+            	
+            Bit 3 is 0 if the file is PS and 1 if the file is TS
+            
+            Bit 4 is 0 if the file is SD and 1 if the files is HD
+            * There are more values folded into "dummy_006" that are yet to be determined.
+       
+        "mpeg_offset" is the offset at which the real MPEG data starts (typically around 14336)
+        "chunks" denotes the number of TiVo-specific chunks of data that follow (typically 3).
+	
+The chunks :
+
+	#define SIZEOF_STREAM_CHUNK 12
+	typedef struct tivo_stream_chunk_s {
+		unsigned int   chunk_size;    /* Size of chunk */
+		unsigned int   data_size;     /* Length of the payload */
+		unsigned short id;            /* Chunk ID */
+		unsigned short type;          /* Subtype */
+		unsigned char  data[1];       /* Variable length data */
+	} tivo_stream_chunk;	
+	
+	Chunk size denotes the size of the current chunk.
+	Data size is the size of the current chunk, less the chunk header.
+	ID is the sequential chunk number of the current chunk (0-based).
+	
+		type==0 is a clear-text copyright notice.
+		
+				<?xml version="1.0" encoding="utf-8"?>
+				<license xmlns="http://www.tivo.com/developer/xml/license-1.0">
+				<notice>
+				TiVo takes copyright violations seriously.  This file may contain
+				content protected by copyright laws.  If you are not the owner or rights
+				holder of such content, you should be aware that if you distribute this
+				file or otherwise make it available to anyone else, you may be violating the
+				intellectual property rights of the owners of the content contained in this
+				file.  If you are not the owner or rights holder of such content, and if you
+				are a TiVo customer, and if you distribute this file or otherwise make it
+				available to anyone else, you may be violating the service agreement.
+				We may permanently discontinue your TiVo service as a result.
+				</notice>
+				<created>
+				01/12/2005 11:22:01
+				</created>
+				<fingerprint>
+				... hex string that is 224 hex digits long ....
+				</fingerprint>
+				<salt>
+				... hex string that is 32 hex digits long...
+				</salt>
+				</license>		
+		
+		type==1 is an encrypted copy of the TiVo XML metadata for this file.  
+				
+				The encryption scheme used here is the metadata variant (see "Crytpo" below)
+				of the Turing stream cipher.
+										
+				Typically, there are two chunks of this type, and the two are nearly identical.
+				The only variations I can see are that the second one includes the "uniqueId"
+				field, which is the unique seriesId (i.e. SH01234567) used by TiVo to perform 
+				grouping in the Now Playing List.			
+				
+
+Crypto
+======
+
+The encryption method utilized by TiVo is the open source Turing stream cipher, by Qualcomm.				
+				
+https://opensource.qualcomm.com/index.php?turing
+
+It follows the usual crypto usage pattern :
+  - initialize crypto session (to zero)
+  - "salt" the crypto session with predefined values (MAK, etc)
+  - pass blocks of the stream data through the cipher to encrypt/decrypt it
+  
+The metadata chunks use an initial MD5 pass to generate its Turing salt value.
+The transport stream data packets use an initial SHA-1 pass to generate its Turing salt value.
+			
+	
+Acquiring TiVo TS crypto info 
+=============================
+
+- We must first acquire the MPEG TS "Program Association Table" (PAT).
+  This packet's only useful data element is the "program_MAP_pid" field,
+  which instructs us as the to PID of the "Program Map Table" (PMT) packet.
+  The PAT is always located at PID 0.
+  
+- Then, we must acquire the MPEG TS "Program Map Table" (PMT).  The PMT 
+  is a table of the elementary stream pids within the MPEG file, and their 
+  types.   The PMT may be located at PID identified in the PAT, or (more
+  likely) may be encapsulated in an audio/video packet.  Typically, a TiVo 
+  file will contain three streams.
+  	0x21 = video
+  	0x22 = audio
+  	0x23 = private data : this is where TiVo puts the crypto goodies
+
+- Not all packets in the audio and video streams are encrypted.   This is
+  verified by comparing encrypted TS files and decrypted MPEG files as 
+  generated by DirectShowDump.   As such, we only need to worry about the
+  packets that are encrypted (which is denoted by the packet's TS header
+  transport_scrambling_control field being set to a non-zero value, usually 0x3).
+
+- Packets in the "private data" stream contain the necessary info to decrypt
+  the audio and video streams within the TiVo MPEG TS file.   They appear 
+  periodically within the packet stream, and the Turing key value changes
+  with each new private data packet.
+  
+	TiVo Private Data format
+	typedef struct TiVo_Private_Data_s
+	{
+		unsigned int 				filetype;		
+		unsigned int				unknown;
+		unsigned short				num_streams;
+		TiVo_Private_Data_Stream	data_streams[N];
+	} TiVo_Private_Data;
+	
+	The filetype is always "TiVo".
+	The unknown field is exactly that, although its value is always 0x81037d00.
+	The num_streams indicates how many TiVo_Private_Data_Stream elements follow.
+	
+	typedef struct TiVo_Private_Data_Stream_s
+	{
+		unsigned short		pid;
+		unsigned char		stream_id;
+		unsigned char		reserved;
+		unsigned char		key[16];
+	} TiVo_Private_Data_Stream;
+		
+	The pid is the Packet ID for this stream (0x21, 0x22, etc).
+	The stream_id is the TS Stream ID (0xE0 video, 0xC0 audio, etc).
+	The reserved field is always 0x10.
+	The key is the 16-byte Turing key used to decrypt this particular stream.			
+
+    The Turing key has two additional values folded into it for later use in
+    the decrypt process :
+    
+	    The first value is the "block_no" value, and indicates the Turing block 
+	    number for this portion of the cipher process.  It increments over time 
+	    within the stream.   
+	    
+	    The second value is the "crypted" value, which appears to be some sort 
+	    of checksum value used by the stream cipher.   In PS files, this number
+	    appears to be a usable hexadecimal value, and as such is used in the 
+	    decrypt process.   However, in the TS files, this number is always zero,
+	    and is not used in the decrypt process.
+    
+    When a TiVo private data packet is encountered, we must update our session's
+    Turing values (key, block_no) to the newer values.   Each packet stream
+    (i.e. audio, video) within the transport stream will have it's own Turing 
+   	session.  So, we must maintain these separate Turing sessions across packets.
+    
+    When an audio/video packet is encountered, we must first verify if it is
+    indeed encrypted by checking the TS header's transport_scrambling_control
+    field.   Any non-zero value (typically 0x3) denotes an encrypted packet.
+    
+    We must take care to only decrypt payload data, and not packet stream control
+    data.   As such, we must pass over other MPEG TS headers, such as the 
+    Adaptation field or PES headers.   
+    
+    When we've finally located the beginning of the encrypted payload data, we
+    must regenerate our Turing cipher for this particular session.   For this 
+    packet, we must : 
+      - locate this particular PID's Turing session
+      - extract the "block_no" and "crypted" values from the Turing key using by
+        calling do_header()
+      - prepare the Turing frame for decrypt by calling prepare_frame() and 
+        pass it the PID and block_no.
+      - decrypt the payload by calling decrypt_buffer(), passing in a pointer
+        to the start of the encrypted payload, and the size of the payload to
+        be decrypted.
+    
+    
+TiVo PS decrypt methodology
+===========================
+
+	- Identify in the stream where private data is located (inside the private
+	  data packets identified as PID 0x23).  This is the crypto key.
+	
+	- Prepare for Turing decrypt operations by passing in this key, along with two 
+	  values (block_no and crypted) into the do_header() function.   This does some 
+	  bitfield math on these three elements, and results in new values being inserted into 
+	  the block_no and crypted fields.    The do_header() function was reconstructed 
+	  from the TiVo DLL by other individuals, and the understanding behind it is 
+	  incomplete.  There is some stuff going on in there that is unknown.  Although, 
+	  it's obviously doing the right stuff (at least for PS operations).
+	  
+	- We then pass the new block_no and stream_id values into the prepare_frame() 
+	  function to prep the Turing structures for data decryption.  
+	  
+	- We then pass the new crypted value (4 bytes worth) into the decrypt_buffer()
+	  function to get the Turing goodies ready for real data.
+	  
+	- We then pass the entire amount of decrypted data through the decrypt_buffer()
+	  function to decrypt the data.   Since this is a data stream, the size of this
+	  operation can be anywhere from 1000 to 15000 bytes.
+	  
+	- Rinse and repeat.
+	
+
+Notes on the code
+=================
+Since I was not an MPEG expert, I was quite verbose in my packet decode and debug output.
+Much of this code can probably be cleaned up, or outright removed as needed.
diff -urN tivodecode-0.2pre4/UpgradeLog.XML tivodecode-0.3pre4/UpgradeLog.XML
--- tivodecode-0.2pre4/UpgradeLog.XML	1969-12-31 18:00:00.000000000 -0600
+++ tivodecode-0.3pre4/UpgradeLog.XML	2009-12-21 15:04:14.000000000 -0600
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet type='text/xsl' href='_UpgradeReport_Files/UpgradeReport.xslt'?><UpgradeLog>
+<Properties><Property Name="Solution" Value="tivodecode">
+</Property><Property Name="Solution File" Value="S:\psimoneau\test\tivo\tivodecode-0.3\tivodecode.sln">
+</Property><Property Name="Date" Value="Monday, December 21, 2009">
+</Property><Property Name="Time" Value="16:03 PM">
+</Property></Properties><Event ErrorLevel="0" Project="tivodecode" Source="tivodecode.vcproj" Description="Web deployment to the local IIS server is no longer supported. The Web Deployment build tool has been removed from your project settings.">
+</Event><Event ErrorLevel="1" Project="tivodecode" Source="tivodecode.vcproj" Description="This application has been updated to include settings related to the User Account Control (UAC) feature of Windows Vista. By default, when run on Windows Vista with UAC enabled, this application is marked to run with the same privileges as the process that launched it. This marking also disables the application from running with virtualization. You can change UAC related settings from the Property Pages of the project.">
+</Event><Event ErrorLevel="0" Project="tivodecode" Source="tivodecode.vcproj" Description="Project upgraded successfully.">
+</Event><Event ErrorLevel="3" Project="tivodecode" Source="tivodecode.vcproj" Description="Converted">
+</Event><Event ErrorLevel="1" Project="libtivodecode" Source="libtivodecode.vcproj" Description="This application has been updated to include settings related to the User Account Control (UAC) feature of Windows Vista. By default, when run on Windows Vista with UAC enabled, this application is marked to run with the same privileges as the process that launched it. This marking also disables the application from running with virtualization. You can change UAC related settings from the Property Pages of the project.">
+</Event><Event ErrorLevel="0" Project="libtivodecode" Source="libtivodecode.vcproj" Description="Project upgraded successfully.">
+</Event><Event ErrorLevel="3" Project="libtivodecode" Source="libtivodecode.vcproj" Description="Converted">
+</Event><Event ErrorLevel="0" Project="tdcat" Source="tdcat.vcproj" Description="Web deployment to the local IIS server is no longer supported. The Web Deployment build tool has been removed from your project settings.">
+</Event><Event ErrorLevel="1" Project="tdcat" Source="tdcat.vcproj" Description="This application has been updated to include settings related to the User Account Control (UAC) feature of Windows Vista. By default, when run on Windows Vista with UAC enabled, this application is marked to run with the same privileges as the process that launched it. This marking also disables the application from running with virtualization. You can change UAC related settings from the Property Pages of the project.">
+</Event><Event ErrorLevel="0" Project="tdcat" Source="tdcat.vcproj" Description="Project upgraded successfully.">
+</Event><Event ErrorLevel="3" Project="tdcat" Source="tdcat.vcproj" Description="Converted">
+</Event><Event ErrorLevel="1" Project="libtdcommon" Source="libtdcommon.vcproj" Description="This application has been updated to include settings related to the User Account Control (UAC) feature of Windows Vista. By default, when run on Windows Vista with UAC enabled, this application is marked to run with the same privileges as the process that launched it. This marking also disables the application from running with virtualization. You can change UAC related settings from the Property Pages of the project.">
+</Event><Event ErrorLevel="0" Project="libtdcommon" Source="libtdcommon.vcproj" Description="Project upgraded successfully.">
+</Event><Event ErrorLevel="3" Project="libtdcommon" Source="libtdcommon.vcproj" Description="Converted">
+</Event><Event ErrorLevel="0" Project="" Source="tivodecode.sln" Description="Solution converted successfully">
+</Event><Event ErrorLevel="3" Project="" Source="tivodecode.sln" Description="Converted">
+</Event></UpgradeLog>
\ No newline at end of file
diff -urN tivodecode-0.2pre4/byteswap.c tivodecode-0.3pre4/byteswap.c
--- tivodecode-0.2pre4/byteswap.c	1969-12-31 18:00:00.000000000 -0600
+++ tivodecode-0.3pre4/byteswap.c	2009-12-22 10:09:10.000000000 -0600
@@ -0,0 +1,15 @@
+
+#include <stdlib.h>
+#include <stdio.h>
+
+int isBigEndian()
+{
+  unsigned char EndianTest[2] = {1,0};
+  short x = *(short *)EndianTest;
+
+  if( x == 1 )
+    return 0;
+  else
+    return 1;
+}
+
diff -urN tivodecode-0.2pre4/byteswap.h tivodecode-0.3pre4/byteswap.h
--- tivodecode-0.2pre4/byteswap.h	1969-12-31 18:00:00.000000000 -0600
+++ tivodecode-0.3pre4/byteswap.h	2009-12-22 10:09:28.000000000 -0600
@@ -0,0 +1 @@
+extern int isBigEndian();
diff -urN tivodecode-0.2pre4/cli_common.h tivodecode-0.3pre4/cli_common.h
--- tivodecode-0.2pre4/cli_common.h	2007-08-05 00:47:23.000000000 -0500
+++ tivodecode-0.3pre4/cli_common.h	2010-02-17 20:46:20.000000000 -0600
@@ -1,5 +1,8 @@
 #ifndef TD_CLI_COMMON_H__
 #define TD_CLI_COMMON_H__
+#ifdef WIN32
+#   include <fcntl.h>
+#endif
 
 #define PRINT_QUALCOMM_MSG() fprintf (stderr, "Encryption by QUALCOMM ;)\n\n")
 
diff -urN tivodecode-0.2pre4/configure tivodecode-0.3pre4/configure
--- tivodecode-0.2pre4/configure	2007-08-28 00:15:51.000000000 -0500
+++ tivodecode-0.3pre4/configure	2010-03-25 12:07:39.000000000 -0500
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.61 for tivodecode 0.2pre4.
+# Generated by GNU Autoconf 2.61 for tivodecode 0.3pre4.
 #
 # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
 # 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
@@ -572,8 +572,8 @@
 # Identity of this package.
 PACKAGE_NAME='tivodecode'
 PACKAGE_TARNAME='tivodecode'
-PACKAGE_VERSION='0.2pre4'
-PACKAGE_STRING='tivodecode 0.2pre4'
+PACKAGE_VERSION='0.3pre4'
+PACKAGE_STRING='tivodecode 0.3pre4'
 PACKAGE_BUGREPORT=''
 
 ac_unique_file="tivodecode.c"
@@ -1209,7 +1209,7 @@
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures tivodecode 0.2pre4 to adapt to many kinds of systems.
+\`configure' configures tivodecode 0.3pre4 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1275,7 +1275,7 @@
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of tivodecode 0.2pre4:";;
+     short | recursive ) echo "Configuration of tivodecode 0.3pre4:";;
    esac
   cat <<\_ACEOF
 
@@ -1361,7 +1361,7 @@
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-tivodecode configure 0.2pre4
+tivodecode configure 0.3pre4
 generated by GNU Autoconf 2.61
 
 Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
@@ -1375,7 +1375,7 @@
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by tivodecode $as_me 0.2pre4, which was
+It was created by tivodecode $as_me 0.3pre4, which was
 generated by GNU Autoconf 2.61.  Invocation command line was
 
   $ $0 $@
@@ -2066,7 +2066,7 @@
 
 # Define the identity of the package.
  PACKAGE='tivodecode'
- VERSION='0.2pre4'
+ VERSION='0.3pre4'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -8495,7 +8495,7 @@
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by tivodecode $as_me 0.2pre4, which was
+This file was extended by tivodecode $as_me 0.3pre4, which was
 generated by GNU Autoconf 2.61.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -8548,7 +8548,7 @@
 _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF
 ac_cs_version="\\
-tivodecode config.status 0.2pre4
+tivodecode config.status 0.3pre4
 configured by $0, generated by GNU Autoconf 2.61,
   with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
 
diff -urN tivodecode-0.2pre4/configure.in tivodecode-0.3pre4/configure.in
--- tivodecode-0.2pre4/configure.in	2007-08-28 00:15:46.000000000 -0500
+++ tivodecode-0.3pre4/configure.in	2010-03-25 12:08:00.000000000 -0500
@@ -1,4 +1,4 @@
-AC_INIT(tivodecode, 0.2pre4)
+AC_INIT(tivodecode, 0.3pre4)
 AC_CONFIG_SRCDIR(tivodecode.c)
 AM_INIT_AUTOMAKE
 AM_MAINTAINER_MODE
diff -urN tivodecode-0.2pre4/hexlib.c tivodecode-0.3pre4/hexlib.c
--- tivodecode-0.2pre4/hexlib.c	2007-04-06 18:54:42.000000000 -0500
+++ tivodecode-0.3pre4/hexlib.c	2009-12-21 08:46:39.000000000 -0600
@@ -11,6 +11,7 @@
 # include <string.h>
 #endif
 #include "hexlib.h"
+#include <ctype.h>
 
 int	nerrors;
 
@@ -22,9 +23,9 @@
 {
     printf("%14s:", s);
     while (--n >= 0) {
-	if (n % 20 == 19)
-	    printf("\n%14s ", "");
-	printf(" %02x", *p++);
+		if (n % 20 == 19)
+		    printf("\n%14s ", "");
+		printf(" %02x", *p++);
     }
     printf("\n");
     return 0;
@@ -36,10 +37,10 @@
     int		i;
 
     while (--n >= 0) {
-	while (*p == ' ') ++p;
-	i = HEX(*p++) << 4;
-	i += HEX(*p++);
-	*buf++ = i;
+		while (*p == ' ') ++p;
+			i = HEX(*p++) << 4;
+		i += HEX(*p++);
+		*buf++ = i;
     }
     return 0;
 }
@@ -50,27 +51,58 @@
     int		i;
 
     while (--n >= 0) {
-	while (*p == ' ') ++p;
-	i = HEX(*p++) << 4;
-	i += HEX(*p++);
-	if (*buf++ != i) {
-	    printf("Expected %02x, got %02x.\n", i, buf[-1]);
-	    ++nerrors;
-	}
+		while (*p == ' ') ++p;
+			i = HEX(*p++) << 4;
+		i += HEX(*p++);
+		if (*buf++ != i) {
+		    printf("Expected %02x, got %02x.\n", i, buf[-1]);
+		    ++nerrors;
+		}
     }
     return nerrors;
 }
 
-#define COLS 20
+#define COLS 16
 
 int
 hexbulk(unsigned char *buf, int n)
 {
-    int		i;
-
-    for (i = 0; i < n; ++i)
-	printf("%02x%c", buf[i], (i%COLS == (COLS-1) ? '\n' : ' '));
-    if (i % COLS != 0)
-	putchar('\n');
+    int		i=0;
+    int		j=0;
+    char 	ch;
+    char 	hexdigit[5];
+    char 	strdigit[5];
+    char 	hexstr[100];
+    char 	strstr[100];
+    
+ 	while ( i<n )
+   	{
+		memset(hexstr, 0, 100);
+		memset(strstr, 0, 100);
+	
+   		for(j=0; (j<COLS) && (i<n); j++, i++ )
+   		{
+	   		if ( isspace(buf[i]) )
+	   			ch = ' ';
+	   		else if ( isprint( buf[i]))
+	   			ch = buf[i];
+	   		else
+	   			ch = '.';
+
+	   		sprintf( hexdigit, "%02x ", buf[i] );	   			
+	   		sprintf( strdigit, "%c",    ch);
+			strcat( hexstr, hexdigit ); 
+			strcat( strstr, strdigit );
+		}
+		
+		while(j<COLS)
+		{
+			strcat( hexstr, "   " );	
+			j++;
+		}
+		
+		printf("%s %s\n", hexstr, strstr);
+	}		
+				
     return 0;
 }
diff -urN tivodecode-0.2pre4/libtdcommon.vcproj tivodecode-0.3pre4/libtdcommon.vcproj
--- tivodecode-0.2pre4/libtdcommon.vcproj	2007-08-06 00:49:13.000000000 -0500
+++ tivodecode-0.3pre4/libtdcommon.vcproj	2009-12-21 15:04:14.000000000 -0600
@@ -1,11 +1,12 @@
 <?xml version="1.0" encoding="Windows-1252"?>
 <VisualStudioProject
 	ProjectType="Visual C++"
-	Version="8.00"
+	Version="9.00"
 	Name="libtdcommon"
 	ProjectGUID="{491A7F57-2E09-492E-9E44-70A34A313611}"
 	RootNamespace="libtdcommon"
 	Keyword="Win32Proj"
+	TargetFrameworkVersion="131072"
 	>
 	<Platforms>
 		<Platform
diff -urN tivodecode-0.2pre4/libtivodecode.vcproj tivodecode-0.3pre4/libtivodecode.vcproj
--- tivodecode-0.2pre4/libtivodecode.vcproj	2007-08-06 00:49:34.000000000 -0500
+++ tivodecode-0.3pre4/libtivodecode.vcproj	2009-12-21 15:04:14.000000000 -0600
@@ -1,11 +1,12 @@
 <?xml version="1.0" encoding="Windows-1252"?>
 <VisualStudioProject
 	ProjectType="Visual C++"
-	Version="8.00"
+	Version="9.00"
 	Name="libtivodecode"
 	ProjectGUID="{9DDBB216-6D06-47EB-B559-B3FB02510DC3}"
 	RootNamespace="libtivodecode"
 	Keyword="Win32Proj"
+	TargetFrameworkVersion="131072"
 	>
 	<Platforms>
 		<Platform
diff -urN tivodecode-0.2pre4/tdcat.c tivodecode-0.3pre4/tdcat.c
--- tivodecode-0.2pre4/tdcat.c	2007-08-06 01:44:01.000000000 -0500
+++ tivodecode-0.3pre4/tdcat.c	2010-02-17 20:45:46.000000000 -0600
@@ -128,6 +128,14 @@
 
     if (!strcmp(tivofile, "-"))
     {
+        // JKOZEE-Make sure stdin is set to binary on Windows
+        #ifdef WIN32
+        int result = _setmode(_fileno(stdin), _O_BINARY );
+        if( result == -1 ) {
+           perror( "Cannot set stdin to binary mode" );
+           return 10;
+        }
+        #endif
         hfh=hattach(stdin);
     }
     else
@@ -141,6 +149,14 @@
 
     if (!outfile || !strcmp(outfile, "-"))
     {
+        // JKOZEE-Make sure stdout is set to binary on Windows
+        #ifdef WIN32
+        int result = _setmode(_fileno(stdout), _O_BINARY );
+        if( result == -1 ) {
+           perror( "Cannot set stdout to binary mode" );
+           return 10;
+        }
+        #endif
         ofh = stdout;
     }
     else
@@ -171,7 +187,7 @@
         if ((chunk = read_tivo_chunk (hfh, &hread_wrapper)) == NULL)
             return 8;
 
-        if (chunk->data_size && chunk->type == TIVO_CHUNK_XML)
+        if (chunk->data_size && chunk->type == TIVO_CHUNK_PLAINTEXT_XML)
         {
             setup_metadata_key (&metaturing, chunk, mak);
             free (chunk);
diff -urN tivodecode-0.2pre4/tdcat.vcproj tivodecode-0.3pre4/tdcat.vcproj
--- tivodecode-0.2pre4/tdcat.vcproj	2007-08-06 00:49:34.000000000 -0500
+++ tivodecode-0.3pre4/tdcat.vcproj	2009-12-21 15:04:14.000000000 -0600
@@ -1,11 +1,12 @@
 <?xml version="1.0" encoding="Windows-1252"?>
 <VisualStudioProject
 	ProjectType="Visual C++"
-	Version="8.00"
+	Version="9.00"
 	Name="tdcat"
 	ProjectGUID="{66AEBB90-9BD8-497E-B546-9409110E9F21}"
 	RootNamespace="tdcat"
 	Keyword="Win32Proj"
+	TargetFrameworkVersion="131072"
 	>
 	<Platforms>
 		<Platform
@@ -67,6 +68,8 @@
 				LinkIncremental="2"
 				GenerateDebugInformation="true"
 				SubSystem="1"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
 				TargetMachine="1"
 			/>
 			<Tool
@@ -88,9 +91,6 @@
 				Name="VCAppVerifierTool"
 			/>
 			<Tool
-				Name="VCWebDeploymentTool"
-			/>
-			<Tool
 				Name="VCPostBuildEventTool"
 			/>
 		</Configuration>
@@ -145,6 +145,8 @@
 				SubSystem="1"
 				OptimizeReferences="2"
 				EnableCOMDATFolding="2"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
 				TargetMachine="1"
 			/>
 			<Tool
@@ -166,9 +168,6 @@
 				Name="VCAppVerifierTool"
 			/>
 			<Tool
-				Name="VCWebDeploymentTool"
-			/>
-			<Tool
 				Name="VCPostBuildEventTool"
 			/>
 		</Configuration>
diff -urN tivodecode-0.2pre4/tdconfig.h.win32 tivodecode-0.3pre4/tdconfig.h.win32
--- tivodecode-0.2pre4/tdconfig.h.win32	2007-08-28 00:16:25.000000000 -0500
+++ tivodecode-0.3pre4/tdconfig.h.win32	2010-03-25 12:06:17.000000000 -0500
@@ -84,13 +84,13 @@
 #define PACKAGE_NAME "tivodecode"
 
 /* Define to the full name and version of this package. */
-#define PACKAGE_STRING "tivodecode 0.2pre4"
+#define PACKAGE_STRING "tivodecode 0.3pre4"
 
 /* Define to the one symbol short name of this package. */
 #define PACKAGE_TARNAME "tivodecode"
 
 /* Define to the version of this package. */
-#define PACKAGE_VERSION "0.2pre4"
+#define PACKAGE_VERSION "0.3pre4"
 
 /* The size of `off_t', as computed by sizeof. */
 #define SIZEOF_OFF_T 4
@@ -108,7 +108,7 @@
 #define STDC_HEADERS 1
 
 /* Version number of package */
-#define VERSION "0.2pre4"
+#define VERSION "0.3pre4"
 
 /* Define to 1 if your processor stores words with the most significant byte
    first (like Motorola and SPARC, unlike Intel and VAX). */
diff -urN tivodecode-0.2pre4/tivo-parse.c tivodecode-0.3pre4/tivo-parse.c
--- tivodecode-0.2pre4/tivo-parse.c	2007-08-06 01:41:49.000000000 -0500
+++ tivodecode-0.3pre4/tivo-parse.c	2009-12-22 10:51:35.000000000 -0600
@@ -24,6 +24,8 @@
 #include "sha1.h"
 #include "tivo-parse.h"
 
+#include "hexlib.h"
+
 #define LOAD_NET_UNALIGNED_HELP(ptr, offset, len) ((unsigned int)ptr[offset] << (((len - 1) << 3) - (offset << 3)))
 
 #define NETLONG_UNALIGNED(ptr) ( \
@@ -33,6 +35,47 @@
 		LOAD_NET_UNALIGNED_HELP(ptr, 3, 4) \
 	)
 
+
+int isBigEndian()
+{
+  unsigned char EndianTest[2] = {1,0};
+  short x = *(short *)EndianTest;
+
+  if( x == 1 )
+    return 0;
+  else
+    return 1;
+}
+
+unsigned long portable_ntohl( unsigned char * pVal )
+{
+	unsigned long s = 0;
+	if ( isBigEndian() )
+	{
+		return *(unsigned long *)pVal;
+	}
+	else
+	{
+		s = (pVal[0] << 24) | (pVal[1] << 16) | (pVal[2]<<8) | pVal[3];
+		return s;
+	}
+}
+
+unsigned short portable_ntohs( unsigned char * pVal )
+{
+	unsigned short s = 0;
+	if ( isBigEndian() )
+	{
+		return *(unsigned short *)pVal;
+	}
+	else
+	{
+		s = (pVal[0] << 8) | pVal[1];
+		return s;
+	}	
+}
+
+
 int read_tivo_header(void * file, tivo_stream_header * head, read_func_t read_handler)
 {
 	struct {
@@ -51,13 +94,11 @@
 		perror ("read head");
 		return -1;
 	}
-#if 1
-	// these are unused
+
 	memcpy(head->filetype, raw_tivo_header.filetype, 4);
 	head->dummy_0004 = ntohs(raw_tivo_header.dummy_0004);
 	head->dummy_0006 = ntohs(raw_tivo_header.dummy_0006);
 	head->dummy_0008 = ntohs(raw_tivo_header.dummy_0008);
-#endif
 	head->mpeg_offset = NETLONG_UNALIGNED(raw_tivo_header.mpeg_offset);
 	head->chunks = ntohs(raw_tivo_header.chunks);
 
@@ -103,3 +144,33 @@
 	return chunk;
 }
 
+void dump_tivo_header(tivo_stream_header * head)
+{
+	if ( !head )
+		return;
+		
+	printf("Head File Type : %s\n",   head->filetype );
+	printf("Head Dummy4    : %04x\n", head->dummy_0004 );
+	printf("Head Dummy6    : %04x\n", head->dummy_0006 );
+	printf("Head Dummy8    : %04x\n", head->dummy_0008 );
+	printf("MPEG offset    : %d\n",   head->mpeg_offset );
+	printf("Head Chunks    : %d\n",   head->chunks );
+	printf("\n");
+	return;
+}
+
+
+void dump_tivo_chunk(tivo_stream_chunk * chunk)
+{
+	if ( !chunk )
+		return;
+		
+	printf("Chunk Size : %d\n", chunk->chunk_size );
+	printf("Data Size  : %d\n", chunk->data_size );
+	printf("Chunk ID   : %d\n", chunk->id );
+	printf("Chunk Type : %d\n", chunk->type );
+	printf("Chunk Data : \n" );
+	hexbulk( (unsigned char *)chunk->data, (int) chunk->data_size );
+	printf("\n");
+	return;
+}
diff -urN tivodecode-0.2pre4/tivo-parse.h tivodecode-0.3pre4/tivo-parse.h
--- tivodecode-0.2pre4/tivo-parse.h	2007-08-06 01:41:49.000000000 -0500
+++ tivodecode-0.3pre4/tivo-parse.h	2009-12-22 10:51:03.000000000 -0600
@@ -27,8 +27,8 @@
 	unsigned short chunks;        /* Number of metadata chunks */
 } tivo_stream_header;
 
-#define TIVO_CHUNK_XML  0
-#define TIVO_CHUNK_BLOB 1
+#define TIVO_CHUNK_PLAINTEXT_XML  0
+#define TIVO_CHUNK_ENCRYPTED_XML  1
 
 #define SIZEOF_STREAM_CHUNK 12
 typedef struct tivo_stream_chunk_s {
@@ -47,6 +47,21 @@
 int read_tivo_header(void * file, tivo_stream_header * head, read_func_t read_handler);
 tivo_stream_chunk * read_tivo_chunk(void * file, read_func_t read_handler);
 
+void dump_tivo_header(tivo_stream_header * head);
+void dump_tivo_chunk(tivo_stream_chunk * chunk);
+
+extern int isBigEndian();
+extern unsigned short portable_ntohs( unsigned char * pVal );
+extern unsigned long  portable_ntohl( unsigned char * pVal );
+
+#define VERBOSE(...)		if ( o_verbose >= 1 ) { printf(__VA_ARGS__); }
+#define VVERBOSE(...)		if ( o_verbose >= 2 ) { printf(__VA_ARGS__); }
+#define VVVERBOSE(...)		if ( o_verbose >= 3 ) { printf(__VA_ARGS__); }
+	
+#define IS_VERBOSE			( o_verbose >= 1 )
+#define IS_VVERBOSE			( o_verbose >= 2 )
+#define IS_VVVERBOSE		( o_verbose >= 3 )
+
 #ifdef __cplusplus
 }
 #endif
diff -urN tivodecode-0.2pre4/tivodecode.c tivodecode-0.3pre4/tivodecode.c
--- tivodecode-0.2pre4/tivodecode.c	2007-08-05 00:47:25.000000000 -0500
+++ tivodecode-0.3pre4/tivodecode.c	2010-02-17 20:50:39.000000000 -0600
@@ -19,6 +19,18 @@
 #include "getopt_long.h"
 #include "happyfile.h"
 #include "cli_common.h"
+#include "tivo-parse.h"
+
+int o_ts_pkt_dump = 0;
+
+typedef enum
+{
+	TIVO_FORMAT_NONE,
+    TIVO_FORMAT_PS,
+    TIVO_FORMAT_TS,
+    TIVO_FORMAT_MAX
+}
+tivo_format_type;
 
 static int hread_wrapper (void * mem, int size, void * fh)
 {
@@ -35,25 +47,27 @@
     {"out", 1, 0, 'o'},
     {"help", 0, 0, 'h'},
     {"verbose", 0, 0, 'v'},
+    {"pkt-dump", 1, 0, 'p'},
     {"version", 0, 0, 'V'},
     {"no-verify", 0, 0, 'n'},
-    {"dump-metadata", 0, 0, 'D'},
+    {"metadata", 0, 0, 'D'},
     {"no-video", 0, 0, 'x'},
     {0, 0, 0, 0}
 };
 
 static void do_help(char * arg0, int exitval)
 {
-    fprintf(stderr, "Usage: %s [--help] [--verbose|-v] [--no-verify|-n] {--mak|-m} mak [{--out|-o} outfile] <tivofile>\n\n", arg0);
+    fprintf(stderr, "Usage: %s [--help] [--verbose|-v] [--no-verify|-n] [--pkt-dump|-p] pkt_num {--mak|-m} mak [--metadata|-D] [{--out|-o} outfile] <tivofile>\n\n", arg0);
 #define ERROUT(s) fprintf(stderr, s)
-    ERROUT ("  --mak, -m          media access key (required)\n");
-    ERROUT ("  --out, -o          output file (default stdout)\n");
-    ERROUT ("  --verbose, -v      verbose\n");
-    ERROUT ("  --no-verify, -n    do not verify MAK while decoding\n");
-    ERROUT ("  --dump-metadata,-D dump metadata from TiVo file to xml files (development)\n");
-    ERROUT ("  --no-video, -x     don't decode video, exit after metadata\n");
-    ERROUT ("  --version, -V      print the version information and exit\n");
-    ERROUT ("  --help, -h         print this help and exit\n\n");
+    ERROUT ("  --mak, -m        media access key (required)\n");
+    ERROUT ("  --out, -o        output file (default stdout)\n");
+    ERROUT ("  --verbose, -v    verbose\n");
+    ERROUT ("  --pkt-dump, -p   verbose logging for specific TS packet number\n");
+    ERROUT ("  --metadata, -D   dump TiVo recording metadata\n");
+    ERROUT ("  --no-verify, -n  do not verify MAK while decoding\n");
+    ERROUT ("  --no-video, -x   don't decode video, exit after metadata\n");
+    ERROUT ("  --version, -V    print the version information and exit\n");
+    ERROUT ("  --help, -h       print this help and exit\n\n");
     ERROUT ("The file names specified for the output file or the tivo file may be -, which\n");
     ERROUT ("means stdout or stdin respectively\n\n");
 #undef ERROUT
@@ -61,15 +75,20 @@
     exit (exitval);
 }
 
+
 int main(int argc, char *argv[])
 {
     int o_no_video = 0;
-    int o_dump_chunks = 0;
+    int o_dump_chunks = 1;
+    int o_dump_metadata = 0;
     unsigned int marker;
     unsigned char byte;
     char first = 1;
+    
+    tivo_format_type format = TIVO_FORMAT_NONE;
 
     int running = 1;
+	int ret = 0;
 
     char * tivofile = NULL;
     char * outfile = NULL;
@@ -101,6 +120,9 @@
                 mak[11] = '\0';
                 makgiven = 1;
                 break;
+			case 'p':
+                sscanf(optarg, "%d", &o_ts_pkt_dump);
+                break;
             case 'o':
                 outfile = optarg;
                 break;
@@ -108,14 +130,14 @@
                 do_help(argv[0], 1);
                 break;
             case 'v':
-                o_verbose = 1;
+                o_verbose++;
                 break;
             case 'n':
                 o_no_verify = 1;
                 break;
-            case 'D':
-                o_dump_chunks = 1;
-                break;
+            case 'D' :
+            	o_dump_metadata = 1;
+            	break;
             case 'x':
                 o_no_video = 1;
                 break;
@@ -148,6 +170,14 @@
 
     if (!strcmp(tivofile, "-"))
     {
+        // JKOZEE-Make sure stdin is set to binary on Windows
+        #ifdef WIN32
+        int result = _setmode(_fileno(stdin), _O_BINARY );
+        if( result == -1 ) {
+           perror( "Cannot set stdin to binary mode" );
+           return 10;
+        }
+        #endif
         hfh=hattach(stdin);
     }
     else
@@ -161,6 +191,14 @@
 
     if (!outfile || !strcmp(outfile, "-"))
     {
+        // JKOZEE-Make sure stdout is set to binary on Windows
+        #ifdef WIN32
+        int result = _setmode(_fileno(stdout), _O_BINARY );
+        if( result == -1 ) {
+           perror( "Cannot set stdout to binary mode" );
+           return 10;
+        }
+        #endif
         ofh = stdout;
     }
     else
@@ -190,21 +228,36 @@
         if (read_tivo_header (hfh, &head, &hread_wrapper))
             return 8;
 
+		VVVERBOSE("TiVo Head\n");
+		if ( IS_VVVERBOSE )
+			dump_tivo_header(&head);
+		
         begin_at = head.mpeg_offset;
+        
+        if ( head.dummy_0006 & 0x20 )
+        {
+        	format = TIVO_FORMAT_TS;
+        }
+        else
+        {
+        	format = TIVO_FORMAT_PS;
+        }
 
-        for (i = 0; i < head.chunks; i++)
+        for (i=0; i<head.chunks; i++)
         {
             /* TODO: find a better way to present the chunks */
             /* maybe a simple tar format writer */
             char buf[4096];
             hoff_t chunk_start = htell(hfh) + SIZEOF_STREAM_CHUNK;
-            FILE * chunkfh;
 
             if ((chunk = read_tivo_chunk (hfh, &hread_wrapper)) == NULL)
                 return 8;
 
-            if (chunk->data_size && chunk->type == TIVO_CHUNK_XML)
+            if (chunk->data_size && chunk->type == TIVO_CHUNK_PLAINTEXT_XML )
             {
+				if ( IS_VVVERBOSE )
+					dump_tivo_chunk(chunk);
+				            	
                 if (!o_no_video)
                     setup_turing_key (&turing, chunk, mak);
                 setup_metadata_key (&metaturing, chunk, mak);
@@ -212,27 +265,36 @@
                 continue;
             }
 
-            sprintf(buf, "%s-%02d-%04x.xml", "chunk", i, chunk->id);
 
-            chunkfh = fopen(buf, "wb");
-            if (!chunkfh)
-            {
-                perror("create chunk file");
-                return 8;
-            }
+			if ( o_dump_metadata )
+			{            
+	            FILE * chunkfh;
+
+	            sprintf(buf, "%s-%02d-%04x.xml", "chunk", i, chunk->id);
+	
+	            chunkfh = fopen(buf, "wb");
+	            if (!chunkfh)
+	            {
+	                perror("create metadata file");
+	                return 8;
+	            }
+	
+	            prepare_frame(&metaturing, 0, 0);
+	            skip_turing_data(&metaturing, (size_t)(chunk_start - current_meta_stream_pos));
+	            decrypt_buffer(&metaturing, chunk->data, chunk->data_size);
+	            current_meta_stream_pos = chunk_start + chunk->data_size;
+
+				if (IS_VVVERBOSE)
+					dump_tivo_chunk(chunk);
+	
+	            if (fwrite (chunk->data, 1, chunk->data_size, chunkfh) != chunk->data_size)
+	            {
+	                perror("write chunk");
+	                return 8;
+	            }
 
-            prepare_frame(&metaturing, 0, 0);
-            skip_turing_data(&metaturing, (size_t)(chunk_start - current_meta_stream_pos));
-            decrypt_buffer(&metaturing, chunk->data, chunk->data_size);
-            current_meta_stream_pos = chunk_start + chunk->data_size;
-
-            if (fwrite (chunk->data, 1, chunk->data_size, chunkfh) != chunk->data_size)
-            {
-                perror("write chunk");
-                return 8;
-            }
-
-            fclose(chunkfh);
+	            fclose(chunkfh);
+        	}
 
             free(chunk);
         }
@@ -256,40 +318,67 @@
         return 9;
     }
 
-    marker = 0xFFFFFFFF;
-    while (running)
-    {
-        if ((marker & 0xFFFFFF00) == 0x100)
-        {
-            int ret = process_frame(byte, &turing, htell(hfh), hfh, &hread_wrapper, ofh, &fwrite_wrapper);
-            if (ret == 1)
-            {
-                marker = 0xFFFFFFFF;
-            }
-            else if (ret == 0)
-            {
-                fwrite(&byte, 1, 1, ofh);
-            }
-            else if (ret < 0)
+	if ( format == TIVO_FORMAT_TS )
+	{
+		running = 1;
+		while ( running )
+		{
+			ret = process_ts_frame(&turing, htell(hfh), hfh, &hread_wrapper, ofh, &fwrite_wrapper);
+			if ( ret < 0 )
             {
                 perror ("processing frame");
                 return 10;
-            }
-        }
-        else if (!first)
-        {
-            fwrite(&byte, 1, 1, ofh);
-        }
-        marker <<= 8;
-        if (hread(&byte, 1, hfh) == 0)
-        {
-            fprintf(stderr, "End of File\n");
-            running = 0;
-        }
-        else
-            marker |= byte;
-        first = 0;
+            }			
+            else if ( ret == 0 )
+           	{
+	            fprintf(stderr, "End of File\n");
+           		running = 0;
+           	}
+        }		
+	}
+	else if ( format == TIVO_FORMAT_PS )
+	{
+	    marker = 0xFFFFFFFF;
+	    while (running)
+	    {
+	        if ((marker & 0xFFFFFF00) == 0x100)
+	        {
+				ret = process_ps_frame(byte, &turing, htell(hfh), hfh, &hread_wrapper, ofh, &fwrite_wrapper);
+					
+				if (ret == 1)
+	            {
+	                marker = 0xFFFFFFFF;
+	            }
+	            else if (ret == 0)
+	            {
+	                fwrite(&byte, 1, 1, ofh);
+	            }
+	            else if (ret < 0)
+	            {
+	                perror ("processing frame");
+	                return 10;
+	            }
+	        }
+	        else if (!first)
+	        {
+	            fwrite(&byte, 1, 1, ofh);
+	        }
+	        marker <<= 8;
+	        if (hread(&byte, 1, hfh) == 0)
+	        {
+	            fprintf(stderr, "End of File\n");
+	            running = 0;
+	        }
+	        else
+	            marker |= byte;
+	        first = 0;
+	    }
     }
+    else
+    {
+		perror ("invalid TiVo format");
+		return 10;
+	}
 
     destruct_turing (&turing);
 
diff -urN tivodecode-0.2pre4/tivodecode.sln tivodecode-0.3pre4/tivodecode.sln
--- tivodecode-0.2pre4/tivodecode.sln	2007-08-06 00:49:34.000000000 -0500
+++ tivodecode-0.3pre4/tivodecode.sln	2009-12-21 15:04:14.000000000 -0600
@@ -1,6 +1,6 @@
 
-Microsoft Visual Studio Solution File, Format Version 9.00
-# Visual C++ Express 2005
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual C++ Express 2008
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tivodecode", "tivodecode.vcproj", "{AB0538B4-79BB-463D-AE34-5C7ACD90D0BA}"
 	ProjectSection(ProjectDependencies) = postProject
 		{491A7F57-2E09-492E-9E44-70A34A313611} = {491A7F57-2E09-492E-9E44-70A34A313611}
Binary files tivodecode-0.2pre4/tivodecode.suo and tivodecode-0.3pre4/tivodecode.suo differ
diff -urN tivodecode-0.2pre4/tivodecode.vcproj tivodecode-0.3pre4/tivodecode.vcproj
--- tivodecode-0.2pre4/tivodecode.vcproj	2007-08-06 00:49:34.000000000 -0500
+++ tivodecode-0.3pre4/tivodecode.vcproj	2009-12-21 15:04:14.000000000 -0600
@@ -1,11 +1,12 @@
 <?xml version="1.0" encoding="Windows-1252"?>
 <VisualStudioProject
 	ProjectType="Visual C++"
-	Version="8.00"
+	Version="9.00"
 	Name="tivodecode"
 	ProjectGUID="{AB0538B4-79BB-463D-AE34-5C7ACD90D0BA}"
 	RootNamespace="tivodecode"
 	Keyword="Win32Proj"
+	TargetFrameworkVersion="131072"
 	>
 	<Platforms>
 		<Platform
@@ -66,6 +67,8 @@
 				LinkIncremental="2"
 				GenerateDebugInformation="true"
 				SubSystem="1"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
 				TargetMachine="1"
 			/>
 			<Tool
@@ -87,9 +90,6 @@
 				Name="VCAppVerifierTool"
 			/>
 			<Tool
-				Name="VCWebDeploymentTool"
-			/>
-			<Tool
 				Name="VCPostBuildEventTool"
 			/>
 		</Configuration>
@@ -144,6 +144,8 @@
 				SubSystem="1"
 				OptimizeReferences="2"
 				EnableCOMDATFolding="2"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
 				TargetMachine="1"
 			/>
 			<Tool
@@ -165,9 +167,6 @@
 				Name="VCAppVerifierTool"
 			/>
 			<Tool
-				Name="VCWebDeploymentTool"
-			/>
-			<Tool
 				Name="VCPostBuildEventTool"
 			/>
 		</Configuration>
diff -urN tivodecode-0.2pre4/tivodecoder.c tivodecode-0.3pre4/tivodecoder.c
--- tivodecode-0.2pre4/tivodecoder.c	2007-08-18 02:22:48.000000000 -0500
+++ tivodecode-0.3pre4/tivodecoder.c	2010-02-16 07:25:37.000000000 -0600
@@ -5,6 +5,7 @@
  * derived from mpegcat, copyright 2006 Kees Cook, used with permission
  */
 #include "tivodecoder.h"
+#include "hexlib.h"
 #include "Turing.h"
 #include <stdio.h>
 #ifdef HAVE_MEMORY_H
@@ -14,26 +15,7 @@
 /* TODO: clean this up */
 extern int o_verbose;
 extern int o_no_verify;
-
-typedef enum
-{
-    PACK_NONE,
-    PACK_SPECIAL,
-    PACK_PES_SIMPLE,            // packet length == data length
-    PACK_PES_COMPLEX,           // crazy headers need skipping
-}
-packet_type;
-
-typedef struct
-{
-    // the byte value match for the packet tags
-    unsigned char code_match_lo;      // low end of the range of matches
-    unsigned char code_match_hi;      // high end of the range of matches
-
-    // what kind of PES is it?
-    packet_type packet;
-}
-packet_tag_info;
+extern int o_ts_pkt_dump;
 
 static packet_tag_info packet_tags[] = {
     {0x00, 0x00, PACK_SPECIAL},     // pic start
@@ -58,6 +40,68 @@
     {0, 0, PACK_NONE}       // end of list
 };
 
+static ts_packet_tag_info ts_packet_tags[] = {
+    {0x0000, 0x0000, TS_PID_TYPE_PROGRAM_ASSOCIATION_TABLE},
+    {0x0001, 0x0001, TS_PID_TYPE_CONDITIONAL_ACCESS_TABLE},
+    {0x0002, 0x000F, TS_PID_TYPE_RESERVED},
+    {0x0010, 0x0010, TS_PID_TYPE_NETWORK_INFORMATION_TABLE},
+    {0x0011, 0x0011, TS_PID_TYPE_SERVICE_DESCRIPTION_TABLE},
+    {0x0012, 0x0012, TS_PID_TYPE_EVENT_INFORMATION_TABLE},
+    {0x0013, 0x0013, TS_PID_TYPE_RUNNING_STATUS_TABLE},
+    {0x0014, 0x0014, TS_PID_TYPE_TIME_DATE_TABLE},
+    {0x0015, 0x001F, TS_PID_TYPE_RESERVED},
+    {0x0020, 0x1FFE, TS_PID_TYPE_AUDIO_VIDEO_PRIVATE_DATA},
+    {0xFFFF, 0xFFFF, TS_PID_TYPE_NONE}
+};
+
+
+static ts_pmt_stream_type_info ts_pmt_stream_tags[] = {
+	// video
+	{ 0x01, 0x01, TS_STREAM_TYPE_VIDEO},		// MPEG1Video
+	{ 0x02, 0x02, TS_STREAM_TYPE_VIDEO},		// MPEG2Video
+	{ 0x10, 0x10, TS_STREAM_TYPE_VIDEO},		// MPEG4Video
+	{ 0x1b, 0x1b, TS_STREAM_TYPE_VIDEO},		// H264Video
+	{ 0x80, 0x80, TS_STREAM_TYPE_VIDEO},		// OpenCableVideo
+	{ 0xea, 0xea, TS_STREAM_TYPE_VIDEO},		// VC1Video
+ 
+	// audio
+	{ 0x03, 0x03, TS_STREAM_TYPE_AUDIO},		// MPEG1Audio
+	{ 0x04, 0x04, TS_STREAM_TYPE_AUDIO},		// MPEG2Audio
+	{ 0x11, 0x11, TS_STREAM_TYPE_AUDIO},		// MPEG2AudioAmd1
+	{ 0x0f, 0x0f, TS_STREAM_TYPE_AUDIO},		// AACAudio
+	{ 0x81, 0x81, TS_STREAM_TYPE_AUDIO},		// AC3Audio
+	{ 0x8a, 0x8a, TS_STREAM_TYPE_AUDIO},		// DTSAudio
+ 
+	// DSM-CC Object Carousel
+	{ 0x08, 0x08, TS_STREAM_TYPE_OTHER},		// DSMCC 
+	{ 0x0a, 0x0a, TS_STREAM_TYPE_OTHER}, 		// DSMCC_A
+	{ 0x0b, 0x0b, TS_STREAM_TYPE_OTHER}, 		// DSMCC_B 
+	{ 0x0c, 0x0c, TS_STREAM_TYPE_OTHER}, 		// DSMCC_C
+	{ 0x0d, 0x0d, TS_STREAM_TYPE_OTHER}, 		// DSMCC_D
+	{ 0x14, 0x14, TS_STREAM_TYPE_OTHER}, 		// DSMCC_DL
+	{ 0x15, 0x15, TS_STREAM_TYPE_OTHER}, 		// MetaDataPES    
+	{ 0x16, 0x16, TS_STREAM_TYPE_OTHER}, 		// MetaDataSec     
+	{ 0x17, 0x17, TS_STREAM_TYPE_OTHER}, 		// MetaDataDC      
+	{ 0x18, 0x18, TS_STREAM_TYPE_OTHER}, 		// MetaDataOC      
+	{ 0x19, 0x19, TS_STREAM_TYPE_OTHER}, 		// MetaDataDL      
+ 
+	// other
+	{ 0x05, 0x05, TS_STREAM_TYPE_OTHER}, 		// PrivSec         
+	{ 0x06, 0x06, TS_STREAM_TYPE_OTHER},		// PrivData        
+	{ 0x07, 0x07, TS_STREAM_TYPE_OTHER}, 		// MHEG            
+	{ 0x09, 0x09, TS_STREAM_TYPE_OTHER}, 		// H222_1          
+	{ 0x0e, 0x0e, TS_STREAM_TYPE_OTHER}, 		// MPEG2Aux        
+	{ 0x12, 0x12, TS_STREAM_TYPE_OTHER}, 		// FlexMuxPES      
+	{ 0x13, 0x13, TS_STREAM_TYPE_OTHER}, 		// FlexMuxSec      
+	{ 0x1a, 0x1a, TS_STREAM_TYPE_OTHER}, 		// MPEG2IPMP       
+	{ 0x7f, 0x7f, TS_STREAM_TYPE_OTHER},		// MPEG2IPMP2     
+
+	{ 0x97, 0x97, TS_STREAM_TYPE_PRIVATE_DATA},	// TiVo Private Data     
+	
+	{ 0x00, 0x00, TS_STREAM_TYPE_NONE}	
+};
+
+
 /**
  * This is from analyzing the TiVo directshow dll.  Most of the parameters I have no idea what they are for.
  *
@@ -146,7 +190,12 @@
 }
 
 #define LOOK_AHEAD(fh, bytes, n) do {\
-    if (read_handler((bytes) + looked_ahead, (n) - looked_ahead, fh) != (n) - looked_ahead) { \
+	int retval = read_handler((bytes) + looked_ahead, (n) - looked_ahead, fh);\
+	if ( retval == 0 )\
+	{\
+		return(0);	\
+	}\
+    else if ( retval != (n) - looked_ahead) { \
         perror ("read"); \
         return -1; \
     } else { \
@@ -155,9 +204,9 @@
 } while (0)
 
 /*
- * called for each frame
+ * called for each PS frame
  */
-int process_frame(unsigned char code, turing_state * turing, OFF_T_TYPE packet_start, void * packet_stream, read_func_t read_handler, void * ofh, write_func_t write_handler)
+int process_ps_frame(unsigned char code, turing_state * turing, OFF_T_TYPE packet_start, void * packet_stream, read_func_t read_handler, void * ofh, write_func_t write_handler)
 {
     static union {
 	    td_uint64_t align;
@@ -170,6 +219,8 @@
     unsigned int header_len = 0;
     unsigned int length;
 
+    memset( bytes, 0, 32 );
+
     for (i = 0; packet_tags[i].packet != PACK_NONE; i++)
     {
         if (code >= packet_tags[i].code_match_lo &&
@@ -223,22 +274,35 @@
                                     off += 4;
                                 }
 
-
                                 //private data flag
                                 if (bytes[ext_byte] & 0x80)
                                 {
-                                    int block_no, crypted;
+                                    int block_no	= 0;
+                                    int crypted		= 0;
+                                    
+									VERBOSE("\n\n---Turing : Key\n");
+									if ( IS_VERBOSE ) 
+										hexbulk( (unsigned char *)&bytes[off], 16 );
+									VERBOSE("---Turing : header : block %d crypted 0x%08x\n", block_no, crypted );
 
                                     if (do_header (&bytes[off], &block_no, NULL, &crypted, NULL, NULL))
                                     {
-                                        fprintf(stderr, "do_header not returned 0!\n");
+                                        fprintf(stderr, "do_header did not return 0!\n");
                                     }
 
-                                    if (o_verbose)
-                                        fprintf(stderr, "%10" OFF_T_FORMAT ": stream_no: %x, block_no: %d\n", packet_start, code, block_no);
+									VERBOSE("BBB : code 0x%02x, blockno %d, crypted 0x%08x\n", code, block_no, crypted );
+									VERBOSE("%Zu" OFF_T_FORMAT ": stream_no: %x, block_no: %d\n", packet_start, code, block_no);
+									VERBOSE("---Turing : prepare : code 0x%02x block_no %d\n", code, block_no );
 
                                     prepare_frame(turing, code, block_no);
+
+									VERBOSE("CCC : code 0x%02x, blockno %d, crypted 0x%08x\n", code, block_no, crypted );
+									VERBOSE("---Turing : decrypt : crypted 0x%08x len %d\n", crypted, 4 );
+
                                     decrypt_buffer(turing, (unsigned char *)&crypted, 4);
+
+									VERBOSE("DDD : code 0x%02x, blockno %d, crypted 0x%08x\n", code, block_no, crypted );
+
                                 }
 
                                 // STD buffer flag
@@ -288,7 +352,10 @@
 
                     if (scramble == 3)
                     {
-                        decrypt_buffer (turing, packet_ptr, packet_size);
+						VERBOSE("---Turing : decrypt : size %d\n", (int)packet_size );
+
+                        decrypt_buffer(turing, packet_ptr, packet_size);
+
                         // turn off scramble bits
                         aligned_buf.packet_buffer[sizeof(td_uint64_t)+2] &= ~0x30;
 
@@ -347,3 +414,978 @@
     return -1;
 }
 
+/*
+ * called for each TS frame
+ */
+
+int ts_fill_headers( TS_Stream * pStream )
+{
+	unsigned int ts_hdr_val		= 0;
+	unsigned short ts_adapt_val	= 0;
+	int i						= 0;
+	unsigned char * pPtr		= NULL;
+
+	if ( !pStream || !pStream->pPacket )
+	{
+		perror("Invalid TS header argument");
+		return(-1);
+	}
+
+	pPtr = pStream->pPacket;
+
+	// Yuck.  Make sure that we're dealing with the proper endianess.
+	// TS packet streams are big endian, and we may be running on little endian platform.
+
+	memset( &pStream->ts_header, 0, sizeof(TS_Header) );
+	ts_hdr_val	= portable_ntohl( pPtr );
+	pPtr		+= 4;
+
+	pStream->ts_header.sync_byte 					= ( ts_hdr_val & 0xff000000 ) >> 24;
+	pStream->ts_header.transport_error_indicator 	= ( ts_hdr_val & 0x00800000 ) >> 23;
+	pStream->ts_header.payload_unit_start_indicator	= ( ts_hdr_val & 0x00400000 ) >> 22;
+	pStream->ts_header.transport_priority 			= ( ts_hdr_val & 0x00200000 ) >> 21;
+	pStream->ts_header.pid 							= ( ts_hdr_val & 0x001FFF00 ) >> 8;
+	pStream->ts_header.transport_scrambling_control = ( ts_hdr_val & 0x000000C0 ) >> 6;
+	pStream->ts_header.adaptation_field_exists		= ( ts_hdr_val & 0x00000020 ) >> 5;
+	pStream->ts_header.payload_data_exists 			= ( ts_hdr_val & 0x00000010 ) >> 4;
+	pStream->ts_header.continuity_counter 			= ( ts_hdr_val & 0x0000000F );
+
+	if ( pStream->ts_header.sync_byte != 0x47 )
+	{
+		fprintf(stderr, "TS header : incorrect sync byte [%02x]\n", pStream->ts_header.sync_byte );
+		fprintf(stderr, "TS header : ts_hdr_val 0x%08x\n", ts_hdr_val );
+		return(-1);
+	}
+
+    for (i = 0; ts_packet_tags[i].ts_packet != TS_PID_TYPE_NONE; i++)
+    {
+        if (pStream->ts_header.pid >= ts_packet_tags[i].code_match_lo &&
+                pStream->ts_header.pid <= ts_packet_tags[i].code_match_hi)
+        {
+        	pStream->ts_packet_type = ts_packet_tags[i].ts_packet;
+        	break;
+        }
+    }
+
+	if ( pStream->ts_header.adaptation_field_exists )
+	{
+		memset( &pStream->ts_adapt, 0, sizeof(TS_Adaptation_Field) );
+		
+		ts_adapt_val											= portable_ntohs( pPtr );
+		pPtr++;
+		
+		pStream->ts_adapt.adaptation_field_length 				= (ts_adapt_val & 0xff00) >> 8;
+		pStream->ts_adapt.discontinuity_indicator 				= (ts_adapt_val & 0x0080) >> 7;
+		pStream->ts_adapt.random_access_indicator 				= (ts_adapt_val & 0x0040) >> 6;
+		pStream->ts_adapt.elementary_stream_priority_indicator 	= (ts_adapt_val & 0x0020) >> 5;
+		pStream->ts_adapt.pcr_flag 								= (ts_adapt_val & 0x0010) >> 4;
+		pStream->ts_adapt.opcr_flag 							= (ts_adapt_val & 0x0008) >> 3;
+		pStream->ts_adapt.splicing_point_flag 					= (ts_adapt_val & 0x0004) >> 2;
+		pStream->ts_adapt.transport_private_data_flag 			= (ts_adapt_val & 0x0002) >> 1;
+		pStream->ts_adapt.adaptation_field_extension_flag 		= (ts_adapt_val & 0x0001);
+		
+		pPtr += pStream->ts_adapt.adaptation_field_length;
+	}
+
+	pStream->payload_offset = (unsigned int)(pPtr - pStream->pPacket);
+	return(0);
+}
+
+
+void ts_dump_headers( OFF_T_TYPE ts_offset, TS_Stream * pStream )
+{
+    char pidType[50];
+
+	if ( !pStream )
+	{
+		perror("Invalid TS header argument");
+		return;
+	}
+
+	VERBOSE("TS   Offset 0x%zx (%Zu)\n", ts_offset,   ts_offset );
+	VERBOSE("MPEG Offset 0x%zx (%Zu)\n", ts_offset - pStream->initial_offset, ts_offset - pStream->initial_offset );
+	VERBOSE("Packet Counter 0x%08x (%d)\n", pStream->packet_counter, pStream->packet_counter );
+	
+	switch(pStream->ts_packet_type)
+	{
+		case TS_PID_TYPE_RESERVED 					: { sprintf(pidType,  "Reserved"); break; }
+		case TS_PID_TYPE_NULL_PACKET 				: { sprintf(pidType,  "NULL Packet"); break; }
+		case TS_PID_TYPE_PROGRAM_ASSOCIATION_TABLE 	: { sprintf(pidType,  "Program Association Table"); break; }
+		case TS_PID_TYPE_PROGRAM_MAP_TABLE 			: { sprintf(pidType,  "Program Map Table"); break; }
+		case TS_PID_TYPE_CONDITIONAL_ACCESS_TABLE 	: { sprintf(pidType,  "Conditional Access Table"); break; }
+		case TS_PID_TYPE_NETWORK_INFORMATION_TABLE 	: { sprintf(pidType,  "Network Information Table"); break; }
+		case TS_PID_TYPE_SERVICE_DESCRIPTION_TABLE 	: { sprintf(pidType,  "Service Description Table"); break; }
+		case TS_PID_TYPE_EVENT_INFORMATION_TABLE 	: {	sprintf(pidType,  "Event Information Table"); break; }
+		case TS_PID_TYPE_RUNNING_STATUS_TABLE 		: { sprintf(pidType,  "Running Status Table"); break; }
+		case TS_PID_TYPE_TIME_DATE_TABLE 			: { sprintf(pidType,  "Time Date Table"); break; }
+		case TS_PID_TYPE_NONE 						: { sprintf(pidType,  "None"); break; }
+		case TS_PID_TYPE_AUDIO_VIDEO_PRIVATE_DATA :
+		{
+			if ( pStream->ts_pat.program_map_pid == pStream->ts_header.pid )
+			{
+				sprintf(pidType,  "Program Map Table");
+			}
+			else
+			{
+				sprintf(pidType,  "Audio/Video/PrivateData");
+			}
+
+			break;
+		}
+
+		default :
+		{
+			sprintf(pidType,  "**** UNKNOWN ***");
+		}
+	}
+
+	VERBOSE("%-15s : %s\n", "TS Pkt header", pidType );
+	
+	VERBOSE("%-15s : %-25.25s : 0x%04x\n", "TS Pkt header", 
+			"sync_byte", pStream->ts_header.sync_byte );
+	VERBOSE("%-15s : %-25.25s : %06d\n", "TS Pkt header", 
+			"transport_error_indicator", pStream->ts_header.transport_error_indicator );
+	VERBOSE("%-15s : %-25.25s : %06d\n", "TS Pkt header", 
+			"payload_unit_start_indicator", pStream->ts_header.payload_unit_start_indicator);
+	VERBOSE("%-15s : %-25.25s : %06d\n", "TS Pkt header",
+			"transport_priority", pStream->ts_header.transport_priority);
+	VERBOSE("%-15s : %-25.25s : 0x%04x\n", "TS Pkt header",
+			"pid", pStream->ts_header.pid);
+	VERBOSE("%-15s : %-25.25s : %06d\n", "TS Pkt header",
+			"transport_scrambling_control", pStream->ts_header.transport_scrambling_control);
+	VERBOSE("%-15s : %-25.25s : %06d\n", "TS Pkt header",
+			"adaptation_field_exists", pStream->ts_header.adaptation_field_exists);
+	VERBOSE("%-15s : %-25.25s : %06d\n", "TS Pkt header",
+			"payload_data_exists", pStream->ts_header.payload_data_exists);
+	VERBOSE("%-15s : %-25.25s : %06d\n", "TS Pkt header",
+			"continuity_counter", pStream->ts_header.continuity_counter);
+
+    if ( pStream->ts_header.adaptation_field_exists )
+    {
+		VERBOSE("%-15s : %-25.25s : %06d\n", "TS Adaptation",
+				"adaptation_field_length", pStream->ts_adapt.adaptation_field_length);
+		
+		VERBOSE("%-15s : %-25.25s : %06d\n", "TS Adaptation",
+				"discontinuity_indicator", pStream->ts_adapt.discontinuity_indicator);
+		
+		VERBOSE("%-15s : %-25.25s : %06d\n", "TS Adaptation",
+				"random_access_indicator", pStream->ts_adapt.random_access_indicator);
+		
+		VERBOSE("%-15s : %-25.25s : %06d\n", "TS Adaptation",
+				"elementary_stream_priority_indicator", pStream->ts_adapt.elementary_stream_priority_indicator);
+		
+		VERBOSE("%-15s : %-25.25s : %06d\n", "TS Adaptation",
+				"pcr_flag", pStream->ts_adapt.pcr_flag);
+		
+		VERBOSE("%-15s : %-25.25s : %06d\n", "TS Adaptation",
+				"opcr_flag", pStream->ts_adapt.opcr_flag);
+		
+		VERBOSE("%-15s : %-25.25s : %06d\n", "TS Adaptation",
+				"splicing_point_flag", pStream->ts_adapt.splicing_point_flag);
+		
+		VERBOSE("%-15s : %-25.25s : %06d\n", "TS Adaptation",
+				"transport_private_data_flag",	pStream->ts_adapt.transport_private_data_flag);
+		
+		VERBOSE("%-15s : %-25.25s : %06d\n", "TS Adaptation",
+				"adaptation_field_extension_flag", pStream->ts_adapt.adaptation_field_extension_flag);
+	}
+    return;
+}
+
+
+int ts_handle_tivo_private_data( TS_Stream * pStream, turing_state * turing )
+{
+	unsigned char * pPtr	= NULL;
+	int	stream_loop			= 0;
+	unsigned int validator		= 0;
+	unsigned short pid			= 0;
+	unsigned char  stream_id	= 0;
+	unsigned short stream_bytes	= 0;		
+	unsigned int foundit		= 0;
+		
+	if ( !pStream || !pStream->pPacket )
+	{
+		perror("Invalid TS header argument");
+		return(-1);
+	}
+
+	pPtr = pStream->pPacket + pStream->payload_offset;
+
+	// TiVo Private Data format
+	// ------------------------
+	//   4 bytes   : validator -- "TiVo"
+	//   4 bytes   : Unknown -- always 0x81 0x3 0x7d 0x0 -- ???
+	//   2 bytes   : number of elementary stream bytes following
+	//   For each elementary stream :
+	//     2 byte  : packet id
+	//     1 byte  : stream id
+	//     1 byte  : Unknown -- always 0x10 -- reserved ???
+	//    16 bytes : Turing key
+
+	VERBOSE("\n");
+
+	validator = portable_ntohl( pPtr );
+	if ( validator != 0x5469566f )
+	{
+		perror("Invalid TiVo private data validator");
+		return(-1);
+	}
+
+	VERBOSE("%-15s : %-25.25s : 0x%08x (%c%c%c%c)\n",	"TiVo Private", 
+			"Validator", validator, *pPtr, *(pPtr+1), *(pPtr+2), *(pPtr+3) );
+
+	VERBOSE("%-15s : %-25.25s : 0x%x 0x%x 0x%x 0x%x\n", "TiVo Private", 
+			"Unknown", *(pPtr+4), *(pPtr+5), *(pPtr+6), *(pPtr+7) );
+
+	pPtr += 4;	// advance past "TiVo"
+
+	pPtr += 4;	// advance past ??? field
+
+	stream_bytes = portable_ntohs( pPtr );
+	pPtr += 2;	// advance past stream_bytes
+
+	VERBOSE("%-15s : %-25.25s : %d\n", "TiVo Private", 
+			"Stream Bytes", stream_bytes );
+
+	while ( stream_bytes > 0 )
+	{
+		pid = portable_ntohs( pPtr );
+		stream_bytes -= 2;
+		pPtr += 2;	// advance past pid
+
+		stream_id = *pPtr;
+		stream_bytes--;
+		pPtr++;		// advance past stream_id;
+
+		stream_bytes--;		
+		pPtr++;		// advance past reserved???
+
+		for ( foundit = 0, stream_loop = 0; stream_loop<TS_STREAM_ELEMENT_MAX; stream_loop++ )
+		{
+			if ( pStream->ts_stream_elem[stream_loop].stream_pid == pid )
+			{
+				foundit = 1;
+				pStream->ts_stream_elem[stream_loop].stream_id = stream_id;
+				
+				if ( memcmp( &pStream->ts_stream_elem[stream_loop].turing_stuff.key[0], pPtr, 16 ) )
+				{
+					VVERBOSE( "\nUpdating PID 0x%04x Type 0x%02x Turing Key\n", pid, stream_id );
+					if ( IS_VVERBOSE ) 
+					{
+						hexbulk( &pStream->ts_stream_elem[stream_loop].turing_stuff.key[0], 16 );
+						hexbulk( pPtr, 16 );
+					}
+
+					memcpy( &pStream->ts_stream_elem[stream_loop].turing_stuff.key[0], pPtr, 16);
+				}
+
+				VERBOSE("%-15s : %-25.25s : %d\n", "TiVo Private", "Block No", 
+						pStream->ts_stream_elem[stream_loop].turing_stuff.block_no );
+				VERBOSE("%-15s : %-25.25s : 0x%08x\n", "TiVo Private", "Crypted", 
+						pStream->ts_stream_elem[stream_loop].turing_stuff.crypted );
+				VERBOSE("%-15s : %-25.25s : 0x%04x (%d)\n", "TiVo Private", "PID", 
+						pStream->ts_stream_elem[stream_loop].stream_pid, 
+						pStream->ts_stream_elem[stream_loop].stream_pid );
+				VERBOSE("%-15s : %-25.25s : 0x%02x (%d)\n", "TiVo Private", "Stream ID", 
+						pStream->ts_stream_elem[stream_loop].stream_id,
+						pStream->ts_stream_elem[stream_loop].stream_id );
+				VERBOSE("%-15s : %-25.25s : ", "TiVo Private", "Turing Key" );
+				if ( IS_VERBOSE )
+					hexbulk( &pStream->ts_stream_elem[stream_loop].turing_stuff.key[0], 16 );
+				break;
+			}
+		}
+		
+		if ( !foundit )
+		{
+			perror("TiVo Private Data : Unmatched Stream ID");
+			return(-1);	
+		}
+
+		pPtr += 16;
+		stream_bytes -= 16;
+	}
+	
+	return(0);
+}
+
+
+int ts_handle_pmt( TS_Stream * pStream, turing_state * turing )
+{
+	unsigned short section_length	= 0;
+	unsigned short pmt_field		= 0;
+	unsigned short i				= 0;
+	unsigned char * pPtr			= NULL;
+
+	if ( !pStream || !pStream->pPacket )
+	{
+		perror("Invalid TS header argument");
+		return(-1);
+	}
+
+	VERBOSE("\n" );
+
+	pPtr = pStream->pPacket + pStream->payload_offset;
+
+	if ( pStream->ts_header.payload_unit_start_indicator )
+	{
+		pPtr++;	// advance past pointer field
+	}
+
+	// advance past table_id field
+	pPtr++;
+
+	pmt_field = portable_ntohs( pPtr );
+	section_length = pmt_field & 0x0fff;
+
+	// advance past section_length
+	pPtr += 2;
+
+	// advance past program/section/next numbers
+	pPtr += 9;
+	section_length -= 9;
+
+	// ignore the CRC for now
+	section_length -= 4;
+
+	for ( i=0; section_length > 0; i++ )
+	{
+		unsigned short es_info_length = 0;
+		char strTypeStr[25];
+		int foundit = 0;
+		int j = 0;
+
+		pStream->ts_stream_elem[i].stream_type_id = *pPtr;
+		for (j = 0; ts_pmt_stream_tags[j].ts_stream_type != TS_STREAM_TYPE_NONE; j++)
+		{
+			if ( ( pStream->ts_stream_elem[i].stream_type_id >= ts_pmt_stream_tags[j].code_match_lo )  &&
+				 ( pStream->ts_stream_elem[i].stream_type_id <= ts_pmt_stream_tags[j].code_match_hi ) )
+			{
+				pStream->ts_stream_elem[i].stream_type = ts_pmt_stream_tags[j].ts_stream_type;
+				foundit = 1;
+				break;
+		}
+		}
+		
+		if ( !foundit )
+		{
+			pStream->ts_stream_elem[i].stream_type_id = TS_STREAM_TYPE_PRIVATE_DATA;
+		}
+		
+		switch( pStream->ts_stream_elem[i].stream_type ) 
+		{
+			case TS_STREAM_TYPE_PRIVATE_DATA : sprintf(strTypeStr,"PrivateData"); break;
+			case TS_STREAM_TYPE_AUDIO 		 : sprintf(strTypeStr,"Audio"); break;
+			case TS_STREAM_TYPE_VIDEO		 : sprintf(strTypeStr,"Video"); break;
+			case TS_STREAM_TYPE_OTHER		 : sprintf(strTypeStr,"Other"); break;
+			default							 : sprintf(strTypeStr,"Unknown"); break;
+		}
+
+		// advance past stream_type field
+		pPtr++;
+		section_length--;
+
+		pmt_field = portable_ntohs( pPtr );
+		pStream->ts_stream_elem[i].stream_pid = pmt_field & 0x1fff;
+
+		// advance past elementary field
+		pPtr += 2;
+		section_length -= 2;
+
+		pmt_field = portable_ntohs( pPtr );
+		es_info_length = pmt_field & 0x1fff;
+
+		// advance past ES info length field
+		pPtr += 2;
+		section_length -= 2;
+
+		// advance past es info
+		pPtr += es_info_length;
+		section_length -= es_info_length;
+
+		VERBOSE("%-15s : StreamId 0x%x (%d), PID 0x%x (%d), Type 0x%0x (%d)(%s)\n", "TS ProgMapTbl",
+				pStream->ts_stream_elem[i].stream_type_id,
+				pStream->ts_stream_elem[i].stream_type_id,
+				pStream->ts_stream_elem[i].stream_pid,
+				pStream->ts_stream_elem[i].stream_pid,
+				pStream->ts_stream_elem[i].stream_type,
+				pStream->ts_stream_elem[i].stream_type,
+				strTypeStr );
+	}
+
+	return(0);
+}
+
+
+int ts_handle_pat( TS_Stream * pStream, turing_state * turing )
+{
+	unsigned short pat_field 			= 0;
+	unsigned short section_length		= 0;
+	unsigned short transport_stream_id 	= 0;
+	unsigned char * pPtr				= NULL;
+
+	VERBOSE("\n" );
+
+	if ( !pStream || !pStream->pPacket )
+	{
+		perror("Invalid TS header argument");
+		return(-1);
+	}
+
+	pPtr = pStream->pPacket + pStream->payload_offset;
+
+	if ( pStream->ts_header.payload_unit_start_indicator )
+	{
+		pPtr++;	// advance past pointer field
+	}
+
+	if ( *pPtr != 0x00 )
+	{
+		perror("PAT Table ID must be 0x00");
+		return(-1);
+	}
+	else
+	{
+		pPtr++;
+	}
+
+	pat_field = portable_ntohs( pPtr );
+	section_length = pat_field & 0x03ff;
+	pPtr += 2;
+
+	if ( (pat_field & 0xC000) != 0x8000 )
+	{
+		perror("Failed to validate PAT Misc field");
+		return(-1);
+	}
+
+	if ( (pat_field & 0x0C00) != 0x0000 )
+	{
+		perror("Failed to validate PAT MBZ of section length");
+		return(-1);
+	}
+
+	transport_stream_id = portable_ntohs( pPtr );
+	pPtr += 2;
+	section_length -= 2;
+
+	if ( (*pPtr & 0x3E) != pStream->ts_pat.version_number )
+	{
+		pStream->ts_pat.version_number = *pPtr & 0x3E;
+		VERBOSE( "%-15s : version changed : %d\n", "TS ProgAssocTbl",
+				pStream->ts_pat.version_number );
+	}
+
+	pPtr++;
+	section_length--;
+
+	pStream->ts_pat.section_number = *pPtr++;
+	section_length--;
+
+	pStream->ts_pat.last_section_number = *pPtr++;
+	section_length--;
+
+	section_length -= 4; // ignore the CRC for now
+
+	while ( section_length > 0 )
+	{
+		pat_field = portable_ntohs( pPtr );
+		VERBOSE( "%-15s : Program Num : %d\n", "TS ProgAssocTbl", pat_field );
+		pPtr += 2;
+		section_length -= 2;
+
+		pat_field = portable_ntohs( pPtr );
+
+		pStream->ts_pat.program_map_pid = pat_field & 0x1FFF;
+		VERBOSE( "%-15s : Program PID : 0x%x (%d)\n", "TS ProgAssocTbl",
+				pStream->ts_pat.program_map_pid, pStream->ts_pat.program_map_pid );
+		pPtr += 2;
+		section_length -= 2;
+	}
+
+	return(0);
+}
+
+
+int ts_handle_audio_video( TS_Stream * pStream, turing_state * turing )
+{
+	unsigned char * pPtr	= NULL;
+	unsigned int done		= 0;
+
+	if ( !pStream || !pStream->pPacket )
+	{
+		perror("Invalid TS header argument");
+		return(-1);
+	}
+
+	pPtr = pStream->pPacket + pStream->payload_offset;
+	
+	if ( !pStream->ts_header.payload_data_exists || !pStream->ts_header.transport_scrambling_control )
+	{
+		return(0);
+	}
+
+	if ( pStream->ts_header.transport_scrambling_control )
+	{
+		VVERBOSE( "\n--- Encrypted transport packet\n");
+		if ( IS_VVERBOSE )
+			hexbulk( (unsigned char *)pStream->pPacket, TS_FRAME_SIZE );
+	}
+
+	while (!done )
+	{
+		if ( (*(pPtr+0)!=0x00) || (*(pPtr+1)!=0x00)	|| (*(pPtr+2)!=0x01) )
+		{
+			// Invalid PES elementary start code
+			done = 1;
+			continue;
+		}
+
+		pPtr += 3;
+		pStream->ts_pes_packet.stream_id = *pPtr;
+		pPtr++;
+
+		VVERBOSE( "\n--- Elementary Stream : 0x%x (%d)\n",
+			pStream->ts_pes_packet.stream_id,
+			pStream->ts_pes_packet.stream_id );
+		
+		if ( pStream->ts_pes_packet.stream_id == EXTENSION_START_CODE )
+		{
+			unsigned int ext_hdr_len = 0;
+
+			if ( (*pPtr & 0x10) == 0x10 )
+			{
+				ext_hdr_len += 6;
+			}
+			else if ( (*pPtr & 0x20) == 0x20 )
+			{
+				if ( (*pPtr & 0x01) == 0x01 )
+				{
+					ext_hdr_len += 3;
+				}
+				ext_hdr_len += 9;
+			}
+			else if ( (*pPtr & 0x80) == 0x80 )
+			{
+				if ( (*(pPtr+4) & 0x40) == 0x40 )
+				{
+					ext_hdr_len += 2;
+				}
+				ext_hdr_len += 5;
+			}
+
+			pPtr += ext_hdr_len;
+			
+			while ( (*(pPtr+0)!=0x00) || (*(pPtr+1)!=0x00) || (*(pPtr+2)!=0x01) )
+			{
+				pPtr++;	
+			}
+			
+			
+			VERBOSE( "%-15s : %-25.25s : %d bytes\n", "TS PES Packet", 
+					"Extension header", ext_hdr_len );
+		}
+		else if ( pStream->ts_pes_packet.stream_id == GROUP_START_CODE )
+		{
+			VERBOSE("%-15s : %-25.25s : %d bytes\n", "TS PES Packet", "Group Of Pictures", 4 );
+			pPtr += 4;
+		}
+		else if ( pStream->ts_pes_packet.stream_id == USER_DATA_START_CODE )
+		{
+			unsigned char * pPtr2 = pPtr;
+			unsigned int i = 0;
+
+			while ( 1 )
+			{
+				if ( (*pPtr2==0x00)	&& ( *(pPtr2+1)==0x00) && ( *(pPtr2+2)==0x01) )
+				{
+					break;
+				}
+
+				i++;
+				pPtr2++;
+			}
+
+			VERBOSE( "%-15s : %-25.25s : %d bytes\n", "TS PES Packet", "User Data", i);
+			pPtr += i;
+		}
+		else if ( pStream->ts_pes_packet.stream_id == PICTURE_START_CODE )
+		{
+			VERBOSE( "%-15s : %-25.25s : %d bytes\n", "TS PES Packet", "Picture", 4 );
+			pPtr += 4;
+		}
+		else if ( pStream->ts_pes_packet.stream_id == SEQUENCE_HEADER_CODE )
+		{
+		    unsigned int PES_load_intra_flag		= 0;
+		    unsigned int PES_load_non_intra_flag	= 0;
+		    
+			VERBOSE( "%-15s : %-25.25s\n", "TS PES Packet", "Sequence header" );
+			pPtr += 7;
+
+			PES_load_intra_flag = *pPtr & 0x02;
+			if ( PES_load_intra_flag ) pPtr += 64;
+
+			PES_load_non_intra_flag = *pPtr & 0x01;
+			if ( PES_load_non_intra_flag ) pPtr += 64;
+
+			pPtr++;
+
+			VERBOSE( "%-15s : %-25.25s : %d\n", "TS PES Packet",
+					"PES_load_intra_flag", PES_load_intra_flag );
+
+			VERBOSE( "%-15s : %-25.25s : %d\n", "TS PES Packet",
+					"PES_load_non_intra_flag", PES_load_non_intra_flag );
+		}
+		else if ( ( pStream->ts_pes_packet.stream_id == 0xBD ) ||
+			 ( pStream->ts_pes_packet.stream_id >= 0xC0 && pStream->ts_pes_packet.stream_id <= 0xEF ) )
+		{
+			pStream->ts_pes_packet.pkt_length 					= portable_ntohs( pPtr );
+			pPtr += 2;
+			VVERBOSE( "%-15s : %-25.25s\n", "TS PES Packet", "Extension Hdr" );
+
+			pStream->ts_pes_packet.marker_bits					= (*pPtr & 0xc0) >> 6;
+			pStream->ts_pes_packet.scrambling_control			= (*pPtr & 0x30) >> 4;
+			pStream->ts_pes_packet.priority						= (*pPtr & 0x08) >> 3;
+			pStream->ts_pes_packet.data_alignment_indicator		= (*pPtr & 0x04) >> 2;
+			pStream->ts_pes_packet.copyright					= (*pPtr & 0x02) >> 1;
+			pStream->ts_pes_packet.original_or_copy				= (*pPtr & 0x01);
+			pPtr++;
+			pStream->ts_pes_packet.PTS_DTS_indicator			= (*pPtr & 0xc0) >> 6;
+			pStream->ts_pes_packet.ESCR_flag					= (*pPtr & 0x20) >> 5;
+			pStream->ts_pes_packet.ES_rate_flag					= (*pPtr & 0x10) >> 4;
+			pStream->ts_pes_packet.DSM_trick_mode_flag			= (*pPtr & 0x08) >> 3;
+			pStream->ts_pes_packet.additional_copy_info_flag	= (*pPtr & 0x04) >> 2;
+			pStream->ts_pes_packet.CRC_flag						= (*pPtr & 0x02) >> 1;
+			pStream->ts_pes_packet.extension_flag				= (*pPtr & 0x01);
+			pPtr++;
+			pStream->ts_pes_packet.PES_header_length			= *pPtr;
+			pPtr++;
+
+			pPtr += pStream->ts_pes_packet.PES_header_length;
+			
+			VVERBOSE("%-15s : %-25.25s : 0x%02x (%d)(%s)\n", "TS PES Packet",
+					"stream_id", pStream->ts_pes_packet.stream_id,	
+					pStream->ts_pes_packet.stream_id,
+					(pStream->ts_pes_packet.stream_id<0xe0) ? "audio" : "video" );
+			
+			VVERBOSE("%-15s : %-25.25s : 0x%04x (%d)\n", "TS PES Packet",
+					"pkt_length", pStream->ts_pes_packet.pkt_length, 
+					pStream->ts_pes_packet.pkt_length );
+			
+			VVERBOSE("%-15s : %-25.25s : 0x%x (%d)\n", "TS PES Packet",
+					"scrambling_control",
+					pStream->ts_pes_packet.scrambling_control,
+					pStream->ts_pes_packet.scrambling_control );
+			
+			VVERBOSE("%-15s : %-25.25s : %d\n", "TS PES Packet",
+					"priority", pStream->ts_pes_packet.priority );
+			
+			VVERBOSE("%-15s : %-25.25s : %d\n", "TS PES Packet",
+					"data_alignment_indicator",	
+					pStream->ts_pes_packet.data_alignment_indicator );
+			
+			VVERBOSE("%-15s : %-25.25s : %d\n", "TS PES Packet",
+					"copyright", pStream->ts_pes_packet.copyright );
+			
+			VVERBOSE("%-15s : %-25.25s : %d\n", "TS PES Packet",
+					"original_or_copy", pStream->ts_pes_packet.original_or_copy );
+			
+			VVERBOSE("%-15s : %-25.25s : 0x%x (%d)\n", "TS PES Packet",
+					"PTS_DTS_indicator",
+					pStream->ts_pes_packet.PTS_DTS_indicator,
+					pStream->ts_pes_packet.PTS_DTS_indicator );
+			
+			VVERBOSE("%-15s : %-25.25s : %d\n", "TS PES Packet",
+					"ESCR_flag", pStream->ts_pes_packet.ESCR_flag );
+			
+			VVERBOSE("%-15s : %-25.25s : %d\n", "TS PES Packet",
+					"ES_rate_flag", pStream->ts_pes_packet.ES_rate_flag );
+			
+			VVERBOSE("%-15s : %-25.25s : %d\n", "TS PES Packet",
+					"DSM_trick_mode_flag", pStream->ts_pes_packet.DSM_trick_mode_flag );
+			
+			VVERBOSE("%-15s : %-25.25s : %d\n", "TS PES Packet", 
+					"additional_copy_info_flag",
+					pStream->ts_pes_packet.additional_copy_info_flag );
+			
+			VVERBOSE("%-15s : %-25.25s : %d\n", "TS PES Packet",
+					"CRC_flag", pStream->ts_pes_packet.CRC_flag );
+			
+			VVERBOSE("%-15s : %-25.25s : %d\n", "TS PES Packet",
+					"extension_flag", pStream->ts_pes_packet.extension_flag );
+			
+			VVERBOSE("%-15s : %-25.25s : %d\n", "TS PES Packet",
+					"PES_header_length", pStream->ts_pes_packet.PES_header_length );
+
+/* 			switch( pStream->ts_pes_packet.PTS_DTS_indicator )
+			{
+				case 0x02 : pPtr +=  5; break;	// advance past PTS
+				case 0x03 : pPtr += 10; break;	// advance past PTS+DTS
+				case 0x00 : break;
+				default	  :
+				{
+					fprintf(stderr,"Invalid PES PTS/DTS indicator : 0x%x\n",
+							pStream->ts_pes_packet.PTS_DTS_indicator );
+					return(-1);
+				}
+			} */
+
+/* 			if ( pStream->ts_pes_packet.ESCR_flag ) 				pPtr += 4;
+			if ( pStream->ts_pes_packet.ES_rate_flag )				pPtr += 2;
+			if ( pStream->ts_pes_packet.additional_copy_info_flag )	pPtr += 1;
+			if ( pStream->ts_pes_packet.CRC_flag )					pPtr += 2;
+
+			if ( pStream->ts_pes_packet.extension_flag )
+			{
+			    unsigned int PES_priv_data	= (*pPtr & 0x80) ? 1 : 0;
+			    unsigned int PES_pack_hdr 	= (*pPtr & 0x40) ? 1 : 0;
+			    unsigned int PES_pkt_seq  	= (*pPtr & 0x20) ? 1 : 0;
+			    unsigned int PES_pstd_buf 	= (*pPtr & 0x10) ? 1 : 0;
+			    unsigned int PES_ext_flag2	= (*pPtr & 0x01) ? 1 : 0;
+
+				VVERBOSE("%-15s : %-25.25s : %d\n", "TS PES Ext",
+						"PES_priv_data", PES_priv_data );
+			
+				VVERBOSE("%-15s : %-25.25s : %d\n", "TS PES Ext",
+						"PES_pack_hdr", PES_pack_hdr );
+			
+				VVERBOSE("%-15s : %-25.25s : %d\n", "TS PES Ext",
+						"PES_pkt_seq", PES_pkt_seq );
+			
+				VVERBOSE("%-15s : %-25.25s : %d\n", "TS PES Ext",
+						"PES_pstd_buf", PES_pstd_buf );
+			
+				VVERBOSE("%-15s : %-25.25s : %d\n", "TS PES Ext",
+						"PES_ext_flag2", PES_ext_flag2 );
+
+				if ( PES_priv_data )
+				{
+					VVERBOSE("%-15s : %-25.25s\n", "TS PES Packet", "PES PRIVATE DATA" );
+					pPtr += 16;
+				}
+
+				if ( PES_pack_hdr )	pPtr += 1;
+				if ( PES_pkt_seq )	pPtr += 2;
+				if ( PES_pstd_buf )	pPtr += 2;
+				if ( PES_ext_flag2 )
+				{
+				    unsigned short PES_ext2_field 	= portable_ntohs( pPtr );
+					unsigned int PES_ext2_len		= (PES_ext2_field & 0x70) >> 8;
+					pPtr += 2;
+					pPtr += PES_ext2_len;
+					VVERBOSE("%-15s : %-25.25s : %d\n", "TS PES Packet", "PES_ext2_len", PES_ext2_len );
+				}
+			} */
+		}
+		else
+		{
+			perror("Unhandled PES header");
+			return(0);
+		}
+	}
+
+	if ( pStream->ts_header.transport_scrambling_control )
+	{
+		unsigned int foundit = 0;
+		int stream_loop		 = 0;
+		
+		// turn off crypto bits in TS header
+		unsigned char * pTsHeader = pStream->pPacket;
+		pTsHeader += 3;
+		*pTsHeader &= ~0xC0;
+		
+		for ( stream_loop = 0; stream_loop<TS_STREAM_ELEMENT_MAX; stream_loop++ )
+		{
+			if ( pStream->ts_stream_elem[stream_loop].stream_pid == pStream->ts_header.pid )
+			{
+				foundit = 1;
+				break;
+			}
+		}		
+		
+		if ( !foundit )
+		{
+			perror("Audio/Video Unmatched Encrypted Stream ID");
+			return(-1);
+		}
+		else
+		{
+	        if ( do_header(&pStream->ts_stream_elem[stream_loop].turing_stuff.key[0],
+	        		&(pStream->ts_stream_elem[stream_loop].turing_stuff.block_no), NULL,
+	        		&(pStream->ts_stream_elem[stream_loop].turing_stuff.crypted), NULL, NULL) )
+	        {
+	            perror("do_header did not return 0!\n");
+	            return(-1);
+	        }
+	
+			VVERBOSE( "BBB : stream_id 0x%02x, blockno %d, crypted 0x%08x\n", 
+					pStream->ts_stream_elem[stream_loop].stream_id,
+					pStream->ts_stream_elem[stream_loop].turing_stuff.block_no,
+					pStream->ts_stream_elem[stream_loop].turing_stuff.crypted );
+	
+	        prepare_frame( turing, pStream->ts_stream_elem[stream_loop].stream_id, 
+	        	pStream->ts_stream_elem[stream_loop].turing_stuff.block_no);
+	
+			VVERBOSE( "CCC : stream_id 0x%02x, blockno %d, crypted 0x%08x\n", 
+					pStream->ts_stream_elem[stream_loop].stream_id,
+					pStream->ts_stream_elem[stream_loop].turing_stuff.block_no,
+					pStream->ts_stream_elem[stream_loop].turing_stuff.crypted );
+	
+			// Do not need to do this for TS streams - crypted is zero and apparently not used
+	        // decrypt_buffer( turing, (unsigned char *)&pStream->ts_stream_elem[stream_loop].turing_stuff.crypted, 4);
+	
+			VVERBOSE( "DDD : stream_id 0x%02x, blockno %d, crypted 0x%08x\n", 
+					pStream->ts_stream_elem[stream_loop].stream_id,
+					pStream->ts_stream_elem[stream_loop].turing_stuff.block_no,
+					pStream->ts_stream_elem[stream_loop].turing_stuff.crypted );
+			
+			decrypt_buffer( turing, pPtr, TS_FRAME_SIZE - ((int)(pPtr - pStream->pPacket)) );
+	
+			VVERBOSE("---Decrypted transport packet\n");
+			if (IS_VVERBOSE)
+				hexbulk( (unsigned char *)pStream->pPacket, TS_FRAME_SIZE );
+		}
+	}
+
+	return(0);
+}
+
+
+int process_ts_frame(turing_state * turing, OFF_T_TYPE packet_start, void * packet_stream, read_func_t read_handler, void * ofh, write_func_t write_handler)
+{
+    static union
+   	{
+	    td_uint64_t align;
+	    unsigned char packet_buffer[TS_FRAME_SIZE + sizeof(td_uint64_t) + 2];
+    } aligned_buf;
+
+	static int tsStreamInit = 0;
+	static TS_Stream tsStream;
+
+    int looked_ahead = 0;
+    int err = 0;
+    int old_verbose_level = 0;
+
+    if ( !tsStreamInit )
+    {
+    	memset( &tsStream, 0, sizeof(TS_Stream) );
+		tsStream.pPacket 		= &aligned_buf.packet_buffer[sizeof(td_uint64_t)];
+		tsStream.initial_offset = packet_start;
+    	tsStreamInit 			= 1;
+    }
+
+	tsStream.packet_counter++;
+
+	if ( o_ts_pkt_dump != tsStream.packet_counter )
+	{
+		old_verbose_level = o_verbose;
+		o_verbose = 0;
+	}
+
+	LOOK_AHEAD(packet_stream, &aligned_buf.packet_buffer[sizeof(td_uint64_t)], TS_FRAME_SIZE);
+
+	if ( ts_fill_headers( &tsStream ) )
+	{
+		perror("Failed to fill TS headers");
+		o_verbose = old_verbose_level;
+		return (-1);
+	}
+
+	VVVERBOSE("\n ==================================== \n" );
+	if (IS_VVVERBOSE)
+	{
+		hexbulk( tsStream.pPacket, TS_FRAME_SIZE );
+		ts_dump_headers( packet_start, &tsStream );
+	}
+
+	switch ( tsStream.ts_packet_type )
+	{
+		case TS_PID_TYPE_RESERVED :
+		case TS_PID_TYPE_NULL_PACKET :
+		case TS_PID_TYPE_PROGRAM_MAP_TABLE :
+		case TS_PID_TYPE_CONDITIONAL_ACCESS_TABLE :
+		case TS_PID_TYPE_NETWORK_INFORMATION_TABLE :
+		case TS_PID_TYPE_SERVICE_DESCRIPTION_TABLE :
+		case TS_PID_TYPE_EVENT_INFORMATION_TABLE :
+		case TS_PID_TYPE_RUNNING_STATUS_TABLE :
+		case TS_PID_TYPE_TIME_DATE_TABLE :
+		{
+			break;
+		}
+		case TS_PID_TYPE_PROGRAM_ASSOCIATION_TABLE :
+		{
+			err = ts_handle_pat( &tsStream, turing );
+			if ( err )
+			{
+				perror("ts_handle_pat failed");
+			}
+			break;
+		}
+		case TS_PID_TYPE_AUDIO_VIDEO_PRIVATE_DATA :
+		{
+			if ( tsStream.ts_header.pid == tsStream.ts_pat.program_map_pid )
+			{
+				err = ts_handle_pmt( &tsStream, turing );
+				if ( err )
+				{
+					perror("ts_handle_pmt failed");
+				}
+			}
+			else
+			{
+				unsigned int i   			= 0;
+				unsigned int is_tivo_pkt	= 0;
+						
+				for ( i=0; i<TS_STREAM_ELEMENT_MAX; i++ )
+				{
+					if ( ( tsStream.ts_stream_elem[i].stream_pid == tsStream.ts_header.pid ) &&
+						 ( tsStream.ts_stream_elem[i].stream_type == TS_STREAM_TYPE_PRIVATE_DATA ) )
+					{
+						is_tivo_pkt = 1;
+						break;
+					}
+				}
+				
+				if ( is_tivo_pkt )
+				{
+					err = ts_handle_tivo_private_data( &tsStream, turing );
+					if ( err )
+					{
+						perror("ts_handle_tivo_private_data failed");
+					}
+				}
+				else
+				{
+					err = ts_handle_audio_video( &tsStream, turing );
+					if ( err )
+					{
+						perror("ts_handle_audio_video failed");
+					}
+				}					
+			}
+			break;
+		}
+		default :
+		{
+			perror( "Unknown Packet Type" );
+			o_verbose = old_verbose_level;			
+			return (-1);
+		}
+	}
+
+	if ( err )
+	{
+		o_verbose = old_verbose_level;		
+		return(err);
+	}
+
+	if (write_handler(aligned_buf.packet_buffer + sizeof(td_uint64_t), TS_FRAME_SIZE, ofh) != TS_FRAME_SIZE)
+	{
+		o_verbose = old_verbose_level;		
+		perror ("writing buffer");
+		return (-1);
+	}
+
+	o_verbose = old_verbose_level;
+	return looked_ahead;
+}
diff -urN tivodecode-0.2pre4/tivodecoder.h tivodecode-0.3pre4/tivodecoder.h
--- tivodecode-0.2pre4/tivodecoder.h	2007-04-20 20:23:24.000000000 -0500
+++ tivodecode-0.3pre4/tivodecoder.h	2010-02-16 07:26:04.000000000 -0600
@@ -13,13 +13,14 @@
 #include "tdconfig.h"
 #include <stddef.h>
 #ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
+#include <sys/types.h>
 #endif
 #ifdef HAVE_UNISTD_H
-# include <unistd.h>
+#include <unistd.h>
 #endif
 #include "turing_stream.h"
 
+
 #if SIZEOF_OFF_T == 8
 # define OFF_T_TYPE off_t
 # define OFF_T_FORMAT  "llu"
@@ -34,10 +35,212 @@
 
 typedef int (*write_func_t) (void * mem, int size, void * fh);
 
+#define PICTURE_START_CODE      0x00
+#define SLICE_START_CODE_MIN    0x01
+#define SLICE_START_CODE_MAX    0xAF
+#define USER_DATA_START_CODE    0xB2
+#define SEQUENCE_HEADER_CODE    0xB3
+#define SEQUENCE_ERROR_CODE     0xB4
+#define EXTENSION_START_CODE    0xB5
+#define SEQUENCE_END_CODE       0xB7
+#define GROUP_START_CODE        0xB8
+#define SYSTEM_START_CODE_MIN   0xB9
+#define SYSTEM_START_CODE_MAX   0xFF
+#define ISO_END_CODE            0xB9
+#define PACK_START_CODE         0xBA
+#define SYSTEM_START_CODE       0xBB
+#define VIDEO_ELEMENTARY_STREAM 0xe0
+
+#define TRANSPORT_STREAM        0x47
+
+#define TS_FRAME_SIZE 			188
+
+
+//============================
+// PS Specific data structures
+//============================
+
+typedef enum
+{
+    PACK_NONE,
+    PACK_SPECIAL,
+    PACK_PES_SIMPLE,            // packet length == data length
+    PACK_PES_COMPLEX,           // crazy headers need skipping
+}
+packet_type;
+
+
+typedef struct
+{
+    // the byte value match for the packet tags
+    unsigned char code_match_lo;      // low end of the range of matches
+    unsigned char code_match_hi;      // high end of the range of matches
+
+    // what kind of PES is it?
+    packet_type packet;
+}
+packet_tag_info;
+
+
+
+
+//============================
+// TS Specific data structures
+//============================
+
+typedef enum
+{
+	TS_PID_TYPE_RESERVED = 1,
+	TS_PID_TYPE_NULL_PACKET,
+	TS_PID_TYPE_PROGRAM_ASSOCIATION_TABLE,
+	TS_PID_TYPE_PROGRAM_MAP_TABLE,
+	TS_PID_TYPE_CONDITIONAL_ACCESS_TABLE,
+	TS_PID_TYPE_NETWORK_INFORMATION_TABLE,
+	TS_PID_TYPE_SERVICE_DESCRIPTION_TABLE,
+	TS_PID_TYPE_EVENT_INFORMATION_TABLE,
+	TS_PID_TYPE_RUNNING_STATUS_TABLE,
+	TS_PID_TYPE_TIME_DATE_TABLE,
+	TS_PID_TYPE_AUDIO_VIDEO_PRIVATE_DATA,
+	TS_PID_TYPE_NONE
+} ts_packet_pid_types;
+
+
+typedef enum
+{
+	TS_STREAM_TYPE_AUDIO = 1,
+	TS_STREAM_TYPE_VIDEO,
+	TS_STREAM_TYPE_PRIVATE_DATA,
+	TS_STREAM_TYPE_OTHER,
+	TS_STREAM_TYPE_NONE
+} ts_stream_types;
+
+
+typedef struct
+{
+    // the 16-bit value match for the packet pids
+    unsigned char code_match_lo;      // low end of the range of matches
+    unsigned char code_match_hi;      // high end of the range of matches
+
+    // what kind of TS packet is it?
+    ts_stream_types ts_stream_type;
+}
+ts_pmt_stream_type_info;
+
+
+#define TS_STREAM_ELEMENT_MAX 10
+
+typedef struct
+{
+    // the 16-bit value match for the packet pids
+    unsigned short code_match_lo;      // low end of the range of matches
+    unsigned short code_match_hi;      // high end of the range of matches
+
+    // what kind of TS packet is it?
+    ts_packet_pid_types ts_packet;
+}
+ts_packet_tag_info;
+
+
+typedef struct _TS_header
+{
+	unsigned int 	sync_byte:8;
+	unsigned int 	transport_error_indicator:1;
+	unsigned int 	payload_unit_start_indicator:1;
+	unsigned int	transport_priority:1;
+	unsigned int	pid:13;
+	unsigned int	transport_scrambling_control:2;
+	unsigned int	adaptation_field_exists:1;
+	unsigned int	payload_data_exists:1;
+	unsigned int	continuity_counter:4;
+}
+TS_Header;
+
+
+typedef struct _TS_adaptation_field
+{
+	unsigned short	adaptation_field_length:8;
+	unsigned short	discontinuity_indicator:1;
+	unsigned short	random_access_indicator:1;
+	unsigned short	elementary_stream_priority_indicator:1;
+	unsigned short	pcr_flag:1;
+	unsigned short	opcr_flag:1;
+	unsigned short	splicing_point_flag:1;
+	unsigned short	transport_private_data_flag:1;
+	unsigned short	adaptation_field_extension_flag:1;
+}
+TS_Adaptation_Field;
+
+
+typedef struct _TS_PAT_data
+{
+	unsigned char	version_number;
+	unsigned char	current_next_indicator;
+	unsigned char	section_number;
+	unsigned char	last_section_number;
+	unsigned short	program_map_pid;
+} TS_PAT_data;
+
+
+typedef struct _TS_Turing_Stuff
+{
+	int						block_no;
+	int						crypted;
+	unsigned char			unknown_field[4];
+	unsigned char			key[16];
+} TS_Turing_Stuff;
+
+
+typedef struct _TS_Prog_Elements
+{
+	unsigned char			stream_type_id;
+	unsigned int			stream_pid;
+	unsigned char			stream_id;
+	ts_stream_types			stream_type;
+	TS_Turing_Stuff			turing_stuff;
+} TS_Stream_Element;
+
+
+typedef struct _TS_PES_Packet
+{
+	unsigned char			stream_id;
+	unsigned short			pkt_length;
+	unsigned char			marker_bits:2;
+	unsigned char			scrambling_control:2;
+	unsigned char			priority:1;
+	unsigned char			data_alignment_indicator:1;
+	unsigned char			copyright:1;
+	unsigned char			original_or_copy:1;
+	unsigned char			PTS_DTS_indicator:2;
+	unsigned char			ESCR_flag:1;
+	unsigned char			ES_rate_flag:1;
+	unsigned char			DSM_trick_mode_flag:1;
+	unsigned char			additional_copy_info_flag:1;
+	unsigned char			CRC_flag:1;
+	unsigned char			extension_flag:1;
+	unsigned char			PES_header_length;
+} PES_packet;
+
+
+typedef struct _TS_Stream
+{
+	unsigned char			* pPacket;
+	unsigned int			payload_offset;
+	unsigned int			initial_offset;
+	unsigned int			packet_counter;
+	TS_Header				ts_header;
+	TS_Adaptation_Field		ts_adapt;
+	TS_PAT_data				ts_pat;
+	ts_packet_pid_types		ts_packet_type;
+	TS_Stream_Element		ts_stream_elem[TS_STREAM_ELEMENT_MAX];
+	PES_packet				ts_pes_packet;
+} TS_Stream;
+
+
 /*
  * called for each frame
  */
-int process_frame(unsigned char code, turing_state * turing, OFF_T_TYPE packet_start, void * packet_stream, read_func_t read_handler, void * ofh, write_func_t write_handler);
+int process_ps_frame(unsigned char code, turing_state * turing, OFF_T_TYPE packet_start, void * packet_stream, read_func_t read_handler, void * ofh, write_func_t write_handler);
+int process_ts_frame(turing_state * turing, OFF_T_TYPE packet_start, void * packet_stream, read_func_t read_handler, void * ofh, write_func_t write_handler);
 
 #ifdef __cplusplus
 }
diff -urN tivodecode-0.2pre4/turing_stream.c tivodecode-0.3pre4/turing_stream.c
--- tivodecode-0.2pre4/turing_stream.c	2007-08-06 01:40:18.000000000 -0500
+++ tivodecode-0.3pre4/turing_stream.c	2009-12-17 15:03:35.000000000 -0600
@@ -102,7 +102,7 @@
         if ((xml = read_tivo_chunk (tivofile, read_handler)) == NULL)
             return -1;
 
-        if (xml->data_size && xml->type == TIVO_CHUNK_XML)
+        if (xml->data_size && xml->type == TIVO_CHUNK_PLAINTEXT_XML )
         {
             setup_turing_key (turing, xml, mak);
             free(xml);
@@ -198,7 +198,7 @@
         (nxt) = (turing)->active; \
         (turing)->active->internal = TuringAlloc(); \
         if (o_verbose) \
-            fprintf(stderr, "Creating turing stream for packet type %02x\n", (stream_id)); \
+            fprintf(stdout, "Creating turing stream for packet type %02x\n", (stream_id)); \
         prepare_frame_helper((turing), (stream_id), (block_id)); \
     } while(0)