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