Mercurial > mplayer.hg
annotate libmpdemux/demux_ty_osd.c @ 16946:47c5e9846cd3
ultra simple&slow pp filter, yes yet another spp like filter :)
this one does actually compress&decompress the video at various shifts with lavc while the other spp filters are doing optimized intra only filtering
limitations:
mpeg4 is hardcoded, all options too, pretty trivial to change though, even filtering with non dct codecs like snow could be tried ...
the qscale/qp is only taken fron the first MB of each image and then used for the whole image (would needs some small changes to lavc to let the user set the qscales for the mbs themselfs but iam to lazy ...)
this needs ALOT of cpu time and memory especially at uspp=8 ...
author | michael |
---|---|
date | Tue, 08 Nov 2005 13:15:19 +0000 |
parents | 6e35326c742f |
children | 6ff3379a0862 |
rev | line source |
---|---|
10263 | 1 // Most of this was written by mbm@linux.com and released on the GPL2 License. |
2 // | |
3 // Modifications and SEVERE cleanup of the code was done by | |
4 // Christopher Wingert | |
5 // Copyright 2003 | |
6 // | |
7 // Released under GPL2 License. | |
8 | |
9 #include <stdio.h> | |
10 #include <stdlib.h> | |
11 #include <unistd.h> | |
12 #include <time.h> | |
13 #include <stdarg.h> | |
10310
68e714ed669f
fix one missing #include, one missing extern and one 10l error.
rathann
parents:
10263
diff
changeset
|
14 #include <string.h> |
10263 | 15 |
16 #include "config.h" | |
17 #include "mp_msg.h" | |
18 #include "help_mp.h" | |
19 | |
20 //#include "stream.h" | |
21 //#include "demuxer.h" | |
22 //#include "parse_es.h" | |
23 //#include "stheader.h" | |
24 //#include "mp3_hdr.h" | |
25 //#include "../subreader.h" | |
26 #include "../sub_cc.h" | |
27 #include "../libvo/sub.h" | |
28 | |
29 //#include "dvdauth.h" | |
30 | |
31 extern int sub_justify; | |
32 | |
33 #define TY_TEXT_MODE ( 1 << 0 ) | |
34 #define TY_OSD_MODE ( 1 << 1 ) | |
35 | |
36 static int TY_OSD_flags = TY_TEXT_MODE | TY_OSD_MODE; | |
37 static int TY_OSD_debug = 0; | |
38 | |
39 // =========================================================================== | |
40 // Closed Caption Decoding and OSD Presentation | |
41 // =========================================================================== | |
42 #define TY_CCNONE ( -3 ) | |
43 #define TY_CCTEXTMODE ( -2 ) | |
44 #define TY_CCPOPUPNB ( -1 ) | |
45 #define TY_CCPOPUP ( 0 ) | |
46 #define TY_CCPAINTON ( 1 ) | |
47 | |
48 #define TY_CC_MAX_X ( 45 ) | |
49 | |
50 static int TY_CC_CUR_X; | |
51 static int TY_CC_CUR_Y; | |
52 static int TY_CC_stat = TY_CCNONE; | |
53 static char TY_CC_buf[ 255 ]; | |
54 static char *TY_CC_ptr = TY_CC_buf; | |
55 static unsigned TY_CC_lastcap = 0; | |
56 static int TY_CC_TextItalic; | |
57 static int TY_CC_Y_Offset; | |
58 | |
59 static subtitle ty_OSD1; | |
60 static subtitle ty_OSD2; | |
61 static subtitle *ty_pOSD1; | |
62 static subtitle *ty_pOSD2; | |
63 static int tyOSDInited = 0; | |
64 static int tyOSDUpdate = 0; | |
65 | |
66 static void ty_DrawOSD() | |
67 { | |
68 // printf( "Calling ty_DrawOSD()\n" ); | |
69 tyOSDUpdate = 1; | |
70 } | |
71 | |
72 void ty_ClearOSD( int start ) | |
73 { | |
74 int index; | |
75 // printf( "Calling ty_ClearOSD()\n" ); | |
76 for ( index = start ; index < SUB_MAX_TEXT ; index++ ) | |
77 { | |
78 memset( ty_OSD1.text[ index ], ' ', TY_CC_MAX_X - 1 ); | |
79 ty_OSD1.text[ index ][ TY_CC_MAX_X - 1 ] = 0; | |
80 memset( ty_OSD2.text[ index ], ' ', TY_CC_MAX_X - 1 ); | |
81 ty_OSD2.text[ index ][ TY_CC_MAX_X - 1 ] = 0; | |
82 } | |
83 } | |
84 | |
85 static void ty_DrawChar( int *x, int *y, char disChar, int fgColor, int bgColor ) | |
86 { | |
87 int index; | |
88 int cx; | |
89 int cy; | |
90 | |
91 cx = *x; | |
92 cy = *y; | |
93 | |
94 if ( *x >= ( TY_CC_MAX_X - 1 ) ) | |
95 { | |
96 cx = 0; | |
97 } | |
98 if ( ( *y + TY_CC_Y_Offset ) > SUB_MAX_TEXT ) | |
99 { | |
100 cy = SUB_MAX_TEXT - TY_CC_Y_Offset - 1; | |
101 } | |
102 | |
103 // printf( "Calling ty_DrawChar() x:%d y:%d %c fg:%d bg:%d\n", | |
104 // cx, cy, disChar, fgColor, bgColor ); | |
105 | |
106 ty_OSD1.text[ TY_CC_Y_Offset + cy ][ cx ] = disChar; | |
107 memset( &( ty_OSD1.text[ TY_CC_Y_Offset + cy ][ cx + 1 ] ), ' ', | |
108 TY_CC_MAX_X - cx - 2 ); | |
109 ( *x )++; | |
110 } | |
111 | |
112 static void ty_RollupBuf( int dest, int source, int numLines ) | |
113 { | |
114 int index; | |
115 | |
116 // printf( "Calling ty_RollupBuf() dest:%d source %d, numLines %d\n", | |
117 // dest, source, numLines ); | |
118 // | |
119 if ( ( source + TY_CC_Y_Offset + numLines ) > SUB_MAX_TEXT ) | |
120 { | |
121 ty_ClearOSD( 1 ); | |
122 return; | |
123 } | |
124 | |
125 if ( ( source + TY_CC_Y_Offset + numLines ) < 0 ) | |
126 { | |
127 ty_ClearOSD( 1 ); | |
128 return; | |
129 } | |
130 | |
131 if ( numLines > SUB_MAX_TEXT ) | |
132 { | |
133 ty_ClearOSD( 1 ); | |
134 return; | |
135 } | |
136 | |
137 for ( index = 0 ; index < numLines ; index++ ) | |
138 { | |
139 strcpy( ty_OSD1.text[ TY_CC_Y_Offset + dest ], | |
140 ty_OSD1.text[ TY_CC_Y_Offset + source ] ); | |
141 dest++; | |
142 source++; | |
143 } | |
144 memset( ty_OSD1.text[ TY_CC_Y_Offset + source - 1 ], ' ', TY_CC_MAX_X - 1 ); | |
145 ty_OSD1.text[ TY_CC_Y_Offset + source - 1 ][ TY_CC_MAX_X - 1 ] = 0; | |
146 } | |
147 | |
148 static void ty_drawchar( char c ) | |
149 { | |
150 if ( c < 2 ) return; | |
151 | |
152 if ( TY_OSD_flags & TY_OSD_MODE && TY_CC_stat != TY_CCNONE && | |
153 TY_CC_CUR_Y != -1 ) | |
154 ty_DrawChar( &TY_CC_CUR_X, &TY_CC_CUR_Y, c, 4, 13 ); | |
155 | |
156 if ( TY_CC_ptr - TY_CC_buf > sizeof( TY_CC_buf ) - 1 ) | |
157 { // buffer overflow | |
158 TY_CC_ptr = TY_CC_buf; | |
159 memset( TY_CC_buf, 0, sizeof( TY_CC_buf ) ); | |
160 } | |
161 *( TY_CC_ptr++ ) = ( c == 14 ) ? '/' : c; // swap a '/' for musical note | |
162 } | |
163 | |
164 static void ty_draw() | |
165 { | |
166 if ( TY_CC_ptr != TY_CC_buf && TY_OSD_flags & TY_TEXT_MODE ) | |
167 { | |
168 if ( *( TY_CC_ptr - 1 ) == '\n' ) *( TY_CC_ptr - 1 ) = 0; | |
169 | |
170 mp_msg( MSGT_DEMUX, MSGL_V, "CC: %s\n", TY_CC_buf ); | |
171 } | |
172 TY_CC_lastcap = time( NULL ); | |
173 | |
174 TY_CC_ptr = TY_CC_buf; | |
175 memset( TY_CC_buf, 0, sizeof( TY_CC_buf) ); | |
176 | |
177 if ( TY_OSD_flags & TY_OSD_MODE ) ty_DrawOSD(); | |
178 if ( TY_CC_TextItalic ) TY_CC_TextItalic = 0; | |
179 } | |
180 | |
181 | |
182 static int CC_last = 0; | |
183 static char CC_mode = 0; | |
184 static int CC_row[] = | |
185 { | |
186 11, -1, 1, 2, 3, 4, 12, 13, 14, 15, 5, 6, 7, 8, 9, 10 | |
187 }; | |
188 | |
189 // char specialchar[] = { '®', '°', '½', '¿', '*', '¢', '£', 14, 'à ', ' ', 'è', 'â', 'ê', 'î', 'ô', 'û' }; | |
190 | |
191 static int ty_CCdecode( char b1, char b2 ) | |
192 { | |
193 int x; | |
194 int data = ( b2 << 8 ) + b1; | |
195 | |
196 if ( b1 & 0x60 ) // text | |
197 { | |
198 if ( !TY_OSD_debug && TY_CC_stat == TY_CCNONE ) return 0; | |
199 if ( TY_OSD_debug > 3 ) | |
200 { | |
201 mp_msg( MSGT_DEMUX, MSGL_DBG3, "%c %c", b1, b2 ); | |
202 } | |
203 ty_drawchar( b1 ); | |
204 ty_drawchar( b2 ); | |
205 | |
206 if ( TY_CC_stat > 0 && TY_OSD_flags & TY_OSD_MODE ) ty_DrawOSD(); | |
207 } | |
208 else if ( ( b1 & 0x10 ) && ( b2 > 0x1F ) && ( data != CC_last ) ) | |
209 { | |
210 #define CURRENT ( ( b1 & 0x08 ) >> 3 ) | |
211 | |
212 if ( CC_mode != CURRENT && TY_CC_stat != TY_CCNONE ) | |
213 { | |
214 if ( TY_OSD_debug && TY_CC_ptr != TY_CC_buf ) ty_draw(); | |
215 TY_CC_stat = TY_CCNONE; | |
216 return 0; | |
217 } | |
218 | |
219 if ( TY_CC_stat == TY_CCNONE || TY_CC_CUR_Y == -1 ) | |
220 { | |
221 if ( TY_CC_ptr != TY_CC_buf ) | |
222 { | |
223 if ( TY_OSD_debug ) | |
224 mp_msg( MSGT_DEMUX, MSGL_DBG3, "(TY_OSD_debug) %s\n", | |
225 TY_CC_buf ); | |
226 TY_CC_ptr = TY_CC_buf; | |
227 memset(TY_CC_buf, 0, sizeof(TY_CC_buf)); | |
228 } | |
229 | |
230 if ( CC_mode != CURRENT ) return 0; | |
231 } | |
232 | |
233 // preamble address code (row & indent) | |
234 if ( b2 & 0x40 ) | |
235 { | |
236 TY_CC_CUR_Y = CC_row[ ( ( b1 << 1 ) & 14 ) | ( ( b2 >> 5 ) & 1 ) ]; | |
237 | |
238 // Offset into MPlayer's Buffer | |
239 if ( ( TY_CC_CUR_Y >= 1 ) && ( TY_CC_CUR_Y <= 4 ) ) | |
240 { | |
241 TY_CC_Y_Offset = SUB_MAX_TEXT - 5 - 1; | |
242 } | |
243 if ( ( TY_CC_CUR_Y >= 5 ) && ( TY_CC_CUR_Y <= 10 ) ) | |
244 { | |
245 TY_CC_Y_Offset = SUB_MAX_TEXT - 5 - 5; | |
246 } | |
247 if ( ( TY_CC_CUR_Y >= 12 ) && ( TY_CC_CUR_Y <= 15 ) ) | |
248 { | |
249 TY_CC_Y_Offset = SUB_MAX_TEXT - 5 - 12; | |
250 } | |
251 | |
252 if ( TY_OSD_debug > 3 ) | |
253 mp_msg( MSGT_DEMUX, MSGL_DBG3, "<< preamble %d >>\n", TY_CC_CUR_Y ); | |
254 | |
255 // we still have something in the text buffer | |
256 if (TY_CC_ptr != TY_CC_buf) | |
257 { | |
258 *(TY_CC_ptr++) = '\n'; | |
259 if ( TY_CC_TextItalic ) | |
260 { | |
261 TY_CC_TextItalic = 0; | |
262 } | |
263 } | |
264 | |
265 TY_CC_CUR_X = 1; | |
266 // row contains indent flag | |
267 if ( b2 & 0x10 ) | |
268 { | |
269 for ( x = 0 ; x < ( ( b2 & 0x0F ) << 1 ) ; x++ ) | |
270 { | |
271 TY_CC_CUR_X++; | |
272 *(TY_CC_ptr++) = ' '; | |
273 } | |
274 } | |
275 } | |
276 else | |
277 // !(b2 & 0x40) | |
278 { | |
279 if ( TY_OSD_debug > 3 ) | |
280 mp_msg( MSGT_DEMUX, MSGL_DBG3, "<< %02x >>\n", b1 & 0x7 ); | |
281 switch (b1 & 0x07) | |
282 { | |
283 case 0x00: // attribute | |
284 { | |
285 if ( TY_OSD_debug > 1 ) | |
286 mp_msg( MSGT_DEMUX, MSGL_DBG3, "<<A: %d>>\n", b2 ); | |
287 break; | |
288 } | |
289 case 0x01: // midrow or char | |
290 { | |
291 switch (b2 & 0x70) | |
292 { | |
293 case 0x20: // midrow attribute change | |
294 { | |
295 switch (b2 & 0x0e) | |
296 { | |
297 case 0x00: // italics off | |
298 { | |
299 TY_CC_TextItalic = 0; | |
300 *(TY_CC_ptr++) = ' '; | |
301 break; | |
302 } | |
303 case 0x0e: // italics on | |
304 { | |
305 ty_drawchar(' '); | |
306 TY_CC_TextItalic = 1; | |
307 break; | |
308 } | |
309 default: | |
310 { | |
311 if ( TY_OSD_debug > 1 ) | |
312 mp_msg( MSGT_DEMUX, MSGL_DBG3, "<<D: %d>>\n", | |
313 b2 & 0x0e ); | |
314 } | |
315 } | |
316 if ( b2 & 0x01 ) | |
317 { | |
318 // TextUnderline = 1; | |
319 } | |
320 else | |
321 { | |
322 // TextUnderline = 0; | |
323 } | |
324 break; | |
325 } | |
326 case 0x30: // special character.. | |
327 { | |
328 // transparent space | |
329 if ( ( b2 & 0x0f ) == 9 ) | |
330 { | |
331 TY_CC_CUR_X++; | |
332 *(TY_CC_ptr++) = ' '; | |
333 } | |
334 else | |
335 { | |
336 // ty_drawchar(specialchar[ b2 & 0x0f ] ); | |
337 ty_drawchar( ' ' ); | |
338 } | |
339 break; | |
340 } | |
341 } | |
342 break; | |
343 } | |
344 | |
345 case 0x04: // misc | |
346 case 0x05: // misc + F | |
347 { | |
348 if ( TY_OSD_debug > 3 ) | |
349 mp_msg( MSGT_DEMUX, MSGL_DBG3, "<< misc %02x >>\n", b2 ); | |
350 switch ( b2 ) | |
351 { | |
352 case 0x20: // resume caption (new caption) | |
353 { | |
354 if ( TY_OSD_flags & TY_OSD_MODE && | |
355 TY_CC_stat != TY_CCPOPUP ) | |
356 ty_ClearOSD( 1 ); | |
357 TY_CC_stat = TY_CCPOPUP; | |
358 break; | |
359 } | |
360 | |
361 case 0x21: // backspace | |
362 { | |
363 TY_CC_CUR_X--; | |
364 break; | |
365 } | |
366 | |
367 case 0x25 ... 0x27: // 2-4 row captions | |
368 { | |
369 if ( TY_CC_stat == TY_CCPOPUP ) ty_ClearOSD( 1 ); | |
370 TY_CC_stat = b2 - 0x23; | |
371 if ( TY_CC_CUR_Y < TY_CC_stat ) TY_CC_CUR_Y = TY_CC_stat; | |
372 break; | |
373 } | |
374 | |
375 case 0x29: // resume direct caption | |
376 { | |
377 TY_CC_stat = TY_CCPAINTON; | |
378 break; | |
379 } | |
380 | |
381 case 0x2A: // text restart | |
382 { | |
383 ty_draw(); | |
384 /* FALL */ | |
385 } | |
386 | |
387 case 0x2B: // resume text display | |
388 { | |
389 TY_CC_stat = TY_CCTEXTMODE; | |
390 break; | |
391 } | |
392 | |
393 case 0x2C: // erase displayed memory | |
394 { | |
395 TY_CC_lastcap = 0; | |
396 if ( TY_OSD_flags & TY_OSD_MODE ) | |
397 { | |
398 if ( TY_CC_stat > TY_CCPOPUP || TY_CC_ptr == TY_CC_buf ) | |
399 { | |
400 ty_ClearOSD( 1 ); | |
401 ty_draw(); | |
402 } | |
403 else | |
404 { | |
405 ty_ClearOSD( 1 ); | |
406 | |
407 // CRW - | |
408 // new buffer | |
409 // Used to be a buffer swap here, dunno why | |
410 } | |
411 } | |
412 break; | |
413 } | |
414 | |
415 case 0x2D: // carriage return | |
416 { | |
417 ty_draw(); | |
418 TY_CC_CUR_X = 1; | |
419 if ( TY_OSD_flags & TY_OSD_MODE ) | |
420 { | |
421 if ( TY_CC_stat > TY_CCPAINTON ) | |
422 ty_RollupBuf | |
423 ( | |
424 TY_CC_CUR_Y - TY_CC_stat + 1 , | |
425 TY_CC_CUR_Y - TY_CC_stat + 2, | |
426 TY_CC_stat - 1 | |
427 ); | |
428 else | |
429 TY_CC_CUR_Y++; | |
430 } | |
431 break; | |
432 } | |
433 | |
434 case 0x2F: // end caption + swap memory | |
435 { | |
436 ty_draw(); | |
437 /* FALL THROUGH TO 0x2E */ | |
438 } | |
439 | |
440 case 0x2E: // erase non-displayed memory | |
441 { | |
442 if ( TY_OSD_debug && TY_CC_ptr != TY_CC_buf ) | |
443 mp_msg( MSGT_DEMUX, MSGL_DBG3, "(TY_OSD_debug) %s\n", | |
444 TY_CC_buf ); | |
445 if ( TY_OSD_flags & TY_OSD_MODE ) ty_ClearOSD( 1 ); | |
446 | |
447 TY_CC_CUR_X = 1; | |
448 TY_CC_CUR_Y = -1; | |
449 | |
450 TY_CC_ptr = TY_CC_buf; | |
451 memset( TY_CC_buf, 0, sizeof( TY_CC_buf ) ); | |
452 } | |
453 } | |
454 break; | |
455 } | |
456 case 0x07: // misc (TAB) | |
457 { | |
458 for ( x = 0 ; x < ( b2 - 0x20 ) ; x++ ) | |
459 TY_CC_CUR_X++; | |
460 break; | |
461 } | |
462 } | |
463 } | |
464 } | |
465 CC_last = data; | |
466 return 0; | |
467 } | |
468 | |
469 // =========================================================================== | |
470 // Extended Data Service Decoding and OSD Presentation | |
471 // =========================================================================== | |
472 #define XDS_BUFFER_LENGTH ( 16 ) | |
473 #define XDS_DISPLAY_FRAMES ( 120 ) | |
474 static char *ty_XDS_Display[ XDS_BUFFER_LENGTH ]; | |
475 static int ty_XDSAddLine = -1; | |
476 static int ty_XDSDisplayCount = -1; | |
477 | |
478 | |
479 static void ty_AddXDSToDisplay( char *format, ... ) | |
480 { | |
481 char line[ 80 ]; | |
482 int index; | |
483 va_list ap; | |
484 | |
485 if ( ty_XDSAddLine == -1 ) | |
486 { | |
487 for( index = 0 ; index < XDS_BUFFER_LENGTH ; index++ ) | |
488 { | |
489 ty_XDS_Display[ index ] = 0; | |
490 } | |
491 ty_XDSAddLine = 0; | |
492 } | |
493 | |
494 va_start( ap, format ); | |
495 vsnprintf( line, 80, format, ap ); | |
496 va_end( ap ); | |
497 mp_msg( MSGT_DEMUX, MSGL_V, "XDS: %s\n", line ); | |
498 | |
499 if ( ty_XDSAddLine == XDS_BUFFER_LENGTH ) | |
500 { | |
501 mp_msg( MSGT_DEMUX, MSGL_ERR, "XDS Buffer would have been blown\n" ); | |
502 } | |
503 | |
504 if ( ty_XDS_Display[ ty_XDSAddLine ] != 0 ) | |
505 { | |
506 free( ty_XDS_Display[ ty_XDSAddLine ] ); | |
507 ty_XDS_Display[ ty_XDSAddLine ] = 0; | |
508 } | |
509 | |
510 ty_XDS_Display[ ty_XDSAddLine ] = malloc( strlen( line ) + 1 ); | |
511 strcpy( ty_XDS_Display[ ty_XDSAddLine ], line ); | |
512 ty_XDSAddLine++; | |
513 } | |
514 | |
515 | |
516 static void ty_DisplayXDSInfo() | |
517 { | |
518 int index; | |
519 int size; | |
520 | |
521 if ( ty_XDSDisplayCount == -1 ) | |
522 { | |
523 for( index = 0 ; index < XDS_BUFFER_LENGTH ; index++ ) | |
524 { | |
525 if ( ty_XDS_Display[ index ] != 0 ) | |
526 { | |
527 break; | |
528 } | |
529 } | |
530 if ( index != XDS_BUFFER_LENGTH ) | |
531 { | |
532 size = strlen( ty_XDS_Display[ index ] ); | |
533 | |
534 // Right Justify the XDS Stuff | |
535 memcpy( &( ty_OSD1.text[ 0 ][ TY_CC_MAX_X - size - 1 ] ), | |
536 ty_XDS_Display[ index ], size ); | |
537 free( ty_XDS_Display[ index ] ); | |
538 ty_XDS_Display[ index ] = 0; | |
539 ty_XDSDisplayCount = 0; | |
540 tyOSDUpdate = 1; | |
541 | |
542 } | |
543 else | |
544 { | |
545 // We cleaned out all the XDS stuff to be displayed | |
546 ty_XDSAddLine = 0; | |
547 } | |
548 } | |
549 else | |
550 { | |
551 // We displayed that piece of XDS information long enough | |
11000 | 552 // Let's move on |
10263 | 553 ty_XDSDisplayCount++; |
554 if ( ty_XDSDisplayCount >= XDS_DISPLAY_FRAMES ) | |
555 { | |
556 memset( ty_OSD1.text[ 0 ], ' ', TY_CC_MAX_X - 1 ); | |
557 ty_OSD1.text[ 0 ][ TY_CC_MAX_X - 1 ] = 0; | |
558 ty_XDSDisplayCount = -1; | |
559 tyOSDUpdate = 1; | |
560 } | |
561 } | |
562 } | |
563 | |
564 | |
565 static int TY_XDS_mode = 0; | |
566 static int TY_XDS_type = 0; | |
567 static int TY_XDS_length = 0; | |
568 static char TY_XDS_checksum = 0; | |
569 | |
570 // Array of [ Mode ][ Type ][ Length ] | |
571 static char TY_XDS [ 8 ][ 25 ][ 34 ]; | |
572 static char TY_XDS_new[ 8 ][ 25 ][ 34 ]; | |
573 | |
574 // Array of [ MPAARating|TVRating ][ NumberRatings ] | |
575 static char *TY_XDS_CHIP[ 2 ][ 8 ] = | |
576 { | |
577 { "(NOT APPLICABLE)", "G", "PG", "PG-13", "R", "NC-17", "X", "(NOT RATED)" }, | |
578 { "(NOT RATED)", "TV-Y", "TV-Y7", "TV-G", "TV-PG", "TV-14", "TV-MA", | |
579 "(NOT RATED)" } | |
580 }; | |
581 | |
582 static char *TY_XDS_modes[] = | |
583 { | |
584 "CURRENT", // 01h-02h current program | |
585 "FUTURE ", // 03h-04h future program | |
586 "CHANNEL", // 05h-06h channel | |
587 "MISC. ", // 07h-08h miscellaneous | |
588 "PUBLIC ", // 09h-0Ah public service | |
589 "RESERV.", // 0Bh-0Ch reserved | |
590 "UNDEF. ", | |
591 "INVALID", | |
592 "INVALID", | |
593 "INVALID" | |
594 }; | |
595 | |
596 static int ty_XDSdecode( char b1, char b2 ) | |
597 { | |
598 char line[ 80 ]; | |
599 | |
600 if ( b1 < 0x0F ) | |
601 { // start packet | |
602 TY_XDS_length = 0; | |
603 TY_XDS_mode = b1 >> 1; // every other mode is a resume | |
604 TY_XDS_type = b2; | |
605 TY_XDS_checksum = b1 + b2; | |
606 return 0; | |
607 } | |
608 | |
609 TY_XDS_checksum += b1 + b2; | |
610 | |
611 // eof (next byte is checksum) | |
612 if ( b1 == 0x0F ) | |
613 { | |
614 // validity check | |
615 if ( !TY_XDS_length || TY_XDS_checksum & 0x7F ) | |
616 { | |
617 if ( TY_OSD_debug > 3 && !TY_XDS_length ) | |
618 { | |
619 mp_msg( MSGT_DEMUX, MSGL_DBG3, | |
620 "%% TY_XDS CHECKSUM ERROR (ignoring)\n" ); | |
621 } | |
622 else | |
623 { | |
624 TY_XDS_mode = 0; | |
625 TY_XDS_type = 0; | |
626 return 1; | |
627 } | |
628 } | |
629 | |
630 // check to see if the data has changed. | |
631 if ( strncmp( TY_XDS[ TY_XDS_mode ][ TY_XDS_type ], | |
632 TY_XDS_new[ TY_XDS_mode ][ TY_XDS_type ], TY_XDS_length - 1 ) ) | |
633 { | |
634 char *TY_XDS_ptr = TY_XDS[ TY_XDS_mode ][ TY_XDS_type ]; | |
635 | |
636 TY_XDS_ptr[ TY_XDS_length ] = 0; | |
637 memcpy( TY_XDS[ TY_XDS_mode ][ TY_XDS_type ], | |
638 TY_XDS_new[ TY_XDS_mode ][ TY_XDS_type ], TY_XDS_length ); | |
639 | |
640 // nasty hack: only print time codes if seconds are 0 | |
641 if ( TY_XDS_mode == 3 && TY_XDS_type == 1 && | |
642 !( TY_XDS_new[ 3 ][ 1 ][ 3 ] & 0x20 ) ) | |
643 { | |
644 return 0; | |
645 } | |
646 if ( TY_XDS_mode == 0 && TY_XDS_type == 2 && | |
647 ( TY_XDS_new[ 0 ][ 2 ][ 4 ] & 0x3f ) > 1 ) | |
648 { | |
649 return 0; | |
650 } | |
651 | |
652 mp_msg( MSGT_DEMUX, MSGL_DBG3, "%% %s ", TY_XDS_modes[ TY_XDS_mode ] ); | |
653 | |
654 line[ 0 ] = 0; | |
655 // printf( "XDS Code %x\n", | |
656 // ( TY_XDS_mode << 9 ) + TY_XDS_type + 0x100 ); | |
657 switch ( ( TY_XDS_mode << 9 ) + TY_XDS_type + 0x100 ) | |
658 { | |
659 // cases are specified in 2 bytes hex representing mode, type. | |
660 // TY_XDS_ptr will point to the current class buffer | |
661 case 0x0101: // current | |
662 case 0x0301: // future | |
663 { | |
664 char *mon[] = | |
665 { | |
666 "0", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", | |
667 "Aug", "Sep", "Oct", "Nov", "Dec", "13", "14", "15" | |
668 }; | |
669 ty_AddXDSToDisplay( "AIR DATE: %s %2d %d:%02d:00", | |
670 mon[ TY_XDS_ptr[ 3 ] & 0x0f ], | |
671 TY_XDS_ptr[ 2 ] & 0x1f, | |
672 TY_XDS_ptr[ 1 ] & 0x1f, | |
673 TY_XDS_ptr[ 0 ] & 0x3f | |
674 ); | |
675 | |
676 // Program is tape delayed | |
677 if ( TY_XDS_ptr[ 3 ] & 0x10 ) ty_AddXDSToDisplay( " TAPE" ); | |
678 } | |
679 break; | |
680 | |
681 case 0x0102: // current program length | |
682 case 0x0302: // future | |
683 { | |
684 ty_AddXDSToDisplay( | |
685 "DURATION: %d:%02d:%02d of %d:%02d:%02d", | |
686 TY_XDS_ptr[ 3 ] & 0x3f, | |
687 TY_XDS_ptr[ 2 ] & 0x3f, | |
688 TY_XDS_ptr[ 4 ] & 0x3f, | |
689 TY_XDS_ptr[ 1 ] & 0x3f, | |
690 TY_XDS_ptr[ 0 ] & 0x3f, 0); | |
691 break; | |
692 } | |
693 | |
694 case 0x0103: // current program name | |
695 case 0x0303: // future | |
696 { | |
697 ty_AddXDSToDisplay( "TITLE: %s", TY_XDS_ptr ); | |
698 break; | |
699 } | |
700 | |
701 case 0x0104: // current program type | |
702 case 0x0304: // future | |
703 { | |
704 // for now just print out the raw data | |
705 // requires a 127 string array to parse | |
706 // properly and isn't worth it. | |
707 sprintf ( line, "%sGENRE:", line ); | |
708 { | |
709 int x; | |
710 for ( x = 0 ; x < TY_XDS_length ; x++ ) | |
711 sprintf( line, "%s %02x", line, TY_XDS_ptr[ x ] ); | |
712 } | |
713 ty_AddXDSToDisplay( line ); | |
714 break; | |
715 } | |
716 | |
717 case 0x0105: // current program rating | |
718 case 0x0305: // future | |
719 { | |
720 sprintf( line, "%sRATING: %s", line, | |
721 TY_XDS_CHIP[ ( TY_XDS_ptr[ 0 ] & 0x08 ) >> 3 ] | |
722 [ TY_XDS_ptr[ 1 ] & 0x07 ] ); | |
723 if ( TY_XDS_ptr[ 0 ] & 0x20 ) | |
724 sprintf( line, "%s DIALOGUE", line ); | |
725 if ( TY_XDS_ptr[ 1 ] & 0x08 ) | |
726 sprintf( line, "%s LANGUAGE", line ); | |
727 if ( TY_XDS_ptr[ 1 ] & 0x10 ) | |
728 sprintf( line, "%s SEXUAL", line ); | |
729 if ( TY_XDS_ptr[ 1 ] & 0x20 ) | |
730 sprintf( line, "%s VIOLENCE", line ); | |
731 ty_AddXDSToDisplay( line ); | |
732 | |
733 // raw output for verification. | |
734 if ( TY_OSD_debug > 1 ) | |
735 mp_msg( MSGT_DEMUX, MSGL_DBG3, " (%02x %02x)", | |
736 TY_XDS_ptr[ 0 ], TY_XDS_ptr[ 1 ] ); | |
737 break; | |
738 } | |
739 | |
740 case 0x0106: // current program audio services | |
741 case 0x0306: // future | |
742 { | |
743 // requires table, never actually seen it used either | |
744 ty_AddXDSToDisplay( "AUDIO: %02x %02x", TY_XDS_ptr[ 0 ], | |
745 TY_XDS_ptr[ 1 ] ); | |
746 break; | |
747 } | |
748 | |
749 case 0x0109: // current program aspect ratio | |
750 case 0x0309: // future | |
751 { | |
752 // requires table, rare | |
753 ty_AddXDSToDisplay( "ASPECT: %02x %02x", | |
754 TY_XDS_ptr[ 0 ], TY_XDS_ptr[ 1 ] ); | |
755 break; | |
756 } | |
757 | |
758 case 0x0110 ... 0x0117: // program description | |
759 { | |
760 ty_AddXDSToDisplay( "DESCRIP: %s", TY_XDS_ptr ); | |
761 break; | |
762 } | |
763 | |
764 case 0x0501: // channel network name | |
765 { | |
766 ty_AddXDSToDisplay( "NETWORK: %s", TY_XDS_ptr ); | |
767 break; | |
768 } | |
769 | |
770 case 0x0502: // channel network call letters | |
771 { | |
772 ty_AddXDSToDisplay( "CALLSIGN: %s", TY_XDS_ptr ); | |
773 break; | |
774 } | |
775 | |
776 case 0x0701: // misc. time of day | |
777 { | |
778 #define TIMEZONE ( TY_XDS[ 3 ][ 4 ][ 0 ] & 0x1f ) | |
779 #define DST ( ( TY_XDS[ 3 ][ 4 ][ 0 ] & 0x20 ) >> 5 ) | |
780 struct tm tm = | |
781 { | |
10858 | 782 .tm_sec = 0, // sec |
783 .tm_min = ( TY_XDS_ptr[ 0 ] & 0x3F ), // min | |
784 .tm_hour = ( TY_XDS_ptr[ 1 ] & 0x1F ), // hour | |
785 .tm_mday = ( TY_XDS_ptr[ 2 ] & 0x1F ), // day | |
786 .tm_mon = ( TY_XDS_ptr[ 3 ] & 0x1f ) - 1, // month | |
787 .tm_year = ( TY_XDS_ptr[ 5 ] & 0x3f ) + 90, // year | |
788 .tm_wday = 0, // day of week | |
789 .tm_yday = 0, // day of year | |
790 .tm_isdst = 0, // DST | |
10263 | 791 }; |
792 | |
793 time_t time_t = mktime( &tm ); | |
794 char *timestr; | |
795 | |
796 time_t -= ( ( TIMEZONE - DST ) * 60 * 60 ); | |
797 timestr = ctime( &time_t ); | |
798 timestr[ strlen( timestr ) - 1 ] = 0; | |
799 | |
800 sprintf( line, "%sCUR.TIME: %s ", line, timestr ); | |
801 if ( TY_XDS[ 3 ][ 4 ][ 0 ] ) | |
802 { | |
803 sprintf( line, "%sUTC-%d", line, TIMEZONE ); | |
804 if (DST) sprintf( line, "%s DST", line ); | |
805 } | |
806 else | |
807 sprintf( line, "%sUTC", line ); | |
808 | |
809 ty_AddXDSToDisplay( line ); | |
810 | |
811 break; | |
812 } | |
813 | |
814 case 0x0704: //misc. local time zone | |
815 { | |
816 sprintf( line, "%sTIMEZONE: UTC-%d", | |
817 line, TY_XDS_ptr[ 0 ] & 0x1f ); | |
818 if ( TY_XDS_ptr[ 0 ] & 0x20 ) sprintf( line, "%s DST", line ); | |
819 ty_AddXDSToDisplay( line ); | |
820 break; | |
821 } | |
822 | |
823 default: | |
824 { | |
825 mp_msg( MSGT_DEMUX, MSGL_DBG3, "UNKNOWN CLASS %d TYPE %d", | |
826 ( TY_XDS_mode << 1 ) + 1, TY_XDS_type ); | |
827 if ( TY_OSD_debug > 1 ) | |
828 { | |
829 int x; | |
830 mp_msg( MSGT_DEMUX, MSGL_DBG3, "\nDUMP:\n" ); | |
831 for ( x = 0 ; x < TY_XDS_length ; x++ ) | |
832 mp_msg( MSGT_DEMUX, MSGL_DBG3, " %02x %c", | |
833 TY_XDS_ptr[ x ], TY_XDS_ptr[ x ] ); | |
834 mp_msg( MSGT_DEMUX, MSGL_DBG3, "\n" ); | |
835 } | |
836 } | |
837 } | |
838 if ( TY_OSD_debug > 1 ) | |
839 mp_msg( MSGT_DEMUX, MSGL_DBG3, " (%d)", TY_XDS_length ); | |
840 } | |
841 TY_XDS_mode = 0; | |
842 TY_XDS_type = 0; | |
843 } | |
844 else if ( TY_XDS_length < 34 ) | |
845 { | |
846 TY_XDS_new[ TY_XDS_mode ][ TY_XDS_type ][ TY_XDS_length++ ] = b1; | |
847 TY_XDS_new[ TY_XDS_mode ][ TY_XDS_type ][ TY_XDS_length++ ] = b2; | |
848 } | |
849 return 0; | |
850 } | |
851 | |
852 | |
853 // 42 x 10 | |
854 static char *testline = "0123456789012345678901234567890123456789012"; | |
855 | |
856 // =========================================================================== | |
857 // Callback from Video Display Processing to put up the OSD | |
858 // =========================================================================== | |
859 void ty_processuserdata( unsigned char* buf, int len ) | |
860 { | |
861 int index; | |
862 | |
863 sub_justify = 1; | |
864 | |
865 if ( subcc_enabled ) | |
866 { | |
867 if ( tyOSDInited == 0 ) | |
868 { | |
869 for ( index = 0; index < SUB_MAX_TEXT ; index++ ) | |
870 { | |
871 ty_OSD1.text[ index ] = malloc( TY_CC_MAX_X ); | |
872 ty_OSD2.text[ index ] = malloc( TY_CC_MAX_X ); | |
873 } | |
874 ty_ClearOSD( 0 ); | |
875 ty_OSD1.lines = SUB_MAX_TEXT; | |
876 ty_OSD2.lines = SUB_MAX_TEXT; | |
877 ty_pOSD1 = &ty_OSD1; | |
878 ty_pOSD2 = &ty_OSD2; | |
879 tyOSDUpdate = 0; | |
880 tyOSDInited = 1; | |
881 } | |
882 | |
883 if ( buf[ 0 ] == 0x01 ) | |
884 { | |
885 ty_CCdecode( buf[ 1 ], buf[ 2 ] ); | |
886 } | |
887 if ( buf[ 0 ] == 0x02 ) | |
888 { | |
889 ty_XDSdecode( buf[ 1 ], buf[ 2 ] ); | |
890 } | |
891 | |
892 ty_DisplayXDSInfo(); | |
893 | |
894 if ( tyOSDUpdate ) | |
895 { | |
896 // for ( index = 0; index < SUB_MAX_TEXT ; index++ ) | |
897 // { | |
898 // printf( "OSD:%d:%s\n", index, ty_OSD1.text[ index ] ); | |
899 // } | |
900 vo_sub = &ty_OSD1; | |
901 vo_osd_changed( OSDTYPE_SUBTITLE ); | |
902 tyOSDUpdate = 0; | |
903 } | |
904 } | |
905 } | |
906 | |
907 | |
908 |