spudec: Add warning about bad values in bounding box handling
[mplayer/glamo.git] / spudec.c
blobaf1e9a37d6ffffff2197832bc2dd907fa7819325
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 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);
228 static int spudec_alloc_image(spudec_handle_t *this, int stride, int height)
230 if (this->width > stride) // just a safeguard
231 this->width = stride;
232 this->stride = stride;
233 this->height = height;
234 if (this->image_size < this->stride * this->height) {
235 if (this->image != NULL) {
236 free(this->image);
237 this->image_size = 0;
239 this->image = malloc(2 * this->stride * this->height);
240 if (this->image) {
241 this->image_size = this->stride * this->height;
242 this->aimage = this->image + this->image_size;
245 return this->image != NULL;
248 static void spudec_process_data(spudec_handle_t *this, packet_t *packet)
250 unsigned int cmap[4], alpha[4];
251 unsigned int i, x, y;
253 this->scaled_frame_width = 0;
254 this->scaled_frame_height = 0;
255 this->start_col = packet->start_col;
256 this->end_col = packet->end_col;
257 this->start_row = packet->start_row;
258 this->end_row = packet->end_row;
259 this->height = packet->height;
260 this->width = packet->width;
261 this->stride = packet->stride;
262 for (i = 0; i < 4; ++i) {
263 alpha[i] = mkalpha(packet->alpha[i]);
264 if (this->custom && (this->cuspal[i] >> 31) != 0)
265 alpha[i] = 0;
266 if (alpha[i] == 0)
267 cmap[i] = 0;
268 else if (this->custom){
269 cmap[i] = ((this->cuspal[i] >> 16) & 0xff);
270 if (cmap[i] + alpha[i] > 255)
271 cmap[i] = 256 - alpha[i];
273 else {
274 cmap[i] = ((this->global_palette[packet->palette[i]] >> 16) & 0xff);
275 if (cmap[i] + alpha[i] > 255)
276 cmap[i] = 256 - alpha[i];
280 if (!spudec_alloc_image(this, this->stride, this->height))
281 return;
283 /* Kludge: draw_alpha needs width multiple of 8. */
284 if (this->width < this->stride)
285 for (y = 0; y < this->height; ++y) {
286 memset(this->aimage + y * this->stride + this->width, 0, this->stride - this->width);
287 /* FIXME: Why is this one needed? */
288 memset(this->image + y * this->stride + this->width, 0, this->stride - this->width);
291 i = packet->current_nibble[1];
292 x = 0;
293 y = 0;
294 while (packet->current_nibble[0] < i
295 && packet->current_nibble[1] / 2 < packet->control_start
296 && y < this->height) {
297 unsigned int len, color;
298 unsigned int rle = 0;
299 rle = get_nibble(packet);
300 if (rle < 0x04) {
301 rle = (rle << 4) | get_nibble(packet);
302 if (rle < 0x10) {
303 rle = (rle << 4) | get_nibble(packet);
304 if (rle < 0x040) {
305 rle = (rle << 4) | get_nibble(packet);
306 if (rle < 0x0004)
307 rle |= ((this->width - x) << 2);
311 color = 3 - (rle & 0x3);
312 len = rle >> 2;
313 if (len > this->width - x || len == 0)
314 len = this->width - x;
315 /* FIXME have to use palette and alpha map*/
316 memset(this->image + y * this->stride + x, cmap[color], len);
317 memset(this->aimage + y * this->stride + x, alpha[color], len);
318 x += len;
319 if (x >= this->width) {
320 next_line(packet);
321 x = 0;
322 ++y;
325 spudec_cut_image(this);
330 This function tries to create a usable palette.
331 It determines how many non-transparent colors are used, and assigns different
332 gray scale values to each color.
333 I tested it with four streams and even got something readable. Half of the
334 times I got black characters with white around and half the reverse.
336 static void compute_palette(spudec_handle_t *this, packet_t *packet)
338 int used[16],i,cused,start,step,color;
340 memset(used, 0, sizeof(used));
341 for (i=0; i<4; i++)
342 if (packet->alpha[i]) /* !Transparent? */
343 used[packet->palette[i]] = 1;
344 for (cused=0, i=0; i<16; i++)
345 if (used[i]) cused++;
346 if (!cused) return;
347 if (cused == 1) {
348 start = 0x80;
349 step = 0;
350 } else {
351 start = this->font_start_level;
352 step = (0xF0-this->font_start_level)/(cused-1);
354 memset(used, 0, sizeof(used));
355 for (i=0; i<4; i++) {
356 color = packet->palette[i];
357 if (packet->alpha[i] && !used[color]) { /* not assigned? */
358 used[color] = 1;
359 this->global_palette[color] = start<<16;
360 start += step;
365 static void spudec_process_control(spudec_handle_t *this, int pts100)
367 int a,b,c,d; /* Temporary vars */
368 unsigned int date, type;
369 unsigned int off;
370 unsigned int start_off = 0;
371 unsigned int next_off;
372 unsigned int start_pts = 0;
373 unsigned int end_pts = 0;
374 unsigned int current_nibble[2] = {0, 0};
375 unsigned int control_start;
376 unsigned int display = 0;
377 unsigned int start_col = 0;
378 unsigned int end_col = 0;
379 unsigned int start_row = 0;
380 unsigned int end_row = 0;
381 unsigned int width = 0;
382 unsigned int height = 0;
383 unsigned int stride = 0;
385 control_start = get_be16(this->packet + 2);
386 next_off = control_start;
387 while (start_off != next_off) {
388 start_off = next_off;
389 date = get_be16(this->packet + start_off) * 1024;
390 next_off = get_be16(this->packet + start_off + 2);
391 mp_msg(MSGT_SPUDEC,MSGL_DBG2, "date=%d\n", date);
392 off = start_off + 4;
393 for (type = this->packet[off++]; type != 0xff; type = this->packet[off++]) {
394 mp_msg(MSGT_SPUDEC,MSGL_DBG2, "cmd=%d ",type);
395 switch(type) {
396 case 0x00:
397 /* Menu ID, 1 byte */
398 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Menu ID\n");
399 /* shouldn't a Menu ID type force display start? */
400 start_pts = pts100 < 0 && -pts100 >= date ? 0 : pts100 + date;
401 end_pts = UINT_MAX;
402 display = 1;
403 this->is_forced_sub=~0; // current subtitle is forced
404 break;
405 case 0x01:
406 /* Start display */
407 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Start display!\n");
408 start_pts = pts100 < 0 && -pts100 >= date ? 0 : pts100 + date;
409 end_pts = UINT_MAX;
410 display = 1;
411 this->is_forced_sub=0;
412 break;
413 case 0x02:
414 /* Stop display */
415 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Stop display!\n");
416 end_pts = pts100 < 0 && -pts100 >= date ? 0 : pts100 + date;
417 break;
418 case 0x03:
419 /* Palette */
420 this->palette[0] = this->packet[off] >> 4;
421 this->palette[1] = this->packet[off] & 0xf;
422 this->palette[2] = this->packet[off + 1] >> 4;
423 this->palette[3] = this->packet[off + 1] & 0xf;
424 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Palette %d, %d, %d, %d\n",
425 this->palette[0], this->palette[1], this->palette[2], this->palette[3]);
426 off+=2;
427 break;
428 case 0x04:
429 /* Alpha */
430 a = this->packet[off] >> 4;
431 b = this->packet[off] & 0xf;
432 c = this->packet[off + 1] >> 4;
433 d = this->packet[off + 1] & 0xf;
434 // Note: some DVDs change these values to create a fade-in/fade-out effect
435 // We can not handle this, so just keep the highest value during the display time.
436 if (display) {
437 a = FFMAX(a, this->alpha[0]);
438 b = FFMAX(b, this->alpha[1]);
439 c = FFMAX(c, this->alpha[2]);
440 d = FFMAX(d, this->alpha[3]);
442 this->alpha[0] = a;
443 this->alpha[1] = b;
444 this->alpha[2] = c;
445 this->alpha[3] = d;
446 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Alpha %d, %d, %d, %d\n",
447 this->alpha[0], this->alpha[1], this->alpha[2], this->alpha[3]);
448 off+=2;
449 break;
450 case 0x05:
451 /* Co-ords */
452 a = get_be24(this->packet + off);
453 b = get_be24(this->packet + off + 3);
454 start_col = a >> 12;
455 end_col = a & 0xfff;
456 width = (end_col < start_col) ? 0 : end_col - start_col + 1;
457 stride = (width + 7) & ~7; /* Kludge: draw_alpha needs width multiple of 8 */
458 start_row = b >> 12;
459 end_row = b & 0xfff;
460 height = (end_row < start_row) ? 0 : end_row - start_row /* + 1 */;
461 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Coords col: %d - %d row: %d - %d (%dx%d)\n",
462 start_col, end_col, start_row, end_row,
463 width, height);
464 off+=6;
465 break;
466 case 0x06:
467 /* Graphic lines */
468 current_nibble[0] = 2 * get_be16(this->packet + off);
469 current_nibble[1] = 2 * get_be16(this->packet + off + 2);
470 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Graphic offset 1: %d offset 2: %d\n",
471 current_nibble[0] / 2, current_nibble[1] / 2);
472 off+=4;
473 break;
474 case 0xff:
475 /* All done, bye-bye */
476 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Done!\n");
477 return;
478 // break;
479 default:
480 mp_msg(MSGT_SPUDEC,MSGL_WARN,"spudec: Error determining control type 0x%02x. Skipping %d bytes.\n",
481 type, next_off - off);
482 goto next_control;
485 next_control:
486 if (!display)
487 continue;
488 if (end_pts == UINT_MAX && start_off != next_off) {
489 end_pts = get_be16(this->packet + next_off) * 1024;
490 end_pts = 1 - pts100 >= end_pts ? 0 : pts100 + end_pts - 1;
492 if (end_pts > 0) {
493 packet_t *packet = calloc(1, sizeof(packet_t));
494 int i;
495 packet->start_pts = start_pts;
496 packet->end_pts = end_pts;
497 packet->current_nibble[0] = current_nibble[0];
498 packet->current_nibble[1] = current_nibble[1];
499 packet->start_row = start_row;
500 packet->end_row = end_row;
501 packet->start_col = start_col;
502 packet->end_col = end_col;
503 packet->width = width;
504 packet->height = height;
505 packet->stride = stride;
506 packet->control_start = control_start;
507 for (i=0; i<4; i++) {
508 packet->alpha[i] = this->alpha[i];
509 packet->palette[i] = this->palette[i];
511 packet->packet = malloc(this->packet_size);
512 memcpy(packet->packet, this->packet, this->packet_size);
513 spudec_queue_packet(this, packet);
518 static void spudec_decode(spudec_handle_t *this, int pts100)
520 if (!this->hw_spu)
521 spudec_process_control(this, pts100);
522 else if (pts100 >= 0) {
523 static vo_mpegpes_t packet = { NULL, 0, 0x20, 0 };
524 static vo_mpegpes_t *pkg=&packet;
525 packet.data = this->packet;
526 packet.size = this->packet_size;
527 packet.timestamp = pts100;
528 vo_draw_frame(this->hw_spu, (uint8_t**)&pkg);
532 int spudec_changed(void * this)
534 spudec_handle_t * spu = (spudec_handle_t*)this;
535 return spu->spu_changed || spu->now_pts > spu->end_pts;
538 void spudec_assemble(void *this, unsigned char *packet, unsigned int len, int pts100)
540 spudec_handle_t *spu = (spudec_handle_t*)this;
541 // spudec_heartbeat(this, pts100);
542 if (len < 2) {
543 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: packet too short\n");
544 return;
546 spu->packet_pts = pts100;
547 if (spu->packet_offset == 0) {
548 unsigned int len2 = get_be16(packet);
549 // Start new fragment
550 if (spu->packet_reserve < len2) {
551 if (spu->packet != NULL)
552 free(spu->packet);
553 spu->packet = malloc(len2);
554 spu->packet_reserve = spu->packet != NULL ? len2 : 0;
556 if (spu->packet != NULL) {
557 spu->packet_size = len2;
558 if (len > len2) {
559 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: invalid frag len / len2: %d / %d \n", len, len2);
560 return;
562 memcpy(spu->packet, packet, len);
563 spu->packet_offset = len;
564 spu->packet_pts = pts100;
566 } else {
567 // Continue current fragment
568 if (spu->packet_size < spu->packet_offset + len){
569 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: invalid fragment\n");
570 spu->packet_size = spu->packet_offset = 0;
571 return;
572 } else {
573 memcpy(spu->packet + spu->packet_offset, packet, len);
574 spu->packet_offset += len;
577 #if 1
578 // check if we have a complete packet (unfortunatelly packet_size is bad
579 // for some disks)
580 // [cb] packet_size is padded to be even -> may be one byte too long
581 if ((spu->packet_offset == spu->packet_size) ||
582 ((spu->packet_offset + 1) == spu->packet_size)){
583 unsigned int x=0,y;
584 while(x+4<=spu->packet_offset){
585 y=get_be16(spu->packet+x+2); // next control pointer
586 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPUtest: x=%d y=%d off=%d size=%d\n",x,y,spu->packet_offset,spu->packet_size);
587 if(x>=4 && x==y){ // if it points to self - we're done!
588 // we got it!
589 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPUgot: off=%d size=%d \n",spu->packet_offset,spu->packet_size);
590 spudec_decode(spu, pts100);
591 spu->packet_offset = 0;
592 break;
594 if(y<=x || y>=spu->packet_size){ // invalid?
595 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUtest: broken packet!!!!! y=%d < x=%d\n",y,x);
596 spu->packet_size = spu->packet_offset = 0;
597 break;
599 x=y;
601 // [cb] packet is done; start new packet
602 spu->packet_offset = 0;
604 #else
605 if (spu->packet_offset == spu->packet_size) {
606 spudec_decode(spu, pts100);
607 spu->packet_offset = 0;
609 #endif
612 void spudec_reset(void *this) // called after seek
614 spudec_handle_t *spu = (spudec_handle_t*)this;
615 while (spu->queue_head)
616 spudec_free_packet(spudec_dequeue_packet(spu));
617 spu->now_pts = 0;
618 spu->end_pts = 0;
619 spu->packet_size = spu->packet_offset = 0;
622 void spudec_heartbeat(void *this, unsigned int pts100)
624 spudec_handle_t *spu = (spudec_handle_t*) this;
625 spu->now_pts = pts100;
627 while (spu->queue_head != NULL && pts100 >= spu->queue_head->start_pts) {
628 packet_t *packet = spudec_dequeue_packet(spu);
629 spu->start_pts = packet->start_pts;
630 spu->end_pts = packet->end_pts;
631 if (spu->auto_palette)
632 compute_palette(spu, packet);
633 spudec_process_data(spu, packet);
634 spudec_free_packet(packet);
635 spu->spu_changed = 1;
639 int spudec_visible(void *this){
640 spudec_handle_t *spu = (spudec_handle_t *)this;
641 int ret=(spu->start_pts <= spu->now_pts &&
642 spu->now_pts < spu->end_pts &&
643 spu->height > 0);
644 // printf("spu visible: %d \n",ret);
645 return ret;
648 void spudec_set_forced_subs_only(void * const this, const unsigned int flag)
650 if(this){
651 ((spudec_handle_t *)this)->forced_subs_only=flag;
652 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPU: Display only forced subs now %s\n", flag ? "enabled": "disabled");
656 void spudec_draw(void *this, void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride))
658 spudec_handle_t *spu = (spudec_handle_t *)this;
659 if (spu->start_pts <= spu->now_pts && spu->now_pts < spu->end_pts && spu->image)
661 draw_alpha(spu->start_col, spu->start_row, spu->width, spu->height,
662 spu->image, spu->aimage, spu->stride);
663 spu->spu_changed = 0;
667 /* calc the bbox for spudec subs */
668 void spudec_calc_bbox(void *me, unsigned int dxs, unsigned int dys, unsigned int* bbox)
670 spudec_handle_t *spu;
671 spu = (spudec_handle_t *)me;
672 if (spu->orig_frame_width == 0 || spu->orig_frame_height == 0
673 || (spu->orig_frame_width == dxs && spu->orig_frame_height == dys)) {
674 bbox[0] = spu->start_col;
675 bbox[1] = spu->start_col + spu->width;
676 bbox[2] = spu->start_row;
677 bbox[3] = spu->start_row + spu->height;
679 else if (spu->scaled_frame_width != dxs || spu->scaled_frame_height != dys) {
680 unsigned int scalex = 0x100 * dxs / spu->orig_frame_width;
681 unsigned int scaley = 0x100 * dys / spu->orig_frame_height;
682 bbox[0] = spu->start_col * scalex / 0x100;
683 bbox[1] = spu->start_col * scalex / 0x100 + spu->width * scalex / 0x100;
684 switch (spu_alignment) {
685 case 0:
686 bbox[3] = dys*sub_pos/100 + spu->height * scaley / 0x100;
687 if (bbox[3] > dys) bbox[3] = dys;
688 bbox[2] = bbox[3] - spu->height * scaley / 0x100;
689 break;
690 case 1:
691 if (sub_pos < 50) {
692 bbox[2] = dys*sub_pos/100 - spu->height * scaley / 0x200;
693 bbox[3] = bbox[2] + spu->height;
694 } else {
695 bbox[3] = dys*sub_pos/100 + spu->height * scaley / 0x200;
696 if (bbox[3] > dys) bbox[3] = dys;
697 bbox[2] = bbox[3] - spu->height * scaley / 0x100;
699 break;
700 case 2:
701 bbox[2] = dys*sub_pos/100 - spu->height * scaley / 0x100;
702 bbox[3] = bbox[2] + spu->height;
703 break;
704 default: /* -1 */
705 bbox[2] = spu->start_row * scaley / 0x100;
706 bbox[3] = spu->start_row * scaley / 0x100 + spu->height * scaley / 0x100;
707 break;
709 } else {
710 mp_msg(MSGT_SPUDEC, MSGL_ERR, "Bad values in spudec_calc_bbox\n");
711 bbox[0] = bbox[1] = bbox[2] = bbox[3] = 0;
714 /* transform mplayer's alpha value into an opacity value that is linear */
715 static inline int canon_alpha(int alpha)
717 return alpha ? 256 - alpha : 0;
720 typedef struct {
721 unsigned position;
722 unsigned left_up;
723 unsigned right_down;
724 }scale_pixel;
727 static void scale_table(unsigned int start_src, unsigned int start_tar, unsigned int end_src, unsigned int end_tar, scale_pixel * table)
729 unsigned int t;
730 unsigned int delta_src = end_src - start_src;
731 unsigned int delta_tar = end_tar - start_tar;
732 int src = 0;
733 int src_step;
734 if (delta_src == 0 || delta_tar == 0) {
735 return;
737 src_step = (delta_src << 16) / delta_tar >>1;
738 for (t = 0; t<=delta_tar; src += (src_step << 1), t++){
739 table[t].position= FFMIN(src >> 16, end_src - 1);
740 table[t].right_down = src & 0xffff;
741 table[t].left_up = 0x10000 - table[t].right_down;
745 /* bilinear scale, similar to vobsub's code */
746 static void scale_image(int x, int y, scale_pixel* table_x, scale_pixel* table_y, spudec_handle_t * spu)
748 int alpha[4];
749 int color[4];
750 unsigned int scale[4];
751 int base = table_y[y].position * spu->stride + table_x[x].position;
752 int scaled = y * spu->scaled_stride + x;
753 alpha[0] = canon_alpha(spu->aimage[base]);
754 alpha[1] = canon_alpha(spu->aimage[base + 1]);
755 alpha[2] = canon_alpha(spu->aimage[base + spu->stride]);
756 alpha[3] = canon_alpha(spu->aimage[base + spu->stride + 1]);
757 color[0] = spu->image[base];
758 color[1] = spu->image[base + 1];
759 color[2] = spu->image[base + spu->stride];
760 color[3] = spu->image[base + spu->stride + 1];
761 scale[0] = (table_x[x].left_up * table_y[y].left_up >> 16) * alpha[0];
762 if (table_y[y].left_up == 0x10000) // necessary to avoid overflow-case
763 scale[0] = table_x[x].left_up * alpha[0];
764 scale[1] = (table_x[x].right_down * table_y[y].left_up >>16) * alpha[1];
765 scale[2] = (table_x[x].left_up * table_y[y].right_down >> 16) * alpha[2];
766 scale[3] = (table_x[x].right_down * table_y[y].right_down >> 16) * alpha[3];
767 spu->scaled_image[scaled] = (color[0] * scale[0] + color[1] * scale[1] + color[2] * scale[2] + color[3] * scale[3])>>24;
768 spu->scaled_aimage[scaled] = (scale[0] + scale[1] + scale[2] + scale[3]) >> 16;
769 if (spu->scaled_aimage[scaled]){
770 // ensure that MPlayer's simplified alpha-blending can not overflow
771 spu->scaled_image[scaled] = FFMIN(spu->scaled_image[scaled], spu->scaled_aimage[scaled]);
772 // convert to MPlayer-style alpha
773 spu->scaled_aimage[scaled] = -spu->scaled_aimage[scaled];
777 static void sws_spu_image(unsigned char *d1, unsigned char *d2, int dw, int dh,
778 int ds, unsigned char *s1, unsigned char *s2, int sw,
779 int sh, int ss)
781 struct SwsContext *ctx;
782 static SwsFilter filter;
783 static int firsttime = 1;
784 static float oldvar;
785 int i;
787 if (!firsttime && oldvar != spu_gaussvar) sws_freeVec(filter.lumH);
788 if (firsttime) {
789 filter.lumH = filter.lumV =
790 filter.chrH = filter.chrV = sws_getGaussianVec(spu_gaussvar, 3.0);
791 sws_normalizeVec(filter.lumH, 1.0);
792 firsttime = 0;
793 oldvar = spu_gaussvar;
796 ctx=sws_getContext(sw, sh, PIX_FMT_GRAY8, dw, dh, PIX_FMT_GRAY8, SWS_GAUSS, &filter, NULL, NULL);
797 sws_scale(ctx,&s1,&ss,0,sh,&d1,&ds);
798 for (i=ss*sh-1; i>=0; i--) if (!s2[i]) s2[i] = 255; //else s2[i] = 1;
799 sws_scale(ctx,&s2,&ss,0,sh,&d2,&ds);
800 for (i=ds*dh-1; i>=0; i--) if (d2[i]==0) d2[i] = 1; else if (d2[i]==255) d2[i] = 0;
801 sws_freeContext(ctx);
804 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)
806 spudec_handle_t *spu = (spudec_handle_t *)me;
807 scale_pixel *table_x;
808 scale_pixel *table_y;
810 if (spu->start_pts <= spu->now_pts && spu->now_pts < spu->end_pts) {
812 // check if only forced subtitles are requested
813 if( (spu->forced_subs_only) && !(spu->is_forced_sub) ){
814 return;
817 if (!(spu_aamode&16) && (spu->orig_frame_width == 0 || spu->orig_frame_height == 0
818 || (spu->orig_frame_width == dxs && spu->orig_frame_height == dys))) {
819 if (spu->image)
821 draw_alpha(ctx, spu->start_col, spu->start_row, spu->width, spu->height,
822 spu->image, spu->aimage, spu->stride);
823 spu->spu_changed = 0;
826 else {
827 if (spu->scaled_frame_width != dxs || spu->scaled_frame_height != dys) { /* Resizing is needed */
828 /* scaled_x = scalex * x / 0x100
829 scaled_y = scaley * y / 0x100
830 order of operations is important because of rounding. */
831 unsigned int scalex = 0x100 * dxs / spu->orig_frame_width;
832 unsigned int scaley = 0x100 * dys / spu->orig_frame_height;
833 spu->scaled_start_col = spu->start_col * scalex / 0x100;
834 spu->scaled_start_row = spu->start_row * scaley / 0x100;
835 spu->scaled_width = spu->width * scalex / 0x100;
836 spu->scaled_height = spu->height * scaley / 0x100;
837 /* Kludge: draw_alpha needs width multiple of 8 */
838 spu->scaled_stride = (spu->scaled_width + 7) & ~7;
839 if (spu->scaled_image_size < spu->scaled_stride * spu->scaled_height) {
840 if (spu->scaled_image) {
841 free(spu->scaled_image);
842 spu->scaled_image_size = 0;
844 spu->scaled_image = malloc(2 * spu->scaled_stride * spu->scaled_height);
845 if (spu->scaled_image) {
846 spu->scaled_image_size = spu->scaled_stride * spu->scaled_height;
847 spu->scaled_aimage = spu->scaled_image + spu->scaled_image_size;
850 if (spu->scaled_image) {
851 unsigned int x, y;
852 if (spu->scaled_width <= 1 || spu->scaled_height <= 1) {
853 goto nothing_to_do;
855 switch(spu_aamode&15) {
856 case 4:
857 sws_spu_image(spu->scaled_image, spu->scaled_aimage,
858 spu->scaled_width, spu->scaled_height, spu->scaled_stride,
859 spu->image, spu->aimage, spu->width, spu->height, spu->stride);
860 break;
861 case 3:
862 table_x = calloc(spu->scaled_width, sizeof(scale_pixel));
863 table_y = calloc(spu->scaled_height, sizeof(scale_pixel));
864 if (!table_x || !table_y) {
865 mp_msg(MSGT_SPUDEC, MSGL_FATAL, "Fatal: spudec_draw_scaled: calloc failed\n");
867 scale_table(0, 0, spu->width - 1, spu->scaled_width - 1, table_x);
868 scale_table(0, 0, spu->height - 1, spu->scaled_height - 1, table_y);
869 for (y = 0; y < spu->scaled_height; y++)
870 for (x = 0; x < spu->scaled_width; x++)
871 scale_image(x, y, table_x, table_y, spu);
872 free(table_x);
873 free(table_y);
874 break;
875 case 0:
876 /* no antialiasing */
877 for (y = 0; y < spu->scaled_height; ++y) {
878 int unscaled_y = y * 0x100 / scaley;
879 int strides = spu->stride * unscaled_y;
880 int scaled_strides = spu->scaled_stride * y;
881 for (x = 0; x < spu->scaled_width; ++x) {
882 int unscaled_x = x * 0x100 / scalex;
883 spu->scaled_image[scaled_strides + x] = spu->image[strides + unscaled_x];
884 spu->scaled_aimage[scaled_strides + x] = spu->aimage[strides + unscaled_x];
887 break;
888 case 1:
890 /* Intermediate antialiasing. */
891 for (y = 0; y < spu->scaled_height; ++y) {
892 const unsigned int unscaled_top = y * spu->orig_frame_height / dys;
893 unsigned int unscaled_bottom = (y + 1) * spu->orig_frame_height / dys;
894 if (unscaled_bottom >= spu->height)
895 unscaled_bottom = spu->height - 1;
896 for (x = 0; x < spu->scaled_width; ++x) {
897 const unsigned int unscaled_left = x * spu->orig_frame_width / dxs;
898 unsigned int unscaled_right = (x + 1) * spu->orig_frame_width / dxs;
899 unsigned int color = 0;
900 unsigned int alpha = 0;
901 unsigned int walkx, walky;
902 unsigned int base, tmp;
903 if (unscaled_right >= spu->width)
904 unscaled_right = spu->width - 1;
905 for (walky = unscaled_top; walky <= unscaled_bottom; ++walky)
906 for (walkx = unscaled_left; walkx <= unscaled_right; ++walkx) {
907 base = walky * spu->stride + walkx;
908 tmp = canon_alpha(spu->aimage[base]);
909 alpha += tmp;
910 color += tmp * spu->image[base];
912 base = y * spu->scaled_stride + x;
913 spu->scaled_image[base] = alpha ? color / alpha : 0;
914 spu->scaled_aimage[base] =
915 alpha * (1 + unscaled_bottom - unscaled_top) * (1 + unscaled_right - unscaled_left);
916 /* spu->scaled_aimage[base] =
917 alpha * dxs * dys / spu->orig_frame_width / spu->orig_frame_height; */
918 if (spu->scaled_aimage[base]) {
919 spu->scaled_aimage[base] = 256 - spu->scaled_aimage[base];
920 if (spu->scaled_aimage[base] + spu->scaled_image[base] > 255)
921 spu->scaled_image[base] = 256 - spu->scaled_aimage[base];
926 break;
927 case 2:
929 /* Best antialiasing. Very slow. */
930 /* Any pixel (x, y) represents pixels from the original
931 rectangular region comprised between the columns
932 unscaled_y and unscaled_y + 0x100 / scaley and the rows
933 unscaled_x and unscaled_x + 0x100 / scalex
935 The original rectangular region that the scaled pixel
936 represents is cut in 9 rectangular areas like this:
938 +---+-----------------+---+
939 | 1 | 2 | 3 |
940 +---+-----------------+---+
941 | | | |
942 | 4 | 5 | 6 |
943 | | | |
944 +---+-----------------+---+
945 | 7 | 8 | 9 |
946 +---+-----------------+---+
948 The width of the left column is at most one pixel and
949 it is never null and its right column is at a pixel
950 boundary. The height of the top row is at most one
951 pixel it is never null and its bottom row is at a
952 pixel boundary. The width and height of region 5 are
953 integral values. The width of the right column is
954 what remains and is less than one pixel. The height
955 of the bottom row is what remains and is less than
956 one pixel.
958 The row above 1, 2, 3 is unscaled_y. The row between
959 1, 2, 3 and 4, 5, 6 is top_low_row. The row between 4,
960 5, 6 and 7, 8, 9 is (unsigned int)unscaled_y_bottom.
961 The row beneath 7, 8, 9 is unscaled_y_bottom.
963 The column left of 1, 4, 7 is unscaled_x. The column
964 between 1, 4, 7 and 2, 5, 8 is left_right_column. The
965 column between 2, 5, 8 and 3, 6, 9 is (unsigned
966 int)unscaled_x_right. The column right of 3, 6, 9 is
967 unscaled_x_right. */
968 const double inv_scalex = (double) 0x100 / scalex;
969 const double inv_scaley = (double) 0x100 / scaley;
970 for (y = 0; y < spu->scaled_height; ++y) {
971 const double unscaled_y = y * inv_scaley;
972 const double unscaled_y_bottom = unscaled_y + inv_scaley;
973 const unsigned int top_low_row = FFMIN(unscaled_y_bottom, unscaled_y + 1.0);
974 const double top = top_low_row - unscaled_y;
975 const unsigned int height = unscaled_y_bottom > top_low_row
976 ? (unsigned int) unscaled_y_bottom - top_low_row
977 : 0;
978 const double bottom = unscaled_y_bottom > top_low_row
979 ? unscaled_y_bottom - floor(unscaled_y_bottom)
980 : 0.0;
981 for (x = 0; x < spu->scaled_width; ++x) {
982 const double unscaled_x = x * inv_scalex;
983 const double unscaled_x_right = unscaled_x + inv_scalex;
984 const unsigned int left_right_column = FFMIN(unscaled_x_right, unscaled_x + 1.0);
985 const double left = left_right_column - unscaled_x;
986 const unsigned int width = unscaled_x_right > left_right_column
987 ? (unsigned int) unscaled_x_right - left_right_column
988 : 0;
989 const double right = unscaled_x_right > left_right_column
990 ? unscaled_x_right - floor(unscaled_x_right)
991 : 0.0;
992 double color = 0.0;
993 double alpha = 0.0;
994 double tmp;
995 unsigned int base;
996 /* Now use these informations to compute a good alpha,
997 and lightness. The sum is on each of the 9
998 region's surface and alpha and lightness.
1000 transformed alpha = sum(surface * alpha) / sum(surface)
1001 transformed color = sum(surface * alpha * color) / sum(surface * alpha)
1003 /* 1: top left part */
1004 base = spu->stride * (unsigned int) unscaled_y;
1005 tmp = left * top * canon_alpha(spu->aimage[base + (unsigned int) unscaled_x]);
1006 alpha += tmp;
1007 color += tmp * spu->image[base + (unsigned int) unscaled_x];
1008 /* 2: top center part */
1009 if (width > 0) {
1010 unsigned int walkx;
1011 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
1012 base = spu->stride * (unsigned int) unscaled_y + walkx;
1013 tmp = /* 1.0 * */ top * canon_alpha(spu->aimage[base]);
1014 alpha += tmp;
1015 color += tmp * spu->image[base];
1018 /* 3: top right part */
1019 if (right > 0.0) {
1020 base = spu->stride * (unsigned int) unscaled_y + (unsigned int) unscaled_x_right;
1021 tmp = right * top * canon_alpha(spu->aimage[base]);
1022 alpha += tmp;
1023 color += tmp * spu->image[base];
1025 /* 4: center left part */
1026 if (height > 0) {
1027 unsigned int walky;
1028 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1029 base = spu->stride * walky + (unsigned int) unscaled_x;
1030 tmp = left /* * 1.0 */ * canon_alpha(spu->aimage[base]);
1031 alpha += tmp;
1032 color += tmp * spu->image[base];
1035 /* 5: center part */
1036 if (width > 0 && height > 0) {
1037 unsigned int walky;
1038 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1039 unsigned int walkx;
1040 base = spu->stride * walky;
1041 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
1042 tmp = /* 1.0 * 1.0 * */ canon_alpha(spu->aimage[base + walkx]);
1043 alpha += tmp;
1044 color += tmp * spu->image[base + walkx];
1048 /* 6: center right part */
1049 if (right > 0.0 && height > 0) {
1050 unsigned int walky;
1051 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1052 base = spu->stride * walky + (unsigned int) unscaled_x_right;
1053 tmp = right /* * 1.0 */ * canon_alpha(spu->aimage[base]);
1054 alpha += tmp;
1055 color += tmp * spu->image[base];
1058 /* 7: bottom left part */
1059 if (bottom > 0.0) {
1060 base = spu->stride * (unsigned int) unscaled_y_bottom + (unsigned int) unscaled_x;
1061 tmp = left * bottom * canon_alpha(spu->aimage[base]);
1062 alpha += tmp;
1063 color += tmp * spu->image[base];
1065 /* 8: bottom center part */
1066 if (width > 0 && bottom > 0.0) {
1067 unsigned int walkx;
1068 base = spu->stride * (unsigned int) unscaled_y_bottom;
1069 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
1070 tmp = /* 1.0 * */ bottom * canon_alpha(spu->aimage[base + walkx]);
1071 alpha += tmp;
1072 color += tmp * spu->image[base + walkx];
1075 /* 9: bottom right part */
1076 if (right > 0.0 && bottom > 0.0) {
1077 base = spu->stride * (unsigned int) unscaled_y_bottom + (unsigned int) unscaled_x_right;
1078 tmp = right * bottom * canon_alpha(spu->aimage[base]);
1079 alpha += tmp;
1080 color += tmp * spu->image[base];
1082 /* Finally mix these transparency and brightness information suitably */
1083 base = spu->scaled_stride * y + x;
1084 spu->scaled_image[base] = alpha > 0 ? color / alpha : 0;
1085 spu->scaled_aimage[base] = alpha * scalex * scaley / 0x10000;
1086 if (spu->scaled_aimage[base]) {
1087 spu->scaled_aimage[base] = 256 - spu->scaled_aimage[base];
1088 if (spu->scaled_aimage[base] + spu->scaled_image[base] > 255)
1089 spu->scaled_image[base] = 256 - spu->scaled_aimage[base];
1095 nothing_to_do:
1096 /* Kludge: draw_alpha needs width multiple of 8. */
1097 if (spu->scaled_width < spu->scaled_stride)
1098 for (y = 0; y < spu->scaled_height; ++y) {
1099 memset(spu->scaled_aimage + y * spu->scaled_stride + spu->scaled_width, 0,
1100 spu->scaled_stride - spu->scaled_width);
1102 spu->scaled_frame_width = dxs;
1103 spu->scaled_frame_height = dys;
1106 if (spu->scaled_image){
1107 switch (spu_alignment) {
1108 case 0:
1109 spu->scaled_start_row = dys*sub_pos/100;
1110 if (spu->scaled_start_row + spu->scaled_height > dys)
1111 spu->scaled_start_row = dys - spu->scaled_height;
1112 break;
1113 case 1:
1114 spu->scaled_start_row = dys*sub_pos/100 - spu->scaled_height/2;
1115 if (sub_pos >= 50 && spu->scaled_start_row + spu->scaled_height > dys)
1116 spu->scaled_start_row = dys - spu->scaled_height;
1117 break;
1118 case 2:
1119 spu->scaled_start_row = dys*sub_pos/100 - spu->scaled_height;
1120 break;
1122 draw_alpha(ctx, spu->scaled_start_col, spu->scaled_start_row, spu->scaled_width, spu->scaled_height,
1123 spu->scaled_image, spu->scaled_aimage, spu->scaled_stride);
1124 spu->spu_changed = 0;
1128 else
1130 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPU not displayed: start_pts=%d end_pts=%d now_pts=%d\n",
1131 spu->start_pts, spu->end_pts, spu->now_pts);
1135 void spudec_update_palette(void * this, unsigned int *palette)
1137 spudec_handle_t *spu = (spudec_handle_t *) this;
1138 if (spu && palette) {
1139 memcpy(spu->global_palette, palette, sizeof(spu->global_palette));
1140 if(spu->hw_spu)
1141 vo_control(spu->hw_spu, VOCTRL_SET_SPU_PALETTE, spu->global_palette);
1145 void spudec_set_font_factor(void * this, double factor)
1147 spudec_handle_t *spu = (spudec_handle_t *) this;
1148 spu->font_start_level = (int)(0xF0-(0xE0*factor));
1151 static void spudec_parse_extradata(spudec_handle_t *this,
1152 uint8_t *extradata, int extradata_len)
1154 uint8_t *buffer, *ptr;
1155 unsigned int *pal = this->global_palette, *cuspal = this->cuspal;
1156 unsigned int tridx;
1157 int i;
1159 if (extradata_len == 16*4) {
1160 for (i=0; i<16; i++)
1161 pal[i] = AV_RB32(extradata + i*4);
1162 this->auto_palette = 0;
1163 return;
1166 if (!(ptr = buffer = malloc(extradata_len+1)))
1167 return;
1168 memcpy(buffer, extradata, extradata_len);
1169 buffer[extradata_len] = 0;
1171 do {
1172 if (*ptr == '#')
1173 continue;
1174 if (!strncmp(ptr, "size: ", 6))
1175 sscanf(ptr + 6, "%dx%d", &this->orig_frame_width, &this->orig_frame_height);
1176 if (!strncmp(ptr, "palette: ", 9) &&
1177 sscanf(ptr + 9, "%x, %x, %x, %x, %x, %x, %x, %x, "
1178 "%x, %x, %x, %x, %x, %x, %x, %x",
1179 &pal[ 0], &pal[ 1], &pal[ 2], &pal[ 3],
1180 &pal[ 4], &pal[ 5], &pal[ 6], &pal[ 7],
1181 &pal[ 8], &pal[ 9], &pal[10], &pal[11],
1182 &pal[12], &pal[13], &pal[14], &pal[15]) == 16) {
1183 for (i=0; i<16; i++)
1184 pal[i] = vobsub_palette_to_yuv(pal[i]);
1185 this->auto_palette = 0;
1187 if (!strncasecmp(ptr, "forced subs: on", 15))
1188 this->forced_subs_only = 1;
1189 if (!strncmp(ptr, "custom colors: ON, tridx: ", 26) &&
1190 sscanf(ptr + 26, "%x, colors: %x, %x, %x, %x",
1191 &tridx, cuspal+0, cuspal+1, cuspal+2, cuspal+3) == 5) {
1192 for (i=0; i<4; i++) {
1193 cuspal[i] = vobsub_rgb_to_yuv(cuspal[i]);
1194 if (tridx & (1 << (12-4*i)))
1195 cuspal[i] |= 1 << 31;
1197 this->custom = 1;
1199 } while ((ptr=strchr(ptr,'\n')) && *++ptr);
1201 free(buffer);
1204 void *spudec_new_scaled(unsigned int *palette, unsigned int frame_width, unsigned int frame_height, uint8_t *extradata, int extradata_len)
1206 spudec_handle_t *this = calloc(1, sizeof(spudec_handle_t));
1207 if (this){
1208 this->orig_frame_height = frame_height;
1209 // set up palette:
1210 if (palette)
1211 memcpy(this->global_palette, palette, sizeof(this->global_palette));
1212 else
1213 this->auto_palette = 1;
1214 if (extradata)
1215 spudec_parse_extradata(this, extradata, extradata_len);
1216 /* XXX Although the video frame is some size, the SPU frame is
1217 always maximum size i.e. 720 wide and 576 or 480 high */
1218 // For HD files in MKV the VobSub resolution can be higher though,
1219 // see largeres_vobsub.mkv
1220 if (this->orig_frame_width <= 720 && this->orig_frame_height <= 576) {
1221 this->orig_frame_width = 720;
1222 if (this->orig_frame_height == 480 || this->orig_frame_height == 240)
1223 this->orig_frame_height = 480;
1224 else
1225 this->orig_frame_height = 576;
1228 else
1229 mp_msg(MSGT_SPUDEC,MSGL_FATAL, "FATAL: spudec_init: calloc");
1230 return this;
1233 void *spudec_new(unsigned int *palette)
1235 return spudec_new_scaled(palette, 0, 0, NULL, 0);
1238 void spudec_free(void *this)
1240 spudec_handle_t *spu = (spudec_handle_t*)this;
1241 if (spu) {
1242 while (spu->queue_head)
1243 spudec_free_packet(spudec_dequeue_packet(spu));
1244 if (spu->packet)
1245 free(spu->packet);
1246 if (spu->scaled_image)
1247 free(spu->scaled_image);
1248 if (spu->image)
1249 free(spu->image);
1250 free(spu);
1254 void spudec_set_hw_spu(void *this, struct vo *hw_spu)
1256 spudec_handle_t *spu = (spudec_handle_t*)this;
1257 if (!spu)
1258 return;
1259 spu->hw_spu = hw_spu;
1260 vo_control(hw_spu, VOCTRL_SET_SPU_PALETTE, spu->global_palette);