configure: --enable-debug: don't change other compiler flags
[mplayer.git] / sub / spudec.c
bloba871aa3cd99245a9020c6741f84b3b38b45504f4
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/avutil.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 struct vo *hw_spu;
123 int spu_changed;
124 unsigned int forced_subs_only; /* flag: 0=display all subtitle, !0 display only forced subtitles */
125 unsigned int is_forced_sub; /* true if current subtitle is a forced subtitle */
127 struct palette_crop_cache palette_crop_cache;
128 } spudec_handle_t;
130 static void spudec_queue_packet(spudec_handle_t *this, packet_t *packet)
132 if (this->queue_head == NULL)
133 this->queue_head = packet;
134 else
135 this->queue_tail->next = packet;
136 this->queue_tail = packet;
139 static packet_t *spudec_dequeue_packet(spudec_handle_t *this)
141 packet_t *retval = this->queue_head;
143 this->queue_head = retval->next;
144 if (this->queue_head == NULL)
145 this->queue_tail = NULL;
147 return retval;
150 static void spudec_free_packet(packet_t *packet)
152 free(packet->packet);
153 free(packet);
156 static inline unsigned int get_be16(const unsigned char *p)
158 return (p[0] << 8) + p[1];
161 static inline unsigned int get_be24(const unsigned char *p)
163 return (get_be16(p) << 8) + p[2];
166 static void next_line(packet_t *packet)
168 if (packet->current_nibble[packet->deinterlace_oddness] % 2)
169 packet->current_nibble[packet->deinterlace_oddness]++;
170 packet->deinterlace_oddness = (packet->deinterlace_oddness + 1) % 2;
173 static inline unsigned char get_nibble(packet_t *packet)
175 unsigned char nib;
176 unsigned int *nibblep = packet->current_nibble + packet->deinterlace_oddness;
177 if (*nibblep / 2 >= packet->control_start) {
178 mp_msg(MSGT_SPUDEC,MSGL_WARN, "SPUdec: ERROR: get_nibble past end of packet\n");
179 return 0;
181 nib = packet->packet[*nibblep / 2];
182 if (*nibblep % 2)
183 nib &= 0xf;
184 else
185 nib >>= 4;
186 ++*nibblep;
187 return nib;
190 /* Cut the sub to visible part */
191 static inline void spudec_cut_image(spudec_handle_t *this)
193 unsigned int fy, ly;
194 unsigned int first_y, last_y;
196 if (this->stride == 0 || this->height == 0) {
197 return;
200 for (fy = 0; fy < this->image_size && !this->aimage[fy]; fy++);
201 for (ly = this->stride * this->height-1; ly && !this->aimage[ly]; ly--);
202 first_y = fy / this->stride;
203 last_y = ly / this->stride;
204 //printf("first_y: %d, last_y: %d\n", first_y, last_y);
205 this->start_row += first_y;
207 // Some subtitles trigger this condition
208 if (last_y + 1 > first_y ) {
209 this->height = last_y - first_y +1;
210 } else {
211 this->height = 0;
212 return;
215 // printf("new h %d new start %d (sz %d st %d)---\n\n", this->height, this->start_row, this->image_size, this->stride);
217 if (first_y > 0) {
218 memmove(this->image, this->image + this->stride * first_y, this->stride * this->height);
219 memmove(this->aimage, this->aimage + this->stride * first_y, this->stride * this->height);
224 static int spudec_alloc_image(spudec_handle_t *this, int stride, int height)
226 if (this->width > stride) // just a safeguard
227 this->width = stride;
228 this->stride = stride;
229 this->height = height;
230 if (this->image_size < this->stride * this->height) {
231 if (this->image != NULL) {
232 free(this->image);
233 free(this->pal_image);
234 this->image_size = 0;
235 this->pal_width = this->pal_height = 0;
237 this->image = malloc(2 * this->stride * this->height);
238 if (this->image) {
239 this->image_size = this->stride * this->height;
240 this->aimage = this->image + this->image_size;
241 // use stride here as well to simplify reallocation checks
242 this->pal_image = malloc(this->stride * this->height);
245 return this->image != NULL;
249 * \param pal palette in MPlayer-style gray-alpha values, i.e.
250 * alpha == 0 means transparent, 1 fully opaque,
251 * gray value <= 256 - alpha.
253 static void pal2gray_alpha(const uint16_t *pal,
254 const uint8_t *src, int src_stride,
255 uint8_t *dst, uint8_t *dsta,
256 int dst_stride, int w, int h)
258 int x, y;
259 for (y = 0; y < h; y++) {
260 for (x = 0; x < w; x++) {
261 uint16_t pixel = pal[src[x]];
262 *dst++ = pixel;
263 *dsta++ = pixel >> 8;
265 for (; x < dst_stride; x++)
266 *dsta++ = *dst++ = 0;
267 src += src_stride;
271 static int apply_palette_crop(spudec_handle_t *this,
272 unsigned crop_x, unsigned crop_y,
273 unsigned crop_w, unsigned crop_h)
275 int i;
276 uint8_t *src;
277 uint16_t pal[4];
278 unsigned stride = (crop_w + 7) & ~7;
279 if (crop_x > this->pal_width || crop_y > this->pal_height ||
280 crop_w > this->pal_width - crop_x || crop_h > this->pal_width - crop_y ||
281 crop_w > 0x8000 || crop_h > 0x8000 ||
282 stride * crop_h > this->image_size) {
283 return 0;
285 for (i = 0; i < 4; ++i) {
286 int color;
287 int alpha = this->alpha[i];
288 // extend 4 -> 8 bit
289 alpha |= alpha << 4;
290 if (this->custom && (this->cuspal[i] >> 31) != 0)
291 alpha = 0;
292 color = this->custom ? this->cuspal[i] :
293 this->global_palette[this->palette[i]];
294 color = (color >> 16) & 0xff;
295 // convert to MPlayer-style gray/alpha palette
296 color = FFMIN(color, alpha);
297 pal[i] = (-alpha << 8) | color;
299 src = this->pal_image + crop_y * this->pal_width + crop_x;
300 pal2gray_alpha(pal, src, this->pal_width,
301 this->image, this->aimage, stride,
302 crop_w, crop_h);
303 this->width = crop_w;
304 this->height = crop_h;
305 this->stride = stride;
306 this->start_col = this->pal_start_col + crop_x;
307 this->start_row = this->pal_start_row + crop_y;
308 spudec_cut_image(this);
310 // reset scaled image
311 this->scaled_frame_width = 0;
312 this->scaled_frame_height = 0;
313 this->palette_crop_cache.valid = 0;
314 return 1;
317 int spudec_apply_palette_crop(void *this, uint32_t palette,
318 int sx, int sy, int ex, int ey)
320 spudec_handle_t *spu = this;
321 struct palette_crop_cache *c = &spu->palette_crop_cache;
322 if (c->valid && c->palette == palette &&
323 c->sx == sx && c->sy == sy && c->ex == ex && c->ey == ey)
324 return c->result;
325 spu->palette[0] = (palette >> 28) & 0xf;
326 spu->palette[1] = (palette >> 24) & 0xf;
327 spu->palette[2] = (palette >> 20) & 0xf;
328 spu->palette[3] = (palette >> 16) & 0xf;
329 spu->alpha[0] = (palette >> 12) & 0xf;
330 spu->alpha[1] = (palette >> 8) & 0xf;
331 spu->alpha[2] = (palette >> 4) & 0xf;
332 spu->alpha[3] = palette & 0xf;
333 spu->spu_changed = 1;
334 c->result = apply_palette_crop(spu,
335 sx - spu->pal_start_col, sy - spu->pal_start_row,
336 ex - sx, ey - sy);
337 c->palette = palette;
338 c->sx = sx; c->sy = sy;
339 c->ex = ex; c->ey = ey;
340 c->valid = 1;
341 return c->result;
344 static void spudec_process_data(spudec_handle_t *this, packet_t *packet)
346 unsigned int i, x, y;
347 uint8_t *dst;
349 if (!spudec_alloc_image(this, packet->stride, packet->height))
350 return;
352 this->pal_start_col = packet->start_col;
353 this->pal_start_row = packet->start_row;
354 this->pal_height = packet->height;
355 this->pal_width = packet->width;
356 this->stride = packet->stride;
357 memcpy(this->palette, packet->palette, sizeof(this->palette));
358 memcpy(this->alpha, packet->alpha, sizeof(this->alpha));
360 i = packet->current_nibble[1];
361 x = 0;
362 y = 0;
363 dst = this->pal_image;
364 while (packet->current_nibble[0] < i
365 && packet->current_nibble[1] / 2 < packet->control_start
366 && y < this->pal_height) {
367 unsigned int len, color;
368 unsigned int rle = 0;
369 rle = get_nibble(packet);
370 if (rle < 0x04) {
371 if (rle == 0) {
372 rle = (rle << 4) | get_nibble(packet);
373 if (rle < 0x04)
374 rle = (rle << 4) | get_nibble(packet);
376 rle = (rle << 4) | get_nibble(packet);
378 color = 3 - (rle & 0x3);
379 len = rle >> 2;
380 x += len;
381 if (len == 0 || x >= this->pal_width) {
382 len += this->pal_width - x;
383 next_line(packet);
384 x = 0;
385 ++y;
387 memset(dst, color, len);
388 dst += len;
390 apply_palette_crop(this, 0, 0, this->pal_width, this->pal_height);
395 This function tries to create a usable palette.
396 It determines how many non-transparent colors are used, and assigns different
397 gray scale values to each color.
398 I tested it with four streams and even got something readable. Half of the
399 times I got black characters with white around and half the reverse.
401 static void compute_palette(spudec_handle_t *this, packet_t *packet)
403 int used[16],i,cused,start,step,color;
405 memset(used, 0, sizeof(used));
406 for (i=0; i<4; i++)
407 if (packet->alpha[i]) /* !Transparent? */
408 used[packet->palette[i]] = 1;
409 for (cused=0, i=0; i<16; i++)
410 if (used[i]) cused++;
411 if (!cused) return;
412 if (cused == 1) {
413 start = 0x80;
414 step = 0;
415 } else {
416 start = this->font_start_level;
417 step = (0xF0-this->font_start_level)/(cused-1);
419 memset(used, 0, sizeof(used));
420 for (i=0; i<4; i++) {
421 color = packet->palette[i];
422 if (packet->alpha[i] && !used[color]) { /* not assigned? */
423 used[color] = 1;
424 this->global_palette[color] = start<<16;
425 start += step;
430 static void spudec_process_control(spudec_handle_t *this, int pts100)
432 int a,b,c,d; /* Temporary vars */
433 unsigned int date, type;
434 unsigned int off;
435 unsigned int start_off = 0;
436 unsigned int next_off;
437 unsigned int start_pts = 0;
438 unsigned int end_pts = 0;
439 unsigned int current_nibble[2] = {0, 0};
440 unsigned int control_start;
441 unsigned int display = 0;
442 unsigned int start_col = 0;
443 unsigned int end_col = 0;
444 unsigned int start_row = 0;
445 unsigned int end_row = 0;
446 unsigned int width = 0;
447 unsigned int height = 0;
448 unsigned int stride = 0;
450 control_start = get_be16(this->packet + 2);
451 next_off = control_start;
452 while (start_off != next_off) {
453 start_off = next_off;
454 date = get_be16(this->packet + start_off) * 1024;
455 next_off = get_be16(this->packet + start_off + 2);
456 mp_msg(MSGT_SPUDEC,MSGL_DBG2, "date=%d\n", date);
457 off = start_off + 4;
458 for (type = this->packet[off++]; type != 0xff; type = this->packet[off++]) {
459 mp_msg(MSGT_SPUDEC,MSGL_DBG2, "cmd=%d ",type);
460 switch(type) {
461 case 0x00:
462 /* Menu ID, 1 byte */
463 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Menu ID\n");
464 /* shouldn't a Menu ID type force display start? */
465 start_pts = pts100 < 0 && -pts100 >= date ? 0 : pts100 + date;
466 end_pts = UINT_MAX;
467 display = 1;
468 this->is_forced_sub=~0; // current subtitle is forced
469 break;
470 case 0x01:
471 /* Start display */
472 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Start display!\n");
473 start_pts = pts100 < 0 && -pts100 >= date ? 0 : pts100 + date;
474 end_pts = UINT_MAX;
475 display = 1;
476 this->is_forced_sub=0;
477 break;
478 case 0x02:
479 /* Stop display */
480 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Stop display!\n");
481 end_pts = pts100 < 0 && -pts100 >= date ? 0 : pts100 + date;
482 break;
483 case 0x03:
484 /* Palette */
485 this->palette[0] = this->packet[off] >> 4;
486 this->palette[1] = this->packet[off] & 0xf;
487 this->palette[2] = this->packet[off + 1] >> 4;
488 this->palette[3] = this->packet[off + 1] & 0xf;
489 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Palette %d, %d, %d, %d\n",
490 this->palette[0], this->palette[1], this->palette[2], this->palette[3]);
491 off+=2;
492 break;
493 case 0x04:
494 /* Alpha */
495 a = this->packet[off] >> 4;
496 b = this->packet[off] & 0xf;
497 c = this->packet[off + 1] >> 4;
498 d = this->packet[off + 1] & 0xf;
499 // Note: some DVDs change these values to create a fade-in/fade-out effect
500 // We can not handle this, so just keep the highest value during the display time.
501 if (display) {
502 a = FFMAX(a, this->alpha[0]);
503 b = FFMAX(b, this->alpha[1]);
504 c = FFMAX(c, this->alpha[2]);
505 d = FFMAX(d, this->alpha[3]);
507 this->alpha[0] = a;
508 this->alpha[1] = b;
509 this->alpha[2] = c;
510 this->alpha[3] = d;
511 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Alpha %d, %d, %d, %d\n",
512 this->alpha[0], this->alpha[1], this->alpha[2], this->alpha[3]);
513 off+=2;
514 break;
515 case 0x05:
516 /* Co-ords */
517 a = get_be24(this->packet + off);
518 b = get_be24(this->packet + off + 3);
519 start_col = a >> 12;
520 end_col = a & 0xfff;
521 width = (end_col < start_col) ? 0 : end_col - start_col + 1;
522 stride = (width + 7) & ~7; /* Kludge: draw_alpha needs width multiple of 8 */
523 start_row = b >> 12;
524 end_row = b & 0xfff;
525 height = (end_row < start_row) ? 0 : end_row - start_row /* + 1 */;
526 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Coords col: %d - %d row: %d - %d (%dx%d)\n",
527 start_col, end_col, start_row, end_row,
528 width, height);
529 off+=6;
530 break;
531 case 0x06:
532 /* Graphic lines */
533 current_nibble[0] = 2 * get_be16(this->packet + off);
534 current_nibble[1] = 2 * get_be16(this->packet + off + 2);
535 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Graphic offset 1: %d offset 2: %d\n",
536 current_nibble[0] / 2, current_nibble[1] / 2);
537 off+=4;
538 break;
539 case 0xff:
540 /* All done, bye-bye */
541 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Done!\n");
542 return;
543 // break;
544 default:
545 mp_msg(MSGT_SPUDEC,MSGL_WARN,"spudec: Error determining control type 0x%02x. Skipping %d bytes.\n",
546 type, next_off - off);
547 goto next_control;
550 next_control:
551 if (!display)
552 continue;
553 if (end_pts == UINT_MAX && start_off != next_off) {
554 end_pts = get_be16(this->packet + next_off) * 1024;
555 end_pts = 1 - pts100 >= end_pts ? 0 : pts100 + end_pts - 1;
557 if (end_pts > 0) {
558 packet_t *packet = calloc(1, sizeof(packet_t));
559 int i;
560 packet->start_pts = start_pts;
561 packet->end_pts = end_pts;
562 packet->current_nibble[0] = current_nibble[0];
563 packet->current_nibble[1] = current_nibble[1];
564 packet->start_row = start_row;
565 packet->start_col = start_col;
566 packet->width = width;
567 packet->height = height;
568 packet->stride = stride;
569 packet->control_start = control_start;
570 for (i=0; i<4; i++) {
571 packet->alpha[i] = this->alpha[i];
572 packet->palette[i] = this->palette[i];
574 packet->packet = malloc(this->packet_size);
575 memcpy(packet->packet, this->packet, this->packet_size);
576 spudec_queue_packet(this, packet);
581 static void spudec_decode(spudec_handle_t *this, int pts100)
583 if (!this->hw_spu)
584 spudec_process_control(this, pts100);
585 else if (pts100 >= 0) {
586 static vo_mpegpes_t packet = { NULL, 0, 0x20, 0 };
587 static vo_mpegpes_t *pkg=&packet;
588 packet.data = this->packet;
589 packet.size = this->packet_size;
590 packet.timestamp = pts100;
591 vo_draw_frame(this->hw_spu, (uint8_t**)&pkg);
595 int spudec_changed(void * this)
597 spudec_handle_t * spu = this;
598 return spu->spu_changed || spu->now_pts > spu->end_pts;
601 void spudec_assemble(void *this, unsigned char *packet, unsigned int len, int pts100)
603 spudec_handle_t *spu = this;
604 // spudec_heartbeat(this, pts100);
605 if (len < 2) {
606 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: packet too short\n");
607 return;
609 spu->packet_pts = pts100;
610 if (spu->packet_offset == 0) {
611 unsigned int len2 = get_be16(packet);
612 // Start new fragment
613 if (spu->packet_reserve < len2) {
614 free(spu->packet);
615 spu->packet = malloc(len2);
616 spu->packet_reserve = spu->packet != NULL ? len2 : 0;
618 if (spu->packet != NULL) {
619 spu->packet_size = len2;
620 if (len > len2) {
621 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: invalid frag len / len2: %d / %d \n", len, len2);
622 return;
624 memcpy(spu->packet, packet, len);
625 spu->packet_offset = len;
626 spu->packet_pts = pts100;
628 } else {
629 // Continue current fragment
630 if (spu->packet_size < spu->packet_offset + len){
631 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: invalid fragment\n");
632 spu->packet_size = spu->packet_offset = 0;
633 return;
634 } else {
635 memcpy(spu->packet + spu->packet_offset, packet, len);
636 spu->packet_offset += len;
639 #if 1
640 // check if we have a complete packet (unfortunatelly packet_size is bad
641 // for some disks)
642 // [cb] packet_size is padded to be even -> may be one byte too long
643 if ((spu->packet_offset == spu->packet_size) ||
644 ((spu->packet_offset + 1) == spu->packet_size)){
645 unsigned int x=0,y;
646 while(x+4<=spu->packet_offset){
647 y=get_be16(spu->packet+x+2); // next control pointer
648 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPUtest: x=%d y=%d off=%d size=%d\n",x,y,spu->packet_offset,spu->packet_size);
649 if(x>=4 && x==y){ // if it points to self - we're done!
650 // we got it!
651 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPUgot: off=%d size=%d \n",spu->packet_offset,spu->packet_size);
652 spudec_decode(spu, pts100);
653 spu->packet_offset = 0;
654 break;
656 if(y<=x || y>=spu->packet_size){ // invalid?
657 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUtest: broken packet!!!!! y=%d < x=%d\n",y,x);
658 spu->packet_size = spu->packet_offset = 0;
659 break;
661 x=y;
663 // [cb] packet is done; start new packet
664 spu->packet_offset = 0;
666 #else
667 if (spu->packet_offset == spu->packet_size) {
668 spudec_decode(spu, pts100);
669 spu->packet_offset = 0;
671 #endif
674 void spudec_reset(void *this) // called after seek
676 spudec_handle_t *spu = this;
677 while (spu->queue_head)
678 spudec_free_packet(spudec_dequeue_packet(spu));
679 spu->now_pts = 0;
680 spu->end_pts = 0;
681 spu->packet_size = spu->packet_offset = 0;
684 void spudec_heartbeat(void *this, unsigned int pts100)
686 spudec_handle_t *spu = this;
687 spu->now_pts = pts100;
689 // TODO: detect and handle broken timestamps (e.g. due to wrapping)
690 while (spu->queue_head != NULL && pts100 >= spu->queue_head->start_pts) {
691 packet_t *packet = spudec_dequeue_packet(spu);
692 spu->start_pts = packet->start_pts;
693 spu->end_pts = packet->end_pts;
694 if (packet->is_decoded) {
695 free(spu->image);
696 spu->image_size = packet->data_len;
697 spu->image = packet->packet;
698 spu->aimage = packet->packet + packet->stride * packet->height;
699 packet->packet = NULL;
700 spu->width = packet->width;
701 spu->height = packet->height;
702 spu->stride = packet->stride;
703 spu->start_col = packet->start_col;
704 spu->start_row = packet->start_row;
706 // reset scaled image
707 spu->scaled_frame_width = 0;
708 spu->scaled_frame_height = 0;
709 } else {
710 if (spu->auto_palette)
711 compute_palette(spu, packet);
712 spudec_process_data(spu, packet);
714 spudec_free_packet(packet);
715 spu->spu_changed = 1;
719 int spudec_visible(void *this){
720 spudec_handle_t *spu = this;
721 int ret=(spu->start_pts <= spu->now_pts &&
722 spu->now_pts < spu->end_pts &&
723 spu->height > 0);
724 // printf("spu visible: %d \n",ret);
725 return ret;
728 void spudec_set_forced_subs_only(void * const this, const unsigned int flag)
730 if(this){
731 ((spudec_handle_t *)this)->forced_subs_only=flag;
732 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPU: Display only forced subs now %s\n", flag ? "enabled": "disabled");
736 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)
738 spudec_handle_t *spu = this;
739 if (spudec_visible(spu))
741 draw_alpha(ctx, spu->start_col, spu->start_row, spu->width, spu->height,
742 spu->image, spu->aimage, spu->stride);
743 spu->spu_changed = 0;
747 /* calc the bbox for spudec subs */
748 void spudec_calc_bbox(void *me, unsigned int dxs, unsigned int dys, unsigned int* bbox)
750 spudec_handle_t *spu = me;
751 if (spu->orig_frame_width == 0 || spu->orig_frame_height == 0
752 || (spu->orig_frame_width == dxs && spu->orig_frame_height == dys)) {
753 // unscaled
754 bbox[0] = spu->start_col;
755 bbox[1] = spu->start_col + spu->width;
756 bbox[2] = spu->start_row;
757 bbox[3] = spu->start_row + spu->height;
759 else {
760 // scaled
761 unsigned int scalex = 0x100 * dxs / spu->orig_frame_width;
762 unsigned int scaley = 0x100 * dys / spu->orig_frame_height;
763 bbox[0] = spu->start_col * scalex / 0x100;
764 bbox[1] = spu->start_col * scalex / 0x100 + spu->width * scalex / 0x100;
765 switch (spu_alignment) {
766 case 0:
767 bbox[3] = dys*sub_pos/100 + spu->height * scaley / 0x100;
768 if (bbox[3] > dys) bbox[3] = dys;
769 bbox[2] = bbox[3] - spu->height * scaley / 0x100;
770 break;
771 case 1:
772 if (sub_pos < 50) {
773 bbox[2] = dys*sub_pos/100 - spu->height * scaley / 0x200;
774 bbox[3] = bbox[2] + spu->height;
775 } else {
776 bbox[3] = dys*sub_pos/100 + spu->height * scaley / 0x200;
777 if (bbox[3] > dys) bbox[3] = dys;
778 bbox[2] = bbox[3] - spu->height * scaley / 0x100;
780 break;
781 case 2:
782 bbox[2] = dys*sub_pos/100 - spu->height * scaley / 0x100;
783 bbox[3] = bbox[2] + spu->height;
784 break;
785 default: /* -1 */
786 bbox[2] = spu->start_row * scaley / 0x100;
787 bbox[3] = spu->start_row * scaley / 0x100 + spu->height * scaley / 0x100;
788 break;
792 /* transform mplayer's alpha value into an opacity value that is linear */
793 static inline int canon_alpha(int alpha)
795 return (uint8_t)-alpha;
798 typedef struct {
799 unsigned position;
800 unsigned left_up;
801 unsigned right_down;
802 }scale_pixel;
805 static void scale_table(unsigned int start_src, unsigned int start_tar, unsigned int end_src, unsigned int end_tar, scale_pixel * table)
807 unsigned int t;
808 unsigned int delta_src = end_src - start_src;
809 unsigned int delta_tar = end_tar - start_tar;
810 int src = 0;
811 int src_step;
812 if (delta_src == 0 || delta_tar == 0) {
813 return;
815 src_step = (delta_src << 16) / delta_tar >>1;
816 for (t = 0; t<=delta_tar; src += (src_step << 1), t++){
817 table[t].position= FFMIN(src >> 16, end_src - 1);
818 table[t].right_down = src & 0xffff;
819 table[t].left_up = 0x10000 - table[t].right_down;
823 /* bilinear scale, similar to vobsub's code */
824 static void scale_image(int x, int y, scale_pixel* table_x, scale_pixel* table_y, spudec_handle_t * spu)
826 int alpha[4];
827 int color[4];
828 unsigned int scale[4];
829 int base = table_y[y].position * spu->stride + table_x[x].position;
830 int scaled = y * spu->scaled_stride + x;
831 alpha[0] = canon_alpha(spu->aimage[base]);
832 alpha[1] = canon_alpha(spu->aimage[base + 1]);
833 alpha[2] = canon_alpha(spu->aimage[base + spu->stride]);
834 alpha[3] = canon_alpha(spu->aimage[base + spu->stride + 1]);
835 color[0] = spu->image[base];
836 color[1] = spu->image[base + 1];
837 color[2] = spu->image[base + spu->stride];
838 color[3] = spu->image[base + spu->stride + 1];
839 scale[0] = (table_x[x].left_up * table_y[y].left_up >> 16) * alpha[0];
840 if (table_y[y].left_up == 0x10000) // necessary to avoid overflow-case
841 scale[0] = table_x[x].left_up * alpha[0];
842 scale[1] = (table_x[x].right_down * table_y[y].left_up >>16) * alpha[1];
843 scale[2] = (table_x[x].left_up * table_y[y].right_down >> 16) * alpha[2];
844 scale[3] = (table_x[x].right_down * table_y[y].right_down >> 16) * alpha[3];
845 spu->scaled_image[scaled] = (color[0] * scale[0] + color[1] * scale[1] + color[2] * scale[2] + color[3] * scale[3])>>24;
846 spu->scaled_aimage[scaled] = (scale[0] + scale[1] + scale[2] + scale[3]) >> 16;
847 if (spu->scaled_aimage[scaled]){
848 // ensure that MPlayer's simplified alpha-blending can not overflow
849 spu->scaled_image[scaled] = FFMIN(spu->scaled_image[scaled], spu->scaled_aimage[scaled]);
850 // convert to MPlayer-style alpha
851 spu->scaled_aimage[scaled] = -spu->scaled_aimage[scaled];
855 static void sws_spu_image(unsigned char *d1, unsigned char *d2, int dw, int dh,
856 int ds, const unsigned char* s1, unsigned char* s2,
857 int sw, int sh, int ss)
859 struct SwsContext *ctx;
860 static SwsFilter filter;
861 static int firsttime = 1;
862 static float oldvar;
863 int i;
865 if (!firsttime && oldvar != spu_gaussvar) sws_freeVec(filter.lumH);
866 if (firsttime) {
867 filter.lumH = filter.lumV =
868 filter.chrH = filter.chrV = sws_getGaussianVec(spu_gaussvar, 3.0);
869 sws_normalizeVec(filter.lumH, 1.0);
870 firsttime = 0;
871 oldvar = spu_gaussvar;
874 ctx=sws_getContext(sw, sh, PIX_FMT_GRAY8, dw, dh, PIX_FMT_GRAY8, SWS_GAUSS, &filter, NULL, NULL);
875 sws_scale(ctx,&s1,&ss,0,sh,&d1,&ds);
876 for (i=ss*sh-1; i>=0; i--) if (!s2[i]) s2[i] = 255; //else s2[i] = 1;
877 sws_scale(ctx,(const uint8_t **)&s2,&ss,0,sh,&d2,&ds);
878 for (i=ds*dh-1; i>=0; i--) if (d2[i]==0) d2[i] = 1; else if (d2[i]==255) d2[i] = 0;
879 sws_freeContext(ctx);
882 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)
884 spudec_handle_t *spu = me;
885 scale_pixel *table_x;
886 scale_pixel *table_y;
888 if (spudec_visible(spu)) {
890 // check if only forced subtitles are requested
891 if( (spu->forced_subs_only) && !(spu->is_forced_sub) ){
892 return;
895 if (!(spu_aamode&16) && (spu->orig_frame_width == 0 || spu->orig_frame_height == 0
896 || (spu->orig_frame_width == dxs && spu->orig_frame_height == dys))) {
897 spudec_draw(spu, draw_alpha, ctx);
899 else {
900 if (spu->scaled_frame_width != dxs || spu->scaled_frame_height != dys) { /* Resizing is needed */
901 /* scaled_x = scalex * x / 0x100
902 scaled_y = scaley * y / 0x100
903 order of operations is important because of rounding. */
904 unsigned int scalex = 0x100 * dxs / spu->orig_frame_width;
905 unsigned int scaley = 0x100 * dys / spu->orig_frame_height;
906 spu->scaled_start_col = spu->start_col * scalex / 0x100;
907 spu->scaled_start_row = spu->start_row * scaley / 0x100;
908 spu->scaled_width = spu->width * scalex / 0x100;
909 spu->scaled_height = spu->height * scaley / 0x100;
910 /* Kludge: draw_alpha needs width multiple of 8 */
911 spu->scaled_stride = (spu->scaled_width + 7) & ~7;
912 if (spu->scaled_image_size < spu->scaled_stride * spu->scaled_height) {
913 if (spu->scaled_image) {
914 free(spu->scaled_image);
915 spu->scaled_image_size = 0;
917 spu->scaled_image = malloc(2 * spu->scaled_stride * spu->scaled_height);
918 if (spu->scaled_image) {
919 spu->scaled_image_size = spu->scaled_stride * spu->scaled_height;
920 spu->scaled_aimage = spu->scaled_image + spu->scaled_image_size;
923 if (spu->scaled_image) {
924 unsigned int x, y;
925 // needs to be 0-initialized because draw_alpha draws always a
926 // multiple of 8 pixels. TODO: optimize
927 if (spu->scaled_width & 7)
928 memset(spu->scaled_image, 0, 2 * spu->scaled_image_size);
929 if (spu->scaled_width <= 1 || spu->scaled_height <= 1) {
930 goto nothing_to_do;
932 switch(spu_aamode&15) {
933 case 4:
934 sws_spu_image(spu->scaled_image, spu->scaled_aimage,
935 spu->scaled_width, spu->scaled_height, spu->scaled_stride,
936 spu->image, spu->aimage, spu->width, spu->height, spu->stride);
937 break;
938 case 3:
939 table_x = calloc(spu->scaled_width, sizeof(scale_pixel));
940 table_y = calloc(spu->scaled_height, sizeof(scale_pixel));
941 if (!table_x || !table_y) {
942 mp_msg(MSGT_SPUDEC, MSGL_FATAL, "Fatal: spudec_draw_scaled: calloc failed\n");
944 scale_table(0, 0, spu->width - 1, spu->scaled_width - 1, table_x);
945 scale_table(0, 0, spu->height - 1, spu->scaled_height - 1, table_y);
946 for (y = 0; y < spu->scaled_height; y++)
947 for (x = 0; x < spu->scaled_width; x++)
948 scale_image(x, y, table_x, table_y, spu);
949 free(table_x);
950 free(table_y);
951 break;
952 case 0:
953 /* no antialiasing */
954 for (y = 0; y < spu->scaled_height; ++y) {
955 int unscaled_y = y * 0x100 / scaley;
956 int strides = spu->stride * unscaled_y;
957 int scaled_strides = spu->scaled_stride * y;
958 for (x = 0; x < spu->scaled_width; ++x) {
959 int unscaled_x = x * 0x100 / scalex;
960 spu->scaled_image[scaled_strides + x] = spu->image[strides + unscaled_x];
961 spu->scaled_aimage[scaled_strides + x] = spu->aimage[strides + unscaled_x];
964 break;
965 case 1:
967 /* Intermediate antialiasing. */
968 for (y = 0; y < spu->scaled_height; ++y) {
969 const unsigned int unscaled_top = y * spu->orig_frame_height / dys;
970 unsigned int unscaled_bottom = (y + 1) * spu->orig_frame_height / dys;
971 if (unscaled_bottom >= spu->height)
972 unscaled_bottom = spu->height - 1;
973 for (x = 0; x < spu->scaled_width; ++x) {
974 const unsigned int unscaled_left = x * spu->orig_frame_width / dxs;
975 unsigned int unscaled_right = (x + 1) * spu->orig_frame_width / dxs;
976 unsigned int color = 0;
977 unsigned int alpha = 0;
978 unsigned int walkx, walky;
979 unsigned int base, tmp;
980 if (unscaled_right >= spu->width)
981 unscaled_right = spu->width - 1;
982 for (walky = unscaled_top; walky <= unscaled_bottom; ++walky)
983 for (walkx = unscaled_left; walkx <= unscaled_right; ++walkx) {
984 base = walky * spu->stride + walkx;
985 tmp = canon_alpha(spu->aimage[base]);
986 alpha += tmp;
987 color += tmp * spu->image[base];
989 base = y * spu->scaled_stride + x;
990 spu->scaled_image[base] = alpha ? color / alpha : 0;
991 spu->scaled_aimage[base] =
992 alpha * (1 + unscaled_bottom - unscaled_top) * (1 + unscaled_right - unscaled_left);
993 /* spu->scaled_aimage[base] =
994 alpha * dxs * dys / spu->orig_frame_width / spu->orig_frame_height; */
995 if (spu->scaled_aimage[base]) {
996 spu->scaled_aimage[base] = 256 - spu->scaled_aimage[base];
997 if (spu->scaled_aimage[base] + spu->scaled_image[base] > 255)
998 spu->scaled_image[base] = 256 - spu->scaled_aimage[base];
1003 break;
1004 case 2:
1006 /* Best antialiasing. Very slow. */
1007 /* Any pixel (x, y) represents pixels from the original
1008 rectangular region comprised between the columns
1009 unscaled_y and unscaled_y + 0x100 / scaley and the rows
1010 unscaled_x and unscaled_x + 0x100 / scalex
1012 The original rectangular region that the scaled pixel
1013 represents is cut in 9 rectangular areas like this:
1015 +---+-----------------+---+
1016 | 1 | 2 | 3 |
1017 +---+-----------------+---+
1018 | | | |
1019 | 4 | 5 | 6 |
1020 | | | |
1021 +---+-----------------+---+
1022 | 7 | 8 | 9 |
1023 +---+-----------------+---+
1025 The width of the left column is at most one pixel and
1026 it is never null and its right column is at a pixel
1027 boundary. The height of the top row is at most one
1028 pixel it is never null and its bottom row is at a
1029 pixel boundary. The width and height of region 5 are
1030 integral values. The width of the right column is
1031 what remains and is less than one pixel. The height
1032 of the bottom row is what remains and is less than
1033 one pixel.
1035 The row above 1, 2, 3 is unscaled_y. The row between
1036 1, 2, 3 and 4, 5, 6 is top_low_row. The row between 4,
1037 5, 6 and 7, 8, 9 is (unsigned int)unscaled_y_bottom.
1038 The row beneath 7, 8, 9 is unscaled_y_bottom.
1040 The column left of 1, 4, 7 is unscaled_x. The column
1041 between 1, 4, 7 and 2, 5, 8 is left_right_column. The
1042 column between 2, 5, 8 and 3, 6, 9 is (unsigned
1043 int)unscaled_x_right. The column right of 3, 6, 9 is
1044 unscaled_x_right. */
1045 const double inv_scalex = (double) 0x100 / scalex;
1046 const double inv_scaley = (double) 0x100 / scaley;
1047 for (y = 0; y < spu->scaled_height; ++y) {
1048 const double unscaled_y = y * inv_scaley;
1049 const double unscaled_y_bottom = unscaled_y + inv_scaley;
1050 const unsigned int top_low_row = FFMIN(unscaled_y_bottom, unscaled_y + 1.0);
1051 const double top = top_low_row - unscaled_y;
1052 const unsigned int height = unscaled_y_bottom > top_low_row
1053 ? (unsigned int) unscaled_y_bottom - top_low_row
1054 : 0;
1055 const double bottom = unscaled_y_bottom > top_low_row
1056 ? unscaled_y_bottom - floor(unscaled_y_bottom)
1057 : 0.0;
1058 for (x = 0; x < spu->scaled_width; ++x) {
1059 const double unscaled_x = x * inv_scalex;
1060 const double unscaled_x_right = unscaled_x + inv_scalex;
1061 const unsigned int left_right_column = FFMIN(unscaled_x_right, unscaled_x + 1.0);
1062 const double left = left_right_column - unscaled_x;
1063 const unsigned int width = unscaled_x_right > left_right_column
1064 ? (unsigned int) unscaled_x_right - left_right_column
1065 : 0;
1066 const double right = unscaled_x_right > left_right_column
1067 ? unscaled_x_right - floor(unscaled_x_right)
1068 : 0.0;
1069 double color = 0.0;
1070 double alpha = 0.0;
1071 double tmp;
1072 unsigned int base;
1073 /* Now use these informations to compute a good alpha,
1074 and lightness. The sum is on each of the 9
1075 region's surface and alpha and lightness.
1077 transformed alpha = sum(surface * alpha) / sum(surface)
1078 transformed color = sum(surface * alpha * color) / sum(surface * alpha)
1080 /* 1: top left part */
1081 base = spu->stride * (unsigned int) unscaled_y;
1082 tmp = left * top * canon_alpha(spu->aimage[base + (unsigned int) unscaled_x]);
1083 alpha += tmp;
1084 color += tmp * spu->image[base + (unsigned int) unscaled_x];
1085 /* 2: top center part */
1086 if (width > 0) {
1087 unsigned int walkx;
1088 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
1089 base = spu->stride * (unsigned int) unscaled_y + walkx;
1090 tmp = /* 1.0 * */ top * canon_alpha(spu->aimage[base]);
1091 alpha += tmp;
1092 color += tmp * spu->image[base];
1095 /* 3: top right part */
1096 if (right > 0.0) {
1097 base = spu->stride * (unsigned int) unscaled_y + (unsigned int) unscaled_x_right;
1098 tmp = right * top * canon_alpha(spu->aimage[base]);
1099 alpha += tmp;
1100 color += tmp * spu->image[base];
1102 /* 4: center left part */
1103 if (height > 0) {
1104 unsigned int walky;
1105 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1106 base = spu->stride * walky + (unsigned int) unscaled_x;
1107 tmp = left /* * 1.0 */ * canon_alpha(spu->aimage[base]);
1108 alpha += tmp;
1109 color += tmp * spu->image[base];
1112 /* 5: center part */
1113 if (width > 0 && height > 0) {
1114 unsigned int walky;
1115 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1116 unsigned int walkx;
1117 base = spu->stride * walky;
1118 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
1119 tmp = /* 1.0 * 1.0 * */ canon_alpha(spu->aimage[base + walkx]);
1120 alpha += tmp;
1121 color += tmp * spu->image[base + walkx];
1125 /* 6: center right part */
1126 if (right > 0.0 && height > 0) {
1127 unsigned int walky;
1128 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1129 base = spu->stride * walky + (unsigned int) unscaled_x_right;
1130 tmp = right /* * 1.0 */ * canon_alpha(spu->aimage[base]);
1131 alpha += tmp;
1132 color += tmp * spu->image[base];
1135 /* 7: bottom left part */
1136 if (bottom > 0.0) {
1137 base = spu->stride * (unsigned int) unscaled_y_bottom + (unsigned int) unscaled_x;
1138 tmp = left * bottom * canon_alpha(spu->aimage[base]);
1139 alpha += tmp;
1140 color += tmp * spu->image[base];
1142 /* 8: bottom center part */
1143 if (width > 0 && bottom > 0.0) {
1144 unsigned int walkx;
1145 base = spu->stride * (unsigned int) unscaled_y_bottom;
1146 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
1147 tmp = /* 1.0 * */ bottom * canon_alpha(spu->aimage[base + walkx]);
1148 alpha += tmp;
1149 color += tmp * spu->image[base + walkx];
1152 /* 9: bottom right part */
1153 if (right > 0.0 && bottom > 0.0) {
1154 base = spu->stride * (unsigned int) unscaled_y_bottom + (unsigned int) unscaled_x_right;
1155 tmp = right * bottom * canon_alpha(spu->aimage[base]);
1156 alpha += tmp;
1157 color += tmp * spu->image[base];
1159 /* Finally mix these transparency and brightness information suitably */
1160 base = spu->scaled_stride * y + x;
1161 spu->scaled_image[base] = alpha > 0 ? color / alpha : 0;
1162 spu->scaled_aimage[base] = alpha * scalex * scaley / 0x10000;
1163 if (spu->scaled_aimage[base]) {
1164 spu->scaled_aimage[base] = 256 - spu->scaled_aimage[base];
1165 if (spu->scaled_aimage[base] + spu->scaled_image[base] > 255)
1166 spu->scaled_image[base] = 256 - spu->scaled_aimage[base];
1172 nothing_to_do:
1173 /* Kludge: draw_alpha needs width multiple of 8. */
1174 if (spu->scaled_width < spu->scaled_stride)
1175 for (y = 0; y < spu->scaled_height; ++y) {
1176 memset(spu->scaled_aimage + y * spu->scaled_stride + spu->scaled_width, 0,
1177 spu->scaled_stride - spu->scaled_width);
1179 spu->scaled_frame_width = dxs;
1180 spu->scaled_frame_height = dys;
1183 if (spu->scaled_image){
1184 switch (spu_alignment) {
1185 case 0:
1186 spu->scaled_start_row = dys*sub_pos/100;
1187 if (spu->scaled_start_row + spu->scaled_height > dys)
1188 spu->scaled_start_row = dys - spu->scaled_height;
1189 break;
1190 case 1:
1191 spu->scaled_start_row = dys*sub_pos/100 - spu->scaled_height/2;
1192 if (sub_pos >= 50 && spu->scaled_start_row + spu->scaled_height > dys)
1193 spu->scaled_start_row = dys - spu->scaled_height;
1194 break;
1195 case 2:
1196 spu->scaled_start_row = dys*sub_pos/100 - spu->scaled_height;
1197 break;
1199 draw_alpha(ctx, spu->scaled_start_col, spu->scaled_start_row, spu->scaled_width, spu->scaled_height,
1200 spu->scaled_image, spu->scaled_aimage, spu->scaled_stride);
1201 spu->spu_changed = 0;
1205 else
1207 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPU not displayed: start_pts=%d end_pts=%d now_pts=%d\n",
1208 spu->start_pts, spu->end_pts, spu->now_pts);
1212 void spudec_update_palette(void * this, unsigned int *palette)
1214 spudec_handle_t *spu = this;
1215 if (spu && palette) {
1216 memcpy(spu->global_palette, palette, sizeof(spu->global_palette));
1217 if(spu->hw_spu)
1218 vo_control(spu->hw_spu, VOCTRL_SET_SPU_PALETTE, spu->global_palette);
1222 void spudec_set_font_factor(void * this, double factor)
1224 spudec_handle_t *spu = this;
1225 spu->font_start_level = (int)(0xF0-(0xE0*factor));
1228 static void spudec_parse_extradata(spudec_handle_t *this,
1229 uint8_t *extradata, int extradata_len)
1231 uint8_t *buffer, *ptr;
1232 unsigned int *pal = this->global_palette, *cuspal = this->cuspal;
1233 unsigned int tridx;
1234 int i;
1236 if (extradata_len == 16*4) {
1237 for (i=0; i<16; i++)
1238 pal[i] = AV_RB32(extradata + i*4);
1239 this->auto_palette = 0;
1240 return;
1243 if (!(ptr = buffer = malloc(extradata_len+1)))
1244 return;
1245 memcpy(buffer, extradata, extradata_len);
1246 buffer[extradata_len] = 0;
1248 do {
1249 if (*ptr == '#')
1250 continue;
1251 if (!strncmp(ptr, "size: ", 6))
1252 sscanf(ptr + 6, "%dx%d", &this->orig_frame_width, &this->orig_frame_height);
1253 if (!strncmp(ptr, "palette: ", 9) &&
1254 sscanf(ptr + 9, "%x, %x, %x, %x, %x, %x, %x, %x, "
1255 "%x, %x, %x, %x, %x, %x, %x, %x",
1256 &pal[ 0], &pal[ 1], &pal[ 2], &pal[ 3],
1257 &pal[ 4], &pal[ 5], &pal[ 6], &pal[ 7],
1258 &pal[ 8], &pal[ 9], &pal[10], &pal[11],
1259 &pal[12], &pal[13], &pal[14], &pal[15]) == 16) {
1260 for (i=0; i<16; i++)
1261 pal[i] = vobsub_palette_to_yuv(pal[i]);
1262 this->auto_palette = 0;
1264 if (!strncasecmp(ptr, "forced subs: on", 15))
1265 this->forced_subs_only = 1;
1266 if (!strncmp(ptr, "custom colors: ON, tridx: ", 26) &&
1267 sscanf(ptr + 26, "%x, colors: %x, %x, %x, %x",
1268 &tridx, cuspal+0, cuspal+1, cuspal+2, cuspal+3) == 5) {
1269 for (i=0; i<4; i++) {
1270 cuspal[i] = vobsub_rgb_to_yuv(cuspal[i]);
1271 if (tridx & (1 << (12-4*i)))
1272 cuspal[i] |= 1 << 31;
1274 this->custom = 1;
1276 } while ((ptr=strchr(ptr,'\n')) && *++ptr);
1278 free(buffer);
1281 void *spudec_new_scaled(unsigned int *palette, unsigned int frame_width, unsigned int frame_height, uint8_t *extradata, int extradata_len)
1283 spudec_handle_t *this = calloc(1, sizeof(spudec_handle_t));
1284 if (this){
1285 this->orig_frame_height = frame_height;
1286 this->orig_frame_width = frame_width;
1287 // set up palette:
1288 if (palette)
1289 memcpy(this->global_palette, palette, sizeof(this->global_palette));
1290 else
1291 this->auto_palette = 1;
1292 if (extradata)
1293 spudec_parse_extradata(this, extradata, extradata_len);
1294 /* XXX Although the video frame is some size, the SPU frame is
1295 always maximum size i.e. 720 wide and 576 or 480 high */
1296 // For HD files in MKV the VobSub resolution can be higher though,
1297 // see largeres_vobsub.mkv
1298 if (this->orig_frame_width <= 720 && this->orig_frame_height <= 576) {
1299 this->orig_frame_width = 720;
1300 if (this->orig_frame_height == 480 || this->orig_frame_height == 240)
1301 this->orig_frame_height = 480;
1302 else
1303 this->orig_frame_height = 576;
1306 else
1307 mp_msg(MSGT_SPUDEC,MSGL_FATAL, "FATAL: spudec_init: calloc");
1308 return this;
1311 void *spudec_new(unsigned int *palette)
1313 return spudec_new_scaled(palette, 0, 0, NULL, 0);
1316 void spudec_free(void *this)
1318 spudec_handle_t *spu = this;
1319 if (spu) {
1320 while (spu->queue_head)
1321 spudec_free_packet(spudec_dequeue_packet(spu));
1322 free(spu->packet);
1323 spu->packet = NULL;
1324 free(spu->scaled_image);
1325 spu->scaled_image = NULL;
1326 free(spu->image);
1327 spu->image = NULL;
1328 spu->aimage = NULL;
1329 free(spu->pal_image);
1330 spu->pal_image = NULL;
1331 spu->image_size = 0;
1332 spu->pal_width = spu->pal_height = 0;
1333 free(spu);
1337 void spudec_set_hw_spu(void *this, struct vo *hw_spu)
1339 spudec_handle_t *spu = this;
1340 if (!spu)
1341 return;
1342 spu->hw_spu = hw_spu;
1343 vo_control(hw_spu, VOCTRL_SET_SPU_PALETTE, spu->global_palette);
1347 * palette must contain at least 256 32-bit entries, otherwise crashes
1348 * are possible
1350 void spudec_set_paletted(void *this, const uint8_t *pal_img, int pal_stride,
1351 const void *palette,
1352 int x, int y, int w, int h,
1353 double pts, double endpts)
1355 int i;
1356 uint16_t g8a8_pal[256];
1357 packet_t *packet;
1358 const uint32_t *pal = palette;
1359 spudec_handle_t *spu = this;
1360 uint8_t *img;
1361 uint8_t *aimg;
1362 int stride = (w + 7) & ~7;
1363 if ((unsigned)w >= 0x8000 || (unsigned)h > 0x4000)
1364 return;
1365 packet = calloc(1, sizeof(packet_t));
1366 packet->is_decoded = 1;
1367 packet->width = w;
1368 packet->height = h;
1369 packet->stride = stride;
1370 packet->start_col = x;
1371 packet->start_row = y;
1372 packet->data_len = 2 * stride * h;
1373 if (packet->data_len) { // size 0 is a special "clear" packet
1374 packet->packet = malloc(packet->data_len);
1375 img = packet->packet;
1376 aimg = packet->packet + stride * h;
1377 for (i = 0; i < 256; i++) {
1378 uint32_t pixel = pal[i];
1379 int alpha = pixel >> 24;
1380 int gray = (((pixel & 0x000000ff) >> 0) +
1381 ((pixel & 0x0000ff00) >> 7) +
1382 ((pixel & 0x00ff0000) >> 16)) >> 2;
1383 gray = FFMIN(gray, alpha);
1384 g8a8_pal[i] = (-alpha << 8) | gray;
1386 pal2gray_alpha(g8a8_pal, pal_img, pal_stride,
1387 img, aimg, stride, w, h);
1389 packet->start_pts = 0;
1390 packet->end_pts = 0x7fffffff;
1391 if (pts != MP_NOPTS_VALUE)
1392 packet->start_pts = pts * 90000;
1393 if (endpts != MP_NOPTS_VALUE)
1394 packet->end_pts = endpts * 90000;
1395 spudec_queue_packet(spu, packet);