2 Skeleton of function spudec_process_controll() is from xine sources.
4 LGB,... (yeah, try to improve it and insert your name here! ;-)
7 implement fragments reassembly, RLE decoding.
8 read brightness from the IFO.
10 For information on SPU format see <URL:http://sam.zoy.org/doc/dvd/subtitles/>
11 and <URL:http://members.aol.com/mpucoder/DVD/spu.html>
24 #include "libvo/video_out.h"
27 #include "libswscale/swscale.h"
29 #define MIN(a, b) ((a)<(b)?(a):(b))
31 /* Valid values for spu_aamode:
32 0: none (fastest, most ugly)
35 3: bilinear (similiar to vobsub, fast and not too bad)
36 4: uses swscaler gaussian (this is the only one that looks good)
40 int spu_alignment
= -1;
41 float spu_gaussvar
= 1.0;
44 typedef struct packet_t packet_t
;
46 unsigned char *packet
;
47 unsigned int palette
[4];
48 unsigned int alpha
[4];
49 unsigned int control_start
; /* index of start of control data */
50 unsigned int current_nibble
[2]; /* next data nibble (4 bits) to be
51 processed (for RLE decoding) for
53 int deinterlace_oddness
; /* 0 or 1, index into current_nibble */
54 unsigned int start_col
, end_col
;
55 unsigned int start_row
, end_row
;
56 unsigned int width
, height
, stride
;
57 unsigned int start_pts
, end_pts
;
64 unsigned int global_palette
[16];
65 unsigned int orig_frame_width
, orig_frame_height
;
66 unsigned char* packet
;
67 size_t packet_reserve
; /* size of the memory pointed to by packet */
68 unsigned int packet_offset
; /* end of the currently assembled fragment */
69 unsigned int packet_size
; /* size of the packet once all fragments are assembled */
70 unsigned int packet_pts
; /* PTS for this packet */
71 unsigned int palette
[4];
72 unsigned int alpha
[4];
73 unsigned int cuspal
[4];
76 unsigned int start_pts
, end_pts
;
77 unsigned int start_col
, end_col
;
78 unsigned int start_row
, end_row
;
79 unsigned int width
, height
, stride
;
80 size_t image_size
; /* Size of the image buffer */
81 unsigned char *image
; /* Grayscale value */
82 unsigned char *aimage
; /* Alpha value */
83 unsigned int scaled_frame_width
, scaled_frame_height
;
84 unsigned int scaled_start_col
, scaled_start_row
;
85 unsigned int scaled_width
, scaled_height
, scaled_stride
;
86 size_t scaled_image_size
;
87 unsigned char *scaled_image
;
88 unsigned char *scaled_aimage
;
89 int auto_palette
; /* 1 if we lack a palette and must use an heuristic. */
90 int font_start_level
; /* Darkest value used for the computed font */
91 vo_functions_t
*hw_spu
;
93 unsigned int forced_subs_only
; /* flag: 0=display all subtitle, !0 display only forced subtitles */
94 unsigned int is_forced_sub
; /* true if current subtitle is a forced subtitle */
97 static void spudec_queue_packet(spudec_handle_t
*this, packet_t
*packet
)
99 if (this->queue_head
== NULL
)
100 this->queue_head
= packet
;
102 this->queue_tail
->next
= packet
;
103 this->queue_tail
= packet
;
106 static packet_t
*spudec_dequeue_packet(spudec_handle_t
*this)
108 packet_t
*retval
= this->queue_head
;
110 this->queue_head
= retval
->next
;
111 if (this->queue_head
== NULL
)
112 this->queue_tail
= NULL
;
117 static void spudec_free_packet(packet_t
*packet
)
119 if (packet
->packet
!= NULL
)
120 free(packet
->packet
);
124 static inline unsigned int get_be16(const unsigned char *p
)
126 return (p
[0] << 8) + p
[1];
129 static inline unsigned int get_be24(const unsigned char *p
)
131 return (get_be16(p
) << 8) + p
[2];
134 static void next_line(packet_t
*packet
)
136 if (packet
->current_nibble
[packet
->deinterlace_oddness
] % 2)
137 packet
->current_nibble
[packet
->deinterlace_oddness
]++;
138 packet
->deinterlace_oddness
= (packet
->deinterlace_oddness
+ 1) % 2;
141 static inline unsigned char get_nibble(packet_t
*packet
)
144 unsigned int *nibblep
= packet
->current_nibble
+ packet
->deinterlace_oddness
;
145 if (*nibblep
/ 2 >= packet
->control_start
) {
146 mp_msg(MSGT_SPUDEC
,MSGL_WARN
, "SPUdec: ERROR: get_nibble past end of packet\n");
149 nib
= packet
->packet
[*nibblep
/ 2];
158 static inline int mkalpha(int i
)
160 /* In mplayer's alpha planes, 0 is transparent, then 1 is nearly
161 opaque upto 255 which is transparent */
168 return (0xf - i
) << 4;
172 /* Cut the sub to visible part */
173 static inline void spudec_cut_image(spudec_handle_t
*this)
176 unsigned int first_y
, last_y
;
177 unsigned char *image
;
178 unsigned char *aimage
;
180 if (this->stride
== 0 || this->height
== 0) {
184 for (fy
= 0; fy
< this->image_size
&& !this->aimage
[fy
]; fy
++);
185 for (ly
= this->stride
* this->height
-1; ly
&& !this->aimage
[ly
]; ly
--);
186 first_y
= fy
/ this->stride
;
187 last_y
= ly
/ this->stride
;
188 //printf("first_y: %d, last_y: %d\n", first_y, last_y);
189 this->start_row
+= first_y
;
191 // Some subtitles trigger this condition
192 if (last_y
+ 1 > first_y
) {
193 this->height
= last_y
- first_y
+1;
196 this->image_size
= 0;
200 // printf("new h %d new start %d (sz %d st %d)---\n\n", this->height, this->start_row, this->image_size, this->stride);
202 image
= malloc(2 * this->stride
* this->height
);
204 this->image_size
= this->stride
* this->height
;
205 aimage
= image
+ this->image_size
;
206 memcpy(image
, this->image
+ this->stride
* first_y
, this->image_size
);
207 memcpy(aimage
, this->aimage
+ this->stride
* first_y
, this->image_size
);
210 this->aimage
= aimage
;
212 mp_msg(MSGT_SPUDEC
, MSGL_FATAL
, "Fatal: update_spu: malloc requested %d bytes\n", 2 * this->stride
* this->height
);
216 static void spudec_process_data(spudec_handle_t
*this, packet_t
*packet
)
218 unsigned int cmap
[4], alpha
[4];
219 unsigned int i
, x
, y
;
221 this->scaled_frame_width
= 0;
222 this->scaled_frame_height
= 0;
223 this->start_col
= packet
->start_col
;
224 this->end_col
= packet
->end_col
;
225 this->start_row
= packet
->start_row
;
226 this->end_row
= packet
->end_row
;
227 this->height
= packet
->height
;
228 this->width
= packet
->width
;
229 this->stride
= packet
->stride
;
230 for (i
= 0; i
< 4; ++i
) {
231 alpha
[i
] = mkalpha(packet
->alpha
[i
]);
234 else if (this->custom
){
235 cmap
[i
] = ((this->cuspal
[i
] >> 16) & 0xff);
236 if (cmap
[i
] + alpha
[i
] > 255)
237 cmap
[i
] = 256 - alpha
[i
];
240 cmap
[i
] = ((this->global_palette
[packet
->palette
[i
]] >> 16) & 0xff);
241 if (cmap
[i
] + alpha
[i
] > 255)
242 cmap
[i
] = 256 - alpha
[i
];
246 if (this->image_size
< this->stride
* this->height
) {
247 if (this->image
!= NULL
) {
249 this->image_size
= 0;
251 this->image
= malloc(2 * this->stride
* this->height
);
253 this->image_size
= this->stride
* this->height
;
254 this->aimage
= this->image
+ this->image_size
;
257 if (this->image
== NULL
)
260 /* Kludge: draw_alpha needs width multiple of 8. */
261 if (this->width
< this->stride
)
262 for (y
= 0; y
< this->height
; ++y
) {
263 memset(this->aimage
+ y
* this->stride
+ this->width
, 0, this->stride
- this->width
);
264 /* FIXME: Why is this one needed? */
265 memset(this->image
+ y
* this->stride
+ this->width
, 0, this->stride
- this->width
);
268 i
= packet
->current_nibble
[1];
271 while (packet
->current_nibble
[0] < i
272 && packet
->current_nibble
[1] / 2 < packet
->control_start
273 && y
< this->height
) {
274 unsigned int len
, color
;
275 unsigned int rle
= 0;
276 rle
= get_nibble(packet
);
278 rle
= (rle
<< 4) | get_nibble(packet
);
280 rle
= (rle
<< 4) | get_nibble(packet
);
282 rle
= (rle
<< 4) | get_nibble(packet
);
284 rle
|= ((this->width
- x
) << 2);
288 color
= 3 - (rle
& 0x3);
290 if (len
> this->width
- x
|| len
== 0)
291 len
= this->width
- x
;
292 /* FIXME have to use palette and alpha map*/
293 memset(this->image
+ y
* this->stride
+ x
, cmap
[color
], len
);
294 memset(this->aimage
+ y
* this->stride
+ x
, alpha
[color
], len
);
296 if (x
>= this->width
) {
302 spudec_cut_image(this);
307 This function tries to create a usable palette.
308 It determines how many non-transparent colors are used, and assigns different
309 gray scale values to each color.
310 I tested it with four streams and even got something readable. Half of the
311 times I got black characters with white around and half the reverse.
313 static void compute_palette(spudec_handle_t
*this, packet_t
*packet
)
315 int used
[16],i
,cused
,start
,step
,color
;
317 memset(used
, 0, sizeof(used
));
319 if (packet
->alpha
[i
]) /* !Transparent? */
320 used
[packet
->palette
[i
]] = 1;
321 for (cused
=0, i
=0; i
<16; i
++)
322 if (used
[i
]) cused
++;
328 start
= this->font_start_level
;
329 step
= (0xF0-this->font_start_level
)/(cused
-1);
331 memset(used
, 0, sizeof(used
));
332 for (i
=0; i
<4; i
++) {
333 color
= packet
->palette
[i
];
334 if (packet
->alpha
[i
] && !used
[color
]) { /* not assigned? */
336 this->global_palette
[color
] = start
<<16;
342 static void spudec_process_control(spudec_handle_t
*this, unsigned int pts100
)
344 int a
,b
; /* Temporary vars */
345 unsigned int date
, type
;
347 unsigned int start_off
= 0;
348 unsigned int next_off
;
349 unsigned int start_pts
;
350 unsigned int end_pts
;
351 unsigned int current_nibble
[2];
352 unsigned int control_start
;
353 unsigned int display
= 0;
354 unsigned int start_col
= 0;
355 unsigned int end_col
= 0;
356 unsigned int start_row
= 0;
357 unsigned int end_row
= 0;
358 unsigned int width
= 0;
359 unsigned int height
= 0;
360 unsigned int stride
= 0;
362 control_start
= get_be16(this->packet
+ 2);
363 next_off
= control_start
;
364 while (start_off
!= next_off
) {
365 start_off
= next_off
;
366 date
= get_be16(this->packet
+ start_off
) * 1024;
367 next_off
= get_be16(this->packet
+ start_off
+ 2);
368 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
, "date=%d\n", date
);
370 for (type
= this->packet
[off
++]; type
!= 0xff; type
= this->packet
[off
++]) {
371 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
, "cmd=%d ",type
);
374 /* Menu ID, 1 byte */
375 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Menu ID\n");
376 /* shouldn't a Menu ID type force display start? */
377 start_pts
= pts100
+ date
;
380 this->is_forced_sub
=~0; // current subtitle is forced
384 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Start display!\n");
385 start_pts
= pts100
+ date
;
388 this->is_forced_sub
=0;
392 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Stop display!\n");
393 end_pts
= pts100
+ date
;
397 this->palette
[0] = this->packet
[off
] >> 4;
398 this->palette
[1] = this->packet
[off
] & 0xf;
399 this->palette
[2] = this->packet
[off
+ 1] >> 4;
400 this->palette
[3] = this->packet
[off
+ 1] & 0xf;
401 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Palette %d, %d, %d, %d\n",
402 this->palette
[0], this->palette
[1], this->palette
[2], this->palette
[3]);
407 this->alpha
[0] = this->packet
[off
] >> 4;
408 this->alpha
[1] = this->packet
[off
] & 0xf;
409 this->alpha
[2] = this->packet
[off
+ 1] >> 4;
410 this->alpha
[3] = this->packet
[off
+ 1] & 0xf;
411 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Alpha %d, %d, %d, %d\n",
412 this->alpha
[0], this->alpha
[1], this->alpha
[2], this->alpha
[3]);
417 a
= get_be24(this->packet
+ off
);
418 b
= get_be24(this->packet
+ off
+ 3);
421 width
= (end_col
< start_col
) ? 0 : end_col
- start_col
+ 1;
422 stride
= (width
+ 7) & ~7; /* Kludge: draw_alpha needs width multiple of 8 */
425 height
= (end_row
< start_row
) ? 0 : end_row
- start_row
/* + 1 */;
426 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Coords col: %d - %d row: %d - %d (%dx%d)\n",
427 start_col
, end_col
, start_row
, end_row
,
433 current_nibble
[0] = 2 * get_be16(this->packet
+ off
);
434 current_nibble
[1] = 2 * get_be16(this->packet
+ off
+ 2);
435 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Graphic offset 1: %d offset 2: %d\n",
436 current_nibble
[0] / 2, current_nibble
[1] / 2);
440 /* All done, bye-bye */
441 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Done!\n");
445 mp_msg(MSGT_SPUDEC
,MSGL_WARN
,"spudec: Error determining control type 0x%02x. Skipping %d bytes.\n",
446 type
, next_off
- off
);
452 packet_t
*packet
= calloc(1, sizeof(packet_t
));
454 packet
->start_pts
= start_pts
;
455 if (end_pts
== UINT_MAX
&& start_off
!= next_off
) {
456 start_pts
= pts100
+ get_be16(this->packet
+ next_off
) * 1024;
457 packet
->end_pts
= start_pts
- 1;
458 } else packet
->end_pts
= end_pts
;
459 packet
->current_nibble
[0] = current_nibble
[0];
460 packet
->current_nibble
[1] = current_nibble
[1];
461 packet
->start_row
= start_row
;
462 packet
->end_row
= end_row
;
463 packet
->start_col
= start_col
;
464 packet
->end_col
= end_col
;
465 packet
->width
= width
;
466 packet
->height
= height
;
467 packet
->stride
= stride
;
468 packet
->control_start
= control_start
;
469 for (i
=0; i
<4; i
++) {
470 packet
->alpha
[i
] = this->alpha
[i
];
471 packet
->palette
[i
] = this->palette
[i
];
473 packet
->packet
= malloc(this->packet_size
);
474 memcpy(packet
->packet
, this->packet
, this->packet_size
);
475 spudec_queue_packet(this, packet
);
480 static void spudec_decode(spudec_handle_t
*this, unsigned int pts100
)
483 static vo_mpegpes_t packet
= { NULL
, 0, 0x20, 0 };
484 static vo_mpegpes_t
*pkg
=&packet
;
485 packet
.data
= this->packet
;
486 packet
.size
= this->packet_size
;
487 packet
.timestamp
= pts100
;
488 this->hw_spu
->draw_frame((uint8_t**)&pkg
);
490 spudec_process_control(this, pts100
);
493 int spudec_changed(void * this)
495 spudec_handle_t
* spu
= (spudec_handle_t
*)this;
496 return (spu
->spu_changed
|| spu
->now_pts
> spu
->end_pts
);
499 void spudec_assemble(void *this, unsigned char *packet
, unsigned int len
, unsigned int pts100
)
501 spudec_handle_t
*spu
= (spudec_handle_t
*)this;
502 // spudec_heartbeat(this, pts100);
504 mp_msg(MSGT_SPUDEC
,MSGL_WARN
,"SPUasm: packet too short\n");
508 if ((spu
->packet_pts
+ 10000) < pts100
) {
509 // [cb] too long since last fragment: force new packet
510 spu
->packet_offset
= 0;
513 spu
->packet_pts
= pts100
;
514 if (spu
->packet_offset
== 0) {
515 unsigned int len2
= get_be16(packet
);
516 // Start new fragment
517 if (spu
->packet_reserve
< len2
) {
518 if (spu
->packet
!= NULL
)
520 spu
->packet
= malloc(len2
);
521 spu
->packet_reserve
= spu
->packet
!= NULL
? len2
: 0;
523 if (spu
->packet
!= NULL
) {
524 spu
->packet_size
= len2
;
526 mp_msg(MSGT_SPUDEC
,MSGL_WARN
,"SPUasm: invalid frag len / len2: %d / %d \n", len
, len2
);
529 memcpy(spu
->packet
, packet
, len
);
530 spu
->packet_offset
= len
;
531 spu
->packet_pts
= pts100
;
534 // Continue current fragment
535 if (spu
->packet_size
< spu
->packet_offset
+ len
){
536 mp_msg(MSGT_SPUDEC
,MSGL_WARN
,"SPUasm: invalid fragment\n");
537 spu
->packet_size
= spu
->packet_offset
= 0;
540 memcpy(spu
->packet
+ spu
->packet_offset
, packet
, len
);
541 spu
->packet_offset
+= len
;
545 // check if we have a complete packet (unfortunatelly packet_size is bad
547 // [cb] packet_size is padded to be even -> may be one byte too long
548 if ((spu
->packet_offset
== spu
->packet_size
) ||
549 ((spu
->packet_offset
+ 1) == spu
->packet_size
)){
551 while(x
+4<=spu
->packet_offset
){
552 y
=get_be16(spu
->packet
+x
+2); // next control pointer
553 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"SPUtest: x=%d y=%d off=%d size=%d\n",x
,y
,spu
->packet_offset
,spu
->packet_size
);
554 if(x
>=4 && x
==y
){ // if it points to self - we're done!
556 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"SPUgot: off=%d size=%d \n",spu
->packet_offset
,spu
->packet_size
);
557 spudec_decode(spu
, pts100
);
558 spu
->packet_offset
= 0;
561 if(y
<=x
|| y
>=spu
->packet_size
){ // invalid?
562 mp_msg(MSGT_SPUDEC
,MSGL_WARN
,"SPUtest: broken packet!!!!! y=%d < x=%d\n",y
,x
);
563 spu
->packet_size
= spu
->packet_offset
= 0;
568 // [cb] packet is done; start new packet
569 spu
->packet_offset
= 0;
572 if (spu
->packet_offset
== spu
->packet_size
) {
573 spudec_decode(spu
, pts100
);
574 spu
->packet_offset
= 0;
579 void spudec_reset(void *this) // called after seek
581 spudec_handle_t
*spu
= (spudec_handle_t
*)this;
582 while (spu
->queue_head
)
583 spudec_free_packet(spudec_dequeue_packet(spu
));
586 spu
->packet_size
= spu
->packet_offset
= 0;
589 void spudec_heartbeat(void *this, unsigned int pts100
)
591 spudec_handle_t
*spu
= (spudec_handle_t
*) this;
592 spu
->now_pts
= pts100
;
594 while (spu
->queue_head
!= NULL
&& pts100
>= spu
->queue_head
->start_pts
) {
595 packet_t
*packet
= spudec_dequeue_packet(spu
);
596 spu
->start_pts
= packet
->start_pts
;
597 spu
->end_pts
= packet
->end_pts
;
598 if (spu
->auto_palette
)
599 compute_palette(spu
, packet
);
600 spudec_process_data(spu
, packet
);
601 spudec_free_packet(packet
);
602 spu
->spu_changed
= 1;
606 int spudec_visible(void *this){
607 spudec_handle_t
*spu
= (spudec_handle_t
*)this;
608 int ret
=(spu
->start_pts
<= spu
->now_pts
&&
609 spu
->now_pts
< spu
->end_pts
&&
611 // printf("spu visible: %d \n",ret);
615 void spudec_set_forced_subs_only(void * const this, const unsigned int flag
)
618 ((spudec_handle_t
*)this)->forced_subs_only
=flag
;
619 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"SPU: Display only forced subs now %s\n", flag
? "enabled": "disabled");
623 void spudec_draw(void *this, void (*draw_alpha
)(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
))
625 spudec_handle_t
*spu
= (spudec_handle_t
*)this;
626 if (spu
->start_pts
<= spu
->now_pts
&& spu
->now_pts
< spu
->end_pts
&& spu
->image
)
628 draw_alpha(spu
->start_col
, spu
->start_row
, spu
->width
, spu
->height
,
629 spu
->image
, spu
->aimage
, spu
->stride
);
630 spu
->spu_changed
= 0;
634 /* calc the bbox for spudec subs */
635 void spudec_calc_bbox(void *me
, unsigned int dxs
, unsigned int dys
, unsigned int* bbox
)
637 spudec_handle_t
*spu
;
638 spu
= (spudec_handle_t
*)me
;
639 if (spu
->orig_frame_width
== 0 || spu
->orig_frame_height
== 0
640 || (spu
->orig_frame_width
== dxs
&& spu
->orig_frame_height
== dys
)) {
641 bbox
[0] = spu
->start_col
;
642 bbox
[1] = spu
->start_col
+ spu
->width
;
643 bbox
[2] = spu
->start_row
;
644 bbox
[3] = spu
->start_row
+ spu
->height
;
646 else if (spu
->scaled_frame_width
!= dxs
|| spu
->scaled_frame_height
!= dys
) {
647 unsigned int scalex
= 0x100 * dxs
/ spu
->orig_frame_width
;
648 unsigned int scaley
= 0x100 * dys
/ spu
->orig_frame_height
;
649 bbox
[0] = spu
->start_col
* scalex
/ 0x100;
650 bbox
[1] = spu
->start_col
* scalex
/ 0x100 + spu
->width
* scalex
/ 0x100;
651 switch (spu_alignment
) {
653 bbox
[3] = dys
*sub_pos
/100 + spu
->height
* scaley
/ 0x100;
654 if (bbox
[3] > dys
) bbox
[3] = dys
;
655 bbox
[2] = bbox
[3] - spu
->height
* scaley
/ 0x100;
659 bbox
[2] = dys
*sub_pos
/100 - spu
->height
* scaley
/ 0x200;
660 if (bbox
[2] < 0) bbox
[2] = 0;
661 bbox
[3] = bbox
[2] + spu
->height
;
663 bbox
[3] = dys
*sub_pos
/100 + spu
->height
* scaley
/ 0x200;
664 if (bbox
[3] > dys
) bbox
[3] = dys
;
665 bbox
[2] = bbox
[3] - spu
->height
* scaley
/ 0x100;
669 bbox
[2] = dys
*sub_pos
/100 - spu
->height
* scaley
/ 0x100;
670 if (bbox
[2] < 0) bbox
[2] = 0;
671 bbox
[3] = bbox
[2] + spu
->height
;
674 bbox
[2] = spu
->start_row
* scaley
/ 0x100;
675 bbox
[3] = spu
->start_row
* scaley
/ 0x100 + spu
->height
* scaley
/ 0x100;
680 /* transform mplayer's alpha value into an opacity value that is linear */
681 static inline int canon_alpha(int alpha
)
683 return alpha
? 256 - alpha
: 0;
693 static void scale_table(unsigned int start_src
, unsigned int start_tar
, unsigned int end_src
, unsigned int end_tar
, scale_pixel
* table
)
696 unsigned int delta_src
= end_src
- start_src
;
697 unsigned int delta_tar
= end_tar
- start_tar
;
700 if (delta_src
== 0 || delta_tar
== 0) {
703 src_step
= (delta_src
<< 16) / delta_tar
>>1;
704 for (t
= 0; t
<=delta_tar
; src
+= (src_step
<< 1), t
++){
705 table
[t
].position
= MIN(src
>> 16, end_src
- 1);
706 table
[t
].right_down
= src
& 0xffff;
707 table
[t
].left_up
= 0x10000 - table
[t
].right_down
;
711 /* bilinear scale, similar to vobsub's code */
712 static void scale_image(int x
, int y
, scale_pixel
* table_x
, scale_pixel
* table_y
, spudec_handle_t
* spu
)
716 unsigned int scale
[4];
717 int base
= table_y
[y
].position
* spu
->stride
+ table_x
[x
].position
;
718 int scaled
= y
* spu
->scaled_stride
+ x
;
719 alpha
[0] = canon_alpha(spu
->aimage
[base
]);
720 alpha
[1] = canon_alpha(spu
->aimage
[base
+ 1]);
721 alpha
[2] = canon_alpha(spu
->aimage
[base
+ spu
->stride
]);
722 alpha
[3] = canon_alpha(spu
->aimage
[base
+ spu
->stride
+ 1]);
723 color
[0] = spu
->image
[base
];
724 color
[1] = spu
->image
[base
+ 1];
725 color
[2] = spu
->image
[base
+ spu
->stride
];
726 color
[3] = spu
->image
[base
+ spu
->stride
+ 1];
727 scale
[0] = (table_x
[x
].left_up
* table_y
[y
].left_up
>> 16) * alpha
[0];
728 scale
[1] = (table_x
[x
].right_down
* table_y
[y
].left_up
>>16) * alpha
[1];
729 scale
[2] = (table_x
[x
].left_up
* table_y
[y
].right_down
>> 16) * alpha
[2];
730 scale
[3] = (table_x
[x
].right_down
* table_y
[y
].right_down
>> 16) * alpha
[3];
731 spu
->scaled_image
[scaled
] = (color
[0] * scale
[0] + color
[1] * scale
[1] + color
[2] * scale
[2] + color
[3] * scale
[3])>>24;
732 spu
->scaled_aimage
[scaled
] = (scale
[0] + scale
[1] + scale
[2] + scale
[3]) >> 16;
733 if (spu
->scaled_aimage
[scaled
]){
734 spu
->scaled_aimage
[scaled
] = 256 - spu
->scaled_aimage
[scaled
];
735 if(spu
->scaled_aimage
[scaled
] + spu
->scaled_image
[scaled
] > 255)
736 spu
->scaled_image
[scaled
] = 256 - spu
->scaled_aimage
[scaled
];
740 void sws_spu_image(unsigned char *d1
, unsigned char *d2
, int dw
, int dh
, int ds
,
741 unsigned char *s1
, unsigned char *s2
, int sw
, int sh
, int ss
)
743 struct SwsContext
*ctx
;
744 static SwsFilter filter
;
745 static int firsttime
= 1;
749 if (!firsttime
&& oldvar
!= spu_gaussvar
) sws_freeVec(filter
.lumH
);
751 filter
.lumH
= filter
.lumV
=
752 filter
.chrH
= filter
.chrV
= sws_getGaussianVec(spu_gaussvar
, 3.0);
753 sws_normalizeVec(filter
.lumH
, 1.0);
755 oldvar
= spu_gaussvar
;
758 ctx
=sws_getContext(sw
, sh
, PIX_FMT_GRAY8
, dw
, dh
, PIX_FMT_GRAY8
, SWS_GAUSS
, &filter
, NULL
, NULL
);
759 sws_scale(ctx
,&s1
,&ss
,0,sh
,&d1
,&ds
);
760 for (i
=ss
*sh
-1; i
>=0; i
--) if (!s2
[i
]) s2
[i
] = 255; //else s2[i] = 1;
761 sws_scale(ctx
,&s2
,&ss
,0,sh
,&d2
,&ds
);
762 for (i
=ds
*dh
-1; i
>=0; i
--) if (d2
[i
]==0) d2
[i
] = 1; else if (d2
[i
]==255) d2
[i
] = 0;
763 sws_freeContext(ctx
);
766 void spudec_draw_scaled(void *me
, unsigned int dxs
, unsigned int dys
, void (*draw_alpha
)(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
))
768 spudec_handle_t
*spu
= (spudec_handle_t
*)me
;
769 scale_pixel
*table_x
;
770 scale_pixel
*table_y
;
772 if (spu
->start_pts
<= spu
->now_pts
&& spu
->now_pts
< spu
->end_pts
) {
774 // check if only forced subtitles are requested
775 if( (spu
->forced_subs_only
) && !(spu
->is_forced_sub
) ){
779 if (!(spu_aamode
&16) && (spu
->orig_frame_width
== 0 || spu
->orig_frame_height
== 0
780 || (spu
->orig_frame_width
== dxs
&& spu
->orig_frame_height
== dys
))) {
783 draw_alpha(spu
->start_col
, spu
->start_row
, spu
->width
, spu
->height
,
784 spu
->image
, spu
->aimage
, spu
->stride
);
785 spu
->spu_changed
= 0;
789 if (spu
->scaled_frame_width
!= dxs
|| spu
->scaled_frame_height
!= dys
) { /* Resizing is needed */
790 /* scaled_x = scalex * x / 0x100
791 scaled_y = scaley * y / 0x100
792 order of operations is important because of rounding. */
793 unsigned int scalex
= 0x100 * dxs
/ spu
->orig_frame_width
;
794 unsigned int scaley
= 0x100 * dys
/ spu
->orig_frame_height
;
795 spu
->scaled_start_col
= spu
->start_col
* scalex
/ 0x100;
796 spu
->scaled_start_row
= spu
->start_row
* scaley
/ 0x100;
797 spu
->scaled_width
= spu
->width
* scalex
/ 0x100;
798 spu
->scaled_height
= spu
->height
* scaley
/ 0x100;
799 /* Kludge: draw_alpha needs width multiple of 8 */
800 spu
->scaled_stride
= (spu
->scaled_width
+ 7) & ~7;
801 if (spu
->scaled_image_size
< spu
->scaled_stride
* spu
->scaled_height
) {
802 if (spu
->scaled_image
) {
803 free(spu
->scaled_image
);
804 spu
->scaled_image_size
= 0;
806 spu
->scaled_image
= malloc(2 * spu
->scaled_stride
* spu
->scaled_height
);
807 if (spu
->scaled_image
) {
808 spu
->scaled_image_size
= spu
->scaled_stride
* spu
->scaled_height
;
809 spu
->scaled_aimage
= spu
->scaled_image
+ spu
->scaled_image_size
;
812 if (spu
->scaled_image
) {
814 if (spu
->scaled_width
<= 1 || spu
->scaled_height
<= 1) {
817 switch(spu_aamode
&15) {
819 sws_spu_image(spu
->scaled_image
, spu
->scaled_aimage
,
820 spu
->scaled_width
, spu
->scaled_height
, spu
->scaled_stride
,
821 spu
->image
, spu
->aimage
, spu
->width
, spu
->height
, spu
->stride
);
824 table_x
= calloc(spu
->scaled_width
, sizeof(scale_pixel
));
825 table_y
= calloc(spu
->scaled_height
, sizeof(scale_pixel
));
826 if (!table_x
|| !table_y
) {
827 mp_msg(MSGT_SPUDEC
, MSGL_FATAL
, "Fatal: spudec_draw_scaled: calloc failed\n");
829 scale_table(0, 0, spu
->width
- 1, spu
->scaled_width
- 1, table_x
);
830 scale_table(0, 0, spu
->height
- 1, spu
->scaled_height
- 1, table_y
);
831 for (y
= 0; y
< spu
->scaled_height
; y
++)
832 for (x
= 0; x
< spu
->scaled_width
; x
++)
833 scale_image(x
, y
, table_x
, table_y
, spu
);
838 /* no antialiasing */
839 for (y
= 0; y
< spu
->scaled_height
; ++y
) {
840 int unscaled_y
= y
* 0x100 / scaley
;
841 int strides
= spu
->stride
* unscaled_y
;
842 int scaled_strides
= spu
->scaled_stride
* y
;
843 for (x
= 0; x
< spu
->scaled_width
; ++x
) {
844 int unscaled_x
= x
* 0x100 / scalex
;
845 spu
->scaled_image
[scaled_strides
+ x
] = spu
->image
[strides
+ unscaled_x
];
846 spu
->scaled_aimage
[scaled_strides
+ x
] = spu
->aimage
[strides
+ unscaled_x
];
852 /* Intermediate antialiasing. */
853 for (y
= 0; y
< spu
->scaled_height
; ++y
) {
854 const unsigned int unscaled_top
= y
* spu
->orig_frame_height
/ dys
;
855 unsigned int unscaled_bottom
= (y
+ 1) * spu
->orig_frame_height
/ dys
;
856 if (unscaled_bottom
>= spu
->height
)
857 unscaled_bottom
= spu
->height
- 1;
858 for (x
= 0; x
< spu
->scaled_width
; ++x
) {
859 const unsigned int unscaled_left
= x
* spu
->orig_frame_width
/ dxs
;
860 unsigned int unscaled_right
= (x
+ 1) * spu
->orig_frame_width
/ dxs
;
861 unsigned int color
= 0;
862 unsigned int alpha
= 0;
863 unsigned int walkx
, walky
;
864 unsigned int base
, tmp
;
865 if (unscaled_right
>= spu
->width
)
866 unscaled_right
= spu
->width
- 1;
867 for (walky
= unscaled_top
; walky
<= unscaled_bottom
; ++walky
)
868 for (walkx
= unscaled_left
; walkx
<= unscaled_right
; ++walkx
) {
869 base
= walky
* spu
->stride
+ walkx
;
870 tmp
= canon_alpha(spu
->aimage
[base
]);
872 color
+= tmp
* spu
->image
[base
];
874 base
= y
* spu
->scaled_stride
+ x
;
875 spu
->scaled_image
[base
] = alpha
? color
/ alpha
: 0;
876 spu
->scaled_aimage
[base
] =
877 alpha
* (1 + unscaled_bottom
- unscaled_top
) * (1 + unscaled_right
- unscaled_left
);
878 /* spu->scaled_aimage[base] =
879 alpha * dxs * dys / spu->orig_frame_width / spu->orig_frame_height; */
880 if (spu
->scaled_aimage
[base
]) {
881 spu
->scaled_aimage
[base
] = 256 - spu
->scaled_aimage
[base
];
882 if (spu
->scaled_aimage
[base
] + spu
->scaled_image
[base
] > 255)
883 spu
->scaled_image
[base
] = 256 - spu
->scaled_aimage
[base
];
891 /* Best antialiasing. Very slow. */
892 /* Any pixel (x, y) represents pixels from the original
893 rectangular region comprised between the columns
894 unscaled_y and unscaled_y + 0x100 / scaley and the rows
895 unscaled_x and unscaled_x + 0x100 / scalex
897 The original rectangular region that the scaled pixel
898 represents is cut in 9 rectangular areas like this:
900 +---+-----------------+---+
902 +---+-----------------+---+
906 +---+-----------------+---+
908 +---+-----------------+---+
910 The width of the left column is at most one pixel and
911 it is never null and its right column is at a pixel
912 boundary. The height of the top row is at most one
913 pixel it is never null and its bottom row is at a
914 pixel boundary. The width and height of region 5 are
915 integral values. The width of the right column is
916 what remains and is less than one pixel. The height
917 of the bottom row is what remains and is less than
920 The row above 1, 2, 3 is unscaled_y. The row between
921 1, 2, 3 and 4, 5, 6 is top_low_row. The row between 4,
922 5, 6 and 7, 8, 9 is (unsigned int)unscaled_y_bottom.
923 The row beneath 7, 8, 9 is unscaled_y_bottom.
925 The column left of 1, 4, 7 is unscaled_x. The column
926 between 1, 4, 7 and 2, 5, 8 is left_right_column. The
927 column between 2, 5, 8 and 3, 6, 9 is (unsigned
928 int)unscaled_x_right. The column right of 3, 6, 9 is
930 const double inv_scalex
= (double) 0x100 / scalex
;
931 const double inv_scaley
= (double) 0x100 / scaley
;
932 for (y
= 0; y
< spu
->scaled_height
; ++y
) {
933 const double unscaled_y
= y
* inv_scaley
;
934 const double unscaled_y_bottom
= unscaled_y
+ inv_scaley
;
935 const unsigned int top_low_row
= MIN(unscaled_y_bottom
, unscaled_y
+ 1.0);
936 const double top
= top_low_row
- unscaled_y
;
937 const unsigned int height
= unscaled_y_bottom
> top_low_row
938 ? (unsigned int) unscaled_y_bottom
- top_low_row
940 const double bottom
= unscaled_y_bottom
> top_low_row
941 ? unscaled_y_bottom
- floor(unscaled_y_bottom
)
943 for (x
= 0; x
< spu
->scaled_width
; ++x
) {
944 const double unscaled_x
= x
* inv_scalex
;
945 const double unscaled_x_right
= unscaled_x
+ inv_scalex
;
946 const unsigned int left_right_column
= MIN(unscaled_x_right
, unscaled_x
+ 1.0);
947 const double left
= left_right_column
- unscaled_x
;
948 const unsigned int width
= unscaled_x_right
> left_right_column
949 ? (unsigned int) unscaled_x_right
- left_right_column
951 const double right
= unscaled_x_right
> left_right_column
952 ? unscaled_x_right
- floor(unscaled_x_right
)
958 /* Now use these informations to compute a good alpha,
959 and lightness. The sum is on each of the 9
960 region's surface and alpha and lightness.
962 transformed alpha = sum(surface * alpha) / sum(surface)
963 transformed color = sum(surface * alpha * color) / sum(surface * alpha)
965 /* 1: top left part */
966 base
= spu
->stride
* (unsigned int) unscaled_y
;
967 tmp
= left
* top
* canon_alpha(spu
->aimage
[base
+ (unsigned int) unscaled_x
]);
969 color
+= tmp
* spu
->image
[base
+ (unsigned int) unscaled_x
];
970 /* 2: top center part */
973 for (walkx
= left_right_column
; walkx
< (unsigned int) unscaled_x_right
; ++walkx
) {
974 base
= spu
->stride
* (unsigned int) unscaled_y
+ walkx
;
975 tmp
= /* 1.0 * */ top
* canon_alpha(spu
->aimage
[base
]);
977 color
+= tmp
* spu
->image
[base
];
980 /* 3: top right part */
982 base
= spu
->stride
* (unsigned int) unscaled_y
+ (unsigned int) unscaled_x_right
;
983 tmp
= right
* top
* canon_alpha(spu
->aimage
[base
]);
985 color
+= tmp
* spu
->image
[base
];
987 /* 4: center left part */
990 for (walky
= top_low_row
; walky
< (unsigned int) unscaled_y_bottom
; ++walky
) {
991 base
= spu
->stride
* walky
+ (unsigned int) unscaled_x
;
992 tmp
= left
/* * 1.0 */ * canon_alpha(spu
->aimage
[base
]);
994 color
+= tmp
* spu
->image
[base
];
998 if (width
> 0 && height
> 0) {
1000 for (walky
= top_low_row
; walky
< (unsigned int) unscaled_y_bottom
; ++walky
) {
1002 base
= spu
->stride
* walky
;
1003 for (walkx
= left_right_column
; walkx
< (unsigned int) unscaled_x_right
; ++walkx
) {
1004 tmp
= /* 1.0 * 1.0 * */ canon_alpha(spu
->aimage
[base
+ walkx
]);
1006 color
+= tmp
* spu
->image
[base
+ walkx
];
1010 /* 6: center right part */
1011 if (right
> 0.0 && height
> 0) {
1013 for (walky
= top_low_row
; walky
< (unsigned int) unscaled_y_bottom
; ++walky
) {
1014 base
= spu
->stride
* walky
+ (unsigned int) unscaled_x_right
;
1015 tmp
= right
/* * 1.0 */ * canon_alpha(spu
->aimage
[base
]);
1017 color
+= tmp
* spu
->image
[base
];
1020 /* 7: bottom left part */
1022 base
= spu
->stride
* (unsigned int) unscaled_y_bottom
+ (unsigned int) unscaled_x
;
1023 tmp
= left
* bottom
* canon_alpha(spu
->aimage
[base
]);
1025 color
+= tmp
* spu
->image
[base
];
1027 /* 8: bottom center part */
1028 if (width
> 0 && bottom
> 0.0) {
1030 base
= spu
->stride
* (unsigned int) unscaled_y_bottom
;
1031 for (walkx
= left_right_column
; walkx
< (unsigned int) unscaled_x_right
; ++walkx
) {
1032 tmp
= /* 1.0 * */ bottom
* canon_alpha(spu
->aimage
[base
+ walkx
]);
1034 color
+= tmp
* spu
->image
[base
+ walkx
];
1037 /* 9: bottom right part */
1038 if (right
> 0.0 && bottom
> 0.0) {
1039 base
= spu
->stride
* (unsigned int) unscaled_y_bottom
+ (unsigned int) unscaled_x_right
;
1040 tmp
= right
* bottom
* canon_alpha(spu
->aimage
[base
]);
1042 color
+= tmp
* spu
->image
[base
];
1044 /* Finally mix these transparency and brightness information suitably */
1045 base
= spu
->scaled_stride
* y
+ x
;
1046 spu
->scaled_image
[base
] = alpha
> 0 ? color
/ alpha
: 0;
1047 spu
->scaled_aimage
[base
] = alpha
* scalex
* scaley
/ 0x10000;
1048 if (spu
->scaled_aimage
[base
]) {
1049 spu
->scaled_aimage
[base
] = 256 - spu
->scaled_aimage
[base
];
1050 if (spu
->scaled_aimage
[base
] + spu
->scaled_image
[base
] > 255)
1051 spu
->scaled_image
[base
] = 256 - spu
->scaled_aimage
[base
];
1058 /* Kludge: draw_alpha needs width multiple of 8. */
1059 if (spu
->scaled_width
< spu
->scaled_stride
)
1060 for (y
= 0; y
< spu
->scaled_height
; ++y
) {
1061 memset(spu
->scaled_aimage
+ y
* spu
->scaled_stride
+ spu
->scaled_width
, 0,
1062 spu
->scaled_stride
- spu
->scaled_width
);
1064 spu
->scaled_frame_width
= dxs
;
1065 spu
->scaled_frame_height
= dys
;
1068 if (spu
->scaled_image
){
1069 switch (spu_alignment
) {
1071 spu
->scaled_start_row
= dys
*sub_pos
/100;
1072 if (spu
->scaled_start_row
+ spu
->scaled_height
> dys
)
1073 spu
->scaled_start_row
= dys
- spu
->scaled_height
;
1076 spu
->scaled_start_row
= dys
*sub_pos
/100 - spu
->scaled_height
/2;
1078 if (spu
->scaled_start_row
< 0) spu
->scaled_start_row
= 0;
1080 if (spu
->scaled_start_row
+ spu
->scaled_height
> dys
)
1081 spu
->scaled_start_row
= dys
- spu
->scaled_height
;
1085 spu
->scaled_start_row
= dys
*sub_pos
/100 - spu
->scaled_height
;
1086 if (spu
->scaled_start_row
< 0) spu
->scaled_start_row
= 0;
1089 draw_alpha(spu
->scaled_start_col
, spu
->scaled_start_row
, spu
->scaled_width
, spu
->scaled_height
,
1090 spu
->scaled_image
, spu
->scaled_aimage
, spu
->scaled_stride
);
1091 spu
->spu_changed
= 0;
1097 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"SPU not displayed: start_pts=%d end_pts=%d now_pts=%d\n",
1098 spu
->start_pts
, spu
->end_pts
, spu
->now_pts
);
1102 void spudec_update_palette(void * this, unsigned int *palette
)
1104 spudec_handle_t
*spu
= (spudec_handle_t
*) this;
1105 if (spu
&& palette
) {
1106 memcpy(spu
->global_palette
, palette
, sizeof(spu
->global_palette
));
1108 spu
->hw_spu
->control(VOCTRL_SET_SPU_PALETTE
,spu
->global_palette
);
1112 void spudec_set_font_factor(void * this, double factor
)
1114 spudec_handle_t
*spu
= (spudec_handle_t
*) this;
1115 spu
->font_start_level
= (int)(0xF0-(0xE0*factor
));
1118 void *spudec_new_scaled(unsigned int *palette
, unsigned int frame_width
, unsigned int frame_height
)
1120 return spudec_new_scaled_vobsub(palette
, NULL
, 0, frame_width
, frame_height
);
1123 /* get palette custom color, width, height from .idx file */
1124 void *spudec_new_scaled_vobsub(unsigned int *palette
, unsigned int *cuspal
, unsigned int custom
, unsigned int frame_width
, unsigned int frame_height
)
1126 spudec_handle_t
*this = calloc(1, sizeof(spudec_handle_t
));
1128 //(fprintf(stderr,"VobSub Custom Palette: %d,%d,%d,%d", this->cuspal[0], this->cuspal[1], this->cuspal[2],this->cuspal[3]);
1129 this->packet
= NULL
;
1131 this->scaled_image
= NULL
;
1132 /* XXX Although the video frame is some size, the SPU frame is
1133 always maximum size i.e. 720 wide and 576 or 480 high */
1134 this->orig_frame_width
= 720;
1135 this->orig_frame_height
= (frame_height
== 480 || frame_height
== 240) ? 480 : 576;
1136 this->custom
= custom
;
1138 this->auto_palette
= 1;
1140 memcpy(this->global_palette
, palette
, sizeof(this->global_palette
));
1141 this->auto_palette
= 0;
1143 this->custom
= custom
;
1144 if (custom
&& cuspal
) {
1145 memcpy(this->cuspal
, cuspal
, sizeof(this->cuspal
));
1146 this->auto_palette
= 0;
1148 // forced subtitles default: show all subtitles
1149 this->forced_subs_only
=0;
1150 this->is_forced_sub
=0;
1153 mp_msg(MSGT_SPUDEC
,MSGL_FATAL
, "FATAL: spudec_init: calloc");
1157 void *spudec_new(unsigned int *palette
)
1159 return spudec_new_scaled(palette
, 0, 0);
1162 void spudec_free(void *this)
1164 spudec_handle_t
*spu
= (spudec_handle_t
*)this;
1166 while (spu
->queue_head
)
1167 spudec_free_packet(spudec_dequeue_packet(spu
));
1170 if (spu
->scaled_image
)
1171 free(spu
->scaled_image
);
1178 void spudec_set_hw_spu(void *this, vo_functions_t
*hw_spu
)
1180 spudec_handle_t
*spu
= (spudec_handle_t
*)this;
1183 spu
->hw_spu
= hw_spu
;
1184 hw_spu
->control(VOCTRL_SET_SPU_PALETTE
,spu
->global_palette
);