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 #ifdef USE_LIBAVUTIL_SO
27 #include <ffmpeg/avutil.h>
31 #include "libswscale/swscale.h"
33 /* Valid values for spu_aamode:
34 0: none (fastest, most ugly)
37 3: bilinear (similiar to vobsub, fast and not too bad)
38 4: uses swscaler gaussian (this is the only one that looks good)
42 int spu_alignment
= -1;
43 float spu_gaussvar
= 1.0;
46 typedef struct packet_t packet_t
;
48 unsigned char *packet
;
49 unsigned int palette
[4];
50 unsigned int alpha
[4];
51 unsigned int control_start
; /* index of start of control data */
52 unsigned int current_nibble
[2]; /* next data nibble (4 bits) to be
53 processed (for RLE decoding) for
55 int deinterlace_oddness
; /* 0 or 1, index into current_nibble */
56 unsigned int start_col
, end_col
;
57 unsigned int start_row
, end_row
;
58 unsigned int width
, height
, stride
;
59 unsigned int start_pts
, end_pts
;
66 unsigned int global_palette
[16];
67 unsigned int orig_frame_width
, orig_frame_height
;
68 unsigned char* packet
;
69 size_t packet_reserve
; /* size of the memory pointed to by packet */
70 unsigned int packet_offset
; /* end of the currently assembled fragment */
71 unsigned int packet_size
; /* size of the packet once all fragments are assembled */
72 unsigned int packet_pts
; /* PTS for this packet */
73 unsigned int palette
[4];
74 unsigned int alpha
[4];
75 unsigned int cuspal
[4];
78 unsigned int start_pts
, end_pts
;
79 unsigned int start_col
, end_col
;
80 unsigned int start_row
, end_row
;
81 unsigned int width
, height
, stride
;
82 size_t image_size
; /* Size of the image buffer */
83 unsigned char *image
; /* Grayscale value */
84 unsigned char *aimage
; /* Alpha value */
85 unsigned int scaled_frame_width
, scaled_frame_height
;
86 unsigned int scaled_start_col
, scaled_start_row
;
87 unsigned int scaled_width
, scaled_height
, scaled_stride
;
88 size_t scaled_image_size
;
89 unsigned char *scaled_image
;
90 unsigned char *scaled_aimage
;
91 int auto_palette
; /* 1 if we lack a palette and must use an heuristic. */
92 int font_start_level
; /* Darkest value used for the computed font */
93 vo_functions_t
*hw_spu
;
95 unsigned int forced_subs_only
; /* flag: 0=display all subtitle, !0 display only forced subtitles */
96 unsigned int is_forced_sub
; /* true if current subtitle is a forced subtitle */
99 static void spudec_queue_packet(spudec_handle_t
*this, packet_t
*packet
)
101 if (this->queue_head
== NULL
)
102 this->queue_head
= packet
;
104 this->queue_tail
->next
= packet
;
105 this->queue_tail
= packet
;
108 static packet_t
*spudec_dequeue_packet(spudec_handle_t
*this)
110 packet_t
*retval
= this->queue_head
;
112 this->queue_head
= retval
->next
;
113 if (this->queue_head
== NULL
)
114 this->queue_tail
= NULL
;
119 static void spudec_free_packet(packet_t
*packet
)
121 if (packet
->packet
!= NULL
)
122 free(packet
->packet
);
126 static inline unsigned int get_be16(const unsigned char *p
)
128 return (p
[0] << 8) + p
[1];
131 static inline unsigned int get_be24(const unsigned char *p
)
133 return (get_be16(p
) << 8) + p
[2];
136 static void next_line(packet_t
*packet
)
138 if (packet
->current_nibble
[packet
->deinterlace_oddness
] % 2)
139 packet
->current_nibble
[packet
->deinterlace_oddness
]++;
140 packet
->deinterlace_oddness
= (packet
->deinterlace_oddness
+ 1) % 2;
143 static inline unsigned char get_nibble(packet_t
*packet
)
146 unsigned int *nibblep
= packet
->current_nibble
+ packet
->deinterlace_oddness
;
147 if (*nibblep
/ 2 >= packet
->control_start
) {
148 mp_msg(MSGT_SPUDEC
,MSGL_WARN
, "SPUdec: ERROR: get_nibble past end of packet\n");
151 nib
= packet
->packet
[*nibblep
/ 2];
160 static inline int mkalpha(int i
)
162 /* In mplayer's alpha planes, 0 is transparent, then 1 is nearly
163 opaque upto 255 which is transparent */
170 return (0xf - i
) << 4;
174 /* Cut the sub to visible part */
175 static inline void spudec_cut_image(spudec_handle_t
*this)
178 unsigned int first_y
, last_y
;
179 unsigned char *image
;
180 unsigned char *aimage
;
182 if (this->stride
== 0 || this->height
== 0) {
186 for (fy
= 0; fy
< this->image_size
&& !this->aimage
[fy
]; fy
++);
187 for (ly
= this->stride
* this->height
-1; ly
&& !this->aimage
[ly
]; ly
--);
188 first_y
= fy
/ this->stride
;
189 last_y
= ly
/ this->stride
;
190 //printf("first_y: %d, last_y: %d\n", first_y, last_y);
191 this->start_row
+= first_y
;
193 // Some subtitles trigger this condition
194 if (last_y
+ 1 > first_y
) {
195 this->height
= last_y
- first_y
+1;
198 this->image_size
= 0;
202 // printf("new h %d new start %d (sz %d st %d)---\n\n", this->height, this->start_row, this->image_size, this->stride);
204 image
= malloc(2 * this->stride
* this->height
);
206 this->image_size
= this->stride
* this->height
;
207 aimage
= image
+ this->image_size
;
208 memcpy(image
, this->image
+ this->stride
* first_y
, this->image_size
);
209 memcpy(aimage
, this->aimage
+ this->stride
* first_y
, this->image_size
);
212 this->aimage
= aimage
;
214 mp_msg(MSGT_SPUDEC
, MSGL_FATAL
, "Fatal: update_spu: malloc requested %d bytes\n", 2 * this->stride
* this->height
);
218 static void spudec_process_data(spudec_handle_t
*this, packet_t
*packet
)
220 unsigned int cmap
[4], alpha
[4];
221 unsigned int i
, x
, y
;
223 this->scaled_frame_width
= 0;
224 this->scaled_frame_height
= 0;
225 this->start_col
= packet
->start_col
;
226 this->end_col
= packet
->end_col
;
227 this->start_row
= packet
->start_row
;
228 this->end_row
= packet
->end_row
;
229 this->height
= packet
->height
;
230 this->width
= packet
->width
;
231 this->stride
= packet
->stride
;
232 for (i
= 0; i
< 4; ++i
) {
233 alpha
[i
] = mkalpha(packet
->alpha
[i
]);
236 else if (this->custom
){
237 cmap
[i
] = ((this->cuspal
[i
] >> 16) & 0xff);
238 if (cmap
[i
] + alpha
[i
] > 255)
239 cmap
[i
] = 256 - alpha
[i
];
242 cmap
[i
] = ((this->global_palette
[packet
->palette
[i
]] >> 16) & 0xff);
243 if (cmap
[i
] + alpha
[i
] > 255)
244 cmap
[i
] = 256 - alpha
[i
];
248 if (this->image_size
< this->stride
* this->height
) {
249 if (this->image
!= NULL
) {
251 this->image_size
= 0;
253 this->image
= malloc(2 * this->stride
* this->height
);
255 this->image_size
= this->stride
* this->height
;
256 this->aimage
= this->image
+ this->image_size
;
259 if (this->image
== NULL
)
262 /* Kludge: draw_alpha needs width multiple of 8. */
263 if (this->width
< this->stride
)
264 for (y
= 0; y
< this->height
; ++y
) {
265 memset(this->aimage
+ y
* this->stride
+ this->width
, 0, this->stride
- this->width
);
266 /* FIXME: Why is this one needed? */
267 memset(this->image
+ y
* this->stride
+ this->width
, 0, this->stride
- this->width
);
270 i
= packet
->current_nibble
[1];
273 while (packet
->current_nibble
[0] < i
274 && packet
->current_nibble
[1] / 2 < packet
->control_start
275 && y
< this->height
) {
276 unsigned int len
, color
;
277 unsigned int rle
= 0;
278 rle
= get_nibble(packet
);
280 rle
= (rle
<< 4) | get_nibble(packet
);
282 rle
= (rle
<< 4) | get_nibble(packet
);
284 rle
= (rle
<< 4) | get_nibble(packet
);
286 rle
|= ((this->width
- x
) << 2);
290 color
= 3 - (rle
& 0x3);
292 if (len
> this->width
- x
|| len
== 0)
293 len
= this->width
- x
;
294 /* FIXME have to use palette and alpha map*/
295 memset(this->image
+ y
* this->stride
+ x
, cmap
[color
], len
);
296 memset(this->aimage
+ y
* this->stride
+ x
, alpha
[color
], len
);
298 if (x
>= this->width
) {
304 spudec_cut_image(this);
309 This function tries to create a usable palette.
310 It determines how many non-transparent colors are used, and assigns different
311 gray scale values to each color.
312 I tested it with four streams and even got something readable. Half of the
313 times I got black characters with white around and half the reverse.
315 static void compute_palette(spudec_handle_t
*this, packet_t
*packet
)
317 int used
[16],i
,cused
,start
,step
,color
;
319 memset(used
, 0, sizeof(used
));
321 if (packet
->alpha
[i
]) /* !Transparent? */
322 used
[packet
->palette
[i
]] = 1;
323 for (cused
=0, i
=0; i
<16; i
++)
324 if (used
[i
]) cused
++;
330 start
= this->font_start_level
;
331 step
= (0xF0-this->font_start_level
)/(cused
-1);
333 memset(used
, 0, sizeof(used
));
334 for (i
=0; i
<4; i
++) {
335 color
= packet
->palette
[i
];
336 if (packet
->alpha
[i
] && !used
[color
]) { /* not assigned? */
338 this->global_palette
[color
] = start
<<16;
344 static void spudec_process_control(spudec_handle_t
*this, unsigned int pts100
)
346 int a
,b
; /* Temporary vars */
347 unsigned int date
, type
;
349 unsigned int start_off
= 0;
350 unsigned int next_off
;
351 unsigned int start_pts
;
352 unsigned int end_pts
;
353 unsigned int current_nibble
[2];
354 unsigned int control_start
;
355 unsigned int display
= 0;
356 unsigned int start_col
= 0;
357 unsigned int end_col
= 0;
358 unsigned int start_row
= 0;
359 unsigned int end_row
= 0;
360 unsigned int width
= 0;
361 unsigned int height
= 0;
362 unsigned int stride
= 0;
364 control_start
= get_be16(this->packet
+ 2);
365 next_off
= control_start
;
366 while (start_off
!= next_off
) {
367 start_off
= next_off
;
368 date
= get_be16(this->packet
+ start_off
) * 1024;
369 next_off
= get_be16(this->packet
+ start_off
+ 2);
370 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
, "date=%d\n", date
);
372 for (type
= this->packet
[off
++]; type
!= 0xff; type
= this->packet
[off
++]) {
373 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
, "cmd=%d ",type
);
376 /* Menu ID, 1 byte */
377 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Menu ID\n");
378 /* shouldn't a Menu ID type force display start? */
379 start_pts
= pts100
+ date
;
382 this->is_forced_sub
=~0; // current subtitle is forced
386 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Start display!\n");
387 start_pts
= pts100
+ date
;
390 this->is_forced_sub
=0;
394 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Stop display!\n");
395 end_pts
= pts100
+ date
;
399 this->palette
[0] = this->packet
[off
] >> 4;
400 this->palette
[1] = this->packet
[off
] & 0xf;
401 this->palette
[2] = this->packet
[off
+ 1] >> 4;
402 this->palette
[3] = this->packet
[off
+ 1] & 0xf;
403 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Palette %d, %d, %d, %d\n",
404 this->palette
[0], this->palette
[1], this->palette
[2], this->palette
[3]);
409 this->alpha
[0] = this->packet
[off
] >> 4;
410 this->alpha
[1] = this->packet
[off
] & 0xf;
411 this->alpha
[2] = this->packet
[off
+ 1] >> 4;
412 this->alpha
[3] = this->packet
[off
+ 1] & 0xf;
413 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Alpha %d, %d, %d, %d\n",
414 this->alpha
[0], this->alpha
[1], this->alpha
[2], this->alpha
[3]);
419 a
= get_be24(this->packet
+ off
);
420 b
= get_be24(this->packet
+ off
+ 3);
423 width
= (end_col
< start_col
) ? 0 : end_col
- start_col
+ 1;
424 stride
= (width
+ 7) & ~7; /* Kludge: draw_alpha needs width multiple of 8 */
427 height
= (end_row
< start_row
) ? 0 : end_row
- start_row
/* + 1 */;
428 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Coords col: %d - %d row: %d - %d (%dx%d)\n",
429 start_col
, end_col
, start_row
, end_row
,
435 current_nibble
[0] = 2 * get_be16(this->packet
+ off
);
436 current_nibble
[1] = 2 * get_be16(this->packet
+ off
+ 2);
437 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Graphic offset 1: %d offset 2: %d\n",
438 current_nibble
[0] / 2, current_nibble
[1] / 2);
442 /* All done, bye-bye */
443 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Done!\n");
447 mp_msg(MSGT_SPUDEC
,MSGL_WARN
,"spudec: Error determining control type 0x%02x. Skipping %d bytes.\n",
448 type
, next_off
- off
);
454 packet_t
*packet
= calloc(1, sizeof(packet_t
));
456 packet
->start_pts
= start_pts
;
457 if (end_pts
== UINT_MAX
&& start_off
!= next_off
) {
458 start_pts
= pts100
+ get_be16(this->packet
+ next_off
) * 1024;
459 packet
->end_pts
= start_pts
- 1;
460 } else packet
->end_pts
= end_pts
;
461 packet
->current_nibble
[0] = current_nibble
[0];
462 packet
->current_nibble
[1] = current_nibble
[1];
463 packet
->start_row
= start_row
;
464 packet
->end_row
= end_row
;
465 packet
->start_col
= start_col
;
466 packet
->end_col
= end_col
;
467 packet
->width
= width
;
468 packet
->height
= height
;
469 packet
->stride
= stride
;
470 packet
->control_start
= control_start
;
471 for (i
=0; i
<4; i
++) {
472 packet
->alpha
[i
] = this->alpha
[i
];
473 packet
->palette
[i
] = this->palette
[i
];
475 packet
->packet
= malloc(this->packet_size
);
476 memcpy(packet
->packet
, this->packet
, this->packet_size
);
477 spudec_queue_packet(this, packet
);
482 static void spudec_decode(spudec_handle_t
*this, unsigned int pts100
)
485 static vo_mpegpes_t packet
= { NULL
, 0, 0x20, 0 };
486 static vo_mpegpes_t
*pkg
=&packet
;
487 packet
.data
= this->packet
;
488 packet
.size
= this->packet_size
;
489 packet
.timestamp
= pts100
;
490 this->hw_spu
->draw_frame((uint8_t**)&pkg
);
492 spudec_process_control(this, pts100
);
495 int spudec_changed(void * this)
497 spudec_handle_t
* spu
= (spudec_handle_t
*)this;
498 return (spu
->spu_changed
|| spu
->now_pts
> spu
->end_pts
);
501 void spudec_assemble(void *this, unsigned char *packet
, unsigned int len
, unsigned int pts100
)
503 spudec_handle_t
*spu
= (spudec_handle_t
*)this;
504 // spudec_heartbeat(this, pts100);
506 mp_msg(MSGT_SPUDEC
,MSGL_WARN
,"SPUasm: packet too short\n");
510 if ((spu
->packet_pts
+ 10000) < pts100
) {
511 // [cb] too long since last fragment: force new packet
512 spu
->packet_offset
= 0;
515 spu
->packet_pts
= pts100
;
516 if (spu
->packet_offset
== 0) {
517 unsigned int len2
= get_be16(packet
);
518 // Start new fragment
519 if (spu
->packet_reserve
< len2
) {
520 if (spu
->packet
!= NULL
)
522 spu
->packet
= malloc(len2
);
523 spu
->packet_reserve
= spu
->packet
!= NULL
? len2
: 0;
525 if (spu
->packet
!= NULL
) {
526 spu
->packet_size
= len2
;
528 mp_msg(MSGT_SPUDEC
,MSGL_WARN
,"SPUasm: invalid frag len / len2: %d / %d \n", len
, len2
);
531 memcpy(spu
->packet
, packet
, len
);
532 spu
->packet_offset
= len
;
533 spu
->packet_pts
= pts100
;
536 // Continue current fragment
537 if (spu
->packet_size
< spu
->packet_offset
+ len
){
538 mp_msg(MSGT_SPUDEC
,MSGL_WARN
,"SPUasm: invalid fragment\n");
539 spu
->packet_size
= spu
->packet_offset
= 0;
542 memcpy(spu
->packet
+ spu
->packet_offset
, packet
, len
);
543 spu
->packet_offset
+= len
;
547 // check if we have a complete packet (unfortunatelly packet_size is bad
549 // [cb] packet_size is padded to be even -> may be one byte too long
550 if ((spu
->packet_offset
== spu
->packet_size
) ||
551 ((spu
->packet_offset
+ 1) == spu
->packet_size
)){
553 while(x
+4<=spu
->packet_offset
){
554 y
=get_be16(spu
->packet
+x
+2); // next control pointer
555 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"SPUtest: x=%d y=%d off=%d size=%d\n",x
,y
,spu
->packet_offset
,spu
->packet_size
);
556 if(x
>=4 && x
==y
){ // if it points to self - we're done!
558 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"SPUgot: off=%d size=%d \n",spu
->packet_offset
,spu
->packet_size
);
559 spudec_decode(spu
, pts100
);
560 spu
->packet_offset
= 0;
563 if(y
<=x
|| y
>=spu
->packet_size
){ // invalid?
564 mp_msg(MSGT_SPUDEC
,MSGL_WARN
,"SPUtest: broken packet!!!!! y=%d < x=%d\n",y
,x
);
565 spu
->packet_size
= spu
->packet_offset
= 0;
570 // [cb] packet is done; start new packet
571 spu
->packet_offset
= 0;
574 if (spu
->packet_offset
== spu
->packet_size
) {
575 spudec_decode(spu
, pts100
);
576 spu
->packet_offset
= 0;
581 void spudec_reset(void *this) // called after seek
583 spudec_handle_t
*spu
= (spudec_handle_t
*)this;
584 while (spu
->queue_head
)
585 spudec_free_packet(spudec_dequeue_packet(spu
));
588 spu
->packet_size
= spu
->packet_offset
= 0;
591 void spudec_heartbeat(void *this, unsigned int pts100
)
593 spudec_handle_t
*spu
= (spudec_handle_t
*) this;
594 spu
->now_pts
= pts100
;
596 while (spu
->queue_head
!= NULL
&& pts100
>= spu
->queue_head
->start_pts
) {
597 packet_t
*packet
= spudec_dequeue_packet(spu
);
598 spu
->start_pts
= packet
->start_pts
;
599 spu
->end_pts
= packet
->end_pts
;
600 if (spu
->auto_palette
)
601 compute_palette(spu
, packet
);
602 spudec_process_data(spu
, packet
);
603 spudec_free_packet(packet
);
604 spu
->spu_changed
= 1;
608 int spudec_visible(void *this){
609 spudec_handle_t
*spu
= (spudec_handle_t
*)this;
610 int ret
=(spu
->start_pts
<= spu
->now_pts
&&
611 spu
->now_pts
< spu
->end_pts
&&
613 // printf("spu visible: %d \n",ret);
617 void spudec_set_forced_subs_only(void * const this, const unsigned int flag
)
620 ((spudec_handle_t
*)this)->forced_subs_only
=flag
;
621 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"SPU: Display only forced subs now %s\n", flag
? "enabled": "disabled");
625 void spudec_draw(void *this, void (*draw_alpha
)(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
))
627 spudec_handle_t
*spu
= (spudec_handle_t
*)this;
628 if (spu
->start_pts
<= spu
->now_pts
&& spu
->now_pts
< spu
->end_pts
&& spu
->image
)
630 draw_alpha(spu
->start_col
, spu
->start_row
, spu
->width
, spu
->height
,
631 spu
->image
, spu
->aimage
, spu
->stride
);
632 spu
->spu_changed
= 0;
636 /* calc the bbox for spudec subs */
637 void spudec_calc_bbox(void *me
, unsigned int dxs
, unsigned int dys
, unsigned int* bbox
)
639 spudec_handle_t
*spu
;
640 spu
= (spudec_handle_t
*)me
;
641 if (spu
->orig_frame_width
== 0 || spu
->orig_frame_height
== 0
642 || (spu
->orig_frame_width
== dxs
&& spu
->orig_frame_height
== dys
)) {
643 bbox
[0] = spu
->start_col
;
644 bbox
[1] = spu
->start_col
+ spu
->width
;
645 bbox
[2] = spu
->start_row
;
646 bbox
[3] = spu
->start_row
+ spu
->height
;
648 else if (spu
->scaled_frame_width
!= dxs
|| spu
->scaled_frame_height
!= dys
) {
649 unsigned int scalex
= 0x100 * dxs
/ spu
->orig_frame_width
;
650 unsigned int scaley
= 0x100 * dys
/ spu
->orig_frame_height
;
651 bbox
[0] = spu
->start_col
* scalex
/ 0x100;
652 bbox
[1] = spu
->start_col
* scalex
/ 0x100 + spu
->width
* scalex
/ 0x100;
653 switch (spu_alignment
) {
655 bbox
[3] = dys
*sub_pos
/100 + spu
->height
* scaley
/ 0x100;
656 if (bbox
[3] > dys
) bbox
[3] = dys
;
657 bbox
[2] = bbox
[3] - spu
->height
* scaley
/ 0x100;
661 bbox
[2] = dys
*sub_pos
/100 - spu
->height
* scaley
/ 0x200;
662 bbox
[3] = bbox
[2] + spu
->height
;
664 bbox
[3] = dys
*sub_pos
/100 + spu
->height
* scaley
/ 0x200;
665 if (bbox
[3] > dys
) bbox
[3] = dys
;
666 bbox
[2] = bbox
[3] - spu
->height
* scaley
/ 0x100;
670 bbox
[2] = dys
*sub_pos
/100 - spu
->height
* scaley
/ 0x100;
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
= FFMIN(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
= FFMIN(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
= FFMIN(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;
1077 if (sub_pos
>= 50 && spu
->scaled_start_row
+ spu
->scaled_height
> dys
)
1078 spu
->scaled_start_row
= dys
- spu
->scaled_height
;
1081 spu
->scaled_start_row
= dys
*sub_pos
/100 - spu
->scaled_height
;
1084 draw_alpha(spu
->scaled_start_col
, spu
->scaled_start_row
, spu
->scaled_width
, spu
->scaled_height
,
1085 spu
->scaled_image
, spu
->scaled_aimage
, spu
->scaled_stride
);
1086 spu
->spu_changed
= 0;
1092 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"SPU not displayed: start_pts=%d end_pts=%d now_pts=%d\n",
1093 spu
->start_pts
, spu
->end_pts
, spu
->now_pts
);
1097 void spudec_update_palette(void * this, unsigned int *palette
)
1099 spudec_handle_t
*spu
= (spudec_handle_t
*) this;
1100 if (spu
&& palette
) {
1101 memcpy(spu
->global_palette
, palette
, sizeof(spu
->global_palette
));
1103 spu
->hw_spu
->control(VOCTRL_SET_SPU_PALETTE
,spu
->global_palette
);
1107 void spudec_set_font_factor(void * this, double factor
)
1109 spudec_handle_t
*spu
= (spudec_handle_t
*) this;
1110 spu
->font_start_level
= (int)(0xF0-(0xE0*factor
));
1113 void *spudec_new_scaled(unsigned int *palette
, unsigned int frame_width
, unsigned int frame_height
)
1115 return spudec_new_scaled_vobsub(palette
, NULL
, 0, frame_width
, frame_height
);
1118 /* get palette custom color, width, height from .idx file */
1119 void *spudec_new_scaled_vobsub(unsigned int *palette
, unsigned int *cuspal
, unsigned int custom
, unsigned int frame_width
, unsigned int frame_height
)
1121 spudec_handle_t
*this = calloc(1, sizeof(spudec_handle_t
));
1123 //(fprintf(stderr,"VobSub Custom Palette: %d,%d,%d,%d", this->cuspal[0], this->cuspal[1], this->cuspal[2],this->cuspal[3]);
1124 this->packet
= NULL
;
1126 this->scaled_image
= NULL
;
1127 /* XXX Although the video frame is some size, the SPU frame is
1128 always maximum size i.e. 720 wide and 576 or 480 high */
1129 this->orig_frame_width
= 720;
1130 this->orig_frame_height
= (frame_height
== 480 || frame_height
== 240) ? 480 : 576;
1131 this->custom
= custom
;
1133 this->auto_palette
= 1;
1135 memcpy(this->global_palette
, palette
, sizeof(this->global_palette
));
1136 this->auto_palette
= 0;
1138 this->custom
= custom
;
1139 if (custom
&& cuspal
) {
1140 memcpy(this->cuspal
, cuspal
, sizeof(this->cuspal
));
1141 this->auto_palette
= 0;
1143 // forced subtitles default: show all subtitles
1144 this->forced_subs_only
=0;
1145 this->is_forced_sub
=0;
1148 mp_msg(MSGT_SPUDEC
,MSGL_FATAL
, "FATAL: spudec_init: calloc");
1152 void *spudec_new(unsigned int *palette
)
1154 return spudec_new_scaled(palette
, 0, 0);
1157 void spudec_free(void *this)
1159 spudec_handle_t
*spu
= (spudec_handle_t
*)this;
1161 while (spu
->queue_head
)
1162 spudec_free_packet(spudec_dequeue_packet(spu
));
1165 if (spu
->scaled_image
)
1166 free(spu
->scaled_image
);
1173 void spudec_set_hw_spu(void *this, vo_functions_t
*hw_spu
)
1175 spudec_handle_t
*spu
= (spudec_handle_t
*)this;
1178 spu
->hw_spu
= hw_spu
;
1179 hw_spu
->control(VOCTRL_SET_SPU_PALETTE
,spu
->global_palette
);