Mercurial > mplayer.hg
annotate libmpdemux/demux_ty_osd.c @ 27985:1c77b86d355d
Remove a ColorFill that is not necessary since the surface it is used
on has exactly the same size as the video image and the video will
be copied into it before it is used the first time.
author | reimar |
---|---|
date | Mon, 24 Nov 2008 09:46:23 +0000 |
parents | a5c4e1f7aaa7 |
children | 0f1b5b68af32 |
rev | line source |
---|---|
25768 | 1 // Most of this was written by Mike Baker <mbm@linux.com> |
26648
e5f5e8891f86
Mike Baker agreed to relicense his parts of the code as GPL v2+ on IRC.
diego
parents:
25962
diff
changeset
|
2 // and released under the GPL v2+ license. |
10263 | 3 // |
4 // Modifications and SEVERE cleanup of the code was done by | |
5 // Christopher Wingert | |
6 // Copyright 2003 | |
7 // | |
8 // Released under GPL2 License. | |
9 | |
10 #include <stdio.h> | |
11 #include <stdlib.h> | |
12 #include <unistd.h> | |
13 #include <time.h> | |
14 #include <stdarg.h> | |
10310
68e714ed669f
fix one missing #include, one missing extern and one 10l error.
rathann
parents:
10263
diff
changeset
|
15 #include <string.h> |
10263 | 16 |
17 #include "config.h" | |
18 #include "mp_msg.h" | |
19 #include "help_mp.h" | |
20 | |
22605
4d81dbdf46b9
Add explicit location for headers from the stream/ directory.
diego
parents:
19104
diff
changeset
|
21 //#include "stream/stream.h" |
10263 | 22 //#include "demuxer.h" |
23 //#include "parse_es.h" | |
24 //#include "stheader.h" | |
25 //#include "mp3_hdr.h" | |
17012 | 26 //#include "subreader.h" |
27 #include "sub_cc.h" | |
28 #include "libvo/sub.h" | |
10263 | 29 |
30 //#include "dvdauth.h" | |
31 | |
32 extern int sub_justify; | |
33 | |
34 #define TY_TEXT_MODE ( 1 << 0 ) | |
35 #define TY_OSD_MODE ( 1 << 1 ) | |
36 | |
37 static int TY_OSD_flags = TY_TEXT_MODE | TY_OSD_MODE; | |
38 static int TY_OSD_debug = 0; | |
39 | |
40 // =========================================================================== | |
41 // Closed Caption Decoding and OSD Presentation | |
42 // =========================================================================== | |
43 #define TY_CCNONE ( -3 ) | |
44 #define TY_CCTEXTMODE ( -2 ) | |
45 #define TY_CCPOPUPNB ( -1 ) | |
46 #define TY_CCPOPUP ( 0 ) | |
47 #define TY_CCPAINTON ( 1 ) | |
48 | |
49 #define TY_CC_MAX_X ( 45 ) | |
50 | |
51 static int TY_CC_CUR_X; | |
52 static int TY_CC_CUR_Y; | |
53 static int TY_CC_stat = TY_CCNONE; | |
54 static char TY_CC_buf[ 255 ]; | |
55 static char *TY_CC_ptr = TY_CC_buf; | |
56 static unsigned TY_CC_lastcap = 0; | |
57 static int TY_CC_TextItalic; | |
58 static int TY_CC_Y_Offset; | |
59 | |
60 static subtitle ty_OSD1; | |
61 static subtitle ty_OSD2; | |
62 static subtitle *ty_pOSD1; | |
63 static subtitle *ty_pOSD2; | |
25962 | 64 static int tyOSDInitialized = 0; |
10263 | 65 static int tyOSDUpdate = 0; |
66 | |
17566
f580a7755ac5
Patch by Stefan Huehner / stefan % huehner ! org \
rathann
parents:
17012
diff
changeset
|
67 static void ty_DrawOSD(void) |
10263 | 68 { |
69 // printf( "Calling ty_DrawOSD()\n" ); | |
70 tyOSDUpdate = 1; | |
71 } | |
72 | |
73 void ty_ClearOSD( int start ) | |
74 { | |
75 int index; | |
76 // printf( "Calling ty_ClearOSD()\n" ); | |
77 for ( index = start ; index < SUB_MAX_TEXT ; index++ ) | |
78 { | |
79 memset( ty_OSD1.text[ index ], ' ', TY_CC_MAX_X - 1 ); | |
80 ty_OSD1.text[ index ][ TY_CC_MAX_X - 1 ] = 0; | |
81 memset( ty_OSD2.text[ index ], ' ', TY_CC_MAX_X - 1 ); | |
82 ty_OSD2.text[ index ][ TY_CC_MAX_X - 1 ] = 0; | |
83 } | |
84 } | |
85 | |
86 static void ty_DrawChar( int *x, int *y, char disChar, int fgColor, int bgColor ) | |
87 { | |
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 | |
17566
f580a7755ac5
Patch by Stefan Huehner / stefan % huehner ! org \
rathann
parents:
17012
diff
changeset
|
164 static void ty_draw(void) |
10263 | 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 | |
23913
8b9b08c45999
Do not use gnu case-range extension if it's easy to avoid
reimar
parents:
23635
diff
changeset
|
367 case 0x25: // 2-4 row captions |
8b9b08c45999
Do not use gnu case-range extension if it's easy to avoid
reimar
parents:
23635
diff
changeset
|
368 case 0x26: |
8b9b08c45999
Do not use gnu case-range extension if it's easy to avoid
reimar
parents:
23635
diff
changeset
|
369 case 0x27: |
10263 | 370 { |
371 if ( TY_CC_stat == TY_CCPOPUP ) ty_ClearOSD( 1 ); | |
372 TY_CC_stat = b2 - 0x23; | |
373 if ( TY_CC_CUR_Y < TY_CC_stat ) TY_CC_CUR_Y = TY_CC_stat; | |
374 break; | |
375 } | |
376 | |
377 case 0x29: // resume direct caption | |
378 { | |
379 TY_CC_stat = TY_CCPAINTON; | |
380 break; | |
381 } | |
382 | |
383 case 0x2A: // text restart | |
384 { | |
385 ty_draw(); | |
386 /* FALL */ | |
387 } | |
388 | |
389 case 0x2B: // resume text display | |
390 { | |
391 TY_CC_stat = TY_CCTEXTMODE; | |
392 break; | |
393 } | |
394 | |
395 case 0x2C: // erase displayed memory | |
396 { | |
397 TY_CC_lastcap = 0; | |
398 if ( TY_OSD_flags & TY_OSD_MODE ) | |
399 { | |
400 if ( TY_CC_stat > TY_CCPOPUP || TY_CC_ptr == TY_CC_buf ) | |
401 { | |
402 ty_ClearOSD( 1 ); | |
403 ty_draw(); | |
404 } | |
405 else | |
406 { | |
407 ty_ClearOSD( 1 ); | |
408 | |
409 // CRW - | |
410 // new buffer | |
411 // Used to be a buffer swap here, dunno why | |
412 } | |
413 } | |
414 break; | |
415 } | |
416 | |
417 case 0x2D: // carriage return | |
418 { | |
419 ty_draw(); | |
420 TY_CC_CUR_X = 1; | |
421 if ( TY_OSD_flags & TY_OSD_MODE ) | |
422 { | |
423 if ( TY_CC_stat > TY_CCPAINTON ) | |
424 ty_RollupBuf | |
425 ( | |
426 TY_CC_CUR_Y - TY_CC_stat + 1 , | |
427 TY_CC_CUR_Y - TY_CC_stat + 2, | |
428 TY_CC_stat - 1 | |
429 ); | |
430 else | |
431 TY_CC_CUR_Y++; | |
432 } | |
433 break; | |
434 } | |
435 | |
436 case 0x2F: // end caption + swap memory | |
437 { | |
438 ty_draw(); | |
439 /* FALL THROUGH TO 0x2E */ | |
440 } | |
441 | |
442 case 0x2E: // erase non-displayed memory | |
443 { | |
444 if ( TY_OSD_debug && TY_CC_ptr != TY_CC_buf ) | |
445 mp_msg( MSGT_DEMUX, MSGL_DBG3, "(TY_OSD_debug) %s\n", | |
446 TY_CC_buf ); | |
447 if ( TY_OSD_flags & TY_OSD_MODE ) ty_ClearOSD( 1 ); | |
448 | |
449 TY_CC_CUR_X = 1; | |
450 TY_CC_CUR_Y = -1; | |
451 | |
452 TY_CC_ptr = TY_CC_buf; | |
453 memset( TY_CC_buf, 0, sizeof( TY_CC_buf ) ); | |
454 } | |
455 } | |
456 break; | |
457 } | |
458 case 0x07: // misc (TAB) | |
459 { | |
460 for ( x = 0 ; x < ( b2 - 0x20 ) ; x++ ) | |
461 TY_CC_CUR_X++; | |
462 break; | |
463 } | |
464 } | |
465 } | |
466 } | |
467 CC_last = data; | |
468 return 0; | |
469 } | |
470 | |
471 // =========================================================================== | |
472 // Extended Data Service Decoding and OSD Presentation | |
473 // =========================================================================== | |
474 #define XDS_BUFFER_LENGTH ( 16 ) | |
475 #define XDS_DISPLAY_FRAMES ( 120 ) | |
476 static char *ty_XDS_Display[ XDS_BUFFER_LENGTH ]; | |
477 static int ty_XDSAddLine = -1; | |
478 static int ty_XDSDisplayCount = -1; | |
479 | |
480 | |
19104
2ec2301183cd
marks several read-only string parameters which aren't modified inside the called function as const. Patch by Stefan Huehner, stefan AT huehner-org
reynaldo
parents:
18958
diff
changeset
|
481 static void ty_AddXDSToDisplay( const char *format, ... ) |
10263 | 482 { |
483 char line[ 80 ]; | |
484 int index; | |
485 va_list ap; | |
486 | |
487 if ( ty_XDSAddLine == -1 ) | |
488 { | |
489 for( index = 0 ; index < XDS_BUFFER_LENGTH ; index++ ) | |
490 { | |
491 ty_XDS_Display[ index ] = 0; | |
492 } | |
493 ty_XDSAddLine = 0; | |
494 } | |
495 | |
496 va_start( ap, format ); | |
497 vsnprintf( line, 80, format, ap ); | |
498 va_end( ap ); | |
499 mp_msg( MSGT_DEMUX, MSGL_V, "XDS: %s\n", line ); | |
500 | |
501 if ( ty_XDSAddLine == XDS_BUFFER_LENGTH ) | |
502 { | |
503 mp_msg( MSGT_DEMUX, MSGL_ERR, "XDS Buffer would have been blown\n" ); | |
504 } | |
505 | |
506 if ( ty_XDS_Display[ ty_XDSAddLine ] != 0 ) | |
507 { | |
508 free( ty_XDS_Display[ ty_XDSAddLine ] ); | |
509 ty_XDS_Display[ ty_XDSAddLine ] = 0; | |
510 } | |
511 | |
512 ty_XDS_Display[ ty_XDSAddLine ] = malloc( strlen( line ) + 1 ); | |
513 strcpy( ty_XDS_Display[ ty_XDSAddLine ], line ); | |
514 ty_XDSAddLine++; | |
515 } | |
516 | |
517 | |
17566
f580a7755ac5
Patch by Stefan Huehner / stefan % huehner ! org \
rathann
parents:
17012
diff
changeset
|
518 static void ty_DisplayXDSInfo(void) |
10263 | 519 { |
520 int index; | |
521 int size; | |
522 | |
523 if ( ty_XDSDisplayCount == -1 ) | |
524 { | |
525 for( index = 0 ; index < XDS_BUFFER_LENGTH ; index++ ) | |
526 { | |
527 if ( ty_XDS_Display[ index ] != 0 ) | |
528 { | |
529 break; | |
530 } | |
531 } | |
532 if ( index != XDS_BUFFER_LENGTH ) | |
533 { | |
534 size = strlen( ty_XDS_Display[ index ] ); | |
535 | |
536 // Right Justify the XDS Stuff | |
537 memcpy( &( ty_OSD1.text[ 0 ][ TY_CC_MAX_X - size - 1 ] ), | |
538 ty_XDS_Display[ index ], size ); | |
539 free( ty_XDS_Display[ index ] ); | |
540 ty_XDS_Display[ index ] = 0; | |
541 ty_XDSDisplayCount = 0; | |
542 tyOSDUpdate = 1; | |
543 | |
544 } | |
545 else | |
546 { | |
547 // We cleaned out all the XDS stuff to be displayed | |
548 ty_XDSAddLine = 0; | |
549 } | |
550 } | |
551 else | |
552 { | |
553 // We displayed that piece of XDS information long enough | |
11000 | 554 // Let's move on |
10263 | 555 ty_XDSDisplayCount++; |
556 if ( ty_XDSDisplayCount >= XDS_DISPLAY_FRAMES ) | |
557 { | |
558 memset( ty_OSD1.text[ 0 ], ' ', TY_CC_MAX_X - 1 ); | |
559 ty_OSD1.text[ 0 ][ TY_CC_MAX_X - 1 ] = 0; | |
560 ty_XDSDisplayCount = -1; | |
561 tyOSDUpdate = 1; | |
562 } | |
563 } | |
564 } | |
565 | |
566 | |
567 static int TY_XDS_mode = 0; | |
568 static int TY_XDS_type = 0; | |
569 static int TY_XDS_length = 0; | |
570 static char TY_XDS_checksum = 0; | |
571 | |
572 // Array of [ Mode ][ Type ][ Length ] | |
573 static char TY_XDS [ 8 ][ 25 ][ 34 ]; | |
574 static char TY_XDS_new[ 8 ][ 25 ][ 34 ]; | |
575 | |
576 // Array of [ MPAARating|TVRating ][ NumberRatings ] | |
27692 | 577 static const char * const TY_XDS_CHIP[ 2 ][ 8 ] = |
10263 | 578 { |
579 { "(NOT APPLICABLE)", "G", "PG", "PG-13", "R", "NC-17", "X", "(NOT RATED)" }, | |
580 { "(NOT RATED)", "TV-Y", "TV-Y7", "TV-G", "TV-PG", "TV-14", "TV-MA", | |
581 "(NOT RATED)" } | |
582 }; | |
583 | |
27692 | 584 static const char * const TY_XDS_modes[] = |
10263 | 585 { |
586 "CURRENT", // 01h-02h current program | |
587 "FUTURE ", // 03h-04h future program | |
588 "CHANNEL", // 05h-06h channel | |
589 "MISC. ", // 07h-08h miscellaneous | |
590 "PUBLIC ", // 09h-0Ah public service | |
591 "RESERV.", // 0Bh-0Ch reserved | |
592 "UNDEF. ", | |
593 "INVALID", | |
594 "INVALID", | |
595 "INVALID" | |
596 }; | |
597 | |
598 static int ty_XDSdecode( char b1, char b2 ) | |
599 { | |
600 char line[ 80 ]; | |
601 | |
602 if ( b1 < 0x0F ) | |
603 { // start packet | |
604 TY_XDS_length = 0; | |
605 TY_XDS_mode = b1 >> 1; // every other mode is a resume | |
606 TY_XDS_type = b2; | |
607 TY_XDS_checksum = b1 + b2; | |
608 return 0; | |
609 } | |
610 | |
611 TY_XDS_checksum += b1 + b2; | |
612 | |
613 // eof (next byte is checksum) | |
614 if ( b1 == 0x0F ) | |
615 { | |
616 // validity check | |
617 if ( !TY_XDS_length || TY_XDS_checksum & 0x7F ) | |
618 { | |
619 if ( TY_OSD_debug > 3 && !TY_XDS_length ) | |
620 { | |
621 mp_msg( MSGT_DEMUX, MSGL_DBG3, | |
622 "%% TY_XDS CHECKSUM ERROR (ignoring)\n" ); | |
623 } | |
624 else | |
625 { | |
626 TY_XDS_mode = 0; | |
627 TY_XDS_type = 0; | |
628 return 1; | |
629 } | |
630 } | |
631 | |
632 // check to see if the data has changed. | |
633 if ( strncmp( TY_XDS[ TY_XDS_mode ][ TY_XDS_type ], | |
634 TY_XDS_new[ TY_XDS_mode ][ TY_XDS_type ], TY_XDS_length - 1 ) ) | |
635 { | |
636 char *TY_XDS_ptr = TY_XDS[ TY_XDS_mode ][ TY_XDS_type ]; | |
637 | |
638 TY_XDS_ptr[ TY_XDS_length ] = 0; | |
639 memcpy( TY_XDS[ TY_XDS_mode ][ TY_XDS_type ], | |
640 TY_XDS_new[ TY_XDS_mode ][ TY_XDS_type ], TY_XDS_length ); | |
641 | |
642 // nasty hack: only print time codes if seconds are 0 | |
643 if ( TY_XDS_mode == 3 && TY_XDS_type == 1 && | |
644 !( TY_XDS_new[ 3 ][ 1 ][ 3 ] & 0x20 ) ) | |
645 { | |
646 return 0; | |
647 } | |
648 if ( TY_XDS_mode == 0 && TY_XDS_type == 2 && | |
649 ( TY_XDS_new[ 0 ][ 2 ][ 4 ] & 0x3f ) > 1 ) | |
650 { | |
651 return 0; | |
652 } | |
653 | |
654 mp_msg( MSGT_DEMUX, MSGL_DBG3, "%% %s ", TY_XDS_modes[ TY_XDS_mode ] ); | |
655 | |
656 line[ 0 ] = 0; | |
657 // printf( "XDS Code %x\n", | |
658 // ( TY_XDS_mode << 9 ) + TY_XDS_type + 0x100 ); | |
659 switch ( ( TY_XDS_mode << 9 ) + TY_XDS_type + 0x100 ) | |
660 { | |
661 // cases are specified in 2 bytes hex representing mode, type. | |
662 // TY_XDS_ptr will point to the current class buffer | |
663 case 0x0101: // current | |
664 case 0x0301: // future | |
665 { | |
666 char *mon[] = | |
667 { | |
668 "0", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", | |
669 "Aug", "Sep", "Oct", "Nov", "Dec", "13", "14", "15" | |
670 }; | |
671 ty_AddXDSToDisplay( "AIR DATE: %s %2d %d:%02d:00", | |
672 mon[ TY_XDS_ptr[ 3 ] & 0x0f ], | |
673 TY_XDS_ptr[ 2 ] & 0x1f, | |
674 TY_XDS_ptr[ 1 ] & 0x1f, | |
675 TY_XDS_ptr[ 0 ] & 0x3f | |
676 ); | |
677 | |
678 // Program is tape delayed | |
679 if ( TY_XDS_ptr[ 3 ] & 0x10 ) ty_AddXDSToDisplay( " TAPE" ); | |
680 } | |
681 break; | |
682 | |
683 case 0x0102: // current program length | |
684 case 0x0302: // future | |
685 { | |
686 ty_AddXDSToDisplay( | |
687 "DURATION: %d:%02d:%02d of %d:%02d:%02d", | |
688 TY_XDS_ptr[ 3 ] & 0x3f, | |
689 TY_XDS_ptr[ 2 ] & 0x3f, | |
690 TY_XDS_ptr[ 4 ] & 0x3f, | |
691 TY_XDS_ptr[ 1 ] & 0x3f, | |
692 TY_XDS_ptr[ 0 ] & 0x3f, 0); | |
693 break; | |
694 } | |
695 | |
696 case 0x0103: // current program name | |
697 case 0x0303: // future | |
698 { | |
699 ty_AddXDSToDisplay( "TITLE: %s", TY_XDS_ptr ); | |
700 break; | |
701 } | |
702 | |
703 case 0x0104: // current program type | |
704 case 0x0304: // future | |
705 { | |
706 // for now just print out the raw data | |
707 // requires a 127 string array to parse | |
708 // properly and isn't worth it. | |
709 sprintf ( line, "%sGENRE:", line ); | |
710 { | |
711 int x; | |
712 for ( x = 0 ; x < TY_XDS_length ; x++ ) | |
713 sprintf( line, "%s %02x", line, TY_XDS_ptr[ x ] ); | |
714 } | |
715 ty_AddXDSToDisplay( line ); | |
716 break; | |
717 } | |
718 | |
719 case 0x0105: // current program rating | |
720 case 0x0305: // future | |
721 { | |
722 sprintf( line, "%sRATING: %s", line, | |
723 TY_XDS_CHIP[ ( TY_XDS_ptr[ 0 ] & 0x08 ) >> 3 ] | |
724 [ TY_XDS_ptr[ 1 ] & 0x07 ] ); | |
725 if ( TY_XDS_ptr[ 0 ] & 0x20 ) | |
726 sprintf( line, "%s DIALOGUE", line ); | |
727 if ( TY_XDS_ptr[ 1 ] & 0x08 ) | |
728 sprintf( line, "%s LANGUAGE", line ); | |
729 if ( TY_XDS_ptr[ 1 ] & 0x10 ) | |
730 sprintf( line, "%s SEXUAL", line ); | |
731 if ( TY_XDS_ptr[ 1 ] & 0x20 ) | |
732 sprintf( line, "%s VIOLENCE", line ); | |
733 ty_AddXDSToDisplay( line ); | |
734 | |
735 // raw output for verification. | |
736 if ( TY_OSD_debug > 1 ) | |
737 mp_msg( MSGT_DEMUX, MSGL_DBG3, " (%02x %02x)", | |
738 TY_XDS_ptr[ 0 ], TY_XDS_ptr[ 1 ] ); | |
739 break; | |
740 } | |
741 | |
742 case 0x0106: // current program audio services | |
743 case 0x0306: // future | |
744 { | |
745 // requires table, never actually seen it used either | |
746 ty_AddXDSToDisplay( "AUDIO: %02x %02x", TY_XDS_ptr[ 0 ], | |
747 TY_XDS_ptr[ 1 ] ); | |
748 break; | |
749 } | |
750 | |
751 case 0x0109: // current program aspect ratio | |
752 case 0x0309: // future | |
753 { | |
754 // requires table, rare | |
755 ty_AddXDSToDisplay( "ASPECT: %02x %02x", | |
756 TY_XDS_ptr[ 0 ], TY_XDS_ptr[ 1 ] ); | |
757 break; | |
758 } | |
759 | |
23914 | 760 case 0x0110: // program description |
761 case 0x0111: | |
762 case 0x0112: | |
763 case 0x0113: | |
764 case 0x0114: | |
765 case 0x0115: | |
766 case 0x0116: | |
767 case 0x0117: | |
10263 | 768 { |
769 ty_AddXDSToDisplay( "DESCRIP: %s", TY_XDS_ptr ); | |
770 break; | |
771 } | |
772 | |
773 case 0x0501: // channel network name | |
774 { | |
775 ty_AddXDSToDisplay( "NETWORK: %s", TY_XDS_ptr ); | |
776 break; | |
777 } | |
778 | |
779 case 0x0502: // channel network call letters | |
780 { | |
781 ty_AddXDSToDisplay( "CALLSIGN: %s", TY_XDS_ptr ); | |
782 break; | |
783 } | |
784 | |
785 case 0x0701: // misc. time of day | |
786 { | |
787 #define TIMEZONE ( TY_XDS[ 3 ][ 4 ][ 0 ] & 0x1f ) | |
788 #define DST ( ( TY_XDS[ 3 ][ 4 ][ 0 ] & 0x20 ) >> 5 ) | |
789 struct tm tm = | |
790 { | |
10858 | 791 .tm_sec = 0, // sec |
792 .tm_min = ( TY_XDS_ptr[ 0 ] & 0x3F ), // min | |
793 .tm_hour = ( TY_XDS_ptr[ 1 ] & 0x1F ), // hour | |
794 .tm_mday = ( TY_XDS_ptr[ 2 ] & 0x1F ), // day | |
795 .tm_mon = ( TY_XDS_ptr[ 3 ] & 0x1f ) - 1, // month | |
796 .tm_year = ( TY_XDS_ptr[ 5 ] & 0x3f ) + 90, // year | |
797 .tm_wday = 0, // day of week | |
798 .tm_yday = 0, // day of year | |
799 .tm_isdst = 0, // DST | |
10263 | 800 }; |
801 | |
802 time_t time_t = mktime( &tm ); | |
803 char *timestr; | |
804 | |
805 time_t -= ( ( TIMEZONE - DST ) * 60 * 60 ); | |
806 timestr = ctime( &time_t ); | |
807 timestr[ strlen( timestr ) - 1 ] = 0; | |
808 | |
809 sprintf( line, "%sCUR.TIME: %s ", line, timestr ); | |
810 if ( TY_XDS[ 3 ][ 4 ][ 0 ] ) | |
811 { | |
812 sprintf( line, "%sUTC-%d", line, TIMEZONE ); | |
813 if (DST) sprintf( line, "%s DST", line ); | |
814 } | |
815 else | |
816 sprintf( line, "%sUTC", line ); | |
817 | |
818 ty_AddXDSToDisplay( line ); | |
819 | |
820 break; | |
821 } | |
822 | |
823 case 0x0704: //misc. local time zone | |
824 { | |
825 sprintf( line, "%sTIMEZONE: UTC-%d", | |
826 line, TY_XDS_ptr[ 0 ] & 0x1f ); | |
827 if ( TY_XDS_ptr[ 0 ] & 0x20 ) sprintf( line, "%s DST", line ); | |
828 ty_AddXDSToDisplay( line ); | |
829 break; | |
830 } | |
831 | |
832 default: | |
833 { | |
834 mp_msg( MSGT_DEMUX, MSGL_DBG3, "UNKNOWN CLASS %d TYPE %d", | |
835 ( TY_XDS_mode << 1 ) + 1, TY_XDS_type ); | |
836 if ( TY_OSD_debug > 1 ) | |
837 { | |
838 int x; | |
839 mp_msg( MSGT_DEMUX, MSGL_DBG3, "\nDUMP:\n" ); | |
840 for ( x = 0 ; x < TY_XDS_length ; x++ ) | |
841 mp_msg( MSGT_DEMUX, MSGL_DBG3, " %02x %c", | |
842 TY_XDS_ptr[ x ], TY_XDS_ptr[ x ] ); | |
843 mp_msg( MSGT_DEMUX, MSGL_DBG3, "\n" ); | |
844 } | |
845 } | |
846 } | |
847 if ( TY_OSD_debug > 1 ) | |
848 mp_msg( MSGT_DEMUX, MSGL_DBG3, " (%d)", TY_XDS_length ); | |
849 } | |
850 TY_XDS_mode = 0; | |
851 TY_XDS_type = 0; | |
852 } | |
853 else if ( TY_XDS_length < 34 ) | |
854 { | |
855 TY_XDS_new[ TY_XDS_mode ][ TY_XDS_type ][ TY_XDS_length++ ] = b1; | |
856 TY_XDS_new[ TY_XDS_mode ][ TY_XDS_type ][ TY_XDS_length++ ] = b2; | |
857 } | |
858 return 0; | |
859 } | |
860 | |
861 | |
862 // =========================================================================== | |
863 // Callback from Video Display Processing to put up the OSD | |
864 // =========================================================================== | |
865 void ty_processuserdata( unsigned char* buf, int len ) | |
866 { | |
867 int index; | |
868 | |
869 sub_justify = 1; | |
870 | |
871 if ( subcc_enabled ) | |
872 { | |
25962 | 873 if ( tyOSDInitialized == 0 ) |
10263 | 874 { |
875 for ( index = 0; index < SUB_MAX_TEXT ; index++ ) | |
876 { | |
877 ty_OSD1.text[ index ] = malloc( TY_CC_MAX_X ); | |
878 ty_OSD2.text[ index ] = malloc( TY_CC_MAX_X ); | |
879 } | |
880 ty_ClearOSD( 0 ); | |
881 ty_OSD1.lines = SUB_MAX_TEXT; | |
882 ty_OSD2.lines = SUB_MAX_TEXT; | |
883 ty_pOSD1 = &ty_OSD1; | |
884 ty_pOSD2 = &ty_OSD2; | |
885 tyOSDUpdate = 0; | |
25962 | 886 tyOSDInitialized = 1; |
10263 | 887 } |
888 | |
889 if ( buf[ 0 ] == 0x01 ) | |
890 { | |
891 ty_CCdecode( buf[ 1 ], buf[ 2 ] ); | |
892 } | |
893 if ( buf[ 0 ] == 0x02 ) | |
894 { | |
895 ty_XDSdecode( buf[ 1 ], buf[ 2 ] ); | |
896 } | |
897 | |
898 ty_DisplayXDSInfo(); | |
899 | |
900 if ( tyOSDUpdate ) | |
901 { | |
902 // for ( index = 0; index < SUB_MAX_TEXT ; index++ ) | |
903 // { | |
904 // printf( "OSD:%d:%s\n", index, ty_OSD1.text[ index ] ); | |
905 // } | |
906 vo_sub = &ty_OSD1; | |
907 vo_osd_changed( OSDTYPE_SUBTITLE ); | |
908 tyOSDUpdate = 0; | |
909 } | |
910 } | |
911 } | |
912 | |
913 | |
914 |