spudec: Simplify creation of color/alpha map
[mplayer/glamo.git] / spudec.c
blob0b7ef44d9bd46074f890a155e006c7c94bec95f2
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 int is_decoded;
63 unsigned char *packet;
64 int data_len;
65 unsigned int palette[4];
66 unsigned int alpha[4];
67 unsigned int control_start; /* index of start of control data */
68 unsigned int current_nibble[2]; /* next data nibble (4 bits) to be
69 processed (for RLE decoding) for
70 even and odd lines */
71 int deinterlace_oddness; /* 0 or 1, index into current_nibble */
72 unsigned int start_col, end_col;
73 unsigned int start_row, end_row;
74 unsigned int width, height, stride;
75 unsigned int start_pts, end_pts;
76 packet_t *next;
79 typedef struct {
80 packet_t *queue_head;
81 packet_t *queue_tail;
82 unsigned int global_palette[16];
83 unsigned int orig_frame_width, orig_frame_height;
84 unsigned char* packet;
85 size_t packet_reserve; /* size of the memory pointed to by packet */
86 unsigned int packet_offset; /* end of the currently assembled fragment */
87 unsigned int packet_size; /* size of the packet once all fragments are assembled */
88 int packet_pts; /* PTS for this packet */
89 unsigned int palette[4];
90 unsigned int alpha[4];
91 unsigned int cuspal[4];
92 unsigned int custom;
93 unsigned int now_pts;
94 unsigned int start_pts, end_pts;
95 unsigned int start_col, end_col;
96 unsigned int start_row, end_row;
97 unsigned int width, height, stride;
98 size_t image_size; /* Size of the image buffer */
99 unsigned char *image; /* Grayscale value */
100 unsigned char *aimage; /* Alpha value */
101 unsigned int scaled_frame_width, scaled_frame_height;
102 unsigned int scaled_start_col, scaled_start_row;
103 unsigned int scaled_width, scaled_height, scaled_stride;
104 size_t scaled_image_size;
105 unsigned char *scaled_image;
106 unsigned char *scaled_aimage;
107 int auto_palette; /* 1 if we lack a palette and must use an heuristic. */
108 int font_start_level; /* Darkest value used for the computed font */
109 struct vo *hw_spu;
110 int spu_changed;
111 unsigned int forced_subs_only; /* flag: 0=display all subtitle, !0 display only forced subtitles */
112 unsigned int is_forced_sub; /* true if current subtitle is a forced subtitle */
113 } spudec_handle_t;
115 static void spudec_queue_packet(spudec_handle_t *this, packet_t *packet)
117 if (this->queue_head == NULL)
118 this->queue_head = packet;
119 else
120 this->queue_tail->next = packet;
121 this->queue_tail = packet;
124 static packet_t *spudec_dequeue_packet(spudec_handle_t *this)
126 packet_t *retval = this->queue_head;
128 this->queue_head = retval->next;
129 if (this->queue_head == NULL)
130 this->queue_tail = NULL;
132 return retval;
135 static void spudec_free_packet(packet_t *packet)
137 if (packet->packet != NULL)
138 free(packet->packet);
139 free(packet);
142 static inline unsigned int get_be16(const unsigned char *p)
144 return (p[0] << 8) + p[1];
147 static inline unsigned int get_be24(const unsigned char *p)
149 return (get_be16(p) << 8) + p[2];
152 static void next_line(packet_t *packet)
154 if (packet->current_nibble[packet->deinterlace_oddness] % 2)
155 packet->current_nibble[packet->deinterlace_oddness]++;
156 packet->deinterlace_oddness = (packet->deinterlace_oddness + 1) % 2;
159 static inline unsigned char get_nibble(packet_t *packet)
161 unsigned char nib;
162 unsigned int *nibblep = packet->current_nibble + packet->deinterlace_oddness;
163 if (*nibblep / 2 >= packet->control_start) {
164 mp_msg(MSGT_SPUDEC,MSGL_WARN, "SPUdec: ERROR: get_nibble past end of packet\n");
165 return 0;
167 nib = packet->packet[*nibblep / 2];
168 if (*nibblep % 2)
169 nib &= 0xf;
170 else
171 nib >>= 4;
172 ++*nibblep;
173 return nib;
176 /* Cut the sub to visible part */
177 static inline void spudec_cut_image(spudec_handle_t *this)
179 unsigned int fy, ly;
180 unsigned int first_y, last_y;
181 unsigned char *image;
182 unsigned char *aimage;
184 if (this->stride == 0 || this->height == 0) {
185 return;
188 for (fy = 0; fy < this->image_size && !this->aimage[fy]; fy++);
189 for (ly = this->stride * this->height-1; ly && !this->aimage[ly]; ly--);
190 first_y = fy / this->stride;
191 last_y = ly / this->stride;
192 //printf("first_y: %d, last_y: %d\n", first_y, last_y);
193 this->start_row += first_y;
195 // Some subtitles trigger this condition
196 if (last_y + 1 > first_y ) {
197 this->height = last_y - first_y +1;
198 } else {
199 this->height = 0;
200 this->image_size = 0;
201 return;
204 // printf("new h %d new start %d (sz %d st %d)---\n\n", this->height, this->start_row, this->image_size, this->stride);
206 image = malloc(2 * this->stride * this->height);
207 if(image){
208 this->image_size = this->stride * this->height;
209 aimage = image + this->image_size;
210 memcpy(image, this->image + this->stride * first_y, this->image_size);
211 memcpy(aimage, this->aimage + this->stride * first_y, this->image_size);
212 free(this->image);
213 this->image = image;
214 this->aimage = aimage;
215 } else {
216 mp_msg(MSGT_SPUDEC, MSGL_FATAL, "Fatal: update_spu: malloc requested %d bytes\n", 2 * this->stride * this->height);
221 static int spudec_alloc_image(spudec_handle_t *this, int stride, int height)
223 if (this->width > stride) // just a safeguard
224 this->width = stride;
225 this->stride = stride;
226 this->height = height;
227 if (this->image_size < this->stride * this->height) {
228 if (this->image != NULL) {
229 free(this->image);
230 this->image_size = 0;
232 this->image = malloc(2 * this->stride * this->height);
233 if (this->image) {
234 this->image_size = this->stride * this->height;
235 this->aimage = this->image + this->image_size;
238 return this->image != NULL;
241 static void spudec_process_data(spudec_handle_t *this, packet_t *packet)
243 unsigned int cmap[4], alpha[4];
244 unsigned int i, x, y;
246 this->scaled_frame_width = 0;
247 this->scaled_frame_height = 0;
248 this->start_col = packet->start_col;
249 this->end_col = packet->end_col;
250 this->start_row = packet->start_row;
251 this->end_row = packet->end_row;
252 this->height = packet->height;
253 this->width = packet->width;
254 this->stride = packet->stride;
255 for (i = 0; i < 4; ++i) {
256 alpha[i] = packet->alpha[i];
257 // extend 4 -> 8 bit
258 alpha[i] |= alpha[i] << 4;
259 if (this->custom && (this->cuspal[i] >> 31) != 0)
260 alpha[i] = 0;
261 cmap[i] = this->custom ? this->cuspal[i] :
262 this->global_palette[packet->palette[i]];
263 cmap[i] = (cmap[i] >> 16) & 0xff;
264 // convert to MPlayer format
265 cmap[i] = FFMIN(cmap[i], alpha[i]);
266 alpha[i] = -alpha[i];
269 if (!spudec_alloc_image(this, this->stride, this->height))
270 return;
272 /* Kludge: draw_alpha needs width multiple of 8. */
273 if (this->width < this->stride)
274 for (y = 0; y < this->height; ++y) {
275 memset(this->aimage + y * this->stride + this->width, 0, this->stride - this->width);
276 /* FIXME: Why is this one needed? */
277 memset(this->image + y * this->stride + this->width, 0, this->stride - this->width);
280 i = packet->current_nibble[1];
281 x = 0;
282 y = 0;
283 while (packet->current_nibble[0] < i
284 && packet->current_nibble[1] / 2 < packet->control_start
285 && y < this->height) {
286 unsigned int len, color;
287 unsigned int rle = 0;
288 rle = get_nibble(packet);
289 if (rle < 0x04) {
290 rle = (rle << 4) | get_nibble(packet);
291 if (rle < 0x10) {
292 rle = (rle << 4) | get_nibble(packet);
293 if (rle < 0x040) {
294 rle = (rle << 4) | get_nibble(packet);
295 if (rle < 0x0004)
296 rle |= ((this->width - x) << 2);
300 color = 3 - (rle & 0x3);
301 len = rle >> 2;
302 if (len > this->width - x || len == 0)
303 len = this->width - x;
304 /* FIXME have to use palette and alpha map*/
305 memset(this->image + y * this->stride + x, cmap[color], len);
306 memset(this->aimage + y * this->stride + x, alpha[color], len);
307 x += len;
308 if (x >= this->width) {
309 next_line(packet);
310 x = 0;
311 ++y;
314 spudec_cut_image(this);
319 This function tries to create a usable palette.
320 It determines how many non-transparent colors are used, and assigns different
321 gray scale values to each color.
322 I tested it with four streams and even got something readable. Half of the
323 times I got black characters with white around and half the reverse.
325 static void compute_palette(spudec_handle_t *this, packet_t *packet)
327 int used[16],i,cused,start,step,color;
329 memset(used, 0, sizeof(used));
330 for (i=0; i<4; i++)
331 if (packet->alpha[i]) /* !Transparent? */
332 used[packet->palette[i]] = 1;
333 for (cused=0, i=0; i<16; i++)
334 if (used[i]) cused++;
335 if (!cused) return;
336 if (cused == 1) {
337 start = 0x80;
338 step = 0;
339 } else {
340 start = this->font_start_level;
341 step = (0xF0-this->font_start_level)/(cused-1);
343 memset(used, 0, sizeof(used));
344 for (i=0; i<4; i++) {
345 color = packet->palette[i];
346 if (packet->alpha[i] && !used[color]) { /* not assigned? */
347 used[color] = 1;
348 this->global_palette[color] = start<<16;
349 start += step;
354 static void spudec_process_control(spudec_handle_t *this, int pts100)
356 int a,b,c,d; /* Temporary vars */
357 unsigned int date, type;
358 unsigned int off;
359 unsigned int start_off = 0;
360 unsigned int next_off;
361 unsigned int start_pts = 0;
362 unsigned int end_pts = 0;
363 unsigned int current_nibble[2] = {0, 0};
364 unsigned int control_start;
365 unsigned int display = 0;
366 unsigned int start_col = 0;
367 unsigned int end_col = 0;
368 unsigned int start_row = 0;
369 unsigned int end_row = 0;
370 unsigned int width = 0;
371 unsigned int height = 0;
372 unsigned int stride = 0;
374 control_start = get_be16(this->packet + 2);
375 next_off = control_start;
376 while (start_off != next_off) {
377 start_off = next_off;
378 date = get_be16(this->packet + start_off) * 1024;
379 next_off = get_be16(this->packet + start_off + 2);
380 mp_msg(MSGT_SPUDEC,MSGL_DBG2, "date=%d\n", date);
381 off = start_off + 4;
382 for (type = this->packet[off++]; type != 0xff; type = this->packet[off++]) {
383 mp_msg(MSGT_SPUDEC,MSGL_DBG2, "cmd=%d ",type);
384 switch(type) {
385 case 0x00:
386 /* Menu ID, 1 byte */
387 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Menu ID\n");
388 /* shouldn't a Menu ID type force display start? */
389 start_pts = pts100 < 0 && -pts100 >= date ? 0 : pts100 + date;
390 end_pts = UINT_MAX;
391 display = 1;
392 this->is_forced_sub=~0; // current subtitle is forced
393 break;
394 case 0x01:
395 /* Start display */
396 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Start display!\n");
397 start_pts = pts100 < 0 && -pts100 >= date ? 0 : pts100 + date;
398 end_pts = UINT_MAX;
399 display = 1;
400 this->is_forced_sub=0;
401 break;
402 case 0x02:
403 /* Stop display */
404 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Stop display!\n");
405 end_pts = pts100 < 0 && -pts100 >= date ? 0 : pts100 + date;
406 break;
407 case 0x03:
408 /* Palette */
409 this->palette[0] = this->packet[off] >> 4;
410 this->palette[1] = this->packet[off] & 0xf;
411 this->palette[2] = this->packet[off + 1] >> 4;
412 this->palette[3] = this->packet[off + 1] & 0xf;
413 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Palette %d, %d, %d, %d\n",
414 this->palette[0], this->palette[1], this->palette[2], this->palette[3]);
415 off+=2;
416 break;
417 case 0x04:
418 /* Alpha */
419 a = this->packet[off] >> 4;
420 b = this->packet[off] & 0xf;
421 c = this->packet[off + 1] >> 4;
422 d = this->packet[off + 1] & 0xf;
423 // Note: some DVDs change these values to create a fade-in/fade-out effect
424 // We can not handle this, so just keep the highest value during the display time.
425 if (display) {
426 a = FFMAX(a, this->alpha[0]);
427 b = FFMAX(b, this->alpha[1]);
428 c = FFMAX(c, this->alpha[2]);
429 d = FFMAX(d, this->alpha[3]);
431 this->alpha[0] = a;
432 this->alpha[1] = b;
433 this->alpha[2] = c;
434 this->alpha[3] = d;
435 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Alpha %d, %d, %d, %d\n",
436 this->alpha[0], this->alpha[1], this->alpha[2], this->alpha[3]);
437 off+=2;
438 break;
439 case 0x05:
440 /* Co-ords */
441 a = get_be24(this->packet + off);
442 b = get_be24(this->packet + off + 3);
443 start_col = a >> 12;
444 end_col = a & 0xfff;
445 width = (end_col < start_col) ? 0 : end_col - start_col + 1;
446 stride = (width + 7) & ~7; /* Kludge: draw_alpha needs width multiple of 8 */
447 start_row = b >> 12;
448 end_row = b & 0xfff;
449 height = (end_row < start_row) ? 0 : end_row - start_row /* + 1 */;
450 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Coords col: %d - %d row: %d - %d (%dx%d)\n",
451 start_col, end_col, start_row, end_row,
452 width, height);
453 off+=6;
454 break;
455 case 0x06:
456 /* Graphic lines */
457 current_nibble[0] = 2 * get_be16(this->packet + off);
458 current_nibble[1] = 2 * get_be16(this->packet + off + 2);
459 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Graphic offset 1: %d offset 2: %d\n",
460 current_nibble[0] / 2, current_nibble[1] / 2);
461 off+=4;
462 break;
463 case 0xff:
464 /* All done, bye-bye */
465 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Done!\n");
466 return;
467 // break;
468 default:
469 mp_msg(MSGT_SPUDEC,MSGL_WARN,"spudec: Error determining control type 0x%02x. Skipping %d bytes.\n",
470 type, next_off - off);
471 goto next_control;
474 next_control:
475 if (!display)
476 continue;
477 if (end_pts == UINT_MAX && start_off != next_off) {
478 end_pts = get_be16(this->packet + next_off) * 1024;
479 end_pts = 1 - pts100 >= end_pts ? 0 : pts100 + end_pts - 1;
481 if (end_pts > 0) {
482 packet_t *packet = calloc(1, sizeof(packet_t));
483 int i;
484 packet->start_pts = start_pts;
485 packet->end_pts = end_pts;
486 packet->current_nibble[0] = current_nibble[0];
487 packet->current_nibble[1] = current_nibble[1];
488 packet->start_row = start_row;
489 packet->end_row = end_row;
490 packet->start_col = start_col;
491 packet->end_col = end_col;
492 packet->width = width;
493 packet->height = height;
494 packet->stride = stride;
495 packet->control_start = control_start;
496 for (i=0; i<4; i++) {
497 packet->alpha[i] = this->alpha[i];
498 packet->palette[i] = this->palette[i];
500 packet->packet = malloc(this->packet_size);
501 memcpy(packet->packet, this->packet, this->packet_size);
502 spudec_queue_packet(this, packet);
507 static void spudec_decode(spudec_handle_t *this, int pts100)
509 if (!this->hw_spu)
510 spudec_process_control(this, pts100);
511 else if (pts100 >= 0) {
512 static vo_mpegpes_t packet = { NULL, 0, 0x20, 0 };
513 static vo_mpegpes_t *pkg=&packet;
514 packet.data = this->packet;
515 packet.size = this->packet_size;
516 packet.timestamp = pts100;
517 vo_draw_frame(this->hw_spu, (uint8_t**)&pkg);
521 int spudec_changed(void * this)
523 spudec_handle_t * spu = this;
524 return spu->spu_changed || spu->now_pts > spu->end_pts;
527 void spudec_assemble(void *this, unsigned char *packet, unsigned int len, int pts100)
529 spudec_handle_t *spu = this;
530 // spudec_heartbeat(this, pts100);
531 if (len < 2) {
532 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: packet too short\n");
533 return;
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 = 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 = this;
614 spu->now_pts = pts100;
616 // TODO: detect and handle broken timestamps (e.g. due to wrapping)
617 while (spu->queue_head != NULL && pts100 >= spu->queue_head->start_pts) {
618 packet_t *packet = spudec_dequeue_packet(spu);
619 spu->start_pts = packet->start_pts;
620 spu->end_pts = packet->end_pts;
621 if (packet->is_decoded) {
622 free(spu->image);
623 spu->image_size = packet->data_len;
624 spu->image = packet->packet;
625 spu->aimage = packet->packet + packet->stride * packet->height;
626 packet->packet = NULL;
627 spu->width = packet->width;
628 spu->height = packet->height;
629 spu->stride = packet->stride;
630 spu->start_col = packet->start_col;
631 spu->start_row = packet->start_row;
633 // reset scaled image
634 spu->scaled_frame_width = 0;
635 spu->scaled_frame_height = 0;
636 } else {
637 if (spu->auto_palette)
638 compute_palette(spu, packet);
639 spudec_process_data(spu, packet);
641 spudec_free_packet(packet);
642 spu->spu_changed = 1;
646 int spudec_visible(void *this){
647 spudec_handle_t *spu = this;
648 int ret=(spu->start_pts <= spu->now_pts &&
649 spu->now_pts < spu->end_pts &&
650 spu->height > 0);
651 // printf("spu visible: %d \n",ret);
652 return ret;
655 void spudec_set_forced_subs_only(void * const this, const unsigned int flag)
657 if(this){
658 ((spudec_handle_t *)this)->forced_subs_only=flag;
659 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPU: Display only forced subs now %s\n", flag ? "enabled": "disabled");
663 void spudec_draw(void *this, void (*draw_alpha)(void *ctx, int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride), void *ctx)
665 spudec_handle_t *spu = this;
666 if (spudec_visible(spu))
668 draw_alpha(ctx, spu->start_col, spu->start_row, spu->width, spu->height,
669 spu->image, spu->aimage, spu->stride);
670 spu->spu_changed = 0;
674 /* calc the bbox for spudec subs */
675 void spudec_calc_bbox(void *me, unsigned int dxs, unsigned int dys, unsigned int* bbox)
677 spudec_handle_t *spu = me;
678 if (spu->orig_frame_width == 0 || spu->orig_frame_height == 0
679 || (spu->orig_frame_width == dxs && spu->orig_frame_height == dys)) {
680 // unscaled
681 bbox[0] = spu->start_col;
682 bbox[1] = spu->start_col + spu->width;
683 bbox[2] = spu->start_row;
684 bbox[3] = spu->start_row + spu->height;
686 else {
687 // scaled
688 unsigned int scalex = 0x100 * dxs / spu->orig_frame_width;
689 unsigned int scaley = 0x100 * dys / spu->orig_frame_height;
690 bbox[0] = spu->start_col * scalex / 0x100;
691 bbox[1] = spu->start_col * scalex / 0x100 + spu->width * scalex / 0x100;
692 switch (spu_alignment) {
693 case 0:
694 bbox[3] = dys*sub_pos/100 + spu->height * scaley / 0x100;
695 if (bbox[3] > dys) bbox[3] = dys;
696 bbox[2] = bbox[3] - spu->height * scaley / 0x100;
697 break;
698 case 1:
699 if (sub_pos < 50) {
700 bbox[2] = dys*sub_pos/100 - spu->height * scaley / 0x200;
701 bbox[3] = bbox[2] + spu->height;
702 } else {
703 bbox[3] = dys*sub_pos/100 + spu->height * scaley / 0x200;
704 if (bbox[3] > dys) bbox[3] = dys;
705 bbox[2] = bbox[3] - spu->height * scaley / 0x100;
707 break;
708 case 2:
709 bbox[2] = dys*sub_pos/100 - spu->height * scaley / 0x100;
710 bbox[3] = bbox[2] + spu->height;
711 break;
712 default: /* -1 */
713 bbox[2] = spu->start_row * scaley / 0x100;
714 bbox[3] = spu->start_row * scaley / 0x100 + spu->height * scaley / 0x100;
715 break;
719 /* transform mplayer's alpha value into an opacity value that is linear */
720 static inline int canon_alpha(int alpha)
722 return (uint8_t)-alpha;
725 typedef struct {
726 unsigned position;
727 unsigned left_up;
728 unsigned right_down;
729 }scale_pixel;
732 static void scale_table(unsigned int start_src, unsigned int start_tar, unsigned int end_src, unsigned int end_tar, scale_pixel * table)
734 unsigned int t;
735 unsigned int delta_src = end_src - start_src;
736 unsigned int delta_tar = end_tar - start_tar;
737 int src = 0;
738 int src_step;
739 if (delta_src == 0 || delta_tar == 0) {
740 return;
742 src_step = (delta_src << 16) / delta_tar >>1;
743 for (t = 0; t<=delta_tar; src += (src_step << 1), t++){
744 table[t].position= FFMIN(src >> 16, end_src - 1);
745 table[t].right_down = src & 0xffff;
746 table[t].left_up = 0x10000 - table[t].right_down;
750 /* bilinear scale, similar to vobsub's code */
751 static void scale_image(int x, int y, scale_pixel* table_x, scale_pixel* table_y, spudec_handle_t * spu)
753 int alpha[4];
754 int color[4];
755 unsigned int scale[4];
756 int base = table_y[y].position * spu->stride + table_x[x].position;
757 int scaled = y * spu->scaled_stride + x;
758 alpha[0] = canon_alpha(spu->aimage[base]);
759 alpha[1] = canon_alpha(spu->aimage[base + 1]);
760 alpha[2] = canon_alpha(spu->aimage[base + spu->stride]);
761 alpha[3] = canon_alpha(spu->aimage[base + spu->stride + 1]);
762 color[0] = spu->image[base];
763 color[1] = spu->image[base + 1];
764 color[2] = spu->image[base + spu->stride];
765 color[3] = spu->image[base + spu->stride + 1];
766 scale[0] = (table_x[x].left_up * table_y[y].left_up >> 16) * alpha[0];
767 if (table_y[y].left_up == 0x10000) // necessary to avoid overflow-case
768 scale[0] = table_x[x].left_up * alpha[0];
769 scale[1] = (table_x[x].right_down * table_y[y].left_up >>16) * alpha[1];
770 scale[2] = (table_x[x].left_up * table_y[y].right_down >> 16) * alpha[2];
771 scale[3] = (table_x[x].right_down * table_y[y].right_down >> 16) * alpha[3];
772 spu->scaled_image[scaled] = (color[0] * scale[0] + color[1] * scale[1] + color[2] * scale[2] + color[3] * scale[3])>>24;
773 spu->scaled_aimage[scaled] = (scale[0] + scale[1] + scale[2] + scale[3]) >> 16;
774 if (spu->scaled_aimage[scaled]){
775 // ensure that MPlayer's simplified alpha-blending can not overflow
776 spu->scaled_image[scaled] = FFMIN(spu->scaled_image[scaled], spu->scaled_aimage[scaled]);
777 // convert to MPlayer-style alpha
778 spu->scaled_aimage[scaled] = -spu->scaled_aimage[scaled];
782 static void sws_spu_image(unsigned char *d1, unsigned char *d2, int dw, int dh,
783 int ds, unsigned char *s1, unsigned char *s2, int sw,
784 int sh, int ss)
786 struct SwsContext *ctx;
787 static SwsFilter filter;
788 static int firsttime = 1;
789 static float oldvar;
790 int i;
792 if (!firsttime && oldvar != spu_gaussvar) sws_freeVec(filter.lumH);
793 if (firsttime) {
794 filter.lumH = filter.lumV =
795 filter.chrH = filter.chrV = sws_getGaussianVec(spu_gaussvar, 3.0);
796 sws_normalizeVec(filter.lumH, 1.0);
797 firsttime = 0;
798 oldvar = spu_gaussvar;
801 ctx=sws_getContext(sw, sh, PIX_FMT_GRAY8, dw, dh, PIX_FMT_GRAY8, SWS_GAUSS, &filter, NULL, NULL);
802 sws_scale(ctx,&s1,&ss,0,sh,&d1,&ds);
803 for (i=ss*sh-1; i>=0; i--) if (!s2[i]) s2[i] = 255; //else s2[i] = 1;
804 sws_scale(ctx,&s2,&ss,0,sh,&d2,&ds);
805 for (i=ds*dh-1; i>=0; i--) if (d2[i]==0) d2[i] = 1; else if (d2[i]==255) d2[i] = 0;
806 sws_freeContext(ctx);
809 void spudec_draw_scaled(void *me, unsigned int dxs, unsigned int dys, void (*draw_alpha)(void *ctx, int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride), void *ctx)
811 spudec_handle_t *spu = me;
812 scale_pixel *table_x;
813 scale_pixel *table_y;
815 if (spudec_visible(spu)) {
817 // check if only forced subtitles are requested
818 if( (spu->forced_subs_only) && !(spu->is_forced_sub) ){
819 return;
822 if (!(spu_aamode&16) && (spu->orig_frame_width == 0 || spu->orig_frame_height == 0
823 || (spu->orig_frame_width == dxs && spu->orig_frame_height == dys))) {
824 spudec_draw(spu, draw_alpha, ctx);
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 = 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 = 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 this->orig_frame_width = frame_width;
1210 // set up palette:
1211 if (palette)
1212 memcpy(this->global_palette, palette, sizeof(this->global_palette));
1213 else
1214 this->auto_palette = 1;
1215 if (extradata)
1216 spudec_parse_extradata(this, extradata, extradata_len);
1217 /* XXX Although the video frame is some size, the SPU frame is
1218 always maximum size i.e. 720 wide and 576 or 480 high */
1219 // For HD files in MKV the VobSub resolution can be higher though,
1220 // see largeres_vobsub.mkv
1221 if (this->orig_frame_width <= 720 && this->orig_frame_height <= 576) {
1222 this->orig_frame_width = 720;
1223 if (this->orig_frame_height == 480 || this->orig_frame_height == 240)
1224 this->orig_frame_height = 480;
1225 else
1226 this->orig_frame_height = 576;
1229 else
1230 mp_msg(MSGT_SPUDEC,MSGL_FATAL, "FATAL: spudec_init: calloc");
1231 return this;
1234 void *spudec_new(unsigned int *palette)
1236 return spudec_new_scaled(palette, 0, 0, NULL, 0);
1239 void spudec_free(void *this)
1241 spudec_handle_t *spu = this;
1242 if (spu) {
1243 while (spu->queue_head)
1244 spudec_free_packet(spudec_dequeue_packet(spu));
1245 if (spu->packet)
1246 free(spu->packet);
1247 if (spu->scaled_image)
1248 free(spu->scaled_image);
1249 if (spu->image)
1250 free(spu->image);
1251 free(spu);
1255 void spudec_set_hw_spu(void *this, struct vo *hw_spu)
1257 spudec_handle_t *spu = this;
1258 if (!spu)
1259 return;
1260 spu->hw_spu = hw_spu;
1261 vo_control(hw_spu, VOCTRL_SET_SPU_PALETTE, spu->global_palette);
1264 #define MP_NOPTS_VALUE (-1LL<<63) //both int64_t and double should be able to represent this exactly
1267 * palette must contain at least 256 32-bit entries, otherwise crashes
1268 * are possible
1270 void spudec_set_paletted(void *this, const uint8_t *pal_img, int pal_stride,
1271 const void *palette,
1272 int x, int y, int w, int h,
1273 double pts, double endpts)
1275 int i;
1276 uint16_t g8a8_pal[256];
1277 packet_t *packet;
1278 const uint32_t *pal = palette;
1279 spudec_handle_t *spu = this;
1280 uint8_t *img;
1281 uint8_t *aimg;
1282 int stride = (w + 7) & ~7;
1283 if ((unsigned)w >= 0x8000 || (unsigned)h > 0x4000)
1284 return;
1285 packet = calloc(1, sizeof(packet_t));
1286 packet->is_decoded = 1;
1287 packet->width = w;
1288 packet->height = h;
1289 packet->stride = stride;
1290 packet->start_col = x;
1291 packet->start_row = y;
1292 packet->data_len = 2 * stride * h;
1293 packet->packet = malloc(packet->data_len);
1294 img = packet->packet;
1295 aimg = packet->packet + stride * h;
1296 for (i = 0; i < 256; i++) {
1297 uint32_t pixel = pal[i];
1298 int alpha = pixel >> 24;
1299 int gray = (((pixel & 0x000000ff) >> 0) +
1300 ((pixel & 0x0000ff00) >> 7) +
1301 ((pixel & 0x00ff0000) >> 16)) >> 2;
1302 gray = FFMIN(gray, alpha);
1303 g8a8_pal[i] = (-alpha << 8) | gray;
1305 for (y = 0; y < h; y++) {
1306 for (x = 0; x < w; x++) {
1307 uint16_t pixel = g8a8_pal[pal_img[x]];
1308 *img++ = pixel;
1309 *aimg++ = pixel >> 8;
1311 for (; x < stride; x++)
1312 *aimg++ = *img++ = 0;
1313 pal_img += pal_stride;
1315 packet->start_pts = 0;
1316 packet->end_pts = 0x7fffffff;
1317 if (pts != MP_NOPTS_VALUE)
1318 packet->start_pts = pts * 90000;
1319 if (endpts != MP_NOPTS_VALUE)
1320 packet->end_pts = endpts * 90000;
1321 spudec_queue_packet(spu, packet);