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.
40 #include "libvo/video_out.h"
43 #include "libavutil/avutil.h"
44 #include "ffmpeg_files/intreadwrite.h"
45 #include "libswscale/swscale.h"
47 /* Valid values for spu_aamode:
48 0: none (fastest, most ugly)
51 3: bilinear (similiar to vobsub, fast and not too bad)
52 4: uses swscaler gaussian (this is the only one that looks good)
56 int spu_alignment
= -1;
57 float spu_gaussvar
= 1.0;
60 typedef struct packet_t packet_t
;
63 unsigned char *packet
;
65 unsigned int palette
[4];
66 unsigned int alpha
[4];
67 unsigned int control_start
; /* index of start of control data */
68 unsigned int current_nibble
[2]; /* next data nibble (4 bits) to be
69 processed (for RLE decoding) for
71 int deinterlace_oddness
; /* 0 or 1, index into current_nibble */
72 unsigned int start_col
;
73 unsigned int start_row
;
74 unsigned int width
, height
, stride
;
75 unsigned int start_pts
, end_pts
;
79 struct palette_crop_cache
{
89 unsigned int global_palette
[16];
90 unsigned int orig_frame_width
, orig_frame_height
;
91 unsigned char* packet
;
92 size_t packet_reserve
; /* size of the memory pointed to by packet */
93 unsigned int packet_offset
; /* end of the currently assembled fragment */
94 unsigned int packet_size
; /* size of the packet once all fragments are assembled */
95 int packet_pts
; /* PTS for this packet */
96 unsigned int palette
[4];
97 unsigned int alpha
[4];
98 unsigned int cuspal
[4];
100 unsigned int now_pts
;
101 unsigned int start_pts
, end_pts
;
102 unsigned int start_col
;
103 unsigned int start_row
;
104 unsigned int width
, height
, stride
;
105 size_t image_size
; /* Size of the image buffer */
106 unsigned char *image
; /* Grayscale value */
107 unsigned char *aimage
; /* Alpha value */
108 unsigned int pal_start_col
, pal_start_row
;
109 unsigned int pal_width
, pal_height
;
110 unsigned char *pal_image
; /* palette entry value */
111 unsigned int scaled_frame_width
, scaled_frame_height
;
112 unsigned int scaled_start_col
, scaled_start_row
;
113 unsigned int scaled_width
, scaled_height
, scaled_stride
;
114 size_t scaled_image_size
;
115 unsigned char *scaled_image
;
116 unsigned char *scaled_aimage
;
117 int auto_palette
; /* 1 if we lack a palette and must use an heuristic. */
118 int font_start_level
; /* Darkest value used for the computed font */
121 unsigned int forced_subs_only
; /* flag: 0=display all subtitle, !0 display only forced subtitles */
122 unsigned int is_forced_sub
; /* true if current subtitle is a forced subtitle */
124 struct palette_crop_cache palette_crop_cache
;
127 static void spudec_queue_packet(spudec_handle_t
*this, packet_t
*packet
)
129 if (this->queue_head
== NULL
)
130 this->queue_head
= packet
;
132 this->queue_tail
->next
= packet
;
133 this->queue_tail
= packet
;
136 static packet_t
*spudec_dequeue_packet(spudec_handle_t
*this)
138 packet_t
*retval
= this->queue_head
;
140 this->queue_head
= retval
->next
;
141 if (this->queue_head
== NULL
)
142 this->queue_tail
= NULL
;
147 static void spudec_free_packet(packet_t
*packet
)
149 free(packet
->packet
);
153 static inline unsigned int get_be16(const unsigned char *p
)
155 return (p
[0] << 8) + p
[1];
158 static inline unsigned int get_be24(const unsigned char *p
)
160 return (get_be16(p
) << 8) + p
[2];
163 static void next_line(packet_t
*packet
)
165 if (packet
->current_nibble
[packet
->deinterlace_oddness
] % 2)
166 packet
->current_nibble
[packet
->deinterlace_oddness
]++;
167 packet
->deinterlace_oddness
= (packet
->deinterlace_oddness
+ 1) % 2;
170 static inline unsigned char get_nibble(packet_t
*packet
)
173 unsigned int *nibblep
= packet
->current_nibble
+ packet
->deinterlace_oddness
;
174 if (*nibblep
/ 2 >= packet
->control_start
) {
175 mp_msg(MSGT_SPUDEC
,MSGL_WARN
, "SPUdec: ERROR: get_nibble past end of packet\n");
178 nib
= packet
->packet
[*nibblep
/ 2];
187 /* Cut the sub to visible part */
188 static inline void spudec_cut_image(spudec_handle_t
*this)
191 unsigned int first_y
, last_y
;
193 if (this->stride
== 0 || this->height
== 0) {
197 for (fy
= 0; fy
< this->image_size
&& !this->aimage
[fy
]; fy
++);
198 for (ly
= this->stride
* this->height
-1; ly
&& !this->aimage
[ly
]; ly
--);
199 first_y
= fy
/ this->stride
;
200 last_y
= ly
/ this->stride
;
201 //printf("first_y: %d, last_y: %d\n", first_y, last_y);
202 this->start_row
+= first_y
;
204 // Some subtitles trigger this condition
205 if (last_y
+ 1 > first_y
) {
206 this->height
= last_y
- first_y
+1;
212 // printf("new h %d new start %d (sz %d st %d)---\n\n", this->height, this->start_row, this->image_size, this->stride);
215 memmove(this->image
, this->image
+ this->stride
* first_y
, this->stride
* this->height
);
216 memmove(this->aimage
, this->aimage
+ this->stride
* first_y
, this->stride
* this->height
);
221 static int spudec_alloc_image(spudec_handle_t
*this, int stride
, int height
)
223 if (this->width
> stride
) // just a safeguard
224 this->width
= stride
;
225 this->stride
= stride
;
226 this->height
= height
;
227 if (this->image_size
< this->stride
* this->height
) {
228 if (this->image
!= NULL
) {
230 free(this->pal_image
);
231 this->image_size
= 0;
232 this->pal_width
= this->pal_height
= 0;
234 this->image
= malloc(2 * this->stride
* this->height
);
236 this->image_size
= this->stride
* this->height
;
237 this->aimage
= this->image
+ this->image_size
;
238 // use stride here as well to simplify reallocation checks
239 this->pal_image
= malloc(this->stride
* this->height
);
242 return this->image
!= NULL
;
246 * \param pal palette in MPlayer-style gray-alpha values, i.e.
247 * alpha == 0 means transparent, 1 fully opaque,
248 * gray value <= 256 - alpha.
250 static void pal2gray_alpha(const uint16_t *pal
,
251 const uint8_t *src
, int src_stride
,
252 uint8_t *dst
, uint8_t *dsta
,
253 int dst_stride
, int w
, int h
)
256 for (y
= 0; y
< h
; y
++) {
257 for (x
= 0; x
< w
; x
++) {
258 uint16_t pixel
= pal
[src
[x
]];
260 *dsta
++ = pixel
>> 8;
262 for (; x
< dst_stride
; x
++)
263 *dsta
++ = *dst
++ = 0;
268 static int apply_palette_crop(spudec_handle_t
*this,
269 unsigned crop_x
, unsigned crop_y
,
270 unsigned crop_w
, unsigned crop_h
)
275 unsigned stride
= (crop_w
+ 7) & ~7;
276 if (crop_x
> this->pal_width
|| crop_y
> this->pal_height
||
277 crop_w
> this->pal_width
- crop_x
|| crop_h
> this->pal_width
- crop_y
||
278 crop_w
> 0x8000 || crop_h
> 0x8000 ||
279 stride
* crop_h
> this->image_size
) {
282 for (i
= 0; i
< 4; ++i
) {
284 int alpha
= this->alpha
[i
];
287 if (this->custom
&& (this->cuspal
[i
] >> 31) != 0)
289 color
= this->custom
? this->cuspal
[i
] :
290 this->global_palette
[this->palette
[i
]];
291 color
= (color
>> 16) & 0xff;
292 // convert to MPlayer-style gray/alpha palette
293 color
= FFMIN(color
, alpha
);
294 pal
[i
] = (-alpha
<< 8) | color
;
296 src
= this->pal_image
+ crop_y
* this->pal_width
+ crop_x
;
297 pal2gray_alpha(pal
, src
, this->pal_width
,
298 this->image
, this->aimage
, stride
,
300 this->width
= crop_w
;
301 this->height
= crop_h
;
302 this->stride
= stride
;
303 this->start_col
= this->pal_start_col
+ crop_x
;
304 this->start_row
= this->pal_start_row
+ crop_y
;
305 spudec_cut_image(this);
307 // reset scaled image
308 this->scaled_frame_width
= 0;
309 this->scaled_frame_height
= 0;
310 this->palette_crop_cache
.valid
= 0;
314 int spudec_apply_palette_crop(void *this, uint32_t palette
,
315 int sx
, int sy
, int ex
, int ey
)
317 spudec_handle_t
*spu
= this;
318 struct palette_crop_cache
*c
= &spu
->palette_crop_cache
;
319 if (c
->valid
&& c
->palette
== palette
&&
320 c
->sx
== sx
&& c
->sy
== sy
&& c
->ex
== ex
&& c
->ey
== ey
)
322 spu
->palette
[0] = (palette
>> 28) & 0xf;
323 spu
->palette
[1] = (palette
>> 24) & 0xf;
324 spu
->palette
[2] = (palette
>> 20) & 0xf;
325 spu
->palette
[3] = (palette
>> 16) & 0xf;
326 spu
->alpha
[0] = (palette
>> 12) & 0xf;
327 spu
->alpha
[1] = (palette
>> 8) & 0xf;
328 spu
->alpha
[2] = (palette
>> 4) & 0xf;
329 spu
->alpha
[3] = palette
& 0xf;
330 spu
->spu_changed
= 1;
331 c
->result
= apply_palette_crop(spu
,
332 sx
- spu
->pal_start_col
, sy
- spu
->pal_start_row
,
334 c
->palette
= palette
;
335 c
->sx
= sx
; c
->sy
= sy
;
336 c
->ex
= ex
; c
->ey
= ey
;
341 static void spudec_process_data(spudec_handle_t
*this, packet_t
*packet
)
343 unsigned int i
, x
, y
;
346 if (!spudec_alloc_image(this, packet
->stride
, packet
->height
))
349 this->pal_start_col
= packet
->start_col
;
350 this->pal_start_row
= packet
->start_row
;
351 this->pal_height
= packet
->height
;
352 this->pal_width
= packet
->width
;
353 this->stride
= packet
->stride
;
354 memcpy(this->palette
, packet
->palette
, sizeof(this->palette
));
355 memcpy(this->alpha
, packet
->alpha
, sizeof(this->alpha
));
357 i
= packet
->current_nibble
[1];
360 dst
= this->pal_image
;
361 while (packet
->current_nibble
[0] < i
362 && packet
->current_nibble
[1] / 2 < packet
->control_start
363 && y
< this->pal_height
) {
364 unsigned int len
, color
;
365 unsigned int rle
= 0;
366 rle
= get_nibble(packet
);
369 rle
= (rle
<< 4) | get_nibble(packet
);
371 rle
= (rle
<< 4) | get_nibble(packet
);
373 rle
= (rle
<< 4) | get_nibble(packet
);
375 color
= 3 - (rle
& 0x3);
378 if (len
== 0 || x
>= this->pal_width
) {
379 len
+= this->pal_width
- x
;
384 memset(dst
, color
, len
);
387 apply_palette_crop(this, 0, 0, this->pal_width
, this->pal_height
);
392 This function tries to create a usable palette.
393 It determines how many non-transparent colors are used, and assigns different
394 gray scale values to each color.
395 I tested it with four streams and even got something readable. Half of the
396 times I got black characters with white around and half the reverse.
398 static void compute_palette(spudec_handle_t
*this, packet_t
*packet
)
400 int used
[16],i
,cused
,start
,step
,color
;
402 memset(used
, 0, sizeof(used
));
404 if (packet
->alpha
[i
]) /* !Transparent? */
405 used
[packet
->palette
[i
]] = 1;
406 for (cused
=0, i
=0; i
<16; i
++)
407 if (used
[i
]) cused
++;
413 start
= this->font_start_level
;
414 step
= (0xF0-this->font_start_level
)/(cused
-1);
416 memset(used
, 0, sizeof(used
));
417 for (i
=0; i
<4; i
++) {
418 color
= packet
->palette
[i
];
419 if (packet
->alpha
[i
] && !used
[color
]) { /* not assigned? */
421 this->global_palette
[color
] = start
<<16;
427 static void spudec_process_control(spudec_handle_t
*this, int pts100
)
429 int a
,b
,c
,d
; /* Temporary vars */
430 unsigned int date
, type
;
432 unsigned int start_off
= 0;
433 unsigned int next_off
;
434 unsigned int start_pts
= 0;
435 unsigned int end_pts
= 0;
436 unsigned int current_nibble
[2] = {0, 0};
437 unsigned int control_start
;
438 unsigned int display
= 0;
439 unsigned int start_col
= 0;
440 unsigned int end_col
= 0;
441 unsigned int start_row
= 0;
442 unsigned int end_row
= 0;
443 unsigned int width
= 0;
444 unsigned int height
= 0;
445 unsigned int stride
= 0;
447 control_start
= get_be16(this->packet
+ 2);
448 next_off
= control_start
;
449 while (start_off
!= next_off
) {
450 start_off
= next_off
;
451 date
= get_be16(this->packet
+ start_off
) * 1024;
452 next_off
= get_be16(this->packet
+ start_off
+ 2);
453 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
, "date=%d\n", date
);
455 for (type
= this->packet
[off
++]; type
!= 0xff; type
= this->packet
[off
++]) {
456 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
, "cmd=%d ",type
);
459 /* Menu ID, 1 byte */
460 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Menu ID\n");
461 /* shouldn't a Menu ID type force display start? */
462 start_pts
= pts100
< 0 && -pts100
>= date
? 0 : pts100
+ date
;
465 this->is_forced_sub
=~0; // current subtitle is forced
469 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Start display!\n");
470 start_pts
= pts100
< 0 && -pts100
>= date
? 0 : pts100
+ date
;
473 this->is_forced_sub
=0;
477 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Stop display!\n");
478 end_pts
= pts100
< 0 && -pts100
>= date
? 0 : pts100
+ date
;
482 this->palette
[0] = this->packet
[off
] >> 4;
483 this->palette
[1] = this->packet
[off
] & 0xf;
484 this->palette
[2] = this->packet
[off
+ 1] >> 4;
485 this->palette
[3] = this->packet
[off
+ 1] & 0xf;
486 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Palette %d, %d, %d, %d\n",
487 this->palette
[0], this->palette
[1], this->palette
[2], this->palette
[3]);
492 a
= this->packet
[off
] >> 4;
493 b
= this->packet
[off
] & 0xf;
494 c
= this->packet
[off
+ 1] >> 4;
495 d
= this->packet
[off
+ 1] & 0xf;
496 // Note: some DVDs change these values to create a fade-in/fade-out effect
497 // We can not handle this, so just keep the highest value during the display time.
499 a
= FFMAX(a
, this->alpha
[0]);
500 b
= FFMAX(b
, this->alpha
[1]);
501 c
= FFMAX(c
, this->alpha
[2]);
502 d
= FFMAX(d
, this->alpha
[3]);
508 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Alpha %d, %d, %d, %d\n",
509 this->alpha
[0], this->alpha
[1], this->alpha
[2], this->alpha
[3]);
514 a
= get_be24(this->packet
+ off
);
515 b
= get_be24(this->packet
+ off
+ 3);
518 width
= (end_col
< start_col
) ? 0 : end_col
- start_col
+ 1;
519 stride
= (width
+ 7) & ~7; /* Kludge: draw_alpha needs width multiple of 8 */
522 height
= (end_row
< start_row
) ? 0 : end_row
- start_row
/* + 1 */;
523 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Coords col: %d - %d row: %d - %d (%dx%d)\n",
524 start_col
, end_col
, start_row
, end_row
,
530 current_nibble
[0] = 2 * get_be16(this->packet
+ off
);
531 current_nibble
[1] = 2 * get_be16(this->packet
+ off
+ 2);
532 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Graphic offset 1: %d offset 2: %d\n",
533 current_nibble
[0] / 2, current_nibble
[1] / 2);
537 /* All done, bye-bye */
538 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Done!\n");
542 mp_msg(MSGT_SPUDEC
,MSGL_WARN
,"spudec: Error determining control type 0x%02x. Skipping %d bytes.\n",
543 type
, next_off
- off
);
550 if (end_pts
== UINT_MAX
&& start_off
!= next_off
) {
551 end_pts
= get_be16(this->packet
+ next_off
) * 1024;
552 end_pts
= 1 - pts100
>= end_pts
? 0 : pts100
+ end_pts
- 1;
555 packet_t
*packet
= calloc(1, sizeof(packet_t
));
557 packet
->start_pts
= start_pts
;
558 packet
->end_pts
= end_pts
;
559 packet
->current_nibble
[0] = current_nibble
[0];
560 packet
->current_nibble
[1] = current_nibble
[1];
561 packet
->start_row
= start_row
;
562 packet
->start_col
= start_col
;
563 packet
->width
= width
;
564 packet
->height
= height
;
565 packet
->stride
= stride
;
566 packet
->control_start
= control_start
;
567 for (i
=0; i
<4; i
++) {
568 packet
->alpha
[i
] = this->alpha
[i
];
569 packet
->palette
[i
] = this->palette
[i
];
571 packet
->packet
= malloc(this->packet_size
);
572 memcpy(packet
->packet
, this->packet
, this->packet_size
);
573 spudec_queue_packet(this, packet
);
578 static void spudec_decode(spudec_handle_t
*this, int pts100
)
581 spudec_process_control(this, pts100
);
582 else if (pts100
>= 0) {
583 static vo_mpegpes_t packet
= { NULL
, 0, 0x20, 0 };
584 static vo_mpegpes_t
*pkg
=&packet
;
585 packet
.data
= this->packet
;
586 packet
.size
= this->packet_size
;
587 packet
.timestamp
= pts100
;
588 vo_draw_frame(this->hw_spu
, (uint8_t**)&pkg
);
592 int spudec_changed(void * this)
594 spudec_handle_t
* spu
= this;
595 return spu
->spu_changed
|| spu
->now_pts
> spu
->end_pts
;
598 void spudec_assemble(void *this, unsigned char *packet
, unsigned int len
, int pts100
)
600 spudec_handle_t
*spu
= this;
601 // spudec_heartbeat(this, pts100);
603 mp_msg(MSGT_SPUDEC
,MSGL_WARN
,"SPUasm: packet too short\n");
606 spu
->packet_pts
= pts100
;
607 if (spu
->packet_offset
== 0) {
608 unsigned int len2
= get_be16(packet
);
609 // Start new fragment
610 if (spu
->packet_reserve
< len2
) {
612 spu
->packet
= malloc(len2
);
613 spu
->packet_reserve
= spu
->packet
!= NULL
? len2
: 0;
615 if (spu
->packet
!= NULL
) {
616 spu
->packet_size
= len2
;
618 mp_msg(MSGT_SPUDEC
,MSGL_WARN
,"SPUasm: invalid frag len / len2: %d / %d \n", len
, len2
);
621 memcpy(spu
->packet
, packet
, len
);
622 spu
->packet_offset
= len
;
623 spu
->packet_pts
= pts100
;
626 // Continue current fragment
627 if (spu
->packet_size
< spu
->packet_offset
+ len
){
628 mp_msg(MSGT_SPUDEC
,MSGL_WARN
,"SPUasm: invalid fragment\n");
629 spu
->packet_size
= spu
->packet_offset
= 0;
632 memcpy(spu
->packet
+ spu
->packet_offset
, packet
, len
);
633 spu
->packet_offset
+= len
;
637 // check if we have a complete packet (unfortunatelly packet_size is bad
639 // [cb] packet_size is padded to be even -> may be one byte too long
640 if ((spu
->packet_offset
== spu
->packet_size
) ||
641 ((spu
->packet_offset
+ 1) == spu
->packet_size
)){
643 while(x
+4<=spu
->packet_offset
){
644 y
=get_be16(spu
->packet
+x
+2); // next control pointer
645 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"SPUtest: x=%d y=%d off=%d size=%d\n",x
,y
,spu
->packet_offset
,spu
->packet_size
);
646 if(x
>=4 && x
==y
){ // if it points to self - we're done!
648 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"SPUgot: off=%d size=%d \n",spu
->packet_offset
,spu
->packet_size
);
649 spudec_decode(spu
, pts100
);
650 spu
->packet_offset
= 0;
653 if(y
<=x
|| y
>=spu
->packet_size
){ // invalid?
654 mp_msg(MSGT_SPUDEC
,MSGL_WARN
,"SPUtest: broken packet!!!!! y=%d < x=%d\n",y
,x
);
655 spu
->packet_size
= spu
->packet_offset
= 0;
660 // [cb] packet is done; start new packet
661 spu
->packet_offset
= 0;
664 if (spu
->packet_offset
== spu
->packet_size
) {
665 spudec_decode(spu
, pts100
);
666 spu
->packet_offset
= 0;
671 void spudec_reset(void *this) // called after seek
673 spudec_handle_t
*spu
= this;
674 while (spu
->queue_head
)
675 spudec_free_packet(spudec_dequeue_packet(spu
));
678 spu
->packet_size
= spu
->packet_offset
= 0;
681 void spudec_heartbeat(void *this, unsigned int pts100
)
683 spudec_handle_t
*spu
= this;
684 spu
->now_pts
= pts100
;
686 // TODO: detect and handle broken timestamps (e.g. due to wrapping)
687 while (spu
->queue_head
!= NULL
&& pts100
>= spu
->queue_head
->start_pts
) {
688 packet_t
*packet
= spudec_dequeue_packet(spu
);
689 spu
->start_pts
= packet
->start_pts
;
690 spu
->end_pts
= packet
->end_pts
;
691 if (packet
->is_decoded
) {
693 spu
->image_size
= packet
->data_len
;
694 spu
->image
= packet
->packet
;
695 spu
->aimage
= packet
->packet
+ packet
->stride
* packet
->height
;
696 packet
->packet
= NULL
;
697 spu
->width
= packet
->width
;
698 spu
->height
= packet
->height
;
699 spu
->stride
= packet
->stride
;
700 spu
->start_col
= packet
->start_col
;
701 spu
->start_row
= packet
->start_row
;
703 // reset scaled image
704 spu
->scaled_frame_width
= 0;
705 spu
->scaled_frame_height
= 0;
707 if (spu
->auto_palette
)
708 compute_palette(spu
, packet
);
709 spudec_process_data(spu
, packet
);
711 spudec_free_packet(packet
);
712 spu
->spu_changed
= 1;
716 int spudec_visible(void *this){
717 spudec_handle_t
*spu
= this;
718 int ret
=(spu
->start_pts
<= spu
->now_pts
&&
719 spu
->now_pts
< spu
->end_pts
&&
721 // printf("spu visible: %d \n",ret);
725 void spudec_set_forced_subs_only(void * const this, const unsigned int flag
)
728 ((spudec_handle_t
*)this)->forced_subs_only
=flag
;
729 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"SPU: Display only forced subs now %s\n", flag
? "enabled": "disabled");
733 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
)
735 spudec_handle_t
*spu
= this;
736 if (spudec_visible(spu
))
738 draw_alpha(ctx
, spu
->start_col
, spu
->start_row
, spu
->width
, spu
->height
,
739 spu
->image
, spu
->aimage
, spu
->stride
);
740 spu
->spu_changed
= 0;
744 /* calc the bbox for spudec subs */
745 void spudec_calc_bbox(void *me
, unsigned int dxs
, unsigned int dys
, unsigned int* bbox
)
747 spudec_handle_t
*spu
= me
;
748 if (spu
->orig_frame_width
== 0 || spu
->orig_frame_height
== 0
749 || (spu
->orig_frame_width
== dxs
&& spu
->orig_frame_height
== dys
)) {
751 bbox
[0] = spu
->start_col
;
752 bbox
[1] = spu
->start_col
+ spu
->width
;
753 bbox
[2] = spu
->start_row
;
754 bbox
[3] = spu
->start_row
+ spu
->height
;
758 unsigned int scalex
= 0x100 * dxs
/ spu
->orig_frame_width
;
759 unsigned int scaley
= 0x100 * dys
/ spu
->orig_frame_height
;
760 bbox
[0] = spu
->start_col
* scalex
/ 0x100;
761 bbox
[1] = spu
->start_col
* scalex
/ 0x100 + spu
->width
* scalex
/ 0x100;
762 switch (spu_alignment
) {
764 bbox
[3] = dys
*sub_pos
/100 + spu
->height
* scaley
/ 0x100;
765 if (bbox
[3] > dys
) bbox
[3] = dys
;
766 bbox
[2] = bbox
[3] - spu
->height
* scaley
/ 0x100;
770 bbox
[2] = dys
*sub_pos
/100 - spu
->height
* scaley
/ 0x200;
771 bbox
[3] = bbox
[2] + spu
->height
;
773 bbox
[3] = dys
*sub_pos
/100 + spu
->height
* scaley
/ 0x200;
774 if (bbox
[3] > dys
) bbox
[3] = dys
;
775 bbox
[2] = bbox
[3] - spu
->height
* scaley
/ 0x100;
779 bbox
[2] = dys
*sub_pos
/100 - spu
->height
* scaley
/ 0x100;
780 bbox
[3] = bbox
[2] + spu
->height
;
783 bbox
[2] = spu
->start_row
* scaley
/ 0x100;
784 bbox
[3] = spu
->start_row
* scaley
/ 0x100 + spu
->height
* scaley
/ 0x100;
789 /* transform mplayer's alpha value into an opacity value that is linear */
790 static inline int canon_alpha(int alpha
)
792 return (uint8_t)-alpha
;
802 static void scale_table(unsigned int start_src
, unsigned int start_tar
, unsigned int end_src
, unsigned int end_tar
, scale_pixel
* table
)
805 unsigned int delta_src
= end_src
- start_src
;
806 unsigned int delta_tar
= end_tar
- start_tar
;
809 if (delta_src
== 0 || delta_tar
== 0) {
812 src_step
= (delta_src
<< 16) / delta_tar
>>1;
813 for (t
= 0; t
<=delta_tar
; src
+= (src_step
<< 1), t
++){
814 table
[t
].position
= FFMIN(src
>> 16, end_src
- 1);
815 table
[t
].right_down
= src
& 0xffff;
816 table
[t
].left_up
= 0x10000 - table
[t
].right_down
;
820 /* bilinear scale, similar to vobsub's code */
821 static void scale_image(int x
, int y
, scale_pixel
* table_x
, scale_pixel
* table_y
, spudec_handle_t
* spu
)
825 unsigned int scale
[4];
826 int base
= table_y
[y
].position
* spu
->stride
+ table_x
[x
].position
;
827 int scaled
= y
* spu
->scaled_stride
+ x
;
828 alpha
[0] = canon_alpha(spu
->aimage
[base
]);
829 alpha
[1] = canon_alpha(spu
->aimage
[base
+ 1]);
830 alpha
[2] = canon_alpha(spu
->aimage
[base
+ spu
->stride
]);
831 alpha
[3] = canon_alpha(spu
->aimage
[base
+ spu
->stride
+ 1]);
832 color
[0] = spu
->image
[base
];
833 color
[1] = spu
->image
[base
+ 1];
834 color
[2] = spu
->image
[base
+ spu
->stride
];
835 color
[3] = spu
->image
[base
+ spu
->stride
+ 1];
836 scale
[0] = (table_x
[x
].left_up
* table_y
[y
].left_up
>> 16) * alpha
[0];
837 if (table_y
[y
].left_up
== 0x10000) // necessary to avoid overflow-case
838 scale
[0] = table_x
[x
].left_up
* alpha
[0];
839 scale
[1] = (table_x
[x
].right_down
* table_y
[y
].left_up
>>16) * alpha
[1];
840 scale
[2] = (table_x
[x
].left_up
* table_y
[y
].right_down
>> 16) * alpha
[2];
841 scale
[3] = (table_x
[x
].right_down
* table_y
[y
].right_down
>> 16) * alpha
[3];
842 spu
->scaled_image
[scaled
] = (color
[0] * scale
[0] + color
[1] * scale
[1] + color
[2] * scale
[2] + color
[3] * scale
[3])>>24;
843 spu
->scaled_aimage
[scaled
] = (scale
[0] + scale
[1] + scale
[2] + scale
[3]) >> 16;
844 if (spu
->scaled_aimage
[scaled
]){
845 // ensure that MPlayer's simplified alpha-blending can not overflow
846 spu
->scaled_image
[scaled
] = FFMIN(spu
->scaled_image
[scaled
], spu
->scaled_aimage
[scaled
]);
847 // convert to MPlayer-style alpha
848 spu
->scaled_aimage
[scaled
] = -spu
->scaled_aimage
[scaled
];
852 static void sws_spu_image(unsigned char *d1
, unsigned char *d2
, int dw
, int dh
,
853 int ds
, const unsigned char* s1
, unsigned char* s2
,
854 int sw
, int sh
, int ss
)
856 struct SwsContext
*ctx
;
857 static SwsFilter filter
;
858 static int firsttime
= 1;
862 if (!firsttime
&& oldvar
!= spu_gaussvar
) sws_freeVec(filter
.lumH
);
864 filter
.lumH
= filter
.lumV
=
865 filter
.chrH
= filter
.chrV
= sws_getGaussianVec(spu_gaussvar
, 3.0);
866 sws_normalizeVec(filter
.lumH
, 1.0);
868 oldvar
= spu_gaussvar
;
871 ctx
=sws_getContext(sw
, sh
, PIX_FMT_GRAY8
, dw
, dh
, PIX_FMT_GRAY8
, SWS_GAUSS
, &filter
, NULL
, NULL
);
872 sws_scale(ctx
,&s1
,&ss
,0,sh
,&d1
,&ds
);
873 for (i
=ss
*sh
-1; i
>=0; i
--) if (!s2
[i
]) s2
[i
] = 255; //else s2[i] = 1;
874 sws_scale(ctx
,&s2
,&ss
,0,sh
,&d2
,&ds
);
875 for (i
=ds
*dh
-1; i
>=0; i
--) if (d2
[i
]==0) d2
[i
] = 1; else if (d2
[i
]==255) d2
[i
] = 0;
876 sws_freeContext(ctx
);
879 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
)
881 spudec_handle_t
*spu
= me
;
882 scale_pixel
*table_x
;
883 scale_pixel
*table_y
;
885 if (spudec_visible(spu
)) {
887 // check if only forced subtitles are requested
888 if( (spu
->forced_subs_only
) && !(spu
->is_forced_sub
) ){
892 if (!(spu_aamode
&16) && (spu
->orig_frame_width
== 0 || spu
->orig_frame_height
== 0
893 || (spu
->orig_frame_width
== dxs
&& spu
->orig_frame_height
== dys
))) {
894 spudec_draw(spu
, draw_alpha
, ctx
);
897 if (spu
->scaled_frame_width
!= dxs
|| spu
->scaled_frame_height
!= dys
) { /* Resizing is needed */
898 /* scaled_x = scalex * x / 0x100
899 scaled_y = scaley * y / 0x100
900 order of operations is important because of rounding. */
901 unsigned int scalex
= 0x100 * dxs
/ spu
->orig_frame_width
;
902 unsigned int scaley
= 0x100 * dys
/ spu
->orig_frame_height
;
903 spu
->scaled_start_col
= spu
->start_col
* scalex
/ 0x100;
904 spu
->scaled_start_row
= spu
->start_row
* scaley
/ 0x100;
905 spu
->scaled_width
= spu
->width
* scalex
/ 0x100;
906 spu
->scaled_height
= spu
->height
* scaley
/ 0x100;
907 /* Kludge: draw_alpha needs width multiple of 8 */
908 spu
->scaled_stride
= (spu
->scaled_width
+ 7) & ~7;
909 if (spu
->scaled_image_size
< spu
->scaled_stride
* spu
->scaled_height
) {
910 if (spu
->scaled_image
) {
911 free(spu
->scaled_image
);
912 spu
->scaled_image_size
= 0;
914 spu
->scaled_image
= malloc(2 * spu
->scaled_stride
* spu
->scaled_height
);
915 if (spu
->scaled_image
) {
916 spu
->scaled_image_size
= spu
->scaled_stride
* spu
->scaled_height
;
917 spu
->scaled_aimage
= spu
->scaled_image
+ spu
->scaled_image_size
;
920 if (spu
->scaled_image
) {
922 if (spu
->scaled_width
<= 1 || spu
->scaled_height
<= 1) {
925 switch(spu_aamode
&15) {
927 sws_spu_image(spu
->scaled_image
, spu
->scaled_aimage
,
928 spu
->scaled_width
, spu
->scaled_height
, spu
->scaled_stride
,
929 spu
->image
, spu
->aimage
, spu
->width
, spu
->height
, spu
->stride
);
932 table_x
= calloc(spu
->scaled_width
, sizeof(scale_pixel
));
933 table_y
= calloc(spu
->scaled_height
, sizeof(scale_pixel
));
934 if (!table_x
|| !table_y
) {
935 mp_msg(MSGT_SPUDEC
, MSGL_FATAL
, "Fatal: spudec_draw_scaled: calloc failed\n");
937 scale_table(0, 0, spu
->width
- 1, spu
->scaled_width
- 1, table_x
);
938 scale_table(0, 0, spu
->height
- 1, spu
->scaled_height
- 1, table_y
);
939 for (y
= 0; y
< spu
->scaled_height
; y
++)
940 for (x
= 0; x
< spu
->scaled_width
; x
++)
941 scale_image(x
, y
, table_x
, table_y
, spu
);
946 /* no antialiasing */
947 for (y
= 0; y
< spu
->scaled_height
; ++y
) {
948 int unscaled_y
= y
* 0x100 / scaley
;
949 int strides
= spu
->stride
* unscaled_y
;
950 int scaled_strides
= spu
->scaled_stride
* y
;
951 for (x
= 0; x
< spu
->scaled_width
; ++x
) {
952 int unscaled_x
= x
* 0x100 / scalex
;
953 spu
->scaled_image
[scaled_strides
+ x
] = spu
->image
[strides
+ unscaled_x
];
954 spu
->scaled_aimage
[scaled_strides
+ x
] = spu
->aimage
[strides
+ unscaled_x
];
960 /* Intermediate antialiasing. */
961 for (y
= 0; y
< spu
->scaled_height
; ++y
) {
962 const unsigned int unscaled_top
= y
* spu
->orig_frame_height
/ dys
;
963 unsigned int unscaled_bottom
= (y
+ 1) * spu
->orig_frame_height
/ dys
;
964 if (unscaled_bottom
>= spu
->height
)
965 unscaled_bottom
= spu
->height
- 1;
966 for (x
= 0; x
< spu
->scaled_width
; ++x
) {
967 const unsigned int unscaled_left
= x
* spu
->orig_frame_width
/ dxs
;
968 unsigned int unscaled_right
= (x
+ 1) * spu
->orig_frame_width
/ dxs
;
969 unsigned int color
= 0;
970 unsigned int alpha
= 0;
971 unsigned int walkx
, walky
;
972 unsigned int base
, tmp
;
973 if (unscaled_right
>= spu
->width
)
974 unscaled_right
= spu
->width
- 1;
975 for (walky
= unscaled_top
; walky
<= unscaled_bottom
; ++walky
)
976 for (walkx
= unscaled_left
; walkx
<= unscaled_right
; ++walkx
) {
977 base
= walky
* spu
->stride
+ walkx
;
978 tmp
= canon_alpha(spu
->aimage
[base
]);
980 color
+= tmp
* spu
->image
[base
];
982 base
= y
* spu
->scaled_stride
+ x
;
983 spu
->scaled_image
[base
] = alpha
? color
/ alpha
: 0;
984 spu
->scaled_aimage
[base
] =
985 alpha
* (1 + unscaled_bottom
- unscaled_top
) * (1 + unscaled_right
- unscaled_left
);
986 /* spu->scaled_aimage[base] =
987 alpha * dxs * dys / spu->orig_frame_width / spu->orig_frame_height; */
988 if (spu
->scaled_aimage
[base
]) {
989 spu
->scaled_aimage
[base
] = 256 - spu
->scaled_aimage
[base
];
990 if (spu
->scaled_aimage
[base
] + spu
->scaled_image
[base
] > 255)
991 spu
->scaled_image
[base
] = 256 - spu
->scaled_aimage
[base
];
999 /* Best antialiasing. Very slow. */
1000 /* Any pixel (x, y) represents pixels from the original
1001 rectangular region comprised between the columns
1002 unscaled_y and unscaled_y + 0x100 / scaley and the rows
1003 unscaled_x and unscaled_x + 0x100 / scalex
1005 The original rectangular region that the scaled pixel
1006 represents is cut in 9 rectangular areas like this:
1008 +---+-----------------+---+
1010 +---+-----------------+---+
1014 +---+-----------------+---+
1016 +---+-----------------+---+
1018 The width of the left column is at most one pixel and
1019 it is never null and its right column is at a pixel
1020 boundary. The height of the top row is at most one
1021 pixel it is never null and its bottom row is at a
1022 pixel boundary. The width and height of region 5 are
1023 integral values. The width of the right column is
1024 what remains and is less than one pixel. The height
1025 of the bottom row is what remains and is less than
1028 The row above 1, 2, 3 is unscaled_y. The row between
1029 1, 2, 3 and 4, 5, 6 is top_low_row. The row between 4,
1030 5, 6 and 7, 8, 9 is (unsigned int)unscaled_y_bottom.
1031 The row beneath 7, 8, 9 is unscaled_y_bottom.
1033 The column left of 1, 4, 7 is unscaled_x. The column
1034 between 1, 4, 7 and 2, 5, 8 is left_right_column. The
1035 column between 2, 5, 8 and 3, 6, 9 is (unsigned
1036 int)unscaled_x_right. The column right of 3, 6, 9 is
1037 unscaled_x_right. */
1038 const double inv_scalex
= (double) 0x100 / scalex
;
1039 const double inv_scaley
= (double) 0x100 / scaley
;
1040 for (y
= 0; y
< spu
->scaled_height
; ++y
) {
1041 const double unscaled_y
= y
* inv_scaley
;
1042 const double unscaled_y_bottom
= unscaled_y
+ inv_scaley
;
1043 const unsigned int top_low_row
= FFMIN(unscaled_y_bottom
, unscaled_y
+ 1.0);
1044 const double top
= top_low_row
- unscaled_y
;
1045 const unsigned int height
= unscaled_y_bottom
> top_low_row
1046 ? (unsigned int) unscaled_y_bottom
- top_low_row
1048 const double bottom
= unscaled_y_bottom
> top_low_row
1049 ? unscaled_y_bottom
- floor(unscaled_y_bottom
)
1051 for (x
= 0; x
< spu
->scaled_width
; ++x
) {
1052 const double unscaled_x
= x
* inv_scalex
;
1053 const double unscaled_x_right
= unscaled_x
+ inv_scalex
;
1054 const unsigned int left_right_column
= FFMIN(unscaled_x_right
, unscaled_x
+ 1.0);
1055 const double left
= left_right_column
- unscaled_x
;
1056 const unsigned int width
= unscaled_x_right
> left_right_column
1057 ? (unsigned int) unscaled_x_right
- left_right_column
1059 const double right
= unscaled_x_right
> left_right_column
1060 ? unscaled_x_right
- floor(unscaled_x_right
)
1066 /* Now use these informations to compute a good alpha,
1067 and lightness. The sum is on each of the 9
1068 region's surface and alpha and lightness.
1070 transformed alpha = sum(surface * alpha) / sum(surface)
1071 transformed color = sum(surface * alpha * color) / sum(surface * alpha)
1073 /* 1: top left part */
1074 base
= spu
->stride
* (unsigned int) unscaled_y
;
1075 tmp
= left
* top
* canon_alpha(spu
->aimage
[base
+ (unsigned int) unscaled_x
]);
1077 color
+= tmp
* spu
->image
[base
+ (unsigned int) unscaled_x
];
1078 /* 2: top center part */
1081 for (walkx
= left_right_column
; walkx
< (unsigned int) unscaled_x_right
; ++walkx
) {
1082 base
= spu
->stride
* (unsigned int) unscaled_y
+ walkx
;
1083 tmp
= /* 1.0 * */ top
* canon_alpha(spu
->aimage
[base
]);
1085 color
+= tmp
* spu
->image
[base
];
1088 /* 3: top right part */
1090 base
= spu
->stride
* (unsigned int) unscaled_y
+ (unsigned int) unscaled_x_right
;
1091 tmp
= right
* top
* canon_alpha(spu
->aimage
[base
]);
1093 color
+= tmp
* spu
->image
[base
];
1095 /* 4: center left part */
1098 for (walky
= top_low_row
; walky
< (unsigned int) unscaled_y_bottom
; ++walky
) {
1099 base
= spu
->stride
* walky
+ (unsigned int) unscaled_x
;
1100 tmp
= left
/* * 1.0 */ * canon_alpha(spu
->aimage
[base
]);
1102 color
+= tmp
* spu
->image
[base
];
1105 /* 5: center part */
1106 if (width
> 0 && height
> 0) {
1108 for (walky
= top_low_row
; walky
< (unsigned int) unscaled_y_bottom
; ++walky
) {
1110 base
= spu
->stride
* walky
;
1111 for (walkx
= left_right_column
; walkx
< (unsigned int) unscaled_x_right
; ++walkx
) {
1112 tmp
= /* 1.0 * 1.0 * */ canon_alpha(spu
->aimage
[base
+ walkx
]);
1114 color
+= tmp
* spu
->image
[base
+ walkx
];
1118 /* 6: center right part */
1119 if (right
> 0.0 && height
> 0) {
1121 for (walky
= top_low_row
; walky
< (unsigned int) unscaled_y_bottom
; ++walky
) {
1122 base
= spu
->stride
* walky
+ (unsigned int) unscaled_x_right
;
1123 tmp
= right
/* * 1.0 */ * canon_alpha(spu
->aimage
[base
]);
1125 color
+= tmp
* spu
->image
[base
];
1128 /* 7: bottom left part */
1130 base
= spu
->stride
* (unsigned int) unscaled_y_bottom
+ (unsigned int) unscaled_x
;
1131 tmp
= left
* bottom
* canon_alpha(spu
->aimage
[base
]);
1133 color
+= tmp
* spu
->image
[base
];
1135 /* 8: bottom center part */
1136 if (width
> 0 && bottom
> 0.0) {
1138 base
= spu
->stride
* (unsigned int) unscaled_y_bottom
;
1139 for (walkx
= left_right_column
; walkx
< (unsigned int) unscaled_x_right
; ++walkx
) {
1140 tmp
= /* 1.0 * */ bottom
* canon_alpha(spu
->aimage
[base
+ walkx
]);
1142 color
+= tmp
* spu
->image
[base
+ walkx
];
1145 /* 9: bottom right part */
1146 if (right
> 0.0 && bottom
> 0.0) {
1147 base
= spu
->stride
* (unsigned int) unscaled_y_bottom
+ (unsigned int) unscaled_x_right
;
1148 tmp
= right
* bottom
* canon_alpha(spu
->aimage
[base
]);
1150 color
+= tmp
* spu
->image
[base
];
1152 /* Finally mix these transparency and brightness information suitably */
1153 base
= spu
->scaled_stride
* y
+ x
;
1154 spu
->scaled_image
[base
] = alpha
> 0 ? color
/ alpha
: 0;
1155 spu
->scaled_aimage
[base
] = alpha
* scalex
* scaley
/ 0x10000;
1156 if (spu
->scaled_aimage
[base
]) {
1157 spu
->scaled_aimage
[base
] = 256 - spu
->scaled_aimage
[base
];
1158 if (spu
->scaled_aimage
[base
] + spu
->scaled_image
[base
] > 255)
1159 spu
->scaled_image
[base
] = 256 - spu
->scaled_aimage
[base
];
1166 /* Kludge: draw_alpha needs width multiple of 8. */
1167 if (spu
->scaled_width
< spu
->scaled_stride
)
1168 for (y
= 0; y
< spu
->scaled_height
; ++y
) {
1169 memset(spu
->scaled_aimage
+ y
* spu
->scaled_stride
+ spu
->scaled_width
, 0,
1170 spu
->scaled_stride
- spu
->scaled_width
);
1172 spu
->scaled_frame_width
= dxs
;
1173 spu
->scaled_frame_height
= dys
;
1176 if (spu
->scaled_image
){
1177 switch (spu_alignment
) {
1179 spu
->scaled_start_row
= dys
*sub_pos
/100;
1180 if (spu
->scaled_start_row
+ spu
->scaled_height
> dys
)
1181 spu
->scaled_start_row
= dys
- spu
->scaled_height
;
1184 spu
->scaled_start_row
= dys
*sub_pos
/100 - spu
->scaled_height
/2;
1185 if (sub_pos
>= 50 && spu
->scaled_start_row
+ spu
->scaled_height
> dys
)
1186 spu
->scaled_start_row
= dys
- spu
->scaled_height
;
1189 spu
->scaled_start_row
= dys
*sub_pos
/100 - spu
->scaled_height
;
1192 draw_alpha(ctx
, spu
->scaled_start_col
, spu
->scaled_start_row
, spu
->scaled_width
, spu
->scaled_height
,
1193 spu
->scaled_image
, spu
->scaled_aimage
, spu
->scaled_stride
);
1194 spu
->spu_changed
= 0;
1200 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"SPU not displayed: start_pts=%d end_pts=%d now_pts=%d\n",
1201 spu
->start_pts
, spu
->end_pts
, spu
->now_pts
);
1205 void spudec_update_palette(void * this, unsigned int *palette
)
1207 spudec_handle_t
*spu
= this;
1208 if (spu
&& palette
) {
1209 memcpy(spu
->global_palette
, palette
, sizeof(spu
->global_palette
));
1211 vo_control(spu
->hw_spu
, VOCTRL_SET_SPU_PALETTE
, spu
->global_palette
);
1215 void spudec_set_font_factor(void * this, double factor
)
1217 spudec_handle_t
*spu
= this;
1218 spu
->font_start_level
= (int)(0xF0-(0xE0*factor
));
1221 static void spudec_parse_extradata(spudec_handle_t
*this,
1222 uint8_t *extradata
, int extradata_len
)
1224 uint8_t *buffer
, *ptr
;
1225 unsigned int *pal
= this->global_palette
, *cuspal
= this->cuspal
;
1229 if (extradata_len
== 16*4) {
1230 for (i
=0; i
<16; i
++)
1231 pal
[i
] = AV_RB32(extradata
+ i
*4);
1232 this->auto_palette
= 0;
1236 if (!(ptr
= buffer
= malloc(extradata_len
+1)))
1238 memcpy(buffer
, extradata
, extradata_len
);
1239 buffer
[extradata_len
] = 0;
1244 if (!strncmp(ptr
, "size: ", 6))
1245 sscanf(ptr
+ 6, "%dx%d", &this->orig_frame_width
, &this->orig_frame_height
);
1246 if (!strncmp(ptr
, "palette: ", 9) &&
1247 sscanf(ptr
+ 9, "%x, %x, %x, %x, %x, %x, %x, %x, "
1248 "%x, %x, %x, %x, %x, %x, %x, %x",
1249 &pal
[ 0], &pal
[ 1], &pal
[ 2], &pal
[ 3],
1250 &pal
[ 4], &pal
[ 5], &pal
[ 6], &pal
[ 7],
1251 &pal
[ 8], &pal
[ 9], &pal
[10], &pal
[11],
1252 &pal
[12], &pal
[13], &pal
[14], &pal
[15]) == 16) {
1253 for (i
=0; i
<16; i
++)
1254 pal
[i
] = vobsub_palette_to_yuv(pal
[i
]);
1255 this->auto_palette
= 0;
1257 if (!strncasecmp(ptr
, "forced subs: on", 15))
1258 this->forced_subs_only
= 1;
1259 if (!strncmp(ptr
, "custom colors: ON, tridx: ", 26) &&
1260 sscanf(ptr
+ 26, "%x, colors: %x, %x, %x, %x",
1261 &tridx
, cuspal
+0, cuspal
+1, cuspal
+2, cuspal
+3) == 5) {
1262 for (i
=0; i
<4; i
++) {
1263 cuspal
[i
] = vobsub_rgb_to_yuv(cuspal
[i
]);
1264 if (tridx
& (1 << (12-4*i
)))
1265 cuspal
[i
] |= 1 << 31;
1269 } while ((ptr
=strchr(ptr
,'\n')) && *++ptr
);
1274 void *spudec_new_scaled(unsigned int *palette
, unsigned int frame_width
, unsigned int frame_height
, uint8_t *extradata
, int extradata_len
)
1276 spudec_handle_t
*this = calloc(1, sizeof(spudec_handle_t
));
1278 this->orig_frame_height
= frame_height
;
1279 this->orig_frame_width
= frame_width
;
1282 memcpy(this->global_palette
, palette
, sizeof(this->global_palette
));
1284 this->auto_palette
= 1;
1286 spudec_parse_extradata(this, extradata
, extradata_len
);
1287 /* XXX Although the video frame is some size, the SPU frame is
1288 always maximum size i.e. 720 wide and 576 or 480 high */
1289 // For HD files in MKV the VobSub resolution can be higher though,
1290 // see largeres_vobsub.mkv
1291 if (this->orig_frame_width
<= 720 && this->orig_frame_height
<= 576) {
1292 this->orig_frame_width
= 720;
1293 if (this->orig_frame_height
== 480 || this->orig_frame_height
== 240)
1294 this->orig_frame_height
= 480;
1296 this->orig_frame_height
= 576;
1300 mp_msg(MSGT_SPUDEC
,MSGL_FATAL
, "FATAL: spudec_init: calloc");
1304 void *spudec_new(unsigned int *palette
)
1306 return spudec_new_scaled(palette
, 0, 0, NULL
, 0);
1309 void spudec_free(void *this)
1311 spudec_handle_t
*spu
= this;
1313 while (spu
->queue_head
)
1314 spudec_free_packet(spudec_dequeue_packet(spu
));
1317 free(spu
->scaled_image
);
1318 spu
->scaled_image
= NULL
;
1322 free(spu
->pal_image
);
1323 spu
->pal_image
= NULL
;
1324 spu
->image_size
= 0;
1325 spu
->pal_width
= spu
->pal_height
= 0;
1330 void spudec_set_hw_spu(void *this, struct vo
*hw_spu
)
1332 spudec_handle_t
*spu
= this;
1335 spu
->hw_spu
= hw_spu
;
1336 vo_control(hw_spu
, VOCTRL_SET_SPU_PALETTE
, spu
->global_palette
);
1339 #define MP_NOPTS_VALUE (-1LL<<63) //both int64_t and double should be able to represent this exactly
1342 * palette must contain at least 256 32-bit entries, otherwise crashes
1345 void spudec_set_paletted(void *this, const uint8_t *pal_img
, int pal_stride
,
1346 const void *palette
,
1347 int x
, int y
, int w
, int h
,
1348 double pts
, double endpts
)
1351 uint16_t g8a8_pal
[256];
1353 const uint32_t *pal
= palette
;
1354 spudec_handle_t
*spu
= this;
1357 int stride
= (w
+ 7) & ~7;
1358 if ((unsigned)w
>= 0x8000 || (unsigned)h
> 0x4000)
1360 packet
= calloc(1, sizeof(packet_t
));
1361 packet
->is_decoded
= 1;
1364 packet
->stride
= stride
;
1365 packet
->start_col
= x
;
1366 packet
->start_row
= y
;
1367 packet
->data_len
= 2 * stride
* h
;
1368 if (packet
->data_len
) { // size 0 is a special "clear" packet
1369 packet
->packet
= malloc(packet
->data_len
);
1370 img
= packet
->packet
;
1371 aimg
= packet
->packet
+ stride
* h
;
1372 for (i
= 0; i
< 256; i
++) {
1373 uint32_t pixel
= pal
[i
];
1374 int alpha
= pixel
>> 24;
1375 int gray
= (((pixel
& 0x000000ff) >> 0) +
1376 ((pixel
& 0x0000ff00) >> 7) +
1377 ((pixel
& 0x00ff0000) >> 16)) >> 2;
1378 gray
= FFMIN(gray
, alpha
);
1379 g8a8_pal
[i
] = (-alpha
<< 8) | gray
;
1381 pal2gray_alpha(g8a8_pal
, pal_img
, pal_stride
,
1382 img
, aimg
, stride
, w
, h
);
1384 packet
->start_pts
= 0;
1385 packet
->end_pts
= 0x7fffffff;
1386 if (pts
!= MP_NOPTS_VALUE
)
1387 packet
->start_pts
= pts
* 90000;
1388 if (endpts
!= MP_NOPTS_VALUE
)
1389 packet
->end_pts
= endpts
* 90000;
1390 spudec_queue_packet(spu
, packet
);