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/common.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 */
123 unsigned int forced_subs_only
; /* flag: 0=display all subtitle, !0 display only forced subtitles */
124 unsigned int is_forced_sub
; /* true if current subtitle is a forced subtitle */
126 struct palette_crop_cache palette_crop_cache
;
129 static void spudec_queue_packet(spudec_handle_t
*this, packet_t
*packet
)
131 if (this->queue_head
== NULL
)
132 this->queue_head
= packet
;
134 this->queue_tail
->next
= packet
;
135 this->queue_tail
= packet
;
138 static packet_t
*spudec_dequeue_packet(spudec_handle_t
*this)
140 packet_t
*retval
= this->queue_head
;
142 this->queue_head
= retval
->next
;
143 if (this->queue_head
== NULL
)
144 this->queue_tail
= NULL
;
149 static void spudec_free_packet(packet_t
*packet
)
151 free(packet
->packet
);
155 static inline unsigned int get_be16(const unsigned char *p
)
157 return (p
[0] << 8) + p
[1];
160 static inline unsigned int get_be24(const unsigned char *p
)
162 return (get_be16(p
) << 8) + p
[2];
165 static void next_line(packet_t
*packet
)
167 if (packet
->current_nibble
[packet
->deinterlace_oddness
] % 2)
168 packet
->current_nibble
[packet
->deinterlace_oddness
]++;
169 packet
->deinterlace_oddness
= (packet
->deinterlace_oddness
+ 1) % 2;
172 static inline unsigned char get_nibble(packet_t
*packet
)
175 unsigned int *nibblep
= packet
->current_nibble
+ packet
->deinterlace_oddness
;
176 if (*nibblep
/ 2 >= packet
->control_start
) {
177 mp_msg(MSGT_SPUDEC
,MSGL_WARN
, "SPUdec: ERROR: get_nibble past end of packet\n");
180 nib
= packet
->packet
[*nibblep
/ 2];
189 /* Cut the sub to visible part */
190 static inline void spudec_cut_image(spudec_handle_t
*this)
193 unsigned int first_y
, last_y
;
195 if (this->stride
== 0 || this->height
== 0) {
199 for (fy
= 0; fy
< this->image_size
&& !this->aimage
[fy
]; fy
++);
200 for (ly
= this->stride
* this->height
-1; ly
&& !this->aimage
[ly
]; ly
--);
201 first_y
= fy
/ this->stride
;
202 last_y
= ly
/ this->stride
;
203 //printf("first_y: %d, last_y: %d\n", first_y, last_y);
204 this->start_row
+= first_y
;
206 // Some subtitles trigger this condition
207 if (last_y
+ 1 > first_y
) {
208 this->height
= last_y
- first_y
+1;
214 // printf("new h %d new start %d (sz %d st %d)---\n\n", this->height, this->start_row, this->image_size, this->stride);
217 memmove(this->image
, this->image
+ this->stride
* first_y
, this->stride
* this->height
);
218 memmove(this->aimage
, this->aimage
+ this->stride
* first_y
, this->stride
* this->height
);
223 static int spudec_alloc_image(spudec_handle_t
*this, int stride
, int height
)
225 if (this->width
> stride
) // just a safeguard
226 this->width
= stride
;
227 this->stride
= stride
;
228 this->height
= height
;
229 if (this->image_size
< this->stride
* this->height
) {
230 if (this->image
!= NULL
) {
232 free(this->pal_image
);
233 this->image_size
= 0;
234 this->pal_width
= this->pal_height
= 0;
236 this->image
= malloc(2 * this->stride
* this->height
);
238 this->image_size
= this->stride
* this->height
;
239 this->aimage
= this->image
+ this->image_size
;
240 // use stride here as well to simplify reallocation checks
241 this->pal_image
= malloc(this->stride
* this->height
);
244 return this->image
!= NULL
;
248 * \param pal palette in MPlayer-style gray-alpha values, i.e.
249 * alpha == 0 means transparent, 1 fully opaque,
250 * gray value <= 256 - alpha.
252 static void pal2gray_alpha(const uint16_t *pal
,
253 const uint8_t *src
, int src_stride
,
254 uint8_t *dst
, uint8_t *dsta
,
255 int dst_stride
, int w
, int h
)
258 for (y
= 0; y
< h
; y
++) {
259 for (x
= 0; x
< w
; x
++) {
260 uint16_t pixel
= pal
[src
[x
]];
262 *dsta
++ = pixel
>> 8;
264 for (; x
< dst_stride
; x
++)
265 *dsta
++ = *dst
++ = 0;
270 static int apply_palette_crop(spudec_handle_t
*this,
271 unsigned crop_x
, unsigned crop_y
,
272 unsigned crop_w
, unsigned crop_h
)
277 unsigned stride
= (crop_w
+ 7) & ~7;
278 if (crop_x
> this->pal_width
|| crop_y
> this->pal_height
||
279 crop_w
> this->pal_width
- crop_x
|| crop_h
> this->pal_width
- crop_y
||
280 crop_w
> 0x8000 || crop_h
> 0x8000 ||
281 stride
* crop_h
> this->image_size
) {
284 for (i
= 0; i
< 4; ++i
) {
286 int alpha
= this->alpha
[i
];
289 if (this->custom
&& (this->cuspal
[i
] >> 31) != 0)
291 color
= this->custom
? this->cuspal
[i
] :
292 this->global_palette
[this->palette
[i
]];
293 color
= (color
>> 16) & 0xff;
294 // convert to MPlayer-style gray/alpha palette
295 color
= FFMIN(color
, alpha
);
296 pal
[i
] = (-alpha
<< 8) | color
;
298 src
= this->pal_image
+ crop_y
* this->pal_width
+ crop_x
;
299 pal2gray_alpha(pal
, src
, this->pal_width
,
300 this->image
, this->aimage
, stride
,
302 this->width
= crop_w
;
303 this->height
= crop_h
;
304 this->stride
= stride
;
305 this->start_col
= this->pal_start_col
+ crop_x
;
306 this->start_row
= this->pal_start_row
+ crop_y
;
307 spudec_cut_image(this);
309 // reset scaled image
310 this->scaled_frame_width
= 0;
311 this->scaled_frame_height
= 0;
312 this->palette_crop_cache
.valid
= 0;
316 int spudec_apply_palette_crop(void *this, uint32_t palette
,
317 int sx
, int sy
, int ex
, int ey
)
319 spudec_handle_t
*spu
= this;
320 struct palette_crop_cache
*c
= &spu
->palette_crop_cache
;
321 if (c
->valid
&& c
->palette
== palette
&&
322 c
->sx
== sx
&& c
->sy
== sy
&& c
->ex
== ex
&& c
->ey
== ey
)
324 spu
->palette
[0] = (palette
>> 28) & 0xf;
325 spu
->palette
[1] = (palette
>> 24) & 0xf;
326 spu
->palette
[2] = (palette
>> 20) & 0xf;
327 spu
->palette
[3] = (palette
>> 16) & 0xf;
328 spu
->alpha
[0] = (palette
>> 12) & 0xf;
329 spu
->alpha
[1] = (palette
>> 8) & 0xf;
330 spu
->alpha
[2] = (palette
>> 4) & 0xf;
331 spu
->alpha
[3] = palette
& 0xf;
332 spu
->spu_changed
= 1;
333 c
->result
= apply_palette_crop(spu
,
334 sx
- spu
->pal_start_col
, sy
- spu
->pal_start_row
,
336 c
->palette
= palette
;
337 c
->sx
= sx
; c
->sy
= sy
;
338 c
->ex
= ex
; c
->ey
= ey
;
343 static void spudec_process_data(spudec_handle_t
*this, packet_t
*packet
)
345 unsigned int i
, x
, y
;
348 if (!spudec_alloc_image(this, packet
->stride
, packet
->height
))
351 this->pal_start_col
= packet
->start_col
;
352 this->pal_start_row
= packet
->start_row
;
353 this->pal_height
= packet
->height
;
354 this->pal_width
= packet
->width
;
355 this->stride
= packet
->stride
;
356 memcpy(this->palette
, packet
->palette
, sizeof(this->palette
));
357 memcpy(this->alpha
, packet
->alpha
, sizeof(this->alpha
));
359 i
= packet
->current_nibble
[1];
362 dst
= this->pal_image
;
363 while (packet
->current_nibble
[0] < i
364 && packet
->current_nibble
[1] / 2 < packet
->control_start
365 && y
< this->pal_height
) {
366 unsigned int len
, color
;
367 unsigned int rle
= 0;
368 rle
= get_nibble(packet
);
371 rle
= (rle
<< 4) | get_nibble(packet
);
373 rle
= (rle
<< 4) | get_nibble(packet
);
375 rle
= (rle
<< 4) | get_nibble(packet
);
377 color
= 3 - (rle
& 0x3);
380 if (len
== 0 || x
>= this->pal_width
) {
381 len
+= this->pal_width
- x
;
386 memset(dst
, color
, len
);
389 apply_palette_crop(this, 0, 0, this->pal_width
, this->pal_height
);
394 This function tries to create a usable palette.
395 It determines how many non-transparent colors are used, and assigns different
396 gray scale values to each color.
397 I tested it with four streams and even got something readable. Half of the
398 times I got black characters with white around and half the reverse.
400 static void compute_palette(spudec_handle_t
*this, packet_t
*packet
)
402 int used
[16],i
,cused
,start
,step
,color
;
404 memset(used
, 0, sizeof(used
));
406 if (packet
->alpha
[i
]) /* !Transparent? */
407 used
[packet
->palette
[i
]] = 1;
408 for (cused
=0, i
=0; i
<16; i
++)
409 if (used
[i
]) cused
++;
415 start
= this->font_start_level
;
416 step
= (0xF0-this->font_start_level
)/(cused
-1);
418 memset(used
, 0, sizeof(used
));
419 for (i
=0; i
<4; i
++) {
420 color
= packet
->palette
[i
];
421 if (packet
->alpha
[i
] && !used
[color
]) { /* not assigned? */
423 this->global_palette
[color
] = start
<<16;
429 static void spudec_process_control(spudec_handle_t
*this, int pts100
)
431 int a
,b
,c
,d
; /* Temporary vars */
432 unsigned int date
, type
;
434 unsigned int start_off
= 0;
435 unsigned int next_off
;
436 unsigned int start_pts
= 0;
437 unsigned int end_pts
= 0;
438 unsigned int current_nibble
[2] = {0, 0};
439 unsigned int control_start
;
440 unsigned int display
= 0;
441 unsigned int start_col
= 0;
442 unsigned int end_col
= 0;
443 unsigned int start_row
= 0;
444 unsigned int end_row
= 0;
445 unsigned int width
= 0;
446 unsigned int height
= 0;
447 unsigned int stride
= 0;
449 control_start
= get_be16(this->packet
+ 2);
450 next_off
= control_start
;
451 while (start_off
!= next_off
) {
452 start_off
= next_off
;
453 date
= get_be16(this->packet
+ start_off
) * 1024;
454 next_off
= get_be16(this->packet
+ start_off
+ 2);
455 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
, "date=%d\n", date
);
457 for (type
= this->packet
[off
++]; type
!= 0xff; type
= this->packet
[off
++]) {
458 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
, "cmd=%d ",type
);
461 /* Menu ID, 1 byte */
462 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Menu ID\n");
463 /* shouldn't a Menu ID type force display start? */
464 start_pts
= pts100
< 0 && -pts100
>= date
? 0 : pts100
+ date
;
467 this->is_forced_sub
=~0; // current subtitle is forced
471 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Start display!\n");
472 start_pts
= pts100
< 0 && -pts100
>= date
? 0 : pts100
+ date
;
475 this->is_forced_sub
=0;
479 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Stop display!\n");
480 end_pts
= pts100
< 0 && -pts100
>= date
? 0 : pts100
+ date
;
484 this->palette
[0] = this->packet
[off
] >> 4;
485 this->palette
[1] = this->packet
[off
] & 0xf;
486 this->palette
[2] = this->packet
[off
+ 1] >> 4;
487 this->palette
[3] = this->packet
[off
+ 1] & 0xf;
488 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Palette %d, %d, %d, %d\n",
489 this->palette
[0], this->palette
[1], this->palette
[2], this->palette
[3]);
494 a
= this->packet
[off
] >> 4;
495 b
= this->packet
[off
] & 0xf;
496 c
= this->packet
[off
+ 1] >> 4;
497 d
= this->packet
[off
+ 1] & 0xf;
498 // Note: some DVDs change these values to create a fade-in/fade-out effect
499 // We can not handle this, so just keep the highest value during the display time.
501 a
= FFMAX(a
, this->alpha
[0]);
502 b
= FFMAX(b
, this->alpha
[1]);
503 c
= FFMAX(c
, this->alpha
[2]);
504 d
= FFMAX(d
, this->alpha
[3]);
510 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Alpha %d, %d, %d, %d\n",
511 this->alpha
[0], this->alpha
[1], this->alpha
[2], this->alpha
[3]);
516 a
= get_be24(this->packet
+ off
);
517 b
= get_be24(this->packet
+ off
+ 3);
520 width
= (end_col
< start_col
) ? 0 : end_col
- start_col
+ 1;
521 stride
= (width
+ 7) & ~7; /* Kludge: draw_alpha needs width multiple of 8 */
524 height
= (end_row
< start_row
) ? 0 : end_row
- start_row
/* + 1 */;
525 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Coords col: %d - %d row: %d - %d (%dx%d)\n",
526 start_col
, end_col
, start_row
, end_row
,
532 current_nibble
[0] = 2 * get_be16(this->packet
+ off
);
533 current_nibble
[1] = 2 * get_be16(this->packet
+ off
+ 2);
534 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Graphic offset 1: %d offset 2: %d\n",
535 current_nibble
[0] / 2, current_nibble
[1] / 2);
539 /* All done, bye-bye */
540 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Done!\n");
544 mp_msg(MSGT_SPUDEC
,MSGL_WARN
,"spudec: Error determining control type 0x%02x. Skipping %d bytes.\n",
545 type
, next_off
- off
);
552 if (end_pts
== UINT_MAX
&& start_off
!= next_off
) {
553 end_pts
= get_be16(this->packet
+ next_off
) * 1024;
554 end_pts
= 1 - pts100
>= end_pts
? 0 : pts100
+ end_pts
- 1;
557 packet_t
*packet
= calloc(1, sizeof(packet_t
));
559 packet
->start_pts
= start_pts
;
560 packet
->end_pts
= end_pts
;
561 packet
->current_nibble
[0] = current_nibble
[0];
562 packet
->current_nibble
[1] = current_nibble
[1];
563 packet
->start_row
= start_row
;
564 packet
->start_col
= start_col
;
565 packet
->width
= width
;
566 packet
->height
= height
;
567 packet
->stride
= stride
;
568 packet
->control_start
= control_start
;
569 for (i
=0; i
<4; i
++) {
570 packet
->alpha
[i
] = this->alpha
[i
];
571 packet
->palette
[i
] = this->palette
[i
];
573 packet
->packet
= malloc(this->packet_size
);
574 memcpy(packet
->packet
, this->packet
, this->packet_size
);
575 spudec_queue_packet(this, packet
);
580 static void spudec_decode(spudec_handle_t
*this, int pts100
)
582 spudec_process_control(this, pts100
);
585 int spudec_changed(void * this)
587 spudec_handle_t
* spu
= this;
588 return spu
->spu_changed
|| spu
->now_pts
> spu
->end_pts
;
591 void spudec_assemble(void *this, unsigned char *packet
, unsigned int len
, int pts100
)
593 spudec_handle_t
*spu
= this;
594 // spudec_heartbeat(this, pts100);
596 mp_msg(MSGT_SPUDEC
,MSGL_WARN
,"SPUasm: packet too short\n");
599 spu
->packet_pts
= pts100
;
600 if (spu
->packet_offset
== 0) {
601 unsigned int len2
= get_be16(packet
);
602 // Start new fragment
603 if (spu
->packet_reserve
< len2
) {
605 spu
->packet
= malloc(len2
);
606 spu
->packet_reserve
= spu
->packet
!= NULL
? len2
: 0;
608 if (spu
->packet
!= NULL
) {
609 spu
->packet_size
= len2
;
611 mp_msg(MSGT_SPUDEC
,MSGL_WARN
,"SPUasm: invalid frag len / len2: %d / %d \n", len
, len2
);
614 memcpy(spu
->packet
, packet
, len
);
615 spu
->packet_offset
= len
;
616 spu
->packet_pts
= pts100
;
619 // Continue current fragment
620 if (spu
->packet_size
< spu
->packet_offset
+ len
){
621 mp_msg(MSGT_SPUDEC
,MSGL_WARN
,"SPUasm: invalid fragment\n");
622 spu
->packet_size
= spu
->packet_offset
= 0;
625 memcpy(spu
->packet
+ spu
->packet_offset
, packet
, len
);
626 spu
->packet_offset
+= len
;
630 // check if we have a complete packet (unfortunatelly packet_size is bad
632 // [cb] packet_size is padded to be even -> may be one byte too long
633 if ((spu
->packet_offset
== spu
->packet_size
) ||
634 ((spu
->packet_offset
+ 1) == spu
->packet_size
)){
636 while(x
+4<=spu
->packet_offset
){
637 y
=get_be16(spu
->packet
+x
+2); // next control pointer
638 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"SPUtest: x=%d y=%d off=%d size=%d\n",x
,y
,spu
->packet_offset
,spu
->packet_size
);
639 if(x
>=4 && x
==y
){ // if it points to self - we're done!
641 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"SPUgot: off=%d size=%d \n",spu
->packet_offset
,spu
->packet_size
);
642 spudec_decode(spu
, pts100
);
643 spu
->packet_offset
= 0;
646 if(y
<=x
|| y
>=spu
->packet_size
){ // invalid?
647 mp_msg(MSGT_SPUDEC
,MSGL_WARN
,"SPUtest: broken packet!!!!! y=%d < x=%d\n",y
,x
);
648 spu
->packet_size
= spu
->packet_offset
= 0;
653 // [cb] packet is done; start new packet
654 spu
->packet_offset
= 0;
657 if (spu
->packet_offset
== spu
->packet_size
) {
658 spudec_decode(spu
, pts100
);
659 spu
->packet_offset
= 0;
664 void spudec_reset(void *this) // called after seek
666 spudec_handle_t
*spu
= this;
667 while (spu
->queue_head
)
668 spudec_free_packet(spudec_dequeue_packet(spu
));
671 spu
->packet_size
= spu
->packet_offset
= 0;
674 void spudec_heartbeat(void *this, unsigned int pts100
)
676 spudec_handle_t
*spu
= this;
677 spu
->now_pts
= pts100
;
679 // TODO: detect and handle broken timestamps (e.g. due to wrapping)
680 while (spu
->queue_head
!= NULL
&& pts100
>= spu
->queue_head
->start_pts
) {
681 packet_t
*packet
= spudec_dequeue_packet(spu
);
682 spu
->start_pts
= packet
->start_pts
;
683 spu
->end_pts
= packet
->end_pts
;
684 if (packet
->is_decoded
) {
686 spu
->image_size
= packet
->data_len
;
687 spu
->image
= packet
->packet
;
688 spu
->aimage
= packet
->packet
+ packet
->stride
* packet
->height
;
689 packet
->packet
= NULL
;
690 spu
->width
= packet
->width
;
691 spu
->height
= packet
->height
;
692 spu
->stride
= packet
->stride
;
693 spu
->start_col
= packet
->start_col
;
694 spu
->start_row
= packet
->start_row
;
696 // reset scaled image
697 spu
->scaled_frame_width
= 0;
698 spu
->scaled_frame_height
= 0;
700 if (spu
->auto_palette
)
701 compute_palette(spu
, packet
);
702 spudec_process_data(spu
, packet
);
704 spudec_free_packet(packet
);
705 spu
->spu_changed
= 1;
709 int spudec_visible(void *this){
710 spudec_handle_t
*spu
= this;
711 int ret
=(spu
->start_pts
<= spu
->now_pts
&&
712 spu
->now_pts
< spu
->end_pts
&&
714 // printf("spu visible: %d \n",ret);
718 void spudec_set_forced_subs_only(void * const this, const unsigned int flag
)
721 ((spudec_handle_t
*)this)->forced_subs_only
=flag
;
722 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"SPU: Display only forced subs now %s\n", flag
? "enabled": "disabled");
726 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
)
728 spudec_handle_t
*spu
= this;
729 if (spudec_visible(spu
))
731 draw_alpha(ctx
, spu
->start_col
, spu
->start_row
, spu
->width
, spu
->height
,
732 spu
->image
, spu
->aimage
, spu
->stride
);
733 spu
->spu_changed
= 0;
737 /* calc the bbox for spudec subs */
738 void spudec_calc_bbox(void *me
, unsigned int dxs
, unsigned int dys
, unsigned int* bbox
)
740 spudec_handle_t
*spu
= me
;
741 if (spu
->orig_frame_width
== 0 || spu
->orig_frame_height
== 0
742 || (spu
->orig_frame_width
== dxs
&& spu
->orig_frame_height
== dys
)) {
744 bbox
[0] = spu
->start_col
;
745 bbox
[1] = spu
->start_col
+ spu
->width
;
746 bbox
[2] = spu
->start_row
;
747 bbox
[3] = spu
->start_row
+ spu
->height
;
751 unsigned int scalex
= 0x100 * dxs
/ spu
->orig_frame_width
;
752 unsigned int scaley
= 0x100 * dys
/ spu
->orig_frame_height
;
753 bbox
[0] = spu
->start_col
* scalex
/ 0x100;
754 bbox
[1] = spu
->start_col
* scalex
/ 0x100 + spu
->width
* scalex
/ 0x100;
755 switch (spu_alignment
) {
757 bbox
[3] = dys
*sub_pos
/100 + spu
->height
* scaley
/ 0x100;
758 if (bbox
[3] > dys
) bbox
[3] = dys
;
759 bbox
[2] = bbox
[3] - spu
->height
* scaley
/ 0x100;
763 bbox
[2] = dys
*sub_pos
/100 - spu
->height
* scaley
/ 0x200;
764 bbox
[3] = bbox
[2] + spu
->height
;
766 bbox
[3] = dys
*sub_pos
/100 + spu
->height
* scaley
/ 0x200;
767 if (bbox
[3] > dys
) bbox
[3] = dys
;
768 bbox
[2] = bbox
[3] - spu
->height
* scaley
/ 0x100;
772 bbox
[2] = dys
*sub_pos
/100 - spu
->height
* scaley
/ 0x100;
773 bbox
[3] = bbox
[2] + spu
->height
;
776 bbox
[2] = spu
->start_row
* scaley
/ 0x100;
777 bbox
[3] = spu
->start_row
* scaley
/ 0x100 + spu
->height
* scaley
/ 0x100;
782 /* transform mplayer's alpha value into an opacity value that is linear */
783 static inline int canon_alpha(int alpha
)
785 return (uint8_t)-alpha
;
795 static void scale_table(unsigned int start_src
, unsigned int start_tar
, unsigned int end_src
, unsigned int end_tar
, scale_pixel
* table
)
798 unsigned int delta_src
= end_src
- start_src
;
799 unsigned int delta_tar
= end_tar
- start_tar
;
802 if (delta_src
== 0 || delta_tar
== 0) {
805 src_step
= (delta_src
<< 16) / delta_tar
>>1;
806 for (t
= 0; t
<=delta_tar
; src
+= (src_step
<< 1), t
++){
807 table
[t
].position
= FFMIN(src
>> 16, end_src
- 1);
808 table
[t
].right_down
= src
& 0xffff;
809 table
[t
].left_up
= 0x10000 - table
[t
].right_down
;
813 /* bilinear scale, similar to vobsub's code */
814 static void scale_image(int x
, int y
, scale_pixel
* table_x
, scale_pixel
* table_y
, spudec_handle_t
* spu
)
818 unsigned int scale
[4];
819 int base
= table_y
[y
].position
* spu
->stride
+ table_x
[x
].position
;
820 int scaled
= y
* spu
->scaled_stride
+ x
;
821 alpha
[0] = canon_alpha(spu
->aimage
[base
]);
822 alpha
[1] = canon_alpha(spu
->aimage
[base
+ 1]);
823 alpha
[2] = canon_alpha(spu
->aimage
[base
+ spu
->stride
]);
824 alpha
[3] = canon_alpha(spu
->aimage
[base
+ spu
->stride
+ 1]);
825 color
[0] = spu
->image
[base
];
826 color
[1] = spu
->image
[base
+ 1];
827 color
[2] = spu
->image
[base
+ spu
->stride
];
828 color
[3] = spu
->image
[base
+ spu
->stride
+ 1];
829 scale
[0] = (table_x
[x
].left_up
* table_y
[y
].left_up
>> 16) * alpha
[0];
830 if (table_y
[y
].left_up
== 0x10000) // necessary to avoid overflow-case
831 scale
[0] = table_x
[x
].left_up
* alpha
[0];
832 scale
[1] = (table_x
[x
].right_down
* table_y
[y
].left_up
>>16) * alpha
[1];
833 scale
[2] = (table_x
[x
].left_up
* table_y
[y
].right_down
>> 16) * alpha
[2];
834 scale
[3] = (table_x
[x
].right_down
* table_y
[y
].right_down
>> 16) * alpha
[3];
835 spu
->scaled_image
[scaled
] = (color
[0] * scale
[0] + color
[1] * scale
[1] + color
[2] * scale
[2] + color
[3] * scale
[3])>>24;
836 spu
->scaled_aimage
[scaled
] = (scale
[0] + scale
[1] + scale
[2] + scale
[3]) >> 16;
837 if (spu
->scaled_aimage
[scaled
]){
838 // ensure that MPlayer's simplified alpha-blending can not overflow
839 spu
->scaled_image
[scaled
] = FFMIN(spu
->scaled_image
[scaled
], spu
->scaled_aimage
[scaled
]);
840 // convert to MPlayer-style alpha
841 spu
->scaled_aimage
[scaled
] = -spu
->scaled_aimage
[scaled
];
845 static void sws_spu_image(unsigned char *d1
, unsigned char *d2
, int dw
, int dh
,
846 int ds
, const unsigned char* s1
, unsigned char* s2
,
847 int sw
, int sh
, int ss
)
849 struct SwsContext
*ctx
;
850 static SwsFilter filter
;
851 static int firsttime
= 1;
855 if (!firsttime
&& oldvar
!= spu_gaussvar
) sws_freeVec(filter
.lumH
);
857 filter
.lumH
= filter
.lumV
=
858 filter
.chrH
= filter
.chrV
= sws_getGaussianVec(spu_gaussvar
, 3.0);
859 sws_normalizeVec(filter
.lumH
, 1.0);
861 oldvar
= spu_gaussvar
;
864 ctx
=sws_getContext(sw
, sh
, PIX_FMT_GRAY8
, dw
, dh
, PIX_FMT_GRAY8
, SWS_GAUSS
, &filter
, NULL
, NULL
);
865 sws_scale(ctx
,&s1
,&ss
,0,sh
,&d1
,&ds
);
866 for (i
=ss
*sh
-1; i
>=0; i
--) if (!s2
[i
]) s2
[i
] = 255; //else s2[i] = 1;
867 sws_scale(ctx
,(const uint8_t **)&s2
,&ss
,0,sh
,&d2
,&ds
);
868 for (i
=ds
*dh
-1; i
>=0; i
--) if (d2
[i
]==0) d2
[i
] = 1; else if (d2
[i
]==255) d2
[i
] = 0;
869 sws_freeContext(ctx
);
872 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
)
874 spudec_handle_t
*spu
= me
;
875 scale_pixel
*table_x
;
876 scale_pixel
*table_y
;
878 if (spudec_visible(spu
)) {
880 // check if only forced subtitles are requested
881 if( (spu
->forced_subs_only
) && !(spu
->is_forced_sub
) ){
885 if (!(spu_aamode
&16) && (spu
->orig_frame_width
== 0 || spu
->orig_frame_height
== 0
886 || (spu
->orig_frame_width
== dxs
&& spu
->orig_frame_height
== dys
))) {
887 spudec_draw(spu
, draw_alpha
, ctx
);
890 if (spu
->scaled_frame_width
!= dxs
|| spu
->scaled_frame_height
!= dys
) { /* Resizing is needed */
891 /* scaled_x = scalex * x / 0x100
892 scaled_y = scaley * y / 0x100
893 order of operations is important because of rounding. */
894 unsigned int scalex
= 0x100 * dxs
/ spu
->orig_frame_width
;
895 unsigned int scaley
= 0x100 * dys
/ spu
->orig_frame_height
;
896 spu
->scaled_start_col
= spu
->start_col
* scalex
/ 0x100;
897 spu
->scaled_start_row
= spu
->start_row
* scaley
/ 0x100;
898 spu
->scaled_width
= spu
->width
* scalex
/ 0x100;
899 spu
->scaled_height
= spu
->height
* scaley
/ 0x100;
900 /* Kludge: draw_alpha needs width multiple of 8 */
901 spu
->scaled_stride
= (spu
->scaled_width
+ 7) & ~7;
902 if (spu
->scaled_image_size
< spu
->scaled_stride
* spu
->scaled_height
) {
903 if (spu
->scaled_image
) {
904 free(spu
->scaled_image
);
905 spu
->scaled_image_size
= 0;
907 spu
->scaled_image
= malloc(2 * spu
->scaled_stride
* spu
->scaled_height
);
908 if (spu
->scaled_image
) {
909 spu
->scaled_image_size
= spu
->scaled_stride
* spu
->scaled_height
;
910 spu
->scaled_aimage
= spu
->scaled_image
+ spu
->scaled_image_size
;
913 if (spu
->scaled_image
) {
915 // needs to be 0-initialized because draw_alpha draws always a
916 // multiple of 8 pixels. TODO: optimize
917 if (spu
->scaled_width
& 7)
918 memset(spu
->scaled_image
, 0, 2 * spu
->scaled_image_size
);
919 if (spu
->scaled_width
<= 1 || spu
->scaled_height
<= 1) {
922 switch(spu_aamode
&15) {
924 sws_spu_image(spu
->scaled_image
, spu
->scaled_aimage
,
925 spu
->scaled_width
, spu
->scaled_height
, spu
->scaled_stride
,
926 spu
->image
, spu
->aimage
, spu
->width
, spu
->height
, spu
->stride
);
929 table_x
= calloc(spu
->scaled_width
, sizeof(scale_pixel
));
930 table_y
= calloc(spu
->scaled_height
, sizeof(scale_pixel
));
931 if (!table_x
|| !table_y
) {
932 mp_msg(MSGT_SPUDEC
, MSGL_FATAL
, "Fatal: spudec_draw_scaled: calloc failed\n");
934 scale_table(0, 0, spu
->width
- 1, spu
->scaled_width
- 1, table_x
);
935 scale_table(0, 0, spu
->height
- 1, spu
->scaled_height
- 1, table_y
);
936 for (y
= 0; y
< spu
->scaled_height
; y
++)
937 for (x
= 0; x
< spu
->scaled_width
; x
++)
938 scale_image(x
, y
, table_x
, table_y
, spu
);
943 /* no antialiasing */
944 for (y
= 0; y
< spu
->scaled_height
; ++y
) {
945 int unscaled_y
= y
* 0x100 / scaley
;
946 int strides
= spu
->stride
* unscaled_y
;
947 int scaled_strides
= spu
->scaled_stride
* y
;
948 for (x
= 0; x
< spu
->scaled_width
; ++x
) {
949 int unscaled_x
= x
* 0x100 / scalex
;
950 spu
->scaled_image
[scaled_strides
+ x
] = spu
->image
[strides
+ unscaled_x
];
951 spu
->scaled_aimage
[scaled_strides
+ x
] = spu
->aimage
[strides
+ unscaled_x
];
957 /* Intermediate antialiasing. */
958 for (y
= 0; y
< spu
->scaled_height
; ++y
) {
959 const unsigned int unscaled_top
= y
* spu
->orig_frame_height
/ dys
;
960 unsigned int unscaled_bottom
= (y
+ 1) * spu
->orig_frame_height
/ dys
;
961 if (unscaled_bottom
>= spu
->height
)
962 unscaled_bottom
= spu
->height
- 1;
963 for (x
= 0; x
< spu
->scaled_width
; ++x
) {
964 const unsigned int unscaled_left
= x
* spu
->orig_frame_width
/ dxs
;
965 unsigned int unscaled_right
= (x
+ 1) * spu
->orig_frame_width
/ dxs
;
966 unsigned int color
= 0;
967 unsigned int alpha
= 0;
968 unsigned int walkx
, walky
;
969 unsigned int base
, tmp
;
970 if (unscaled_right
>= spu
->width
)
971 unscaled_right
= spu
->width
- 1;
972 for (walky
= unscaled_top
; walky
<= unscaled_bottom
; ++walky
)
973 for (walkx
= unscaled_left
; walkx
<= unscaled_right
; ++walkx
) {
974 base
= walky
* spu
->stride
+ walkx
;
975 tmp
= canon_alpha(spu
->aimage
[base
]);
977 color
+= tmp
* spu
->image
[base
];
979 base
= y
* spu
->scaled_stride
+ x
;
980 spu
->scaled_image
[base
] = alpha
? color
/ alpha
: 0;
981 spu
->scaled_aimage
[base
] =
982 alpha
* (1 + unscaled_bottom
- unscaled_top
) * (1 + unscaled_right
- unscaled_left
);
983 /* spu->scaled_aimage[base] =
984 alpha * dxs * dys / spu->orig_frame_width / spu->orig_frame_height; */
985 if (spu
->scaled_aimage
[base
]) {
986 spu
->scaled_aimage
[base
] = 256 - spu
->scaled_aimage
[base
];
987 if (spu
->scaled_aimage
[base
] + spu
->scaled_image
[base
] > 255)
988 spu
->scaled_image
[base
] = 256 - spu
->scaled_aimage
[base
];
996 /* Best antialiasing. Very slow. */
997 /* Any pixel (x, y) represents pixels from the original
998 rectangular region comprised between the columns
999 unscaled_y and unscaled_y + 0x100 / scaley and the rows
1000 unscaled_x and unscaled_x + 0x100 / scalex
1002 The original rectangular region that the scaled pixel
1003 represents is cut in 9 rectangular areas like this:
1005 +---+-----------------+---+
1007 +---+-----------------+---+
1011 +---+-----------------+---+
1013 +---+-----------------+---+
1015 The width of the left column is at most one pixel and
1016 it is never null and its right column is at a pixel
1017 boundary. The height of the top row is at most one
1018 pixel it is never null and its bottom row is at a
1019 pixel boundary. The width and height of region 5 are
1020 integral values. The width of the right column is
1021 what remains and is less than one pixel. The height
1022 of the bottom row is what remains and is less than
1025 The row above 1, 2, 3 is unscaled_y. The row between
1026 1, 2, 3 and 4, 5, 6 is top_low_row. The row between 4,
1027 5, 6 and 7, 8, 9 is (unsigned int)unscaled_y_bottom.
1028 The row beneath 7, 8, 9 is unscaled_y_bottom.
1030 The column left of 1, 4, 7 is unscaled_x. The column
1031 between 1, 4, 7 and 2, 5, 8 is left_right_column. The
1032 column between 2, 5, 8 and 3, 6, 9 is (unsigned
1033 int)unscaled_x_right. The column right of 3, 6, 9 is
1034 unscaled_x_right. */
1035 const double inv_scalex
= (double) 0x100 / scalex
;
1036 const double inv_scaley
= (double) 0x100 / scaley
;
1037 for (y
= 0; y
< spu
->scaled_height
; ++y
) {
1038 const double unscaled_y
= y
* inv_scaley
;
1039 const double unscaled_y_bottom
= unscaled_y
+ inv_scaley
;
1040 const unsigned int top_low_row
= FFMIN(unscaled_y_bottom
, unscaled_y
+ 1.0);
1041 const double top
= top_low_row
- unscaled_y
;
1042 const unsigned int height
= unscaled_y_bottom
> top_low_row
1043 ? (unsigned int) unscaled_y_bottom
- top_low_row
1045 const double bottom
= unscaled_y_bottom
> top_low_row
1046 ? unscaled_y_bottom
- floor(unscaled_y_bottom
)
1048 for (x
= 0; x
< spu
->scaled_width
; ++x
) {
1049 const double unscaled_x
= x
* inv_scalex
;
1050 const double unscaled_x_right
= unscaled_x
+ inv_scalex
;
1051 const unsigned int left_right_column
= FFMIN(unscaled_x_right
, unscaled_x
+ 1.0);
1052 const double left
= left_right_column
- unscaled_x
;
1053 const unsigned int width
= unscaled_x_right
> left_right_column
1054 ? (unsigned int) unscaled_x_right
- left_right_column
1056 const double right
= unscaled_x_right
> left_right_column
1057 ? unscaled_x_right
- floor(unscaled_x_right
)
1063 /* Now use these informations to compute a good alpha,
1064 and lightness. The sum is on each of the 9
1065 region's surface and alpha and lightness.
1067 transformed alpha = sum(surface * alpha) / sum(surface)
1068 transformed color = sum(surface * alpha * color) / sum(surface * alpha)
1070 /* 1: top left part */
1071 base
= spu
->stride
* (unsigned int) unscaled_y
;
1072 tmp
= left
* top
* canon_alpha(spu
->aimage
[base
+ (unsigned int) unscaled_x
]);
1074 color
+= tmp
* spu
->image
[base
+ (unsigned int) unscaled_x
];
1075 /* 2: top center part */
1078 for (walkx
= left_right_column
; walkx
< (unsigned int) unscaled_x_right
; ++walkx
) {
1079 base
= spu
->stride
* (unsigned int) unscaled_y
+ walkx
;
1080 tmp
= /* 1.0 * */ top
* canon_alpha(spu
->aimage
[base
]);
1082 color
+= tmp
* spu
->image
[base
];
1085 /* 3: top right part */
1087 base
= spu
->stride
* (unsigned int) unscaled_y
+ (unsigned int) unscaled_x_right
;
1088 tmp
= right
* top
* canon_alpha(spu
->aimage
[base
]);
1090 color
+= tmp
* spu
->image
[base
];
1092 /* 4: center left part */
1095 for (walky
= top_low_row
; walky
< (unsigned int) unscaled_y_bottom
; ++walky
) {
1096 base
= spu
->stride
* walky
+ (unsigned int) unscaled_x
;
1097 tmp
= left
/* * 1.0 */ * canon_alpha(spu
->aimage
[base
]);
1099 color
+= tmp
* spu
->image
[base
];
1102 /* 5: center part */
1103 if (width
> 0 && height
> 0) {
1105 for (walky
= top_low_row
; walky
< (unsigned int) unscaled_y_bottom
; ++walky
) {
1107 base
= spu
->stride
* walky
;
1108 for (walkx
= left_right_column
; walkx
< (unsigned int) unscaled_x_right
; ++walkx
) {
1109 tmp
= /* 1.0 * 1.0 * */ canon_alpha(spu
->aimage
[base
+ walkx
]);
1111 color
+= tmp
* spu
->image
[base
+ walkx
];
1115 /* 6: center right part */
1116 if (right
> 0.0 && height
> 0) {
1118 for (walky
= top_low_row
; walky
< (unsigned int) unscaled_y_bottom
; ++walky
) {
1119 base
= spu
->stride
* walky
+ (unsigned int) unscaled_x_right
;
1120 tmp
= right
/* * 1.0 */ * canon_alpha(spu
->aimage
[base
]);
1122 color
+= tmp
* spu
->image
[base
];
1125 /* 7: bottom left part */
1127 base
= spu
->stride
* (unsigned int) unscaled_y_bottom
+ (unsigned int) unscaled_x
;
1128 tmp
= left
* bottom
* canon_alpha(spu
->aimage
[base
]);
1130 color
+= tmp
* spu
->image
[base
];
1132 /* 8: bottom center part */
1133 if (width
> 0 && bottom
> 0.0) {
1135 base
= spu
->stride
* (unsigned int) unscaled_y_bottom
;
1136 for (walkx
= left_right_column
; walkx
< (unsigned int) unscaled_x_right
; ++walkx
) {
1137 tmp
= /* 1.0 * */ bottom
* canon_alpha(spu
->aimage
[base
+ walkx
]);
1139 color
+= tmp
* spu
->image
[base
+ walkx
];
1142 /* 9: bottom right part */
1143 if (right
> 0.0 && bottom
> 0.0) {
1144 base
= spu
->stride
* (unsigned int) unscaled_y_bottom
+ (unsigned int) unscaled_x_right
;
1145 tmp
= right
* bottom
* canon_alpha(spu
->aimage
[base
]);
1147 color
+= tmp
* spu
->image
[base
];
1149 /* Finally mix these transparency and brightness information suitably */
1150 base
= spu
->scaled_stride
* y
+ x
;
1151 spu
->scaled_image
[base
] = alpha
> 0 ? color
/ alpha
: 0;
1152 spu
->scaled_aimage
[base
] = alpha
* scalex
* scaley
/ 0x10000;
1153 if (spu
->scaled_aimage
[base
]) {
1154 spu
->scaled_aimage
[base
] = 256 - spu
->scaled_aimage
[base
];
1155 if (spu
->scaled_aimage
[base
] + spu
->scaled_image
[base
] > 255)
1156 spu
->scaled_image
[base
] = 256 - spu
->scaled_aimage
[base
];
1163 /* Kludge: draw_alpha needs width multiple of 8. */
1164 if (spu
->scaled_width
< spu
->scaled_stride
)
1165 for (y
= 0; y
< spu
->scaled_height
; ++y
) {
1166 memset(spu
->scaled_aimage
+ y
* spu
->scaled_stride
+ spu
->scaled_width
, 0,
1167 spu
->scaled_stride
- spu
->scaled_width
);
1169 spu
->scaled_frame_width
= dxs
;
1170 spu
->scaled_frame_height
= dys
;
1173 if (spu
->scaled_image
){
1174 switch (spu_alignment
) {
1176 spu
->scaled_start_row
= dys
*sub_pos
/100;
1177 if (spu
->scaled_start_row
+ spu
->scaled_height
> dys
)
1178 spu
->scaled_start_row
= dys
- spu
->scaled_height
;
1181 spu
->scaled_start_row
= dys
*sub_pos
/100 - spu
->scaled_height
/2;
1182 if (sub_pos
>= 50 && spu
->scaled_start_row
+ spu
->scaled_height
> dys
)
1183 spu
->scaled_start_row
= dys
- spu
->scaled_height
;
1186 spu
->scaled_start_row
= dys
*sub_pos
/100 - spu
->scaled_height
;
1189 draw_alpha(ctx
, spu
->scaled_start_col
, spu
->scaled_start_row
, spu
->scaled_width
, spu
->scaled_height
,
1190 spu
->scaled_image
, spu
->scaled_aimage
, spu
->scaled_stride
);
1191 spu
->spu_changed
= 0;
1197 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"SPU not displayed: start_pts=%d end_pts=%d now_pts=%d\n",
1198 spu
->start_pts
, spu
->end_pts
, spu
->now_pts
);
1202 void spudec_set_font_factor(void * this, double factor
)
1204 spudec_handle_t
*spu
= this;
1205 spu
->font_start_level
= (int)(0xF0-(0xE0*factor
));
1208 static void spudec_parse_extradata(spudec_handle_t
*this,
1209 uint8_t *extradata
, int extradata_len
)
1211 uint8_t *buffer
, *ptr
;
1212 unsigned int *pal
= this->global_palette
, *cuspal
= this->cuspal
;
1216 if (extradata_len
== 16*4) {
1217 for (i
=0; i
<16; i
++)
1218 pal
[i
] = AV_RB32(extradata
+ i
*4);
1219 this->auto_palette
= 0;
1223 if (!(ptr
= buffer
= malloc(extradata_len
+1)))
1225 memcpy(buffer
, extradata
, extradata_len
);
1226 buffer
[extradata_len
] = 0;
1231 if (!strncmp(ptr
, "size: ", 6))
1232 sscanf(ptr
+ 6, "%dx%d", &this->orig_frame_width
, &this->orig_frame_height
);
1233 if (!strncmp(ptr
, "palette: ", 9) &&
1234 sscanf(ptr
+ 9, "%x, %x, %x, %x, %x, %x, %x, %x, "
1235 "%x, %x, %x, %x, %x, %x, %x, %x",
1236 &pal
[ 0], &pal
[ 1], &pal
[ 2], &pal
[ 3],
1237 &pal
[ 4], &pal
[ 5], &pal
[ 6], &pal
[ 7],
1238 &pal
[ 8], &pal
[ 9], &pal
[10], &pal
[11],
1239 &pal
[12], &pal
[13], &pal
[14], &pal
[15]) == 16) {
1240 for (i
=0; i
<16; i
++)
1241 pal
[i
] = vobsub_palette_to_yuv(pal
[i
]);
1242 this->auto_palette
= 0;
1244 if (!strncasecmp(ptr
, "forced subs: on", 15))
1245 this->forced_subs_only
= 1;
1246 if (!strncmp(ptr
, "custom colors: ON, tridx: ", 26) &&
1247 sscanf(ptr
+ 26, "%x, colors: %x, %x, %x, %x",
1248 &tridx
, cuspal
+0, cuspal
+1, cuspal
+2, cuspal
+3) == 5) {
1249 for (i
=0; i
<4; i
++) {
1250 cuspal
[i
] = vobsub_rgb_to_yuv(cuspal
[i
]);
1251 if (tridx
& (1 << (12-4*i
)))
1252 cuspal
[i
] |= 1 << 31;
1256 } while ((ptr
=strchr(ptr
,'\n')) && *++ptr
);
1261 void *spudec_new_scaled(unsigned int *palette
, unsigned int frame_width
, unsigned int frame_height
, uint8_t *extradata
, int extradata_len
)
1263 spudec_handle_t
*this = calloc(1, sizeof(spudec_handle_t
));
1265 this->orig_frame_height
= frame_height
;
1266 this->orig_frame_width
= frame_width
;
1269 memcpy(this->global_palette
, palette
, sizeof(this->global_palette
));
1271 this->auto_palette
= 1;
1273 spudec_parse_extradata(this, extradata
, extradata_len
);
1274 /* XXX Although the video frame is some size, the SPU frame is
1275 always maximum size i.e. 720 wide and 576 or 480 high */
1276 // For HD files in MKV the VobSub resolution can be higher though,
1277 // see largeres_vobsub.mkv
1278 if (this->orig_frame_width
<= 720 && this->orig_frame_height
<= 576) {
1279 this->orig_frame_width
= 720;
1280 if (this->orig_frame_height
== 480 || this->orig_frame_height
== 240)
1281 this->orig_frame_height
= 480;
1283 this->orig_frame_height
= 576;
1287 mp_msg(MSGT_SPUDEC
,MSGL_FATAL
, "FATAL: spudec_init: calloc");
1291 void *spudec_new(unsigned int *palette
)
1293 return spudec_new_scaled(palette
, 0, 0, NULL
, 0);
1296 void spudec_free(void *this)
1298 spudec_handle_t
*spu
= this;
1300 while (spu
->queue_head
)
1301 spudec_free_packet(spudec_dequeue_packet(spu
));
1304 free(spu
->scaled_image
);
1305 spu
->scaled_image
= NULL
;
1309 free(spu
->pal_image
);
1310 spu
->pal_image
= NULL
;
1311 spu
->image_size
= 0;
1312 spu
->pal_width
= spu
->pal_height
= 0;
1318 * palette must contain at least 256 32-bit entries, otherwise crashes
1321 void spudec_set_paletted(void *this, const uint8_t *pal_img
, int pal_stride
,
1322 const void *palette
,
1323 int x
, int y
, int w
, int h
,
1324 double pts
, double endpts
)
1327 uint16_t g8a8_pal
[256];
1329 const uint32_t *pal
= palette
;
1330 spudec_handle_t
*spu
= this;
1333 int stride
= (w
+ 7) & ~7;
1334 if ((unsigned)w
>= 0x8000 || (unsigned)h
> 0x4000)
1336 packet
= calloc(1, sizeof(packet_t
));
1337 packet
->is_decoded
= 1;
1340 packet
->stride
= stride
;
1341 packet
->start_col
= x
;
1342 packet
->start_row
= y
;
1343 packet
->data_len
= 2 * stride
* h
;
1344 if (packet
->data_len
) { // size 0 is a special "clear" packet
1345 packet
->packet
= malloc(packet
->data_len
);
1346 img
= packet
->packet
;
1347 aimg
= packet
->packet
+ stride
* h
;
1348 for (i
= 0; i
< 256; i
++) {
1349 uint32_t pixel
= pal
[i
];
1350 int alpha
= pixel
>> 24;
1351 int gray
= (((pixel
& 0x000000ff) >> 0) +
1352 ((pixel
& 0x0000ff00) >> 7) +
1353 ((pixel
& 0x00ff0000) >> 16)) >> 2;
1354 gray
= FFMIN(gray
, alpha
);
1355 g8a8_pal
[i
] = (-alpha
<< 8) | gray
;
1357 pal2gray_alpha(g8a8_pal
, pal_img
, pal_stride
,
1358 img
, aimg
, stride
, w
, h
);
1360 packet
->start_pts
= 0;
1361 packet
->end_pts
= 0x7fffffff;
1362 if (pts
!= MP_NOPTS_VALUE
)
1363 packet
->start_pts
= pts
* 90000;
1364 if (endpts
!= MP_NOPTS_VALUE
)
1365 packet
->end_pts
= endpts
* 90000;
1366 spudec_queue_packet(spu
, packet
);