Ignore svn change r30495
[mplayer/kovensky.git] / spudec.c
blob05ec81f514692eebc2dca9ea4f67bdbb648a24f1
1 /*
2 * Skeleton of function spudec_process_controll() is from xine sources.
3 * Further works:
4 * LGB,... (yeah, try to improve it and insert your name here! ;-)
6 * Kim Minh Kaplan
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.
30 #include "config.h"
31 #include "mp_msg.h"
33 #include <errno.h>
34 #include <limits.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <unistd.h>
38 #include <string.h>
39 #include <math.h>
40 #include "libvo/video_out.h"
41 #include "spudec.h"
42 #include "vobsub.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)
49 1: approximate
50 2: full (slowest)
51 3: bilinear (similiar to vobsub, fast and not too bad)
52 4: uses swscaler gaussian (this is the only one that looks good)
55 int spu_aamode = 3;
56 int spu_alignment = -1;
57 float spu_gaussvar = 1.0;
58 extern int sub_pos;
60 typedef struct packet_t packet_t;
61 struct packet_t {
62 unsigned char *packet;
63 unsigned int palette[4];
64 unsigned int alpha[4];
65 unsigned int control_start; /* index of start of control data */
66 unsigned int current_nibble[2]; /* next data nibble (4 bits) to be
67 processed (for RLE decoding) for
68 even and odd lines */
69 int deinterlace_oddness; /* 0 or 1, index into current_nibble */
70 unsigned int start_col, end_col;
71 unsigned int start_row, end_row;
72 unsigned int width, height, stride;
73 unsigned int start_pts, end_pts;
74 packet_t *next;
77 typedef struct {
78 packet_t *queue_head;
79 packet_t *queue_tail;
80 unsigned int global_palette[16];
81 unsigned int orig_frame_width, orig_frame_height;
82 unsigned char* packet;
83 size_t packet_reserve; /* size of the memory pointed to by packet */
84 unsigned int packet_offset; /* end of the currently assembled fragment */
85 unsigned int packet_size; /* size of the packet once all fragments are assembled */
86 int packet_pts; /* PTS for this packet */
87 unsigned int palette[4];
88 unsigned int alpha[4];
89 unsigned int cuspal[4];
90 unsigned int custom;
91 unsigned int now_pts;
92 unsigned int start_pts, end_pts;
93 unsigned int start_col, end_col;
94 unsigned int start_row, end_row;
95 unsigned int width, height, stride;
96 size_t image_size; /* Size of the image buffer */
97 unsigned char *image; /* Grayscale value */
98 unsigned char *aimage; /* Alpha value */
99 unsigned int scaled_frame_width, scaled_frame_height;
100 unsigned int scaled_start_col, scaled_start_row;
101 unsigned int scaled_width, scaled_height, scaled_stride;
102 size_t scaled_image_size;
103 unsigned char *scaled_image;
104 unsigned char *scaled_aimage;
105 int auto_palette; /* 1 if we lack a palette and must use an heuristic. */
106 int font_start_level; /* Darkest value used for the computed font */
107 struct vo *hw_spu;
108 int spu_changed;
109 unsigned int forced_subs_only; /* flag: 0=display all subtitle, !0 display only forced subtitles */
110 unsigned int is_forced_sub; /* true if current subtitle is a forced subtitle */
111 } spudec_handle_t;
113 static void spudec_queue_packet(spudec_handle_t *this, packet_t *packet)
115 if (this->queue_head == NULL)
116 this->queue_head = packet;
117 else
118 this->queue_tail->next = packet;
119 this->queue_tail = packet;
122 static packet_t *spudec_dequeue_packet(spudec_handle_t *this)
124 packet_t *retval = this->queue_head;
126 this->queue_head = retval->next;
127 if (this->queue_head == NULL)
128 this->queue_tail = NULL;
130 return retval;
133 static void spudec_free_packet(packet_t *packet)
135 if (packet->packet != NULL)
136 free(packet->packet);
137 free(packet);
140 static inline unsigned int get_be16(const unsigned char *p)
142 return (p[0] << 8) + p[1];
145 static inline unsigned int get_be24(const unsigned char *p)
147 return (get_be16(p) << 8) + p[2];
150 static void next_line(packet_t *packet)
152 if (packet->current_nibble[packet->deinterlace_oddness] % 2)
153 packet->current_nibble[packet->deinterlace_oddness]++;
154 packet->deinterlace_oddness = (packet->deinterlace_oddness + 1) % 2;
157 static inline unsigned char get_nibble(packet_t *packet)
159 unsigned char nib;
160 unsigned int *nibblep = packet->current_nibble + packet->deinterlace_oddness;
161 if (*nibblep / 2 >= packet->control_start) {
162 mp_msg(MSGT_SPUDEC,MSGL_WARN, "SPUdec: ERROR: get_nibble past end of packet\n");
163 return 0;
165 nib = packet->packet[*nibblep / 2];
166 if (*nibblep % 2)
167 nib &= 0xf;
168 else
169 nib >>= 4;
170 ++*nibblep;
171 return nib;
174 static inline int mkalpha(int i)
176 /* In mplayer's alpha planes, 0 is transparent, then 1 is nearly
177 opaque upto 255 which is transparent */
178 switch (i) {
179 case 0xf:
180 return 1;
181 case 0:
182 return 0;
183 default:
184 return (0xf - i) << 4;
188 /* Cut the sub to visible part */
189 static inline void spudec_cut_image(spudec_handle_t *this)
191 unsigned int fy, ly;
192 unsigned int first_y, last_y;
193 unsigned char *image;
194 unsigned char *aimage;
196 if (this->stride == 0 || this->height == 0) {
197 return;
200 for (fy = 0; fy < this->image_size && !this->aimage[fy]; fy++);
201 for (ly = this->stride * this->height-1; ly && !this->aimage[ly]; ly--);
202 first_y = fy / this->stride;
203 last_y = ly / this->stride;
204 //printf("first_y: %d, last_y: %d\n", first_y, last_y);
205 this->start_row += first_y;
207 // Some subtitles trigger this condition
208 if (last_y + 1 > first_y ) {
209 this->height = last_y - first_y +1;
210 } else {
211 this->height = 0;
212 this->image_size = 0;
213 return;
216 // printf("new h %d new start %d (sz %d st %d)---\n\n", this->height, this->start_row, this->image_size, this->stride);
218 image = malloc(2 * this->stride * this->height);
219 if(image){
220 this->image_size = this->stride * this->height;
221 aimage = image + this->image_size;
222 memcpy(image, this->image + this->stride * first_y, this->image_size);
223 memcpy(aimage, this->aimage + this->stride * first_y, this->image_size);
224 free(this->image);
225 this->image = image;
226 this->aimage = aimage;
227 } else {
228 mp_msg(MSGT_SPUDEC, MSGL_FATAL, "Fatal: update_spu: malloc requested %d bytes\n", 2 * this->stride * this->height);
232 static void spudec_process_data(spudec_handle_t *this, packet_t *packet)
234 unsigned int cmap[4], alpha[4];
235 unsigned int i, x, y;
237 this->scaled_frame_width = 0;
238 this->scaled_frame_height = 0;
239 this->start_col = packet->start_col;
240 this->end_col = packet->end_col;
241 this->start_row = packet->start_row;
242 this->end_row = packet->end_row;
243 this->height = packet->height;
244 this->width = packet->width;
245 this->stride = packet->stride;
246 for (i = 0; i < 4; ++i) {
247 alpha[i] = mkalpha(packet->alpha[i]);
248 if (this->custom && (this->cuspal[i] >> 31) != 0)
249 alpha[i] = 0;
250 if (alpha[i] == 0)
251 cmap[i] = 0;
252 else if (this->custom){
253 cmap[i] = ((this->cuspal[i] >> 16) & 0xff);
254 if (cmap[i] + alpha[i] > 255)
255 cmap[i] = 256 - alpha[i];
257 else {
258 cmap[i] = ((this->global_palette[packet->palette[i]] >> 16) & 0xff);
259 if (cmap[i] + alpha[i] > 255)
260 cmap[i] = 256 - alpha[i];
264 if (this->image_size < this->stride * this->height) {
265 if (this->image != NULL) {
266 free(this->image);
267 this->image_size = 0;
269 this->image = malloc(2 * this->stride * this->height);
270 if (this->image) {
271 this->image_size = this->stride * this->height;
272 this->aimage = this->image + this->image_size;
275 if (this->image == NULL)
276 return;
278 /* Kludge: draw_alpha needs width multiple of 8. */
279 if (this->width < this->stride)
280 for (y = 0; y < this->height; ++y) {
281 memset(this->aimage + y * this->stride + this->width, 0, this->stride - this->width);
282 /* FIXME: Why is this one needed? */
283 memset(this->image + y * this->stride + this->width, 0, this->stride - this->width);
286 i = packet->current_nibble[1];
287 x = 0;
288 y = 0;
289 while (packet->current_nibble[0] < i
290 && packet->current_nibble[1] / 2 < packet->control_start
291 && y < this->height) {
292 unsigned int len, color;
293 unsigned int rle = 0;
294 rle = get_nibble(packet);
295 if (rle < 0x04) {
296 rle = (rle << 4) | get_nibble(packet);
297 if (rle < 0x10) {
298 rle = (rle << 4) | get_nibble(packet);
299 if (rle < 0x040) {
300 rle = (rle << 4) | get_nibble(packet);
301 if (rle < 0x0004)
302 rle |= ((this->width - x) << 2);
306 color = 3 - (rle & 0x3);
307 len = rle >> 2;
308 if (len > this->width - x || len == 0)
309 len = this->width - x;
310 /* FIXME have to use palette and alpha map*/
311 memset(this->image + y * this->stride + x, cmap[color], len);
312 memset(this->aimage + y * this->stride + x, alpha[color], len);
313 x += len;
314 if (x >= this->width) {
315 next_line(packet);
316 x = 0;
317 ++y;
320 spudec_cut_image(this);
325 This function tries to create a usable palette.
326 It determines how many non-transparent colors are used, and assigns different
327 gray scale values to each color.
328 I tested it with four streams and even got something readable. Half of the
329 times I got black characters with white around and half the reverse.
331 static void compute_palette(spudec_handle_t *this, packet_t *packet)
333 int used[16],i,cused,start,step,color;
335 memset(used, 0, sizeof(used));
336 for (i=0; i<4; i++)
337 if (packet->alpha[i]) /* !Transparent? */
338 used[packet->palette[i]] = 1;
339 for (cused=0, i=0; i<16; i++)
340 if (used[i]) cused++;
341 if (!cused) return;
342 if (cused == 1) {
343 start = 0x80;
344 step = 0;
345 } else {
346 start = this->font_start_level;
347 step = (0xF0-this->font_start_level)/(cused-1);
349 memset(used, 0, sizeof(used));
350 for (i=0; i<4; i++) {
351 color = packet->palette[i];
352 if (packet->alpha[i] && !used[color]) { /* not assigned? */
353 used[color] = 1;
354 this->global_palette[color] = start<<16;
355 start += step;
360 static void spudec_process_control(spudec_handle_t *this, int pts100)
362 int a,b; /* Temporary vars */
363 unsigned int date, type;
364 unsigned int off;
365 unsigned int start_off = 0;
366 unsigned int next_off;
367 unsigned int start_pts = 0;
368 unsigned int end_pts = 0;
369 unsigned int current_nibble[2] = {0, 0};
370 unsigned int control_start;
371 unsigned int display = 0;
372 unsigned int start_col = 0;
373 unsigned int end_col = 0;
374 unsigned int start_row = 0;
375 unsigned int end_row = 0;
376 unsigned int width = 0;
377 unsigned int height = 0;
378 unsigned int stride = 0;
380 control_start = get_be16(this->packet + 2);
381 next_off = control_start;
382 while (start_off != next_off) {
383 start_off = next_off;
384 date = get_be16(this->packet + start_off) * 1024;
385 next_off = get_be16(this->packet + start_off + 2);
386 mp_msg(MSGT_SPUDEC,MSGL_DBG2, "date=%d\n", date);
387 off = start_off + 4;
388 for (type = this->packet[off++]; type != 0xff; type = this->packet[off++]) {
389 mp_msg(MSGT_SPUDEC,MSGL_DBG2, "cmd=%d ",type);
390 switch(type) {
391 case 0x00:
392 /* Menu ID, 1 byte */
393 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Menu ID\n");
394 /* shouldn't a Menu ID type force display start? */
395 start_pts = pts100 < 0 && -pts100 >= date ? 0 : pts100 + date;
396 end_pts = UINT_MAX;
397 display = 1;
398 this->is_forced_sub=~0; // current subtitle is forced
399 break;
400 case 0x01:
401 /* Start display */
402 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Start display!\n");
403 start_pts = pts100 < 0 && -pts100 >= date ? 0 : pts100 + date;
404 end_pts = UINT_MAX;
405 display = 1;
406 this->is_forced_sub=0;
407 break;
408 case 0x02:
409 /* Stop display */
410 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Stop display!\n");
411 end_pts = pts100 < 0 && -pts100 >= date ? 0 : pts100 + date;
412 break;
413 case 0x03:
414 /* Palette */
415 this->palette[0] = this->packet[off] >> 4;
416 this->palette[1] = this->packet[off] & 0xf;
417 this->palette[2] = this->packet[off + 1] >> 4;
418 this->palette[3] = this->packet[off + 1] & 0xf;
419 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Palette %d, %d, %d, %d\n",
420 this->palette[0], this->palette[1], this->palette[2], this->palette[3]);
421 off+=2;
422 break;
423 case 0x04:
424 /* Alpha */
425 this->alpha[0] = this->packet[off] >> 4;
426 this->alpha[1] = this->packet[off] & 0xf;
427 this->alpha[2] = this->packet[off + 1] >> 4;
428 this->alpha[3] = this->packet[off + 1] & 0xf;
429 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Alpha %d, %d, %d, %d\n",
430 this->alpha[0], this->alpha[1], this->alpha[2], this->alpha[3]);
431 off+=2;
432 break;
433 case 0x05:
434 /* Co-ords */
435 a = get_be24(this->packet + off);
436 b = get_be24(this->packet + off + 3);
437 start_col = a >> 12;
438 end_col = a & 0xfff;
439 width = (end_col < start_col) ? 0 : end_col - start_col + 1;
440 stride = (width + 7) & ~7; /* Kludge: draw_alpha needs width multiple of 8 */
441 start_row = b >> 12;
442 end_row = b & 0xfff;
443 height = (end_row < start_row) ? 0 : end_row - start_row /* + 1 */;
444 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Coords col: %d - %d row: %d - %d (%dx%d)\n",
445 start_col, end_col, start_row, end_row,
446 width, height);
447 off+=6;
448 break;
449 case 0x06:
450 /* Graphic lines */
451 current_nibble[0] = 2 * get_be16(this->packet + off);
452 current_nibble[1] = 2 * get_be16(this->packet + off + 2);
453 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Graphic offset 1: %d offset 2: %d\n",
454 current_nibble[0] / 2, current_nibble[1] / 2);
455 off+=4;
456 break;
457 case 0xff:
458 /* All done, bye-bye */
459 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Done!\n");
460 return;
461 // break;
462 default:
463 mp_msg(MSGT_SPUDEC,MSGL_WARN,"spudec: Error determining control type 0x%02x. Skipping %d bytes.\n",
464 type, next_off - off);
465 goto next_control;
468 next_control:
469 if (!display)
470 continue;
471 if (end_pts == UINT_MAX && start_off != next_off) {
472 end_pts = get_be16(this->packet + next_off) * 1024;
473 end_pts = 1 - pts100 >= end_pts ? 0 : pts100 + end_pts - 1;
475 if (end_pts > 0) {
476 packet_t *packet = calloc(1, sizeof(packet_t));
477 int i;
478 packet->start_pts = start_pts;
479 packet->end_pts = end_pts;
480 packet->current_nibble[0] = current_nibble[0];
481 packet->current_nibble[1] = current_nibble[1];
482 packet->start_row = start_row;
483 packet->end_row = end_row;
484 packet->start_col = start_col;
485 packet->end_col = end_col;
486 packet->width = width;
487 packet->height = height;
488 packet->stride = stride;
489 packet->control_start = control_start;
490 for (i=0; i<4; i++) {
491 packet->alpha[i] = this->alpha[i];
492 packet->palette[i] = this->palette[i];
494 packet->packet = malloc(this->packet_size);
495 memcpy(packet->packet, this->packet, this->packet_size);
496 spudec_queue_packet(this, packet);
501 static void spudec_decode(spudec_handle_t *this, int pts100)
503 if (!this->hw_spu)
504 spudec_process_control(this, pts100);
505 else if (pts100 >= 0) {
506 static vo_mpegpes_t packet = { NULL, 0, 0x20, 0 };
507 static vo_mpegpes_t *pkg=&packet;
508 packet.data = this->packet;
509 packet.size = this->packet_size;
510 packet.timestamp = pts100;
511 vo_draw_frame(this->hw_spu, (uint8_t**)&pkg);
515 int spudec_changed(void * this)
517 spudec_handle_t * spu = (spudec_handle_t*)this;
518 return spu->spu_changed || spu->now_pts > spu->end_pts;
521 void spudec_assemble(void *this, unsigned char *packet, unsigned int len, int pts100)
523 spudec_handle_t *spu = (spudec_handle_t*)this;
524 // spudec_heartbeat(this, pts100);
525 if (len < 2) {
526 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: packet too short\n");
527 return;
529 #if 0
530 if ((spu->packet_pts + 10000) < pts100) {
531 // [cb] too long since last fragment: force new packet
532 spu->packet_offset = 0;
534 #endif
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)
541 free(spu->packet);
542 spu->packet = malloc(len2);
543 spu->packet_reserve = spu->packet != NULL ? len2 : 0;
545 if (spu->packet != NULL) {
546 spu->packet_size = len2;
547 if (len > len2) {
548 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: invalid frag len / len2: %d / %d \n", len, len2);
549 return;
551 memcpy(spu->packet, packet, len);
552 spu->packet_offset = len;
553 spu->packet_pts = pts100;
555 } else {
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;
560 return;
561 } else {
562 memcpy(spu->packet + spu->packet_offset, packet, len);
563 spu->packet_offset += len;
566 #if 1
567 // check if we have a complete packet (unfortunatelly packet_size is bad
568 // for some disks)
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)){
572 unsigned int x=0,y;
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!
577 // we got it!
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;
581 break;
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;
586 break;
588 x=y;
590 // [cb] packet is done; start new packet
591 spu->packet_offset = 0;
593 #else
594 if (spu->packet_offset == spu->packet_size) {
595 spudec_decode(spu, pts100);
596 spu->packet_offset = 0;
598 #endif
601 void spudec_reset(void *this) // called after seek
603 spudec_handle_t *spu = (spudec_handle_t*)this;
604 while (spu->queue_head)
605 spudec_free_packet(spudec_dequeue_packet(spu));
606 spu->now_pts = 0;
607 spu->end_pts = 0;
608 spu->packet_size = spu->packet_offset = 0;
611 void spudec_heartbeat(void *this, unsigned int pts100)
613 spudec_handle_t *spu = (spudec_handle_t*) this;
614 spu->now_pts = pts100;
616 while (spu->queue_head != NULL && pts100 >= spu->queue_head->start_pts) {
617 packet_t *packet = spudec_dequeue_packet(spu);
618 spu->start_pts = packet->start_pts;
619 spu->end_pts = packet->end_pts;
620 if (spu->auto_palette)
621 compute_palette(spu, packet);
622 spudec_process_data(spu, packet);
623 spudec_free_packet(packet);
624 spu->spu_changed = 1;
628 int spudec_visible(void *this){
629 spudec_handle_t *spu = (spudec_handle_t *)this;
630 int ret=(spu->start_pts <= spu->now_pts &&
631 spu->now_pts < spu->end_pts &&
632 spu->height > 0);
633 // printf("spu visible: %d \n",ret);
634 return ret;
637 void spudec_set_forced_subs_only(void * const this, const unsigned int flag)
639 if(this){
640 ((spudec_handle_t *)this)->forced_subs_only=flag;
641 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPU: Display only forced subs now %s\n", flag ? "enabled": "disabled");
645 void spudec_draw(void *this, void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride))
647 spudec_handle_t *spu = (spudec_handle_t *)this;
648 if (spu->start_pts <= spu->now_pts && spu->now_pts < spu->end_pts && spu->image)
650 draw_alpha(spu->start_col, spu->start_row, spu->width, spu->height,
651 spu->image, spu->aimage, spu->stride);
652 spu->spu_changed = 0;
656 /* calc the bbox for spudec subs */
657 void spudec_calc_bbox(void *me, unsigned int dxs, unsigned int dys, unsigned int* bbox)
659 spudec_handle_t *spu;
660 spu = (spudec_handle_t *)me;
661 if (spu->orig_frame_width == 0 || spu->orig_frame_height == 0
662 || (spu->orig_frame_width == dxs && spu->orig_frame_height == dys)) {
663 bbox[0] = spu->start_col;
664 bbox[1] = spu->start_col + spu->width;
665 bbox[2] = spu->start_row;
666 bbox[3] = spu->start_row + spu->height;
668 else if (spu->scaled_frame_width != dxs || spu->scaled_frame_height != dys) {
669 unsigned int scalex = 0x100 * dxs / spu->orig_frame_width;
670 unsigned int scaley = 0x100 * dys / spu->orig_frame_height;
671 bbox[0] = spu->start_col * scalex / 0x100;
672 bbox[1] = spu->start_col * scalex / 0x100 + spu->width * scalex / 0x100;
673 switch (spu_alignment) {
674 case 0:
675 bbox[3] = dys*sub_pos/100 + spu->height * scaley / 0x100;
676 if (bbox[3] > dys) bbox[3] = dys;
677 bbox[2] = bbox[3] - spu->height * scaley / 0x100;
678 break;
679 case 1:
680 if (sub_pos < 50) {
681 bbox[2] = dys*sub_pos/100 - spu->height * scaley / 0x200;
682 bbox[3] = bbox[2] + spu->height;
683 } else {
684 bbox[3] = dys*sub_pos/100 + spu->height * scaley / 0x200;
685 if (bbox[3] > dys) bbox[3] = dys;
686 bbox[2] = bbox[3] - spu->height * scaley / 0x100;
688 break;
689 case 2:
690 bbox[2] = dys*sub_pos/100 - spu->height * scaley / 0x100;
691 bbox[3] = bbox[2] + spu->height;
692 break;
693 default: /* -1 */
694 bbox[2] = spu->start_row * scaley / 0x100;
695 bbox[3] = spu->start_row * scaley / 0x100 + spu->height * scaley / 0x100;
696 break;
700 /* transform mplayer's alpha value into an opacity value that is linear */
701 static inline int canon_alpha(int alpha)
703 return alpha ? 256 - alpha : 0;
706 typedef struct {
707 unsigned position;
708 unsigned left_up;
709 unsigned right_down;
710 }scale_pixel;
713 static void scale_table(unsigned int start_src, unsigned int start_tar, unsigned int end_src, unsigned int end_tar, scale_pixel * table)
715 unsigned int t;
716 unsigned int delta_src = end_src - start_src;
717 unsigned int delta_tar = end_tar - start_tar;
718 int src = 0;
719 int src_step;
720 if (delta_src == 0 || delta_tar == 0) {
721 return;
723 src_step = (delta_src << 16) / delta_tar >>1;
724 for (t = 0; t<=delta_tar; src += (src_step << 1), t++){
725 table[t].position= FFMIN(src >> 16, end_src - 1);
726 table[t].right_down = src & 0xffff;
727 table[t].left_up = 0x10000 - table[t].right_down;
731 /* bilinear scale, similar to vobsub's code */
732 static void scale_image(int x, int y, scale_pixel* table_x, scale_pixel* table_y, spudec_handle_t * spu)
734 int alpha[4];
735 int color[4];
736 unsigned int scale[4];
737 int base = table_y[y].position * spu->stride + table_x[x].position;
738 int scaled = y * spu->scaled_stride + x;
739 alpha[0] = canon_alpha(spu->aimage[base]);
740 alpha[1] = canon_alpha(spu->aimage[base + 1]);
741 alpha[2] = canon_alpha(spu->aimage[base + spu->stride]);
742 alpha[3] = canon_alpha(spu->aimage[base + spu->stride + 1]);
743 color[0] = spu->image[base];
744 color[1] = spu->image[base + 1];
745 color[2] = spu->image[base + spu->stride];
746 color[3] = spu->image[base + spu->stride + 1];
747 scale[0] = (table_x[x].left_up * table_y[y].left_up >> 16) * alpha[0];
748 if (table_y[y].left_up == 0x10000) // necessary to avoid overflow-case
749 scale[0] = table_x[x].left_up * alpha[0];
750 scale[1] = (table_x[x].right_down * table_y[y].left_up >>16) * alpha[1];
751 scale[2] = (table_x[x].left_up * table_y[y].right_down >> 16) * alpha[2];
752 scale[3] = (table_x[x].right_down * table_y[y].right_down >> 16) * alpha[3];
753 spu->scaled_image[scaled] = (color[0] * scale[0] + color[1] * scale[1] + color[2] * scale[2] + color[3] * scale[3])>>24;
754 spu->scaled_aimage[scaled] = (scale[0] + scale[1] + scale[2] + scale[3]) >> 16;
755 if (spu->scaled_aimage[scaled]){
756 // ensure that MPlayer's simplified alpha-blending can not overflow
757 spu->scaled_image[scaled] = FFMIN(spu->scaled_image[scaled], spu->scaled_aimage[scaled]);
758 // convert to MPlayer-style alpha
759 spu->scaled_aimage[scaled] = -spu->scaled_aimage[scaled];
763 static void sws_spu_image(unsigned char *d1, unsigned char *d2, int dw, int dh,
764 int ds, unsigned char *s1, unsigned char *s2, int sw,
765 int sh, int ss)
767 struct SwsContext *ctx;
768 static SwsFilter filter;
769 static int firsttime = 1;
770 static float oldvar;
771 int i;
773 if (!firsttime && oldvar != spu_gaussvar) sws_freeVec(filter.lumH);
774 if (firsttime) {
775 filter.lumH = filter.lumV =
776 filter.chrH = filter.chrV = sws_getGaussianVec(spu_gaussvar, 3.0);
777 sws_normalizeVec(filter.lumH, 1.0);
778 firsttime = 0;
779 oldvar = spu_gaussvar;
782 ctx=sws_getContext(sw, sh, PIX_FMT_GRAY8, dw, dh, PIX_FMT_GRAY8, SWS_GAUSS, &filter, NULL, NULL);
783 sws_scale(ctx,&s1,&ss,0,sh,&d1,&ds);
784 for (i=ss*sh-1; i>=0; i--) if (!s2[i]) s2[i] = 255; //else s2[i] = 1;
785 sws_scale(ctx,&s2,&ss,0,sh,&d2,&ds);
786 for (i=ds*dh-1; i>=0; i--) if (d2[i]==0) d2[i] = 1; else if (d2[i]==255) d2[i] = 0;
787 sws_freeContext(ctx);
790 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)
792 spudec_handle_t *spu = (spudec_handle_t *)me;
793 scale_pixel *table_x;
794 scale_pixel *table_y;
796 if (spu->start_pts <= spu->now_pts && spu->now_pts < spu->end_pts) {
798 // check if only forced subtitles are requested
799 if( (spu->forced_subs_only) && !(spu->is_forced_sub) ){
800 return;
803 if (!(spu_aamode&16) && (spu->orig_frame_width == 0 || spu->orig_frame_height == 0
804 || (spu->orig_frame_width == dxs && spu->orig_frame_height == dys))) {
805 if (spu->image)
807 draw_alpha(ctx, spu->start_col, spu->start_row, spu->width, spu->height,
808 spu->image, spu->aimage, spu->stride);
809 spu->spu_changed = 0;
812 else {
813 if (spu->scaled_frame_width != dxs || spu->scaled_frame_height != dys) { /* Resizing is needed */
814 /* scaled_x = scalex * x / 0x100
815 scaled_y = scaley * y / 0x100
816 order of operations is important because of rounding. */
817 unsigned int scalex = 0x100 * dxs / spu->orig_frame_width;
818 unsigned int scaley = 0x100 * dys / spu->orig_frame_height;
819 spu->scaled_start_col = spu->start_col * scalex / 0x100;
820 spu->scaled_start_row = spu->start_row * scaley / 0x100;
821 spu->scaled_width = spu->width * scalex / 0x100;
822 spu->scaled_height = spu->height * scaley / 0x100;
823 /* Kludge: draw_alpha needs width multiple of 8 */
824 spu->scaled_stride = (spu->scaled_width + 7) & ~7;
825 if (spu->scaled_image_size < spu->scaled_stride * spu->scaled_height) {
826 if (spu->scaled_image) {
827 free(spu->scaled_image);
828 spu->scaled_image_size = 0;
830 spu->scaled_image = malloc(2 * spu->scaled_stride * spu->scaled_height);
831 if (spu->scaled_image) {
832 spu->scaled_image_size = spu->scaled_stride * spu->scaled_height;
833 spu->scaled_aimage = spu->scaled_image + spu->scaled_image_size;
836 if (spu->scaled_image) {
837 unsigned int x, y;
838 if (spu->scaled_width <= 1 || spu->scaled_height <= 1) {
839 goto nothing_to_do;
841 switch(spu_aamode&15) {
842 case 4:
843 sws_spu_image(spu->scaled_image, spu->scaled_aimage,
844 spu->scaled_width, spu->scaled_height, spu->scaled_stride,
845 spu->image, spu->aimage, spu->width, spu->height, spu->stride);
846 break;
847 case 3:
848 table_x = calloc(spu->scaled_width, sizeof(scale_pixel));
849 table_y = calloc(spu->scaled_height, sizeof(scale_pixel));
850 if (!table_x || !table_y) {
851 mp_msg(MSGT_SPUDEC, MSGL_FATAL, "Fatal: spudec_draw_scaled: calloc failed\n");
853 scale_table(0, 0, spu->width - 1, spu->scaled_width - 1, table_x);
854 scale_table(0, 0, spu->height - 1, spu->scaled_height - 1, table_y);
855 for (y = 0; y < spu->scaled_height; y++)
856 for (x = 0; x < spu->scaled_width; x++)
857 scale_image(x, y, table_x, table_y, spu);
858 free(table_x);
859 free(table_y);
860 break;
861 case 0:
862 /* no antialiasing */
863 for (y = 0; y < spu->scaled_height; ++y) {
864 int unscaled_y = y * 0x100 / scaley;
865 int strides = spu->stride * unscaled_y;
866 int scaled_strides = spu->scaled_stride * y;
867 for (x = 0; x < spu->scaled_width; ++x) {
868 int unscaled_x = x * 0x100 / scalex;
869 spu->scaled_image[scaled_strides + x] = spu->image[strides + unscaled_x];
870 spu->scaled_aimage[scaled_strides + x] = spu->aimage[strides + unscaled_x];
873 break;
874 case 1:
876 /* Intermediate antialiasing. */
877 for (y = 0; y < spu->scaled_height; ++y) {
878 const unsigned int unscaled_top = y * spu->orig_frame_height / dys;
879 unsigned int unscaled_bottom = (y + 1) * spu->orig_frame_height / dys;
880 if (unscaled_bottom >= spu->height)
881 unscaled_bottom = spu->height - 1;
882 for (x = 0; x < spu->scaled_width; ++x) {
883 const unsigned int unscaled_left = x * spu->orig_frame_width / dxs;
884 unsigned int unscaled_right = (x + 1) * spu->orig_frame_width / dxs;
885 unsigned int color = 0;
886 unsigned int alpha = 0;
887 unsigned int walkx, walky;
888 unsigned int base, tmp;
889 if (unscaled_right >= spu->width)
890 unscaled_right = spu->width - 1;
891 for (walky = unscaled_top; walky <= unscaled_bottom; ++walky)
892 for (walkx = unscaled_left; walkx <= unscaled_right; ++walkx) {
893 base = walky * spu->stride + walkx;
894 tmp = canon_alpha(spu->aimage[base]);
895 alpha += tmp;
896 color += tmp * spu->image[base];
898 base = y * spu->scaled_stride + x;
899 spu->scaled_image[base] = alpha ? color / alpha : 0;
900 spu->scaled_aimage[base] =
901 alpha * (1 + unscaled_bottom - unscaled_top) * (1 + unscaled_right - unscaled_left);
902 /* spu->scaled_aimage[base] =
903 alpha * dxs * dys / spu->orig_frame_width / spu->orig_frame_height; */
904 if (spu->scaled_aimage[base]) {
905 spu->scaled_aimage[base] = 256 - spu->scaled_aimage[base];
906 if (spu->scaled_aimage[base] + spu->scaled_image[base] > 255)
907 spu->scaled_image[base] = 256 - spu->scaled_aimage[base];
912 break;
913 case 2:
915 /* Best antialiasing. Very slow. */
916 /* Any pixel (x, y) represents pixels from the original
917 rectangular region comprised between the columns
918 unscaled_y and unscaled_y + 0x100 / scaley and the rows
919 unscaled_x and unscaled_x + 0x100 / scalex
921 The original rectangular region that the scaled pixel
922 represents is cut in 9 rectangular areas like this:
924 +---+-----------------+---+
925 | 1 | 2 | 3 |
926 +---+-----------------+---+
927 | | | |
928 | 4 | 5 | 6 |
929 | | | |
930 +---+-----------------+---+
931 | 7 | 8 | 9 |
932 +---+-----------------+---+
934 The width of the left column is at most one pixel and
935 it is never null and its right column is at a pixel
936 boundary. The height of the top row is at most one
937 pixel it is never null and its bottom row is at a
938 pixel boundary. The width and height of region 5 are
939 integral values. The width of the right column is
940 what remains and is less than one pixel. The height
941 of the bottom row is what remains and is less than
942 one pixel.
944 The row above 1, 2, 3 is unscaled_y. The row between
945 1, 2, 3 and 4, 5, 6 is top_low_row. The row between 4,
946 5, 6 and 7, 8, 9 is (unsigned int)unscaled_y_bottom.
947 The row beneath 7, 8, 9 is unscaled_y_bottom.
949 The column left of 1, 4, 7 is unscaled_x. The column
950 between 1, 4, 7 and 2, 5, 8 is left_right_column. The
951 column between 2, 5, 8 and 3, 6, 9 is (unsigned
952 int)unscaled_x_right. The column right of 3, 6, 9 is
953 unscaled_x_right. */
954 const double inv_scalex = (double) 0x100 / scalex;
955 const double inv_scaley = (double) 0x100 / scaley;
956 for (y = 0; y < spu->scaled_height; ++y) {
957 const double unscaled_y = y * inv_scaley;
958 const double unscaled_y_bottom = unscaled_y + inv_scaley;
959 const unsigned int top_low_row = FFMIN(unscaled_y_bottom, unscaled_y + 1.0);
960 const double top = top_low_row - unscaled_y;
961 const unsigned int height = unscaled_y_bottom > top_low_row
962 ? (unsigned int) unscaled_y_bottom - top_low_row
963 : 0;
964 const double bottom = unscaled_y_bottom > top_low_row
965 ? unscaled_y_bottom - floor(unscaled_y_bottom)
966 : 0.0;
967 for (x = 0; x < spu->scaled_width; ++x) {
968 const double unscaled_x = x * inv_scalex;
969 const double unscaled_x_right = unscaled_x + inv_scalex;
970 const unsigned int left_right_column = FFMIN(unscaled_x_right, unscaled_x + 1.0);
971 const double left = left_right_column - unscaled_x;
972 const unsigned int width = unscaled_x_right > left_right_column
973 ? (unsigned int) unscaled_x_right - left_right_column
974 : 0;
975 const double right = unscaled_x_right > left_right_column
976 ? unscaled_x_right - floor(unscaled_x_right)
977 : 0.0;
978 double color = 0.0;
979 double alpha = 0.0;
980 double tmp;
981 unsigned int base;
982 /* Now use these informations to compute a good alpha,
983 and lightness. The sum is on each of the 9
984 region's surface and alpha and lightness.
986 transformed alpha = sum(surface * alpha) / sum(surface)
987 transformed color = sum(surface * alpha * color) / sum(surface * alpha)
989 /* 1: top left part */
990 base = spu->stride * (unsigned int) unscaled_y;
991 tmp = left * top * canon_alpha(spu->aimage[base + (unsigned int) unscaled_x]);
992 alpha += tmp;
993 color += tmp * spu->image[base + (unsigned int) unscaled_x];
994 /* 2: top center part */
995 if (width > 0) {
996 unsigned int walkx;
997 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
998 base = spu->stride * (unsigned int) unscaled_y + walkx;
999 tmp = /* 1.0 * */ top * canon_alpha(spu->aimage[base]);
1000 alpha += tmp;
1001 color += tmp * spu->image[base];
1004 /* 3: top right part */
1005 if (right > 0.0) {
1006 base = spu->stride * (unsigned int) unscaled_y + (unsigned int) unscaled_x_right;
1007 tmp = right * top * canon_alpha(spu->aimage[base]);
1008 alpha += tmp;
1009 color += tmp * spu->image[base];
1011 /* 4: center left part */
1012 if (height > 0) {
1013 unsigned int walky;
1014 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1015 base = spu->stride * walky + (unsigned int) unscaled_x;
1016 tmp = left /* * 1.0 */ * canon_alpha(spu->aimage[base]);
1017 alpha += tmp;
1018 color += tmp * spu->image[base];
1021 /* 5: center part */
1022 if (width > 0 && height > 0) {
1023 unsigned int walky;
1024 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1025 unsigned int walkx;
1026 base = spu->stride * walky;
1027 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
1028 tmp = /* 1.0 * 1.0 * */ canon_alpha(spu->aimage[base + walkx]);
1029 alpha += tmp;
1030 color += tmp * spu->image[base + walkx];
1034 /* 6: center right part */
1035 if (right > 0.0 && height > 0) {
1036 unsigned int walky;
1037 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1038 base = spu->stride * walky + (unsigned int) unscaled_x_right;
1039 tmp = right /* * 1.0 */ * canon_alpha(spu->aimage[base]);
1040 alpha += tmp;
1041 color += tmp * spu->image[base];
1044 /* 7: bottom left part */
1045 if (bottom > 0.0) {
1046 base = spu->stride * (unsigned int) unscaled_y_bottom + (unsigned int) unscaled_x;
1047 tmp = left * bottom * canon_alpha(spu->aimage[base]);
1048 alpha += tmp;
1049 color += tmp * spu->image[base];
1051 /* 8: bottom center part */
1052 if (width > 0 && bottom > 0.0) {
1053 unsigned int walkx;
1054 base = spu->stride * (unsigned int) unscaled_y_bottom;
1055 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
1056 tmp = /* 1.0 * */ bottom * canon_alpha(spu->aimage[base + walkx]);
1057 alpha += tmp;
1058 color += tmp * spu->image[base + walkx];
1061 /* 9: bottom right part */
1062 if (right > 0.0 && bottom > 0.0) {
1063 base = spu->stride * (unsigned int) unscaled_y_bottom + (unsigned int) unscaled_x_right;
1064 tmp = right * bottom * canon_alpha(spu->aimage[base]);
1065 alpha += tmp;
1066 color += tmp * spu->image[base];
1068 /* Finally mix these transparency and brightness information suitably */
1069 base = spu->scaled_stride * y + x;
1070 spu->scaled_image[base] = alpha > 0 ? color / alpha : 0;
1071 spu->scaled_aimage[base] = alpha * scalex * scaley / 0x10000;
1072 if (spu->scaled_aimage[base]) {
1073 spu->scaled_aimage[base] = 256 - spu->scaled_aimage[base];
1074 if (spu->scaled_aimage[base] + spu->scaled_image[base] > 255)
1075 spu->scaled_image[base] = 256 - spu->scaled_aimage[base];
1081 nothing_to_do:
1082 /* Kludge: draw_alpha needs width multiple of 8. */
1083 if (spu->scaled_width < spu->scaled_stride)
1084 for (y = 0; y < spu->scaled_height; ++y) {
1085 memset(spu->scaled_aimage + y * spu->scaled_stride + spu->scaled_width, 0,
1086 spu->scaled_stride - spu->scaled_width);
1088 spu->scaled_frame_width = dxs;
1089 spu->scaled_frame_height = dys;
1092 if (spu->scaled_image){
1093 switch (spu_alignment) {
1094 case 0:
1095 spu->scaled_start_row = dys*sub_pos/100;
1096 if (spu->scaled_start_row + spu->scaled_height > dys)
1097 spu->scaled_start_row = dys - spu->scaled_height;
1098 break;
1099 case 1:
1100 spu->scaled_start_row = dys*sub_pos/100 - spu->scaled_height/2;
1101 if (sub_pos >= 50 && spu->scaled_start_row + spu->scaled_height > dys)
1102 spu->scaled_start_row = dys - spu->scaled_height;
1103 break;
1104 case 2:
1105 spu->scaled_start_row = dys*sub_pos/100 - spu->scaled_height;
1106 break;
1108 draw_alpha(ctx, spu->scaled_start_col, spu->scaled_start_row, spu->scaled_width, spu->scaled_height,
1109 spu->scaled_image, spu->scaled_aimage, spu->scaled_stride);
1110 spu->spu_changed = 0;
1114 else
1116 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPU not displayed: start_pts=%d end_pts=%d now_pts=%d\n",
1117 spu->start_pts, spu->end_pts, spu->now_pts);
1121 void spudec_update_palette(void * this, unsigned int *palette)
1123 spudec_handle_t *spu = (spudec_handle_t *) this;
1124 if (spu && palette) {
1125 memcpy(spu->global_palette, palette, sizeof(spu->global_palette));
1126 if(spu->hw_spu)
1127 vo_control(spu->hw_spu, VOCTRL_SET_SPU_PALETTE, spu->global_palette);
1131 void spudec_set_font_factor(void * this, double factor)
1133 spudec_handle_t *spu = (spudec_handle_t *) this;
1134 spu->font_start_level = (int)(0xF0-(0xE0*factor));
1137 static void spudec_parse_extradata(spudec_handle_t *this,
1138 uint8_t *extradata, int extradata_len)
1140 uint8_t *buffer, *ptr;
1141 unsigned int *pal = this->global_palette, *cuspal = this->cuspal;
1142 unsigned int tridx;
1143 int i;
1145 if (extradata_len == 16*4) {
1146 for (i=0; i<16; i++)
1147 pal[i] = AV_RB32(extradata + i*4);
1148 this->auto_palette = 0;
1149 return;
1152 if (!(ptr = buffer = malloc(extradata_len+1)))
1153 return;
1154 memcpy(buffer, extradata, extradata_len);
1155 buffer[extradata_len] = 0;
1157 do {
1158 sscanf(ptr, "size: %dx%d", &this->orig_frame_width, &this->orig_frame_height);
1159 if (sscanf(ptr, "palette: %x, %x, %x, %x, %x, %x, %x, %x,"
1160 " %x, %x, %x, %x, %x, %x, %x, %x",
1161 &pal[ 0], &pal[ 1], &pal[ 2], &pal[ 3],
1162 &pal[ 4], &pal[ 5], &pal[ 6], &pal[ 7],
1163 &pal[ 8], &pal[ 9], &pal[10], &pal[11],
1164 &pal[12], &pal[13], &pal[14], &pal[15]) == 16) {
1165 for (i=0; i<16; i++)
1166 pal[i] = vobsub_palette_to_yuv(pal[i]);
1167 this->auto_palette = 0;
1169 if (!strncasecmp(ptr, "forced subs: on", 15))
1170 this->forced_subs_only = 1;
1171 if (sscanf(ptr, "custom colors: ON, tridx: %x, colors: %x, %x, %x, %x",
1172 &tridx, cuspal+0, cuspal+1, cuspal+2, cuspal+3) == 5) {
1173 for (i=0; i<4; i++) {
1174 cuspal[i] = vobsub_rgb_to_yuv(cuspal[i]);
1175 if (tridx & (1 << (12-4*i)))
1176 cuspal[i] |= 1 << 31;
1178 this->custom = 1;
1180 } while ((ptr=strchr(ptr,'\n')) && *++ptr);
1182 free(buffer);
1185 void *spudec_new_scaled(unsigned int *palette, unsigned int frame_width, unsigned int frame_height, uint8_t *extradata, int extradata_len)
1187 spudec_handle_t *this = calloc(1, sizeof(spudec_handle_t));
1188 if (this){
1189 this->orig_frame_height = frame_height;
1190 // set up palette:
1191 if (palette)
1192 memcpy(this->global_palette, palette, sizeof(this->global_palette));
1193 else
1194 this->auto_palette = 1;
1195 if (extradata)
1196 spudec_parse_extradata(this, extradata, extradata_len);
1197 /* XXX Although the video frame is some size, the SPU frame is
1198 always maximum size i.e. 720 wide and 576 or 480 high */
1199 this->orig_frame_width = 720;
1200 if (this->orig_frame_height == 480 || this->orig_frame_height == 240)
1201 this->orig_frame_height = 480;
1202 else
1203 this->orig_frame_height = 576;
1205 else
1206 mp_msg(MSGT_SPUDEC,MSGL_FATAL, "FATAL: spudec_init: calloc");
1207 return this;
1210 void *spudec_new(unsigned int *palette)
1212 return spudec_new_scaled(palette, 0, 0, NULL, 0);
1215 void spudec_free(void *this)
1217 spudec_handle_t *spu = (spudec_handle_t*)this;
1218 if (spu) {
1219 while (spu->queue_head)
1220 spudec_free_packet(spudec_dequeue_packet(spu));
1221 if (spu->packet)
1222 free(spu->packet);
1223 if (spu->scaled_image)
1224 free(spu->scaled_image);
1225 if (spu->image)
1226 free(spu->image);
1227 free(spu);
1231 void spudec_set_hw_spu(void *this, struct vo *hw_spu)
1233 spudec_handle_t *spu = (spudec_handle_t*)this;
1234 if (!spu)
1235 return;
1236 spu->hw_spu = hw_spu;
1237 vo_control(hw_spu, VOCTRL_SET_SPU_PALETTE, spu->global_palette);