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>
13 * This file is part of MPlayer.
15 * MPlayer is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
20 * MPlayer is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License along
26 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
27 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
38 #include <libavutil/avutil.h>
39 #include <libavutil/intreadwrite.h>
40 #include <libswscale/swscale.h>
45 #include "libvo/video_out.h"
50 /* Valid values for spu_aamode:
51 0: none (fastest, most ugly)
54 3: bilinear (similiar to vobsub, fast and not too bad)
55 4: uses swscaler gaussian (this is the only one that looks good)
59 int spu_alignment
= -1;
60 float spu_gaussvar
= 1.0;
63 typedef struct packet_t packet_t
;
66 unsigned char *packet
;
68 unsigned int palette
[4];
69 unsigned int alpha
[4];
70 unsigned int control_start
; /* index of start of control data */
71 unsigned int current_nibble
[2]; /* next data nibble (4 bits) to be
72 processed (for RLE decoding) for
74 int deinterlace_oddness
; /* 0 or 1, index into current_nibble */
75 unsigned int start_col
;
76 unsigned int start_row
;
77 unsigned int width
, height
, stride
;
78 unsigned int start_pts
, end_pts
;
82 struct palette_crop_cache
{
92 unsigned int global_palette
[16];
93 unsigned int orig_frame_width
, orig_frame_height
;
94 unsigned char* packet
;
95 size_t packet_reserve
; /* size of the memory pointed to by packet */
96 unsigned int packet_offset
; /* end of the currently assembled fragment */
97 unsigned int packet_size
; /* size of the packet once all fragments are assembled */
98 int packet_pts
; /* PTS for this packet */
99 unsigned int palette
[4];
100 unsigned int alpha
[4];
101 unsigned int cuspal
[4];
103 unsigned int now_pts
;
104 unsigned int start_pts
, end_pts
;
105 unsigned int start_col
;
106 unsigned int start_row
;
107 unsigned int width
, height
, stride
;
108 size_t image_size
; /* Size of the image buffer */
109 unsigned char *image
; /* Grayscale value */
110 unsigned char *aimage
; /* Alpha value */
111 unsigned int pal_start_col
, pal_start_row
;
112 unsigned int pal_width
, pal_height
;
113 unsigned char *pal_image
; /* palette entry value */
114 unsigned int scaled_frame_width
, scaled_frame_height
;
115 unsigned int scaled_start_col
, scaled_start_row
;
116 unsigned int scaled_width
, scaled_height
, scaled_stride
;
117 size_t scaled_image_size
;
118 unsigned char *scaled_image
;
119 unsigned char *scaled_aimage
;
120 int auto_palette
; /* 1 if we lack a palette and must use an heuristic. */
121 int font_start_level
; /* Darkest value used for the computed font */
124 unsigned int forced_subs_only
; /* flag: 0=display all subtitle, !0 display only forced subtitles */
125 unsigned int is_forced_sub
; /* true if current subtitle is a forced subtitle */
127 struct palette_crop_cache palette_crop_cache
;
130 static void spudec_queue_packet(spudec_handle_t
*this, packet_t
*packet
)
132 if (this->queue_head
== NULL
)
133 this->queue_head
= packet
;
135 this->queue_tail
->next
= packet
;
136 this->queue_tail
= packet
;
139 static packet_t
*spudec_dequeue_packet(spudec_handle_t
*this)
141 packet_t
*retval
= this->queue_head
;
143 this->queue_head
= retval
->next
;
144 if (this->queue_head
== NULL
)
145 this->queue_tail
= NULL
;
150 static void spudec_free_packet(packet_t
*packet
)
152 free(packet
->packet
);
156 static inline unsigned int get_be16(const unsigned char *p
)
158 return (p
[0] << 8) + p
[1];
161 static inline unsigned int get_be24(const unsigned char *p
)
163 return (get_be16(p
) << 8) + p
[2];
166 static void next_line(packet_t
*packet
)
168 if (packet
->current_nibble
[packet
->deinterlace_oddness
] % 2)
169 packet
->current_nibble
[packet
->deinterlace_oddness
]++;
170 packet
->deinterlace_oddness
= (packet
->deinterlace_oddness
+ 1) % 2;
173 static inline unsigned char get_nibble(packet_t
*packet
)
176 unsigned int *nibblep
= packet
->current_nibble
+ packet
->deinterlace_oddness
;
177 if (*nibblep
/ 2 >= packet
->control_start
) {
178 mp_msg(MSGT_SPUDEC
,MSGL_WARN
, "SPUdec: ERROR: get_nibble past end of packet\n");
181 nib
= packet
->packet
[*nibblep
/ 2];
190 /* Cut the sub to visible part */
191 static inline void spudec_cut_image(spudec_handle_t
*this)
194 unsigned int first_y
, last_y
;
196 if (this->stride
== 0 || this->height
== 0) {
200 for (fy
= 0; fy
< this->image_size
&& !this->aimage
[fy
]; fy
++);
201 for (ly
= this->stride
* this->height
-1; ly
&& !this->aimage
[ly
]; ly
--);
202 first_y
= fy
/ this->stride
;
203 last_y
= ly
/ this->stride
;
204 //printf("first_y: %d, last_y: %d\n", first_y, last_y);
205 this->start_row
+= first_y
;
207 // Some subtitles trigger this condition
208 if (last_y
+ 1 > first_y
) {
209 this->height
= last_y
- first_y
+1;
215 // printf("new h %d new start %d (sz %d st %d)---\n\n", this->height, this->start_row, this->image_size, this->stride);
218 memmove(this->image
, this->image
+ this->stride
* first_y
, this->stride
* this->height
);
219 memmove(this->aimage
, this->aimage
+ this->stride
* first_y
, this->stride
* this->height
);
224 static int spudec_alloc_image(spudec_handle_t
*this, int stride
, int height
)
226 if (this->width
> stride
) // just a safeguard
227 this->width
= stride
;
228 this->stride
= stride
;
229 this->height
= height
;
230 if (this->image_size
< this->stride
* this->height
) {
231 if (this->image
!= NULL
) {
233 free(this->pal_image
);
234 this->image_size
= 0;
235 this->pal_width
= this->pal_height
= 0;
237 this->image
= malloc(2 * this->stride
* this->height
);
239 this->image_size
= this->stride
* this->height
;
240 this->aimage
= this->image
+ this->image_size
;
241 // use stride here as well to simplify reallocation checks
242 this->pal_image
= malloc(this->stride
* this->height
);
245 return this->image
!= NULL
;
249 * \param pal palette in MPlayer-style gray-alpha values, i.e.
250 * alpha == 0 means transparent, 1 fully opaque,
251 * gray value <= 256 - alpha.
253 static void pal2gray_alpha(const uint16_t *pal
,
254 const uint8_t *src
, int src_stride
,
255 uint8_t *dst
, uint8_t *dsta
,
256 int dst_stride
, int w
, int h
)
259 for (y
= 0; y
< h
; y
++) {
260 for (x
= 0; x
< w
; x
++) {
261 uint16_t pixel
= pal
[src
[x
]];
263 *dsta
++ = pixel
>> 8;
265 for (; x
< dst_stride
; x
++)
266 *dsta
++ = *dst
++ = 0;
271 static int apply_palette_crop(spudec_handle_t
*this,
272 unsigned crop_x
, unsigned crop_y
,
273 unsigned crop_w
, unsigned crop_h
)
278 unsigned stride
= (crop_w
+ 7) & ~7;
279 if (crop_x
> this->pal_width
|| crop_y
> this->pal_height
||
280 crop_w
> this->pal_width
- crop_x
|| crop_h
> this->pal_width
- crop_y
||
281 crop_w
> 0x8000 || crop_h
> 0x8000 ||
282 stride
* crop_h
> this->image_size
) {
285 for (i
= 0; i
< 4; ++i
) {
287 int alpha
= this->alpha
[i
];
290 if (this->custom
&& (this->cuspal
[i
] >> 31) != 0)
292 color
= this->custom
? this->cuspal
[i
] :
293 this->global_palette
[this->palette
[i
]];
294 color
= (color
>> 16) & 0xff;
295 // convert to MPlayer-style gray/alpha palette
296 color
= FFMIN(color
, alpha
);
297 pal
[i
] = (-alpha
<< 8) | color
;
299 src
= this->pal_image
+ crop_y
* this->pal_width
+ crop_x
;
300 pal2gray_alpha(pal
, src
, this->pal_width
,
301 this->image
, this->aimage
, stride
,
303 this->width
= crop_w
;
304 this->height
= crop_h
;
305 this->stride
= stride
;
306 this->start_col
= this->pal_start_col
+ crop_x
;
307 this->start_row
= this->pal_start_row
+ crop_y
;
308 spudec_cut_image(this);
310 // reset scaled image
311 this->scaled_frame_width
= 0;
312 this->scaled_frame_height
= 0;
313 this->palette_crop_cache
.valid
= 0;
317 int spudec_apply_palette_crop(void *this, uint32_t palette
,
318 int sx
, int sy
, int ex
, int ey
)
320 spudec_handle_t
*spu
= this;
321 struct palette_crop_cache
*c
= &spu
->palette_crop_cache
;
322 if (c
->valid
&& c
->palette
== palette
&&
323 c
->sx
== sx
&& c
->sy
== sy
&& c
->ex
== ex
&& c
->ey
== ey
)
325 spu
->palette
[0] = (palette
>> 28) & 0xf;
326 spu
->palette
[1] = (palette
>> 24) & 0xf;
327 spu
->palette
[2] = (palette
>> 20) & 0xf;
328 spu
->palette
[3] = (palette
>> 16) & 0xf;
329 spu
->alpha
[0] = (palette
>> 12) & 0xf;
330 spu
->alpha
[1] = (palette
>> 8) & 0xf;
331 spu
->alpha
[2] = (palette
>> 4) & 0xf;
332 spu
->alpha
[3] = palette
& 0xf;
333 spu
->spu_changed
= 1;
334 c
->result
= apply_palette_crop(spu
,
335 sx
- spu
->pal_start_col
, sy
- spu
->pal_start_row
,
337 c
->palette
= palette
;
338 c
->sx
= sx
; c
->sy
= sy
;
339 c
->ex
= ex
; c
->ey
= ey
;
344 static void spudec_process_data(spudec_handle_t
*this, packet_t
*packet
)
346 unsigned int i
, x
, y
;
349 if (!spudec_alloc_image(this, packet
->stride
, packet
->height
))
352 this->pal_start_col
= packet
->start_col
;
353 this->pal_start_row
= packet
->start_row
;
354 this->pal_height
= packet
->height
;
355 this->pal_width
= packet
->width
;
356 this->stride
= packet
->stride
;
357 memcpy(this->palette
, packet
->palette
, sizeof(this->palette
));
358 memcpy(this->alpha
, packet
->alpha
, sizeof(this->alpha
));
360 i
= packet
->current_nibble
[1];
363 dst
= this->pal_image
;
364 while (packet
->current_nibble
[0] < i
365 && packet
->current_nibble
[1] / 2 < packet
->control_start
366 && y
< this->pal_height
) {
367 unsigned int len
, color
;
368 unsigned int rle
= 0;
369 rle
= get_nibble(packet
);
372 rle
= (rle
<< 4) | get_nibble(packet
);
374 rle
= (rle
<< 4) | get_nibble(packet
);
376 rle
= (rle
<< 4) | get_nibble(packet
);
378 color
= 3 - (rle
& 0x3);
381 if (len
== 0 || x
>= this->pal_width
) {
382 len
+= this->pal_width
- x
;
387 memset(dst
, color
, len
);
390 apply_palette_crop(this, 0, 0, this->pal_width
, this->pal_height
);
395 This function tries to create a usable palette.
396 It determines how many non-transparent colors are used, and assigns different
397 gray scale values to each color.
398 I tested it with four streams and even got something readable. Half of the
399 times I got black characters with white around and half the reverse.
401 static void compute_palette(spudec_handle_t
*this, packet_t
*packet
)
403 int used
[16],i
,cused
,start
,step
,color
;
405 memset(used
, 0, sizeof(used
));
407 if (packet
->alpha
[i
]) /* !Transparent? */
408 used
[packet
->palette
[i
]] = 1;
409 for (cused
=0, i
=0; i
<16; i
++)
410 if (used
[i
]) cused
++;
416 start
= this->font_start_level
;
417 step
= (0xF0-this->font_start_level
)/(cused
-1);
419 memset(used
, 0, sizeof(used
));
420 for (i
=0; i
<4; i
++) {
421 color
= packet
->palette
[i
];
422 if (packet
->alpha
[i
] && !used
[color
]) { /* not assigned? */
424 this->global_palette
[color
] = start
<<16;
430 static void spudec_process_control(spudec_handle_t
*this, int pts100
)
432 int a
,b
,c
,d
; /* Temporary vars */
433 unsigned int date
, type
;
435 unsigned int start_off
= 0;
436 unsigned int next_off
;
437 unsigned int start_pts
= 0;
438 unsigned int end_pts
= 0;
439 unsigned int current_nibble
[2] = {0, 0};
440 unsigned int control_start
;
441 unsigned int display
= 0;
442 unsigned int start_col
= 0;
443 unsigned int end_col
= 0;
444 unsigned int start_row
= 0;
445 unsigned int end_row
= 0;
446 unsigned int width
= 0;
447 unsigned int height
= 0;
448 unsigned int stride
= 0;
450 control_start
= get_be16(this->packet
+ 2);
451 next_off
= control_start
;
452 while (start_off
!= next_off
) {
453 start_off
= next_off
;
454 date
= get_be16(this->packet
+ start_off
) * 1024;
455 next_off
= get_be16(this->packet
+ start_off
+ 2);
456 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
, "date=%d\n", date
);
458 for (type
= this->packet
[off
++]; type
!= 0xff; type
= this->packet
[off
++]) {
459 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
, "cmd=%d ",type
);
462 /* Menu ID, 1 byte */
463 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Menu ID\n");
464 /* shouldn't a Menu ID type force display start? */
465 start_pts
= pts100
< 0 && -pts100
>= date
? 0 : pts100
+ date
;
468 this->is_forced_sub
=~0; // current subtitle is forced
472 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Start display!\n");
473 start_pts
= pts100
< 0 && -pts100
>= date
? 0 : pts100
+ date
;
476 this->is_forced_sub
=0;
480 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Stop display!\n");
481 end_pts
= pts100
< 0 && -pts100
>= date
? 0 : pts100
+ date
;
485 this->palette
[0] = this->packet
[off
] >> 4;
486 this->palette
[1] = this->packet
[off
] & 0xf;
487 this->palette
[2] = this->packet
[off
+ 1] >> 4;
488 this->palette
[3] = this->packet
[off
+ 1] & 0xf;
489 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Palette %d, %d, %d, %d\n",
490 this->palette
[0], this->palette
[1], this->palette
[2], this->palette
[3]);
495 a
= this->packet
[off
] >> 4;
496 b
= this->packet
[off
] & 0xf;
497 c
= this->packet
[off
+ 1] >> 4;
498 d
= this->packet
[off
+ 1] & 0xf;
499 // Note: some DVDs change these values to create a fade-in/fade-out effect
500 // We can not handle this, so just keep the highest value during the display time.
502 a
= FFMAX(a
, this->alpha
[0]);
503 b
= FFMAX(b
, this->alpha
[1]);
504 c
= FFMAX(c
, this->alpha
[2]);
505 d
= FFMAX(d
, this->alpha
[3]);
511 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Alpha %d, %d, %d, %d\n",
512 this->alpha
[0], this->alpha
[1], this->alpha
[2], this->alpha
[3]);
517 a
= get_be24(this->packet
+ off
);
518 b
= get_be24(this->packet
+ off
+ 3);
521 width
= (end_col
< start_col
) ? 0 : end_col
- start_col
+ 1;
522 stride
= (width
+ 7) & ~7; /* Kludge: draw_alpha needs width multiple of 8 */
525 height
= (end_row
< start_row
) ? 0 : end_row
- start_row
/* + 1 */;
526 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Coords col: %d - %d row: %d - %d (%dx%d)\n",
527 start_col
, end_col
, start_row
, end_row
,
533 current_nibble
[0] = 2 * get_be16(this->packet
+ off
);
534 current_nibble
[1] = 2 * get_be16(this->packet
+ off
+ 2);
535 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Graphic offset 1: %d offset 2: %d\n",
536 current_nibble
[0] / 2, current_nibble
[1] / 2);
540 /* All done, bye-bye */
541 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Done!\n");
545 mp_msg(MSGT_SPUDEC
,MSGL_WARN
,"spudec: Error determining control type 0x%02x. Skipping %d bytes.\n",
546 type
, next_off
- off
);
553 if (end_pts
== UINT_MAX
&& start_off
!= next_off
) {
554 end_pts
= get_be16(this->packet
+ next_off
) * 1024;
555 end_pts
= 1 - pts100
>= end_pts
? 0 : pts100
+ end_pts
- 1;
558 packet_t
*packet
= calloc(1, sizeof(packet_t
));
560 packet
->start_pts
= start_pts
;
561 packet
->end_pts
= end_pts
;
562 packet
->current_nibble
[0] = current_nibble
[0];
563 packet
->current_nibble
[1] = current_nibble
[1];
564 packet
->start_row
= start_row
;
565 packet
->start_col
= start_col
;
566 packet
->width
= width
;
567 packet
->height
= height
;
568 packet
->stride
= stride
;
569 packet
->control_start
= control_start
;
570 for (i
=0; i
<4; i
++) {
571 packet
->alpha
[i
] = this->alpha
[i
];
572 packet
->palette
[i
] = this->palette
[i
];
574 packet
->packet
= malloc(this->packet_size
);
575 memcpy(packet
->packet
, this->packet
, this->packet_size
);
576 spudec_queue_packet(this, packet
);
581 static void spudec_decode(spudec_handle_t
*this, int pts100
)
584 spudec_process_control(this, pts100
);
585 else if (pts100
>= 0) {
586 static vo_mpegpes_t packet
= { NULL
, 0, 0x20, 0 };
587 static vo_mpegpes_t
*pkg
=&packet
;
588 packet
.data
= this->packet
;
589 packet
.size
= this->packet_size
;
590 packet
.timestamp
= pts100
;
591 vo_draw_frame(this->hw_spu
, (uint8_t**)&pkg
);
595 int spudec_changed(void * this)
597 spudec_handle_t
* spu
= this;
598 return spu
->spu_changed
|| spu
->now_pts
> spu
->end_pts
;
601 void spudec_assemble(void *this, unsigned char *packet
, unsigned int len
, int pts100
)
603 spudec_handle_t
*spu
= this;
604 // spudec_heartbeat(this, pts100);
606 mp_msg(MSGT_SPUDEC
,MSGL_WARN
,"SPUasm: packet too short\n");
609 spu
->packet_pts
= pts100
;
610 if (spu
->packet_offset
== 0) {
611 unsigned int len2
= get_be16(packet
);
612 // Start new fragment
613 if (spu
->packet_reserve
< len2
) {
615 spu
->packet
= malloc(len2
);
616 spu
->packet_reserve
= spu
->packet
!= NULL
? len2
: 0;
618 if (spu
->packet
!= NULL
) {
619 spu
->packet_size
= len2
;
621 mp_msg(MSGT_SPUDEC
,MSGL_WARN
,"SPUasm: invalid frag len / len2: %d / %d \n", len
, len2
);
624 memcpy(spu
->packet
, packet
, len
);
625 spu
->packet_offset
= len
;
626 spu
->packet_pts
= pts100
;
629 // Continue current fragment
630 if (spu
->packet_size
< spu
->packet_offset
+ len
){
631 mp_msg(MSGT_SPUDEC
,MSGL_WARN
,"SPUasm: invalid fragment\n");
632 spu
->packet_size
= spu
->packet_offset
= 0;
635 memcpy(spu
->packet
+ spu
->packet_offset
, packet
, len
);
636 spu
->packet_offset
+= len
;
640 // check if we have a complete packet (unfortunatelly packet_size is bad
642 // [cb] packet_size is padded to be even -> may be one byte too long
643 if ((spu
->packet_offset
== spu
->packet_size
) ||
644 ((spu
->packet_offset
+ 1) == spu
->packet_size
)){
646 while(x
+4<=spu
->packet_offset
){
647 y
=get_be16(spu
->packet
+x
+2); // next control pointer
648 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"SPUtest: x=%d y=%d off=%d size=%d\n",x
,y
,spu
->packet_offset
,spu
->packet_size
);
649 if(x
>=4 && x
==y
){ // if it points to self - we're done!
651 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"SPUgot: off=%d size=%d \n",spu
->packet_offset
,spu
->packet_size
);
652 spudec_decode(spu
, pts100
);
653 spu
->packet_offset
= 0;
656 if(y
<=x
|| y
>=spu
->packet_size
){ // invalid?
657 mp_msg(MSGT_SPUDEC
,MSGL_WARN
,"SPUtest: broken packet!!!!! y=%d < x=%d\n",y
,x
);
658 spu
->packet_size
= spu
->packet_offset
= 0;
663 // [cb] packet is done; start new packet
664 spu
->packet_offset
= 0;
667 if (spu
->packet_offset
== spu
->packet_size
) {
668 spudec_decode(spu
, pts100
);
669 spu
->packet_offset
= 0;
674 void spudec_reset(void *this) // called after seek
676 spudec_handle_t
*spu
= this;
677 while (spu
->queue_head
)
678 spudec_free_packet(spudec_dequeue_packet(spu
));
681 spu
->packet_size
= spu
->packet_offset
= 0;
684 void spudec_heartbeat(void *this, unsigned int pts100
)
686 spudec_handle_t
*spu
= this;
687 spu
->now_pts
= pts100
;
689 // TODO: detect and handle broken timestamps (e.g. due to wrapping)
690 while (spu
->queue_head
!= NULL
&& pts100
>= spu
->queue_head
->start_pts
) {
691 packet_t
*packet
= spudec_dequeue_packet(spu
);
692 spu
->start_pts
= packet
->start_pts
;
693 spu
->end_pts
= packet
->end_pts
;
694 if (packet
->is_decoded
) {
696 spu
->image_size
= packet
->data_len
;
697 spu
->image
= packet
->packet
;
698 spu
->aimage
= packet
->packet
+ packet
->stride
* packet
->height
;
699 packet
->packet
= NULL
;
700 spu
->width
= packet
->width
;
701 spu
->height
= packet
->height
;
702 spu
->stride
= packet
->stride
;
703 spu
->start_col
= packet
->start_col
;
704 spu
->start_row
= packet
->start_row
;
706 // reset scaled image
707 spu
->scaled_frame_width
= 0;
708 spu
->scaled_frame_height
= 0;
710 if (spu
->auto_palette
)
711 compute_palette(spu
, packet
);
712 spudec_process_data(spu
, packet
);
714 spudec_free_packet(packet
);
715 spu
->spu_changed
= 1;
719 int spudec_visible(void *this){
720 spudec_handle_t
*spu
= this;
721 int ret
=(spu
->start_pts
<= spu
->now_pts
&&
722 spu
->now_pts
< spu
->end_pts
&&
724 // printf("spu visible: %d \n",ret);
728 void spudec_set_forced_subs_only(void * const this, const unsigned int flag
)
731 ((spudec_handle_t
*)this)->forced_subs_only
=flag
;
732 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"SPU: Display only forced subs now %s\n", flag
? "enabled": "disabled");
736 void spudec_draw(void *this, void (*draw_alpha
)(void *ctx
, int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
), void *ctx
)
738 spudec_handle_t
*spu
= this;
739 if (spudec_visible(spu
))
741 draw_alpha(ctx
, spu
->start_col
, spu
->start_row
, spu
->width
, spu
->height
,
742 spu
->image
, spu
->aimage
, spu
->stride
);
743 spu
->spu_changed
= 0;
747 /* calc the bbox for spudec subs */
748 void spudec_calc_bbox(void *me
, unsigned int dxs
, unsigned int dys
, unsigned int* bbox
)
750 spudec_handle_t
*spu
= me
;
751 if (spu
->orig_frame_width
== 0 || spu
->orig_frame_height
== 0
752 || (spu
->orig_frame_width
== dxs
&& spu
->orig_frame_height
== dys
)) {
754 bbox
[0] = spu
->start_col
;
755 bbox
[1] = spu
->start_col
+ spu
->width
;
756 bbox
[2] = spu
->start_row
;
757 bbox
[3] = spu
->start_row
+ spu
->height
;
761 unsigned int scalex
= 0x100 * dxs
/ spu
->orig_frame_width
;
762 unsigned int scaley
= 0x100 * dys
/ spu
->orig_frame_height
;
763 bbox
[0] = spu
->start_col
* scalex
/ 0x100;
764 bbox
[1] = spu
->start_col
* scalex
/ 0x100 + spu
->width
* scalex
/ 0x100;
765 switch (spu_alignment
) {
767 bbox
[3] = dys
*sub_pos
/100 + spu
->height
* scaley
/ 0x100;
768 if (bbox
[3] > dys
) bbox
[3] = dys
;
769 bbox
[2] = bbox
[3] - spu
->height
* scaley
/ 0x100;
773 bbox
[2] = dys
*sub_pos
/100 - spu
->height
* scaley
/ 0x200;
774 bbox
[3] = bbox
[2] + spu
->height
;
776 bbox
[3] = dys
*sub_pos
/100 + spu
->height
* scaley
/ 0x200;
777 if (bbox
[3] > dys
) bbox
[3] = dys
;
778 bbox
[2] = bbox
[3] - spu
->height
* scaley
/ 0x100;
782 bbox
[2] = dys
*sub_pos
/100 - spu
->height
* scaley
/ 0x100;
783 bbox
[3] = bbox
[2] + spu
->height
;
786 bbox
[2] = spu
->start_row
* scaley
/ 0x100;
787 bbox
[3] = spu
->start_row
* scaley
/ 0x100 + spu
->height
* scaley
/ 0x100;
792 /* transform mplayer's alpha value into an opacity value that is linear */
793 static inline int canon_alpha(int alpha
)
795 return (uint8_t)-alpha
;
805 static void scale_table(unsigned int start_src
, unsigned int start_tar
, unsigned int end_src
, unsigned int end_tar
, scale_pixel
* table
)
808 unsigned int delta_src
= end_src
- start_src
;
809 unsigned int delta_tar
= end_tar
- start_tar
;
812 if (delta_src
== 0 || delta_tar
== 0) {
815 src_step
= (delta_src
<< 16) / delta_tar
>>1;
816 for (t
= 0; t
<=delta_tar
; src
+= (src_step
<< 1), t
++){
817 table
[t
].position
= FFMIN(src
>> 16, end_src
- 1);
818 table
[t
].right_down
= src
& 0xffff;
819 table
[t
].left_up
= 0x10000 - table
[t
].right_down
;
823 /* bilinear scale, similar to vobsub's code */
824 static void scale_image(int x
, int y
, scale_pixel
* table_x
, scale_pixel
* table_y
, spudec_handle_t
* spu
)
828 unsigned int scale
[4];
829 int base
= table_y
[y
].position
* spu
->stride
+ table_x
[x
].position
;
830 int scaled
= y
* spu
->scaled_stride
+ x
;
831 alpha
[0] = canon_alpha(spu
->aimage
[base
]);
832 alpha
[1] = canon_alpha(spu
->aimage
[base
+ 1]);
833 alpha
[2] = canon_alpha(spu
->aimage
[base
+ spu
->stride
]);
834 alpha
[3] = canon_alpha(spu
->aimage
[base
+ spu
->stride
+ 1]);
835 color
[0] = spu
->image
[base
];
836 color
[1] = spu
->image
[base
+ 1];
837 color
[2] = spu
->image
[base
+ spu
->stride
];
838 color
[3] = spu
->image
[base
+ spu
->stride
+ 1];
839 scale
[0] = (table_x
[x
].left_up
* table_y
[y
].left_up
>> 16) * alpha
[0];
840 if (table_y
[y
].left_up
== 0x10000) // necessary to avoid overflow-case
841 scale
[0] = table_x
[x
].left_up
* alpha
[0];
842 scale
[1] = (table_x
[x
].right_down
* table_y
[y
].left_up
>>16) * alpha
[1];
843 scale
[2] = (table_x
[x
].left_up
* table_y
[y
].right_down
>> 16) * alpha
[2];
844 scale
[3] = (table_x
[x
].right_down
* table_y
[y
].right_down
>> 16) * alpha
[3];
845 spu
->scaled_image
[scaled
] = (color
[0] * scale
[0] + color
[1] * scale
[1] + color
[2] * scale
[2] + color
[3] * scale
[3])>>24;
846 spu
->scaled_aimage
[scaled
] = (scale
[0] + scale
[1] + scale
[2] + scale
[3]) >> 16;
847 if (spu
->scaled_aimage
[scaled
]){
848 // ensure that MPlayer's simplified alpha-blending can not overflow
849 spu
->scaled_image
[scaled
] = FFMIN(spu
->scaled_image
[scaled
], spu
->scaled_aimage
[scaled
]);
850 // convert to MPlayer-style alpha
851 spu
->scaled_aimage
[scaled
] = -spu
->scaled_aimage
[scaled
];
855 static void sws_spu_image(unsigned char *d1
, unsigned char *d2
, int dw
, int dh
,
856 int ds
, const unsigned char* s1
, unsigned char* s2
,
857 int sw
, int sh
, int ss
)
859 struct SwsContext
*ctx
;
860 static SwsFilter filter
;
861 static int firsttime
= 1;
865 if (!firsttime
&& oldvar
!= spu_gaussvar
) sws_freeVec(filter
.lumH
);
867 filter
.lumH
= filter
.lumV
=
868 filter
.chrH
= filter
.chrV
= sws_getGaussianVec(spu_gaussvar
, 3.0);
869 sws_normalizeVec(filter
.lumH
, 1.0);
871 oldvar
= spu_gaussvar
;
874 ctx
=sws_getContext(sw
, sh
, PIX_FMT_GRAY8
, dw
, dh
, PIX_FMT_GRAY8
, SWS_GAUSS
, &filter
, NULL
, NULL
);
875 sws_scale(ctx
,&s1
,&ss
,0,sh
,&d1
,&ds
);
876 for (i
=ss
*sh
-1; i
>=0; i
--) if (!s2
[i
]) s2
[i
] = 255; //else s2[i] = 1;
877 sws_scale(ctx
,(const uint8_t **)&s2
,&ss
,0,sh
,&d2
,&ds
);
878 for (i
=ds
*dh
-1; i
>=0; i
--) if (d2
[i
]==0) d2
[i
] = 1; else if (d2
[i
]==255) d2
[i
] = 0;
879 sws_freeContext(ctx
);
882 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
)
884 spudec_handle_t
*spu
= me
;
885 scale_pixel
*table_x
;
886 scale_pixel
*table_y
;
888 if (spudec_visible(spu
)) {
890 // check if only forced subtitles are requested
891 if( (spu
->forced_subs_only
) && !(spu
->is_forced_sub
) ){
895 if (!(spu_aamode
&16) && (spu
->orig_frame_width
== 0 || spu
->orig_frame_height
== 0
896 || (spu
->orig_frame_width
== dxs
&& spu
->orig_frame_height
== dys
))) {
897 spudec_draw(spu
, draw_alpha
, ctx
);
900 if (spu
->scaled_frame_width
!= dxs
|| spu
->scaled_frame_height
!= dys
) { /* Resizing is needed */
901 /* scaled_x = scalex * x / 0x100
902 scaled_y = scaley * y / 0x100
903 order of operations is important because of rounding. */
904 unsigned int scalex
= 0x100 * dxs
/ spu
->orig_frame_width
;
905 unsigned int scaley
= 0x100 * dys
/ spu
->orig_frame_height
;
906 spu
->scaled_start_col
= spu
->start_col
* scalex
/ 0x100;
907 spu
->scaled_start_row
= spu
->start_row
* scaley
/ 0x100;
908 spu
->scaled_width
= spu
->width
* scalex
/ 0x100;
909 spu
->scaled_height
= spu
->height
* scaley
/ 0x100;
910 /* Kludge: draw_alpha needs width multiple of 8 */
911 spu
->scaled_stride
= (spu
->scaled_width
+ 7) & ~7;
912 if (spu
->scaled_image_size
< spu
->scaled_stride
* spu
->scaled_height
) {
913 if (spu
->scaled_image
) {
914 free(spu
->scaled_image
);
915 spu
->scaled_image_size
= 0;
917 spu
->scaled_image
= malloc(2 * spu
->scaled_stride
* spu
->scaled_height
);
918 if (spu
->scaled_image
) {
919 spu
->scaled_image_size
= spu
->scaled_stride
* spu
->scaled_height
;
920 spu
->scaled_aimage
= spu
->scaled_image
+ spu
->scaled_image_size
;
923 if (spu
->scaled_image
) {
925 // needs to be 0-initialized because draw_alpha draws always a
926 // multiple of 8 pixels. TODO: optimize
927 if (spu
->scaled_width
& 7)
928 memset(spu
->scaled_image
, 0, 2 * spu
->scaled_image_size
);
929 if (spu
->scaled_width
<= 1 || spu
->scaled_height
<= 1) {
932 switch(spu_aamode
&15) {
934 sws_spu_image(spu
->scaled_image
, spu
->scaled_aimage
,
935 spu
->scaled_width
, spu
->scaled_height
, spu
->scaled_stride
,
936 spu
->image
, spu
->aimage
, spu
->width
, spu
->height
, spu
->stride
);
939 table_x
= calloc(spu
->scaled_width
, sizeof(scale_pixel
));
940 table_y
= calloc(spu
->scaled_height
, sizeof(scale_pixel
));
941 if (!table_x
|| !table_y
) {
942 mp_msg(MSGT_SPUDEC
, MSGL_FATAL
, "Fatal: spudec_draw_scaled: calloc failed\n");
944 scale_table(0, 0, spu
->width
- 1, spu
->scaled_width
- 1, table_x
);
945 scale_table(0, 0, spu
->height
- 1, spu
->scaled_height
- 1, table_y
);
946 for (y
= 0; y
< spu
->scaled_height
; y
++)
947 for (x
= 0; x
< spu
->scaled_width
; x
++)
948 scale_image(x
, y
, table_x
, table_y
, spu
);
953 /* no antialiasing */
954 for (y
= 0; y
< spu
->scaled_height
; ++y
) {
955 int unscaled_y
= y
* 0x100 / scaley
;
956 int strides
= spu
->stride
* unscaled_y
;
957 int scaled_strides
= spu
->scaled_stride
* y
;
958 for (x
= 0; x
< spu
->scaled_width
; ++x
) {
959 int unscaled_x
= x
* 0x100 / scalex
;
960 spu
->scaled_image
[scaled_strides
+ x
] = spu
->image
[strides
+ unscaled_x
];
961 spu
->scaled_aimage
[scaled_strides
+ x
] = spu
->aimage
[strides
+ unscaled_x
];
967 /* Intermediate antialiasing. */
968 for (y
= 0; y
< spu
->scaled_height
; ++y
) {
969 const unsigned int unscaled_top
= y
* spu
->orig_frame_height
/ dys
;
970 unsigned int unscaled_bottom
= (y
+ 1) * spu
->orig_frame_height
/ dys
;
971 if (unscaled_bottom
>= spu
->height
)
972 unscaled_bottom
= spu
->height
- 1;
973 for (x
= 0; x
< spu
->scaled_width
; ++x
) {
974 const unsigned int unscaled_left
= x
* spu
->orig_frame_width
/ dxs
;
975 unsigned int unscaled_right
= (x
+ 1) * spu
->orig_frame_width
/ dxs
;
976 unsigned int color
= 0;
977 unsigned int alpha
= 0;
978 unsigned int walkx
, walky
;
979 unsigned int base
, tmp
;
980 if (unscaled_right
>= spu
->width
)
981 unscaled_right
= spu
->width
- 1;
982 for (walky
= unscaled_top
; walky
<= unscaled_bottom
; ++walky
)
983 for (walkx
= unscaled_left
; walkx
<= unscaled_right
; ++walkx
) {
984 base
= walky
* spu
->stride
+ walkx
;
985 tmp
= canon_alpha(spu
->aimage
[base
]);
987 color
+= tmp
* spu
->image
[base
];
989 base
= y
* spu
->scaled_stride
+ x
;
990 spu
->scaled_image
[base
] = alpha
? color
/ alpha
: 0;
991 spu
->scaled_aimage
[base
] =
992 alpha
* (1 + unscaled_bottom
- unscaled_top
) * (1 + unscaled_right
- unscaled_left
);
993 /* spu->scaled_aimage[base] =
994 alpha * dxs * dys / spu->orig_frame_width / spu->orig_frame_height; */
995 if (spu
->scaled_aimage
[base
]) {
996 spu
->scaled_aimage
[base
] = 256 - spu
->scaled_aimage
[base
];
997 if (spu
->scaled_aimage
[base
] + spu
->scaled_image
[base
] > 255)
998 spu
->scaled_image
[base
] = 256 - spu
->scaled_aimage
[base
];
1006 /* Best antialiasing. Very slow. */
1007 /* Any pixel (x, y) represents pixels from the original
1008 rectangular region comprised between the columns
1009 unscaled_y and unscaled_y + 0x100 / scaley and the rows
1010 unscaled_x and unscaled_x + 0x100 / scalex
1012 The original rectangular region that the scaled pixel
1013 represents is cut in 9 rectangular areas like this:
1015 +---+-----------------+---+
1017 +---+-----------------+---+
1021 +---+-----------------+---+
1023 +---+-----------------+---+
1025 The width of the left column is at most one pixel and
1026 it is never null and its right column is at a pixel
1027 boundary. The height of the top row is at most one
1028 pixel it is never null and its bottom row is at a
1029 pixel boundary. The width and height of region 5 are
1030 integral values. The width of the right column is
1031 what remains and is less than one pixel. The height
1032 of the bottom row is what remains and is less than
1035 The row above 1, 2, 3 is unscaled_y. The row between
1036 1, 2, 3 and 4, 5, 6 is top_low_row. The row between 4,
1037 5, 6 and 7, 8, 9 is (unsigned int)unscaled_y_bottom.
1038 The row beneath 7, 8, 9 is unscaled_y_bottom.
1040 The column left of 1, 4, 7 is unscaled_x. The column
1041 between 1, 4, 7 and 2, 5, 8 is left_right_column. The
1042 column between 2, 5, 8 and 3, 6, 9 is (unsigned
1043 int)unscaled_x_right. The column right of 3, 6, 9 is
1044 unscaled_x_right. */
1045 const double inv_scalex
= (double) 0x100 / scalex
;
1046 const double inv_scaley
= (double) 0x100 / scaley
;
1047 for (y
= 0; y
< spu
->scaled_height
; ++y
) {
1048 const double unscaled_y
= y
* inv_scaley
;
1049 const double unscaled_y_bottom
= unscaled_y
+ inv_scaley
;
1050 const unsigned int top_low_row
= FFMIN(unscaled_y_bottom
, unscaled_y
+ 1.0);
1051 const double top
= top_low_row
- unscaled_y
;
1052 const unsigned int height
= unscaled_y_bottom
> top_low_row
1053 ? (unsigned int) unscaled_y_bottom
- top_low_row
1055 const double bottom
= unscaled_y_bottom
> top_low_row
1056 ? unscaled_y_bottom
- floor(unscaled_y_bottom
)
1058 for (x
= 0; x
< spu
->scaled_width
; ++x
) {
1059 const double unscaled_x
= x
* inv_scalex
;
1060 const double unscaled_x_right
= unscaled_x
+ inv_scalex
;
1061 const unsigned int left_right_column
= FFMIN(unscaled_x_right
, unscaled_x
+ 1.0);
1062 const double left
= left_right_column
- unscaled_x
;
1063 const unsigned int width
= unscaled_x_right
> left_right_column
1064 ? (unsigned int) unscaled_x_right
- left_right_column
1066 const double right
= unscaled_x_right
> left_right_column
1067 ? unscaled_x_right
- floor(unscaled_x_right
)
1073 /* Now use these informations to compute a good alpha,
1074 and lightness. The sum is on each of the 9
1075 region's surface and alpha and lightness.
1077 transformed alpha = sum(surface * alpha) / sum(surface)
1078 transformed color = sum(surface * alpha * color) / sum(surface * alpha)
1080 /* 1: top left part */
1081 base
= spu
->stride
* (unsigned int) unscaled_y
;
1082 tmp
= left
* top
* canon_alpha(spu
->aimage
[base
+ (unsigned int) unscaled_x
]);
1084 color
+= tmp
* spu
->image
[base
+ (unsigned int) unscaled_x
];
1085 /* 2: top center part */
1088 for (walkx
= left_right_column
; walkx
< (unsigned int) unscaled_x_right
; ++walkx
) {
1089 base
= spu
->stride
* (unsigned int) unscaled_y
+ walkx
;
1090 tmp
= /* 1.0 * */ top
* canon_alpha(spu
->aimage
[base
]);
1092 color
+= tmp
* spu
->image
[base
];
1095 /* 3: top right part */
1097 base
= spu
->stride
* (unsigned int) unscaled_y
+ (unsigned int) unscaled_x_right
;
1098 tmp
= right
* top
* canon_alpha(spu
->aimage
[base
]);
1100 color
+= tmp
* spu
->image
[base
];
1102 /* 4: center left part */
1105 for (walky
= top_low_row
; walky
< (unsigned int) unscaled_y_bottom
; ++walky
) {
1106 base
= spu
->stride
* walky
+ (unsigned int) unscaled_x
;
1107 tmp
= left
/* * 1.0 */ * canon_alpha(spu
->aimage
[base
]);
1109 color
+= tmp
* spu
->image
[base
];
1112 /* 5: center part */
1113 if (width
> 0 && height
> 0) {
1115 for (walky
= top_low_row
; walky
< (unsigned int) unscaled_y_bottom
; ++walky
) {
1117 base
= spu
->stride
* walky
;
1118 for (walkx
= left_right_column
; walkx
< (unsigned int) unscaled_x_right
; ++walkx
) {
1119 tmp
= /* 1.0 * 1.0 * */ canon_alpha(spu
->aimage
[base
+ walkx
]);
1121 color
+= tmp
* spu
->image
[base
+ walkx
];
1125 /* 6: center right part */
1126 if (right
> 0.0 && height
> 0) {
1128 for (walky
= top_low_row
; walky
< (unsigned int) unscaled_y_bottom
; ++walky
) {
1129 base
= spu
->stride
* walky
+ (unsigned int) unscaled_x_right
;
1130 tmp
= right
/* * 1.0 */ * canon_alpha(spu
->aimage
[base
]);
1132 color
+= tmp
* spu
->image
[base
];
1135 /* 7: bottom left part */
1137 base
= spu
->stride
* (unsigned int) unscaled_y_bottom
+ (unsigned int) unscaled_x
;
1138 tmp
= left
* bottom
* canon_alpha(spu
->aimage
[base
]);
1140 color
+= tmp
* spu
->image
[base
];
1142 /* 8: bottom center part */
1143 if (width
> 0 && bottom
> 0.0) {
1145 base
= spu
->stride
* (unsigned int) unscaled_y_bottom
;
1146 for (walkx
= left_right_column
; walkx
< (unsigned int) unscaled_x_right
; ++walkx
) {
1147 tmp
= /* 1.0 * */ bottom
* canon_alpha(spu
->aimage
[base
+ walkx
]);
1149 color
+= tmp
* spu
->image
[base
+ walkx
];
1152 /* 9: bottom right part */
1153 if (right
> 0.0 && bottom
> 0.0) {
1154 base
= spu
->stride
* (unsigned int) unscaled_y_bottom
+ (unsigned int) unscaled_x_right
;
1155 tmp
= right
* bottom
* canon_alpha(spu
->aimage
[base
]);
1157 color
+= tmp
* spu
->image
[base
];
1159 /* Finally mix these transparency and brightness information suitably */
1160 base
= spu
->scaled_stride
* y
+ x
;
1161 spu
->scaled_image
[base
] = alpha
> 0 ? color
/ alpha
: 0;
1162 spu
->scaled_aimage
[base
] = alpha
* scalex
* scaley
/ 0x10000;
1163 if (spu
->scaled_aimage
[base
]) {
1164 spu
->scaled_aimage
[base
] = 256 - spu
->scaled_aimage
[base
];
1165 if (spu
->scaled_aimage
[base
] + spu
->scaled_image
[base
] > 255)
1166 spu
->scaled_image
[base
] = 256 - spu
->scaled_aimage
[base
];
1173 /* Kludge: draw_alpha needs width multiple of 8. */
1174 if (spu
->scaled_width
< spu
->scaled_stride
)
1175 for (y
= 0; y
< spu
->scaled_height
; ++y
) {
1176 memset(spu
->scaled_aimage
+ y
* spu
->scaled_stride
+ spu
->scaled_width
, 0,
1177 spu
->scaled_stride
- spu
->scaled_width
);
1179 spu
->scaled_frame_width
= dxs
;
1180 spu
->scaled_frame_height
= dys
;
1183 if (spu
->scaled_image
){
1184 switch (spu_alignment
) {
1186 spu
->scaled_start_row
= dys
*sub_pos
/100;
1187 if (spu
->scaled_start_row
+ spu
->scaled_height
> dys
)
1188 spu
->scaled_start_row
= dys
- spu
->scaled_height
;
1191 spu
->scaled_start_row
= dys
*sub_pos
/100 - spu
->scaled_height
/2;
1192 if (sub_pos
>= 50 && spu
->scaled_start_row
+ spu
->scaled_height
> dys
)
1193 spu
->scaled_start_row
= dys
- spu
->scaled_height
;
1196 spu
->scaled_start_row
= dys
*sub_pos
/100 - spu
->scaled_height
;
1199 draw_alpha(ctx
, spu
->scaled_start_col
, spu
->scaled_start_row
, spu
->scaled_width
, spu
->scaled_height
,
1200 spu
->scaled_image
, spu
->scaled_aimage
, spu
->scaled_stride
);
1201 spu
->spu_changed
= 0;
1207 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"SPU not displayed: start_pts=%d end_pts=%d now_pts=%d\n",
1208 spu
->start_pts
, spu
->end_pts
, spu
->now_pts
);
1212 void spudec_update_palette(void * this, unsigned int *palette
)
1214 spudec_handle_t
*spu
= this;
1215 if (spu
&& palette
) {
1216 memcpy(spu
->global_palette
, palette
, sizeof(spu
->global_palette
));
1218 vo_control(spu
->hw_spu
, VOCTRL_SET_SPU_PALETTE
, spu
->global_palette
);
1222 void spudec_set_font_factor(void * this, double factor
)
1224 spudec_handle_t
*spu
= this;
1225 spu
->font_start_level
= (int)(0xF0-(0xE0*factor
));
1228 static void spudec_parse_extradata(spudec_handle_t
*this,
1229 uint8_t *extradata
, int extradata_len
)
1231 uint8_t *buffer
, *ptr
;
1232 unsigned int *pal
= this->global_palette
, *cuspal
= this->cuspal
;
1236 if (extradata_len
== 16*4) {
1237 for (i
=0; i
<16; i
++)
1238 pal
[i
] = AV_RB32(extradata
+ i
*4);
1239 this->auto_palette
= 0;
1243 if (!(ptr
= buffer
= malloc(extradata_len
+1)))
1245 memcpy(buffer
, extradata
, extradata_len
);
1246 buffer
[extradata_len
] = 0;
1251 if (!strncmp(ptr
, "size: ", 6))
1252 sscanf(ptr
+ 6, "%dx%d", &this->orig_frame_width
, &this->orig_frame_height
);
1253 if (!strncmp(ptr
, "palette: ", 9) &&
1254 sscanf(ptr
+ 9, "%x, %x, %x, %x, %x, %x, %x, %x, "
1255 "%x, %x, %x, %x, %x, %x, %x, %x",
1256 &pal
[ 0], &pal
[ 1], &pal
[ 2], &pal
[ 3],
1257 &pal
[ 4], &pal
[ 5], &pal
[ 6], &pal
[ 7],
1258 &pal
[ 8], &pal
[ 9], &pal
[10], &pal
[11],
1259 &pal
[12], &pal
[13], &pal
[14], &pal
[15]) == 16) {
1260 for (i
=0; i
<16; i
++)
1261 pal
[i
] = vobsub_palette_to_yuv(pal
[i
]);
1262 this->auto_palette
= 0;
1264 if (!strncasecmp(ptr
, "forced subs: on", 15))
1265 this->forced_subs_only
= 1;
1266 if (!strncmp(ptr
, "custom colors: ON, tridx: ", 26) &&
1267 sscanf(ptr
+ 26, "%x, colors: %x, %x, %x, %x",
1268 &tridx
, cuspal
+0, cuspal
+1, cuspal
+2, cuspal
+3) == 5) {
1269 for (i
=0; i
<4; i
++) {
1270 cuspal
[i
] = vobsub_rgb_to_yuv(cuspal
[i
]);
1271 if (tridx
& (1 << (12-4*i
)))
1272 cuspal
[i
] |= 1 << 31;
1276 } while ((ptr
=strchr(ptr
,'\n')) && *++ptr
);
1281 void *spudec_new_scaled(unsigned int *palette
, unsigned int frame_width
, unsigned int frame_height
, uint8_t *extradata
, int extradata_len
)
1283 spudec_handle_t
*this = calloc(1, sizeof(spudec_handle_t
));
1285 this->orig_frame_height
= frame_height
;
1286 this->orig_frame_width
= frame_width
;
1289 memcpy(this->global_palette
, palette
, sizeof(this->global_palette
));
1291 this->auto_palette
= 1;
1293 spudec_parse_extradata(this, extradata
, extradata_len
);
1294 /* XXX Although the video frame is some size, the SPU frame is
1295 always maximum size i.e. 720 wide and 576 or 480 high */
1296 // For HD files in MKV the VobSub resolution can be higher though,
1297 // see largeres_vobsub.mkv
1298 if (this->orig_frame_width
<= 720 && this->orig_frame_height
<= 576) {
1299 this->orig_frame_width
= 720;
1300 if (this->orig_frame_height
== 480 || this->orig_frame_height
== 240)
1301 this->orig_frame_height
= 480;
1303 this->orig_frame_height
= 576;
1307 mp_msg(MSGT_SPUDEC
,MSGL_FATAL
, "FATAL: spudec_init: calloc");
1311 void *spudec_new(unsigned int *palette
)
1313 return spudec_new_scaled(palette
, 0, 0, NULL
, 0);
1316 void spudec_free(void *this)
1318 spudec_handle_t
*spu
= this;
1320 while (spu
->queue_head
)
1321 spudec_free_packet(spudec_dequeue_packet(spu
));
1324 free(spu
->scaled_image
);
1325 spu
->scaled_image
= NULL
;
1329 free(spu
->pal_image
);
1330 spu
->pal_image
= NULL
;
1331 spu
->image_size
= 0;
1332 spu
->pal_width
= spu
->pal_height
= 0;
1337 void spudec_set_hw_spu(void *this, struct vo
*hw_spu
)
1339 spudec_handle_t
*spu
= this;
1342 spu
->hw_spu
= hw_spu
;
1343 vo_control(hw_spu
, VOCTRL_SET_SPU_PALETTE
, spu
->global_palette
);
1347 * palette must contain at least 256 32-bit entries, otherwise crashes
1350 void spudec_set_paletted(void *this, const uint8_t *pal_img
, int pal_stride
,
1351 const void *palette
,
1352 int x
, int y
, int w
, int h
,
1353 double pts
, double endpts
)
1356 uint16_t g8a8_pal
[256];
1358 const uint32_t *pal
= palette
;
1359 spudec_handle_t
*spu
= this;
1362 int stride
= (w
+ 7) & ~7;
1363 if ((unsigned)w
>= 0x8000 || (unsigned)h
> 0x4000)
1365 packet
= calloc(1, sizeof(packet_t
));
1366 packet
->is_decoded
= 1;
1369 packet
->stride
= stride
;
1370 packet
->start_col
= x
;
1371 packet
->start_row
= y
;
1372 packet
->data_len
= 2 * stride
* h
;
1373 if (packet
->data_len
) { // size 0 is a special "clear" packet
1374 packet
->packet
= malloc(packet
->data_len
);
1375 img
= packet
->packet
;
1376 aimg
= packet
->packet
+ stride
* h
;
1377 for (i
= 0; i
< 256; i
++) {
1378 uint32_t pixel
= pal
[i
];
1379 int alpha
= pixel
>> 24;
1380 int gray
= (((pixel
& 0x000000ff) >> 0) +
1381 ((pixel
& 0x0000ff00) >> 7) +
1382 ((pixel
& 0x00ff0000) >> 16)) >> 2;
1383 gray
= FFMIN(gray
, alpha
);
1384 g8a8_pal
[i
] = (-alpha
<< 8) | gray
;
1386 pal2gray_alpha(g8a8_pal
, pal_img
, pal_stride
,
1387 img
, aimg
, stride
, w
, h
);
1389 packet
->start_pts
= 0;
1390 packet
->end_pts
= 0x7fffffff;
1391 if (pts
!= MP_NOPTS_VALUE
)
1392 packet
->start_pts
= pts
* 90000;
1393 if (endpts
!= MP_NOPTS_VALUE
)
1394 packet
->end_pts
= endpts
* 90000;
1395 spudec_queue_packet(spu
, packet
);