mp_msg: print messages to stdout, statusline to stderr
[mplayer.git] / sub / spudec.c
blob8c4ba978546ea09f2c554a72678edb3e8c2d897c
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 <errno.h>
31 #include <limits.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <string.h>
36 #include <math.h>
38 #include <libavutil/common.h>
39 #include <libavutil/intreadwrite.h>
40 #include <libswscale/swscale.h>
42 #include "config.h"
43 #include "mp_msg.h"
45 #include "libvo/video_out.h"
46 #include "spudec.h"
47 #include "vobsub.h"
48 #include "mpcommon.h"
50 /* Valid values for spu_aamode:
51 0: none (fastest, most ugly)
52 1: approximate
53 2: full (slowest)
54 3: bilinear (similiar to vobsub, fast and not too bad)
55 4: uses swscaler gaussian (this is the only one that looks good)
58 int spu_aamode = 3;
59 int spu_alignment = -1;
60 float spu_gaussvar = 1.0;
61 extern int sub_pos;
63 typedef struct packet_t packet_t;
64 struct packet_t {
65 int is_decoded;
66 unsigned char *packet;
67 int data_len;
68 unsigned int palette[4];
69 unsigned int alpha[4];
70 unsigned int control_start; /* index of start of control data */
71 unsigned int current_nibble[2]; /* next data nibble (4 bits) to be
72 processed (for RLE decoding) for
73 even and odd lines */
74 int deinterlace_oddness; /* 0 or 1, index into current_nibble */
75 unsigned int start_col;
76 unsigned int start_row;
77 unsigned int width, height, stride;
78 unsigned int start_pts, end_pts;
79 packet_t *next;
82 struct palette_crop_cache {
83 int valid;
84 uint32_t palette;
85 int sx, sy, ex, ey;
86 int result;
89 typedef struct {
90 packet_t *queue_head;
91 packet_t *queue_tail;
92 unsigned int global_palette[16];
93 unsigned int orig_frame_width, orig_frame_height;
94 unsigned char* packet;
95 size_t packet_reserve; /* size of the memory pointed to by packet */
96 unsigned int packet_offset; /* end of the currently assembled fragment */
97 unsigned int packet_size; /* size of the packet once all fragments are assembled */
98 int packet_pts; /* PTS for this packet */
99 unsigned int palette[4];
100 unsigned int alpha[4];
101 unsigned int cuspal[4];
102 unsigned int custom;
103 unsigned int now_pts;
104 unsigned int start_pts, end_pts;
105 unsigned int start_col;
106 unsigned int start_row;
107 unsigned int width, height, stride;
108 size_t image_size; /* Size of the image buffer */
109 unsigned char *image; /* Grayscale value */
110 unsigned char *aimage; /* Alpha value */
111 unsigned int pal_start_col, pal_start_row;
112 unsigned int pal_width, pal_height;
113 unsigned char *pal_image; /* palette entry value */
114 unsigned int scaled_frame_width, scaled_frame_height;
115 unsigned int scaled_start_col, scaled_start_row;
116 unsigned int scaled_width, scaled_height, scaled_stride;
117 size_t scaled_image_size;
118 unsigned char *scaled_image;
119 unsigned char *scaled_aimage;
120 int auto_palette; /* 1 if we lack a palette and must use an heuristic. */
121 int font_start_level; /* Darkest value used for the computed font */
122 int spu_changed;
123 unsigned int forced_subs_only; /* flag: 0=display all subtitle, !0 display only forced subtitles */
124 unsigned int is_forced_sub; /* true if current subtitle is a forced subtitle */
126 struct palette_crop_cache palette_crop_cache;
127 } spudec_handle_t;
129 static void spudec_queue_packet(spudec_handle_t *this, packet_t *packet)
131 if (this->queue_head == NULL)
132 this->queue_head = packet;
133 else
134 this->queue_tail->next = packet;
135 this->queue_tail = packet;
138 static packet_t *spudec_dequeue_packet(spudec_handle_t *this)
140 packet_t *retval = this->queue_head;
142 this->queue_head = retval->next;
143 if (this->queue_head == NULL)
144 this->queue_tail = NULL;
146 return retval;
149 static void spudec_free_packet(packet_t *packet)
151 free(packet->packet);
152 free(packet);
155 static inline unsigned int get_be16(const unsigned char *p)
157 return (p[0] << 8) + p[1];
160 static inline unsigned int get_be24(const unsigned char *p)
162 return (get_be16(p) << 8) + p[2];
165 static void next_line(packet_t *packet)
167 if (packet->current_nibble[packet->deinterlace_oddness] % 2)
168 packet->current_nibble[packet->deinterlace_oddness]++;
169 packet->deinterlace_oddness = (packet->deinterlace_oddness + 1) % 2;
172 static inline unsigned char get_nibble(packet_t *packet)
174 unsigned char nib;
175 unsigned int *nibblep = packet->current_nibble + packet->deinterlace_oddness;
176 if (*nibblep / 2 >= packet->control_start) {
177 mp_msg(MSGT_SPUDEC,MSGL_WARN, "SPUdec: ERROR: get_nibble past end of packet\n");
178 return 0;
180 nib = packet->packet[*nibblep / 2];
181 if (*nibblep % 2)
182 nib &= 0xf;
183 else
184 nib >>= 4;
185 ++*nibblep;
186 return nib;
189 /* Cut the sub to visible part */
190 static inline void spudec_cut_image(spudec_handle_t *this)
192 unsigned int fy, ly;
193 unsigned int first_y, last_y;
195 if (this->stride == 0 || this->height == 0) {
196 return;
199 for (fy = 0; fy < this->image_size && !this->aimage[fy]; fy++);
200 for (ly = this->stride * this->height-1; ly && !this->aimage[ly]; ly--);
201 first_y = fy / this->stride;
202 last_y = ly / this->stride;
203 //printf("first_y: %d, last_y: %d\n", first_y, last_y);
204 this->start_row += first_y;
206 // Some subtitles trigger this condition
207 if (last_y + 1 > first_y ) {
208 this->height = last_y - first_y +1;
209 } else {
210 this->height = 0;
211 return;
214 // printf("new h %d new start %d (sz %d st %d)---\n\n", this->height, this->start_row, this->image_size, this->stride);
216 if (first_y > 0) {
217 memmove(this->image, this->image + this->stride * first_y, this->stride * this->height);
218 memmove(this->aimage, this->aimage + this->stride * first_y, this->stride * this->height);
223 static int spudec_alloc_image(spudec_handle_t *this, int stride, int height)
225 if (this->width > stride) // just a safeguard
226 this->width = stride;
227 this->stride = stride;
228 this->height = height;
229 if (this->image_size < this->stride * this->height) {
230 if (this->image != NULL) {
231 free(this->image);
232 free(this->pal_image);
233 this->image_size = 0;
234 this->pal_width = this->pal_height = 0;
236 this->image = malloc(2 * this->stride * this->height);
237 if (this->image) {
238 this->image_size = this->stride * this->height;
239 this->aimage = this->image + this->image_size;
240 // use stride here as well to simplify reallocation checks
241 this->pal_image = malloc(this->stride * this->height);
244 return this->image != NULL;
248 * \param pal palette in MPlayer-style gray-alpha values, i.e.
249 * alpha == 0 means transparent, 1 fully opaque,
250 * gray value <= 256 - alpha.
252 static void pal2gray_alpha(const uint16_t *pal,
253 const uint8_t *src, int src_stride,
254 uint8_t *dst, uint8_t *dsta,
255 int dst_stride, int w, int h)
257 int x, y;
258 for (y = 0; y < h; y++) {
259 for (x = 0; x < w; x++) {
260 uint16_t pixel = pal[src[x]];
261 *dst++ = pixel;
262 *dsta++ = pixel >> 8;
264 for (; x < dst_stride; x++)
265 *dsta++ = *dst++ = 0;
266 src += src_stride;
270 static int apply_palette_crop(spudec_handle_t *this,
271 unsigned crop_x, unsigned crop_y,
272 unsigned crop_w, unsigned crop_h)
274 int i;
275 uint8_t *src;
276 uint16_t pal[4];
277 unsigned stride = (crop_w + 7) & ~7;
278 if (crop_x > this->pal_width || crop_y > this->pal_height ||
279 crop_w > this->pal_width - crop_x || crop_h > this->pal_width - crop_y ||
280 crop_w > 0x8000 || crop_h > 0x8000 ||
281 stride * crop_h > this->image_size) {
282 return 0;
284 for (i = 0; i < 4; ++i) {
285 int color;
286 int alpha = this->alpha[i];
287 // extend 4 -> 8 bit
288 alpha |= alpha << 4;
289 if (this->custom && (this->cuspal[i] >> 31) != 0)
290 alpha = 0;
291 color = this->custom ? this->cuspal[i] :
292 this->global_palette[this->palette[i]];
293 color = (color >> 16) & 0xff;
294 // convert to MPlayer-style gray/alpha palette
295 color = FFMIN(color, alpha);
296 pal[i] = (-alpha << 8) | color;
298 src = this->pal_image + crop_y * this->pal_width + crop_x;
299 pal2gray_alpha(pal, src, this->pal_width,
300 this->image, this->aimage, stride,
301 crop_w, crop_h);
302 this->width = crop_w;
303 this->height = crop_h;
304 this->stride = stride;
305 this->start_col = this->pal_start_col + crop_x;
306 this->start_row = this->pal_start_row + crop_y;
307 spudec_cut_image(this);
309 // reset scaled image
310 this->scaled_frame_width = 0;
311 this->scaled_frame_height = 0;
312 this->palette_crop_cache.valid = 0;
313 return 1;
316 int spudec_apply_palette_crop(void *this, uint32_t palette,
317 int sx, int sy, int ex, int ey)
319 spudec_handle_t *spu = this;
320 struct palette_crop_cache *c = &spu->palette_crop_cache;
321 if (c->valid && c->palette == palette &&
322 c->sx == sx && c->sy == sy && c->ex == ex && c->ey == ey)
323 return c->result;
324 spu->palette[0] = (palette >> 28) & 0xf;
325 spu->palette[1] = (palette >> 24) & 0xf;
326 spu->palette[2] = (palette >> 20) & 0xf;
327 spu->palette[3] = (palette >> 16) & 0xf;
328 spu->alpha[0] = (palette >> 12) & 0xf;
329 spu->alpha[1] = (palette >> 8) & 0xf;
330 spu->alpha[2] = (palette >> 4) & 0xf;
331 spu->alpha[3] = palette & 0xf;
332 spu->spu_changed = 1;
333 c->result = apply_palette_crop(spu,
334 sx - spu->pal_start_col, sy - spu->pal_start_row,
335 ex - sx, ey - sy);
336 c->palette = palette;
337 c->sx = sx; c->sy = sy;
338 c->ex = ex; c->ey = ey;
339 c->valid = 1;
340 return c->result;
343 static void spudec_process_data(spudec_handle_t *this, packet_t *packet)
345 unsigned int i, x, y;
346 uint8_t *dst;
348 if (!spudec_alloc_image(this, packet->stride, packet->height))
349 return;
351 this->pal_start_col = packet->start_col;
352 this->pal_start_row = packet->start_row;
353 this->pal_height = packet->height;
354 this->pal_width = packet->width;
355 this->stride = packet->stride;
356 memcpy(this->palette, packet->palette, sizeof(this->palette));
357 memcpy(this->alpha, packet->alpha, sizeof(this->alpha));
359 i = packet->current_nibble[1];
360 x = 0;
361 y = 0;
362 dst = this->pal_image;
363 while (packet->current_nibble[0] < i
364 && packet->current_nibble[1] / 2 < packet->control_start
365 && y < this->pal_height) {
366 unsigned int len, color;
367 unsigned int rle = 0;
368 rle = get_nibble(packet);
369 if (rle < 0x04) {
370 if (rle == 0) {
371 rle = (rle << 4) | get_nibble(packet);
372 if (rle < 0x04)
373 rle = (rle << 4) | get_nibble(packet);
375 rle = (rle << 4) | get_nibble(packet);
377 color = 3 - (rle & 0x3);
378 len = rle >> 2;
379 x += len;
380 if (len == 0 || x >= this->pal_width) {
381 len += this->pal_width - x;
382 next_line(packet);
383 x = 0;
384 ++y;
386 memset(dst, color, len);
387 dst += len;
389 apply_palette_crop(this, 0, 0, this->pal_width, this->pal_height);
394 This function tries to create a usable palette.
395 It determines how many non-transparent colors are used, and assigns different
396 gray scale values to each color.
397 I tested it with four streams and even got something readable. Half of the
398 times I got black characters with white around and half the reverse.
400 static void compute_palette(spudec_handle_t *this, packet_t *packet)
402 int used[16],i,cused,start,step,color;
404 memset(used, 0, sizeof(used));
405 for (i=0; i<4; i++)
406 if (packet->alpha[i]) /* !Transparent? */
407 used[packet->palette[i]] = 1;
408 for (cused=0, i=0; i<16; i++)
409 if (used[i]) cused++;
410 if (!cused) return;
411 if (cused == 1) {
412 start = 0x80;
413 step = 0;
414 } else {
415 start = this->font_start_level;
416 step = (0xF0-this->font_start_level)/(cused-1);
418 memset(used, 0, sizeof(used));
419 for (i=0; i<4; i++) {
420 color = packet->palette[i];
421 if (packet->alpha[i] && !used[color]) { /* not assigned? */
422 used[color] = 1;
423 this->global_palette[color] = start<<16;
424 start += step;
429 static void spudec_process_control(spudec_handle_t *this, int pts100)
431 int a,b,c,d; /* Temporary vars */
432 unsigned int date, type;
433 unsigned int off;
434 unsigned int start_off = 0;
435 unsigned int next_off;
436 unsigned int start_pts = 0;
437 unsigned int end_pts = 0;
438 unsigned int current_nibble[2] = {0, 0};
439 unsigned int control_start;
440 unsigned int display = 0;
441 unsigned int start_col = 0;
442 unsigned int end_col = 0;
443 unsigned int start_row = 0;
444 unsigned int end_row = 0;
445 unsigned int width = 0;
446 unsigned int height = 0;
447 unsigned int stride = 0;
449 control_start = get_be16(this->packet + 2);
450 next_off = control_start;
451 while (start_off != next_off) {
452 start_off = next_off;
453 date = get_be16(this->packet + start_off) * 1024;
454 next_off = get_be16(this->packet + start_off + 2);
455 mp_msg(MSGT_SPUDEC,MSGL_DBG2, "date=%d\n", date);
456 off = start_off + 4;
457 for (type = this->packet[off++]; type != 0xff; type = this->packet[off++]) {
458 mp_msg(MSGT_SPUDEC,MSGL_DBG2, "cmd=%d ",type);
459 switch(type) {
460 case 0x00:
461 /* Menu ID, 1 byte */
462 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Menu ID\n");
463 /* shouldn't a Menu ID type force display start? */
464 start_pts = pts100 < 0 && -pts100 >= date ? 0 : pts100 + date;
465 end_pts = UINT_MAX;
466 display = 1;
467 this->is_forced_sub=~0; // current subtitle is forced
468 break;
469 case 0x01:
470 /* Start display */
471 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Start display!\n");
472 start_pts = pts100 < 0 && -pts100 >= date ? 0 : pts100 + date;
473 end_pts = UINT_MAX;
474 display = 1;
475 this->is_forced_sub=0;
476 break;
477 case 0x02:
478 /* Stop display */
479 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Stop display!\n");
480 end_pts = pts100 < 0 && -pts100 >= date ? 0 : pts100 + date;
481 break;
482 case 0x03:
483 /* Palette */
484 this->palette[0] = this->packet[off] >> 4;
485 this->palette[1] = this->packet[off] & 0xf;
486 this->palette[2] = this->packet[off + 1] >> 4;
487 this->palette[3] = this->packet[off + 1] & 0xf;
488 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Palette %d, %d, %d, %d\n",
489 this->palette[0], this->palette[1], this->palette[2], this->palette[3]);
490 off+=2;
491 break;
492 case 0x04:
493 /* Alpha */
494 a = this->packet[off] >> 4;
495 b = this->packet[off] & 0xf;
496 c = this->packet[off + 1] >> 4;
497 d = this->packet[off + 1] & 0xf;
498 // Note: some DVDs change these values to create a fade-in/fade-out effect
499 // We can not handle this, so just keep the highest value during the display time.
500 if (display) {
501 a = FFMAX(a, this->alpha[0]);
502 b = FFMAX(b, this->alpha[1]);
503 c = FFMAX(c, this->alpha[2]);
504 d = FFMAX(d, this->alpha[3]);
506 this->alpha[0] = a;
507 this->alpha[1] = b;
508 this->alpha[2] = c;
509 this->alpha[3] = d;
510 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Alpha %d, %d, %d, %d\n",
511 this->alpha[0], this->alpha[1], this->alpha[2], this->alpha[3]);
512 off+=2;
513 break;
514 case 0x05:
515 /* Co-ords */
516 a = get_be24(this->packet + off);
517 b = get_be24(this->packet + off + 3);
518 start_col = a >> 12;
519 end_col = a & 0xfff;
520 width = (end_col < start_col) ? 0 : end_col - start_col + 1;
521 stride = (width + 7) & ~7; /* Kludge: draw_alpha needs width multiple of 8 */
522 start_row = b >> 12;
523 end_row = b & 0xfff;
524 height = (end_row < start_row) ? 0 : end_row - start_row /* + 1 */;
525 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Coords col: %d - %d row: %d - %d (%dx%d)\n",
526 start_col, end_col, start_row, end_row,
527 width, height);
528 off+=6;
529 break;
530 case 0x06:
531 /* Graphic lines */
532 current_nibble[0] = 2 * get_be16(this->packet + off);
533 current_nibble[1] = 2 * get_be16(this->packet + off + 2);
534 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Graphic offset 1: %d offset 2: %d\n",
535 current_nibble[0] / 2, current_nibble[1] / 2);
536 off+=4;
537 break;
538 case 0xff:
539 /* All done, bye-bye */
540 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Done!\n");
541 return;
542 // break;
543 default:
544 mp_msg(MSGT_SPUDEC,MSGL_WARN,"spudec: Error determining control type 0x%02x. Skipping %d bytes.\n",
545 type, next_off - off);
546 goto next_control;
549 next_control:
550 if (!display)
551 continue;
552 if (end_pts == UINT_MAX && start_off != next_off) {
553 end_pts = get_be16(this->packet + next_off) * 1024;
554 end_pts = 1 - pts100 >= end_pts ? 0 : pts100 + end_pts - 1;
556 if (end_pts > 0) {
557 packet_t *packet = calloc(1, sizeof(packet_t));
558 int i;
559 packet->start_pts = start_pts;
560 packet->end_pts = end_pts;
561 packet->current_nibble[0] = current_nibble[0];
562 packet->current_nibble[1] = current_nibble[1];
563 packet->start_row = start_row;
564 packet->start_col = start_col;
565 packet->width = width;
566 packet->height = height;
567 packet->stride = stride;
568 packet->control_start = control_start;
569 for (i=0; i<4; i++) {
570 packet->alpha[i] = this->alpha[i];
571 packet->palette[i] = this->palette[i];
573 packet->packet = malloc(this->packet_size);
574 memcpy(packet->packet, this->packet, this->packet_size);
575 spudec_queue_packet(this, packet);
580 static void spudec_decode(spudec_handle_t *this, int pts100)
582 spudec_process_control(this, pts100);
585 int spudec_changed(void * this)
587 spudec_handle_t * spu = this;
588 return spu->spu_changed || spu->now_pts > spu->end_pts;
591 void spudec_assemble(void *this, unsigned char *packet, unsigned int len, int pts100)
593 spudec_handle_t *spu = this;
594 // spudec_heartbeat(this, pts100);
595 if (len < 2) {
596 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: packet too short\n");
597 return;
599 spu->packet_pts = pts100;
600 if (spu->packet_offset == 0) {
601 unsigned int len2 = get_be16(packet);
602 // Start new fragment
603 if (spu->packet_reserve < len2) {
604 free(spu->packet);
605 spu->packet = malloc(len2);
606 spu->packet_reserve = spu->packet != NULL ? len2 : 0;
608 if (spu->packet != NULL) {
609 spu->packet_size = len2;
610 if (len > len2) {
611 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: invalid frag len / len2: %d / %d \n", len, len2);
612 return;
614 memcpy(spu->packet, packet, len);
615 spu->packet_offset = len;
616 spu->packet_pts = pts100;
618 } else {
619 // Continue current fragment
620 if (spu->packet_size < spu->packet_offset + len){
621 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: invalid fragment\n");
622 spu->packet_size = spu->packet_offset = 0;
623 return;
624 } else {
625 memcpy(spu->packet + spu->packet_offset, packet, len);
626 spu->packet_offset += len;
629 #if 1
630 // check if we have a complete packet (unfortunatelly packet_size is bad
631 // for some disks)
632 // [cb] packet_size is padded to be even -> may be one byte too long
633 if ((spu->packet_offset == spu->packet_size) ||
634 ((spu->packet_offset + 1) == spu->packet_size)){
635 unsigned int x=0,y;
636 while(x+4<=spu->packet_offset){
637 y=get_be16(spu->packet+x+2); // next control pointer
638 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPUtest: x=%d y=%d off=%d size=%d\n",x,y,spu->packet_offset,spu->packet_size);
639 if(x>=4 && x==y){ // if it points to self - we're done!
640 // we got it!
641 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPUgot: off=%d size=%d \n",spu->packet_offset,spu->packet_size);
642 spudec_decode(spu, pts100);
643 spu->packet_offset = 0;
644 break;
646 if(y<=x || y>=spu->packet_size){ // invalid?
647 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUtest: broken packet!!!!! y=%d < x=%d\n",y,x);
648 spu->packet_size = spu->packet_offset = 0;
649 break;
651 x=y;
653 // [cb] packet is done; start new packet
654 spu->packet_offset = 0;
656 #else
657 if (spu->packet_offset == spu->packet_size) {
658 spudec_decode(spu, pts100);
659 spu->packet_offset = 0;
661 #endif
664 void spudec_reset(void *this) // called after seek
666 spudec_handle_t *spu = this;
667 while (spu->queue_head)
668 spudec_free_packet(spudec_dequeue_packet(spu));
669 spu->now_pts = 0;
670 spu->end_pts = 0;
671 spu->packet_size = spu->packet_offset = 0;
674 void spudec_heartbeat(void *this, unsigned int pts100)
676 spudec_handle_t *spu = this;
677 spu->now_pts = pts100;
679 // TODO: detect and handle broken timestamps (e.g. due to wrapping)
680 while (spu->queue_head != NULL && pts100 >= spu->queue_head->start_pts) {
681 packet_t *packet = spudec_dequeue_packet(spu);
682 spu->start_pts = packet->start_pts;
683 spu->end_pts = packet->end_pts;
684 if (packet->is_decoded) {
685 free(spu->image);
686 spu->image_size = packet->data_len;
687 spu->image = packet->packet;
688 spu->aimage = packet->packet + packet->stride * packet->height;
689 packet->packet = NULL;
690 spu->width = packet->width;
691 spu->height = packet->height;
692 spu->stride = packet->stride;
693 spu->start_col = packet->start_col;
694 spu->start_row = packet->start_row;
696 // reset scaled image
697 spu->scaled_frame_width = 0;
698 spu->scaled_frame_height = 0;
699 } else {
700 if (spu->auto_palette)
701 compute_palette(spu, packet);
702 spudec_process_data(spu, packet);
704 spudec_free_packet(packet);
705 spu->spu_changed = 1;
709 int spudec_visible(void *this){
710 spudec_handle_t *spu = this;
711 int ret=(spu->start_pts <= spu->now_pts &&
712 spu->now_pts < spu->end_pts &&
713 spu->height > 0);
714 // printf("spu visible: %d \n",ret);
715 return ret;
718 void spudec_set_forced_subs_only(void * const this, const unsigned int flag)
720 if(this){
721 ((spudec_handle_t *)this)->forced_subs_only=flag;
722 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPU: Display only forced subs now %s\n", flag ? "enabled": "disabled");
726 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)
728 spudec_handle_t *spu = this;
729 if (spudec_visible(spu))
731 draw_alpha(ctx, spu->start_col, spu->start_row, spu->width, spu->height,
732 spu->image, spu->aimage, spu->stride);
733 spu->spu_changed = 0;
737 /* calc the bbox for spudec subs */
738 void spudec_calc_bbox(void *me, unsigned int dxs, unsigned int dys, unsigned int* bbox)
740 spudec_handle_t *spu = me;
741 if (spu->orig_frame_width == 0 || spu->orig_frame_height == 0
742 || (spu->orig_frame_width == dxs && spu->orig_frame_height == dys)) {
743 // unscaled
744 bbox[0] = spu->start_col;
745 bbox[1] = spu->start_col + spu->width;
746 bbox[2] = spu->start_row;
747 bbox[3] = spu->start_row + spu->height;
749 else {
750 // scaled
751 unsigned int scalex = 0x100 * dxs / spu->orig_frame_width;
752 unsigned int scaley = 0x100 * dys / spu->orig_frame_height;
753 bbox[0] = spu->start_col * scalex / 0x100;
754 bbox[1] = spu->start_col * scalex / 0x100 + spu->width * scalex / 0x100;
755 switch (spu_alignment) {
756 case 0:
757 bbox[3] = dys*sub_pos/100 + spu->height * scaley / 0x100;
758 if (bbox[3] > dys) bbox[3] = dys;
759 bbox[2] = bbox[3] - spu->height * scaley / 0x100;
760 break;
761 case 1:
762 if (sub_pos < 50) {
763 bbox[2] = dys*sub_pos/100 - spu->height * scaley / 0x200;
764 bbox[3] = bbox[2] + spu->height;
765 } else {
766 bbox[3] = dys*sub_pos/100 + spu->height * scaley / 0x200;
767 if (bbox[3] > dys) bbox[3] = dys;
768 bbox[2] = bbox[3] - spu->height * scaley / 0x100;
770 break;
771 case 2:
772 bbox[2] = dys*sub_pos/100 - spu->height * scaley / 0x100;
773 bbox[3] = bbox[2] + spu->height;
774 break;
775 default: /* -1 */
776 bbox[2] = spu->start_row * scaley / 0x100;
777 bbox[3] = spu->start_row * scaley / 0x100 + spu->height * scaley / 0x100;
778 break;
782 /* transform mplayer's alpha value into an opacity value that is linear */
783 static inline int canon_alpha(int alpha)
785 return (uint8_t)-alpha;
788 typedef struct {
789 unsigned position;
790 unsigned left_up;
791 unsigned right_down;
792 }scale_pixel;
795 static void scale_table(unsigned int start_src, unsigned int start_tar, unsigned int end_src, unsigned int end_tar, scale_pixel * table)
797 unsigned int t;
798 unsigned int delta_src = end_src - start_src;
799 unsigned int delta_tar = end_tar - start_tar;
800 int src = 0;
801 int src_step;
802 if (delta_src == 0 || delta_tar == 0) {
803 return;
805 src_step = (delta_src << 16) / delta_tar >>1;
806 for (t = 0; t<=delta_tar; src += (src_step << 1), t++){
807 table[t].position= FFMIN(src >> 16, end_src - 1);
808 table[t].right_down = src & 0xffff;
809 table[t].left_up = 0x10000 - table[t].right_down;
813 /* bilinear scale, similar to vobsub's code */
814 static void scale_image(int x, int y, scale_pixel* table_x, scale_pixel* table_y, spudec_handle_t * spu)
816 int alpha[4];
817 int color[4];
818 unsigned int scale[4];
819 int base = table_y[y].position * spu->stride + table_x[x].position;
820 int scaled = y * spu->scaled_stride + x;
821 alpha[0] = canon_alpha(spu->aimage[base]);
822 alpha[1] = canon_alpha(spu->aimage[base + 1]);
823 alpha[2] = canon_alpha(spu->aimage[base + spu->stride]);
824 alpha[3] = canon_alpha(spu->aimage[base + spu->stride + 1]);
825 color[0] = spu->image[base];
826 color[1] = spu->image[base + 1];
827 color[2] = spu->image[base + spu->stride];
828 color[3] = spu->image[base + spu->stride + 1];
829 scale[0] = (table_x[x].left_up * table_y[y].left_up >> 16) * alpha[0];
830 if (table_y[y].left_up == 0x10000) // necessary to avoid overflow-case
831 scale[0] = table_x[x].left_up * alpha[0];
832 scale[1] = (table_x[x].right_down * table_y[y].left_up >>16) * alpha[1];
833 scale[2] = (table_x[x].left_up * table_y[y].right_down >> 16) * alpha[2];
834 scale[3] = (table_x[x].right_down * table_y[y].right_down >> 16) * alpha[3];
835 spu->scaled_image[scaled] = (color[0] * scale[0] + color[1] * scale[1] + color[2] * scale[2] + color[3] * scale[3])>>24;
836 spu->scaled_aimage[scaled] = (scale[0] + scale[1] + scale[2] + scale[3]) >> 16;
837 if (spu->scaled_aimage[scaled]){
838 // ensure that MPlayer's simplified alpha-blending can not overflow
839 spu->scaled_image[scaled] = FFMIN(spu->scaled_image[scaled], spu->scaled_aimage[scaled]);
840 // convert to MPlayer-style alpha
841 spu->scaled_aimage[scaled] = -spu->scaled_aimage[scaled];
845 static void sws_spu_image(unsigned char *d1, unsigned char *d2, int dw, int dh,
846 int ds, const unsigned char* s1, unsigned char* s2,
847 int sw, int sh, int ss)
849 struct SwsContext *ctx;
850 static SwsFilter filter;
851 static int firsttime = 1;
852 static float oldvar;
853 int i;
855 if (!firsttime && oldvar != spu_gaussvar) sws_freeVec(filter.lumH);
856 if (firsttime) {
857 filter.lumH = filter.lumV =
858 filter.chrH = filter.chrV = sws_getGaussianVec(spu_gaussvar, 3.0);
859 sws_normalizeVec(filter.lumH, 1.0);
860 firsttime = 0;
861 oldvar = spu_gaussvar;
864 ctx=sws_getContext(sw, sh, PIX_FMT_GRAY8, dw, dh, PIX_FMT_GRAY8, SWS_GAUSS, &filter, NULL, NULL);
865 sws_scale(ctx,&s1,&ss,0,sh,&d1,&ds);
866 for (i=ss*sh-1; i>=0; i--) if (!s2[i]) s2[i] = 255; //else s2[i] = 1;
867 sws_scale(ctx,(const uint8_t **)&s2,&ss,0,sh,&d2,&ds);
868 for (i=ds*dh-1; i>=0; i--) if (d2[i]==0) d2[i] = 1; else if (d2[i]==255) d2[i] = 0;
869 sws_freeContext(ctx);
872 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)
874 spudec_handle_t *spu = me;
875 scale_pixel *table_x;
876 scale_pixel *table_y;
878 if (spudec_visible(spu)) {
880 // check if only forced subtitles are requested
881 if( (spu->forced_subs_only) && !(spu->is_forced_sub) ){
882 return;
885 if (!(spu_aamode&16) && (spu->orig_frame_width == 0 || spu->orig_frame_height == 0
886 || (spu->orig_frame_width == dxs && spu->orig_frame_height == dys))) {
887 spudec_draw(spu, draw_alpha, ctx);
889 else {
890 if (spu->scaled_frame_width != dxs || spu->scaled_frame_height != dys) { /* Resizing is needed */
891 /* scaled_x = scalex * x / 0x100
892 scaled_y = scaley * y / 0x100
893 order of operations is important because of rounding. */
894 unsigned int scalex = 0x100 * dxs / spu->orig_frame_width;
895 unsigned int scaley = 0x100 * dys / spu->orig_frame_height;
896 spu->scaled_start_col = spu->start_col * scalex / 0x100;
897 spu->scaled_start_row = spu->start_row * scaley / 0x100;
898 spu->scaled_width = spu->width * scalex / 0x100;
899 spu->scaled_height = spu->height * scaley / 0x100;
900 /* Kludge: draw_alpha needs width multiple of 8 */
901 spu->scaled_stride = (spu->scaled_width + 7) & ~7;
902 if (spu->scaled_image_size < spu->scaled_stride * spu->scaled_height) {
903 if (spu->scaled_image) {
904 free(spu->scaled_image);
905 spu->scaled_image_size = 0;
907 spu->scaled_image = malloc(2 * spu->scaled_stride * spu->scaled_height);
908 if (spu->scaled_image) {
909 spu->scaled_image_size = spu->scaled_stride * spu->scaled_height;
910 spu->scaled_aimage = spu->scaled_image + spu->scaled_image_size;
913 if (spu->scaled_image) {
914 unsigned int x, y;
915 // needs to be 0-initialized because draw_alpha draws always a
916 // multiple of 8 pixels. TODO: optimize
917 if (spu->scaled_width & 7)
918 memset(spu->scaled_image, 0, 2 * spu->scaled_image_size);
919 if (spu->scaled_width <= 1 || spu->scaled_height <= 1) {
920 goto nothing_to_do;
922 switch(spu_aamode&15) {
923 case 4:
924 sws_spu_image(spu->scaled_image, spu->scaled_aimage,
925 spu->scaled_width, spu->scaled_height, spu->scaled_stride,
926 spu->image, spu->aimage, spu->width, spu->height, spu->stride);
927 break;
928 case 3:
929 table_x = calloc(spu->scaled_width, sizeof(scale_pixel));
930 table_y = calloc(spu->scaled_height, sizeof(scale_pixel));
931 if (!table_x || !table_y) {
932 mp_msg(MSGT_SPUDEC, MSGL_FATAL, "Fatal: spudec_draw_scaled: calloc failed\n");
934 scale_table(0, 0, spu->width - 1, spu->scaled_width - 1, table_x);
935 scale_table(0, 0, spu->height - 1, spu->scaled_height - 1, table_y);
936 for (y = 0; y < spu->scaled_height; y++)
937 for (x = 0; x < spu->scaled_width; x++)
938 scale_image(x, y, table_x, table_y, spu);
939 free(table_x);
940 free(table_y);
941 break;
942 case 0:
943 /* no antialiasing */
944 for (y = 0; y < spu->scaled_height; ++y) {
945 int unscaled_y = y * 0x100 / scaley;
946 int strides = spu->stride * unscaled_y;
947 int scaled_strides = spu->scaled_stride * y;
948 for (x = 0; x < spu->scaled_width; ++x) {
949 int unscaled_x = x * 0x100 / scalex;
950 spu->scaled_image[scaled_strides + x] = spu->image[strides + unscaled_x];
951 spu->scaled_aimage[scaled_strides + x] = spu->aimage[strides + unscaled_x];
954 break;
955 case 1:
957 /* Intermediate antialiasing. */
958 for (y = 0; y < spu->scaled_height; ++y) {
959 const unsigned int unscaled_top = y * spu->orig_frame_height / dys;
960 unsigned int unscaled_bottom = (y + 1) * spu->orig_frame_height / dys;
961 if (unscaled_bottom >= spu->height)
962 unscaled_bottom = spu->height - 1;
963 for (x = 0; x < spu->scaled_width; ++x) {
964 const unsigned int unscaled_left = x * spu->orig_frame_width / dxs;
965 unsigned int unscaled_right = (x + 1) * spu->orig_frame_width / dxs;
966 unsigned int color = 0;
967 unsigned int alpha = 0;
968 unsigned int walkx, walky;
969 unsigned int base, tmp;
970 if (unscaled_right >= spu->width)
971 unscaled_right = spu->width - 1;
972 for (walky = unscaled_top; walky <= unscaled_bottom; ++walky)
973 for (walkx = unscaled_left; walkx <= unscaled_right; ++walkx) {
974 base = walky * spu->stride + walkx;
975 tmp = canon_alpha(spu->aimage[base]);
976 alpha += tmp;
977 color += tmp * spu->image[base];
979 base = y * spu->scaled_stride + x;
980 spu->scaled_image[base] = alpha ? color / alpha : 0;
981 spu->scaled_aimage[base] =
982 alpha * (1 + unscaled_bottom - unscaled_top) * (1 + unscaled_right - unscaled_left);
983 /* spu->scaled_aimage[base] =
984 alpha * dxs * dys / spu->orig_frame_width / spu->orig_frame_height; */
985 if (spu->scaled_aimage[base]) {
986 spu->scaled_aimage[base] = 256 - spu->scaled_aimage[base];
987 if (spu->scaled_aimage[base] + spu->scaled_image[base] > 255)
988 spu->scaled_image[base] = 256 - spu->scaled_aimage[base];
993 break;
994 case 2:
996 /* Best antialiasing. Very slow. */
997 /* Any pixel (x, y) represents pixels from the original
998 rectangular region comprised between the columns
999 unscaled_y and unscaled_y + 0x100 / scaley and the rows
1000 unscaled_x and unscaled_x + 0x100 / scalex
1002 The original rectangular region that the scaled pixel
1003 represents is cut in 9 rectangular areas like this:
1005 +---+-----------------+---+
1006 | 1 | 2 | 3 |
1007 +---+-----------------+---+
1008 | | | |
1009 | 4 | 5 | 6 |
1010 | | | |
1011 +---+-----------------+---+
1012 | 7 | 8 | 9 |
1013 +---+-----------------+---+
1015 The width of the left column is at most one pixel and
1016 it is never null and its right column is at a pixel
1017 boundary. The height of the top row is at most one
1018 pixel it is never null and its bottom row is at a
1019 pixel boundary. The width and height of region 5 are
1020 integral values. The width of the right column is
1021 what remains and is less than one pixel. The height
1022 of the bottom row is what remains and is less than
1023 one pixel.
1025 The row above 1, 2, 3 is unscaled_y. The row between
1026 1, 2, 3 and 4, 5, 6 is top_low_row. The row between 4,
1027 5, 6 and 7, 8, 9 is (unsigned int)unscaled_y_bottom.
1028 The row beneath 7, 8, 9 is unscaled_y_bottom.
1030 The column left of 1, 4, 7 is unscaled_x. The column
1031 between 1, 4, 7 and 2, 5, 8 is left_right_column. The
1032 column between 2, 5, 8 and 3, 6, 9 is (unsigned
1033 int)unscaled_x_right. The column right of 3, 6, 9 is
1034 unscaled_x_right. */
1035 const double inv_scalex = (double) 0x100 / scalex;
1036 const double inv_scaley = (double) 0x100 / scaley;
1037 for (y = 0; y < spu->scaled_height; ++y) {
1038 const double unscaled_y = y * inv_scaley;
1039 const double unscaled_y_bottom = unscaled_y + inv_scaley;
1040 const unsigned int top_low_row = FFMIN(unscaled_y_bottom, unscaled_y + 1.0);
1041 const double top = top_low_row - unscaled_y;
1042 const unsigned int height = unscaled_y_bottom > top_low_row
1043 ? (unsigned int) unscaled_y_bottom - top_low_row
1044 : 0;
1045 const double bottom = unscaled_y_bottom > top_low_row
1046 ? unscaled_y_bottom - floor(unscaled_y_bottom)
1047 : 0.0;
1048 for (x = 0; x < spu->scaled_width; ++x) {
1049 const double unscaled_x = x * inv_scalex;
1050 const double unscaled_x_right = unscaled_x + inv_scalex;
1051 const unsigned int left_right_column = FFMIN(unscaled_x_right, unscaled_x + 1.0);
1052 const double left = left_right_column - unscaled_x;
1053 const unsigned int width = unscaled_x_right > left_right_column
1054 ? (unsigned int) unscaled_x_right - left_right_column
1055 : 0;
1056 const double right = unscaled_x_right > left_right_column
1057 ? unscaled_x_right - floor(unscaled_x_right)
1058 : 0.0;
1059 double color = 0.0;
1060 double alpha = 0.0;
1061 double tmp;
1062 unsigned int base;
1063 /* Now use these informations to compute a good alpha,
1064 and lightness. The sum is on each of the 9
1065 region's surface and alpha and lightness.
1067 transformed alpha = sum(surface * alpha) / sum(surface)
1068 transformed color = sum(surface * alpha * color) / sum(surface * alpha)
1070 /* 1: top left part */
1071 base = spu->stride * (unsigned int) unscaled_y;
1072 tmp = left * top * canon_alpha(spu->aimage[base + (unsigned int) unscaled_x]);
1073 alpha += tmp;
1074 color += tmp * spu->image[base + (unsigned int) unscaled_x];
1075 /* 2: top center part */
1076 if (width > 0) {
1077 unsigned int walkx;
1078 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
1079 base = spu->stride * (unsigned int) unscaled_y + walkx;
1080 tmp = /* 1.0 * */ top * canon_alpha(spu->aimage[base]);
1081 alpha += tmp;
1082 color += tmp * spu->image[base];
1085 /* 3: top right part */
1086 if (right > 0.0) {
1087 base = spu->stride * (unsigned int) unscaled_y + (unsigned int) unscaled_x_right;
1088 tmp = right * top * canon_alpha(spu->aimage[base]);
1089 alpha += tmp;
1090 color += tmp * spu->image[base];
1092 /* 4: center left part */
1093 if (height > 0) {
1094 unsigned int walky;
1095 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1096 base = spu->stride * walky + (unsigned int) unscaled_x;
1097 tmp = left /* * 1.0 */ * canon_alpha(spu->aimage[base]);
1098 alpha += tmp;
1099 color += tmp * spu->image[base];
1102 /* 5: center part */
1103 if (width > 0 && height > 0) {
1104 unsigned int walky;
1105 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1106 unsigned int walkx;
1107 base = spu->stride * walky;
1108 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
1109 tmp = /* 1.0 * 1.0 * */ canon_alpha(spu->aimage[base + walkx]);
1110 alpha += tmp;
1111 color += tmp * spu->image[base + walkx];
1115 /* 6: center right part */
1116 if (right > 0.0 && height > 0) {
1117 unsigned int walky;
1118 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1119 base = spu->stride * walky + (unsigned int) unscaled_x_right;
1120 tmp = right /* * 1.0 */ * canon_alpha(spu->aimage[base]);
1121 alpha += tmp;
1122 color += tmp * spu->image[base];
1125 /* 7: bottom left part */
1126 if (bottom > 0.0) {
1127 base = spu->stride * (unsigned int) unscaled_y_bottom + (unsigned int) unscaled_x;
1128 tmp = left * bottom * canon_alpha(spu->aimage[base]);
1129 alpha += tmp;
1130 color += tmp * spu->image[base];
1132 /* 8: bottom center part */
1133 if (width > 0 && bottom > 0.0) {
1134 unsigned int walkx;
1135 base = spu->stride * (unsigned int) unscaled_y_bottom;
1136 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
1137 tmp = /* 1.0 * */ bottom * canon_alpha(spu->aimage[base + walkx]);
1138 alpha += tmp;
1139 color += tmp * spu->image[base + walkx];
1142 /* 9: bottom right part */
1143 if (right > 0.0 && bottom > 0.0) {
1144 base = spu->stride * (unsigned int) unscaled_y_bottom + (unsigned int) unscaled_x_right;
1145 tmp = right * bottom * canon_alpha(spu->aimage[base]);
1146 alpha += tmp;
1147 color += tmp * spu->image[base];
1149 /* Finally mix these transparency and brightness information suitably */
1150 base = spu->scaled_stride * y + x;
1151 spu->scaled_image[base] = alpha > 0 ? color / alpha : 0;
1152 spu->scaled_aimage[base] = alpha * scalex * scaley / 0x10000;
1153 if (spu->scaled_aimage[base]) {
1154 spu->scaled_aimage[base] = 256 - spu->scaled_aimage[base];
1155 if (spu->scaled_aimage[base] + spu->scaled_image[base] > 255)
1156 spu->scaled_image[base] = 256 - spu->scaled_aimage[base];
1162 nothing_to_do:
1163 /* Kludge: draw_alpha needs width multiple of 8. */
1164 if (spu->scaled_width < spu->scaled_stride)
1165 for (y = 0; y < spu->scaled_height; ++y) {
1166 memset(spu->scaled_aimage + y * spu->scaled_stride + spu->scaled_width, 0,
1167 spu->scaled_stride - spu->scaled_width);
1169 spu->scaled_frame_width = dxs;
1170 spu->scaled_frame_height = dys;
1173 if (spu->scaled_image){
1174 switch (spu_alignment) {
1175 case 0:
1176 spu->scaled_start_row = dys*sub_pos/100;
1177 if (spu->scaled_start_row + spu->scaled_height > dys)
1178 spu->scaled_start_row = dys - spu->scaled_height;
1179 break;
1180 case 1:
1181 spu->scaled_start_row = dys*sub_pos/100 - spu->scaled_height/2;
1182 if (sub_pos >= 50 && spu->scaled_start_row + spu->scaled_height > dys)
1183 spu->scaled_start_row = dys - spu->scaled_height;
1184 break;
1185 case 2:
1186 spu->scaled_start_row = dys*sub_pos/100 - spu->scaled_height;
1187 break;
1189 draw_alpha(ctx, spu->scaled_start_col, spu->scaled_start_row, spu->scaled_width, spu->scaled_height,
1190 spu->scaled_image, spu->scaled_aimage, spu->scaled_stride);
1191 spu->spu_changed = 0;
1195 else
1197 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPU not displayed: start_pts=%d end_pts=%d now_pts=%d\n",
1198 spu->start_pts, spu->end_pts, spu->now_pts);
1202 void spudec_set_font_factor(void * this, double factor)
1204 spudec_handle_t *spu = this;
1205 spu->font_start_level = (int)(0xF0-(0xE0*factor));
1208 static void spudec_parse_extradata(spudec_handle_t *this,
1209 uint8_t *extradata, int extradata_len)
1211 uint8_t *buffer, *ptr;
1212 unsigned int *pal = this->global_palette, *cuspal = this->cuspal;
1213 unsigned int tridx;
1214 int i;
1216 if (extradata_len == 16*4) {
1217 for (i=0; i<16; i++)
1218 pal[i] = AV_RB32(extradata + i*4);
1219 this->auto_palette = 0;
1220 return;
1223 if (!(ptr = buffer = malloc(extradata_len+1)))
1224 return;
1225 memcpy(buffer, extradata, extradata_len);
1226 buffer[extradata_len] = 0;
1228 do {
1229 if (*ptr == '#')
1230 continue;
1231 if (!strncmp(ptr, "size: ", 6))
1232 sscanf(ptr + 6, "%dx%d", &this->orig_frame_width, &this->orig_frame_height);
1233 if (!strncmp(ptr, "palette: ", 9) &&
1234 sscanf(ptr + 9, "%x, %x, %x, %x, %x, %x, %x, %x, "
1235 "%x, %x, %x, %x, %x, %x, %x, %x",
1236 &pal[ 0], &pal[ 1], &pal[ 2], &pal[ 3],
1237 &pal[ 4], &pal[ 5], &pal[ 6], &pal[ 7],
1238 &pal[ 8], &pal[ 9], &pal[10], &pal[11],
1239 &pal[12], &pal[13], &pal[14], &pal[15]) == 16) {
1240 for (i=0; i<16; i++)
1241 pal[i] = vobsub_palette_to_yuv(pal[i]);
1242 this->auto_palette = 0;
1244 if (!strncasecmp(ptr, "forced subs: on", 15))
1245 this->forced_subs_only = 1;
1246 if (!strncmp(ptr, "custom colors: ON, tridx: ", 26) &&
1247 sscanf(ptr + 26, "%x, colors: %x, %x, %x, %x",
1248 &tridx, cuspal+0, cuspal+1, cuspal+2, cuspal+3) == 5) {
1249 for (i=0; i<4; i++) {
1250 cuspal[i] = vobsub_rgb_to_yuv(cuspal[i]);
1251 if (tridx & (1 << (12-4*i)))
1252 cuspal[i] |= 1 << 31;
1254 this->custom = 1;
1256 } while ((ptr=strchr(ptr,'\n')) && *++ptr);
1258 free(buffer);
1261 void *spudec_new_scaled(unsigned int *palette, unsigned int frame_width, unsigned int frame_height, uint8_t *extradata, int extradata_len)
1263 spudec_handle_t *this = calloc(1, sizeof(spudec_handle_t));
1264 if (this){
1265 this->orig_frame_height = frame_height;
1266 this->orig_frame_width = frame_width;
1267 // set up palette:
1268 if (palette)
1269 memcpy(this->global_palette, palette, sizeof(this->global_palette));
1270 else
1271 this->auto_palette = 1;
1272 if (extradata)
1273 spudec_parse_extradata(this, extradata, extradata_len);
1274 /* XXX Although the video frame is some size, the SPU frame is
1275 always maximum size i.e. 720 wide and 576 or 480 high */
1276 // For HD files in MKV the VobSub resolution can be higher though,
1277 // see largeres_vobsub.mkv
1278 if (this->orig_frame_width <= 720 && this->orig_frame_height <= 576) {
1279 this->orig_frame_width = 720;
1280 if (this->orig_frame_height == 480 || this->orig_frame_height == 240)
1281 this->orig_frame_height = 480;
1282 else
1283 this->orig_frame_height = 576;
1286 else
1287 mp_msg(MSGT_SPUDEC,MSGL_FATAL, "FATAL: spudec_init: calloc");
1288 return this;
1291 void *spudec_new(unsigned int *palette)
1293 return spudec_new_scaled(palette, 0, 0, NULL, 0);
1296 void spudec_free(void *this)
1298 spudec_handle_t *spu = this;
1299 if (spu) {
1300 while (spu->queue_head)
1301 spudec_free_packet(spudec_dequeue_packet(spu));
1302 free(spu->packet);
1303 spu->packet = NULL;
1304 free(spu->scaled_image);
1305 spu->scaled_image = NULL;
1306 free(spu->image);
1307 spu->image = NULL;
1308 spu->aimage = NULL;
1309 free(spu->pal_image);
1310 spu->pal_image = NULL;
1311 spu->image_size = 0;
1312 spu->pal_width = spu->pal_height = 0;
1313 free(spu);
1318 * palette must contain at least 256 32-bit entries, otherwise crashes
1319 * are possible
1321 void spudec_set_paletted(void *this, const uint8_t *pal_img, int pal_stride,
1322 const void *palette,
1323 int x, int y, int w, int h,
1324 double pts, double endpts)
1326 int i;
1327 uint16_t g8a8_pal[256];
1328 packet_t *packet;
1329 const uint32_t *pal = palette;
1330 spudec_handle_t *spu = this;
1331 uint8_t *img;
1332 uint8_t *aimg;
1333 int stride = (w + 7) & ~7;
1334 if ((unsigned)w >= 0x8000 || (unsigned)h > 0x4000)
1335 return;
1336 packet = calloc(1, sizeof(packet_t));
1337 packet->is_decoded = 1;
1338 packet->width = w;
1339 packet->height = h;
1340 packet->stride = stride;
1341 packet->start_col = x;
1342 packet->start_row = y;
1343 packet->data_len = 2 * stride * h;
1344 if (packet->data_len) { // size 0 is a special "clear" packet
1345 packet->packet = malloc(packet->data_len);
1346 img = packet->packet;
1347 aimg = packet->packet + stride * h;
1348 for (i = 0; i < 256; i++) {
1349 uint32_t pixel = pal[i];
1350 int alpha = pixel >> 24;
1351 int gray = (((pixel & 0x000000ff) >> 0) +
1352 ((pixel & 0x0000ff00) >> 7) +
1353 ((pixel & 0x00ff0000) >> 16)) >> 2;
1354 gray = FFMIN(gray, alpha);
1355 g8a8_pal[i] = (-alpha << 8) | gray;
1357 pal2gray_alpha(g8a8_pal, pal_img, pal_stride,
1358 img, aimg, stride, w, h);
1360 packet->start_pts = 0;
1361 packet->end_pts = 0x7fffffff;
1362 if (pts != MP_NOPTS_VALUE)
1363 packet->start_pts = pts * 90000;
1364 if (endpts != MP_NOPTS_VALUE)
1365 packet->end_pts = endpts * 90000;
1366 spudec_queue_packet(spu, packet);