Fix typo in message.
[mplayer/glamo.git] / spudec.c
blobe4267bf49a98f791d54eb822140c3665f265e0ac
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 "libavutil/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 const vo_functions_t *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 fully opaque */
178 // extend 4 -> 8 bit
179 i |= i << 4;
180 return (uint8_t)(-i);
183 /* Cut the sub to visible part */
184 static inline void spudec_cut_image(spudec_handle_t *this)
186 unsigned int fy, ly;
187 unsigned int first_y, last_y;
188 unsigned char *image;
189 unsigned char *aimage;
191 if (this->stride == 0 || this->height == 0) {
192 return;
195 for (fy = 0; fy < this->image_size && !this->aimage[fy]; fy++);
196 for (ly = this->stride * this->height-1; ly && !this->aimage[ly]; ly--);
197 first_y = fy / this->stride;
198 last_y = ly / this->stride;
199 //printf("first_y: %d, last_y: %d\n", first_y, last_y);
200 this->start_row += first_y;
202 // Some subtitles trigger this condition
203 if (last_y + 1 > first_y ) {
204 this->height = last_y - first_y +1;
205 } else {
206 this->height = 0;
207 this->image_size = 0;
208 return;
211 // printf("new h %d new start %d (sz %d st %d)---\n\n", this->height, this->start_row, this->image_size, this->stride);
213 image = malloc(2 * this->stride * this->height);
214 if(image){
215 this->image_size = this->stride * this->height;
216 aimage = image + this->image_size;
217 memcpy(image, this->image + this->stride * first_y, this->image_size);
218 memcpy(aimage, this->aimage + this->stride * first_y, this->image_size);
219 free(this->image);
220 this->image = image;
221 this->aimage = aimage;
222 } else {
223 mp_msg(MSGT_SPUDEC, MSGL_FATAL, "Fatal: update_spu: malloc requested %d bytes\n", 2 * this->stride * this->height);
227 static void spudec_process_data(spudec_handle_t *this, packet_t *packet)
229 unsigned int cmap[4], alpha[4];
230 unsigned int i, x, y;
232 this->scaled_frame_width = 0;
233 this->scaled_frame_height = 0;
234 this->start_col = packet->start_col;
235 this->end_col = packet->end_col;
236 this->start_row = packet->start_row;
237 this->end_row = packet->end_row;
238 this->height = packet->height;
239 this->width = packet->width;
240 this->stride = packet->stride;
241 for (i = 0; i < 4; ++i) {
242 alpha[i] = mkalpha(packet->alpha[i]);
243 if (this->custom && (this->cuspal[i] >> 31) != 0)
244 alpha[i] = 0;
245 if (alpha[i] == 0)
246 cmap[i] = 0;
247 else if (this->custom){
248 cmap[i] = ((this->cuspal[i] >> 16) & 0xff);
249 if (cmap[i] + alpha[i] > 255)
250 cmap[i] = 256 - alpha[i];
252 else {
253 cmap[i] = ((this->global_palette[packet->palette[i]] >> 16) & 0xff);
254 if (cmap[i] + alpha[i] > 255)
255 cmap[i] = 256 - alpha[i];
259 if (this->image_size < this->stride * this->height) {
260 if (this->image != NULL) {
261 free(this->image);
262 this->image_size = 0;
264 this->image = malloc(2 * this->stride * this->height);
265 if (this->image) {
266 this->image_size = this->stride * this->height;
267 this->aimage = this->image + this->image_size;
270 if (this->image == NULL)
271 return;
273 /* Kludge: draw_alpha needs width multiple of 8. */
274 if (this->width < this->stride)
275 for (y = 0; y < this->height; ++y) {
276 memset(this->aimage + y * this->stride + this->width, 0, this->stride - this->width);
277 /* FIXME: Why is this one needed? */
278 memset(this->image + y * this->stride + this->width, 0, this->stride - this->width);
281 i = packet->current_nibble[1];
282 x = 0;
283 y = 0;
284 while (packet->current_nibble[0] < i
285 && packet->current_nibble[1] / 2 < packet->control_start
286 && y < this->height) {
287 unsigned int len, color;
288 unsigned int rle = 0;
289 rle = get_nibble(packet);
290 if (rle < 0x04) {
291 rle = (rle << 4) | get_nibble(packet);
292 if (rle < 0x10) {
293 rle = (rle << 4) | get_nibble(packet);
294 if (rle < 0x040) {
295 rle = (rle << 4) | get_nibble(packet);
296 if (rle < 0x0004)
297 rle |= ((this->width - x) << 2);
301 color = 3 - (rle & 0x3);
302 len = rle >> 2;
303 if (len > this->width - x || len == 0)
304 len = this->width - x;
305 /* FIXME have to use palette and alpha map*/
306 memset(this->image + y * this->stride + x, cmap[color], len);
307 memset(this->aimage + y * this->stride + x, alpha[color], len);
308 x += len;
309 if (x >= this->width) {
310 next_line(packet);
311 x = 0;
312 ++y;
315 spudec_cut_image(this);
320 This function tries to create a usable palette.
321 It determines how many non-transparent colors are used, and assigns different
322 gray scale values to each color.
323 I tested it with four streams and even got something readable. Half of the
324 times I got black characters with white around and half the reverse.
326 static void compute_palette(spudec_handle_t *this, packet_t *packet)
328 int used[16],i,cused,start,step,color;
330 memset(used, 0, sizeof(used));
331 for (i=0; i<4; i++)
332 if (packet->alpha[i]) /* !Transparent? */
333 used[packet->palette[i]] = 1;
334 for (cused=0, i=0; i<16; i++)
335 if (used[i]) cused++;
336 if (!cused) return;
337 if (cused == 1) {
338 start = 0x80;
339 step = 0;
340 } else {
341 start = this->font_start_level;
342 step = (0xF0-this->font_start_level)/(cused-1);
344 memset(used, 0, sizeof(used));
345 for (i=0; i<4; i++) {
346 color = packet->palette[i];
347 if (packet->alpha[i] && !used[color]) { /* not assigned? */
348 used[color] = 1;
349 this->global_palette[color] = start<<16;
350 start += step;
355 static void spudec_process_control(spudec_handle_t *this, int pts100)
357 int a,b,c,d; /* Temporary vars */
358 unsigned int date, type;
359 unsigned int off;
360 unsigned int start_off = 0;
361 unsigned int next_off;
362 unsigned int start_pts = 0;
363 unsigned int end_pts = 0;
364 unsigned int current_nibble[2] = {0, 0};
365 unsigned int control_start;
366 unsigned int display = 0;
367 unsigned int start_col = 0;
368 unsigned int end_col = 0;
369 unsigned int start_row = 0;
370 unsigned int end_row = 0;
371 unsigned int width = 0;
372 unsigned int height = 0;
373 unsigned int stride = 0;
375 control_start = get_be16(this->packet + 2);
376 next_off = control_start;
377 while (start_off != next_off) {
378 start_off = next_off;
379 date = get_be16(this->packet + start_off) * 1024;
380 next_off = get_be16(this->packet + start_off + 2);
381 mp_msg(MSGT_SPUDEC,MSGL_DBG2, "date=%d\n", date);
382 off = start_off + 4;
383 for (type = this->packet[off++]; type != 0xff; type = this->packet[off++]) {
384 mp_msg(MSGT_SPUDEC,MSGL_DBG2, "cmd=%d ",type);
385 switch(type) {
386 case 0x00:
387 /* Menu ID, 1 byte */
388 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Menu ID\n");
389 /* shouldn't a Menu ID type force display start? */
390 start_pts = pts100 < 0 && -pts100 >= date ? 0 : pts100 + date;
391 end_pts = UINT_MAX;
392 display = 1;
393 this->is_forced_sub=~0; // current subtitle is forced
394 break;
395 case 0x01:
396 /* Start display */
397 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Start display!\n");
398 start_pts = pts100 < 0 && -pts100 >= date ? 0 : pts100 + date;
399 end_pts = UINT_MAX;
400 display = 1;
401 this->is_forced_sub=0;
402 break;
403 case 0x02:
404 /* Stop display */
405 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Stop display!\n");
406 end_pts = pts100 < 0 && -pts100 >= date ? 0 : pts100 + date;
407 break;
408 case 0x03:
409 /* Palette */
410 this->palette[0] = this->packet[off] >> 4;
411 this->palette[1] = this->packet[off] & 0xf;
412 this->palette[2] = this->packet[off + 1] >> 4;
413 this->palette[3] = this->packet[off + 1] & 0xf;
414 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Palette %d, %d, %d, %d\n",
415 this->palette[0], this->palette[1], this->palette[2], this->palette[3]);
416 off+=2;
417 break;
418 case 0x04:
419 /* Alpha */
420 a = this->packet[off] >> 4;
421 b = this->packet[off] & 0xf;
422 c = this->packet[off + 1] >> 4;
423 d = this->packet[off + 1] & 0xf;
424 // Note: some DVDs change these values to create a fade-in/fade-out effect
425 // We can not handle this, so just keep the highest value during the display time.
426 if (display) {
427 a = FFMAX(a, this->alpha[0]);
428 b = FFMAX(b, this->alpha[1]);
429 c = FFMAX(c, this->alpha[2]);
430 d = FFMAX(d, this->alpha[3]);
432 this->alpha[0] = a;
433 this->alpha[1] = b;
434 this->alpha[2] = c;
435 this->alpha[3] = d;
436 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Alpha %d, %d, %d, %d\n",
437 this->alpha[0], this->alpha[1], this->alpha[2], this->alpha[3]);
438 off+=2;
439 break;
440 case 0x05:
441 /* Co-ords */
442 a = get_be24(this->packet + off);
443 b = get_be24(this->packet + off + 3);
444 start_col = a >> 12;
445 end_col = a & 0xfff;
446 width = (end_col < start_col) ? 0 : end_col - start_col + 1;
447 stride = (width + 7) & ~7; /* Kludge: draw_alpha needs width multiple of 8 */
448 start_row = b >> 12;
449 end_row = b & 0xfff;
450 height = (end_row < start_row) ? 0 : end_row - start_row /* + 1 */;
451 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Coords col: %d - %d row: %d - %d (%dx%d)\n",
452 start_col, end_col, start_row, end_row,
453 width, height);
454 off+=6;
455 break;
456 case 0x06:
457 /* Graphic lines */
458 current_nibble[0] = 2 * get_be16(this->packet + off);
459 current_nibble[1] = 2 * get_be16(this->packet + off + 2);
460 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Graphic offset 1: %d offset 2: %d\n",
461 current_nibble[0] / 2, current_nibble[1] / 2);
462 off+=4;
463 break;
464 case 0xff:
465 /* All done, bye-bye */
466 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Done!\n");
467 return;
468 // break;
469 default:
470 mp_msg(MSGT_SPUDEC,MSGL_WARN,"spudec: Error determining control type 0x%02x. Skipping %d bytes.\n",
471 type, next_off - off);
472 goto next_control;
475 next_control:
476 if (!display)
477 continue;
478 if (end_pts == UINT_MAX && start_off != next_off) {
479 end_pts = get_be16(this->packet + next_off) * 1024;
480 end_pts = 1 - pts100 >= end_pts ? 0 : pts100 + end_pts - 1;
482 if (end_pts > 0) {
483 packet_t *packet = calloc(1, sizeof(packet_t));
484 int i;
485 packet->start_pts = start_pts;
486 packet->end_pts = end_pts;
487 packet->current_nibble[0] = current_nibble[0];
488 packet->current_nibble[1] = current_nibble[1];
489 packet->start_row = start_row;
490 packet->end_row = end_row;
491 packet->start_col = start_col;
492 packet->end_col = end_col;
493 packet->width = width;
494 packet->height = height;
495 packet->stride = stride;
496 packet->control_start = control_start;
497 for (i=0; i<4; i++) {
498 packet->alpha[i] = this->alpha[i];
499 packet->palette[i] = this->palette[i];
501 packet->packet = malloc(this->packet_size);
502 memcpy(packet->packet, this->packet, this->packet_size);
503 spudec_queue_packet(this, packet);
508 static void spudec_decode(spudec_handle_t *this, int pts100)
510 if (!this->hw_spu)
511 spudec_process_control(this, pts100);
512 else if (pts100 >= 0) {
513 static vo_mpegpes_t packet = { NULL, 0, 0x20, 0 };
514 static vo_mpegpes_t *pkg=&packet;
515 packet.data = this->packet;
516 packet.size = this->packet_size;
517 packet.timestamp = pts100;
518 this->hw_spu->draw_frame((uint8_t**)&pkg);
522 int spudec_changed(void * this)
524 spudec_handle_t * spu = (spudec_handle_t*)this;
525 return spu->spu_changed || spu->now_pts > spu->end_pts;
528 void spudec_assemble(void *this, unsigned char *packet, unsigned int len, int pts100)
530 spudec_handle_t *spu = (spudec_handle_t*)this;
531 // spudec_heartbeat(this, pts100);
532 if (len < 2) {
533 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: packet too short\n");
534 return;
536 spu->packet_pts = pts100;
537 if (spu->packet_offset == 0) {
538 unsigned int len2 = get_be16(packet);
539 // Start new fragment
540 if (spu->packet_reserve < len2) {
541 if (spu->packet != NULL)
542 free(spu->packet);
543 spu->packet = malloc(len2);
544 spu->packet_reserve = spu->packet != NULL ? len2 : 0;
546 if (spu->packet != NULL) {
547 spu->packet_size = len2;
548 if (len > len2) {
549 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: invalid frag len / len2: %d / %d \n", len, len2);
550 return;
552 memcpy(spu->packet, packet, len);
553 spu->packet_offset = len;
554 spu->packet_pts = pts100;
556 } else {
557 // Continue current fragment
558 if (spu->packet_size < spu->packet_offset + len){
559 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: invalid fragment\n");
560 spu->packet_size = spu->packet_offset = 0;
561 return;
562 } else {
563 memcpy(spu->packet + spu->packet_offset, packet, len);
564 spu->packet_offset += len;
567 #if 1
568 // check if we have a complete packet (unfortunatelly packet_size is bad
569 // for some disks)
570 // [cb] packet_size is padded to be even -> may be one byte too long
571 if ((spu->packet_offset == spu->packet_size) ||
572 ((spu->packet_offset + 1) == spu->packet_size)){
573 unsigned int x=0,y;
574 while(x+4<=spu->packet_offset){
575 y=get_be16(spu->packet+x+2); // next control pointer
576 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPUtest: x=%d y=%d off=%d size=%d\n",x,y,spu->packet_offset,spu->packet_size);
577 if(x>=4 && x==y){ // if it points to self - we're done!
578 // we got it!
579 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPUgot: off=%d size=%d \n",spu->packet_offset,spu->packet_size);
580 spudec_decode(spu, pts100);
581 spu->packet_offset = 0;
582 break;
584 if(y<=x || y>=spu->packet_size){ // invalid?
585 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUtest: broken packet!!!!! y=%d < x=%d\n",y,x);
586 spu->packet_size = spu->packet_offset = 0;
587 break;
589 x=y;
591 // [cb] packet is done; start new packet
592 spu->packet_offset = 0;
594 #else
595 if (spu->packet_offset == spu->packet_size) {
596 spudec_decode(spu, pts100);
597 spu->packet_offset = 0;
599 #endif
602 void spudec_reset(void *this) // called after seek
604 spudec_handle_t *spu = (spudec_handle_t*)this;
605 while (spu->queue_head)
606 spudec_free_packet(spudec_dequeue_packet(spu));
607 spu->now_pts = 0;
608 spu->end_pts = 0;
609 spu->packet_size = spu->packet_offset = 0;
612 void spudec_heartbeat(void *this, unsigned int pts100)
614 spudec_handle_t *spu = (spudec_handle_t*) this;
615 spu->now_pts = pts100;
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 (spu->auto_palette)
622 compute_palette(spu, packet);
623 spudec_process_data(spu, packet);
624 spudec_free_packet(packet);
625 spu->spu_changed = 1;
629 int spudec_visible(void *this){
630 spudec_handle_t *spu = (spudec_handle_t *)this;
631 int ret=(spu->start_pts <= spu->now_pts &&
632 spu->now_pts < spu->end_pts &&
633 spu->height > 0);
634 // printf("spu visible: %d \n",ret);
635 return ret;
638 void spudec_set_forced_subs_only(void * const this, const unsigned int flag)
640 if(this){
641 ((spudec_handle_t *)this)->forced_subs_only=flag;
642 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPU: Display only forced subs now %s\n", flag ? "enabled": "disabled");
646 void spudec_draw(void *this, void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride))
648 spudec_handle_t *spu = (spudec_handle_t *)this;
649 if (spu->start_pts <= spu->now_pts && spu->now_pts < spu->end_pts && spu->image)
651 draw_alpha(spu->start_col, spu->start_row, spu->width, spu->height,
652 spu->image, spu->aimage, spu->stride);
653 spu->spu_changed = 0;
657 /* calc the bbox for spudec subs */
658 void spudec_calc_bbox(void *me, unsigned int dxs, unsigned int dys, unsigned int* bbox)
660 spudec_handle_t *spu;
661 spu = (spudec_handle_t *)me;
662 if (spu->orig_frame_width == 0 || spu->orig_frame_height == 0
663 || (spu->orig_frame_width == dxs && spu->orig_frame_height == dys)) {
664 bbox[0] = spu->start_col;
665 bbox[1] = spu->start_col + spu->width;
666 bbox[2] = spu->start_row;
667 bbox[3] = spu->start_row + spu->height;
669 else if (spu->scaled_frame_width != dxs || spu->scaled_frame_height != dys) {
670 unsigned int scalex = 0x100 * dxs / spu->orig_frame_width;
671 unsigned int scaley = 0x100 * dys / spu->orig_frame_height;
672 bbox[0] = spu->start_col * scalex / 0x100;
673 bbox[1] = spu->start_col * scalex / 0x100 + spu->width * scalex / 0x100;
674 switch (spu_alignment) {
675 case 0:
676 bbox[3] = dys*sub_pos/100 + spu->height * scaley / 0x100;
677 if (bbox[3] > dys) bbox[3] = dys;
678 bbox[2] = bbox[3] - spu->height * scaley / 0x100;
679 break;
680 case 1:
681 if (sub_pos < 50) {
682 bbox[2] = dys*sub_pos/100 - spu->height * scaley / 0x200;
683 bbox[3] = bbox[2] + spu->height;
684 } else {
685 bbox[3] = dys*sub_pos/100 + spu->height * scaley / 0x200;
686 if (bbox[3] > dys) bbox[3] = dys;
687 bbox[2] = bbox[3] - spu->height * scaley / 0x100;
689 break;
690 case 2:
691 bbox[2] = dys*sub_pos/100 - spu->height * scaley / 0x100;
692 bbox[3] = bbox[2] + spu->height;
693 break;
694 default: /* -1 */
695 bbox[2] = spu->start_row * scaley / 0x100;
696 bbox[3] = spu->start_row * scaley / 0x100 + spu->height * scaley / 0x100;
697 break;
701 /* transform mplayer's alpha value into an opacity value that is linear */
702 static inline int canon_alpha(int alpha)
704 return alpha ? 256 - alpha : 0;
707 typedef struct {
708 unsigned position;
709 unsigned left_up;
710 unsigned right_down;
711 }scale_pixel;
714 static void scale_table(unsigned int start_src, unsigned int start_tar, unsigned int end_src, unsigned int end_tar, scale_pixel * table)
716 unsigned int t;
717 unsigned int delta_src = end_src - start_src;
718 unsigned int delta_tar = end_tar - start_tar;
719 int src = 0;
720 int src_step;
721 if (delta_src == 0 || delta_tar == 0) {
722 return;
724 src_step = (delta_src << 16) / delta_tar >>1;
725 for (t = 0; t<=delta_tar; src += (src_step << 1), t++){
726 table[t].position= FFMIN(src >> 16, end_src - 1);
727 table[t].right_down = src & 0xffff;
728 table[t].left_up = 0x10000 - table[t].right_down;
732 /* bilinear scale, similar to vobsub's code */
733 static void scale_image(int x, int y, scale_pixel* table_x, scale_pixel* table_y, spudec_handle_t * spu)
735 int alpha[4];
736 int color[4];
737 unsigned int scale[4];
738 int base = table_y[y].position * spu->stride + table_x[x].position;
739 int scaled = y * spu->scaled_stride + x;
740 alpha[0] = canon_alpha(spu->aimage[base]);
741 alpha[1] = canon_alpha(spu->aimage[base + 1]);
742 alpha[2] = canon_alpha(spu->aimage[base + spu->stride]);
743 alpha[3] = canon_alpha(spu->aimage[base + spu->stride + 1]);
744 color[0] = spu->image[base];
745 color[1] = spu->image[base + 1];
746 color[2] = spu->image[base + spu->stride];
747 color[3] = spu->image[base + spu->stride + 1];
748 scale[0] = (table_x[x].left_up * table_y[y].left_up >> 16) * alpha[0];
749 if (table_y[y].left_up == 0x10000) // necessary to avoid overflow-case
750 scale[0] = table_x[x].left_up * alpha[0];
751 scale[1] = (table_x[x].right_down * table_y[y].left_up >>16) * alpha[1];
752 scale[2] = (table_x[x].left_up * table_y[y].right_down >> 16) * alpha[2];
753 scale[3] = (table_x[x].right_down * table_y[y].right_down >> 16) * alpha[3];
754 spu->scaled_image[scaled] = (color[0] * scale[0] + color[1] * scale[1] + color[2] * scale[2] + color[3] * scale[3])>>24;
755 spu->scaled_aimage[scaled] = (scale[0] + scale[1] + scale[2] + scale[3]) >> 16;
756 if (spu->scaled_aimage[scaled]){
757 // ensure that MPlayer's simplified alpha-blending can not overflow
758 spu->scaled_image[scaled] = FFMIN(spu->scaled_image[scaled], spu->scaled_aimage[scaled]);
759 // convert to MPlayer-style alpha
760 spu->scaled_aimage[scaled] = -spu->scaled_aimage[scaled];
764 static void sws_spu_image(unsigned char *d1, unsigned char *d2, int dw, int dh,
765 int ds, unsigned char *s1, unsigned char *s2, int sw,
766 int sh, int ss)
768 struct SwsContext *ctx;
769 static SwsFilter filter;
770 static int firsttime = 1;
771 static float oldvar;
772 int i;
774 if (!firsttime && oldvar != spu_gaussvar) sws_freeVec(filter.lumH);
775 if (firsttime) {
776 filter.lumH = filter.lumV =
777 filter.chrH = filter.chrV = sws_getGaussianVec(spu_gaussvar, 3.0);
778 sws_normalizeVec(filter.lumH, 1.0);
779 firsttime = 0;
780 oldvar = spu_gaussvar;
783 ctx=sws_getContext(sw, sh, PIX_FMT_GRAY8, dw, dh, PIX_FMT_GRAY8, SWS_GAUSS, &filter, NULL, NULL);
784 sws_scale(ctx,&s1,&ss,0,sh,&d1,&ds);
785 for (i=ss*sh-1; i>=0; i--) if (!s2[i]) s2[i] = 255; //else s2[i] = 1;
786 sws_scale(ctx,&s2,&ss,0,sh,&d2,&ds);
787 for (i=ds*dh-1; i>=0; i--) if (d2[i]==0) d2[i] = 1; else if (d2[i]==255) d2[i] = 0;
788 sws_freeContext(ctx);
791 void spudec_draw_scaled(void *me, unsigned int dxs, unsigned int dys, void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride))
793 spudec_handle_t *spu = (spudec_handle_t *)me;
794 scale_pixel *table_x;
795 scale_pixel *table_y;
797 if (spu->start_pts <= spu->now_pts && spu->now_pts < spu->end_pts) {
799 // check if only forced subtitles are requested
800 if( (spu->forced_subs_only) && !(spu->is_forced_sub) ){
801 return;
804 if (!(spu_aamode&16) && (spu->orig_frame_width == 0 || spu->orig_frame_height == 0
805 || (spu->orig_frame_width == dxs && spu->orig_frame_height == dys))) {
806 if (spu->image)
808 draw_alpha(spu->start_col, spu->start_row, spu->width, spu->height,
809 spu->image, spu->aimage, spu->stride);
810 spu->spu_changed = 0;
813 else {
814 if (spu->scaled_frame_width != dxs || spu->scaled_frame_height != dys) { /* Resizing is needed */
815 /* scaled_x = scalex * x / 0x100
816 scaled_y = scaley * y / 0x100
817 order of operations is important because of rounding. */
818 unsigned int scalex = 0x100 * dxs / spu->orig_frame_width;
819 unsigned int scaley = 0x100 * dys / spu->orig_frame_height;
820 spu->scaled_start_col = spu->start_col * scalex / 0x100;
821 spu->scaled_start_row = spu->start_row * scaley / 0x100;
822 spu->scaled_width = spu->width * scalex / 0x100;
823 spu->scaled_height = spu->height * scaley / 0x100;
824 /* Kludge: draw_alpha needs width multiple of 8 */
825 spu->scaled_stride = (spu->scaled_width + 7) & ~7;
826 if (spu->scaled_image_size < spu->scaled_stride * spu->scaled_height) {
827 if (spu->scaled_image) {
828 free(spu->scaled_image);
829 spu->scaled_image_size = 0;
831 spu->scaled_image = malloc(2 * spu->scaled_stride * spu->scaled_height);
832 if (spu->scaled_image) {
833 spu->scaled_image_size = spu->scaled_stride * spu->scaled_height;
834 spu->scaled_aimage = spu->scaled_image + spu->scaled_image_size;
837 if (spu->scaled_image) {
838 unsigned int x, y;
839 if (spu->scaled_width <= 1 || spu->scaled_height <= 1) {
840 goto nothing_to_do;
842 switch(spu_aamode&15) {
843 case 4:
844 sws_spu_image(spu->scaled_image, spu->scaled_aimage,
845 spu->scaled_width, spu->scaled_height, spu->scaled_stride,
846 spu->image, spu->aimage, spu->width, spu->height, spu->stride);
847 break;
848 case 3:
849 table_x = calloc(spu->scaled_width, sizeof(scale_pixel));
850 table_y = calloc(spu->scaled_height, sizeof(scale_pixel));
851 if (!table_x || !table_y) {
852 mp_msg(MSGT_SPUDEC, MSGL_FATAL, "Fatal: spudec_draw_scaled: calloc failed\n");
854 scale_table(0, 0, spu->width - 1, spu->scaled_width - 1, table_x);
855 scale_table(0, 0, spu->height - 1, spu->scaled_height - 1, table_y);
856 for (y = 0; y < spu->scaled_height; y++)
857 for (x = 0; x < spu->scaled_width; x++)
858 scale_image(x, y, table_x, table_y, spu);
859 free(table_x);
860 free(table_y);
861 break;
862 case 0:
863 /* no antialiasing */
864 for (y = 0; y < spu->scaled_height; ++y) {
865 int unscaled_y = y * 0x100 / scaley;
866 int strides = spu->stride * unscaled_y;
867 int scaled_strides = spu->scaled_stride * y;
868 for (x = 0; x < spu->scaled_width; ++x) {
869 int unscaled_x = x * 0x100 / scalex;
870 spu->scaled_image[scaled_strides + x] = spu->image[strides + unscaled_x];
871 spu->scaled_aimage[scaled_strides + x] = spu->aimage[strides + unscaled_x];
874 break;
875 case 1:
877 /* Intermediate antialiasing. */
878 for (y = 0; y < spu->scaled_height; ++y) {
879 const unsigned int unscaled_top = y * spu->orig_frame_height / dys;
880 unsigned int unscaled_bottom = (y + 1) * spu->orig_frame_height / dys;
881 if (unscaled_bottom >= spu->height)
882 unscaled_bottom = spu->height - 1;
883 for (x = 0; x < spu->scaled_width; ++x) {
884 const unsigned int unscaled_left = x * spu->orig_frame_width / dxs;
885 unsigned int unscaled_right = (x + 1) * spu->orig_frame_width / dxs;
886 unsigned int color = 0;
887 unsigned int alpha = 0;
888 unsigned int walkx, walky;
889 unsigned int base, tmp;
890 if (unscaled_right >= spu->width)
891 unscaled_right = spu->width - 1;
892 for (walky = unscaled_top; walky <= unscaled_bottom; ++walky)
893 for (walkx = unscaled_left; walkx <= unscaled_right; ++walkx) {
894 base = walky * spu->stride + walkx;
895 tmp = canon_alpha(spu->aimage[base]);
896 alpha += tmp;
897 color += tmp * spu->image[base];
899 base = y * spu->scaled_stride + x;
900 spu->scaled_image[base] = alpha ? color / alpha : 0;
901 spu->scaled_aimage[base] =
902 alpha * (1 + unscaled_bottom - unscaled_top) * (1 + unscaled_right - unscaled_left);
903 /* spu->scaled_aimage[base] =
904 alpha * dxs * dys / spu->orig_frame_width / spu->orig_frame_height; */
905 if (spu->scaled_aimage[base]) {
906 spu->scaled_aimage[base] = 256 - spu->scaled_aimage[base];
907 if (spu->scaled_aimage[base] + spu->scaled_image[base] > 255)
908 spu->scaled_image[base] = 256 - spu->scaled_aimage[base];
913 break;
914 case 2:
916 /* Best antialiasing. Very slow. */
917 /* Any pixel (x, y) represents pixels from the original
918 rectangular region comprised between the columns
919 unscaled_y and unscaled_y + 0x100 / scaley and the rows
920 unscaled_x and unscaled_x + 0x100 / scalex
922 The original rectangular region that the scaled pixel
923 represents is cut in 9 rectangular areas like this:
925 +---+-----------------+---+
926 | 1 | 2 | 3 |
927 +---+-----------------+---+
928 | | | |
929 | 4 | 5 | 6 |
930 | | | |
931 +---+-----------------+---+
932 | 7 | 8 | 9 |
933 +---+-----------------+---+
935 The width of the left column is at most one pixel and
936 it is never null and its right column is at a pixel
937 boundary. The height of the top row is at most one
938 pixel it is never null and its bottom row is at a
939 pixel boundary. The width and height of region 5 are
940 integral values. The width of the right column is
941 what remains and is less than one pixel. The height
942 of the bottom row is what remains and is less than
943 one pixel.
945 The row above 1, 2, 3 is unscaled_y. The row between
946 1, 2, 3 and 4, 5, 6 is top_low_row. The row between 4,
947 5, 6 and 7, 8, 9 is (unsigned int)unscaled_y_bottom.
948 The row beneath 7, 8, 9 is unscaled_y_bottom.
950 The column left of 1, 4, 7 is unscaled_x. The column
951 between 1, 4, 7 and 2, 5, 8 is left_right_column. The
952 column between 2, 5, 8 and 3, 6, 9 is (unsigned
953 int)unscaled_x_right. The column right of 3, 6, 9 is
954 unscaled_x_right. */
955 const double inv_scalex = (double) 0x100 / scalex;
956 const double inv_scaley = (double) 0x100 / scaley;
957 for (y = 0; y < spu->scaled_height; ++y) {
958 const double unscaled_y = y * inv_scaley;
959 const double unscaled_y_bottom = unscaled_y + inv_scaley;
960 const unsigned int top_low_row = FFMIN(unscaled_y_bottom, unscaled_y + 1.0);
961 const double top = top_low_row - unscaled_y;
962 const unsigned int height = unscaled_y_bottom > top_low_row
963 ? (unsigned int) unscaled_y_bottom - top_low_row
964 : 0;
965 const double bottom = unscaled_y_bottom > top_low_row
966 ? unscaled_y_bottom - floor(unscaled_y_bottom)
967 : 0.0;
968 for (x = 0; x < spu->scaled_width; ++x) {
969 const double unscaled_x = x * inv_scalex;
970 const double unscaled_x_right = unscaled_x + inv_scalex;
971 const unsigned int left_right_column = FFMIN(unscaled_x_right, unscaled_x + 1.0);
972 const double left = left_right_column - unscaled_x;
973 const unsigned int width = unscaled_x_right > left_right_column
974 ? (unsigned int) unscaled_x_right - left_right_column
975 : 0;
976 const double right = unscaled_x_right > left_right_column
977 ? unscaled_x_right - floor(unscaled_x_right)
978 : 0.0;
979 double color = 0.0;
980 double alpha = 0.0;
981 double tmp;
982 unsigned int base;
983 /* Now use these informations to compute a good alpha,
984 and lightness. The sum is on each of the 9
985 region's surface and alpha and lightness.
987 transformed alpha = sum(surface * alpha) / sum(surface)
988 transformed color = sum(surface * alpha * color) / sum(surface * alpha)
990 /* 1: top left part */
991 base = spu->stride * (unsigned int) unscaled_y;
992 tmp = left * top * canon_alpha(spu->aimage[base + (unsigned int) unscaled_x]);
993 alpha += tmp;
994 color += tmp * spu->image[base + (unsigned int) unscaled_x];
995 /* 2: top center part */
996 if (width > 0) {
997 unsigned int walkx;
998 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
999 base = spu->stride * (unsigned int) unscaled_y + walkx;
1000 tmp = /* 1.0 * */ top * canon_alpha(spu->aimage[base]);
1001 alpha += tmp;
1002 color += tmp * spu->image[base];
1005 /* 3: top right part */
1006 if (right > 0.0) {
1007 base = spu->stride * (unsigned int) unscaled_y + (unsigned int) unscaled_x_right;
1008 tmp = right * top * canon_alpha(spu->aimage[base]);
1009 alpha += tmp;
1010 color += tmp * spu->image[base];
1012 /* 4: center left part */
1013 if (height > 0) {
1014 unsigned int walky;
1015 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1016 base = spu->stride * walky + (unsigned int) unscaled_x;
1017 tmp = left /* * 1.0 */ * canon_alpha(spu->aimage[base]);
1018 alpha += tmp;
1019 color += tmp * spu->image[base];
1022 /* 5: center part */
1023 if (width > 0 && height > 0) {
1024 unsigned int walky;
1025 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1026 unsigned int walkx;
1027 base = spu->stride * walky;
1028 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
1029 tmp = /* 1.0 * 1.0 * */ canon_alpha(spu->aimage[base + walkx]);
1030 alpha += tmp;
1031 color += tmp * spu->image[base + walkx];
1035 /* 6: center right part */
1036 if (right > 0.0 && height > 0) {
1037 unsigned int walky;
1038 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1039 base = spu->stride * walky + (unsigned int) unscaled_x_right;
1040 tmp = right /* * 1.0 */ * canon_alpha(spu->aimage[base]);
1041 alpha += tmp;
1042 color += tmp * spu->image[base];
1045 /* 7: bottom left part */
1046 if (bottom > 0.0) {
1047 base = spu->stride * (unsigned int) unscaled_y_bottom + (unsigned int) unscaled_x;
1048 tmp = left * bottom * canon_alpha(spu->aimage[base]);
1049 alpha += tmp;
1050 color += tmp * spu->image[base];
1052 /* 8: bottom center part */
1053 if (width > 0 && bottom > 0.0) {
1054 unsigned int walkx;
1055 base = spu->stride * (unsigned int) unscaled_y_bottom;
1056 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
1057 tmp = /* 1.0 * */ bottom * canon_alpha(spu->aimage[base + walkx]);
1058 alpha += tmp;
1059 color += tmp * spu->image[base + walkx];
1062 /* 9: bottom right part */
1063 if (right > 0.0 && bottom > 0.0) {
1064 base = spu->stride * (unsigned int) unscaled_y_bottom + (unsigned int) unscaled_x_right;
1065 tmp = right * bottom * canon_alpha(spu->aimage[base]);
1066 alpha += tmp;
1067 color += tmp * spu->image[base];
1069 /* Finally mix these transparency and brightness information suitably */
1070 base = spu->scaled_stride * y + x;
1071 spu->scaled_image[base] = alpha > 0 ? color / alpha : 0;
1072 spu->scaled_aimage[base] = alpha * scalex * scaley / 0x10000;
1073 if (spu->scaled_aimage[base]) {
1074 spu->scaled_aimage[base] = 256 - spu->scaled_aimage[base];
1075 if (spu->scaled_aimage[base] + spu->scaled_image[base] > 255)
1076 spu->scaled_image[base] = 256 - spu->scaled_aimage[base];
1082 nothing_to_do:
1083 /* Kludge: draw_alpha needs width multiple of 8. */
1084 if (spu->scaled_width < spu->scaled_stride)
1085 for (y = 0; y < spu->scaled_height; ++y) {
1086 memset(spu->scaled_aimage + y * spu->scaled_stride + spu->scaled_width, 0,
1087 spu->scaled_stride - spu->scaled_width);
1089 spu->scaled_frame_width = dxs;
1090 spu->scaled_frame_height = dys;
1093 if (spu->scaled_image){
1094 switch (spu_alignment) {
1095 case 0:
1096 spu->scaled_start_row = dys*sub_pos/100;
1097 if (spu->scaled_start_row + spu->scaled_height > dys)
1098 spu->scaled_start_row = dys - spu->scaled_height;
1099 break;
1100 case 1:
1101 spu->scaled_start_row = dys*sub_pos/100 - spu->scaled_height/2;
1102 if (sub_pos >= 50 && spu->scaled_start_row + spu->scaled_height > dys)
1103 spu->scaled_start_row = dys - spu->scaled_height;
1104 break;
1105 case 2:
1106 spu->scaled_start_row = dys*sub_pos/100 - spu->scaled_height;
1107 break;
1109 draw_alpha(spu->scaled_start_col, spu->scaled_start_row, spu->scaled_width, spu->scaled_height,
1110 spu->scaled_image, spu->scaled_aimage, spu->scaled_stride);
1111 spu->spu_changed = 0;
1115 else
1117 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPU not displayed: start_pts=%d end_pts=%d now_pts=%d\n",
1118 spu->start_pts, spu->end_pts, spu->now_pts);
1122 void spudec_update_palette(void * this, unsigned int *palette)
1124 spudec_handle_t *spu = (spudec_handle_t *) this;
1125 if (spu && palette) {
1126 memcpy(spu->global_palette, palette, sizeof(spu->global_palette));
1127 if(spu->hw_spu)
1128 spu->hw_spu->control(VOCTRL_SET_SPU_PALETTE,spu->global_palette);
1132 void spudec_set_font_factor(void * this, double factor)
1134 spudec_handle_t *spu = (spudec_handle_t *) this;
1135 spu->font_start_level = (int)(0xF0-(0xE0*factor));
1138 static void spudec_parse_extradata(spudec_handle_t *this,
1139 uint8_t *extradata, int extradata_len)
1141 uint8_t *buffer, *ptr;
1142 unsigned int *pal = this->global_palette, *cuspal = this->cuspal;
1143 unsigned int tridx;
1144 int i;
1146 if (extradata_len == 16*4) {
1147 for (i=0; i<16; i++)
1148 pal[i] = AV_RB32(extradata + i*4);
1149 this->auto_palette = 0;
1150 return;
1153 if (!(ptr = buffer = malloc(extradata_len+1)))
1154 return;
1155 memcpy(buffer, extradata, extradata_len);
1156 buffer[extradata_len] = 0;
1158 do {
1159 if (*ptr == '#')
1160 continue;
1161 if (!strncmp(ptr, "size: ", 6))
1162 sscanf(ptr + 6, "%dx%d", &this->orig_frame_width, &this->orig_frame_height);
1163 if (!strncmp(ptr, "palette: ", 9) &&
1164 sscanf(ptr + 9, "%x, %x, %x, %x, %x, %x, %x, %x, "
1165 "%x, %x, %x, %x, %x, %x, %x, %x",
1166 &pal[ 0], &pal[ 1], &pal[ 2], &pal[ 3],
1167 &pal[ 4], &pal[ 5], &pal[ 6], &pal[ 7],
1168 &pal[ 8], &pal[ 9], &pal[10], &pal[11],
1169 &pal[12], &pal[13], &pal[14], &pal[15]) == 16) {
1170 for (i=0; i<16; i++)
1171 pal[i] = vobsub_palette_to_yuv(pal[i]);
1172 this->auto_palette = 0;
1174 if (!strncasecmp(ptr, "forced subs: on", 15))
1175 this->forced_subs_only = 1;
1176 if (!strncmp(ptr, "custom colors: ON, tridx: ", 26) &&
1177 sscanf(ptr + 26, "%x, colors: %x, %x, %x, %x",
1178 &tridx, cuspal+0, cuspal+1, cuspal+2, cuspal+3) == 5) {
1179 for (i=0; i<4; i++) {
1180 cuspal[i] = vobsub_rgb_to_yuv(cuspal[i]);
1181 if (tridx & (1 << (12-4*i)))
1182 cuspal[i] |= 1 << 31;
1184 this->custom = 1;
1186 } while ((ptr=strchr(ptr,'\n')) && *++ptr);
1188 free(buffer);
1191 void *spudec_new_scaled(unsigned int *palette, unsigned int frame_width, unsigned int frame_height, uint8_t *extradata, int extradata_len)
1193 spudec_handle_t *this = calloc(1, sizeof(spudec_handle_t));
1194 if (this){
1195 this->orig_frame_height = frame_height;
1196 // set up palette:
1197 if (palette)
1198 memcpy(this->global_palette, palette, sizeof(this->global_palette));
1199 else
1200 this->auto_palette = 1;
1201 if (extradata)
1202 spudec_parse_extradata(this, extradata, extradata_len);
1203 /* XXX Although the video frame is some size, the SPU frame is
1204 always maximum size i.e. 720 wide and 576 or 480 high */
1205 this->orig_frame_width = 720;
1206 if (this->orig_frame_height == 480 || this->orig_frame_height == 240)
1207 this->orig_frame_height = 480;
1208 else
1209 this->orig_frame_height = 576;
1211 else
1212 mp_msg(MSGT_SPUDEC,MSGL_FATAL, "FATAL: spudec_init: calloc");
1213 return this;
1216 void *spudec_new(unsigned int *palette)
1218 return spudec_new_scaled(palette, 0, 0, NULL, 0);
1221 void spudec_free(void *this)
1223 spudec_handle_t *spu = (spudec_handle_t*)this;
1224 if (spu) {
1225 while (spu->queue_head)
1226 spudec_free_packet(spudec_dequeue_packet(spu));
1227 if (spu->packet)
1228 free(spu->packet);
1229 if (spu->scaled_image)
1230 free(spu->scaled_image);
1231 if (spu->image)
1232 free(spu->image);
1233 free(spu);
1237 void spudec_set_hw_spu(void *this, const vo_functions_t *hw_spu)
1239 spudec_handle_t *spu = (spudec_handle_t*)this;
1240 if (!spu)
1241 return;
1242 spu->hw_spu = hw_spu;
1243 hw_spu->control(VOCTRL_SET_SPU_PALETTE,spu->global_palette);