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
, end_col
;
73 unsigned int start_row
, end_row
;
74 unsigned int width
, height
, stride
;
75 unsigned int start_pts
, end_pts
;
82 unsigned int global_palette
[16];
83 unsigned int orig_frame_width
, orig_frame_height
;
84 unsigned char* packet
;
85 size_t packet_reserve
; /* size of the memory pointed to by packet */
86 unsigned int packet_offset
; /* end of the currently assembled fragment */
87 unsigned int packet_size
; /* size of the packet once all fragments are assembled */
88 int packet_pts
; /* PTS for this packet */
89 unsigned int palette
[4];
90 unsigned int alpha
[4];
91 unsigned int cuspal
[4];
94 unsigned int start_pts
, end_pts
;
95 unsigned int start_col
, end_col
;
96 unsigned int start_row
, end_row
;
97 unsigned int width
, height
, stride
;
98 size_t image_size
; /* Size of the image buffer */
99 unsigned char *image
; /* Grayscale value */
100 unsigned char *aimage
; /* Alpha value */
101 unsigned int scaled_frame_width
, scaled_frame_height
;
102 unsigned int scaled_start_col
, scaled_start_row
;
103 unsigned int scaled_width
, scaled_height
, scaled_stride
;
104 size_t scaled_image_size
;
105 unsigned char *scaled_image
;
106 unsigned char *scaled_aimage
;
107 int auto_palette
; /* 1 if we lack a palette and must use an heuristic. */
108 int font_start_level
; /* Darkest value used for the computed font */
111 unsigned int forced_subs_only
; /* flag: 0=display all subtitle, !0 display only forced subtitles */
112 unsigned int is_forced_sub
; /* true if current subtitle is a forced subtitle */
115 static void spudec_queue_packet(spudec_handle_t
*this, packet_t
*packet
)
117 if (this->queue_head
== NULL
)
118 this->queue_head
= packet
;
120 this->queue_tail
->next
= packet
;
121 this->queue_tail
= packet
;
124 static packet_t
*spudec_dequeue_packet(spudec_handle_t
*this)
126 packet_t
*retval
= this->queue_head
;
128 this->queue_head
= retval
->next
;
129 if (this->queue_head
== NULL
)
130 this->queue_tail
= NULL
;
135 static void spudec_free_packet(packet_t
*packet
)
137 if (packet
->packet
!= NULL
)
138 free(packet
->packet
);
142 static inline unsigned int get_be16(const unsigned char *p
)
144 return (p
[0] << 8) + p
[1];
147 static inline unsigned int get_be24(const unsigned char *p
)
149 return (get_be16(p
) << 8) + p
[2];
152 static void next_line(packet_t
*packet
)
154 if (packet
->current_nibble
[packet
->deinterlace_oddness
] % 2)
155 packet
->current_nibble
[packet
->deinterlace_oddness
]++;
156 packet
->deinterlace_oddness
= (packet
->deinterlace_oddness
+ 1) % 2;
159 static inline unsigned char get_nibble(packet_t
*packet
)
162 unsigned int *nibblep
= packet
->current_nibble
+ packet
->deinterlace_oddness
;
163 if (*nibblep
/ 2 >= packet
->control_start
) {
164 mp_msg(MSGT_SPUDEC
,MSGL_WARN
, "SPUdec: ERROR: get_nibble past end of packet\n");
167 nib
= packet
->packet
[*nibblep
/ 2];
176 /* Cut the sub to visible part */
177 static inline void spudec_cut_image(spudec_handle_t
*this)
180 unsigned int first_y
, last_y
;
181 unsigned char *image
;
182 unsigned char *aimage
;
184 if (this->stride
== 0 || this->height
== 0) {
188 for (fy
= 0; fy
< this->image_size
&& !this->aimage
[fy
]; fy
++);
189 for (ly
= this->stride
* this->height
-1; ly
&& !this->aimage
[ly
]; ly
--);
190 first_y
= fy
/ this->stride
;
191 last_y
= ly
/ this->stride
;
192 //printf("first_y: %d, last_y: %d\n", first_y, last_y);
193 this->start_row
+= first_y
;
195 // Some subtitles trigger this condition
196 if (last_y
+ 1 > first_y
) {
197 this->height
= last_y
- first_y
+1;
200 this->image_size
= 0;
204 // printf("new h %d new start %d (sz %d st %d)---\n\n", this->height, this->start_row, this->image_size, this->stride);
206 image
= malloc(2 * this->stride
* this->height
);
208 this->image_size
= this->stride
* this->height
;
209 aimage
= image
+ this->image_size
;
210 memcpy(image
, this->image
+ this->stride
* first_y
, this->image_size
);
211 memcpy(aimage
, this->aimage
+ this->stride
* first_y
, this->image_size
);
214 this->aimage
= aimage
;
216 mp_msg(MSGT_SPUDEC
, MSGL_FATAL
, "Fatal: update_spu: malloc requested %d bytes\n", 2 * 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 this->image_size
= 0;
232 this->image
= malloc(2 * this->stride
* this->height
);
234 this->image_size
= this->stride
* this->height
;
235 this->aimage
= this->image
+ this->image_size
;
238 return this->image
!= NULL
;
241 static void spudec_process_data(spudec_handle_t
*this, packet_t
*packet
)
243 unsigned int cmap
[4], alpha
[4];
244 unsigned int i
, x
, y
;
246 this->scaled_frame_width
= 0;
247 this->scaled_frame_height
= 0;
248 this->start_col
= packet
->start_col
;
249 this->end_col
= packet
->end_col
;
250 this->start_row
= packet
->start_row
;
251 this->end_row
= packet
->end_row
;
252 this->height
= packet
->height
;
253 this->width
= packet
->width
;
254 this->stride
= packet
->stride
;
255 for (i
= 0; i
< 4; ++i
) {
256 alpha
[i
] = packet
->alpha
[i
];
258 alpha
[i
] |= alpha
[i
] << 4;
259 if (this->custom
&& (this->cuspal
[i
] >> 31) != 0)
261 cmap
[i
] = this->custom
? this->cuspal
[i
] :
262 this->global_palette
[packet
->palette
[i
]];
263 cmap
[i
] = (cmap
[i
] >> 16) & 0xff;
264 // convert to MPlayer format
265 cmap
[i
] = FFMIN(cmap
[i
], alpha
[i
]);
266 alpha
[i
] = -alpha
[i
];
269 if (!spudec_alloc_image(this, this->stride
, this->height
))
272 /* Kludge: draw_alpha needs width multiple of 8. */
273 if (this->width
< this->stride
)
274 for (y
= 0; y
< this->height
; ++y
) {
275 memset(this->aimage
+ y
* this->stride
+ this->width
, 0, this->stride
- this->width
);
276 /* FIXME: Why is this one needed? */
277 memset(this->image
+ y
* this->stride
+ this->width
, 0, this->stride
- this->width
);
280 i
= packet
->current_nibble
[1];
283 while (packet
->current_nibble
[0] < i
284 && packet
->current_nibble
[1] / 2 < packet
->control_start
285 && y
< this->height
) {
286 unsigned int len
, color
;
287 unsigned int rle
= 0;
288 rle
= get_nibble(packet
);
290 rle
= (rle
<< 4) | get_nibble(packet
);
292 rle
= (rle
<< 4) | get_nibble(packet
);
294 rle
= (rle
<< 4) | get_nibble(packet
);
296 rle
|= ((this->width
- x
) << 2);
300 color
= 3 - (rle
& 0x3);
302 if (len
> this->width
- x
|| len
== 0)
303 len
= this->width
- x
;
304 /* FIXME have to use palette and alpha map*/
305 memset(this->image
+ y
* this->stride
+ x
, cmap
[color
], len
);
306 memset(this->aimage
+ y
* this->stride
+ x
, alpha
[color
], len
);
308 if (x
>= this->width
) {
314 spudec_cut_image(this);
319 This function tries to create a usable palette.
320 It determines how many non-transparent colors are used, and assigns different
321 gray scale values to each color.
322 I tested it with four streams and even got something readable. Half of the
323 times I got black characters with white around and half the reverse.
325 static void compute_palette(spudec_handle_t
*this, packet_t
*packet
)
327 int used
[16],i
,cused
,start
,step
,color
;
329 memset(used
, 0, sizeof(used
));
331 if (packet
->alpha
[i
]) /* !Transparent? */
332 used
[packet
->palette
[i
]] = 1;
333 for (cused
=0, i
=0; i
<16; i
++)
334 if (used
[i
]) cused
++;
340 start
= this->font_start_level
;
341 step
= (0xF0-this->font_start_level
)/(cused
-1);
343 memset(used
, 0, sizeof(used
));
344 for (i
=0; i
<4; i
++) {
345 color
= packet
->palette
[i
];
346 if (packet
->alpha
[i
] && !used
[color
]) { /* not assigned? */
348 this->global_palette
[color
] = start
<<16;
354 static void spudec_process_control(spudec_handle_t
*this, int pts100
)
356 int a
,b
,c
,d
; /* Temporary vars */
357 unsigned int date
, type
;
359 unsigned int start_off
= 0;
360 unsigned int next_off
;
361 unsigned int start_pts
= 0;
362 unsigned int end_pts
= 0;
363 unsigned int current_nibble
[2] = {0, 0};
364 unsigned int control_start
;
365 unsigned int display
= 0;
366 unsigned int start_col
= 0;
367 unsigned int end_col
= 0;
368 unsigned int start_row
= 0;
369 unsigned int end_row
= 0;
370 unsigned int width
= 0;
371 unsigned int height
= 0;
372 unsigned int stride
= 0;
374 control_start
= get_be16(this->packet
+ 2);
375 next_off
= control_start
;
376 while (start_off
!= next_off
) {
377 start_off
= next_off
;
378 date
= get_be16(this->packet
+ start_off
) * 1024;
379 next_off
= get_be16(this->packet
+ start_off
+ 2);
380 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
, "date=%d\n", date
);
382 for (type
= this->packet
[off
++]; type
!= 0xff; type
= this->packet
[off
++]) {
383 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
, "cmd=%d ",type
);
386 /* Menu ID, 1 byte */
387 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Menu ID\n");
388 /* shouldn't a Menu ID type force display start? */
389 start_pts
= pts100
< 0 && -pts100
>= date
? 0 : pts100
+ date
;
392 this->is_forced_sub
=~0; // current subtitle is forced
396 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Start display!\n");
397 start_pts
= pts100
< 0 && -pts100
>= date
? 0 : pts100
+ date
;
400 this->is_forced_sub
=0;
404 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Stop display!\n");
405 end_pts
= pts100
< 0 && -pts100
>= date
? 0 : pts100
+ date
;
409 this->palette
[0] = this->packet
[off
] >> 4;
410 this->palette
[1] = this->packet
[off
] & 0xf;
411 this->palette
[2] = this->packet
[off
+ 1] >> 4;
412 this->palette
[3] = this->packet
[off
+ 1] & 0xf;
413 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Palette %d, %d, %d, %d\n",
414 this->palette
[0], this->palette
[1], this->palette
[2], this->palette
[3]);
419 a
= this->packet
[off
] >> 4;
420 b
= this->packet
[off
] & 0xf;
421 c
= this->packet
[off
+ 1] >> 4;
422 d
= this->packet
[off
+ 1] & 0xf;
423 // Note: some DVDs change these values to create a fade-in/fade-out effect
424 // We can not handle this, so just keep the highest value during the display time.
426 a
= FFMAX(a
, this->alpha
[0]);
427 b
= FFMAX(b
, this->alpha
[1]);
428 c
= FFMAX(c
, this->alpha
[2]);
429 d
= FFMAX(d
, this->alpha
[3]);
435 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Alpha %d, %d, %d, %d\n",
436 this->alpha
[0], this->alpha
[1], this->alpha
[2], this->alpha
[3]);
441 a
= get_be24(this->packet
+ off
);
442 b
= get_be24(this->packet
+ off
+ 3);
445 width
= (end_col
< start_col
) ? 0 : end_col
- start_col
+ 1;
446 stride
= (width
+ 7) & ~7; /* Kludge: draw_alpha needs width multiple of 8 */
449 height
= (end_row
< start_row
) ? 0 : end_row
- start_row
/* + 1 */;
450 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Coords col: %d - %d row: %d - %d (%dx%d)\n",
451 start_col
, end_col
, start_row
, end_row
,
457 current_nibble
[0] = 2 * get_be16(this->packet
+ off
);
458 current_nibble
[1] = 2 * get_be16(this->packet
+ off
+ 2);
459 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Graphic offset 1: %d offset 2: %d\n",
460 current_nibble
[0] / 2, current_nibble
[1] / 2);
464 /* All done, bye-bye */
465 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Done!\n");
469 mp_msg(MSGT_SPUDEC
,MSGL_WARN
,"spudec: Error determining control type 0x%02x. Skipping %d bytes.\n",
470 type
, next_off
- off
);
477 if (end_pts
== UINT_MAX
&& start_off
!= next_off
) {
478 end_pts
= get_be16(this->packet
+ next_off
) * 1024;
479 end_pts
= 1 - pts100
>= end_pts
? 0 : pts100
+ end_pts
- 1;
482 packet_t
*packet
= calloc(1, sizeof(packet_t
));
484 packet
->start_pts
= start_pts
;
485 packet
->end_pts
= end_pts
;
486 packet
->current_nibble
[0] = current_nibble
[0];
487 packet
->current_nibble
[1] = current_nibble
[1];
488 packet
->start_row
= start_row
;
489 packet
->end_row
= end_row
;
490 packet
->start_col
= start_col
;
491 packet
->end_col
= end_col
;
492 packet
->width
= width
;
493 packet
->height
= height
;
494 packet
->stride
= stride
;
495 packet
->control_start
= control_start
;
496 for (i
=0; i
<4; i
++) {
497 packet
->alpha
[i
] = this->alpha
[i
];
498 packet
->palette
[i
] = this->palette
[i
];
500 packet
->packet
= malloc(this->packet_size
);
501 memcpy(packet
->packet
, this->packet
, this->packet_size
);
502 spudec_queue_packet(this, packet
);
507 static void spudec_decode(spudec_handle_t
*this, int pts100
)
510 spudec_process_control(this, pts100
);
511 else if (pts100
>= 0) {
512 static vo_mpegpes_t packet
= { NULL
, 0, 0x20, 0 };
513 static vo_mpegpes_t
*pkg
=&packet
;
514 packet
.data
= this->packet
;
515 packet
.size
= this->packet_size
;
516 packet
.timestamp
= pts100
;
517 vo_draw_frame(this->hw_spu
, (uint8_t**)&pkg
);
521 int spudec_changed(void * this)
523 spudec_handle_t
* spu
= this;
524 return spu
->spu_changed
|| spu
->now_pts
> spu
->end_pts
;
527 void spudec_assemble(void *this, unsigned char *packet
, unsigned int len
, int pts100
)
529 spudec_handle_t
*spu
= this;
530 // spudec_heartbeat(this, pts100);
532 mp_msg(MSGT_SPUDEC
,MSGL_WARN
,"SPUasm: packet too short\n");
535 spu
->packet_pts
= pts100
;
536 if (spu
->packet_offset
== 0) {
537 unsigned int len2
= get_be16(packet
);
538 // Start new fragment
539 if (spu
->packet_reserve
< len2
) {
540 if (spu
->packet
!= NULL
)
542 spu
->packet
= malloc(len2
);
543 spu
->packet_reserve
= spu
->packet
!= NULL
? len2
: 0;
545 if (spu
->packet
!= NULL
) {
546 spu
->packet_size
= len2
;
548 mp_msg(MSGT_SPUDEC
,MSGL_WARN
,"SPUasm: invalid frag len / len2: %d / %d \n", len
, len2
);
551 memcpy(spu
->packet
, packet
, len
);
552 spu
->packet_offset
= len
;
553 spu
->packet_pts
= pts100
;
556 // Continue current fragment
557 if (spu
->packet_size
< spu
->packet_offset
+ len
){
558 mp_msg(MSGT_SPUDEC
,MSGL_WARN
,"SPUasm: invalid fragment\n");
559 spu
->packet_size
= spu
->packet_offset
= 0;
562 memcpy(spu
->packet
+ spu
->packet_offset
, packet
, len
);
563 spu
->packet_offset
+= len
;
567 // check if we have a complete packet (unfortunatelly packet_size is bad
569 // [cb] packet_size is padded to be even -> may be one byte too long
570 if ((spu
->packet_offset
== spu
->packet_size
) ||
571 ((spu
->packet_offset
+ 1) == spu
->packet_size
)){
573 while(x
+4<=spu
->packet_offset
){
574 y
=get_be16(spu
->packet
+x
+2); // next control pointer
575 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"SPUtest: x=%d y=%d off=%d size=%d\n",x
,y
,spu
->packet_offset
,spu
->packet_size
);
576 if(x
>=4 && x
==y
){ // if it points to self - we're done!
578 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"SPUgot: off=%d size=%d \n",spu
->packet_offset
,spu
->packet_size
);
579 spudec_decode(spu
, pts100
);
580 spu
->packet_offset
= 0;
583 if(y
<=x
|| y
>=spu
->packet_size
){ // invalid?
584 mp_msg(MSGT_SPUDEC
,MSGL_WARN
,"SPUtest: broken packet!!!!! y=%d < x=%d\n",y
,x
);
585 spu
->packet_size
= spu
->packet_offset
= 0;
590 // [cb] packet is done; start new packet
591 spu
->packet_offset
= 0;
594 if (spu
->packet_offset
== spu
->packet_size
) {
595 spudec_decode(spu
, pts100
);
596 spu
->packet_offset
= 0;
601 void spudec_reset(void *this) // called after seek
603 spudec_handle_t
*spu
= this;
604 while (spu
->queue_head
)
605 spudec_free_packet(spudec_dequeue_packet(spu
));
608 spu
->packet_size
= spu
->packet_offset
= 0;
611 void spudec_heartbeat(void *this, unsigned int pts100
)
613 spudec_handle_t
*spu
= this;
614 spu
->now_pts
= pts100
;
616 // TODO: detect and handle broken timestamps (e.g. due to wrapping)
617 while (spu
->queue_head
!= NULL
&& pts100
>= spu
->queue_head
->start_pts
) {
618 packet_t
*packet
= spudec_dequeue_packet(spu
);
619 spu
->start_pts
= packet
->start_pts
;
620 spu
->end_pts
= packet
->end_pts
;
621 if (packet
->is_decoded
) {
623 spu
->image_size
= packet
->data_len
;
624 spu
->image
= packet
->packet
;
625 spu
->aimage
= packet
->packet
+ packet
->stride
* packet
->height
;
626 packet
->packet
= NULL
;
627 spu
->width
= packet
->width
;
628 spu
->height
= packet
->height
;
629 spu
->stride
= packet
->stride
;
630 spu
->start_col
= packet
->start_col
;
631 spu
->start_row
= packet
->start_row
;
633 // reset scaled image
634 spu
->scaled_frame_width
= 0;
635 spu
->scaled_frame_height
= 0;
637 if (spu
->auto_palette
)
638 compute_palette(spu
, packet
);
639 spudec_process_data(spu
, packet
);
641 spudec_free_packet(packet
);
642 spu
->spu_changed
= 1;
646 int spudec_visible(void *this){
647 spudec_handle_t
*spu
= this;
648 int ret
=(spu
->start_pts
<= spu
->now_pts
&&
649 spu
->now_pts
< spu
->end_pts
&&
651 // printf("spu visible: %d \n",ret);
655 void spudec_set_forced_subs_only(void * const this, const unsigned int flag
)
658 ((spudec_handle_t
*)this)->forced_subs_only
=flag
;
659 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"SPU: Display only forced subs now %s\n", flag
? "enabled": "disabled");
663 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
)
665 spudec_handle_t
*spu
= this;
666 if (spudec_visible(spu
))
668 draw_alpha(ctx
, spu
->start_col
, spu
->start_row
, spu
->width
, spu
->height
,
669 spu
->image
, spu
->aimage
, spu
->stride
);
670 spu
->spu_changed
= 0;
674 /* calc the bbox for spudec subs */
675 void spudec_calc_bbox(void *me
, unsigned int dxs
, unsigned int dys
, unsigned int* bbox
)
677 spudec_handle_t
*spu
= me
;
678 if (spu
->orig_frame_width
== 0 || spu
->orig_frame_height
== 0
679 || (spu
->orig_frame_width
== dxs
&& spu
->orig_frame_height
== dys
)) {
681 bbox
[0] = spu
->start_col
;
682 bbox
[1] = spu
->start_col
+ spu
->width
;
683 bbox
[2] = spu
->start_row
;
684 bbox
[3] = spu
->start_row
+ spu
->height
;
688 unsigned int scalex
= 0x100 * dxs
/ spu
->orig_frame_width
;
689 unsigned int scaley
= 0x100 * dys
/ spu
->orig_frame_height
;
690 bbox
[0] = spu
->start_col
* scalex
/ 0x100;
691 bbox
[1] = spu
->start_col
* scalex
/ 0x100 + spu
->width
* scalex
/ 0x100;
692 switch (spu_alignment
) {
694 bbox
[3] = dys
*sub_pos
/100 + spu
->height
* scaley
/ 0x100;
695 if (bbox
[3] > dys
) bbox
[3] = dys
;
696 bbox
[2] = bbox
[3] - spu
->height
* scaley
/ 0x100;
700 bbox
[2] = dys
*sub_pos
/100 - spu
->height
* scaley
/ 0x200;
701 bbox
[3] = bbox
[2] + spu
->height
;
703 bbox
[3] = dys
*sub_pos
/100 + spu
->height
* scaley
/ 0x200;
704 if (bbox
[3] > dys
) bbox
[3] = dys
;
705 bbox
[2] = bbox
[3] - spu
->height
* scaley
/ 0x100;
709 bbox
[2] = dys
*sub_pos
/100 - spu
->height
* scaley
/ 0x100;
710 bbox
[3] = bbox
[2] + spu
->height
;
713 bbox
[2] = spu
->start_row
* scaley
/ 0x100;
714 bbox
[3] = spu
->start_row
* scaley
/ 0x100 + spu
->height
* scaley
/ 0x100;
719 /* transform mplayer's alpha value into an opacity value that is linear */
720 static inline int canon_alpha(int alpha
)
722 return (uint8_t)-alpha
;
732 static void scale_table(unsigned int start_src
, unsigned int start_tar
, unsigned int end_src
, unsigned int end_tar
, scale_pixel
* table
)
735 unsigned int delta_src
= end_src
- start_src
;
736 unsigned int delta_tar
= end_tar
- start_tar
;
739 if (delta_src
== 0 || delta_tar
== 0) {
742 src_step
= (delta_src
<< 16) / delta_tar
>>1;
743 for (t
= 0; t
<=delta_tar
; src
+= (src_step
<< 1), t
++){
744 table
[t
].position
= FFMIN(src
>> 16, end_src
- 1);
745 table
[t
].right_down
= src
& 0xffff;
746 table
[t
].left_up
= 0x10000 - table
[t
].right_down
;
750 /* bilinear scale, similar to vobsub's code */
751 static void scale_image(int x
, int y
, scale_pixel
* table_x
, scale_pixel
* table_y
, spudec_handle_t
* spu
)
755 unsigned int scale
[4];
756 int base
= table_y
[y
].position
* spu
->stride
+ table_x
[x
].position
;
757 int scaled
= y
* spu
->scaled_stride
+ x
;
758 alpha
[0] = canon_alpha(spu
->aimage
[base
]);
759 alpha
[1] = canon_alpha(spu
->aimage
[base
+ 1]);
760 alpha
[2] = canon_alpha(spu
->aimage
[base
+ spu
->stride
]);
761 alpha
[3] = canon_alpha(spu
->aimage
[base
+ spu
->stride
+ 1]);
762 color
[0] = spu
->image
[base
];
763 color
[1] = spu
->image
[base
+ 1];
764 color
[2] = spu
->image
[base
+ spu
->stride
];
765 color
[3] = spu
->image
[base
+ spu
->stride
+ 1];
766 scale
[0] = (table_x
[x
].left_up
* table_y
[y
].left_up
>> 16) * alpha
[0];
767 if (table_y
[y
].left_up
== 0x10000) // necessary to avoid overflow-case
768 scale
[0] = table_x
[x
].left_up
* alpha
[0];
769 scale
[1] = (table_x
[x
].right_down
* table_y
[y
].left_up
>>16) * alpha
[1];
770 scale
[2] = (table_x
[x
].left_up
* table_y
[y
].right_down
>> 16) * alpha
[2];
771 scale
[3] = (table_x
[x
].right_down
* table_y
[y
].right_down
>> 16) * alpha
[3];
772 spu
->scaled_image
[scaled
] = (color
[0] * scale
[0] + color
[1] * scale
[1] + color
[2] * scale
[2] + color
[3] * scale
[3])>>24;
773 spu
->scaled_aimage
[scaled
] = (scale
[0] + scale
[1] + scale
[2] + scale
[3]) >> 16;
774 if (spu
->scaled_aimage
[scaled
]){
775 // ensure that MPlayer's simplified alpha-blending can not overflow
776 spu
->scaled_image
[scaled
] = FFMIN(spu
->scaled_image
[scaled
], spu
->scaled_aimage
[scaled
]);
777 // convert to MPlayer-style alpha
778 spu
->scaled_aimage
[scaled
] = -spu
->scaled_aimage
[scaled
];
782 static void sws_spu_image(unsigned char *d1
, unsigned char *d2
, int dw
, int dh
,
783 int ds
, unsigned char *s1
, unsigned char *s2
, int sw
,
786 struct SwsContext
*ctx
;
787 static SwsFilter filter
;
788 static int firsttime
= 1;
792 if (!firsttime
&& oldvar
!= spu_gaussvar
) sws_freeVec(filter
.lumH
);
794 filter
.lumH
= filter
.lumV
=
795 filter
.chrH
= filter
.chrV
= sws_getGaussianVec(spu_gaussvar
, 3.0);
796 sws_normalizeVec(filter
.lumH
, 1.0);
798 oldvar
= spu_gaussvar
;
801 ctx
=sws_getContext(sw
, sh
, PIX_FMT_GRAY8
, dw
, dh
, PIX_FMT_GRAY8
, SWS_GAUSS
, &filter
, NULL
, NULL
);
802 sws_scale(ctx
,&s1
,&ss
,0,sh
,&d1
,&ds
);
803 for (i
=ss
*sh
-1; i
>=0; i
--) if (!s2
[i
]) s2
[i
] = 255; //else s2[i] = 1;
804 sws_scale(ctx
,&s2
,&ss
,0,sh
,&d2
,&ds
);
805 for (i
=ds
*dh
-1; i
>=0; i
--) if (d2
[i
]==0) d2
[i
] = 1; else if (d2
[i
]==255) d2
[i
] = 0;
806 sws_freeContext(ctx
);
809 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
)
811 spudec_handle_t
*spu
= me
;
812 scale_pixel
*table_x
;
813 scale_pixel
*table_y
;
815 if (spudec_visible(spu
)) {
817 // check if only forced subtitles are requested
818 if( (spu
->forced_subs_only
) && !(spu
->is_forced_sub
) ){
822 if (!(spu_aamode
&16) && (spu
->orig_frame_width
== 0 || spu
->orig_frame_height
== 0
823 || (spu
->orig_frame_width
== dxs
&& spu
->orig_frame_height
== dys
))) {
824 spudec_draw(spu
, draw_alpha
, ctx
);
827 if (spu
->scaled_frame_width
!= dxs
|| spu
->scaled_frame_height
!= dys
) { /* Resizing is needed */
828 /* scaled_x = scalex * x / 0x100
829 scaled_y = scaley * y / 0x100
830 order of operations is important because of rounding. */
831 unsigned int scalex
= 0x100 * dxs
/ spu
->orig_frame_width
;
832 unsigned int scaley
= 0x100 * dys
/ spu
->orig_frame_height
;
833 spu
->scaled_start_col
= spu
->start_col
* scalex
/ 0x100;
834 spu
->scaled_start_row
= spu
->start_row
* scaley
/ 0x100;
835 spu
->scaled_width
= spu
->width
* scalex
/ 0x100;
836 spu
->scaled_height
= spu
->height
* scaley
/ 0x100;
837 /* Kludge: draw_alpha needs width multiple of 8 */
838 spu
->scaled_stride
= (spu
->scaled_width
+ 7) & ~7;
839 if (spu
->scaled_image_size
< spu
->scaled_stride
* spu
->scaled_height
) {
840 if (spu
->scaled_image
) {
841 free(spu
->scaled_image
);
842 spu
->scaled_image_size
= 0;
844 spu
->scaled_image
= malloc(2 * spu
->scaled_stride
* spu
->scaled_height
);
845 if (spu
->scaled_image
) {
846 spu
->scaled_image_size
= spu
->scaled_stride
* spu
->scaled_height
;
847 spu
->scaled_aimage
= spu
->scaled_image
+ spu
->scaled_image_size
;
850 if (spu
->scaled_image
) {
852 if (spu
->scaled_width
<= 1 || spu
->scaled_height
<= 1) {
855 switch(spu_aamode
&15) {
857 sws_spu_image(spu
->scaled_image
, spu
->scaled_aimage
,
858 spu
->scaled_width
, spu
->scaled_height
, spu
->scaled_stride
,
859 spu
->image
, spu
->aimage
, spu
->width
, spu
->height
, spu
->stride
);
862 table_x
= calloc(spu
->scaled_width
, sizeof(scale_pixel
));
863 table_y
= calloc(spu
->scaled_height
, sizeof(scale_pixel
));
864 if (!table_x
|| !table_y
) {
865 mp_msg(MSGT_SPUDEC
, MSGL_FATAL
, "Fatal: spudec_draw_scaled: calloc failed\n");
867 scale_table(0, 0, spu
->width
- 1, spu
->scaled_width
- 1, table_x
);
868 scale_table(0, 0, spu
->height
- 1, spu
->scaled_height
- 1, table_y
);
869 for (y
= 0; y
< spu
->scaled_height
; y
++)
870 for (x
= 0; x
< spu
->scaled_width
; x
++)
871 scale_image(x
, y
, table_x
, table_y
, spu
);
876 /* no antialiasing */
877 for (y
= 0; y
< spu
->scaled_height
; ++y
) {
878 int unscaled_y
= y
* 0x100 / scaley
;
879 int strides
= spu
->stride
* unscaled_y
;
880 int scaled_strides
= spu
->scaled_stride
* y
;
881 for (x
= 0; x
< spu
->scaled_width
; ++x
) {
882 int unscaled_x
= x
* 0x100 / scalex
;
883 spu
->scaled_image
[scaled_strides
+ x
] = spu
->image
[strides
+ unscaled_x
];
884 spu
->scaled_aimage
[scaled_strides
+ x
] = spu
->aimage
[strides
+ unscaled_x
];
890 /* Intermediate antialiasing. */
891 for (y
= 0; y
< spu
->scaled_height
; ++y
) {
892 const unsigned int unscaled_top
= y
* spu
->orig_frame_height
/ dys
;
893 unsigned int unscaled_bottom
= (y
+ 1) * spu
->orig_frame_height
/ dys
;
894 if (unscaled_bottom
>= spu
->height
)
895 unscaled_bottom
= spu
->height
- 1;
896 for (x
= 0; x
< spu
->scaled_width
; ++x
) {
897 const unsigned int unscaled_left
= x
* spu
->orig_frame_width
/ dxs
;
898 unsigned int unscaled_right
= (x
+ 1) * spu
->orig_frame_width
/ dxs
;
899 unsigned int color
= 0;
900 unsigned int alpha
= 0;
901 unsigned int walkx
, walky
;
902 unsigned int base
, tmp
;
903 if (unscaled_right
>= spu
->width
)
904 unscaled_right
= spu
->width
- 1;
905 for (walky
= unscaled_top
; walky
<= unscaled_bottom
; ++walky
)
906 for (walkx
= unscaled_left
; walkx
<= unscaled_right
; ++walkx
) {
907 base
= walky
* spu
->stride
+ walkx
;
908 tmp
= canon_alpha(spu
->aimage
[base
]);
910 color
+= tmp
* spu
->image
[base
];
912 base
= y
* spu
->scaled_stride
+ x
;
913 spu
->scaled_image
[base
] = alpha
? color
/ alpha
: 0;
914 spu
->scaled_aimage
[base
] =
915 alpha
* (1 + unscaled_bottom
- unscaled_top
) * (1 + unscaled_right
- unscaled_left
);
916 /* spu->scaled_aimage[base] =
917 alpha * dxs * dys / spu->orig_frame_width / spu->orig_frame_height; */
918 if (spu
->scaled_aimage
[base
]) {
919 spu
->scaled_aimage
[base
] = 256 - spu
->scaled_aimage
[base
];
920 if (spu
->scaled_aimage
[base
] + spu
->scaled_image
[base
] > 255)
921 spu
->scaled_image
[base
] = 256 - spu
->scaled_aimage
[base
];
929 /* Best antialiasing. Very slow. */
930 /* Any pixel (x, y) represents pixels from the original
931 rectangular region comprised between the columns
932 unscaled_y and unscaled_y + 0x100 / scaley and the rows
933 unscaled_x and unscaled_x + 0x100 / scalex
935 The original rectangular region that the scaled pixel
936 represents is cut in 9 rectangular areas like this:
938 +---+-----------------+---+
940 +---+-----------------+---+
944 +---+-----------------+---+
946 +---+-----------------+---+
948 The width of the left column is at most one pixel and
949 it is never null and its right column is at a pixel
950 boundary. The height of the top row is at most one
951 pixel it is never null and its bottom row is at a
952 pixel boundary. The width and height of region 5 are
953 integral values. The width of the right column is
954 what remains and is less than one pixel. The height
955 of the bottom row is what remains and is less than
958 The row above 1, 2, 3 is unscaled_y. The row between
959 1, 2, 3 and 4, 5, 6 is top_low_row. The row between 4,
960 5, 6 and 7, 8, 9 is (unsigned int)unscaled_y_bottom.
961 The row beneath 7, 8, 9 is unscaled_y_bottom.
963 The column left of 1, 4, 7 is unscaled_x. The column
964 between 1, 4, 7 and 2, 5, 8 is left_right_column. The
965 column between 2, 5, 8 and 3, 6, 9 is (unsigned
966 int)unscaled_x_right. The column right of 3, 6, 9 is
968 const double inv_scalex
= (double) 0x100 / scalex
;
969 const double inv_scaley
= (double) 0x100 / scaley
;
970 for (y
= 0; y
< spu
->scaled_height
; ++y
) {
971 const double unscaled_y
= y
* inv_scaley
;
972 const double unscaled_y_bottom
= unscaled_y
+ inv_scaley
;
973 const unsigned int top_low_row
= FFMIN(unscaled_y_bottom
, unscaled_y
+ 1.0);
974 const double top
= top_low_row
- unscaled_y
;
975 const unsigned int height
= unscaled_y_bottom
> top_low_row
976 ? (unsigned int) unscaled_y_bottom
- top_low_row
978 const double bottom
= unscaled_y_bottom
> top_low_row
979 ? unscaled_y_bottom
- floor(unscaled_y_bottom
)
981 for (x
= 0; x
< spu
->scaled_width
; ++x
) {
982 const double unscaled_x
= x
* inv_scalex
;
983 const double unscaled_x_right
= unscaled_x
+ inv_scalex
;
984 const unsigned int left_right_column
= FFMIN(unscaled_x_right
, unscaled_x
+ 1.0);
985 const double left
= left_right_column
- unscaled_x
;
986 const unsigned int width
= unscaled_x_right
> left_right_column
987 ? (unsigned int) unscaled_x_right
- left_right_column
989 const double right
= unscaled_x_right
> left_right_column
990 ? unscaled_x_right
- floor(unscaled_x_right
)
996 /* Now use these informations to compute a good alpha,
997 and lightness. The sum is on each of the 9
998 region's surface and alpha and lightness.
1000 transformed alpha = sum(surface * alpha) / sum(surface)
1001 transformed color = sum(surface * alpha * color) / sum(surface * alpha)
1003 /* 1: top left part */
1004 base
= spu
->stride
* (unsigned int) unscaled_y
;
1005 tmp
= left
* top
* canon_alpha(spu
->aimage
[base
+ (unsigned int) unscaled_x
]);
1007 color
+= tmp
* spu
->image
[base
+ (unsigned int) unscaled_x
];
1008 /* 2: top center part */
1011 for (walkx
= left_right_column
; walkx
< (unsigned int) unscaled_x_right
; ++walkx
) {
1012 base
= spu
->stride
* (unsigned int) unscaled_y
+ walkx
;
1013 tmp
= /* 1.0 * */ top
* canon_alpha(spu
->aimage
[base
]);
1015 color
+= tmp
* spu
->image
[base
];
1018 /* 3: top right part */
1020 base
= spu
->stride
* (unsigned int) unscaled_y
+ (unsigned int) unscaled_x_right
;
1021 tmp
= right
* top
* canon_alpha(spu
->aimage
[base
]);
1023 color
+= tmp
* spu
->image
[base
];
1025 /* 4: center left part */
1028 for (walky
= top_low_row
; walky
< (unsigned int) unscaled_y_bottom
; ++walky
) {
1029 base
= spu
->stride
* walky
+ (unsigned int) unscaled_x
;
1030 tmp
= left
/* * 1.0 */ * canon_alpha(spu
->aimage
[base
]);
1032 color
+= tmp
* spu
->image
[base
];
1035 /* 5: center part */
1036 if (width
> 0 && height
> 0) {
1038 for (walky
= top_low_row
; walky
< (unsigned int) unscaled_y_bottom
; ++walky
) {
1040 base
= spu
->stride
* walky
;
1041 for (walkx
= left_right_column
; walkx
< (unsigned int) unscaled_x_right
; ++walkx
) {
1042 tmp
= /* 1.0 * 1.0 * */ canon_alpha(spu
->aimage
[base
+ walkx
]);
1044 color
+= tmp
* spu
->image
[base
+ walkx
];
1048 /* 6: center right part */
1049 if (right
> 0.0 && height
> 0) {
1051 for (walky
= top_low_row
; walky
< (unsigned int) unscaled_y_bottom
; ++walky
) {
1052 base
= spu
->stride
* walky
+ (unsigned int) unscaled_x_right
;
1053 tmp
= right
/* * 1.0 */ * canon_alpha(spu
->aimage
[base
]);
1055 color
+= tmp
* spu
->image
[base
];
1058 /* 7: bottom left part */
1060 base
= spu
->stride
* (unsigned int) unscaled_y_bottom
+ (unsigned int) unscaled_x
;
1061 tmp
= left
* bottom
* canon_alpha(spu
->aimage
[base
]);
1063 color
+= tmp
* spu
->image
[base
];
1065 /* 8: bottom center part */
1066 if (width
> 0 && bottom
> 0.0) {
1068 base
= spu
->stride
* (unsigned int) unscaled_y_bottom
;
1069 for (walkx
= left_right_column
; walkx
< (unsigned int) unscaled_x_right
; ++walkx
) {
1070 tmp
= /* 1.0 * */ bottom
* canon_alpha(spu
->aimage
[base
+ walkx
]);
1072 color
+= tmp
* spu
->image
[base
+ walkx
];
1075 /* 9: bottom right part */
1076 if (right
> 0.0 && bottom
> 0.0) {
1077 base
= spu
->stride
* (unsigned int) unscaled_y_bottom
+ (unsigned int) unscaled_x_right
;
1078 tmp
= right
* bottom
* canon_alpha(spu
->aimage
[base
]);
1080 color
+= tmp
* spu
->image
[base
];
1082 /* Finally mix these transparency and brightness information suitably */
1083 base
= spu
->scaled_stride
* y
+ x
;
1084 spu
->scaled_image
[base
] = alpha
> 0 ? color
/ alpha
: 0;
1085 spu
->scaled_aimage
[base
] = alpha
* scalex
* scaley
/ 0x10000;
1086 if (spu
->scaled_aimage
[base
]) {
1087 spu
->scaled_aimage
[base
] = 256 - spu
->scaled_aimage
[base
];
1088 if (spu
->scaled_aimage
[base
] + spu
->scaled_image
[base
] > 255)
1089 spu
->scaled_image
[base
] = 256 - spu
->scaled_aimage
[base
];
1096 /* Kludge: draw_alpha needs width multiple of 8. */
1097 if (spu
->scaled_width
< spu
->scaled_stride
)
1098 for (y
= 0; y
< spu
->scaled_height
; ++y
) {
1099 memset(spu
->scaled_aimage
+ y
* spu
->scaled_stride
+ spu
->scaled_width
, 0,
1100 spu
->scaled_stride
- spu
->scaled_width
);
1102 spu
->scaled_frame_width
= dxs
;
1103 spu
->scaled_frame_height
= dys
;
1106 if (spu
->scaled_image
){
1107 switch (spu_alignment
) {
1109 spu
->scaled_start_row
= dys
*sub_pos
/100;
1110 if (spu
->scaled_start_row
+ spu
->scaled_height
> dys
)
1111 spu
->scaled_start_row
= dys
- spu
->scaled_height
;
1114 spu
->scaled_start_row
= dys
*sub_pos
/100 - spu
->scaled_height
/2;
1115 if (sub_pos
>= 50 && spu
->scaled_start_row
+ spu
->scaled_height
> dys
)
1116 spu
->scaled_start_row
= dys
- spu
->scaled_height
;
1119 spu
->scaled_start_row
= dys
*sub_pos
/100 - spu
->scaled_height
;
1122 draw_alpha(ctx
, spu
->scaled_start_col
, spu
->scaled_start_row
, spu
->scaled_width
, spu
->scaled_height
,
1123 spu
->scaled_image
, spu
->scaled_aimage
, spu
->scaled_stride
);
1124 spu
->spu_changed
= 0;
1130 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"SPU not displayed: start_pts=%d end_pts=%d now_pts=%d\n",
1131 spu
->start_pts
, spu
->end_pts
, spu
->now_pts
);
1135 void spudec_update_palette(void * this, unsigned int *palette
)
1137 spudec_handle_t
*spu
= this;
1138 if (spu
&& palette
) {
1139 memcpy(spu
->global_palette
, palette
, sizeof(spu
->global_palette
));
1141 vo_control(spu
->hw_spu
, VOCTRL_SET_SPU_PALETTE
, spu
->global_palette
);
1145 void spudec_set_font_factor(void * this, double factor
)
1147 spudec_handle_t
*spu
= this;
1148 spu
->font_start_level
= (int)(0xF0-(0xE0*factor
));
1151 static void spudec_parse_extradata(spudec_handle_t
*this,
1152 uint8_t *extradata
, int extradata_len
)
1154 uint8_t *buffer
, *ptr
;
1155 unsigned int *pal
= this->global_palette
, *cuspal
= this->cuspal
;
1159 if (extradata_len
== 16*4) {
1160 for (i
=0; i
<16; i
++)
1161 pal
[i
] = AV_RB32(extradata
+ i
*4);
1162 this->auto_palette
= 0;
1166 if (!(ptr
= buffer
= malloc(extradata_len
+1)))
1168 memcpy(buffer
, extradata
, extradata_len
);
1169 buffer
[extradata_len
] = 0;
1174 if (!strncmp(ptr
, "size: ", 6))
1175 sscanf(ptr
+ 6, "%dx%d", &this->orig_frame_width
, &this->orig_frame_height
);
1176 if (!strncmp(ptr
, "palette: ", 9) &&
1177 sscanf(ptr
+ 9, "%x, %x, %x, %x, %x, %x, %x, %x, "
1178 "%x, %x, %x, %x, %x, %x, %x, %x",
1179 &pal
[ 0], &pal
[ 1], &pal
[ 2], &pal
[ 3],
1180 &pal
[ 4], &pal
[ 5], &pal
[ 6], &pal
[ 7],
1181 &pal
[ 8], &pal
[ 9], &pal
[10], &pal
[11],
1182 &pal
[12], &pal
[13], &pal
[14], &pal
[15]) == 16) {
1183 for (i
=0; i
<16; i
++)
1184 pal
[i
] = vobsub_palette_to_yuv(pal
[i
]);
1185 this->auto_palette
= 0;
1187 if (!strncasecmp(ptr
, "forced subs: on", 15))
1188 this->forced_subs_only
= 1;
1189 if (!strncmp(ptr
, "custom colors: ON, tridx: ", 26) &&
1190 sscanf(ptr
+ 26, "%x, colors: %x, %x, %x, %x",
1191 &tridx
, cuspal
+0, cuspal
+1, cuspal
+2, cuspal
+3) == 5) {
1192 for (i
=0; i
<4; i
++) {
1193 cuspal
[i
] = vobsub_rgb_to_yuv(cuspal
[i
]);
1194 if (tridx
& (1 << (12-4*i
)))
1195 cuspal
[i
] |= 1 << 31;
1199 } while ((ptr
=strchr(ptr
,'\n')) && *++ptr
);
1204 void *spudec_new_scaled(unsigned int *palette
, unsigned int frame_width
, unsigned int frame_height
, uint8_t *extradata
, int extradata_len
)
1206 spudec_handle_t
*this = calloc(1, sizeof(spudec_handle_t
));
1208 this->orig_frame_height
= frame_height
;
1209 this->orig_frame_width
= frame_width
;
1212 memcpy(this->global_palette
, palette
, sizeof(this->global_palette
));
1214 this->auto_palette
= 1;
1216 spudec_parse_extradata(this, extradata
, extradata_len
);
1217 /* XXX Although the video frame is some size, the SPU frame is
1218 always maximum size i.e. 720 wide and 576 or 480 high */
1219 // For HD files in MKV the VobSub resolution can be higher though,
1220 // see largeres_vobsub.mkv
1221 if (this->orig_frame_width
<= 720 && this->orig_frame_height
<= 576) {
1222 this->orig_frame_width
= 720;
1223 if (this->orig_frame_height
== 480 || this->orig_frame_height
== 240)
1224 this->orig_frame_height
= 480;
1226 this->orig_frame_height
= 576;
1230 mp_msg(MSGT_SPUDEC
,MSGL_FATAL
, "FATAL: spudec_init: calloc");
1234 void *spudec_new(unsigned int *palette
)
1236 return spudec_new_scaled(palette
, 0, 0, NULL
, 0);
1239 void spudec_free(void *this)
1241 spudec_handle_t
*spu
= this;
1243 while (spu
->queue_head
)
1244 spudec_free_packet(spudec_dequeue_packet(spu
));
1247 if (spu
->scaled_image
)
1248 free(spu
->scaled_image
);
1255 void spudec_set_hw_spu(void *this, struct vo
*hw_spu
)
1257 spudec_handle_t
*spu
= this;
1260 spu
->hw_spu
= hw_spu
;
1261 vo_control(hw_spu
, VOCTRL_SET_SPU_PALETTE
, spu
->global_palette
);
1264 #define MP_NOPTS_VALUE (-1LL<<63) //both int64_t and double should be able to represent this exactly
1267 * palette must contain at least 256 32-bit entries, otherwise crashes
1270 void spudec_set_paletted(void *this, const uint8_t *pal_img
, int pal_stride
,
1271 const void *palette
,
1272 int x
, int y
, int w
, int h
,
1273 double pts
, double endpts
)
1276 uint16_t g8a8_pal
[256];
1278 const uint32_t *pal
= palette
;
1279 spudec_handle_t
*spu
= this;
1282 int stride
= (w
+ 7) & ~7;
1283 if ((unsigned)w
>= 0x8000 || (unsigned)h
> 0x4000)
1285 packet
= calloc(1, sizeof(packet_t
));
1286 packet
->is_decoded
= 1;
1289 packet
->stride
= stride
;
1290 packet
->start_col
= x
;
1291 packet
->start_row
= y
;
1292 packet
->data_len
= 2 * stride
* h
;
1293 packet
->packet
= malloc(packet
->data_len
);
1294 img
= packet
->packet
;
1295 aimg
= packet
->packet
+ stride
* h
;
1296 for (i
= 0; i
< 256; i
++) {
1297 uint32_t pixel
= pal
[i
];
1298 int alpha
= pixel
>> 24;
1299 int gray
= (((pixel
& 0x000000ff) >> 0) +
1300 ((pixel
& 0x0000ff00) >> 7) +
1301 ((pixel
& 0x00ff0000) >> 16)) >> 2;
1302 gray
= FFMIN(gray
, alpha
);
1303 g8a8_pal
[i
] = (-alpha
<< 8) | gray
;
1305 for (y
= 0; y
< h
; y
++) {
1306 for (x
= 0; x
< w
; x
++) {
1307 uint16_t pixel
= g8a8_pal
[pal_img
[x
]];
1309 *aimg
++ = pixel
>> 8;
1311 for (; x
< stride
; x
++)
1312 *aimg
++ = *img
++ = 0;
1313 pal_img
+= pal_stride
;
1315 packet
->start_pts
= 0;
1316 packet
->end_pts
= 0x7fffffff;
1317 if (pts
!= MP_NOPTS_VALUE
)
1318 packet
->start_pts
= pts
* 90000;
1319 if (endpts
!= MP_NOPTS_VALUE
)
1320 packet
->end_pts
= endpts
* 90000;
1321 spudec_queue_packet(spu
, packet
);