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 "libavutil/avutil.h"
28 #include "libavutil/intreadwrite.h"
29 #include "libswscale/swscale.h"
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 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 */
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
]);
232 if (this->custom
&& (this->cuspal
[i
] >> 31) != 0)
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, 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
= 0;
352 unsigned int end_pts
= 0;
353 unsigned int current_nibble
[2] = {0, 0};
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
< 0 && -pts100
>= date
? 0 : 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
< 0 && -pts100
>= date
? 0 : pts100
+ date
;
390 this->is_forced_sub
=0;
394 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Stop display!\n");
395 end_pts
= pts100
< 0 && -pts100
>= date
? 0 : 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
);
455 if (end_pts
== UINT_MAX
&& start_off
!= next_off
) {
456 end_pts
= get_be16(this->packet
+ next_off
) * 1024;
457 end_pts
= 1 - pts100
>= end_pts
? 0 : pts100
+ end_pts
- 1;
460 packet_t
*packet
= calloc(1, sizeof(packet_t
));
462 packet
->start_pts
= start_pts
;
463 packet
->end_pts
= end_pts
;
464 packet
->current_nibble
[0] = current_nibble
[0];
465 packet
->current_nibble
[1] = current_nibble
[1];
466 packet
->start_row
= start_row
;
467 packet
->end_row
= end_row
;
468 packet
->start_col
= start_col
;
469 packet
->end_col
= end_col
;
470 packet
->width
= width
;
471 packet
->height
= height
;
472 packet
->stride
= stride
;
473 packet
->control_start
= control_start
;
474 for (i
=0; i
<4; i
++) {
475 packet
->alpha
[i
] = this->alpha
[i
];
476 packet
->palette
[i
] = this->palette
[i
];
478 packet
->packet
= malloc(this->packet_size
);
479 memcpy(packet
->packet
, this->packet
, this->packet_size
);
480 spudec_queue_packet(this, packet
);
485 static void spudec_decode(spudec_handle_t
*this, int pts100
)
488 spudec_process_control(this, pts100
);
489 else if (pts100
>= 0) {
490 static vo_mpegpes_t packet
= { NULL
, 0, 0x20, 0 };
491 static vo_mpegpes_t
*pkg
=&packet
;
492 packet
.data
= this->packet
;
493 packet
.size
= this->packet_size
;
494 packet
.timestamp
= pts100
;
495 vo_draw_frame(this->hw_spu
, (uint8_t**)&pkg
);
499 int spudec_changed(void * this)
501 spudec_handle_t
* spu
= (spudec_handle_t
*)this;
502 return spu
->spu_changed
|| spu
->now_pts
> spu
->end_pts
;
505 void spudec_assemble(void *this, unsigned char *packet
, unsigned int len
, int pts100
)
507 spudec_handle_t
*spu
= (spudec_handle_t
*)this;
508 // spudec_heartbeat(this, pts100);
510 mp_msg(MSGT_SPUDEC
,MSGL_WARN
,"SPUasm: packet too short\n");
514 if ((spu
->packet_pts
+ 10000) < pts100
) {
515 // [cb] too long since last fragment: force new packet
516 spu
->packet_offset
= 0;
519 spu
->packet_pts
= pts100
;
520 if (spu
->packet_offset
== 0) {
521 unsigned int len2
= get_be16(packet
);
522 // Start new fragment
523 if (spu
->packet_reserve
< len2
) {
524 if (spu
->packet
!= NULL
)
526 spu
->packet
= malloc(len2
);
527 spu
->packet_reserve
= spu
->packet
!= NULL
? len2
: 0;
529 if (spu
->packet
!= NULL
) {
530 spu
->packet_size
= len2
;
532 mp_msg(MSGT_SPUDEC
,MSGL_WARN
,"SPUasm: invalid frag len / len2: %d / %d \n", len
, len2
);
535 memcpy(spu
->packet
, packet
, len
);
536 spu
->packet_offset
= len
;
537 spu
->packet_pts
= pts100
;
540 // Continue current fragment
541 if (spu
->packet_size
< spu
->packet_offset
+ len
){
542 mp_msg(MSGT_SPUDEC
,MSGL_WARN
,"SPUasm: invalid fragment\n");
543 spu
->packet_size
= spu
->packet_offset
= 0;
546 memcpy(spu
->packet
+ spu
->packet_offset
, packet
, len
);
547 spu
->packet_offset
+= len
;
551 // check if we have a complete packet (unfortunatelly packet_size is bad
553 // [cb] packet_size is padded to be even -> may be one byte too long
554 if ((spu
->packet_offset
== spu
->packet_size
) ||
555 ((spu
->packet_offset
+ 1) == spu
->packet_size
)){
557 while(x
+4<=spu
->packet_offset
){
558 y
=get_be16(spu
->packet
+x
+2); // next control pointer
559 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"SPUtest: x=%d y=%d off=%d size=%d\n",x
,y
,spu
->packet_offset
,spu
->packet_size
);
560 if(x
>=4 && x
==y
){ // if it points to self - we're done!
562 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"SPUgot: off=%d size=%d \n",spu
->packet_offset
,spu
->packet_size
);
563 spudec_decode(spu
, pts100
);
564 spu
->packet_offset
= 0;
567 if(y
<=x
|| y
>=spu
->packet_size
){ // invalid?
568 mp_msg(MSGT_SPUDEC
,MSGL_WARN
,"SPUtest: broken packet!!!!! y=%d < x=%d\n",y
,x
);
569 spu
->packet_size
= spu
->packet_offset
= 0;
574 // [cb] packet is done; start new packet
575 spu
->packet_offset
= 0;
578 if (spu
->packet_offset
== spu
->packet_size
) {
579 spudec_decode(spu
, pts100
);
580 spu
->packet_offset
= 0;
585 void spudec_reset(void *this) // called after seek
587 spudec_handle_t
*spu
= (spudec_handle_t
*)this;
588 while (spu
->queue_head
)
589 spudec_free_packet(spudec_dequeue_packet(spu
));
592 spu
->packet_size
= spu
->packet_offset
= 0;
595 void spudec_heartbeat(void *this, unsigned int pts100
)
597 spudec_handle_t
*spu
= (spudec_handle_t
*) this;
598 spu
->now_pts
= pts100
;
600 while (spu
->queue_head
!= NULL
&& pts100
>= spu
->queue_head
->start_pts
) {
601 packet_t
*packet
= spudec_dequeue_packet(spu
);
602 spu
->start_pts
= packet
->start_pts
;
603 spu
->end_pts
= packet
->end_pts
;
604 if (spu
->auto_palette
)
605 compute_palette(spu
, packet
);
606 spudec_process_data(spu
, packet
);
607 spudec_free_packet(packet
);
608 spu
->spu_changed
= 1;
612 int spudec_visible(void *this){
613 spudec_handle_t
*spu
= (spudec_handle_t
*)this;
614 int ret
=(spu
->start_pts
<= spu
->now_pts
&&
615 spu
->now_pts
< spu
->end_pts
&&
617 // printf("spu visible: %d \n",ret);
621 void spudec_set_forced_subs_only(void * const this, const unsigned int flag
)
624 ((spudec_handle_t
*)this)->forced_subs_only
=flag
;
625 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"SPU: Display only forced subs now %s\n", flag
? "enabled": "disabled");
629 void spudec_draw(void *this, void (*draw_alpha
)(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
))
631 spudec_handle_t
*spu
= (spudec_handle_t
*)this;
632 if (spu
->start_pts
<= spu
->now_pts
&& spu
->now_pts
< spu
->end_pts
&& spu
->image
)
634 draw_alpha(spu
->start_col
, spu
->start_row
, spu
->width
, spu
->height
,
635 spu
->image
, spu
->aimage
, spu
->stride
);
636 spu
->spu_changed
= 0;
640 /* calc the bbox for spudec subs */
641 void spudec_calc_bbox(void *me
, unsigned int dxs
, unsigned int dys
, unsigned int* bbox
)
643 spudec_handle_t
*spu
;
644 spu
= (spudec_handle_t
*)me
;
645 if (spu
->orig_frame_width
== 0 || spu
->orig_frame_height
== 0
646 || (spu
->orig_frame_width
== dxs
&& spu
->orig_frame_height
== dys
)) {
647 bbox
[0] = spu
->start_col
;
648 bbox
[1] = spu
->start_col
+ spu
->width
;
649 bbox
[2] = spu
->start_row
;
650 bbox
[3] = spu
->start_row
+ spu
->height
;
652 else if (spu
->scaled_frame_width
!= dxs
|| spu
->scaled_frame_height
!= dys
) {
653 unsigned int scalex
= 0x100 * dxs
/ spu
->orig_frame_width
;
654 unsigned int scaley
= 0x100 * dys
/ spu
->orig_frame_height
;
655 bbox
[0] = spu
->start_col
* scalex
/ 0x100;
656 bbox
[1] = spu
->start_col
* scalex
/ 0x100 + spu
->width
* scalex
/ 0x100;
657 switch (spu_alignment
) {
659 bbox
[3] = dys
*sub_pos
/100 + spu
->height
* scaley
/ 0x100;
660 if (bbox
[3] > dys
) bbox
[3] = dys
;
661 bbox
[2] = bbox
[3] - spu
->height
* scaley
/ 0x100;
665 bbox
[2] = dys
*sub_pos
/100 - spu
->height
* scaley
/ 0x200;
666 bbox
[3] = bbox
[2] + spu
->height
;
668 bbox
[3] = dys
*sub_pos
/100 + spu
->height
* scaley
/ 0x200;
669 if (bbox
[3] > dys
) bbox
[3] = dys
;
670 bbox
[2] = bbox
[3] - spu
->height
* scaley
/ 0x100;
674 bbox
[2] = dys
*sub_pos
/100 - spu
->height
* scaley
/ 0x100;
675 bbox
[3] = bbox
[2] + spu
->height
;
678 bbox
[2] = spu
->start_row
* scaley
/ 0x100;
679 bbox
[3] = spu
->start_row
* scaley
/ 0x100 + spu
->height
* scaley
/ 0x100;
684 /* transform mplayer's alpha value into an opacity value that is linear */
685 static inline int canon_alpha(int alpha
)
687 return alpha
? 256 - alpha
: 0;
697 static void scale_table(unsigned int start_src
, unsigned int start_tar
, unsigned int end_src
, unsigned int end_tar
, scale_pixel
* table
)
700 unsigned int delta_src
= end_src
- start_src
;
701 unsigned int delta_tar
= end_tar
- start_tar
;
704 if (delta_src
== 0 || delta_tar
== 0) {
707 src_step
= (delta_src
<< 16) / delta_tar
>>1;
708 for (t
= 0; t
<=delta_tar
; src
+= (src_step
<< 1), t
++){
709 table
[t
].position
= FFMIN(src
>> 16, end_src
- 1);
710 table
[t
].right_down
= src
& 0xffff;
711 table
[t
].left_up
= 0x10000 - table
[t
].right_down
;
715 /* bilinear scale, similar to vobsub's code */
716 static void scale_image(int x
, int y
, scale_pixel
* table_x
, scale_pixel
* table_y
, spudec_handle_t
* spu
)
720 unsigned int scale
[4];
721 int base
= table_y
[y
].position
* spu
->stride
+ table_x
[x
].position
;
722 int scaled
= y
* spu
->scaled_stride
+ x
;
723 alpha
[0] = canon_alpha(spu
->aimage
[base
]);
724 alpha
[1] = canon_alpha(spu
->aimage
[base
+ 1]);
725 alpha
[2] = canon_alpha(spu
->aimage
[base
+ spu
->stride
]);
726 alpha
[3] = canon_alpha(spu
->aimage
[base
+ spu
->stride
+ 1]);
727 color
[0] = spu
->image
[base
];
728 color
[1] = spu
->image
[base
+ 1];
729 color
[2] = spu
->image
[base
+ spu
->stride
];
730 color
[3] = spu
->image
[base
+ spu
->stride
+ 1];
731 scale
[0] = (table_x
[x
].left_up
* table_y
[y
].left_up
>> 16) * alpha
[0];
732 if (table_y
[y
].left_up
== 0x10000) // necessary to avoid overflow-case
733 scale
[0] = table_x
[x
].left_up
* alpha
[0];
734 scale
[1] = (table_x
[x
].right_down
* table_y
[y
].left_up
>>16) * alpha
[1];
735 scale
[2] = (table_x
[x
].left_up
* table_y
[y
].right_down
>> 16) * alpha
[2];
736 scale
[3] = (table_x
[x
].right_down
* table_y
[y
].right_down
>> 16) * alpha
[3];
737 spu
->scaled_image
[scaled
] = (color
[0] * scale
[0] + color
[1] * scale
[1] + color
[2] * scale
[2] + color
[3] * scale
[3])>>24;
738 spu
->scaled_aimage
[scaled
] = (scale
[0] + scale
[1] + scale
[2] + scale
[3]) >> 16;
739 if (spu
->scaled_aimage
[scaled
]){
740 // ensure that MPlayer's simplified alpha-blending can not overflow
741 spu
->scaled_image
[scaled
] = FFMIN(spu
->scaled_image
[scaled
], spu
->scaled_aimage
[scaled
]);
742 // convert to MPlayer-style alpha
743 spu
->scaled_aimage
[scaled
] = -spu
->scaled_aimage
[scaled
];
747 static void sws_spu_image(unsigned char *d1
, unsigned char *d2
, int dw
, int dh
,
748 int ds
, unsigned char *s1
, unsigned char *s2
, int sw
,
751 struct SwsContext
*ctx
;
752 static SwsFilter filter
;
753 static int firsttime
= 1;
757 if (!firsttime
&& oldvar
!= spu_gaussvar
) sws_freeVec(filter
.lumH
);
759 filter
.lumH
= filter
.lumV
=
760 filter
.chrH
= filter
.chrV
= sws_getGaussianVec(spu_gaussvar
, 3.0);
761 sws_normalizeVec(filter
.lumH
, 1.0);
763 oldvar
= spu_gaussvar
;
766 ctx
=sws_getContext(sw
, sh
, PIX_FMT_GRAY8
, dw
, dh
, PIX_FMT_GRAY8
, SWS_GAUSS
, &filter
, NULL
, NULL
);
767 sws_scale(ctx
,&s1
,&ss
,0,sh
,&d1
,&ds
);
768 for (i
=ss
*sh
-1; i
>=0; i
--) if (!s2
[i
]) s2
[i
] = 255; //else s2[i] = 1;
769 sws_scale(ctx
,&s2
,&ss
,0,sh
,&d2
,&ds
);
770 for (i
=ds
*dh
-1; i
>=0; i
--) if (d2
[i
]==0) d2
[i
] = 1; else if (d2
[i
]==255) d2
[i
] = 0;
771 sws_freeContext(ctx
);
774 void spudec_draw_scaled(void *me
, unsigned int dxs
, unsigned int dys
, void (*draw_alpha
)(void *ctx
, int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
), void *ctx
)
776 spudec_handle_t
*spu
= (spudec_handle_t
*)me
;
777 scale_pixel
*table_x
;
778 scale_pixel
*table_y
;
780 if (spu
->start_pts
<= spu
->now_pts
&& spu
->now_pts
< spu
->end_pts
) {
782 // check if only forced subtitles are requested
783 if( (spu
->forced_subs_only
) && !(spu
->is_forced_sub
) ){
787 if (!(spu_aamode
&16) && (spu
->orig_frame_width
== 0 || spu
->orig_frame_height
== 0
788 || (spu
->orig_frame_width
== dxs
&& spu
->orig_frame_height
== dys
))) {
791 draw_alpha(ctx
, spu
->start_col
, spu
->start_row
, spu
->width
, spu
->height
,
792 spu
->image
, spu
->aimage
, spu
->stride
);
793 spu
->spu_changed
= 0;
797 if (spu
->scaled_frame_width
!= dxs
|| spu
->scaled_frame_height
!= dys
) { /* Resizing is needed */
798 /* scaled_x = scalex * x / 0x100
799 scaled_y = scaley * y / 0x100
800 order of operations is important because of rounding. */
801 unsigned int scalex
= 0x100 * dxs
/ spu
->orig_frame_width
;
802 unsigned int scaley
= 0x100 * dys
/ spu
->orig_frame_height
;
803 spu
->scaled_start_col
= spu
->start_col
* scalex
/ 0x100;
804 spu
->scaled_start_row
= spu
->start_row
* scaley
/ 0x100;
805 spu
->scaled_width
= spu
->width
* scalex
/ 0x100;
806 spu
->scaled_height
= spu
->height
* scaley
/ 0x100;
807 /* Kludge: draw_alpha needs width multiple of 8 */
808 spu
->scaled_stride
= (spu
->scaled_width
+ 7) & ~7;
809 if (spu
->scaled_image_size
< spu
->scaled_stride
* spu
->scaled_height
) {
810 if (spu
->scaled_image
) {
811 free(spu
->scaled_image
);
812 spu
->scaled_image_size
= 0;
814 spu
->scaled_image
= malloc(2 * spu
->scaled_stride
* spu
->scaled_height
);
815 if (spu
->scaled_image
) {
816 spu
->scaled_image_size
= spu
->scaled_stride
* spu
->scaled_height
;
817 spu
->scaled_aimage
= spu
->scaled_image
+ spu
->scaled_image_size
;
820 if (spu
->scaled_image
) {
822 if (spu
->scaled_width
<= 1 || spu
->scaled_height
<= 1) {
825 switch(spu_aamode
&15) {
827 sws_spu_image(spu
->scaled_image
, spu
->scaled_aimage
,
828 spu
->scaled_width
, spu
->scaled_height
, spu
->scaled_stride
,
829 spu
->image
, spu
->aimage
, spu
->width
, spu
->height
, spu
->stride
);
832 table_x
= calloc(spu
->scaled_width
, sizeof(scale_pixel
));
833 table_y
= calloc(spu
->scaled_height
, sizeof(scale_pixel
));
834 if (!table_x
|| !table_y
) {
835 mp_msg(MSGT_SPUDEC
, MSGL_FATAL
, "Fatal: spudec_draw_scaled: calloc failed\n");
837 scale_table(0, 0, spu
->width
- 1, spu
->scaled_width
- 1, table_x
);
838 scale_table(0, 0, spu
->height
- 1, spu
->scaled_height
- 1, table_y
);
839 for (y
= 0; y
< spu
->scaled_height
; y
++)
840 for (x
= 0; x
< spu
->scaled_width
; x
++)
841 scale_image(x
, y
, table_x
, table_y
, spu
);
846 /* no antialiasing */
847 for (y
= 0; y
< spu
->scaled_height
; ++y
) {
848 int unscaled_y
= y
* 0x100 / scaley
;
849 int strides
= spu
->stride
* unscaled_y
;
850 int scaled_strides
= spu
->scaled_stride
* y
;
851 for (x
= 0; x
< spu
->scaled_width
; ++x
) {
852 int unscaled_x
= x
* 0x100 / scalex
;
853 spu
->scaled_image
[scaled_strides
+ x
] = spu
->image
[strides
+ unscaled_x
];
854 spu
->scaled_aimage
[scaled_strides
+ x
] = spu
->aimage
[strides
+ unscaled_x
];
860 /* Intermediate antialiasing. */
861 for (y
= 0; y
< spu
->scaled_height
; ++y
) {
862 const unsigned int unscaled_top
= y
* spu
->orig_frame_height
/ dys
;
863 unsigned int unscaled_bottom
= (y
+ 1) * spu
->orig_frame_height
/ dys
;
864 if (unscaled_bottom
>= spu
->height
)
865 unscaled_bottom
= spu
->height
- 1;
866 for (x
= 0; x
< spu
->scaled_width
; ++x
) {
867 const unsigned int unscaled_left
= x
* spu
->orig_frame_width
/ dxs
;
868 unsigned int unscaled_right
= (x
+ 1) * spu
->orig_frame_width
/ dxs
;
869 unsigned int color
= 0;
870 unsigned int alpha
= 0;
871 unsigned int walkx
, walky
;
872 unsigned int base
, tmp
;
873 if (unscaled_right
>= spu
->width
)
874 unscaled_right
= spu
->width
- 1;
875 for (walky
= unscaled_top
; walky
<= unscaled_bottom
; ++walky
)
876 for (walkx
= unscaled_left
; walkx
<= unscaled_right
; ++walkx
) {
877 base
= walky
* spu
->stride
+ walkx
;
878 tmp
= canon_alpha(spu
->aimage
[base
]);
880 color
+= tmp
* spu
->image
[base
];
882 base
= y
* spu
->scaled_stride
+ x
;
883 spu
->scaled_image
[base
] = alpha
? color
/ alpha
: 0;
884 spu
->scaled_aimage
[base
] =
885 alpha
* (1 + unscaled_bottom
- unscaled_top
) * (1 + unscaled_right
- unscaled_left
);
886 /* spu->scaled_aimage[base] =
887 alpha * dxs * dys / spu->orig_frame_width / spu->orig_frame_height; */
888 if (spu
->scaled_aimage
[base
]) {
889 spu
->scaled_aimage
[base
] = 256 - spu
->scaled_aimage
[base
];
890 if (spu
->scaled_aimage
[base
] + spu
->scaled_image
[base
] > 255)
891 spu
->scaled_image
[base
] = 256 - spu
->scaled_aimage
[base
];
899 /* Best antialiasing. Very slow. */
900 /* Any pixel (x, y) represents pixels from the original
901 rectangular region comprised between the columns
902 unscaled_y and unscaled_y + 0x100 / scaley and the rows
903 unscaled_x and unscaled_x + 0x100 / scalex
905 The original rectangular region that the scaled pixel
906 represents is cut in 9 rectangular areas like this:
908 +---+-----------------+---+
910 +---+-----------------+---+
914 +---+-----------------+---+
916 +---+-----------------+---+
918 The width of the left column is at most one pixel and
919 it is never null and its right column is at a pixel
920 boundary. The height of the top row is at most one
921 pixel it is never null and its bottom row is at a
922 pixel boundary. The width and height of region 5 are
923 integral values. The width of the right column is
924 what remains and is less than one pixel. The height
925 of the bottom row is what remains and is less than
928 The row above 1, 2, 3 is unscaled_y. The row between
929 1, 2, 3 and 4, 5, 6 is top_low_row. The row between 4,
930 5, 6 and 7, 8, 9 is (unsigned int)unscaled_y_bottom.
931 The row beneath 7, 8, 9 is unscaled_y_bottom.
933 The column left of 1, 4, 7 is unscaled_x. The column
934 between 1, 4, 7 and 2, 5, 8 is left_right_column. The
935 column between 2, 5, 8 and 3, 6, 9 is (unsigned
936 int)unscaled_x_right. The column right of 3, 6, 9 is
938 const double inv_scalex
= (double) 0x100 / scalex
;
939 const double inv_scaley
= (double) 0x100 / scaley
;
940 for (y
= 0; y
< spu
->scaled_height
; ++y
) {
941 const double unscaled_y
= y
* inv_scaley
;
942 const double unscaled_y_bottom
= unscaled_y
+ inv_scaley
;
943 const unsigned int top_low_row
= FFMIN(unscaled_y_bottom
, unscaled_y
+ 1.0);
944 const double top
= top_low_row
- unscaled_y
;
945 const unsigned int height
= unscaled_y_bottom
> top_low_row
946 ? (unsigned int) unscaled_y_bottom
- top_low_row
948 const double bottom
= unscaled_y_bottom
> top_low_row
949 ? unscaled_y_bottom
- floor(unscaled_y_bottom
)
951 for (x
= 0; x
< spu
->scaled_width
; ++x
) {
952 const double unscaled_x
= x
* inv_scalex
;
953 const double unscaled_x_right
= unscaled_x
+ inv_scalex
;
954 const unsigned int left_right_column
= FFMIN(unscaled_x_right
, unscaled_x
+ 1.0);
955 const double left
= left_right_column
- unscaled_x
;
956 const unsigned int width
= unscaled_x_right
> left_right_column
957 ? (unsigned int) unscaled_x_right
- left_right_column
959 const double right
= unscaled_x_right
> left_right_column
960 ? unscaled_x_right
- floor(unscaled_x_right
)
966 /* Now use these informations to compute a good alpha,
967 and lightness. The sum is on each of the 9
968 region's surface and alpha and lightness.
970 transformed alpha = sum(surface * alpha) / sum(surface)
971 transformed color = sum(surface * alpha * color) / sum(surface * alpha)
973 /* 1: top left part */
974 base
= spu
->stride
* (unsigned int) unscaled_y
;
975 tmp
= left
* top
* canon_alpha(spu
->aimage
[base
+ (unsigned int) unscaled_x
]);
977 color
+= tmp
* spu
->image
[base
+ (unsigned int) unscaled_x
];
978 /* 2: top center part */
981 for (walkx
= left_right_column
; walkx
< (unsigned int) unscaled_x_right
; ++walkx
) {
982 base
= spu
->stride
* (unsigned int) unscaled_y
+ walkx
;
983 tmp
= /* 1.0 * */ top
* canon_alpha(spu
->aimage
[base
]);
985 color
+= tmp
* spu
->image
[base
];
988 /* 3: top right part */
990 base
= spu
->stride
* (unsigned int) unscaled_y
+ (unsigned int) unscaled_x_right
;
991 tmp
= right
* top
* canon_alpha(spu
->aimage
[base
]);
993 color
+= tmp
* spu
->image
[base
];
995 /* 4: center left part */
998 for (walky
= top_low_row
; walky
< (unsigned int) unscaled_y_bottom
; ++walky
) {
999 base
= spu
->stride
* walky
+ (unsigned int) unscaled_x
;
1000 tmp
= left
/* * 1.0 */ * canon_alpha(spu
->aimage
[base
]);
1002 color
+= tmp
* spu
->image
[base
];
1005 /* 5: center part */
1006 if (width
> 0 && height
> 0) {
1008 for (walky
= top_low_row
; walky
< (unsigned int) unscaled_y_bottom
; ++walky
) {
1010 base
= spu
->stride
* walky
;
1011 for (walkx
= left_right_column
; walkx
< (unsigned int) unscaled_x_right
; ++walkx
) {
1012 tmp
= /* 1.0 * 1.0 * */ canon_alpha(spu
->aimage
[base
+ walkx
]);
1014 color
+= tmp
* spu
->image
[base
+ walkx
];
1018 /* 6: center right part */
1019 if (right
> 0.0 && height
> 0) {
1021 for (walky
= top_low_row
; walky
< (unsigned int) unscaled_y_bottom
; ++walky
) {
1022 base
= spu
->stride
* walky
+ (unsigned int) unscaled_x_right
;
1023 tmp
= right
/* * 1.0 */ * canon_alpha(spu
->aimage
[base
]);
1025 color
+= tmp
* spu
->image
[base
];
1028 /* 7: bottom left part */
1030 base
= spu
->stride
* (unsigned int) unscaled_y_bottom
+ (unsigned int) unscaled_x
;
1031 tmp
= left
* bottom
* canon_alpha(spu
->aimage
[base
]);
1033 color
+= tmp
* spu
->image
[base
];
1035 /* 8: bottom center part */
1036 if (width
> 0 && bottom
> 0.0) {
1038 base
= spu
->stride
* (unsigned int) unscaled_y_bottom
;
1039 for (walkx
= left_right_column
; walkx
< (unsigned int) unscaled_x_right
; ++walkx
) {
1040 tmp
= /* 1.0 * */ bottom
* canon_alpha(spu
->aimage
[base
+ walkx
]);
1042 color
+= tmp
* spu
->image
[base
+ walkx
];
1045 /* 9: bottom right part */
1046 if (right
> 0.0 && bottom
> 0.0) {
1047 base
= spu
->stride
* (unsigned int) unscaled_y_bottom
+ (unsigned int) unscaled_x_right
;
1048 tmp
= right
* bottom
* canon_alpha(spu
->aimage
[base
]);
1050 color
+= tmp
* spu
->image
[base
];
1052 /* Finally mix these transparency and brightness information suitably */
1053 base
= spu
->scaled_stride
* y
+ x
;
1054 spu
->scaled_image
[base
] = alpha
> 0 ? color
/ alpha
: 0;
1055 spu
->scaled_aimage
[base
] = alpha
* scalex
* scaley
/ 0x10000;
1056 if (spu
->scaled_aimage
[base
]) {
1057 spu
->scaled_aimage
[base
] = 256 - spu
->scaled_aimage
[base
];
1058 if (spu
->scaled_aimage
[base
] + spu
->scaled_image
[base
] > 255)
1059 spu
->scaled_image
[base
] = 256 - spu
->scaled_aimage
[base
];
1066 /* Kludge: draw_alpha needs width multiple of 8. */
1067 if (spu
->scaled_width
< spu
->scaled_stride
)
1068 for (y
= 0; y
< spu
->scaled_height
; ++y
) {
1069 memset(spu
->scaled_aimage
+ y
* spu
->scaled_stride
+ spu
->scaled_width
, 0,
1070 spu
->scaled_stride
- spu
->scaled_width
);
1072 spu
->scaled_frame_width
= dxs
;
1073 spu
->scaled_frame_height
= dys
;
1076 if (spu
->scaled_image
){
1077 switch (spu_alignment
) {
1079 spu
->scaled_start_row
= dys
*sub_pos
/100;
1080 if (spu
->scaled_start_row
+ spu
->scaled_height
> dys
)
1081 spu
->scaled_start_row
= dys
- spu
->scaled_height
;
1084 spu
->scaled_start_row
= dys
*sub_pos
/100 - spu
->scaled_height
/2;
1085 if (sub_pos
>= 50 && spu
->scaled_start_row
+ spu
->scaled_height
> dys
)
1086 spu
->scaled_start_row
= dys
- spu
->scaled_height
;
1089 spu
->scaled_start_row
= dys
*sub_pos
/100 - spu
->scaled_height
;
1092 draw_alpha(ctx
, spu
->scaled_start_col
, spu
->scaled_start_row
, spu
->scaled_width
, spu
->scaled_height
,
1093 spu
->scaled_image
, spu
->scaled_aimage
, spu
->scaled_stride
);
1094 spu
->spu_changed
= 0;
1100 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"SPU not displayed: start_pts=%d end_pts=%d now_pts=%d\n",
1101 spu
->start_pts
, spu
->end_pts
, spu
->now_pts
);
1105 void spudec_update_palette(void * this, unsigned int *palette
)
1107 spudec_handle_t
*spu
= (spudec_handle_t
*) this;
1108 if (spu
&& palette
) {
1109 memcpy(spu
->global_palette
, palette
, sizeof(spu
->global_palette
));
1111 vo_control(spu
->hw_spu
, VOCTRL_SET_SPU_PALETTE
, spu
->global_palette
);
1115 void spudec_set_font_factor(void * this, double factor
)
1117 spudec_handle_t
*spu
= (spudec_handle_t
*) this;
1118 spu
->font_start_level
= (int)(0xF0-(0xE0*factor
));
1121 static void spudec_parse_extradata(spudec_handle_t
*this,
1122 uint8_t *extradata
, int extradata_len
)
1124 uint8_t *buffer
, *ptr
;
1125 unsigned int *pal
= this->global_palette
, *cuspal
= this->cuspal
;
1129 if (extradata_len
== 16*4) {
1130 for (i
=0; i
<16; i
++)
1131 pal
[i
] = AV_RB32(extradata
+ i
*4);
1132 this->auto_palette
= 0;
1136 if (!(ptr
= buffer
= malloc(extradata_len
+1)))
1138 memcpy(buffer
, extradata
, extradata_len
);
1139 buffer
[extradata_len
] = 0;
1142 sscanf(ptr
, "size: %dx%d", &this->orig_frame_width
, &this->orig_frame_height
);
1143 if (sscanf(ptr
, "palette: %x, %x, %x, %x, %x, %x, %x, %x,"
1144 " %x, %x, %x, %x, %x, %x, %x, %x",
1145 &pal
[ 0], &pal
[ 1], &pal
[ 2], &pal
[ 3],
1146 &pal
[ 4], &pal
[ 5], &pal
[ 6], &pal
[ 7],
1147 &pal
[ 8], &pal
[ 9], &pal
[10], &pal
[11],
1148 &pal
[12], &pal
[13], &pal
[14], &pal
[15]) == 16) {
1149 for (i
=0; i
<16; i
++)
1150 pal
[i
] = vobsub_palette_to_yuv(pal
[i
]);
1151 this->auto_palette
= 0;
1153 if (!strncasecmp(ptr
, "forced subs: on", 15))
1154 this->forced_subs_only
= 1;
1155 if (sscanf(ptr
, "custom colors: ON, tridx: %x, colors: %x, %x, %x, %x",
1156 &tridx
, cuspal
+0, cuspal
+1, cuspal
+2, cuspal
+3) == 5) {
1157 for (i
=0; i
<4; i
++) {
1158 cuspal
[i
] = vobsub_rgb_to_yuv(cuspal
[i
]);
1159 if (tridx
& (1 << (12-4*i
)))
1160 cuspal
[i
] |= 1 << 31;
1164 } while ((ptr
=strchr(ptr
,'\n')) && *++ptr
);
1169 void *spudec_new_scaled(unsigned int *palette
, unsigned int frame_width
, unsigned int frame_height
, uint8_t *extradata
, int extradata_len
)
1171 spudec_handle_t
*this = calloc(1, sizeof(spudec_handle_t
));
1173 this->orig_frame_height
= frame_height
;
1176 memcpy(this->global_palette
, palette
, sizeof(this->global_palette
));
1178 this->auto_palette
= 1;
1180 spudec_parse_extradata(this, extradata
, extradata_len
);
1181 /* XXX Although the video frame is some size, the SPU frame is
1182 always maximum size i.e. 720 wide and 576 or 480 high */
1183 this->orig_frame_width
= 720;
1184 if (this->orig_frame_height
== 480 || this->orig_frame_height
== 240)
1185 this->orig_frame_height
= 480;
1187 this->orig_frame_height
= 576;
1190 mp_msg(MSGT_SPUDEC
,MSGL_FATAL
, "FATAL: spudec_init: calloc");
1194 void *spudec_new(unsigned int *palette
)
1196 return spudec_new_scaled(palette
, 0, 0, NULL
, 0);
1199 void spudec_free(void *this)
1201 spudec_handle_t
*spu
= (spudec_handle_t
*)this;
1203 while (spu
->queue_head
)
1204 spudec_free_packet(spudec_dequeue_packet(spu
));
1207 if (spu
->scaled_image
)
1208 free(spu
->scaled_image
);
1215 void spudec_set_hw_spu(void *this, struct vo
*hw_spu
)
1217 spudec_handle_t
*spu
= (spudec_handle_t
*)this;
1220 spu
->hw_spu
= hw_spu
;
1221 vo_control(hw_spu
, VOCTRL_SET_SPU_PALETTE
, spu
->global_palette
);