options: fix -profile parsing after 2db33ab48c
[mplayer/greg.git] / sub / spudec.c
blob48e219a93034acbcb422fdd7f725ecdf68ed7269
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"
46 #include "mpcommon.h"
48 /* Valid values for spu_aamode:
49 0: none (fastest, most ugly)
50 1: approximate
51 2: full (slowest)
52 3: bilinear (similiar to vobsub, fast and not too bad)
53 4: uses swscaler gaussian (this is the only one that looks good)
56 int spu_aamode = 3;
57 int spu_alignment = -1;
58 float spu_gaussvar = 1.0;
59 extern int sub_pos;
61 typedef struct packet_t packet_t;
62 struct packet_t {
63 int is_decoded;
64 unsigned char *packet;
65 int data_len;
66 unsigned int palette[4];
67 unsigned int alpha[4];
68 unsigned int control_start; /* index of start of control data */
69 unsigned int current_nibble[2]; /* next data nibble (4 bits) to be
70 processed (for RLE decoding) for
71 even and odd lines */
72 int deinterlace_oddness; /* 0 or 1, index into current_nibble */
73 unsigned int start_col;
74 unsigned int start_row;
75 unsigned int width, height, stride;
76 unsigned int start_pts, end_pts;
77 packet_t *next;
80 struct palette_crop_cache {
81 int valid;
82 uint32_t palette;
83 int sx, sy, ex, ey;
84 int result;
87 typedef struct {
88 packet_t *queue_head;
89 packet_t *queue_tail;
90 unsigned int global_palette[16];
91 unsigned int orig_frame_width, orig_frame_height;
92 unsigned char* packet;
93 size_t packet_reserve; /* size of the memory pointed to by packet */
94 unsigned int packet_offset; /* end of the currently assembled fragment */
95 unsigned int packet_size; /* size of the packet once all fragments are assembled */
96 int packet_pts; /* PTS for this packet */
97 unsigned int palette[4];
98 unsigned int alpha[4];
99 unsigned int cuspal[4];
100 unsigned int custom;
101 unsigned int now_pts;
102 unsigned int start_pts, end_pts;
103 unsigned int start_col;
104 unsigned int start_row;
105 unsigned int width, height, stride;
106 size_t image_size; /* Size of the image buffer */
107 unsigned char *image; /* Grayscale value */
108 unsigned char *aimage; /* Alpha value */
109 unsigned int pal_start_col, pal_start_row;
110 unsigned int pal_width, pal_height;
111 unsigned char *pal_image; /* palette entry value */
112 unsigned int scaled_frame_width, scaled_frame_height;
113 unsigned int scaled_start_col, scaled_start_row;
114 unsigned int scaled_width, scaled_height, scaled_stride;
115 size_t scaled_image_size;
116 unsigned char *scaled_image;
117 unsigned char *scaled_aimage;
118 int auto_palette; /* 1 if we lack a palette and must use an heuristic. */
119 int font_start_level; /* Darkest value used for the computed font */
120 struct vo *hw_spu;
121 int spu_changed;
122 unsigned int forced_subs_only; /* flag: 0=display all subtitle, !0 display only forced subtitles */
123 unsigned int is_forced_sub; /* true if current subtitle is a forced subtitle */
125 struct palette_crop_cache palette_crop_cache;
126 } spudec_handle_t;
128 static void spudec_queue_packet(spudec_handle_t *this, packet_t *packet)
130 if (this->queue_head == NULL)
131 this->queue_head = packet;
132 else
133 this->queue_tail->next = packet;
134 this->queue_tail = packet;
137 static packet_t *spudec_dequeue_packet(spudec_handle_t *this)
139 packet_t *retval = this->queue_head;
141 this->queue_head = retval->next;
142 if (this->queue_head == NULL)
143 this->queue_tail = NULL;
145 return retval;
148 static void spudec_free_packet(packet_t *packet)
150 free(packet->packet);
151 free(packet);
154 static inline unsigned int get_be16(const unsigned char *p)
156 return (p[0] << 8) + p[1];
159 static inline unsigned int get_be24(const unsigned char *p)
161 return (get_be16(p) << 8) + p[2];
164 static void next_line(packet_t *packet)
166 if (packet->current_nibble[packet->deinterlace_oddness] % 2)
167 packet->current_nibble[packet->deinterlace_oddness]++;
168 packet->deinterlace_oddness = (packet->deinterlace_oddness + 1) % 2;
171 static inline unsigned char get_nibble(packet_t *packet)
173 unsigned char nib;
174 unsigned int *nibblep = packet->current_nibble + packet->deinterlace_oddness;
175 if (*nibblep / 2 >= packet->control_start) {
176 mp_msg(MSGT_SPUDEC,MSGL_WARN, "SPUdec: ERROR: get_nibble past end of packet\n");
177 return 0;
179 nib = packet->packet[*nibblep / 2];
180 if (*nibblep % 2)
181 nib &= 0xf;
182 else
183 nib >>= 4;
184 ++*nibblep;
185 return nib;
188 /* Cut the sub to visible part */
189 static inline void spudec_cut_image(spudec_handle_t *this)
191 unsigned int fy, ly;
192 unsigned int first_y, last_y;
194 if (this->stride == 0 || this->height == 0) {
195 return;
198 for (fy = 0; fy < this->image_size && !this->aimage[fy]; fy++);
199 for (ly = this->stride * this->height-1; ly && !this->aimage[ly]; ly--);
200 first_y = fy / this->stride;
201 last_y = ly / this->stride;
202 //printf("first_y: %d, last_y: %d\n", first_y, last_y);
203 this->start_row += first_y;
205 // Some subtitles trigger this condition
206 if (last_y + 1 > first_y ) {
207 this->height = last_y - first_y +1;
208 } else {
209 this->height = 0;
210 return;
213 // printf("new h %d new start %d (sz %d st %d)---\n\n", this->height, this->start_row, this->image_size, this->stride);
215 if (first_y > 0) {
216 memmove(this->image, this->image + this->stride * first_y, this->stride * this->height);
217 memmove(this->aimage, this->aimage + this->stride * first_y, this->stride * this->height);
222 static int spudec_alloc_image(spudec_handle_t *this, int stride, int height)
224 if (this->width > stride) // just a safeguard
225 this->width = stride;
226 this->stride = stride;
227 this->height = height;
228 if (this->image_size < this->stride * this->height) {
229 if (this->image != NULL) {
230 free(this->image);
231 free(this->pal_image);
232 this->image_size = 0;
233 this->pal_width = this->pal_height = 0;
235 this->image = malloc(2 * this->stride * this->height);
236 if (this->image) {
237 this->image_size = this->stride * this->height;
238 this->aimage = this->image + this->image_size;
239 // use stride here as well to simplify reallocation checks
240 this->pal_image = malloc(this->stride * this->height);
243 return this->image != NULL;
247 * \param pal palette in MPlayer-style gray-alpha values, i.e.
248 * alpha == 0 means transparent, 1 fully opaque,
249 * gray value <= 256 - alpha.
251 static void pal2gray_alpha(const uint16_t *pal,
252 const uint8_t *src, int src_stride,
253 uint8_t *dst, uint8_t *dsta,
254 int dst_stride, int w, int h)
256 int x, y;
257 for (y = 0; y < h; y++) {
258 for (x = 0; x < w; x++) {
259 uint16_t pixel = pal[src[x]];
260 *dst++ = pixel;
261 *dsta++ = pixel >> 8;
263 for (; x < dst_stride; x++)
264 *dsta++ = *dst++ = 0;
265 src += src_stride;
269 static int apply_palette_crop(spudec_handle_t *this,
270 unsigned crop_x, unsigned crop_y,
271 unsigned crop_w, unsigned crop_h)
273 int i;
274 uint8_t *src;
275 uint16_t pal[4];
276 unsigned stride = (crop_w + 7) & ~7;
277 if (crop_x > this->pal_width || crop_y > this->pal_height ||
278 crop_w > this->pal_width - crop_x || crop_h > this->pal_width - crop_y ||
279 crop_w > 0x8000 || crop_h > 0x8000 ||
280 stride * crop_h > this->image_size) {
281 return 0;
283 for (i = 0; i < 4; ++i) {
284 int color;
285 int alpha = this->alpha[i];
286 // extend 4 -> 8 bit
287 alpha |= alpha << 4;
288 if (this->custom && (this->cuspal[i] >> 31) != 0)
289 alpha = 0;
290 color = this->custom ? this->cuspal[i] :
291 this->global_palette[this->palette[i]];
292 color = (color >> 16) & 0xff;
293 // convert to MPlayer-style gray/alpha palette
294 color = FFMIN(color, alpha);
295 pal[i] = (-alpha << 8) | color;
297 src = this->pal_image + crop_y * this->pal_width + crop_x;
298 pal2gray_alpha(pal, src, this->pal_width,
299 this->image, this->aimage, stride,
300 crop_w, crop_h);
301 this->width = crop_w;
302 this->height = crop_h;
303 this->stride = stride;
304 this->start_col = this->pal_start_col + crop_x;
305 this->start_row = this->pal_start_row + crop_y;
306 spudec_cut_image(this);
308 // reset scaled image
309 this->scaled_frame_width = 0;
310 this->scaled_frame_height = 0;
311 this->palette_crop_cache.valid = 0;
312 return 1;
315 int spudec_apply_palette_crop(void *this, uint32_t palette,
316 int sx, int sy, int ex, int ey)
318 spudec_handle_t *spu = this;
319 struct palette_crop_cache *c = &spu->palette_crop_cache;
320 if (c->valid && c->palette == palette &&
321 c->sx == sx && c->sy == sy && c->ex == ex && c->ey == ey)
322 return c->result;
323 spu->palette[0] = (palette >> 28) & 0xf;
324 spu->palette[1] = (palette >> 24) & 0xf;
325 spu->palette[2] = (palette >> 20) & 0xf;
326 spu->palette[3] = (palette >> 16) & 0xf;
327 spu->alpha[0] = (palette >> 12) & 0xf;
328 spu->alpha[1] = (palette >> 8) & 0xf;
329 spu->alpha[2] = (palette >> 4) & 0xf;
330 spu->alpha[3] = palette & 0xf;
331 spu->spu_changed = 1;
332 c->result = apply_palette_crop(spu,
333 sx - spu->pal_start_col, sy - spu->pal_start_row,
334 ex - sx, ey - sy);
335 c->palette = palette;
336 c->sx = sx; c->sy = sy;
337 c->ex = ex; c->ey = ey;
338 c->valid = 1;
339 return c->result;
342 static void spudec_process_data(spudec_handle_t *this, packet_t *packet)
344 unsigned int i, x, y;
345 uint8_t *dst;
347 if (!spudec_alloc_image(this, packet->stride, packet->height))
348 return;
350 this->pal_start_col = packet->start_col;
351 this->pal_start_row = packet->start_row;
352 this->pal_height = packet->height;
353 this->pal_width = packet->width;
354 this->stride = packet->stride;
355 memcpy(this->palette, packet->palette, sizeof(this->palette));
356 memcpy(this->alpha, packet->alpha, sizeof(this->alpha));
358 i = packet->current_nibble[1];
359 x = 0;
360 y = 0;
361 dst = this->pal_image;
362 while (packet->current_nibble[0] < i
363 && packet->current_nibble[1] / 2 < packet->control_start
364 && y < this->pal_height) {
365 unsigned int len, color;
366 unsigned int rle = 0;
367 rle = get_nibble(packet);
368 if (rle < 0x04) {
369 if (rle == 0) {
370 rle = (rle << 4) | get_nibble(packet);
371 if (rle < 0x04)
372 rle = (rle << 4) | get_nibble(packet);
374 rle = (rle << 4) | get_nibble(packet);
376 color = 3 - (rle & 0x3);
377 len = rle >> 2;
378 x += len;
379 if (len == 0 || x >= this->pal_width) {
380 len += this->pal_width - x;
381 next_line(packet);
382 x = 0;
383 ++y;
385 memset(dst, color, len);
386 dst += len;
388 apply_palette_crop(this, 0, 0, this->pal_width, this->pal_height);
393 This function tries to create a usable palette.
394 It determines how many non-transparent colors are used, and assigns different
395 gray scale values to each color.
396 I tested it with four streams and even got something readable. Half of the
397 times I got black characters with white around and half the reverse.
399 static void compute_palette(spudec_handle_t *this, packet_t *packet)
401 int used[16],i,cused,start,step,color;
403 memset(used, 0, sizeof(used));
404 for (i=0; i<4; i++)
405 if (packet->alpha[i]) /* !Transparent? */
406 used[packet->palette[i]] = 1;
407 for (cused=0, i=0; i<16; i++)
408 if (used[i]) cused++;
409 if (!cused) return;
410 if (cused == 1) {
411 start = 0x80;
412 step = 0;
413 } else {
414 start = this->font_start_level;
415 step = (0xF0-this->font_start_level)/(cused-1);
417 memset(used, 0, sizeof(used));
418 for (i=0; i<4; i++) {
419 color = packet->palette[i];
420 if (packet->alpha[i] && !used[color]) { /* not assigned? */
421 used[color] = 1;
422 this->global_palette[color] = start<<16;
423 start += step;
428 static void spudec_process_control(spudec_handle_t *this, int pts100)
430 int a,b,c,d; /* Temporary vars */
431 unsigned int date, type;
432 unsigned int off;
433 unsigned int start_off = 0;
434 unsigned int next_off;
435 unsigned int start_pts = 0;
436 unsigned int end_pts = 0;
437 unsigned int current_nibble[2] = {0, 0};
438 unsigned int control_start;
439 unsigned int display = 0;
440 unsigned int start_col = 0;
441 unsigned int end_col = 0;
442 unsigned int start_row = 0;
443 unsigned int end_row = 0;
444 unsigned int width = 0;
445 unsigned int height = 0;
446 unsigned int stride = 0;
448 control_start = get_be16(this->packet + 2);
449 next_off = control_start;
450 while (start_off != next_off) {
451 start_off = next_off;
452 date = get_be16(this->packet + start_off) * 1024;
453 next_off = get_be16(this->packet + start_off + 2);
454 mp_msg(MSGT_SPUDEC,MSGL_DBG2, "date=%d\n", date);
455 off = start_off + 4;
456 for (type = this->packet[off++]; type != 0xff; type = this->packet[off++]) {
457 mp_msg(MSGT_SPUDEC,MSGL_DBG2, "cmd=%d ",type);
458 switch(type) {
459 case 0x00:
460 /* Menu ID, 1 byte */
461 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Menu ID\n");
462 /* shouldn't a Menu ID type force display start? */
463 start_pts = pts100 < 0 && -pts100 >= date ? 0 : pts100 + date;
464 end_pts = UINT_MAX;
465 display = 1;
466 this->is_forced_sub=~0; // current subtitle is forced
467 break;
468 case 0x01:
469 /* Start display */
470 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Start display!\n");
471 start_pts = pts100 < 0 && -pts100 >= date ? 0 : pts100 + date;
472 end_pts = UINT_MAX;
473 display = 1;
474 this->is_forced_sub=0;
475 break;
476 case 0x02:
477 /* Stop display */
478 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Stop display!\n");
479 end_pts = pts100 < 0 && -pts100 >= date ? 0 : pts100 + date;
480 break;
481 case 0x03:
482 /* Palette */
483 this->palette[0] = this->packet[off] >> 4;
484 this->palette[1] = this->packet[off] & 0xf;
485 this->palette[2] = this->packet[off + 1] >> 4;
486 this->palette[3] = this->packet[off + 1] & 0xf;
487 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Palette %d, %d, %d, %d\n",
488 this->palette[0], this->palette[1], this->palette[2], this->palette[3]);
489 off+=2;
490 break;
491 case 0x04:
492 /* Alpha */
493 a = this->packet[off] >> 4;
494 b = this->packet[off] & 0xf;
495 c = this->packet[off + 1] >> 4;
496 d = this->packet[off + 1] & 0xf;
497 // Note: some DVDs change these values to create a fade-in/fade-out effect
498 // We can not handle this, so just keep the highest value during the display time.
499 if (display) {
500 a = FFMAX(a, this->alpha[0]);
501 b = FFMAX(b, this->alpha[1]);
502 c = FFMAX(c, this->alpha[2]);
503 d = FFMAX(d, this->alpha[3]);
505 this->alpha[0] = a;
506 this->alpha[1] = b;
507 this->alpha[2] = c;
508 this->alpha[3] = d;
509 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Alpha %d, %d, %d, %d\n",
510 this->alpha[0], this->alpha[1], this->alpha[2], this->alpha[3]);
511 off+=2;
512 break;
513 case 0x05:
514 /* Co-ords */
515 a = get_be24(this->packet + off);
516 b = get_be24(this->packet + off + 3);
517 start_col = a >> 12;
518 end_col = a & 0xfff;
519 width = (end_col < start_col) ? 0 : end_col - start_col + 1;
520 stride = (width + 7) & ~7; /* Kludge: draw_alpha needs width multiple of 8 */
521 start_row = b >> 12;
522 end_row = b & 0xfff;
523 height = (end_row < start_row) ? 0 : end_row - start_row /* + 1 */;
524 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Coords col: %d - %d row: %d - %d (%dx%d)\n",
525 start_col, end_col, start_row, end_row,
526 width, height);
527 off+=6;
528 break;
529 case 0x06:
530 /* Graphic lines */
531 current_nibble[0] = 2 * get_be16(this->packet + off);
532 current_nibble[1] = 2 * get_be16(this->packet + off + 2);
533 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Graphic offset 1: %d offset 2: %d\n",
534 current_nibble[0] / 2, current_nibble[1] / 2);
535 off+=4;
536 break;
537 case 0xff:
538 /* All done, bye-bye */
539 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Done!\n");
540 return;
541 // break;
542 default:
543 mp_msg(MSGT_SPUDEC,MSGL_WARN,"spudec: Error determining control type 0x%02x. Skipping %d bytes.\n",
544 type, next_off - off);
545 goto next_control;
548 next_control:
549 if (!display)
550 continue;
551 if (end_pts == UINT_MAX && start_off != next_off) {
552 end_pts = get_be16(this->packet + next_off) * 1024;
553 end_pts = 1 - pts100 >= end_pts ? 0 : pts100 + end_pts - 1;
555 if (end_pts > 0) {
556 packet_t *packet = calloc(1, sizeof(packet_t));
557 int i;
558 packet->start_pts = start_pts;
559 packet->end_pts = end_pts;
560 packet->current_nibble[0] = current_nibble[0];
561 packet->current_nibble[1] = current_nibble[1];
562 packet->start_row = start_row;
563 packet->start_col = start_col;
564 packet->width = width;
565 packet->height = height;
566 packet->stride = stride;
567 packet->control_start = control_start;
568 for (i=0; i<4; i++) {
569 packet->alpha[i] = this->alpha[i];
570 packet->palette[i] = this->palette[i];
572 packet->packet = malloc(this->packet_size);
573 memcpy(packet->packet, this->packet, this->packet_size);
574 spudec_queue_packet(this, packet);
579 static void spudec_decode(spudec_handle_t *this, int pts100)
581 if (!this->hw_spu)
582 spudec_process_control(this, pts100);
583 else if (pts100 >= 0) {
584 static vo_mpegpes_t packet = { NULL, 0, 0x20, 0 };
585 static vo_mpegpes_t *pkg=&packet;
586 packet.data = this->packet;
587 packet.size = this->packet_size;
588 packet.timestamp = pts100;
589 vo_draw_frame(this->hw_spu, (uint8_t**)&pkg);
593 int spudec_changed(void * this)
595 spudec_handle_t * spu = this;
596 return spu->spu_changed || spu->now_pts > spu->end_pts;
599 void spudec_assemble(void *this, unsigned char *packet, unsigned int len, int pts100)
601 spudec_handle_t *spu = this;
602 // spudec_heartbeat(this, pts100);
603 if (len < 2) {
604 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: packet too short\n");
605 return;
607 spu->packet_pts = pts100;
608 if (spu->packet_offset == 0) {
609 unsigned int len2 = get_be16(packet);
610 // Start new fragment
611 if (spu->packet_reserve < len2) {
612 free(spu->packet);
613 spu->packet = malloc(len2);
614 spu->packet_reserve = spu->packet != NULL ? len2 : 0;
616 if (spu->packet != NULL) {
617 spu->packet_size = len2;
618 if (len > len2) {
619 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: invalid frag len / len2: %d / %d \n", len, len2);
620 return;
622 memcpy(spu->packet, packet, len);
623 spu->packet_offset = len;
624 spu->packet_pts = pts100;
626 } else {
627 // Continue current fragment
628 if (spu->packet_size < spu->packet_offset + len){
629 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: invalid fragment\n");
630 spu->packet_size = spu->packet_offset = 0;
631 return;
632 } else {
633 memcpy(spu->packet + spu->packet_offset, packet, len);
634 spu->packet_offset += len;
637 #if 1
638 // check if we have a complete packet (unfortunatelly packet_size is bad
639 // for some disks)
640 // [cb] packet_size is padded to be even -> may be one byte too long
641 if ((spu->packet_offset == spu->packet_size) ||
642 ((spu->packet_offset + 1) == spu->packet_size)){
643 unsigned int x=0,y;
644 while(x+4<=spu->packet_offset){
645 y=get_be16(spu->packet+x+2); // next control pointer
646 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPUtest: x=%d y=%d off=%d size=%d\n",x,y,spu->packet_offset,spu->packet_size);
647 if(x>=4 && x==y){ // if it points to self - we're done!
648 // we got it!
649 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPUgot: off=%d size=%d \n",spu->packet_offset,spu->packet_size);
650 spudec_decode(spu, pts100);
651 spu->packet_offset = 0;
652 break;
654 if(y<=x || y>=spu->packet_size){ // invalid?
655 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUtest: broken packet!!!!! y=%d < x=%d\n",y,x);
656 spu->packet_size = spu->packet_offset = 0;
657 break;
659 x=y;
661 // [cb] packet is done; start new packet
662 spu->packet_offset = 0;
664 #else
665 if (spu->packet_offset == spu->packet_size) {
666 spudec_decode(spu, pts100);
667 spu->packet_offset = 0;
669 #endif
672 void spudec_reset(void *this) // called after seek
674 spudec_handle_t *spu = this;
675 while (spu->queue_head)
676 spudec_free_packet(spudec_dequeue_packet(spu));
677 spu->now_pts = 0;
678 spu->end_pts = 0;
679 spu->packet_size = spu->packet_offset = 0;
682 void spudec_heartbeat(void *this, unsigned int pts100)
684 spudec_handle_t *spu = this;
685 spu->now_pts = pts100;
687 // TODO: detect and handle broken timestamps (e.g. due to wrapping)
688 while (spu->queue_head != NULL && pts100 >= spu->queue_head->start_pts) {
689 packet_t *packet = spudec_dequeue_packet(spu);
690 spu->start_pts = packet->start_pts;
691 spu->end_pts = packet->end_pts;
692 if (packet->is_decoded) {
693 free(spu->image);
694 spu->image_size = packet->data_len;
695 spu->image = packet->packet;
696 spu->aimage = packet->packet + packet->stride * packet->height;
697 packet->packet = NULL;
698 spu->width = packet->width;
699 spu->height = packet->height;
700 spu->stride = packet->stride;
701 spu->start_col = packet->start_col;
702 spu->start_row = packet->start_row;
704 // reset scaled image
705 spu->scaled_frame_width = 0;
706 spu->scaled_frame_height = 0;
707 } else {
708 if (spu->auto_palette)
709 compute_palette(spu, packet);
710 spudec_process_data(spu, packet);
712 spudec_free_packet(packet);
713 spu->spu_changed = 1;
717 int spudec_visible(void *this){
718 spudec_handle_t *spu = this;
719 int ret=(spu->start_pts <= spu->now_pts &&
720 spu->now_pts < spu->end_pts &&
721 spu->height > 0);
722 // printf("spu visible: %d \n",ret);
723 return ret;
726 void spudec_set_forced_subs_only(void * const this, const unsigned int flag)
728 if(this){
729 ((spudec_handle_t *)this)->forced_subs_only=flag;
730 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPU: Display only forced subs now %s\n", flag ? "enabled": "disabled");
734 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)
736 spudec_handle_t *spu = this;
737 if (spudec_visible(spu))
739 draw_alpha(ctx, spu->start_col, spu->start_row, spu->width, spu->height,
740 spu->image, spu->aimage, spu->stride);
741 spu->spu_changed = 0;
745 /* calc the bbox for spudec subs */
746 void spudec_calc_bbox(void *me, unsigned int dxs, unsigned int dys, unsigned int* bbox)
748 spudec_handle_t *spu = me;
749 if (spu->orig_frame_width == 0 || spu->orig_frame_height == 0
750 || (spu->orig_frame_width == dxs && spu->orig_frame_height == dys)) {
751 // unscaled
752 bbox[0] = spu->start_col;
753 bbox[1] = spu->start_col + spu->width;
754 bbox[2] = spu->start_row;
755 bbox[3] = spu->start_row + spu->height;
757 else {
758 // scaled
759 unsigned int scalex = 0x100 * dxs / spu->orig_frame_width;
760 unsigned int scaley = 0x100 * dys / spu->orig_frame_height;
761 bbox[0] = spu->start_col * scalex / 0x100;
762 bbox[1] = spu->start_col * scalex / 0x100 + spu->width * scalex / 0x100;
763 switch (spu_alignment) {
764 case 0:
765 bbox[3] = dys*sub_pos/100 + spu->height * scaley / 0x100;
766 if (bbox[3] > dys) bbox[3] = dys;
767 bbox[2] = bbox[3] - spu->height * scaley / 0x100;
768 break;
769 case 1:
770 if (sub_pos < 50) {
771 bbox[2] = dys*sub_pos/100 - spu->height * scaley / 0x200;
772 bbox[3] = bbox[2] + spu->height;
773 } else {
774 bbox[3] = dys*sub_pos/100 + spu->height * scaley / 0x200;
775 if (bbox[3] > dys) bbox[3] = dys;
776 bbox[2] = bbox[3] - spu->height * scaley / 0x100;
778 break;
779 case 2:
780 bbox[2] = dys*sub_pos/100 - spu->height * scaley / 0x100;
781 bbox[3] = bbox[2] + spu->height;
782 break;
783 default: /* -1 */
784 bbox[2] = spu->start_row * scaley / 0x100;
785 bbox[3] = spu->start_row * scaley / 0x100 + spu->height * scaley / 0x100;
786 break;
790 /* transform mplayer's alpha value into an opacity value that is linear */
791 static inline int canon_alpha(int alpha)
793 return (uint8_t)-alpha;
796 typedef struct {
797 unsigned position;
798 unsigned left_up;
799 unsigned right_down;
800 }scale_pixel;
803 static void scale_table(unsigned int start_src, unsigned int start_tar, unsigned int end_src, unsigned int end_tar, scale_pixel * table)
805 unsigned int t;
806 unsigned int delta_src = end_src - start_src;
807 unsigned int delta_tar = end_tar - start_tar;
808 int src = 0;
809 int src_step;
810 if (delta_src == 0 || delta_tar == 0) {
811 return;
813 src_step = (delta_src << 16) / delta_tar >>1;
814 for (t = 0; t<=delta_tar; src += (src_step << 1), t++){
815 table[t].position= FFMIN(src >> 16, end_src - 1);
816 table[t].right_down = src & 0xffff;
817 table[t].left_up = 0x10000 - table[t].right_down;
821 /* bilinear scale, similar to vobsub's code */
822 static void scale_image(int x, int y, scale_pixel* table_x, scale_pixel* table_y, spudec_handle_t * spu)
824 int alpha[4];
825 int color[4];
826 unsigned int scale[4];
827 int base = table_y[y].position * spu->stride + table_x[x].position;
828 int scaled = y * spu->scaled_stride + x;
829 alpha[0] = canon_alpha(spu->aimage[base]);
830 alpha[1] = canon_alpha(spu->aimage[base + 1]);
831 alpha[2] = canon_alpha(spu->aimage[base + spu->stride]);
832 alpha[3] = canon_alpha(spu->aimage[base + spu->stride + 1]);
833 color[0] = spu->image[base];
834 color[1] = spu->image[base + 1];
835 color[2] = spu->image[base + spu->stride];
836 color[3] = spu->image[base + spu->stride + 1];
837 scale[0] = (table_x[x].left_up * table_y[y].left_up >> 16) * alpha[0];
838 if (table_y[y].left_up == 0x10000) // necessary to avoid overflow-case
839 scale[0] = table_x[x].left_up * alpha[0];
840 scale[1] = (table_x[x].right_down * table_y[y].left_up >>16) * alpha[1];
841 scale[2] = (table_x[x].left_up * table_y[y].right_down >> 16) * alpha[2];
842 scale[3] = (table_x[x].right_down * table_y[y].right_down >> 16) * alpha[3];
843 spu->scaled_image[scaled] = (color[0] * scale[0] + color[1] * scale[1] + color[2] * scale[2] + color[3] * scale[3])>>24;
844 spu->scaled_aimage[scaled] = (scale[0] + scale[1] + scale[2] + scale[3]) >> 16;
845 if (spu->scaled_aimage[scaled]){
846 // ensure that MPlayer's simplified alpha-blending can not overflow
847 spu->scaled_image[scaled] = FFMIN(spu->scaled_image[scaled], spu->scaled_aimage[scaled]);
848 // convert to MPlayer-style alpha
849 spu->scaled_aimage[scaled] = -spu->scaled_aimage[scaled];
853 static void sws_spu_image(unsigned char *d1, unsigned char *d2, int dw, int dh,
854 int ds, const unsigned char* s1, unsigned char* s2,
855 int sw, int sh, int ss)
857 struct SwsContext *ctx;
858 static SwsFilter filter;
859 static int firsttime = 1;
860 static float oldvar;
861 int i;
863 if (!firsttime && oldvar != spu_gaussvar) sws_freeVec(filter.lumH);
864 if (firsttime) {
865 filter.lumH = filter.lumV =
866 filter.chrH = filter.chrV = sws_getGaussianVec(spu_gaussvar, 3.0);
867 sws_normalizeVec(filter.lumH, 1.0);
868 firsttime = 0;
869 oldvar = spu_gaussvar;
872 ctx=sws_getContext(sw, sh, PIX_FMT_GRAY8, dw, dh, PIX_FMT_GRAY8, SWS_GAUSS, &filter, NULL, NULL);
873 sws_scale(ctx,&s1,&ss,0,sh,&d1,&ds);
874 for (i=ss*sh-1; i>=0; i--) if (!s2[i]) s2[i] = 255; //else s2[i] = 1;
875 sws_scale(ctx,(const uint8_t **)&s2,&ss,0,sh,&d2,&ds);
876 for (i=ds*dh-1; i>=0; i--) if (d2[i]==0) d2[i] = 1; else if (d2[i]==255) d2[i] = 0;
877 sws_freeContext(ctx);
880 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)
882 spudec_handle_t *spu = me;
883 scale_pixel *table_x;
884 scale_pixel *table_y;
886 if (spudec_visible(spu)) {
888 // check if only forced subtitles are requested
889 if( (spu->forced_subs_only) && !(spu->is_forced_sub) ){
890 return;
893 if (!(spu_aamode&16) && (spu->orig_frame_width == 0 || spu->orig_frame_height == 0
894 || (spu->orig_frame_width == dxs && spu->orig_frame_height == dys))) {
895 spudec_draw(spu, draw_alpha, ctx);
897 else {
898 if (spu->scaled_frame_width != dxs || spu->scaled_frame_height != dys) { /* Resizing is needed */
899 /* scaled_x = scalex * x / 0x100
900 scaled_y = scaley * y / 0x100
901 order of operations is important because of rounding. */
902 unsigned int scalex = 0x100 * dxs / spu->orig_frame_width;
903 unsigned int scaley = 0x100 * dys / spu->orig_frame_height;
904 spu->scaled_start_col = spu->start_col * scalex / 0x100;
905 spu->scaled_start_row = spu->start_row * scaley / 0x100;
906 spu->scaled_width = spu->width * scalex / 0x100;
907 spu->scaled_height = spu->height * scaley / 0x100;
908 /* Kludge: draw_alpha needs width multiple of 8 */
909 spu->scaled_stride = (spu->scaled_width + 7) & ~7;
910 if (spu->scaled_image_size < spu->scaled_stride * spu->scaled_height) {
911 if (spu->scaled_image) {
912 free(spu->scaled_image);
913 spu->scaled_image_size = 0;
915 spu->scaled_image = malloc(2 * spu->scaled_stride * spu->scaled_height);
916 if (spu->scaled_image) {
917 spu->scaled_image_size = spu->scaled_stride * spu->scaled_height;
918 spu->scaled_aimage = spu->scaled_image + spu->scaled_image_size;
921 if (spu->scaled_image) {
922 unsigned int x, y;
923 // needs to be 0-initialized because draw_alpha draws always a
924 // multiple of 8 pixels. TODO: optimize
925 if (spu->scaled_width & 7)
926 memset(spu->scaled_image, 0, 2 * spu->scaled_image_size);
927 if (spu->scaled_width <= 1 || spu->scaled_height <= 1) {
928 goto nothing_to_do;
930 switch(spu_aamode&15) {
931 case 4:
932 sws_spu_image(spu->scaled_image, spu->scaled_aimage,
933 spu->scaled_width, spu->scaled_height, spu->scaled_stride,
934 spu->image, spu->aimage, spu->width, spu->height, spu->stride);
935 break;
936 case 3:
937 table_x = calloc(spu->scaled_width, sizeof(scale_pixel));
938 table_y = calloc(spu->scaled_height, sizeof(scale_pixel));
939 if (!table_x || !table_y) {
940 mp_msg(MSGT_SPUDEC, MSGL_FATAL, "Fatal: spudec_draw_scaled: calloc failed\n");
942 scale_table(0, 0, spu->width - 1, spu->scaled_width - 1, table_x);
943 scale_table(0, 0, spu->height - 1, spu->scaled_height - 1, table_y);
944 for (y = 0; y < spu->scaled_height; y++)
945 for (x = 0; x < spu->scaled_width; x++)
946 scale_image(x, y, table_x, table_y, spu);
947 free(table_x);
948 free(table_y);
949 break;
950 case 0:
951 /* no antialiasing */
952 for (y = 0; y < spu->scaled_height; ++y) {
953 int unscaled_y = y * 0x100 / scaley;
954 int strides = spu->stride * unscaled_y;
955 int scaled_strides = spu->scaled_stride * y;
956 for (x = 0; x < spu->scaled_width; ++x) {
957 int unscaled_x = x * 0x100 / scalex;
958 spu->scaled_image[scaled_strides + x] = spu->image[strides + unscaled_x];
959 spu->scaled_aimage[scaled_strides + x] = spu->aimage[strides + unscaled_x];
962 break;
963 case 1:
965 /* Intermediate antialiasing. */
966 for (y = 0; y < spu->scaled_height; ++y) {
967 const unsigned int unscaled_top = y * spu->orig_frame_height / dys;
968 unsigned int unscaled_bottom = (y + 1) * spu->orig_frame_height / dys;
969 if (unscaled_bottom >= spu->height)
970 unscaled_bottom = spu->height - 1;
971 for (x = 0; x < spu->scaled_width; ++x) {
972 const unsigned int unscaled_left = x * spu->orig_frame_width / dxs;
973 unsigned int unscaled_right = (x + 1) * spu->orig_frame_width / dxs;
974 unsigned int color = 0;
975 unsigned int alpha = 0;
976 unsigned int walkx, walky;
977 unsigned int base, tmp;
978 if (unscaled_right >= spu->width)
979 unscaled_right = spu->width - 1;
980 for (walky = unscaled_top; walky <= unscaled_bottom; ++walky)
981 for (walkx = unscaled_left; walkx <= unscaled_right; ++walkx) {
982 base = walky * spu->stride + walkx;
983 tmp = canon_alpha(spu->aimage[base]);
984 alpha += tmp;
985 color += tmp * spu->image[base];
987 base = y * spu->scaled_stride + x;
988 spu->scaled_image[base] = alpha ? color / alpha : 0;
989 spu->scaled_aimage[base] =
990 alpha * (1 + unscaled_bottom - unscaled_top) * (1 + unscaled_right - unscaled_left);
991 /* spu->scaled_aimage[base] =
992 alpha * dxs * dys / spu->orig_frame_width / spu->orig_frame_height; */
993 if (spu->scaled_aimage[base]) {
994 spu->scaled_aimage[base] = 256 - spu->scaled_aimage[base];
995 if (spu->scaled_aimage[base] + spu->scaled_image[base] > 255)
996 spu->scaled_image[base] = 256 - spu->scaled_aimage[base];
1001 break;
1002 case 2:
1004 /* Best antialiasing. Very slow. */
1005 /* Any pixel (x, y) represents pixels from the original
1006 rectangular region comprised between the columns
1007 unscaled_y and unscaled_y + 0x100 / scaley and the rows
1008 unscaled_x and unscaled_x + 0x100 / scalex
1010 The original rectangular region that the scaled pixel
1011 represents is cut in 9 rectangular areas like this:
1013 +---+-----------------+---+
1014 | 1 | 2 | 3 |
1015 +---+-----------------+---+
1016 | | | |
1017 | 4 | 5 | 6 |
1018 | | | |
1019 +---+-----------------+---+
1020 | 7 | 8 | 9 |
1021 +---+-----------------+---+
1023 The width of the left column is at most one pixel and
1024 it is never null and its right column is at a pixel
1025 boundary. The height of the top row is at most one
1026 pixel it is never null and its bottom row is at a
1027 pixel boundary. The width and height of region 5 are
1028 integral values. The width of the right column is
1029 what remains and is less than one pixel. The height
1030 of the bottom row is what remains and is less than
1031 one pixel.
1033 The row above 1, 2, 3 is unscaled_y. The row between
1034 1, 2, 3 and 4, 5, 6 is top_low_row. The row between 4,
1035 5, 6 and 7, 8, 9 is (unsigned int)unscaled_y_bottom.
1036 The row beneath 7, 8, 9 is unscaled_y_bottom.
1038 The column left of 1, 4, 7 is unscaled_x. The column
1039 between 1, 4, 7 and 2, 5, 8 is left_right_column. The
1040 column between 2, 5, 8 and 3, 6, 9 is (unsigned
1041 int)unscaled_x_right. The column right of 3, 6, 9 is
1042 unscaled_x_right. */
1043 const double inv_scalex = (double) 0x100 / scalex;
1044 const double inv_scaley = (double) 0x100 / scaley;
1045 for (y = 0; y < spu->scaled_height; ++y) {
1046 const double unscaled_y = y * inv_scaley;
1047 const double unscaled_y_bottom = unscaled_y + inv_scaley;
1048 const unsigned int top_low_row = FFMIN(unscaled_y_bottom, unscaled_y + 1.0);
1049 const double top = top_low_row - unscaled_y;
1050 const unsigned int height = unscaled_y_bottom > top_low_row
1051 ? (unsigned int) unscaled_y_bottom - top_low_row
1052 : 0;
1053 const double bottom = unscaled_y_bottom > top_low_row
1054 ? unscaled_y_bottom - floor(unscaled_y_bottom)
1055 : 0.0;
1056 for (x = 0; x < spu->scaled_width; ++x) {
1057 const double unscaled_x = x * inv_scalex;
1058 const double unscaled_x_right = unscaled_x + inv_scalex;
1059 const unsigned int left_right_column = FFMIN(unscaled_x_right, unscaled_x + 1.0);
1060 const double left = left_right_column - unscaled_x;
1061 const unsigned int width = unscaled_x_right > left_right_column
1062 ? (unsigned int) unscaled_x_right - left_right_column
1063 : 0;
1064 const double right = unscaled_x_right > left_right_column
1065 ? unscaled_x_right - floor(unscaled_x_right)
1066 : 0.0;
1067 double color = 0.0;
1068 double alpha = 0.0;
1069 double tmp;
1070 unsigned int base;
1071 /* Now use these informations to compute a good alpha,
1072 and lightness. The sum is on each of the 9
1073 region's surface and alpha and lightness.
1075 transformed alpha = sum(surface * alpha) / sum(surface)
1076 transformed color = sum(surface * alpha * color) / sum(surface * alpha)
1078 /* 1: top left part */
1079 base = spu->stride * (unsigned int) unscaled_y;
1080 tmp = left * top * canon_alpha(spu->aimage[base + (unsigned int) unscaled_x]);
1081 alpha += tmp;
1082 color += tmp * spu->image[base + (unsigned int) unscaled_x];
1083 /* 2: top center part */
1084 if (width > 0) {
1085 unsigned int walkx;
1086 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
1087 base = spu->stride * (unsigned int) unscaled_y + walkx;
1088 tmp = /* 1.0 * */ top * canon_alpha(spu->aimage[base]);
1089 alpha += tmp;
1090 color += tmp * spu->image[base];
1093 /* 3: top right part */
1094 if (right > 0.0) {
1095 base = spu->stride * (unsigned int) unscaled_y + (unsigned int) unscaled_x_right;
1096 tmp = right * top * canon_alpha(spu->aimage[base]);
1097 alpha += tmp;
1098 color += tmp * spu->image[base];
1100 /* 4: center left part */
1101 if (height > 0) {
1102 unsigned int walky;
1103 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1104 base = spu->stride * walky + (unsigned int) unscaled_x;
1105 tmp = left /* * 1.0 */ * canon_alpha(spu->aimage[base]);
1106 alpha += tmp;
1107 color += tmp * spu->image[base];
1110 /* 5: center part */
1111 if (width > 0 && height > 0) {
1112 unsigned int walky;
1113 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1114 unsigned int walkx;
1115 base = spu->stride * walky;
1116 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
1117 tmp = /* 1.0 * 1.0 * */ canon_alpha(spu->aimage[base + walkx]);
1118 alpha += tmp;
1119 color += tmp * spu->image[base + walkx];
1123 /* 6: center right part */
1124 if (right > 0.0 && height > 0) {
1125 unsigned int walky;
1126 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1127 base = spu->stride * walky + (unsigned int) unscaled_x_right;
1128 tmp = right /* * 1.0 */ * canon_alpha(spu->aimage[base]);
1129 alpha += tmp;
1130 color += tmp * spu->image[base];
1133 /* 7: bottom left part */
1134 if (bottom > 0.0) {
1135 base = spu->stride * (unsigned int) unscaled_y_bottom + (unsigned int) unscaled_x;
1136 tmp = left * bottom * canon_alpha(spu->aimage[base]);
1137 alpha += tmp;
1138 color += tmp * spu->image[base];
1140 /* 8: bottom center part */
1141 if (width > 0 && bottom > 0.0) {
1142 unsigned int walkx;
1143 base = spu->stride * (unsigned int) unscaled_y_bottom;
1144 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
1145 tmp = /* 1.0 * */ bottom * canon_alpha(spu->aimage[base + walkx]);
1146 alpha += tmp;
1147 color += tmp * spu->image[base + walkx];
1150 /* 9: bottom right part */
1151 if (right > 0.0 && bottom > 0.0) {
1152 base = spu->stride * (unsigned int) unscaled_y_bottom + (unsigned int) unscaled_x_right;
1153 tmp = right * bottom * canon_alpha(spu->aimage[base]);
1154 alpha += tmp;
1155 color += tmp * spu->image[base];
1157 /* Finally mix these transparency and brightness information suitably */
1158 base = spu->scaled_stride * y + x;
1159 spu->scaled_image[base] = alpha > 0 ? color / alpha : 0;
1160 spu->scaled_aimage[base] = alpha * scalex * scaley / 0x10000;
1161 if (spu->scaled_aimage[base]) {
1162 spu->scaled_aimage[base] = 256 - spu->scaled_aimage[base];
1163 if (spu->scaled_aimage[base] + spu->scaled_image[base] > 255)
1164 spu->scaled_image[base] = 256 - spu->scaled_aimage[base];
1170 nothing_to_do:
1171 /* Kludge: draw_alpha needs width multiple of 8. */
1172 if (spu->scaled_width < spu->scaled_stride)
1173 for (y = 0; y < spu->scaled_height; ++y) {
1174 memset(spu->scaled_aimage + y * spu->scaled_stride + spu->scaled_width, 0,
1175 spu->scaled_stride - spu->scaled_width);
1177 spu->scaled_frame_width = dxs;
1178 spu->scaled_frame_height = dys;
1181 if (spu->scaled_image){
1182 switch (spu_alignment) {
1183 case 0:
1184 spu->scaled_start_row = dys*sub_pos/100;
1185 if (spu->scaled_start_row + spu->scaled_height > dys)
1186 spu->scaled_start_row = dys - spu->scaled_height;
1187 break;
1188 case 1:
1189 spu->scaled_start_row = dys*sub_pos/100 - spu->scaled_height/2;
1190 if (sub_pos >= 50 && spu->scaled_start_row + spu->scaled_height > dys)
1191 spu->scaled_start_row = dys - spu->scaled_height;
1192 break;
1193 case 2:
1194 spu->scaled_start_row = dys*sub_pos/100 - spu->scaled_height;
1195 break;
1197 draw_alpha(ctx, spu->scaled_start_col, spu->scaled_start_row, spu->scaled_width, spu->scaled_height,
1198 spu->scaled_image, spu->scaled_aimage, spu->scaled_stride);
1199 spu->spu_changed = 0;
1203 else
1205 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPU not displayed: start_pts=%d end_pts=%d now_pts=%d\n",
1206 spu->start_pts, spu->end_pts, spu->now_pts);
1210 void spudec_update_palette(void * this, unsigned int *palette)
1212 spudec_handle_t *spu = this;
1213 if (spu && palette) {
1214 memcpy(spu->global_palette, palette, sizeof(spu->global_palette));
1215 if(spu->hw_spu)
1216 vo_control(spu->hw_spu, VOCTRL_SET_SPU_PALETTE, spu->global_palette);
1220 void spudec_set_font_factor(void * this, double factor)
1222 spudec_handle_t *spu = this;
1223 spu->font_start_level = (int)(0xF0-(0xE0*factor));
1226 static void spudec_parse_extradata(spudec_handle_t *this,
1227 uint8_t *extradata, int extradata_len)
1229 uint8_t *buffer, *ptr;
1230 unsigned int *pal = this->global_palette, *cuspal = this->cuspal;
1231 unsigned int tridx;
1232 int i;
1234 if (extradata_len == 16*4) {
1235 for (i=0; i<16; i++)
1236 pal[i] = AV_RB32(extradata + i*4);
1237 this->auto_palette = 0;
1238 return;
1241 if (!(ptr = buffer = malloc(extradata_len+1)))
1242 return;
1243 memcpy(buffer, extradata, extradata_len);
1244 buffer[extradata_len] = 0;
1246 do {
1247 if (*ptr == '#')
1248 continue;
1249 if (!strncmp(ptr, "size: ", 6))
1250 sscanf(ptr + 6, "%dx%d", &this->orig_frame_width, &this->orig_frame_height);
1251 if (!strncmp(ptr, "palette: ", 9) &&
1252 sscanf(ptr + 9, "%x, %x, %x, %x, %x, %x, %x, %x, "
1253 "%x, %x, %x, %x, %x, %x, %x, %x",
1254 &pal[ 0], &pal[ 1], &pal[ 2], &pal[ 3],
1255 &pal[ 4], &pal[ 5], &pal[ 6], &pal[ 7],
1256 &pal[ 8], &pal[ 9], &pal[10], &pal[11],
1257 &pal[12], &pal[13], &pal[14], &pal[15]) == 16) {
1258 for (i=0; i<16; i++)
1259 pal[i] = vobsub_palette_to_yuv(pal[i]);
1260 this->auto_palette = 0;
1262 if (!strncasecmp(ptr, "forced subs: on", 15))
1263 this->forced_subs_only = 1;
1264 if (!strncmp(ptr, "custom colors: ON, tridx: ", 26) &&
1265 sscanf(ptr + 26, "%x, colors: %x, %x, %x, %x",
1266 &tridx, cuspal+0, cuspal+1, cuspal+2, cuspal+3) == 5) {
1267 for (i=0; i<4; i++) {
1268 cuspal[i] = vobsub_rgb_to_yuv(cuspal[i]);
1269 if (tridx & (1 << (12-4*i)))
1270 cuspal[i] |= 1 << 31;
1272 this->custom = 1;
1274 } while ((ptr=strchr(ptr,'\n')) && *++ptr);
1276 free(buffer);
1279 void *spudec_new_scaled(unsigned int *palette, unsigned int frame_width, unsigned int frame_height, uint8_t *extradata, int extradata_len)
1281 spudec_handle_t *this = calloc(1, sizeof(spudec_handle_t));
1282 if (this){
1283 this->orig_frame_height = frame_height;
1284 this->orig_frame_width = frame_width;
1285 // set up palette:
1286 if (palette)
1287 memcpy(this->global_palette, palette, sizeof(this->global_palette));
1288 else
1289 this->auto_palette = 1;
1290 if (extradata)
1291 spudec_parse_extradata(this, extradata, extradata_len);
1292 /* XXX Although the video frame is some size, the SPU frame is
1293 always maximum size i.e. 720 wide and 576 or 480 high */
1294 // For HD files in MKV the VobSub resolution can be higher though,
1295 // see largeres_vobsub.mkv
1296 if (this->orig_frame_width <= 720 && this->orig_frame_height <= 576) {
1297 this->orig_frame_width = 720;
1298 if (this->orig_frame_height == 480 || this->orig_frame_height == 240)
1299 this->orig_frame_height = 480;
1300 else
1301 this->orig_frame_height = 576;
1304 else
1305 mp_msg(MSGT_SPUDEC,MSGL_FATAL, "FATAL: spudec_init: calloc");
1306 return this;
1309 void *spudec_new(unsigned int *palette)
1311 return spudec_new_scaled(palette, 0, 0, NULL, 0);
1314 void spudec_free(void *this)
1316 spudec_handle_t *spu = this;
1317 if (spu) {
1318 while (spu->queue_head)
1319 spudec_free_packet(spudec_dequeue_packet(spu));
1320 free(spu->packet);
1321 spu->packet = NULL;
1322 free(spu->scaled_image);
1323 spu->scaled_image = NULL;
1324 free(spu->image);
1325 spu->image = NULL;
1326 spu->aimage = NULL;
1327 free(spu->pal_image);
1328 spu->pal_image = NULL;
1329 spu->image_size = 0;
1330 spu->pal_width = spu->pal_height = 0;
1331 free(spu);
1335 void spudec_set_hw_spu(void *this, struct vo *hw_spu)
1337 spudec_handle_t *spu = this;
1338 if (!spu)
1339 return;
1340 spu->hw_spu = hw_spu;
1341 vo_control(hw_spu, VOCTRL_SET_SPU_PALETTE, spu->global_palette);
1345 * palette must contain at least 256 32-bit entries, otherwise crashes
1346 * are possible
1348 void spudec_set_paletted(void *this, const uint8_t *pal_img, int pal_stride,
1349 const void *palette,
1350 int x, int y, int w, int h,
1351 double pts, double endpts)
1353 int i;
1354 uint16_t g8a8_pal[256];
1355 packet_t *packet;
1356 const uint32_t *pal = palette;
1357 spudec_handle_t *spu = this;
1358 uint8_t *img;
1359 uint8_t *aimg;
1360 int stride = (w + 7) & ~7;
1361 if ((unsigned)w >= 0x8000 || (unsigned)h > 0x4000)
1362 return;
1363 packet = calloc(1, sizeof(packet_t));
1364 packet->is_decoded = 1;
1365 packet->width = w;
1366 packet->height = h;
1367 packet->stride = stride;
1368 packet->start_col = x;
1369 packet->start_row = y;
1370 packet->data_len = 2 * stride * h;
1371 if (packet->data_len) { // size 0 is a special "clear" packet
1372 packet->packet = malloc(packet->data_len);
1373 img = packet->packet;
1374 aimg = packet->packet + stride * h;
1375 for (i = 0; i < 256; i++) {
1376 uint32_t pixel = pal[i];
1377 int alpha = pixel >> 24;
1378 int gray = (((pixel & 0x000000ff) >> 0) +
1379 ((pixel & 0x0000ff00) >> 7) +
1380 ((pixel & 0x00ff0000) >> 16)) >> 2;
1381 gray = FFMIN(gray, alpha);
1382 g8a8_pal[i] = (-alpha << 8) | gray;
1384 pal2gray_alpha(g8a8_pal, pal_img, pal_stride,
1385 img, aimg, stride, w, h);
1387 packet->start_pts = 0;
1388 packet->end_pts = 0x7fffffff;
1389 if (pts != MP_NOPTS_VALUE)
1390 packet->start_pts = pts * 90000;
1391 if (endpts != MP_NOPTS_VALUE)
1392 packet->end_pts = endpts * 90000;
1393 spudec_queue_packet(spu, packet);