/[tivodecode]/tivodecode/trunk/tivodecoder.c
ViewVC logotype

Contents of /tivodecode/trunk/tivodecoder.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 66 - (hide annotations) (download)
Wed Dec 13 00:43:25 2006 UTC (15 years, 6 months ago) by jeremyd2019
File MIME type: text/plain
File size: 11848 byte(s)
make process_frame use a write function.  add target to make libtivodecode.a

1 jeremyd2019 65 /*
2     * tivodecode, (c) 2006, Jeremy Drake
3     * See COPYING file for license terms
4     *
5     * derived from mpegcat, copyright 2006 Kees Cook, used with permission
6     */
7     #include <stdio.h>
8     #include <memory.h>
9     #include "happyfile.h"
10     #include "turing_stream.h"
11     #include "tivodecoder.h"
12    
13     /* TODO: clean this up */
14     extern int o_verbose;
15     extern int o_no_verify;
16    
17     typedef enum
18     {
19     PACK_NONE,
20     PACK_SPECIAL,
21     PACK_PES_SIMPLE, // packet length == data length
22     PACK_PES_COMPLEX, // crazy headers need skipping
23     }
24     packet_type;
25    
26     typedef struct
27     {
28     // the byte value match for the packet tags
29     unsigned char code_match_lo; // low end of the range of matches
30     unsigned char code_match_hi; // high end of the range of matches
31    
32     // what kind of PES is it?
33     packet_type packet;
34     }
35     packet_tag_info;
36    
37     static packet_tag_info packet_tags[] = {
38     {0x00, 0x00, PACK_SPECIAL}, // pic start
39     {0x01, 0xAF, PACK_SPECIAL}, // video slices
40     {0xB0, 0xB1, PACK_SPECIAL}, // reserved
41     {0xB2, 0xB5, PACK_SPECIAL}, // user data, sequences
42     {0xB6, 0xB6, PACK_SPECIAL}, // reserved
43     {0xB7, 0xB9, PACK_SPECIAL}, // sequence, gop, end
44     {0xBA, 0xBA, PACK_SPECIAL}, // pack
45     {0xBB, 0xBB, PACK_PES_SIMPLE}, // system: same len as PES
46     {0xBC, 0xBC, PACK_PES_SIMPLE}, // PES: prog stream map *
47     {0xBD, 0xBD, PACK_PES_COMPLEX}, // PES: priv 1
48     {0xBE, 0xBF, PACK_PES_SIMPLE}, // PES: padding, priv 2 *
49     {0xC0, 0xDF, PACK_PES_COMPLEX}, // PES: Audio
50     {0xE0, 0xEF, PACK_PES_COMPLEX}, // PES: Video
51     {0xF0, 0xF2, PACK_PES_SIMPLE}, // PES: ecm, emm, dsmcc *
52     {0xF3, 0xF7, PACK_PES_COMPLEX}, // PES: iso 13522/h2221a-d
53     {0xF8, 0xF8, PACK_PES_SIMPLE}, // PES: h2221e *
54     {0xF9, 0xF9, PACK_PES_COMPLEX}, // PES: ancillary
55     {0xFA, 0xFE, PACK_PES_SIMPLE}, // PES: reserved
56     {0xFF, 0xFF, PACK_PES_SIMPLE}, // PES: prog stream dir *
57     {0, 0, PACK_NONE} // end of list
58     };
59    
60     /**
61     * This is from analyzing the TiVo directshow dll. Most of the parameters I have no idea what they are for.
62     *
63     * @param arg_0 pointer to the 16 byte private data section of the packet header.
64     * @param block_no pointer to an integer to contain the block number used in the turing key
65     * @param arg_8 no clue
66     * @param crypted pointer to an integer to contain 4 bytes of data encrypted
67     * with the same turing cipher as the video. No idea what to do with it once
68     * it is decrypted, tho, but the turing needs to have 4 bytes
69     * consumed in order to line up with the video/audio data. My
70     * guess is it is a checksum of some sort.
71     * @param arg_10 no clue
72     * @param arg_14 no clue
73     *
74     * @return count of particular bits which are zero. They should all be 1, so the return value should be zero.
75     * I would consider a non-zero return an error.
76     */
77     static int do_header(BYTE * arg_0, int * block_no, int * arg_8, int * crypted, int * arg_10, int * arg_14)
78     {
79     int var_4 = 0;
80    
81     if (!(arg_0[0] & 0x80))
82     var_4++;
83    
84     if (arg_10)
85     {
86     *arg_10 = (arg_0[0x0] & 0x78) >> 3;
87     }
88    
89     if (arg_14)
90     {
91     *arg_14 = (arg_0[0x0] & 0x07) << 1;
92     *arg_14 |= (arg_0[0x1] & 0x80) >> 7;
93     }
94    
95     if (!(arg_0[1] & 0x40))
96     var_4++;
97    
98     if (block_no)
99     {
100     *block_no = (arg_0[0x1] & 0x3f) << 0x12;
101     *block_no |= (arg_0[0x2] & 0xff) << 0xa;
102     *block_no |= (arg_0[0x3] & 0xc0) << 0x2;
103    
104     if (!(arg_0[3] & 0x20))
105     var_4++;
106    
107     *block_no |= (arg_0[0x3] & 0x1f) << 0x3;
108     *block_no |= (arg_0[0x4] & 0xe0) >> 0x5;
109     }
110    
111     if (!(arg_0[4] & 0x10))
112     var_4++;
113    
114     if (arg_8)
115     {
116     *arg_8 = (arg_0[0x4] & 0x0f) << 0x14;
117     *arg_8 |= (arg_0[0x5] & 0xff) << 0xc;
118     *arg_8 |= (arg_0[0x6] & 0xf0) << 0x4;
119    
120     if (!(arg_0[6] & 0x8))
121     var_4++;
122    
123     *arg_8 |= (arg_0[0x6] & 0x07) << 0x5;
124     *arg_8 |= (arg_0[0x7] & 0xf8) >> 0x3;
125     }
126    
127     if (crypted)
128     {
129     *crypted = (arg_0[0xb] & 0x03) << 0x1e;
130     *crypted |= (arg_0[0xc] & 0xff) << 0x16;
131     *crypted |= (arg_0[0xd] & 0xfc) << 0xe;
132    
133     if (!(arg_0[0xd] & 0x2))
134     var_4++;
135    
136     *crypted |= (arg_0[0xd] & 0x01) << 0xf;
137     *crypted |= (arg_0[0xe] & 0xff) << 0x7;
138     *crypted |= (arg_0[0xf] & 0xfe) >> 0x1;
139     }
140    
141     if (!(arg_0[0xf] & 0x1))
142     var_4++;
143    
144     return var_4;
145     }
146    
147     #define LOOK_AHEAD(fh, bytes, n) do {\
148     if (read_handler((bytes) + looked_ahead, (n) - looked_ahead, fh) != (n) - looked_ahead) { \
149     perror ("read"); \
150     return -1; \
151     } else { \
152     looked_ahead = (n); \
153     } \
154     } while (0)
155    
156     /*
157     * called for each frame
158     */
159 jeremyd2019 66 int process_frame(unsigned char code, turing_state * turing, off_t packet_start, void * packet_stream, read_func_t read_handler, void * ofh, write_func_t write_handler)
160 jeremyd2019 65 {
161     static unsigned char packet_buffer[65536 + 3];
162     unsigned char bytes[32];
163     int looked_ahead = 0;
164     int i;
165     int scramble=0;
166     unsigned int header_len = 0;
167     unsigned int length;
168    
169     for (i = 0; packet_tags[i].packet != PACK_NONE; i++)
170     {
171     if (code >= packet_tags[i].code_match_lo &&
172     code <= packet_tags[i].code_match_hi)
173     {
174     if (packet_tags[i].packet == PACK_PES_SIMPLE
175     || packet_tags[i].packet == PACK_PES_COMPLEX)
176     {
177     if (packet_tags[i].packet == PACK_PES_COMPLEX)
178     {
179     LOOK_AHEAD (packet_stream, bytes, 5);
180    
181     // packet_length is 0 and 1
182     // PES header variables
183     // | 2 | 3 | 4 |
184     // 76 54 3 2 1 0 76 5 4 3 2 1 0 76543210
185     // 10 scramble pts/dts pes_crc
186     // priority escr extension
187     // alignment es_rate header_data_length
188     // copyright dsm_trick
189     // copy addtl copy
190    
191     if ((bytes[2]>>6) != 0x2) {
192     fprintf(stderr, "PES (0x%02X) header mark != 0x2: 0x%x (is this an MPEG2-PS file?)\n",code,(bytes[2]>>6));
193     }
194    
195     scramble=((bytes[2]>>4)&0x3);
196    
197     header_len = 5 + bytes[4];
198    
199     if (scramble == 3)
200     {
201     if (bytes[3] & 0x1)
202     {
203     int off = 6;
204     int ext_byte = 5;
205     int goagain = 0;
206     // extension
207     if (header_len > 32)
208     return -1;
209    
210     LOOK_AHEAD (packet_stream, bytes, header_len);
211    
212     do
213     {
214     goagain = 0;
215    
216     //packet seq counter flag
217     if (bytes[ext_byte] & 0x20)
218     {
219     off += 4;
220     }
221    
222    
223     //private data flag
224     if (bytes[ext_byte] & 0x80)
225     {
226     int block_no, crypted;
227    
228     if (do_header (&bytes[off], &block_no, NULL, &crypted, NULL, NULL))
229     {
230     fprintf(stderr, "do_header not returned 0!\n");
231     }
232    
233     if (o_verbose)
234     fprintf(stderr, "%10" OFF_T_FORMAT ": stream_no: %x, block_no: %d\n", packet_start, code, block_no);
235    
236     prepare_frame(turing, code, block_no);
237     decrypt_buffer(turing, (unsigned char *)&crypted, 4);
238     }
239    
240     // STD buffer flag
241     if (bytes[ext_byte] & 0x10)
242     {
243     off += 2;
244     }
245    
246     // extension flag 2
247     if (bytes[ext_byte] & 0x1)
248     {
249     ext_byte = off;
250     off++;
251     goagain = 1;
252     continue;
253     }
254     } while (goagain);
255     }
256     }
257     }
258     else
259     {
260     LOOK_AHEAD (packet_stream, bytes, 2);
261     }
262    
263     length = bytes[1] | (bytes[0] << 8);
264    
265     memcpy (packet_buffer + 1, bytes, looked_ahead);
266    
267     LOOK_AHEAD (packet_stream, packet_buffer + 1, length + 2);
268     {
269     unsigned char * packet_ptr = packet_buffer + 1;
270     size_t packet_size;
271    
272     packet_buffer[0] = code;
273    
274     if (header_len)
275     {
276     packet_ptr += header_len;
277     packet_size = length - header_len + 2;
278     }
279     else
280     {
281     packet_ptr += 2;
282     packet_size = length;
283     }
284    
285     if (scramble == 3)
286     {
287     decrypt_buffer (turing, packet_ptr, packet_size);
288     // turn off scramble bits
289     packet_buffer[1+2] &= ~0x30;
290    
291     // scan video buffer for Slices. If no slices are
292     // found, the MAK is wrong.
293     if (!o_no_verify && code == 0xe0) {
294     int slice_count=0;
295     size_t offset;
296    
297     for (offset=0;offset+4<packet_size;offset++)
298     {
299     if (packet_buffer[offset] == 0x00 &&
300     packet_buffer[offset+1] == 0x00 &&
301     packet_buffer[offset+2] == 0x01 &&
302     packet_buffer[offset+3] >= 0x01 &&
303     packet_buffer[offset+3] <= 0xAF)
304     {
305     slice_count++;
306     }
307     // choose 8 as a good test that if 8 slices
308     // are seen, it's probably not random noise
309     if (slice_count>8)
310     {
311     // disable future verification
312     o_no_verify = 1;
313     }
314     }
315     if (!o_no_verify)
316     {
317     fprintf(stderr, "Invalid MAK -- aborting\n");
318     exit(20);
319     }
320     }
321     }
322     else if (code == 0xbc)
323     {
324     // don't know why, but tivo dll does this.
325     // I can find no good docs on the format of the program_stream_map
326     // but I think this clears a reserved bit. No idea why
327     packet_buffer[1+2] &= ~0x20;
328     }
329    
330 jeremyd2019 66 if (write_handler(packet_buffer, length + 3, ofh) != length + 3)
331 jeremyd2019 65 {
332     perror ("writing buffer");
333     }
334    
335     return 1;
336     }
337     }
338    
339     return 0;
340     }
341     }
342    
343     return -1;
344     }
345    

cvs@jdrake.com
ViewVC Help
Powered by ViewVC 1.1.13