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"
26 #include "postproc/swscale.h"
28 #define MIN(a, b) ((a)<(b)?(a):(b))
30 /* Valid values for spu_aamode:
31 0: none (fastest, most ugly)
34 3: bilinear (similiar to vobsub, fast and not too bad)
35 4: uses swscaler gaussian (this is the only one that looks good)
39 int spu_alignment
= -1;
40 float spu_gaussvar
= 1.0;
43 typedef struct packet_t packet_t
;
45 unsigned char *packet
;
46 unsigned int palette
[4];
47 unsigned int alpha
[4];
48 unsigned int control_start
; /* index of start of control data */
49 unsigned int current_nibble
[2]; /* next data nibble (4 bits) to be
50 processed (for RLE decoding) for
52 int deinterlace_oddness
; /* 0 or 1, index into current_nibble */
53 unsigned int start_col
, end_col
;
54 unsigned int start_row
, end_row
;
55 unsigned int width
, height
, stride
;
56 unsigned int start_pts
, end_pts
;
63 unsigned int global_palette
[16];
64 unsigned int orig_frame_width
, orig_frame_height
;
65 unsigned char* packet
;
66 size_t packet_reserve
; /* size of the memory pointed to by packet */
67 unsigned int packet_offset
; /* end of the currently assembled fragment */
68 unsigned int packet_size
; /* size of the packet once all fragments are assembled */
69 unsigned int packet_pts
; /* PTS for this packet */
70 unsigned int palette
[4];
71 unsigned int alpha
[4];
72 unsigned int cuspal
[4];
75 unsigned int start_pts
, end_pts
;
76 unsigned int start_col
, end_col
;
77 unsigned int start_row
, end_row
;
78 unsigned int width
, height
, stride
;
79 size_t image_size
; /* Size of the image buffer */
80 unsigned char *image
; /* Grayscale value */
81 unsigned char *aimage
; /* Alpha value */
82 unsigned int scaled_frame_width
, scaled_frame_height
;
83 unsigned int scaled_start_col
, scaled_start_row
;
84 unsigned int scaled_width
, scaled_height
, scaled_stride
;
85 size_t scaled_image_size
;
86 unsigned char *scaled_image
;
87 unsigned char *scaled_aimage
;
88 int auto_palette
; /* 1 if we lack a palette and must use an heuristic. */
89 int font_start_level
; /* Darkest value used for the computed font */
90 vo_functions_t
*hw_spu
;
94 static void spudec_queue_packet(spudec_handle_t
*this, packet_t
*packet
)
96 if (this->queue_head
== NULL
)
97 this->queue_head
= packet
;
99 this->queue_tail
->next
= packet
;
100 this->queue_tail
= packet
;
103 static packet_t
*spudec_dequeue_packet(spudec_handle_t
*this)
105 packet_t
*retval
= this->queue_head
;
107 this->queue_head
= retval
->next
;
108 if (this->queue_head
== NULL
)
109 this->queue_tail
= NULL
;
114 static void spudec_free_packet(packet_t
*packet
)
116 if (packet
->packet
!= NULL
)
117 free(packet
->packet
);
121 static inline unsigned int get_be16(const unsigned char *p
)
123 return (p
[0] << 8) + p
[1];
126 static inline unsigned int get_be24(const unsigned char *p
)
128 return (get_be16(p
) << 8) + p
[2];
131 static void next_line(packet_t
*packet
)
133 if (packet
->current_nibble
[packet
->deinterlace_oddness
] % 2)
134 packet
->current_nibble
[packet
->deinterlace_oddness
]++;
135 packet
->deinterlace_oddness
= (packet
->deinterlace_oddness
+ 1) % 2;
138 static inline unsigned char get_nibble(packet_t
*packet
)
141 unsigned int *nibblep
= packet
->current_nibble
+ packet
->deinterlace_oddness
;
142 if (*nibblep
/ 2 >= packet
->control_start
) {
143 mp_msg(MSGT_SPUDEC
,MSGL_WARN
, "SPUdec: ERROR: get_nibble past end of packet\n");
146 nib
= packet
->packet
[*nibblep
/ 2];
155 static inline int mkalpha(int i
)
157 /* In mplayer's alpha planes, 0 is transparent, then 1 is nearly
158 opaque upto 255 which is transparent */
165 return (0xf - i
) << 4;
169 /* Cut the sub to visible part */
170 static inline void spudec_cut_image(spudec_handle_t
*this)
173 unsigned int first_y
, last_y
;
174 unsigned char *image
;
175 unsigned char *aimage
;
177 if (this->stride
== 0 || this->height
== 0) {
181 for (fy
= 0; fy
< this->image_size
&& !this->aimage
[fy
]; fy
++);
182 for (ly
= this->stride
* this->height
-1; ly
&& !this->aimage
[ly
]; ly
--);
183 first_y
= fy
/ this->stride
;
184 last_y
= ly
/ this->stride
;
185 //printf("first_y: %d, last_y: %d\n", first_y, last_y);
186 this->start_row
+= first_y
;
188 // Some subtitles trigger this condition
189 if (last_y
+ 1 > first_y
) {
190 this->height
= last_y
- first_y
+1;
193 this->image_size
= 0;
197 // printf("new h %d new start %d (sz %d st %d)---\n\n", this->height, this->start_row, this->image_size, this->stride);
199 image
= malloc(2 * this->stride
* this->height
);
201 this->image_size
= this->stride
* this->height
;
202 aimage
= image
+ this->image_size
;
203 memcpy(image
, this->image
+ this->stride
* first_y
, this->image_size
);
204 memcpy(aimage
, this->aimage
+ this->stride
* first_y
, this->image_size
);
207 this->aimage
= aimage
;
209 mp_msg(MSGT_SPUDEC
, MSGL_FATAL
, "Fatal: update_spu: malloc requested %d bytes\n", 2 * this->stride
* this->height
);
213 static void spudec_process_data(spudec_handle_t
*this, packet_t
*packet
)
215 unsigned int cmap
[4], alpha
[4];
216 unsigned int i
, x
, y
;
218 this->scaled_frame_width
= 0;
219 this->scaled_frame_height
= 0;
220 this->start_col
= packet
->start_col
;
221 this->end_col
= packet
->end_col
;
222 this->start_row
= packet
->start_row
;
223 this->end_row
= packet
->end_row
;
224 this->height
= packet
->height
;
225 this->width
= packet
->width
;
226 this->stride
= packet
->stride
;
227 for (i
= 0; i
< 4; ++i
) {
228 alpha
[i
] = mkalpha(packet
->alpha
[i
]);
231 else if (this->custom
){
232 cmap
[i
] = ((this->cuspal
[i
] >> 16) & 0xff);
233 if (cmap
[i
] + alpha
[i
] > 255)
234 cmap
[i
] = 256 - alpha
[i
];
237 cmap
[i
] = ((this->global_palette
[packet
->palette
[i
]] >> 16) & 0xff);
238 if (cmap
[i
] + alpha
[i
] > 255)
239 cmap
[i
] = 256 - alpha
[i
];
243 if (this->image_size
< this->stride
* this->height
) {
244 if (this->image
!= NULL
) {
246 this->image_size
= 0;
248 this->image
= malloc(2 * this->stride
* this->height
);
250 this->image_size
= this->stride
* this->height
;
251 this->aimage
= this->image
+ this->image_size
;
254 if (this->image
== NULL
)
257 /* Kludge: draw_alpha needs width multiple of 8. */
258 if (this->width
< this->stride
)
259 for (y
= 0; y
< this->height
; ++y
) {
260 memset(this->aimage
+ y
* this->stride
+ this->width
, 0, this->stride
- this->width
);
261 /* FIXME: Why is this one needed? */
262 memset(this->image
+ y
* this->stride
+ this->width
, 0, this->stride
- this->width
);
265 i
= packet
->current_nibble
[1];
268 while (packet
->current_nibble
[0] < i
269 && packet
->current_nibble
[1] / 2 < packet
->control_start
270 && y
< this->height
) {
271 unsigned int len
, color
;
272 unsigned int rle
= 0;
273 rle
= get_nibble(packet
);
275 rle
= (rle
<< 4) | get_nibble(packet
);
277 rle
= (rle
<< 4) | get_nibble(packet
);
279 rle
= (rle
<< 4) | get_nibble(packet
);
281 rle
|= ((this->width
- x
) << 2);
285 color
= 3 - (rle
& 0x3);
287 if (len
> this->width
- x
|| len
== 0)
288 len
= this->width
- x
;
289 /* FIXME have to use palette and alpha map*/
290 memset(this->image
+ y
* this->stride
+ x
, cmap
[color
], len
);
291 memset(this->aimage
+ y
* this->stride
+ x
, alpha
[color
], len
);
293 if (x
>= this->width
) {
299 spudec_cut_image(this);
304 This function tries to create a usable palette.
305 Is searchs how many non-transparent colors are used and assigns different
306 gray scale values to each color.
307 I tested it with four streams and even got something readable. Half of the
308 times I got black characters with white around and half the reverse.
310 static void compute_palette(spudec_handle_t
*this, packet_t
*packet
)
312 int used
[16],i
,cused
,start
,step
,color
;
314 memset(used
, 0, sizeof(used
));
316 if (packet
->alpha
[i
]) /* !Transparent? */
317 used
[packet
->palette
[i
]] = 1;
318 for (cused
=0, i
=0; i
<16; i
++)
319 if (used
[i
]) cused
++;
325 start
= this->font_start_level
;
326 step
= (0xF0-this->font_start_level
)/(cused
-1);
328 memset(used
, 0, sizeof(used
));
329 for (i
=0; i
<4; i
++) {
330 color
= packet
->palette
[i
];
331 if (packet
->alpha
[i
] && !used
[color
]) { /* not assigned? */
333 this->global_palette
[color
] = start
<<16;
339 static void spudec_process_control(spudec_handle_t
*this, unsigned int pts100
)
341 int a
,b
; /* Temporary vars */
342 unsigned int date
, type
;
344 unsigned int start_off
= 0;
345 unsigned int next_off
;
346 unsigned int start_pts
;
347 unsigned int end_pts
;
348 unsigned int current_nibble
[2];
349 unsigned int control_start
;
350 unsigned int display
= 0;
351 unsigned int start_col
= 0;
352 unsigned int end_col
= 0;
353 unsigned int start_row
= 0;
354 unsigned int end_row
= 0;
355 unsigned int width
= 0;
356 unsigned int height
= 0;
357 unsigned int stride
= 0;
359 control_start
= get_be16(this->packet
+ 2);
360 next_off
= control_start
;
361 while (start_off
!= next_off
) {
362 start_off
= next_off
;
363 date
= get_be16(this->packet
+ start_off
) * 1024;
364 next_off
= get_be16(this->packet
+ start_off
+ 2);
365 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
, "date=%d\n", date
);
367 for (type
= this->packet
[off
++]; type
!= 0xff; type
= this->packet
[off
++]) {
368 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
, "cmd=%d ",type
);
371 /* Menu ID, 1 byte */
372 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Menu ID\n");
373 /* shouldn't a Menu ID type force display start? */
374 //this->start_pts = pts100 + date;
375 //this->end_pts = UINT_MAX;
379 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Start display!\n");
380 start_pts
= pts100
+ date
;
386 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Stop display!\n");
387 end_pts
= pts100
+ date
;
391 this->palette
[0] = this->packet
[off
] >> 4;
392 this->palette
[1] = this->packet
[off
] & 0xf;
393 this->palette
[2] = this->packet
[off
+ 1] >> 4;
394 this->palette
[3] = this->packet
[off
+ 1] & 0xf;
395 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Palette %d, %d, %d, %d\n",
396 this->palette
[0], this->palette
[1], this->palette
[2], this->palette
[3]);
401 this->alpha
[0] = this->packet
[off
] >> 4;
402 this->alpha
[1] = this->packet
[off
] & 0xf;
403 this->alpha
[2] = this->packet
[off
+ 1] >> 4;
404 this->alpha
[3] = this->packet
[off
+ 1] & 0xf;
405 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Alpha %d, %d, %d, %d\n",
406 this->alpha
[0], this->alpha
[1], this->alpha
[2], this->alpha
[3]);
411 a
= get_be24(this->packet
+ off
);
412 b
= get_be24(this->packet
+ off
+ 3);
415 width
= (end_col
< start_col
) ? 0 : end_col
- start_col
+ 1;
416 stride
= (width
+ 7) & ~7; /* Kludge: draw_alpha needs width multiple of 8 */
419 height
= (end_row
< start_row
) ? 0 : end_row
- start_row
/* + 1 */;
420 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Coords col: %d - %d row: %d - %d (%dx%d)\n",
421 start_col
, end_col
, start_row
, end_row
,
427 current_nibble
[0] = 2 * get_be16(this->packet
+ off
);
428 current_nibble
[1] = 2 * get_be16(this->packet
+ off
+ 2);
429 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Graphic offset 1: %d offset 2: %d\n",
430 current_nibble
[0] / 2, current_nibble
[1] / 2);
434 /* All done, bye-bye */
435 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Done!\n");
439 mp_msg(MSGT_SPUDEC
,MSGL_WARN
,"spudec: Error determining control type 0x%02x. Skipping %d bytes.\n",
440 type
, next_off
- off
);
446 packet_t
*packet
= calloc(1, sizeof(packet_t
));
448 packet
->start_pts
= start_pts
;
449 if (end_pts
== UINT_MAX
&& start_off
!= next_off
) {
450 start_pts
= pts100
+ get_be16(this->packet
+ next_off
) * 1024;
451 packet
->end_pts
= start_pts
- 1;
452 } else packet
->end_pts
= end_pts
;
453 packet
->current_nibble
[0] = current_nibble
[0];
454 packet
->current_nibble
[1] = current_nibble
[1];
455 packet
->start_row
= start_row
;
456 packet
->end_row
= end_row
;
457 packet
->start_col
= start_col
;
458 packet
->end_col
= end_col
;
459 packet
->width
= width
;
460 packet
->height
= height
;
461 packet
->stride
= stride
;
462 packet
->control_start
= control_start
;
463 for (i
=0; i
<4; i
++) {
464 packet
->alpha
[i
] = this->alpha
[i
];
465 packet
->palette
[i
] = this->palette
[i
];
467 packet
->packet
= malloc(this->packet_size
);
468 memcpy(packet
->packet
, this->packet
, this->packet_size
);
469 spudec_queue_packet(this, packet
);
474 static void spudec_decode(spudec_handle_t
*this, unsigned int pts100
)
477 static vo_mpegpes_t packet
= { NULL
, 0, 0x20, 0 };
478 static vo_mpegpes_t
*pkg
=&packet
;
479 packet
.data
= this->packet
;
480 packet
.size
= this->packet_size
;
481 packet
.timestamp
= pts100
;
482 this->hw_spu
->draw_frame((uint8_t**)&pkg
);
484 spudec_process_control(this, pts100
);
487 int spudec_changed(void * this)
489 spudec_handle_t
* spu
= (spudec_handle_t
*)this;
490 return (spu
->spu_changed
|| spu
->now_pts
> spu
->end_pts
);
493 void spudec_assemble(void *this, unsigned char *packet
, unsigned int len
, unsigned int pts100
)
495 spudec_handle_t
*spu
= (spudec_handle_t
*)this;
496 // spudec_heartbeat(this, pts100);
498 mp_msg(MSGT_SPUDEC
,MSGL_WARN
,"SPUasm: packet too short\n");
501 if ((spu
->packet_pts
+ 10000) < pts100
) {
502 // [cb] too long since last fragment: force new packet
503 spu
->packet_offset
= 0;
505 spu
->packet_pts
= pts100
;
506 if (spu
->packet_offset
== 0) {
507 unsigned int len2
= get_be16(packet
);
508 // Start new fragment
509 if (spu
->packet_reserve
< len2
) {
510 if (spu
->packet
!= NULL
)
512 spu
->packet
= malloc(len2
);
513 spu
->packet_reserve
= spu
->packet
!= NULL
? len2
: 0;
515 if (spu
->packet
!= NULL
) {
516 spu
->packet_size
= len2
;
518 mp_msg(MSGT_SPUDEC
,MSGL_WARN
,"SPUasm: invalid frag len / len2: %d / %d \n", len
, len2
);
521 memcpy(spu
->packet
, packet
, len
);
522 spu
->packet_offset
= len
;
523 spu
->packet_pts
= pts100
;
526 // Continue current fragment
527 if (spu
->packet_size
< spu
->packet_offset
+ len
){
528 mp_msg(MSGT_SPUDEC
,MSGL_WARN
,"SPUasm: invalid fragment\n");
529 spu
->packet_size
= spu
->packet_offset
= 0;
532 memcpy(spu
->packet
+ spu
->packet_offset
, packet
, len
);
533 spu
->packet_offset
+= len
;
537 // check if we have a complete packet (unfortunatelly packet_size is bad
539 // [cb] packet_size is padded to be even -> may be one byte too long
540 if ((spu
->packet_offset
== spu
->packet_size
) ||
541 ((spu
->packet_offset
+ 1) == spu
->packet_size
)){
543 while(x
+4<=spu
->packet_offset
){
544 y
=get_be16(spu
->packet
+x
+2); // next control pointer
545 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"SPUtest: x=%d y=%d off=%d size=%d\n",x
,y
,spu
->packet_offset
,spu
->packet_size
);
546 if(x
>=4 && x
==y
){ // if it points to self - we're done!
548 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"SPUgot: off=%d size=%d \n",spu
->packet_offset
,spu
->packet_size
);
549 spudec_decode(spu
, pts100
);
550 spu
->packet_offset
= 0;
553 if(y
<=x
|| y
>=spu
->packet_size
){ // invalid?
554 mp_msg(MSGT_SPUDEC
,MSGL_WARN
,"SPUtest: broken packet!!!!! y=%d < x=%d\n",y
,x
);
555 spu
->packet_size
= spu
->packet_offset
= 0;
560 // [cb] packet is done; start new packet
561 spu
->packet_offset
= 0;
564 if (spu
->packet_offset
== spu
->packet_size
) {
565 spudec_decode(spu
, pts100
);
566 spu
->packet_offset
= 0;
571 void spudec_reset(void *this) // called after seek
573 spudec_handle_t
*spu
= (spudec_handle_t
*)this;
574 while (spu
->queue_head
)
575 spudec_free_packet(spudec_dequeue_packet(spu
));
578 spu
->packet_size
= spu
->packet_offset
= 0;
581 void spudec_heartbeat(void *this, unsigned int pts100
)
583 spudec_handle_t
*spu
= (spudec_handle_t
*) this;
584 spu
->now_pts
= pts100
;
586 while (spu
->queue_head
!= NULL
&& pts100
>= spu
->queue_head
->start_pts
) {
587 packet_t
*packet
= spudec_dequeue_packet(spu
);
588 spu
->start_pts
= packet
->start_pts
;
589 spu
->end_pts
= packet
->end_pts
;
590 if (spu
->auto_palette
)
591 compute_palette(spu
, packet
);
592 spudec_process_data(spu
, packet
);
593 spudec_free_packet(packet
);
594 spu
->spu_changed
= 1;
598 int spudec_visible(void *this){
599 spudec_handle_t
*spu
= (spudec_handle_t
*)this;
600 int ret
=(spu
->start_pts
<= spu
->now_pts
&&
601 spu
->now_pts
< spu
->end_pts
&&
603 // printf("spu visible: %d \n",ret);
607 void spudec_draw(void *this, void (*draw_alpha
)(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
))
609 spudec_handle_t
*spu
= (spudec_handle_t
*)this;
610 if (spu
->start_pts
<= spu
->now_pts
&& spu
->now_pts
< spu
->end_pts
&& spu
->image
)
612 draw_alpha(spu
->start_col
, spu
->start_row
, spu
->width
, spu
->height
,
613 spu
->image
, spu
->aimage
, spu
->stride
);
614 spu
->spu_changed
= 0;
618 /* calc the bbox for spudec subs */
619 void spudec_calc_bbox(void *me
, unsigned int dxs
, unsigned int dys
, unsigned int* bbox
)
621 spudec_handle_t
*spu
;
622 spu
= (spudec_handle_t
*)me
;
623 if (spu
->orig_frame_width
== 0 || spu
->orig_frame_height
== 0
624 || (spu
->orig_frame_width
== dxs
&& spu
->orig_frame_height
== dys
)) {
625 bbox
[0] = spu
->start_col
;
626 bbox
[1] = spu
->start_col
+ spu
->width
;
627 bbox
[2] = spu
->start_row
;
628 bbox
[3] = spu
->start_row
+ spu
->height
;
630 else if (spu
->scaled_frame_width
!= dxs
|| spu
->scaled_frame_height
!= dys
) {
631 unsigned int scalex
= 0x100 * dxs
/ spu
->orig_frame_width
;
632 unsigned int scaley
= 0x100 * dys
/ spu
->orig_frame_height
;
633 bbox
[0] = spu
->start_col
* scalex
/ 0x100;
634 bbox
[1] = spu
->start_col
* scalex
/ 0x100 + spu
->width
* scalex
/ 0x100;
635 switch (spu_alignment
) {
637 bbox
[3] = dys
*sub_pos
/100 + spu
->height
* scaley
/ 0x100;
638 if (bbox
[3] > dys
) bbox
[3] = dys
;
639 bbox
[2] = bbox
[3] - spu
->height
* scaley
/ 0x100;
643 bbox
[2] = dys
*sub_pos
/100 - spu
->height
* scaley
/ 0x200;
644 if (bbox
[2] < 0) bbox
[2] = 0;
645 bbox
[3] = bbox
[2] + spu
->height
;
647 bbox
[3] = dys
*sub_pos
/100 + spu
->height
* scaley
/ 0x200;
648 if (bbox
[3] > dys
) bbox
[3] = dys
;
649 bbox
[2] = bbox
[3] - spu
->height
* scaley
/ 0x100;
653 bbox
[2] = dys
*sub_pos
/100 - spu
->height
* scaley
/ 0x100;
654 if (bbox
[2] < 0) bbox
[2] = 0;
655 bbox
[3] = bbox
[2] + spu
->height
;
658 bbox
[2] = spu
->start_row
* scaley
/ 0x100;
659 bbox
[3] = spu
->start_row
* scaley
/ 0x100 + spu
->height
* scaley
/ 0x100;
664 /* transform mplayer's alpha value into an opacity value that is linear */
665 static inline int canon_alpha(int alpha
)
667 return alpha
? 256 - alpha
: 0;
677 static void scale_table(unsigned int start_src
, unsigned int start_tar
, unsigned int end_src
, unsigned int end_tar
, scale_pixel
* table
)
680 unsigned int delta_src
= end_src
- start_src
;
681 unsigned int delta_tar
= end_tar
- start_tar
;
684 if (delta_src
== 0 || delta_tar
== 0) {
687 src_step
= (delta_src
<< 16) / delta_tar
>>1;
688 for (t
= 0; t
<=delta_tar
; src
+= (src_step
<< 1), t
++){
689 table
[t
].position
= MIN(src
>> 16, end_src
- 1);
690 table
[t
].right_down
= src
& 0xffff;
691 table
[t
].left_up
= 0x10000 - table
[t
].right_down
;
695 /* bilinear scale, similar to vobsub's code */
696 static void scale_image(int x
, int y
, scale_pixel
* table_x
, scale_pixel
* table_y
, spudec_handle_t
* spu
)
700 unsigned int scale
[4];
701 int base
= table_y
[y
].position
* spu
->stride
+ table_x
[x
].position
;
702 int scaled
= y
* spu
->scaled_stride
+ x
;
703 alpha
[0] = canon_alpha(spu
->aimage
[base
]);
704 alpha
[1] = canon_alpha(spu
->aimage
[base
+ 1]);
705 alpha
[2] = canon_alpha(spu
->aimage
[base
+ spu
->stride
]);
706 alpha
[3] = canon_alpha(spu
->aimage
[base
+ spu
->stride
+ 1]);
707 color
[0] = spu
->image
[base
];
708 color
[1] = spu
->image
[base
+ 1];
709 color
[2] = spu
->image
[base
+ spu
->stride
];
710 color
[3] = spu
->image
[base
+ spu
->stride
+ 1];
711 scale
[0] = (table_x
[x
].left_up
* table_y
[y
].left_up
>> 16) * alpha
[0];
712 scale
[1] = (table_x
[x
].right_down
* table_y
[y
].left_up
>>16) * alpha
[1];
713 scale
[2] = (table_x
[x
].left_up
* table_y
[y
].right_down
>> 16) * alpha
[2];
714 scale
[3] = (table_x
[x
].right_down
* table_y
[y
].right_down
>> 16) * alpha
[3];
715 spu
->scaled_image
[scaled
] = (color
[0] * scale
[0] + color
[1] * scale
[1] + color
[2] * scale
[2] + color
[3] * scale
[3])>>24;
716 spu
->scaled_aimage
[scaled
] = (scale
[0] + scale
[1] + scale
[2] + scale
[3]) >> 16;
717 if (spu
->scaled_aimage
[scaled
]){
718 spu
->scaled_aimage
[scaled
] = 256 - spu
->scaled_aimage
[scaled
];
719 if(spu
->scaled_aimage
[scaled
] + spu
->scaled_image
[scaled
] > 255)
720 spu
->scaled_image
[scaled
] = 256 - spu
->scaled_aimage
[scaled
];
724 void sws_spu_image(unsigned char *d1
, unsigned char *d2
, int dw
, int dh
, int ds
,
725 unsigned char *s1
, unsigned char *s2
, int sw
, int sh
, int ss
)
727 struct SwsContext
*ctx
;
728 static SwsFilter filter
;
729 static int firsttime
= 1;
733 if (!firsttime
&& oldvar
!= spu_gaussvar
) sws_freeVec(filter
.lumH
);
735 filter
.lumH
= filter
.lumV
=
736 filter
.chrH
= filter
.chrV
= sws_getGaussianVec(spu_gaussvar
, 3.0);
737 sws_normalizeVec(filter
.lumH
, 1.0);
739 oldvar
= spu_gaussvar
;
742 ctx
=sws_getContext(sw
, sh
, IMGFMT_Y800
, dw
, dh
, IMGFMT_Y800
, SWS_GAUSS
, &filter
, NULL
);
743 sws_scale(ctx
,&s1
,&ss
,0,sh
,&d1
,&ds
);
744 for (i
=ss
*sh
-1; i
>=0; i
--) if (!s2
[i
]) s2
[i
] = 255; //else s2[i] = 1;
745 sws_scale(ctx
,&s2
,&ss
,0,sh
,&d2
,&ds
);
746 for (i
=ds
*dh
-1; i
>=0; i
--) if (d2
[i
]==0) d2
[i
] = 1; else if (d2
[i
]==255) d2
[i
] = 0;
747 sws_freeContext(ctx
);
750 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
))
752 spudec_handle_t
*spu
= (spudec_handle_t
*)me
;
753 scale_pixel
*table_x
;
754 scale_pixel
*table_y
;
755 if (spu
->start_pts
<= spu
->now_pts
&& spu
->now_pts
< spu
->end_pts
) {
756 if (!(spu_aamode
&16) && (spu
->orig_frame_width
== 0 || spu
->orig_frame_height
== 0
757 || (spu
->orig_frame_width
== dxs
&& spu
->orig_frame_height
== dys
))) {
760 draw_alpha(spu
->start_col
, spu
->start_row
, spu
->width
, spu
->height
,
761 spu
->image
, spu
->aimage
, spu
->stride
);
762 spu
->spu_changed
= 0;
766 if (spu
->scaled_frame_width
!= dxs
|| spu
->scaled_frame_height
!= dys
) { /* Resizing is needed */
767 /* scaled_x = scalex * x / 0x100
768 scaled_y = scaley * y / 0x100
769 order of operations is important because of rounding. */
770 unsigned int scalex
= 0x100 * dxs
/ spu
->orig_frame_width
;
771 unsigned int scaley
= 0x100 * dys
/ spu
->orig_frame_height
;
772 spu
->scaled_start_col
= spu
->start_col
* scalex
/ 0x100;
773 spu
->scaled_start_row
= spu
->start_row
* scaley
/ 0x100;
774 spu
->scaled_width
= spu
->width
* scalex
/ 0x100;
775 spu
->scaled_height
= spu
->height
* scaley
/ 0x100;
776 /* Kludge: draw_alpha needs width multiple of 8 */
777 spu
->scaled_stride
= (spu
->scaled_width
+ 7) & ~7;
778 if (spu
->scaled_image_size
< spu
->scaled_stride
* spu
->scaled_height
) {
779 if (spu
->scaled_image
) {
780 free(spu
->scaled_image
);
781 spu
->scaled_image_size
= 0;
783 spu
->scaled_image
= malloc(2 * spu
->scaled_stride
* spu
->scaled_height
);
784 if (spu
->scaled_image
) {
785 spu
->scaled_image_size
= spu
->scaled_stride
* spu
->scaled_height
;
786 spu
->scaled_aimage
= spu
->scaled_image
+ spu
->scaled_image_size
;
789 if (spu
->scaled_image
) {
791 /* Kludge: draw_alpha needs width multiple of 8. */
792 if (spu
->scaled_width
< spu
->scaled_stride
)
793 for (y
= 0; y
< spu
->scaled_height
; ++y
) {
794 memset(spu
->scaled_aimage
+ y
* spu
->scaled_stride
+ spu
->scaled_width
, 0,
795 spu
->scaled_stride
- spu
->scaled_width
);
796 /* FIXME: Why is this one needed? */
797 memset(spu
->scaled_image
+ y
* spu
->scaled_stride
+ spu
->scaled_width
, 0,
798 spu
->scaled_stride
- spu
->scaled_width
);
800 if (spu
->scaled_width
<= 1 || spu
->scaled_height
<= 1) {
803 switch(spu_aamode
&15) {
805 sws_spu_image(spu
->scaled_image
, spu
->scaled_aimage
,
806 spu
->scaled_width
, spu
->scaled_height
, spu
->scaled_stride
,
807 spu
->image
, spu
->aimage
, spu
->width
, spu
->height
, spu
->stride
);
810 table_x
= calloc(spu
->scaled_width
, sizeof(scale_pixel
));
811 table_y
= calloc(spu
->scaled_height
, sizeof(scale_pixel
));
812 if (!table_x
|| !table_y
) {
813 mp_msg(MSGT_SPUDEC
, MSGL_FATAL
, "Fatal: spudec_draw_scaled: calloc failed\n");
815 scale_table(0, 0, spu
->width
- 1, spu
->scaled_width
- 1, table_x
);
816 scale_table(0, 0, spu
->height
- 1, spu
->scaled_height
- 1, table_y
);
817 for (y
= 0; y
< spu
->scaled_height
; y
++)
818 for (x
= 0; x
< spu
->scaled_width
; x
++)
819 scale_image(x
, y
, table_x
, table_y
, spu
);
824 /* no antialiasing */
825 for (y
= 0; y
< spu
->scaled_height
; ++y
) {
826 int unscaled_y
= y
* 0x100 / scaley
;
827 int strides
= spu
->stride
* unscaled_y
;
828 int scaled_strides
= spu
->scaled_stride
* y
;
829 for (x
= 0; x
< spu
->scaled_width
; ++x
) {
830 int unscaled_x
= x
* 0x100 / scalex
;
831 spu
->scaled_image
[scaled_strides
+ x
] = spu
->image
[strides
+ unscaled_x
];
832 spu
->scaled_aimage
[scaled_strides
+ x
] = spu
->aimage
[strides
+ unscaled_x
];
838 /* Intermediate antialiasing. */
839 for (y
= 0; y
< spu
->scaled_height
; ++y
) {
840 const unsigned int unscaled_top
= y
* spu
->orig_frame_height
/ dys
;
841 unsigned int unscaled_bottom
= (y
+ 1) * spu
->orig_frame_height
/ dys
;
842 if (unscaled_bottom
>= spu
->height
)
843 unscaled_bottom
= spu
->height
- 1;
844 for (x
= 0; x
< spu
->scaled_width
; ++x
) {
845 const unsigned int unscaled_left
= x
* spu
->orig_frame_width
/ dxs
;
846 unsigned int unscaled_right
= (x
+ 1) * spu
->orig_frame_width
/ dxs
;
847 unsigned int color
= 0;
848 unsigned int alpha
= 0;
849 unsigned int walkx
, walky
;
850 unsigned int base
, tmp
;
851 if (unscaled_right
>= spu
->width
)
852 unscaled_right
= spu
->width
- 1;
853 for (walky
= unscaled_top
; walky
<= unscaled_bottom
; ++walky
)
854 for (walkx
= unscaled_left
; walkx
<= unscaled_right
; ++walkx
) {
855 base
= walky
* spu
->stride
+ walkx
;
856 tmp
= canon_alpha(spu
->aimage
[base
]);
858 color
+= tmp
* spu
->image
[base
];
860 base
= y
* spu
->scaled_stride
+ x
;
861 spu
->scaled_image
[base
] = alpha
? color
/ alpha
: 0;
862 spu
->scaled_aimage
[base
] =
863 alpha
* (1 + unscaled_bottom
- unscaled_top
) * (1 + unscaled_right
- unscaled_left
);
864 /* spu->scaled_aimage[base] =
865 alpha * dxs * dys / spu->orig_frame_width / spu->orig_frame_height; */
866 if (spu
->scaled_aimage
[base
]) {
867 spu
->scaled_aimage
[base
] = 256 - spu
->scaled_aimage
[base
];
868 if (spu
->scaled_aimage
[base
] + spu
->scaled_image
[base
] > 255)
869 spu
->scaled_image
[base
] = 256 - spu
->scaled_aimage
[base
];
877 /* Best antialiasing. Very slow. */
878 /* Any pixel (x, y) represents pixels from the original
879 rectangular region comprised between the columns
880 unscaled_y and unscaled_y + 0x100 / scaley and the rows
881 unscaled_x and unscaled_x + 0x100 / scalex
883 The original rectangular region that the scaled pixel
884 represents is cut in 9 rectangular areas like this:
886 +---+-----------------+---+
888 +---+-----------------+---+
892 +---+-----------------+---+
894 +---+-----------------+---+
896 The width of the left column is at most one pixel and
897 it is never null and its right column is at a pixel
898 boundary. The height of the top row is at most one
899 pixel it is never null and its bottom row is at a
900 pixel boundary. The width and height of region 5 are
901 integral values. The width of the right column is
902 what remains and is less than one pixel. The height
903 of the bottom row is what remains and is less than
906 The row above 1, 2, 3 is unscaled_y. The row between
907 1, 2, 3 and 4, 5, 6 is top_low_row. The row between 4,
908 5, 6 and 7, 8, 9 is (unsigned int)unscaled_y_bottom.
909 The row beneath 7, 8, 9 is unscaled_y_bottom.
911 The column left of 1, 4, 7 is unscaled_x. The column
912 between 1, 4, 7 and 2, 5, 8 is left_right_column. The
913 column between 2, 5, 8 and 3, 6, 9 is (unsigned
914 int)unscaled_x_right. The column right of 3, 6, 9 is
916 const double inv_scalex
= (double) 0x100 / scalex
;
917 const double inv_scaley
= (double) 0x100 / scaley
;
918 for (y
= 0; y
< spu
->scaled_height
; ++y
) {
919 const double unscaled_y
= y
* inv_scaley
;
920 const double unscaled_y_bottom
= unscaled_y
+ inv_scaley
;
921 const unsigned int top_low_row
= MIN(unscaled_y_bottom
, unscaled_y
+ 1.0);
922 const double top
= top_low_row
- unscaled_y
;
923 const unsigned int height
= unscaled_y_bottom
> top_low_row
924 ? (unsigned int) unscaled_y_bottom
- top_low_row
926 const double bottom
= unscaled_y_bottom
> top_low_row
927 ? unscaled_y_bottom
- floor(unscaled_y_bottom
)
929 for (x
= 0; x
< spu
->scaled_width
; ++x
) {
930 const double unscaled_x
= x
* inv_scalex
;
931 const double unscaled_x_right
= unscaled_x
+ inv_scalex
;
932 const unsigned int left_right_column
= MIN(unscaled_x_right
, unscaled_x
+ 1.0);
933 const double left
= left_right_column
- unscaled_x
;
934 const unsigned int width
= unscaled_x_right
> left_right_column
935 ? (unsigned int) unscaled_x_right
- left_right_column
937 const double right
= unscaled_x_right
> left_right_column
938 ? unscaled_x_right
- floor(unscaled_x_right
)
944 /* Now use these informations to compute a good alpha,
945 and lightness. The sum is on each of the 9
946 region's surface and alpha and lightness.
948 transformed alpha = sum(surface * alpha) / sum(surface)
949 transformed color = sum(surface * alpha * color) / sum(surface * alpha)
951 /* 1: top left part */
952 base
= spu
->stride
* (unsigned int) unscaled_y
;
953 tmp
= left
* top
* canon_alpha(spu
->aimage
[base
+ (unsigned int) unscaled_x
]);
955 color
+= tmp
* spu
->image
[base
+ (unsigned int) unscaled_x
];
956 /* 2: top center part */
959 for (walkx
= left_right_column
; walkx
< (unsigned int) unscaled_x_right
; ++walkx
) {
960 base
= spu
->stride
* (unsigned int) unscaled_y
+ walkx
;
961 tmp
= /* 1.0 * */ top
* canon_alpha(spu
->aimage
[base
]);
963 color
+= tmp
* spu
->image
[base
];
966 /* 3: top right part */
968 base
= spu
->stride
* (unsigned int) unscaled_y
+ (unsigned int) unscaled_x_right
;
969 tmp
= right
* top
* canon_alpha(spu
->aimage
[base
]);
971 color
+= tmp
* spu
->image
[base
];
973 /* 4: center left part */
976 for (walky
= top_low_row
; walky
< (unsigned int) unscaled_y_bottom
; ++walky
) {
977 base
= spu
->stride
* walky
+ (unsigned int) unscaled_x
;
978 tmp
= left
/* * 1.0 */ * canon_alpha(spu
->aimage
[base
]);
980 color
+= tmp
* spu
->image
[base
];
984 if (width
> 0 && height
> 0) {
986 for (walky
= top_low_row
; walky
< (unsigned int) unscaled_y_bottom
; ++walky
) {
988 base
= spu
->stride
* walky
;
989 for (walkx
= left_right_column
; walkx
< (unsigned int) unscaled_x_right
; ++walkx
) {
990 tmp
= /* 1.0 * 1.0 * */ canon_alpha(spu
->aimage
[base
+ walkx
]);
992 color
+= tmp
* spu
->image
[base
+ walkx
];
996 /* 6: center right part */
997 if (right
> 0.0 && height
> 0) {
999 for (walky
= top_low_row
; walky
< (unsigned int) unscaled_y_bottom
; ++walky
) {
1000 base
= spu
->stride
* walky
+ (unsigned int) unscaled_x_right
;
1001 tmp
= right
/* * 1.0 */ * canon_alpha(spu
->aimage
[base
]);
1003 color
+= tmp
* spu
->image
[base
];
1006 /* 7: bottom left part */
1008 base
= spu
->stride
* (unsigned int) unscaled_y_bottom
+ (unsigned int) unscaled_x
;
1009 tmp
= left
* bottom
* canon_alpha(spu
->aimage
[base
]);
1011 color
+= tmp
* spu
->image
[base
];
1013 /* 8: bottom center part */
1014 if (width
> 0 && bottom
> 0.0) {
1016 base
= spu
->stride
* (unsigned int) unscaled_y_bottom
;
1017 for (walkx
= left_right_column
; walkx
< (unsigned int) unscaled_x_right
; ++walkx
) {
1018 tmp
= /* 1.0 * */ bottom
* canon_alpha(spu
->aimage
[base
+ walkx
]);
1020 color
+= tmp
* spu
->image
[base
+ walkx
];
1023 /* 9: bottom right part */
1024 if (right
> 0.0 && bottom
> 0.0) {
1025 base
= spu
->stride
* (unsigned int) unscaled_y_bottom
+ (unsigned int) unscaled_x_right
;
1026 tmp
= right
* bottom
* canon_alpha(spu
->aimage
[base
]);
1028 color
+= tmp
* spu
->image
[base
];
1030 /* Finally mix these transparency and brightness information suitably */
1031 base
= spu
->scaled_stride
* y
+ x
;
1032 spu
->scaled_image
[base
] = alpha
> 0 ? color
/ alpha
: 0;
1033 spu
->scaled_aimage
[base
] = alpha
* scalex
* scaley
/ 0x10000;
1034 if (spu
->scaled_aimage
[base
]) {
1035 spu
->scaled_aimage
[base
] = 256 - spu
->scaled_aimage
[base
];
1036 if (spu
->scaled_aimage
[base
] + spu
->scaled_image
[base
] > 255)
1037 spu
->scaled_image
[base
] = 256 - spu
->scaled_aimage
[base
];
1044 spu
->scaled_frame_width
= dxs
;
1045 spu
->scaled_frame_height
= dys
;
1048 if (spu
->scaled_image
){
1049 switch (spu_alignment
) {
1051 spu
->scaled_start_row
= dys
*sub_pos
/100;
1052 if (spu
->scaled_start_row
+ spu
->scaled_height
> dys
)
1053 spu
->scaled_start_row
= dys
- spu
->scaled_height
;
1056 spu
->scaled_start_row
= dys
*sub_pos
/100 - spu
->scaled_height
/2;
1058 if (spu
->scaled_start_row
< 0) spu
->scaled_start_row
= 0;
1060 if (spu
->scaled_start_row
+ spu
->scaled_height
> dys
)
1061 spu
->scaled_start_row
= dys
- spu
->scaled_height
;
1065 spu
->scaled_start_row
= dys
*sub_pos
/100 - spu
->scaled_height
;
1066 if (spu
->scaled_start_row
< 0) spu
->scaled_start_row
= 0;
1069 draw_alpha(spu
->scaled_start_col
, spu
->scaled_start_row
, spu
->scaled_width
, spu
->scaled_height
,
1070 spu
->scaled_image
, spu
->scaled_aimage
, spu
->scaled_stride
);
1071 spu
->spu_changed
= 0;
1077 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"SPU not displayed: start_pts=%d end_pts=%d now_pts=%d\n",
1078 spu
->start_pts
, spu
->end_pts
, spu
->now_pts
);
1082 void spudec_update_palette(void * this, unsigned int *palette
)
1084 spudec_handle_t
*spu
= (spudec_handle_t
*) this;
1085 if (spu
&& palette
) {
1086 memcpy(spu
->global_palette
, palette
, sizeof(spu
->global_palette
));
1088 spu
->hw_spu
->control(VOCTRL_SET_SPU_PALETTE
,spu
->global_palette
);
1092 void spudec_set_font_factor(void * this, double factor
)
1094 spudec_handle_t
*spu
= (spudec_handle_t
*) this;
1095 spu
->font_start_level
= (int)(0xF0-(0xE0*factor
));
1098 void *spudec_new_scaled(unsigned int *palette
, unsigned int frame_width
, unsigned int frame_height
)
1100 return spudec_new_scaled_vobsub(palette
, NULL
, 0, frame_width
, frame_height
);
1103 /* get palette custom color, width, height from .idx file */
1104 void *spudec_new_scaled_vobsub(unsigned int *palette
, unsigned int *cuspal
, unsigned int custom
, unsigned int frame_width
, unsigned int frame_height
)
1106 spudec_handle_t
*this = calloc(1, sizeof(spudec_handle_t
));
1108 //(fprintf(stderr,"VobSub Custom Palette: %d,%d,%d,%d", this->cuspal[0], this->cuspal[1], this->cuspal[2],this->cuspal[3]);
1109 this->packet
= NULL
;
1111 this->scaled_image
= NULL
;
1112 /* XXX Although the video frame is some size, the SPU frame is
1113 always maximum size i.e. 720 wide and 576 or 480 high */
1114 this->orig_frame_width
= 720;
1115 this->orig_frame_height
= (frame_height
== 480 || frame_height
== 240) ? 480 : 576;
1116 this->custom
= custom
;
1118 this->auto_palette
= 1;
1120 memcpy(this->global_palette
, palette
, sizeof(this->global_palette
));
1121 this->auto_palette
= 0;
1123 this->custom
= custom
;
1124 if (custom
&& cuspal
) {
1125 memcpy(this->cuspal
, cuspal
, sizeof(this->cuspal
));
1126 this->auto_palette
= 0;
1130 mp_msg(MSGT_SPUDEC
,MSGL_FATAL
, "FATAL: spudec_init: calloc");
1134 void *spudec_new(unsigned int *palette
)
1136 return spudec_new_scaled(palette
, 0, 0);
1139 void spudec_free(void *this)
1141 spudec_handle_t
*spu
= (spudec_handle_t
*)this;
1143 while (spu
->queue_head
)
1144 spudec_free_packet(spudec_dequeue_packet(spu
));
1147 if (spu
->scaled_image
)
1148 free(spu
->scaled_image
);
1155 void spudec_set_hw_spu(void *this, vo_functions_t
*hw_spu
)
1157 spudec_handle_t
*spu
= (spudec_handle_t
*)this;
1160 spu
->hw_spu
= hw_spu
;
1161 hw_spu
->control(VOCTRL_SET_SPU_PALETTE
,spu
->global_palette
);