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 static inline int mkalpha(int i
)
178 /* In mplayer's alpha planes, 0 is transparent, then 1 is nearly
179 opaque upto 255 which is fully opaque */
182 return (uint8_t)(-i
);
185 /* Cut the sub to visible part */
186 static inline void spudec_cut_image(spudec_handle_t
*this)
189 unsigned int first_y
, last_y
;
190 unsigned char *image
;
191 unsigned char *aimage
;
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;
209 this->image_size
= 0;
213 // printf("new h %d new start %d (sz %d st %d)---\n\n", this->height, this->start_row, this->image_size, this->stride);
215 image
= malloc(2 * this->stride
* this->height
);
217 this->image_size
= this->stride
* this->height
;
218 aimage
= image
+ this->image_size
;
219 memcpy(image
, this->image
+ this->stride
* first_y
, this->image_size
);
220 memcpy(aimage
, this->aimage
+ this->stride
* first_y
, this->image_size
);
223 this->aimage
= aimage
;
225 mp_msg(MSGT_SPUDEC
, MSGL_FATAL
, "Fatal: update_spu: malloc requested %d bytes\n", 2 * this->stride
* this->height
);
230 static int spudec_alloc_image(spudec_handle_t
*this, int stride
, int height
)
232 if (this->width
> stride
) // just a safeguard
233 this->width
= stride
;
234 this->stride
= stride
;
235 this->height
= height
;
236 if (this->image_size
< this->stride
* this->height
) {
237 if (this->image
!= NULL
) {
239 this->image_size
= 0;
241 this->image
= malloc(2 * this->stride
* this->height
);
243 this->image_size
= this->stride
* this->height
;
244 this->aimage
= this->image
+ this->image_size
;
247 return this->image
!= NULL
;
250 static void spudec_process_data(spudec_handle_t
*this, packet_t
*packet
)
252 unsigned int cmap
[4], alpha
[4];
253 unsigned int i
, x
, y
;
255 this->scaled_frame_width
= 0;
256 this->scaled_frame_height
= 0;
257 this->start_col
= packet
->start_col
;
258 this->end_col
= packet
->end_col
;
259 this->start_row
= packet
->start_row
;
260 this->end_row
= packet
->end_row
;
261 this->height
= packet
->height
;
262 this->width
= packet
->width
;
263 this->stride
= packet
->stride
;
264 for (i
= 0; i
< 4; ++i
) {
265 alpha
[i
] = mkalpha(packet
->alpha
[i
]);
266 if (this->custom
&& (this->cuspal
[i
] >> 31) != 0)
270 else if (this->custom
){
271 cmap
[i
] = ((this->cuspal
[i
] >> 16) & 0xff);
272 if (cmap
[i
] + alpha
[i
] > 255)
273 cmap
[i
] = 256 - alpha
[i
];
276 cmap
[i
] = ((this->global_palette
[packet
->palette
[i
]] >> 16) & 0xff);
277 if (cmap
[i
] + alpha
[i
] > 255)
278 cmap
[i
] = 256 - alpha
[i
];
282 if (!spudec_alloc_image(this, this->stride
, this->height
))
285 /* Kludge: draw_alpha needs width multiple of 8. */
286 if (this->width
< this->stride
)
287 for (y
= 0; y
< this->height
; ++y
) {
288 memset(this->aimage
+ y
* this->stride
+ this->width
, 0, this->stride
- this->width
);
289 /* FIXME: Why is this one needed? */
290 memset(this->image
+ y
* this->stride
+ this->width
, 0, this->stride
- this->width
);
293 i
= packet
->current_nibble
[1];
296 while (packet
->current_nibble
[0] < i
297 && packet
->current_nibble
[1] / 2 < packet
->control_start
298 && y
< this->height
) {
299 unsigned int len
, color
;
300 unsigned int rle
= 0;
301 rle
= get_nibble(packet
);
303 rle
= (rle
<< 4) | get_nibble(packet
);
305 rle
= (rle
<< 4) | get_nibble(packet
);
307 rle
= (rle
<< 4) | get_nibble(packet
);
309 rle
|= ((this->width
- x
) << 2);
313 color
= 3 - (rle
& 0x3);
315 if (len
> this->width
- x
|| len
== 0)
316 len
= this->width
- x
;
317 /* FIXME have to use palette and alpha map*/
318 memset(this->image
+ y
* this->stride
+ x
, cmap
[color
], len
);
319 memset(this->aimage
+ y
* this->stride
+ x
, alpha
[color
], len
);
321 if (x
>= this->width
) {
327 spudec_cut_image(this);
332 This function tries to create a usable palette.
333 It determines how many non-transparent colors are used, and assigns different
334 gray scale values to each color.
335 I tested it with four streams and even got something readable. Half of the
336 times I got black characters with white around and half the reverse.
338 static void compute_palette(spudec_handle_t
*this, packet_t
*packet
)
340 int used
[16],i
,cused
,start
,step
,color
;
342 memset(used
, 0, sizeof(used
));
344 if (packet
->alpha
[i
]) /* !Transparent? */
345 used
[packet
->palette
[i
]] = 1;
346 for (cused
=0, i
=0; i
<16; i
++)
347 if (used
[i
]) cused
++;
353 start
= this->font_start_level
;
354 step
= (0xF0-this->font_start_level
)/(cused
-1);
356 memset(used
, 0, sizeof(used
));
357 for (i
=0; i
<4; i
++) {
358 color
= packet
->palette
[i
];
359 if (packet
->alpha
[i
] && !used
[color
]) { /* not assigned? */
361 this->global_palette
[color
] = start
<<16;
367 static void spudec_process_control(spudec_handle_t
*this, int pts100
)
369 int a
,b
,c
,d
; /* Temporary vars */
370 unsigned int date
, type
;
372 unsigned int start_off
= 0;
373 unsigned int next_off
;
374 unsigned int start_pts
= 0;
375 unsigned int end_pts
= 0;
376 unsigned int current_nibble
[2] = {0, 0};
377 unsigned int control_start
;
378 unsigned int display
= 0;
379 unsigned int start_col
= 0;
380 unsigned int end_col
= 0;
381 unsigned int start_row
= 0;
382 unsigned int end_row
= 0;
383 unsigned int width
= 0;
384 unsigned int height
= 0;
385 unsigned int stride
= 0;
387 control_start
= get_be16(this->packet
+ 2);
388 next_off
= control_start
;
389 while (start_off
!= next_off
) {
390 start_off
= next_off
;
391 date
= get_be16(this->packet
+ start_off
) * 1024;
392 next_off
= get_be16(this->packet
+ start_off
+ 2);
393 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
, "date=%d\n", date
);
395 for (type
= this->packet
[off
++]; type
!= 0xff; type
= this->packet
[off
++]) {
396 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
, "cmd=%d ",type
);
399 /* Menu ID, 1 byte */
400 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Menu ID\n");
401 /* shouldn't a Menu ID type force display start? */
402 start_pts
= pts100
< 0 && -pts100
>= date
? 0 : pts100
+ date
;
405 this->is_forced_sub
=~0; // current subtitle is forced
409 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Start display!\n");
410 start_pts
= pts100
< 0 && -pts100
>= date
? 0 : pts100
+ date
;
413 this->is_forced_sub
=0;
417 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Stop display!\n");
418 end_pts
= pts100
< 0 && -pts100
>= date
? 0 : pts100
+ date
;
422 this->palette
[0] = this->packet
[off
] >> 4;
423 this->palette
[1] = this->packet
[off
] & 0xf;
424 this->palette
[2] = this->packet
[off
+ 1] >> 4;
425 this->palette
[3] = this->packet
[off
+ 1] & 0xf;
426 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Palette %d, %d, %d, %d\n",
427 this->palette
[0], this->palette
[1], this->palette
[2], this->palette
[3]);
432 a
= this->packet
[off
] >> 4;
433 b
= this->packet
[off
] & 0xf;
434 c
= this->packet
[off
+ 1] >> 4;
435 d
= this->packet
[off
+ 1] & 0xf;
436 // Note: some DVDs change these values to create a fade-in/fade-out effect
437 // We can not handle this, so just keep the highest value during the display time.
439 a
= FFMAX(a
, this->alpha
[0]);
440 b
= FFMAX(b
, this->alpha
[1]);
441 c
= FFMAX(c
, this->alpha
[2]);
442 d
= FFMAX(d
, this->alpha
[3]);
448 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Alpha %d, %d, %d, %d\n",
449 this->alpha
[0], this->alpha
[1], this->alpha
[2], this->alpha
[3]);
454 a
= get_be24(this->packet
+ off
);
455 b
= get_be24(this->packet
+ off
+ 3);
458 width
= (end_col
< start_col
) ? 0 : end_col
- start_col
+ 1;
459 stride
= (width
+ 7) & ~7; /* Kludge: draw_alpha needs width multiple of 8 */
462 height
= (end_row
< start_row
) ? 0 : end_row
- start_row
/* + 1 */;
463 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Coords col: %d - %d row: %d - %d (%dx%d)\n",
464 start_col
, end_col
, start_row
, end_row
,
470 current_nibble
[0] = 2 * get_be16(this->packet
+ off
);
471 current_nibble
[1] = 2 * get_be16(this->packet
+ off
+ 2);
472 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Graphic offset 1: %d offset 2: %d\n",
473 current_nibble
[0] / 2, current_nibble
[1] / 2);
477 /* All done, bye-bye */
478 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"Done!\n");
482 mp_msg(MSGT_SPUDEC
,MSGL_WARN
,"spudec: Error determining control type 0x%02x. Skipping %d bytes.\n",
483 type
, next_off
- off
);
490 if (end_pts
== UINT_MAX
&& start_off
!= next_off
) {
491 end_pts
= get_be16(this->packet
+ next_off
) * 1024;
492 end_pts
= 1 - pts100
>= end_pts
? 0 : pts100
+ end_pts
- 1;
495 packet_t
*packet
= calloc(1, sizeof(packet_t
));
497 packet
->start_pts
= start_pts
;
498 packet
->end_pts
= end_pts
;
499 packet
->current_nibble
[0] = current_nibble
[0];
500 packet
->current_nibble
[1] = current_nibble
[1];
501 packet
->start_row
= start_row
;
502 packet
->end_row
= end_row
;
503 packet
->start_col
= start_col
;
504 packet
->end_col
= end_col
;
505 packet
->width
= width
;
506 packet
->height
= height
;
507 packet
->stride
= stride
;
508 packet
->control_start
= control_start
;
509 for (i
=0; i
<4; i
++) {
510 packet
->alpha
[i
] = this->alpha
[i
];
511 packet
->palette
[i
] = this->palette
[i
];
513 packet
->packet
= malloc(this->packet_size
);
514 memcpy(packet
->packet
, this->packet
, this->packet_size
);
515 spudec_queue_packet(this, packet
);
520 static void spudec_decode(spudec_handle_t
*this, int pts100
)
523 spudec_process_control(this, pts100
);
524 else if (pts100
>= 0) {
525 static vo_mpegpes_t packet
= { NULL
, 0, 0x20, 0 };
526 static vo_mpegpes_t
*pkg
=&packet
;
527 packet
.data
= this->packet
;
528 packet
.size
= this->packet_size
;
529 packet
.timestamp
= pts100
;
530 vo_draw_frame(this->hw_spu
, (uint8_t**)&pkg
);
534 int spudec_changed(void * this)
536 spudec_handle_t
* spu
= (spudec_handle_t
*)this;
537 return spu
->spu_changed
|| spu
->now_pts
> spu
->end_pts
;
540 void spudec_assemble(void *this, unsigned char *packet
, unsigned int len
, int pts100
)
542 spudec_handle_t
*spu
= (spudec_handle_t
*)this;
543 // spudec_heartbeat(this, pts100);
545 mp_msg(MSGT_SPUDEC
,MSGL_WARN
,"SPUasm: packet too short\n");
548 spu
->packet_pts
= pts100
;
549 if (spu
->packet_offset
== 0) {
550 unsigned int len2
= get_be16(packet
);
551 // Start new fragment
552 if (spu
->packet_reserve
< len2
) {
553 if (spu
->packet
!= NULL
)
555 spu
->packet
= malloc(len2
);
556 spu
->packet_reserve
= spu
->packet
!= NULL
? len2
: 0;
558 if (spu
->packet
!= NULL
) {
559 spu
->packet_size
= len2
;
561 mp_msg(MSGT_SPUDEC
,MSGL_WARN
,"SPUasm: invalid frag len / len2: %d / %d \n", len
, len2
);
564 memcpy(spu
->packet
, packet
, len
);
565 spu
->packet_offset
= len
;
566 spu
->packet_pts
= pts100
;
569 // Continue current fragment
570 if (spu
->packet_size
< spu
->packet_offset
+ len
){
571 mp_msg(MSGT_SPUDEC
,MSGL_WARN
,"SPUasm: invalid fragment\n");
572 spu
->packet_size
= spu
->packet_offset
= 0;
575 memcpy(spu
->packet
+ spu
->packet_offset
, packet
, len
);
576 spu
->packet_offset
+= len
;
580 // check if we have a complete packet (unfortunatelly packet_size is bad
582 // [cb] packet_size is padded to be even -> may be one byte too long
583 if ((spu
->packet_offset
== spu
->packet_size
) ||
584 ((spu
->packet_offset
+ 1) == spu
->packet_size
)){
586 while(x
+4<=spu
->packet_offset
){
587 y
=get_be16(spu
->packet
+x
+2); // next control pointer
588 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"SPUtest: x=%d y=%d off=%d size=%d\n",x
,y
,spu
->packet_offset
,spu
->packet_size
);
589 if(x
>=4 && x
==y
){ // if it points to self - we're done!
591 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"SPUgot: off=%d size=%d \n",spu
->packet_offset
,spu
->packet_size
);
592 spudec_decode(spu
, pts100
);
593 spu
->packet_offset
= 0;
596 if(y
<=x
|| y
>=spu
->packet_size
){ // invalid?
597 mp_msg(MSGT_SPUDEC
,MSGL_WARN
,"SPUtest: broken packet!!!!! y=%d < x=%d\n",y
,x
);
598 spu
->packet_size
= spu
->packet_offset
= 0;
603 // [cb] packet is done; start new packet
604 spu
->packet_offset
= 0;
607 if (spu
->packet_offset
== spu
->packet_size
) {
608 spudec_decode(spu
, pts100
);
609 spu
->packet_offset
= 0;
614 void spudec_reset(void *this) // called after seek
616 spudec_handle_t
*spu
= (spudec_handle_t
*)this;
617 while (spu
->queue_head
)
618 spudec_free_packet(spudec_dequeue_packet(spu
));
621 spu
->packet_size
= spu
->packet_offset
= 0;
624 void spudec_heartbeat(void *this, unsigned int pts100
)
626 spudec_handle_t
*spu
= (spudec_handle_t
*) this;
627 spu
->now_pts
= pts100
;
629 // TODO: detect and handle broken timestamps (e.g. due to wrapping)
630 while (spu
->queue_head
!= NULL
&& pts100
>= spu
->queue_head
->start_pts
) {
631 packet_t
*packet
= spudec_dequeue_packet(spu
);
632 spu
->start_pts
= packet
->start_pts
;
633 spu
->end_pts
= packet
->end_pts
;
634 if (packet
->is_decoded
) {
636 spu
->image_size
= packet
->data_len
;
637 spu
->image
= packet
->packet
;
638 spu
->aimage
= packet
->packet
+ packet
->stride
* packet
->height
;
639 packet
->packet
= NULL
;
640 spu
->width
= packet
->width
;
641 spu
->height
= packet
->height
;
642 spu
->stride
= packet
->stride
;
643 spu
->start_col
= packet
->start_col
;
644 spu
->start_row
= packet
->start_row
;
646 // reset scaled image
647 spu
->scaled_frame_width
= 0;
648 spu
->scaled_frame_height
= 0;
650 if (spu
->auto_palette
)
651 compute_palette(spu
, packet
);
652 spudec_process_data(spu
, packet
);
654 spudec_free_packet(packet
);
655 spu
->spu_changed
= 1;
659 int spudec_visible(void *this){
660 spudec_handle_t
*spu
= (spudec_handle_t
*)this;
661 int ret
=(spu
->start_pts
<= spu
->now_pts
&&
662 spu
->now_pts
< spu
->end_pts
&&
664 // printf("spu visible: %d \n",ret);
668 void spudec_set_forced_subs_only(void * const this, const unsigned int flag
)
671 ((spudec_handle_t
*)this)->forced_subs_only
=flag
;
672 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"SPU: Display only forced subs now %s\n", flag
? "enabled": "disabled");
676 void spudec_draw(void *this, void (*draw_alpha
)(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
))
678 spudec_handle_t
*spu
= (spudec_handle_t
*)this;
679 if (spudec_visible(spu
))
681 draw_alpha(spu
->start_col
, spu
->start_row
, spu
->width
, spu
->height
,
682 spu
->image
, spu
->aimage
, spu
->stride
);
683 spu
->spu_changed
= 0;
687 /* calc the bbox for spudec subs */
688 void spudec_calc_bbox(void *me
, unsigned int dxs
, unsigned int dys
, unsigned int* bbox
)
690 spudec_handle_t
*spu
;
691 spu
= (spudec_handle_t
*)me
;
692 if (spu
->orig_frame_width
== 0 || spu
->orig_frame_height
== 0
693 || (spu
->orig_frame_width
== dxs
&& spu
->orig_frame_height
== dys
)) {
695 bbox
[0] = spu
->start_col
;
696 bbox
[1] = spu
->start_col
+ spu
->width
;
697 bbox
[2] = spu
->start_row
;
698 bbox
[3] = spu
->start_row
+ spu
->height
;
702 unsigned int scalex
= 0x100 * dxs
/ spu
->orig_frame_width
;
703 unsigned int scaley
= 0x100 * dys
/ spu
->orig_frame_height
;
704 bbox
[0] = spu
->start_col
* scalex
/ 0x100;
705 bbox
[1] = spu
->start_col
* scalex
/ 0x100 + spu
->width
* scalex
/ 0x100;
706 switch (spu_alignment
) {
708 bbox
[3] = dys
*sub_pos
/100 + spu
->height
* scaley
/ 0x100;
709 if (bbox
[3] > dys
) bbox
[3] = dys
;
710 bbox
[2] = bbox
[3] - spu
->height
* scaley
/ 0x100;
714 bbox
[2] = dys
*sub_pos
/100 - spu
->height
* scaley
/ 0x200;
715 bbox
[3] = bbox
[2] + spu
->height
;
717 bbox
[3] = dys
*sub_pos
/100 + spu
->height
* scaley
/ 0x200;
718 if (bbox
[3] > dys
) bbox
[3] = dys
;
719 bbox
[2] = bbox
[3] - spu
->height
* scaley
/ 0x100;
723 bbox
[2] = dys
*sub_pos
/100 - spu
->height
* scaley
/ 0x100;
724 bbox
[3] = bbox
[2] + spu
->height
;
727 bbox
[2] = spu
->start_row
* scaley
/ 0x100;
728 bbox
[3] = spu
->start_row
* scaley
/ 0x100 + spu
->height
* scaley
/ 0x100;
733 /* transform mplayer's alpha value into an opacity value that is linear */
734 static inline int canon_alpha(int alpha
)
736 return alpha
? 256 - alpha
: 0;
746 static void scale_table(unsigned int start_src
, unsigned int start_tar
, unsigned int end_src
, unsigned int end_tar
, scale_pixel
* table
)
749 unsigned int delta_src
= end_src
- start_src
;
750 unsigned int delta_tar
= end_tar
- start_tar
;
753 if (delta_src
== 0 || delta_tar
== 0) {
756 src_step
= (delta_src
<< 16) / delta_tar
>>1;
757 for (t
= 0; t
<=delta_tar
; src
+= (src_step
<< 1), t
++){
758 table
[t
].position
= FFMIN(src
>> 16, end_src
- 1);
759 table
[t
].right_down
= src
& 0xffff;
760 table
[t
].left_up
= 0x10000 - table
[t
].right_down
;
764 /* bilinear scale, similar to vobsub's code */
765 static void scale_image(int x
, int y
, scale_pixel
* table_x
, scale_pixel
* table_y
, spudec_handle_t
* spu
)
769 unsigned int scale
[4];
770 int base
= table_y
[y
].position
* spu
->stride
+ table_x
[x
].position
;
771 int scaled
= y
* spu
->scaled_stride
+ x
;
772 alpha
[0] = canon_alpha(spu
->aimage
[base
]);
773 alpha
[1] = canon_alpha(spu
->aimage
[base
+ 1]);
774 alpha
[2] = canon_alpha(spu
->aimage
[base
+ spu
->stride
]);
775 alpha
[3] = canon_alpha(spu
->aimage
[base
+ spu
->stride
+ 1]);
776 color
[0] = spu
->image
[base
];
777 color
[1] = spu
->image
[base
+ 1];
778 color
[2] = spu
->image
[base
+ spu
->stride
];
779 color
[3] = spu
->image
[base
+ spu
->stride
+ 1];
780 scale
[0] = (table_x
[x
].left_up
* table_y
[y
].left_up
>> 16) * alpha
[0];
781 if (table_y
[y
].left_up
== 0x10000) // necessary to avoid overflow-case
782 scale
[0] = table_x
[x
].left_up
* alpha
[0];
783 scale
[1] = (table_x
[x
].right_down
* table_y
[y
].left_up
>>16) * alpha
[1];
784 scale
[2] = (table_x
[x
].left_up
* table_y
[y
].right_down
>> 16) * alpha
[2];
785 scale
[3] = (table_x
[x
].right_down
* table_y
[y
].right_down
>> 16) * alpha
[3];
786 spu
->scaled_image
[scaled
] = (color
[0] * scale
[0] + color
[1] * scale
[1] + color
[2] * scale
[2] + color
[3] * scale
[3])>>24;
787 spu
->scaled_aimage
[scaled
] = (scale
[0] + scale
[1] + scale
[2] + scale
[3]) >> 16;
788 if (spu
->scaled_aimage
[scaled
]){
789 // ensure that MPlayer's simplified alpha-blending can not overflow
790 spu
->scaled_image
[scaled
] = FFMIN(spu
->scaled_image
[scaled
], spu
->scaled_aimage
[scaled
]);
791 // convert to MPlayer-style alpha
792 spu
->scaled_aimage
[scaled
] = -spu
->scaled_aimage
[scaled
];
796 static void sws_spu_image(unsigned char *d1
, unsigned char *d2
, int dw
, int dh
,
797 int ds
, unsigned char *s1
, unsigned char *s2
, int sw
,
800 struct SwsContext
*ctx
;
801 static SwsFilter filter
;
802 static int firsttime
= 1;
806 if (!firsttime
&& oldvar
!= spu_gaussvar
) sws_freeVec(filter
.lumH
);
808 filter
.lumH
= filter
.lumV
=
809 filter
.chrH
= filter
.chrV
= sws_getGaussianVec(spu_gaussvar
, 3.0);
810 sws_normalizeVec(filter
.lumH
, 1.0);
812 oldvar
= spu_gaussvar
;
815 ctx
=sws_getContext(sw
, sh
, PIX_FMT_GRAY8
, dw
, dh
, PIX_FMT_GRAY8
, SWS_GAUSS
, &filter
, NULL
, NULL
);
816 sws_scale(ctx
,&s1
,&ss
,0,sh
,&d1
,&ds
);
817 for (i
=ss
*sh
-1; i
>=0; i
--) if (!s2
[i
]) s2
[i
] = 255; //else s2[i] = 1;
818 sws_scale(ctx
,&s2
,&ss
,0,sh
,&d2
,&ds
);
819 for (i
=ds
*dh
-1; i
>=0; i
--) if (d2
[i
]==0) d2
[i
] = 1; else if (d2
[i
]==255) d2
[i
] = 0;
820 sws_freeContext(ctx
);
823 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
)
825 spudec_handle_t
*spu
= (spudec_handle_t
*)me
;
826 scale_pixel
*table_x
;
827 scale_pixel
*table_y
;
829 if (spudec_visible(spu
)) {
831 // check if only forced subtitles are requested
832 if( (spu
->forced_subs_only
) && !(spu
->is_forced_sub
) ){
836 if (!(spu_aamode
&16) && (spu
->orig_frame_width
== 0 || spu
->orig_frame_height
== 0
837 || (spu
->orig_frame_width
== dxs
&& spu
->orig_frame_height
== dys
))) {
840 draw_alpha(ctx
, spu
->start_col
, spu
->start_row
, spu
->width
, spu
->height
,
841 spu
->image
, spu
->aimage
, spu
->stride
);
842 spu
->spu_changed
= 0;
846 if (spu
->scaled_frame_width
!= dxs
|| spu
->scaled_frame_height
!= dys
) { /* Resizing is needed */
847 /* scaled_x = scalex * x / 0x100
848 scaled_y = scaley * y / 0x100
849 order of operations is important because of rounding. */
850 unsigned int scalex
= 0x100 * dxs
/ spu
->orig_frame_width
;
851 unsigned int scaley
= 0x100 * dys
/ spu
->orig_frame_height
;
852 spu
->scaled_start_col
= spu
->start_col
* scalex
/ 0x100;
853 spu
->scaled_start_row
= spu
->start_row
* scaley
/ 0x100;
854 spu
->scaled_width
= spu
->width
* scalex
/ 0x100;
855 spu
->scaled_height
= spu
->height
* scaley
/ 0x100;
856 /* Kludge: draw_alpha needs width multiple of 8 */
857 spu
->scaled_stride
= (spu
->scaled_width
+ 7) & ~7;
858 if (spu
->scaled_image_size
< spu
->scaled_stride
* spu
->scaled_height
) {
859 if (spu
->scaled_image
) {
860 free(spu
->scaled_image
);
861 spu
->scaled_image_size
= 0;
863 spu
->scaled_image
= malloc(2 * spu
->scaled_stride
* spu
->scaled_height
);
864 if (spu
->scaled_image
) {
865 spu
->scaled_image_size
= spu
->scaled_stride
* spu
->scaled_height
;
866 spu
->scaled_aimage
= spu
->scaled_image
+ spu
->scaled_image_size
;
869 if (spu
->scaled_image
) {
871 if (spu
->scaled_width
<= 1 || spu
->scaled_height
<= 1) {
874 switch(spu_aamode
&15) {
876 sws_spu_image(spu
->scaled_image
, spu
->scaled_aimage
,
877 spu
->scaled_width
, spu
->scaled_height
, spu
->scaled_stride
,
878 spu
->image
, spu
->aimage
, spu
->width
, spu
->height
, spu
->stride
);
881 table_x
= calloc(spu
->scaled_width
, sizeof(scale_pixel
));
882 table_y
= calloc(spu
->scaled_height
, sizeof(scale_pixel
));
883 if (!table_x
|| !table_y
) {
884 mp_msg(MSGT_SPUDEC
, MSGL_FATAL
, "Fatal: spudec_draw_scaled: calloc failed\n");
886 scale_table(0, 0, spu
->width
- 1, spu
->scaled_width
- 1, table_x
);
887 scale_table(0, 0, spu
->height
- 1, spu
->scaled_height
- 1, table_y
);
888 for (y
= 0; y
< spu
->scaled_height
; y
++)
889 for (x
= 0; x
< spu
->scaled_width
; x
++)
890 scale_image(x
, y
, table_x
, table_y
, spu
);
895 /* no antialiasing */
896 for (y
= 0; y
< spu
->scaled_height
; ++y
) {
897 int unscaled_y
= y
* 0x100 / scaley
;
898 int strides
= spu
->stride
* unscaled_y
;
899 int scaled_strides
= spu
->scaled_stride
* y
;
900 for (x
= 0; x
< spu
->scaled_width
; ++x
) {
901 int unscaled_x
= x
* 0x100 / scalex
;
902 spu
->scaled_image
[scaled_strides
+ x
] = spu
->image
[strides
+ unscaled_x
];
903 spu
->scaled_aimage
[scaled_strides
+ x
] = spu
->aimage
[strides
+ unscaled_x
];
909 /* Intermediate antialiasing. */
910 for (y
= 0; y
< spu
->scaled_height
; ++y
) {
911 const unsigned int unscaled_top
= y
* spu
->orig_frame_height
/ dys
;
912 unsigned int unscaled_bottom
= (y
+ 1) * spu
->orig_frame_height
/ dys
;
913 if (unscaled_bottom
>= spu
->height
)
914 unscaled_bottom
= spu
->height
- 1;
915 for (x
= 0; x
< spu
->scaled_width
; ++x
) {
916 const unsigned int unscaled_left
= x
* spu
->orig_frame_width
/ dxs
;
917 unsigned int unscaled_right
= (x
+ 1) * spu
->orig_frame_width
/ dxs
;
918 unsigned int color
= 0;
919 unsigned int alpha
= 0;
920 unsigned int walkx
, walky
;
921 unsigned int base
, tmp
;
922 if (unscaled_right
>= spu
->width
)
923 unscaled_right
= spu
->width
- 1;
924 for (walky
= unscaled_top
; walky
<= unscaled_bottom
; ++walky
)
925 for (walkx
= unscaled_left
; walkx
<= unscaled_right
; ++walkx
) {
926 base
= walky
* spu
->stride
+ walkx
;
927 tmp
= canon_alpha(spu
->aimage
[base
]);
929 color
+= tmp
* spu
->image
[base
];
931 base
= y
* spu
->scaled_stride
+ x
;
932 spu
->scaled_image
[base
] = alpha
? color
/ alpha
: 0;
933 spu
->scaled_aimage
[base
] =
934 alpha
* (1 + unscaled_bottom
- unscaled_top
) * (1 + unscaled_right
- unscaled_left
);
935 /* spu->scaled_aimage[base] =
936 alpha * dxs * dys / spu->orig_frame_width / spu->orig_frame_height; */
937 if (spu
->scaled_aimage
[base
]) {
938 spu
->scaled_aimage
[base
] = 256 - spu
->scaled_aimage
[base
];
939 if (spu
->scaled_aimage
[base
] + spu
->scaled_image
[base
] > 255)
940 spu
->scaled_image
[base
] = 256 - spu
->scaled_aimage
[base
];
948 /* Best antialiasing. Very slow. */
949 /* Any pixel (x, y) represents pixels from the original
950 rectangular region comprised between the columns
951 unscaled_y and unscaled_y + 0x100 / scaley and the rows
952 unscaled_x and unscaled_x + 0x100 / scalex
954 The original rectangular region that the scaled pixel
955 represents is cut in 9 rectangular areas like this:
957 +---+-----------------+---+
959 +---+-----------------+---+
963 +---+-----------------+---+
965 +---+-----------------+---+
967 The width of the left column is at most one pixel and
968 it is never null and its right column is at a pixel
969 boundary. The height of the top row is at most one
970 pixel it is never null and its bottom row is at a
971 pixel boundary. The width and height of region 5 are
972 integral values. The width of the right column is
973 what remains and is less than one pixel. The height
974 of the bottom row is what remains and is less than
977 The row above 1, 2, 3 is unscaled_y. The row between
978 1, 2, 3 and 4, 5, 6 is top_low_row. The row between 4,
979 5, 6 and 7, 8, 9 is (unsigned int)unscaled_y_bottom.
980 The row beneath 7, 8, 9 is unscaled_y_bottom.
982 The column left of 1, 4, 7 is unscaled_x. The column
983 between 1, 4, 7 and 2, 5, 8 is left_right_column. The
984 column between 2, 5, 8 and 3, 6, 9 is (unsigned
985 int)unscaled_x_right. The column right of 3, 6, 9 is
987 const double inv_scalex
= (double) 0x100 / scalex
;
988 const double inv_scaley
= (double) 0x100 / scaley
;
989 for (y
= 0; y
< spu
->scaled_height
; ++y
) {
990 const double unscaled_y
= y
* inv_scaley
;
991 const double unscaled_y_bottom
= unscaled_y
+ inv_scaley
;
992 const unsigned int top_low_row
= FFMIN(unscaled_y_bottom
, unscaled_y
+ 1.0);
993 const double top
= top_low_row
- unscaled_y
;
994 const unsigned int height
= unscaled_y_bottom
> top_low_row
995 ? (unsigned int) unscaled_y_bottom
- top_low_row
997 const double bottom
= unscaled_y_bottom
> top_low_row
998 ? unscaled_y_bottom
- floor(unscaled_y_bottom
)
1000 for (x
= 0; x
< spu
->scaled_width
; ++x
) {
1001 const double unscaled_x
= x
* inv_scalex
;
1002 const double unscaled_x_right
= unscaled_x
+ inv_scalex
;
1003 const unsigned int left_right_column
= FFMIN(unscaled_x_right
, unscaled_x
+ 1.0);
1004 const double left
= left_right_column
- unscaled_x
;
1005 const unsigned int width
= unscaled_x_right
> left_right_column
1006 ? (unsigned int) unscaled_x_right
- left_right_column
1008 const double right
= unscaled_x_right
> left_right_column
1009 ? unscaled_x_right
- floor(unscaled_x_right
)
1015 /* Now use these informations to compute a good alpha,
1016 and lightness. The sum is on each of the 9
1017 region's surface and alpha and lightness.
1019 transformed alpha = sum(surface * alpha) / sum(surface)
1020 transformed color = sum(surface * alpha * color) / sum(surface * alpha)
1022 /* 1: top left part */
1023 base
= spu
->stride
* (unsigned int) unscaled_y
;
1024 tmp
= left
* top
* canon_alpha(spu
->aimage
[base
+ (unsigned int) unscaled_x
]);
1026 color
+= tmp
* spu
->image
[base
+ (unsigned int) unscaled_x
];
1027 /* 2: top center part */
1030 for (walkx
= left_right_column
; walkx
< (unsigned int) unscaled_x_right
; ++walkx
) {
1031 base
= spu
->stride
* (unsigned int) unscaled_y
+ walkx
;
1032 tmp
= /* 1.0 * */ top
* canon_alpha(spu
->aimage
[base
]);
1034 color
+= tmp
* spu
->image
[base
];
1037 /* 3: top right part */
1039 base
= spu
->stride
* (unsigned int) unscaled_y
+ (unsigned int) unscaled_x_right
;
1040 tmp
= right
* top
* canon_alpha(spu
->aimage
[base
]);
1042 color
+= tmp
* spu
->image
[base
];
1044 /* 4: center left part */
1047 for (walky
= top_low_row
; walky
< (unsigned int) unscaled_y_bottom
; ++walky
) {
1048 base
= spu
->stride
* walky
+ (unsigned int) unscaled_x
;
1049 tmp
= left
/* * 1.0 */ * canon_alpha(spu
->aimage
[base
]);
1051 color
+= tmp
* spu
->image
[base
];
1054 /* 5: center part */
1055 if (width
> 0 && height
> 0) {
1057 for (walky
= top_low_row
; walky
< (unsigned int) unscaled_y_bottom
; ++walky
) {
1059 base
= spu
->stride
* walky
;
1060 for (walkx
= left_right_column
; walkx
< (unsigned int) unscaled_x_right
; ++walkx
) {
1061 tmp
= /* 1.0 * 1.0 * */ canon_alpha(spu
->aimage
[base
+ walkx
]);
1063 color
+= tmp
* spu
->image
[base
+ walkx
];
1067 /* 6: center right part */
1068 if (right
> 0.0 && height
> 0) {
1070 for (walky
= top_low_row
; walky
< (unsigned int) unscaled_y_bottom
; ++walky
) {
1071 base
= spu
->stride
* walky
+ (unsigned int) unscaled_x_right
;
1072 tmp
= right
/* * 1.0 */ * canon_alpha(spu
->aimage
[base
]);
1074 color
+= tmp
* spu
->image
[base
];
1077 /* 7: bottom left part */
1079 base
= spu
->stride
* (unsigned int) unscaled_y_bottom
+ (unsigned int) unscaled_x
;
1080 tmp
= left
* bottom
* canon_alpha(spu
->aimage
[base
]);
1082 color
+= tmp
* spu
->image
[base
];
1084 /* 8: bottom center part */
1085 if (width
> 0 && bottom
> 0.0) {
1087 base
= spu
->stride
* (unsigned int) unscaled_y_bottom
;
1088 for (walkx
= left_right_column
; walkx
< (unsigned int) unscaled_x_right
; ++walkx
) {
1089 tmp
= /* 1.0 * */ bottom
* canon_alpha(spu
->aimage
[base
+ walkx
]);
1091 color
+= tmp
* spu
->image
[base
+ walkx
];
1094 /* 9: bottom right part */
1095 if (right
> 0.0 && bottom
> 0.0) {
1096 base
= spu
->stride
* (unsigned int) unscaled_y_bottom
+ (unsigned int) unscaled_x_right
;
1097 tmp
= right
* bottom
* canon_alpha(spu
->aimage
[base
]);
1099 color
+= tmp
* spu
->image
[base
];
1101 /* Finally mix these transparency and brightness information suitably */
1102 base
= spu
->scaled_stride
* y
+ x
;
1103 spu
->scaled_image
[base
] = alpha
> 0 ? color
/ alpha
: 0;
1104 spu
->scaled_aimage
[base
] = alpha
* scalex
* scaley
/ 0x10000;
1105 if (spu
->scaled_aimage
[base
]) {
1106 spu
->scaled_aimage
[base
] = 256 - spu
->scaled_aimage
[base
];
1107 if (spu
->scaled_aimage
[base
] + spu
->scaled_image
[base
] > 255)
1108 spu
->scaled_image
[base
] = 256 - spu
->scaled_aimage
[base
];
1115 /* Kludge: draw_alpha needs width multiple of 8. */
1116 if (spu
->scaled_width
< spu
->scaled_stride
)
1117 for (y
= 0; y
< spu
->scaled_height
; ++y
) {
1118 memset(spu
->scaled_aimage
+ y
* spu
->scaled_stride
+ spu
->scaled_width
, 0,
1119 spu
->scaled_stride
- spu
->scaled_width
);
1121 spu
->scaled_frame_width
= dxs
;
1122 spu
->scaled_frame_height
= dys
;
1125 if (spu
->scaled_image
){
1126 switch (spu_alignment
) {
1128 spu
->scaled_start_row
= dys
*sub_pos
/100;
1129 if (spu
->scaled_start_row
+ spu
->scaled_height
> dys
)
1130 spu
->scaled_start_row
= dys
- spu
->scaled_height
;
1133 spu
->scaled_start_row
= dys
*sub_pos
/100 - spu
->scaled_height
/2;
1134 if (sub_pos
>= 50 && spu
->scaled_start_row
+ spu
->scaled_height
> dys
)
1135 spu
->scaled_start_row
= dys
- spu
->scaled_height
;
1138 spu
->scaled_start_row
= dys
*sub_pos
/100 - spu
->scaled_height
;
1141 draw_alpha(ctx
, spu
->scaled_start_col
, spu
->scaled_start_row
, spu
->scaled_width
, spu
->scaled_height
,
1142 spu
->scaled_image
, spu
->scaled_aimage
, spu
->scaled_stride
);
1143 spu
->spu_changed
= 0;
1149 mp_msg(MSGT_SPUDEC
,MSGL_DBG2
,"SPU not displayed: start_pts=%d end_pts=%d now_pts=%d\n",
1150 spu
->start_pts
, spu
->end_pts
, spu
->now_pts
);
1154 void spudec_update_palette(void * this, unsigned int *palette
)
1156 spudec_handle_t
*spu
= (spudec_handle_t
*) this;
1157 if (spu
&& palette
) {
1158 memcpy(spu
->global_palette
, palette
, sizeof(spu
->global_palette
));
1160 vo_control(spu
->hw_spu
, VOCTRL_SET_SPU_PALETTE
, spu
->global_palette
);
1164 void spudec_set_font_factor(void * this, double factor
)
1166 spudec_handle_t
*spu
= (spudec_handle_t
*) this;
1167 spu
->font_start_level
= (int)(0xF0-(0xE0*factor
));
1170 static void spudec_parse_extradata(spudec_handle_t
*this,
1171 uint8_t *extradata
, int extradata_len
)
1173 uint8_t *buffer
, *ptr
;
1174 unsigned int *pal
= this->global_palette
, *cuspal
= this->cuspal
;
1178 if (extradata_len
== 16*4) {
1179 for (i
=0; i
<16; i
++)
1180 pal
[i
] = AV_RB32(extradata
+ i
*4);
1181 this->auto_palette
= 0;
1185 if (!(ptr
= buffer
= malloc(extradata_len
+1)))
1187 memcpy(buffer
, extradata
, extradata_len
);
1188 buffer
[extradata_len
] = 0;
1193 if (!strncmp(ptr
, "size: ", 6))
1194 sscanf(ptr
+ 6, "%dx%d", &this->orig_frame_width
, &this->orig_frame_height
);
1195 if (!strncmp(ptr
, "palette: ", 9) &&
1196 sscanf(ptr
+ 9, "%x, %x, %x, %x, %x, %x, %x, %x, "
1197 "%x, %x, %x, %x, %x, %x, %x, %x",
1198 &pal
[ 0], &pal
[ 1], &pal
[ 2], &pal
[ 3],
1199 &pal
[ 4], &pal
[ 5], &pal
[ 6], &pal
[ 7],
1200 &pal
[ 8], &pal
[ 9], &pal
[10], &pal
[11],
1201 &pal
[12], &pal
[13], &pal
[14], &pal
[15]) == 16) {
1202 for (i
=0; i
<16; i
++)
1203 pal
[i
] = vobsub_palette_to_yuv(pal
[i
]);
1204 this->auto_palette
= 0;
1206 if (!strncasecmp(ptr
, "forced subs: on", 15))
1207 this->forced_subs_only
= 1;
1208 if (!strncmp(ptr
, "custom colors: ON, tridx: ", 26) &&
1209 sscanf(ptr
+ 26, "%x, colors: %x, %x, %x, %x",
1210 &tridx
, cuspal
+0, cuspal
+1, cuspal
+2, cuspal
+3) == 5) {
1211 for (i
=0; i
<4; i
++) {
1212 cuspal
[i
] = vobsub_rgb_to_yuv(cuspal
[i
]);
1213 if (tridx
& (1 << (12-4*i
)))
1214 cuspal
[i
] |= 1 << 31;
1218 } while ((ptr
=strchr(ptr
,'\n')) && *++ptr
);
1223 void *spudec_new_scaled(unsigned int *palette
, unsigned int frame_width
, unsigned int frame_height
, uint8_t *extradata
, int extradata_len
)
1225 spudec_handle_t
*this = calloc(1, sizeof(spudec_handle_t
));
1227 this->orig_frame_height
= frame_height
;
1228 this->orig_frame_width
= frame_width
;
1231 memcpy(this->global_palette
, palette
, sizeof(this->global_palette
));
1233 this->auto_palette
= 1;
1235 spudec_parse_extradata(this, extradata
, extradata_len
);
1236 /* XXX Although the video frame is some size, the SPU frame is
1237 always maximum size i.e. 720 wide and 576 or 480 high */
1238 // For HD files in MKV the VobSub resolution can be higher though,
1239 // see largeres_vobsub.mkv
1240 if (this->orig_frame_width
<= 720 && this->orig_frame_height
<= 576) {
1241 this->orig_frame_width
= 720;
1242 if (this->orig_frame_height
== 480 || this->orig_frame_height
== 240)
1243 this->orig_frame_height
= 480;
1245 this->orig_frame_height
= 576;
1249 mp_msg(MSGT_SPUDEC
,MSGL_FATAL
, "FATAL: spudec_init: calloc");
1253 void *spudec_new(unsigned int *palette
)
1255 return spudec_new_scaled(palette
, 0, 0, NULL
, 0);
1258 void spudec_free(void *this)
1260 spudec_handle_t
*spu
= (spudec_handle_t
*)this;
1262 while (spu
->queue_head
)
1263 spudec_free_packet(spudec_dequeue_packet(spu
));
1266 if (spu
->scaled_image
)
1267 free(spu
->scaled_image
);
1274 void spudec_set_hw_spu(void *this, struct vo
*hw_spu
)
1276 spudec_handle_t
*spu
= (spudec_handle_t
*)this;
1279 spu
->hw_spu
= hw_spu
;
1280 vo_control(hw_spu
, VOCTRL_SET_SPU_PALETTE
, spu
->global_palette
);
1283 #define MP_NOPTS_VALUE (-1LL<<63) //both int64_t and double should be able to represent this exactly
1286 * palette must contain at least 256 32-bit entries, otherwise crashes
1289 void spudec_set_paletted(void *this, const uint8_t *pal_img
, int pal_stride
,
1290 const void *palette
,
1291 int x
, int y
, int w
, int h
,
1292 double pts
, double endpts
)
1295 const uint32_t *pal
= palette
;
1296 spudec_handle_t
*spu
= this;
1299 int stride
= (w
+ 7) & ~7;
1300 if ((unsigned)w
>= 0x8000 || (unsigned)h
> 0x4000)
1302 packet
= calloc(1, sizeof(packet_t
));
1303 packet
->is_decoded
= 1;
1306 packet
->stride
= stride
;
1307 packet
->start_col
= x
;
1308 packet
->start_row
= y
;
1309 packet
->data_len
= 2 * stride
* h
;
1310 packet
->packet
= malloc(packet
->data_len
);
1311 img
= packet
->packet
;
1312 aimg
= packet
->packet
+ stride
* h
;
1313 for (y
= 0; y
< h
; y
++) {
1314 for (x
= 0; x
< w
; x
++) {
1315 uint32_t pixel
= pal
[pal_img
[x
]];
1316 *aimg
++ = -(pixel
>> 24);
1317 *img
++ = (((pixel
& 0x000000ff) >> 0) +
1318 ((pixel
& 0x0000ff00) >> 7) +
1319 ((pixel
& 0x00ff0000) >> 16)) >> 2;
1321 for (; x
< stride
; x
++)
1322 *aimg
++ = *img
++ = 0;
1323 pal_img
+= pal_stride
;
1325 packet
->start_pts
= 0;
1326 packet
->end_pts
= 0x7fffffff;
1327 if (pts
!= MP_NOPTS_VALUE
)
1328 packet
->start_pts
= pts
* 90000;
1329 if (endpts
!= MP_NOPTS_VALUE
)
1330 packet
->end_pts
= endpts
* 90000;
1331 spudec_queue_packet(spu
, packet
);