stream/tv: move new_handle() function from header to tv.c
[mplayer/greg.git] / spudec.c
blob5e39846fe6cb645e9b63d283cdcfc0a674a9809e
1 /*
2 * Skeleton of function spudec_process_controll() is from xine sources.
3 * Further works:
4 * LGB,... (yeah, try to improve it and insert your name here! ;-)
6 * Kim Minh Kaplan
7 * implement fragments reassembly, RLE decoding.
8 * read brightness from the IFO.
10 * For information on SPU format see <URL:http://sam.zoy.org/doc/dvd/subtitles/>
11 * and <URL:http://members.aol.com/mpucoder/DVD/spu.html>
13 * This file is part of MPlayer.
15 * MPlayer is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
20 * MPlayer is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License along
26 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
27 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
30 #include "config.h"
31 #include "mp_msg.h"
33 #include <errno.h>
34 #include <limits.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <unistd.h>
38 #include <string.h>
39 #include <math.h>
40 #include "libvo/video_out.h"
41 #include "spudec.h"
42 #include "vobsub.h"
43 #include "libavutil/avutil.h"
44 #include "ffmpeg_files/intreadwrite.h"
45 #include "libswscale/swscale.h"
47 /* Valid values for spu_aamode:
48 0: none (fastest, most ugly)
49 1: approximate
50 2: full (slowest)
51 3: bilinear (similiar to vobsub, fast and not too bad)
52 4: uses swscaler gaussian (this is the only one that looks good)
55 int spu_aamode = 3;
56 int spu_alignment = -1;
57 float spu_gaussvar = 1.0;
58 extern int sub_pos;
60 typedef struct packet_t packet_t;
61 struct packet_t {
62 int is_decoded;
63 unsigned char *packet;
64 int data_len;
65 unsigned int palette[4];
66 unsigned int alpha[4];
67 unsigned int control_start; /* index of start of control data */
68 unsigned int current_nibble[2]; /* next data nibble (4 bits) to be
69 processed (for RLE decoding) for
70 even and odd lines */
71 int deinterlace_oddness; /* 0 or 1, index into current_nibble */
72 unsigned int start_col;
73 unsigned int start_row;
74 unsigned int width, height, stride;
75 unsigned int start_pts, end_pts;
76 packet_t *next;
79 struct palette_crop_cache {
80 int valid;
81 uint32_t palette;
82 int sx, sy, ex, ey;
83 int result;
86 typedef struct {
87 packet_t *queue_head;
88 packet_t *queue_tail;
89 unsigned int global_palette[16];
90 unsigned int orig_frame_width, orig_frame_height;
91 unsigned char* packet;
92 size_t packet_reserve; /* size of the memory pointed to by packet */
93 unsigned int packet_offset; /* end of the currently assembled fragment */
94 unsigned int packet_size; /* size of the packet once all fragments are assembled */
95 int packet_pts; /* PTS for this packet */
96 unsigned int palette[4];
97 unsigned int alpha[4];
98 unsigned int cuspal[4];
99 unsigned int custom;
100 unsigned int now_pts;
101 unsigned int start_pts, end_pts;
102 unsigned int start_col;
103 unsigned int start_row;
104 unsigned int width, height, stride;
105 size_t image_size; /* Size of the image buffer */
106 unsigned char *image; /* Grayscale value */
107 unsigned char *aimage; /* Alpha value */
108 unsigned int pal_start_col, pal_start_row;
109 unsigned int pal_width, pal_height;
110 unsigned char *pal_image; /* palette entry value */
111 unsigned int scaled_frame_width, scaled_frame_height;
112 unsigned int scaled_start_col, scaled_start_row;
113 unsigned int scaled_width, scaled_height, scaled_stride;
114 size_t scaled_image_size;
115 unsigned char *scaled_image;
116 unsigned char *scaled_aimage;
117 int auto_palette; /* 1 if we lack a palette and must use an heuristic. */
118 int font_start_level; /* Darkest value used for the computed font */
119 struct vo *hw_spu;
120 int spu_changed;
121 unsigned int forced_subs_only; /* flag: 0=display all subtitle, !0 display only forced subtitles */
122 unsigned int is_forced_sub; /* true if current subtitle is a forced subtitle */
124 struct palette_crop_cache palette_crop_cache;
125 } spudec_handle_t;
127 static void spudec_queue_packet(spudec_handle_t *this, packet_t *packet)
129 if (this->queue_head == NULL)
130 this->queue_head = packet;
131 else
132 this->queue_tail->next = packet;
133 this->queue_tail = packet;
136 static packet_t *spudec_dequeue_packet(spudec_handle_t *this)
138 packet_t *retval = this->queue_head;
140 this->queue_head = retval->next;
141 if (this->queue_head == NULL)
142 this->queue_tail = NULL;
144 return retval;
147 static void spudec_free_packet(packet_t *packet)
149 if (packet->packet != NULL)
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 if (spu->packet != NULL)
613 free(spu->packet);
614 spu->packet = malloc(len2);
615 spu->packet_reserve = spu->packet != NULL ? len2 : 0;
617 if (spu->packet != NULL) {
618 spu->packet_size = len2;
619 if (len > len2) {
620 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: invalid frag len / len2: %d / %d \n", len, len2);
621 return;
623 memcpy(spu->packet, packet, len);
624 spu->packet_offset = len;
625 spu->packet_pts = pts100;
627 } else {
628 // Continue current fragment
629 if (spu->packet_size < spu->packet_offset + len){
630 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: invalid fragment\n");
631 spu->packet_size = spu->packet_offset = 0;
632 return;
633 } else {
634 memcpy(spu->packet + spu->packet_offset, packet, len);
635 spu->packet_offset += len;
638 #if 1
639 // check if we have a complete packet (unfortunatelly packet_size is bad
640 // for some disks)
641 // [cb] packet_size is padded to be even -> may be one byte too long
642 if ((spu->packet_offset == spu->packet_size) ||
643 ((spu->packet_offset + 1) == spu->packet_size)){
644 unsigned int x=0,y;
645 while(x+4<=spu->packet_offset){
646 y=get_be16(spu->packet+x+2); // next control pointer
647 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPUtest: x=%d y=%d off=%d size=%d\n",x,y,spu->packet_offset,spu->packet_size);
648 if(x>=4 && x==y){ // if it points to self - we're done!
649 // we got it!
650 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPUgot: off=%d size=%d \n",spu->packet_offset,spu->packet_size);
651 spudec_decode(spu, pts100);
652 spu->packet_offset = 0;
653 break;
655 if(y<=x || y>=spu->packet_size){ // invalid?
656 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUtest: broken packet!!!!! y=%d < x=%d\n",y,x);
657 spu->packet_size = spu->packet_offset = 0;
658 break;
660 x=y;
662 // [cb] packet is done; start new packet
663 spu->packet_offset = 0;
665 #else
666 if (spu->packet_offset == spu->packet_size) {
667 spudec_decode(spu, pts100);
668 spu->packet_offset = 0;
670 #endif
673 void spudec_reset(void *this) // called after seek
675 spudec_handle_t *spu = this;
676 while (spu->queue_head)
677 spudec_free_packet(spudec_dequeue_packet(spu));
678 spu->now_pts = 0;
679 spu->end_pts = 0;
680 spu->packet_size = spu->packet_offset = 0;
683 void spudec_heartbeat(void *this, unsigned int pts100)
685 spudec_handle_t *spu = this;
686 spu->now_pts = pts100;
688 // TODO: detect and handle broken timestamps (e.g. due to wrapping)
689 while (spu->queue_head != NULL && pts100 >= spu->queue_head->start_pts) {
690 packet_t *packet = spudec_dequeue_packet(spu);
691 spu->start_pts = packet->start_pts;
692 spu->end_pts = packet->end_pts;
693 if (packet->is_decoded) {
694 free(spu->image);
695 spu->image_size = packet->data_len;
696 spu->image = packet->packet;
697 spu->aimage = packet->packet + packet->stride * packet->height;
698 packet->packet = NULL;
699 spu->width = packet->width;
700 spu->height = packet->height;
701 spu->stride = packet->stride;
702 spu->start_col = packet->start_col;
703 spu->start_row = packet->start_row;
705 // reset scaled image
706 spu->scaled_frame_width = 0;
707 spu->scaled_frame_height = 0;
708 } else {
709 if (spu->auto_palette)
710 compute_palette(spu, packet);
711 spudec_process_data(spu, packet);
713 spudec_free_packet(packet);
714 spu->spu_changed = 1;
718 int spudec_visible(void *this){
719 spudec_handle_t *spu = this;
720 int ret=(spu->start_pts <= spu->now_pts &&
721 spu->now_pts < spu->end_pts &&
722 spu->height > 0);
723 // printf("spu visible: %d \n",ret);
724 return ret;
727 void spudec_set_forced_subs_only(void * const this, const unsigned int flag)
729 if(this){
730 ((spudec_handle_t *)this)->forced_subs_only=flag;
731 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPU: Display only forced subs now %s\n", flag ? "enabled": "disabled");
735 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)
737 spudec_handle_t *spu = this;
738 if (spudec_visible(spu))
740 draw_alpha(ctx, spu->start_col, spu->start_row, spu->width, spu->height,
741 spu->image, spu->aimage, spu->stride);
742 spu->spu_changed = 0;
746 /* calc the bbox for spudec subs */
747 void spudec_calc_bbox(void *me, unsigned int dxs, unsigned int dys, unsigned int* bbox)
749 spudec_handle_t *spu = me;
750 if (spu->orig_frame_width == 0 || spu->orig_frame_height == 0
751 || (spu->orig_frame_width == dxs && spu->orig_frame_height == dys)) {
752 // unscaled
753 bbox[0] = spu->start_col;
754 bbox[1] = spu->start_col + spu->width;
755 bbox[2] = spu->start_row;
756 bbox[3] = spu->start_row + spu->height;
758 else {
759 // scaled
760 unsigned int scalex = 0x100 * dxs / spu->orig_frame_width;
761 unsigned int scaley = 0x100 * dys / spu->orig_frame_height;
762 bbox[0] = spu->start_col * scalex / 0x100;
763 bbox[1] = spu->start_col * scalex / 0x100 + spu->width * scalex / 0x100;
764 switch (spu_alignment) {
765 case 0:
766 bbox[3] = dys*sub_pos/100 + spu->height * scaley / 0x100;
767 if (bbox[3] > dys) bbox[3] = dys;
768 bbox[2] = bbox[3] - spu->height * scaley / 0x100;
769 break;
770 case 1:
771 if (sub_pos < 50) {
772 bbox[2] = dys*sub_pos/100 - spu->height * scaley / 0x200;
773 bbox[3] = bbox[2] + spu->height;
774 } else {
775 bbox[3] = dys*sub_pos/100 + spu->height * scaley / 0x200;
776 if (bbox[3] > dys) bbox[3] = dys;
777 bbox[2] = bbox[3] - spu->height * scaley / 0x100;
779 break;
780 case 2:
781 bbox[2] = dys*sub_pos/100 - spu->height * scaley / 0x100;
782 bbox[3] = bbox[2] + spu->height;
783 break;
784 default: /* -1 */
785 bbox[2] = spu->start_row * scaley / 0x100;
786 bbox[3] = spu->start_row * scaley / 0x100 + spu->height * scaley / 0x100;
787 break;
791 /* transform mplayer's alpha value into an opacity value that is linear */
792 static inline int canon_alpha(int alpha)
794 return (uint8_t)-alpha;
797 typedef struct {
798 unsigned position;
799 unsigned left_up;
800 unsigned right_down;
801 }scale_pixel;
804 static void scale_table(unsigned int start_src, unsigned int start_tar, unsigned int end_src, unsigned int end_tar, scale_pixel * table)
806 unsigned int t;
807 unsigned int delta_src = end_src - start_src;
808 unsigned int delta_tar = end_tar - start_tar;
809 int src = 0;
810 int src_step;
811 if (delta_src == 0 || delta_tar == 0) {
812 return;
814 src_step = (delta_src << 16) / delta_tar >>1;
815 for (t = 0; t<=delta_tar; src += (src_step << 1), t++){
816 table[t].position= FFMIN(src >> 16, end_src - 1);
817 table[t].right_down = src & 0xffff;
818 table[t].left_up = 0x10000 - table[t].right_down;
822 /* bilinear scale, similar to vobsub's code */
823 static void scale_image(int x, int y, scale_pixel* table_x, scale_pixel* table_y, spudec_handle_t * spu)
825 int alpha[4];
826 int color[4];
827 unsigned int scale[4];
828 int base = table_y[y].position * spu->stride + table_x[x].position;
829 int scaled = y * spu->scaled_stride + x;
830 alpha[0] = canon_alpha(spu->aimage[base]);
831 alpha[1] = canon_alpha(spu->aimage[base + 1]);
832 alpha[2] = canon_alpha(spu->aimage[base + spu->stride]);
833 alpha[3] = canon_alpha(spu->aimage[base + spu->stride + 1]);
834 color[0] = spu->image[base];
835 color[1] = spu->image[base + 1];
836 color[2] = spu->image[base + spu->stride];
837 color[3] = spu->image[base + spu->stride + 1];
838 scale[0] = (table_x[x].left_up * table_y[y].left_up >> 16) * alpha[0];
839 if (table_y[y].left_up == 0x10000) // necessary to avoid overflow-case
840 scale[0] = table_x[x].left_up * alpha[0];
841 scale[1] = (table_x[x].right_down * table_y[y].left_up >>16) * alpha[1];
842 scale[2] = (table_x[x].left_up * table_y[y].right_down >> 16) * alpha[2];
843 scale[3] = (table_x[x].right_down * table_y[y].right_down >> 16) * alpha[3];
844 spu->scaled_image[scaled] = (color[0] * scale[0] + color[1] * scale[1] + color[2] * scale[2] + color[3] * scale[3])>>24;
845 spu->scaled_aimage[scaled] = (scale[0] + scale[1] + scale[2] + scale[3]) >> 16;
846 if (spu->scaled_aimage[scaled]){
847 // ensure that MPlayer's simplified alpha-blending can not overflow
848 spu->scaled_image[scaled] = FFMIN(spu->scaled_image[scaled], spu->scaled_aimage[scaled]);
849 // convert to MPlayer-style alpha
850 spu->scaled_aimage[scaled] = -spu->scaled_aimage[scaled];
854 static void sws_spu_image(unsigned char *d1, unsigned char *d2, int dw, int dh,
855 int ds, const unsigned char* s1, unsigned char* s2,
856 int sw, int sh, int ss)
858 struct SwsContext *ctx;
859 static SwsFilter filter;
860 static int firsttime = 1;
861 static float oldvar;
862 int i;
864 if (!firsttime && oldvar != spu_gaussvar) sws_freeVec(filter.lumH);
865 if (firsttime) {
866 filter.lumH = filter.lumV =
867 filter.chrH = filter.chrV = sws_getGaussianVec(spu_gaussvar, 3.0);
868 sws_normalizeVec(filter.lumH, 1.0);
869 firsttime = 0;
870 oldvar = spu_gaussvar;
873 ctx=sws_getContext(sw, sh, PIX_FMT_GRAY8, dw, dh, PIX_FMT_GRAY8, SWS_GAUSS, &filter, NULL, NULL);
874 sws_scale(ctx,&s1,&ss,0,sh,&d1,&ds);
875 for (i=ss*sh-1; i>=0; i--) if (!s2[i]) s2[i] = 255; //else s2[i] = 1;
876 sws_scale(ctx,&s2,&ss,0,sh,&d2,&ds);
877 for (i=ds*dh-1; i>=0; i--) if (d2[i]==0) d2[i] = 1; else if (d2[i]==255) d2[i] = 0;
878 sws_freeContext(ctx);
881 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)
883 spudec_handle_t *spu = me;
884 scale_pixel *table_x;
885 scale_pixel *table_y;
887 if (spudec_visible(spu)) {
889 // check if only forced subtitles are requested
890 if( (spu->forced_subs_only) && !(spu->is_forced_sub) ){
891 return;
894 if (!(spu_aamode&16) && (spu->orig_frame_width == 0 || spu->orig_frame_height == 0
895 || (spu->orig_frame_width == dxs && spu->orig_frame_height == dys))) {
896 spudec_draw(spu, draw_alpha, ctx);
898 else {
899 if (spu->scaled_frame_width != dxs || spu->scaled_frame_height != dys) { /* Resizing is needed */
900 /* scaled_x = scalex * x / 0x100
901 scaled_y = scaley * y / 0x100
902 order of operations is important because of rounding. */
903 unsigned int scalex = 0x100 * dxs / spu->orig_frame_width;
904 unsigned int scaley = 0x100 * dys / spu->orig_frame_height;
905 spu->scaled_start_col = spu->start_col * scalex / 0x100;
906 spu->scaled_start_row = spu->start_row * scaley / 0x100;
907 spu->scaled_width = spu->width * scalex / 0x100;
908 spu->scaled_height = spu->height * scaley / 0x100;
909 /* Kludge: draw_alpha needs width multiple of 8 */
910 spu->scaled_stride = (spu->scaled_width + 7) & ~7;
911 if (spu->scaled_image_size < spu->scaled_stride * spu->scaled_height) {
912 if (spu->scaled_image) {
913 free(spu->scaled_image);
914 spu->scaled_image_size = 0;
916 spu->scaled_image = malloc(2 * spu->scaled_stride * spu->scaled_height);
917 if (spu->scaled_image) {
918 spu->scaled_image_size = spu->scaled_stride * spu->scaled_height;
919 spu->scaled_aimage = spu->scaled_image + spu->scaled_image_size;
922 if (spu->scaled_image) {
923 unsigned int x, y;
924 if (spu->scaled_width <= 1 || spu->scaled_height <= 1) {
925 goto nothing_to_do;
927 switch(spu_aamode&15) {
928 case 4:
929 sws_spu_image(spu->scaled_image, spu->scaled_aimage,
930 spu->scaled_width, spu->scaled_height, spu->scaled_stride,
931 spu->image, spu->aimage, spu->width, spu->height, spu->stride);
932 break;
933 case 3:
934 table_x = calloc(spu->scaled_width, sizeof(scale_pixel));
935 table_y = calloc(spu->scaled_height, sizeof(scale_pixel));
936 if (!table_x || !table_y) {
937 mp_msg(MSGT_SPUDEC, MSGL_FATAL, "Fatal: spudec_draw_scaled: calloc failed\n");
939 scale_table(0, 0, spu->width - 1, spu->scaled_width - 1, table_x);
940 scale_table(0, 0, spu->height - 1, spu->scaled_height - 1, table_y);
941 for (y = 0; y < spu->scaled_height; y++)
942 for (x = 0; x < spu->scaled_width; x++)
943 scale_image(x, y, table_x, table_y, spu);
944 free(table_x);
945 free(table_y);
946 break;
947 case 0:
948 /* no antialiasing */
949 for (y = 0; y < spu->scaled_height; ++y) {
950 int unscaled_y = y * 0x100 / scaley;
951 int strides = spu->stride * unscaled_y;
952 int scaled_strides = spu->scaled_stride * y;
953 for (x = 0; x < spu->scaled_width; ++x) {
954 int unscaled_x = x * 0x100 / scalex;
955 spu->scaled_image[scaled_strides + x] = spu->image[strides + unscaled_x];
956 spu->scaled_aimage[scaled_strides + x] = spu->aimage[strides + unscaled_x];
959 break;
960 case 1:
962 /* Intermediate antialiasing. */
963 for (y = 0; y < spu->scaled_height; ++y) {
964 const unsigned int unscaled_top = y * spu->orig_frame_height / dys;
965 unsigned int unscaled_bottom = (y + 1) * spu->orig_frame_height / dys;
966 if (unscaled_bottom >= spu->height)
967 unscaled_bottom = spu->height - 1;
968 for (x = 0; x < spu->scaled_width; ++x) {
969 const unsigned int unscaled_left = x * spu->orig_frame_width / dxs;
970 unsigned int unscaled_right = (x + 1) * spu->orig_frame_width / dxs;
971 unsigned int color = 0;
972 unsigned int alpha = 0;
973 unsigned int walkx, walky;
974 unsigned int base, tmp;
975 if (unscaled_right >= spu->width)
976 unscaled_right = spu->width - 1;
977 for (walky = unscaled_top; walky <= unscaled_bottom; ++walky)
978 for (walkx = unscaled_left; walkx <= unscaled_right; ++walkx) {
979 base = walky * spu->stride + walkx;
980 tmp = canon_alpha(spu->aimage[base]);
981 alpha += tmp;
982 color += tmp * spu->image[base];
984 base = y * spu->scaled_stride + x;
985 spu->scaled_image[base] = alpha ? color / alpha : 0;
986 spu->scaled_aimage[base] =
987 alpha * (1 + unscaled_bottom - unscaled_top) * (1 + unscaled_right - unscaled_left);
988 /* spu->scaled_aimage[base] =
989 alpha * dxs * dys / spu->orig_frame_width / spu->orig_frame_height; */
990 if (spu->scaled_aimage[base]) {
991 spu->scaled_aimage[base] = 256 - spu->scaled_aimage[base];
992 if (spu->scaled_aimage[base] + spu->scaled_image[base] > 255)
993 spu->scaled_image[base] = 256 - spu->scaled_aimage[base];
998 break;
999 case 2:
1001 /* Best antialiasing. Very slow. */
1002 /* Any pixel (x, y) represents pixels from the original
1003 rectangular region comprised between the columns
1004 unscaled_y and unscaled_y + 0x100 / scaley and the rows
1005 unscaled_x and unscaled_x + 0x100 / scalex
1007 The original rectangular region that the scaled pixel
1008 represents is cut in 9 rectangular areas like this:
1010 +---+-----------------+---+
1011 | 1 | 2 | 3 |
1012 +---+-----------------+---+
1013 | | | |
1014 | 4 | 5 | 6 |
1015 | | | |
1016 +---+-----------------+---+
1017 | 7 | 8 | 9 |
1018 +---+-----------------+---+
1020 The width of the left column is at most one pixel and
1021 it is never null and its right column is at a pixel
1022 boundary. The height of the top row is at most one
1023 pixel it is never null and its bottom row is at a
1024 pixel boundary. The width and height of region 5 are
1025 integral values. The width of the right column is
1026 what remains and is less than one pixel. The height
1027 of the bottom row is what remains and is less than
1028 one pixel.
1030 The row above 1, 2, 3 is unscaled_y. The row between
1031 1, 2, 3 and 4, 5, 6 is top_low_row. The row between 4,
1032 5, 6 and 7, 8, 9 is (unsigned int)unscaled_y_bottom.
1033 The row beneath 7, 8, 9 is unscaled_y_bottom.
1035 The column left of 1, 4, 7 is unscaled_x. The column
1036 between 1, 4, 7 and 2, 5, 8 is left_right_column. The
1037 column between 2, 5, 8 and 3, 6, 9 is (unsigned
1038 int)unscaled_x_right. The column right of 3, 6, 9 is
1039 unscaled_x_right. */
1040 const double inv_scalex = (double) 0x100 / scalex;
1041 const double inv_scaley = (double) 0x100 / scaley;
1042 for (y = 0; y < spu->scaled_height; ++y) {
1043 const double unscaled_y = y * inv_scaley;
1044 const double unscaled_y_bottom = unscaled_y + inv_scaley;
1045 const unsigned int top_low_row = FFMIN(unscaled_y_bottom, unscaled_y + 1.0);
1046 const double top = top_low_row - unscaled_y;
1047 const unsigned int height = unscaled_y_bottom > top_low_row
1048 ? (unsigned int) unscaled_y_bottom - top_low_row
1049 : 0;
1050 const double bottom = unscaled_y_bottom > top_low_row
1051 ? unscaled_y_bottom - floor(unscaled_y_bottom)
1052 : 0.0;
1053 for (x = 0; x < spu->scaled_width; ++x) {
1054 const double unscaled_x = x * inv_scalex;
1055 const double unscaled_x_right = unscaled_x + inv_scalex;
1056 const unsigned int left_right_column = FFMIN(unscaled_x_right, unscaled_x + 1.0);
1057 const double left = left_right_column - unscaled_x;
1058 const unsigned int width = unscaled_x_right > left_right_column
1059 ? (unsigned int) unscaled_x_right - left_right_column
1060 : 0;
1061 const double right = unscaled_x_right > left_right_column
1062 ? unscaled_x_right - floor(unscaled_x_right)
1063 : 0.0;
1064 double color = 0.0;
1065 double alpha = 0.0;
1066 double tmp;
1067 unsigned int base;
1068 /* Now use these informations to compute a good alpha,
1069 and lightness. The sum is on each of the 9
1070 region's surface and alpha and lightness.
1072 transformed alpha = sum(surface * alpha) / sum(surface)
1073 transformed color = sum(surface * alpha * color) / sum(surface * alpha)
1075 /* 1: top left part */
1076 base = spu->stride * (unsigned int) unscaled_y;
1077 tmp = left * top * canon_alpha(spu->aimage[base + (unsigned int) unscaled_x]);
1078 alpha += tmp;
1079 color += tmp * spu->image[base + (unsigned int) unscaled_x];
1080 /* 2: top center part */
1081 if (width > 0) {
1082 unsigned int walkx;
1083 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
1084 base = spu->stride * (unsigned int) unscaled_y + walkx;
1085 tmp = /* 1.0 * */ top * canon_alpha(spu->aimage[base]);
1086 alpha += tmp;
1087 color += tmp * spu->image[base];
1090 /* 3: top right part */
1091 if (right > 0.0) {
1092 base = spu->stride * (unsigned int) unscaled_y + (unsigned int) unscaled_x_right;
1093 tmp = right * top * canon_alpha(spu->aimage[base]);
1094 alpha += tmp;
1095 color += tmp * spu->image[base];
1097 /* 4: center left part */
1098 if (height > 0) {
1099 unsigned int walky;
1100 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1101 base = spu->stride * walky + (unsigned int) unscaled_x;
1102 tmp = left /* * 1.0 */ * canon_alpha(spu->aimage[base]);
1103 alpha += tmp;
1104 color += tmp * spu->image[base];
1107 /* 5: center part */
1108 if (width > 0 && height > 0) {
1109 unsigned int walky;
1110 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1111 unsigned int walkx;
1112 base = spu->stride * walky;
1113 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
1114 tmp = /* 1.0 * 1.0 * */ canon_alpha(spu->aimage[base + walkx]);
1115 alpha += tmp;
1116 color += tmp * spu->image[base + walkx];
1120 /* 6: center right part */
1121 if (right > 0.0 && height > 0) {
1122 unsigned int walky;
1123 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1124 base = spu->stride * walky + (unsigned int) unscaled_x_right;
1125 tmp = right /* * 1.0 */ * canon_alpha(spu->aimage[base]);
1126 alpha += tmp;
1127 color += tmp * spu->image[base];
1130 /* 7: bottom left part */
1131 if (bottom > 0.0) {
1132 base = spu->stride * (unsigned int) unscaled_y_bottom + (unsigned int) unscaled_x;
1133 tmp = left * bottom * canon_alpha(spu->aimage[base]);
1134 alpha += tmp;
1135 color += tmp * spu->image[base];
1137 /* 8: bottom center part */
1138 if (width > 0 && bottom > 0.0) {
1139 unsigned int walkx;
1140 base = spu->stride * (unsigned int) unscaled_y_bottom;
1141 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
1142 tmp = /* 1.0 * */ bottom * canon_alpha(spu->aimage[base + walkx]);
1143 alpha += tmp;
1144 color += tmp * spu->image[base + walkx];
1147 /* 9: bottom right part */
1148 if (right > 0.0 && bottom > 0.0) {
1149 base = spu->stride * (unsigned int) unscaled_y_bottom + (unsigned int) unscaled_x_right;
1150 tmp = right * bottom * canon_alpha(spu->aimage[base]);
1151 alpha += tmp;
1152 color += tmp * spu->image[base];
1154 /* Finally mix these transparency and brightness information suitably */
1155 base = spu->scaled_stride * y + x;
1156 spu->scaled_image[base] = alpha > 0 ? color / alpha : 0;
1157 spu->scaled_aimage[base] = alpha * scalex * scaley / 0x10000;
1158 if (spu->scaled_aimage[base]) {
1159 spu->scaled_aimage[base] = 256 - spu->scaled_aimage[base];
1160 if (spu->scaled_aimage[base] + spu->scaled_image[base] > 255)
1161 spu->scaled_image[base] = 256 - spu->scaled_aimage[base];
1167 nothing_to_do:
1168 /* Kludge: draw_alpha needs width multiple of 8. */
1169 if (spu->scaled_width < spu->scaled_stride)
1170 for (y = 0; y < spu->scaled_height; ++y) {
1171 memset(spu->scaled_aimage + y * spu->scaled_stride + spu->scaled_width, 0,
1172 spu->scaled_stride - spu->scaled_width);
1174 spu->scaled_frame_width = dxs;
1175 spu->scaled_frame_height = dys;
1178 if (spu->scaled_image){
1179 switch (spu_alignment) {
1180 case 0:
1181 spu->scaled_start_row = dys*sub_pos/100;
1182 if (spu->scaled_start_row + spu->scaled_height > dys)
1183 spu->scaled_start_row = dys - spu->scaled_height;
1184 break;
1185 case 1:
1186 spu->scaled_start_row = dys*sub_pos/100 - spu->scaled_height/2;
1187 if (sub_pos >= 50 && spu->scaled_start_row + spu->scaled_height > dys)
1188 spu->scaled_start_row = dys - spu->scaled_height;
1189 break;
1190 case 2:
1191 spu->scaled_start_row = dys*sub_pos/100 - spu->scaled_height;
1192 break;
1194 draw_alpha(ctx, spu->scaled_start_col, spu->scaled_start_row, spu->scaled_width, spu->scaled_height,
1195 spu->scaled_image, spu->scaled_aimage, spu->scaled_stride);
1196 spu->spu_changed = 0;
1200 else
1202 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPU not displayed: start_pts=%d end_pts=%d now_pts=%d\n",
1203 spu->start_pts, spu->end_pts, spu->now_pts);
1207 void spudec_update_palette(void * this, unsigned int *palette)
1209 spudec_handle_t *spu = this;
1210 if (spu && palette) {
1211 memcpy(spu->global_palette, palette, sizeof(spu->global_palette));
1212 if(spu->hw_spu)
1213 vo_control(spu->hw_spu, VOCTRL_SET_SPU_PALETTE, spu->global_palette);
1217 void spudec_set_font_factor(void * this, double factor)
1219 spudec_handle_t *spu = this;
1220 spu->font_start_level = (int)(0xF0-(0xE0*factor));
1223 static void spudec_parse_extradata(spudec_handle_t *this,
1224 uint8_t *extradata, int extradata_len)
1226 uint8_t *buffer, *ptr;
1227 unsigned int *pal = this->global_palette, *cuspal = this->cuspal;
1228 unsigned int tridx;
1229 int i;
1231 if (extradata_len == 16*4) {
1232 for (i=0; i<16; i++)
1233 pal[i] = AV_RB32(extradata + i*4);
1234 this->auto_palette = 0;
1235 return;
1238 if (!(ptr = buffer = malloc(extradata_len+1)))
1239 return;
1240 memcpy(buffer, extradata, extradata_len);
1241 buffer[extradata_len] = 0;
1243 do {
1244 if (*ptr == '#')
1245 continue;
1246 if (!strncmp(ptr, "size: ", 6))
1247 sscanf(ptr + 6, "%dx%d", &this->orig_frame_width, &this->orig_frame_height);
1248 if (!strncmp(ptr, "palette: ", 9) &&
1249 sscanf(ptr + 9, "%x, %x, %x, %x, %x, %x, %x, %x, "
1250 "%x, %x, %x, %x, %x, %x, %x, %x",
1251 &pal[ 0], &pal[ 1], &pal[ 2], &pal[ 3],
1252 &pal[ 4], &pal[ 5], &pal[ 6], &pal[ 7],
1253 &pal[ 8], &pal[ 9], &pal[10], &pal[11],
1254 &pal[12], &pal[13], &pal[14], &pal[15]) == 16) {
1255 for (i=0; i<16; i++)
1256 pal[i] = vobsub_palette_to_yuv(pal[i]);
1257 this->auto_palette = 0;
1259 if (!strncasecmp(ptr, "forced subs: on", 15))
1260 this->forced_subs_only = 1;
1261 if (!strncmp(ptr, "custom colors: ON, tridx: ", 26) &&
1262 sscanf(ptr + 26, "%x, colors: %x, %x, %x, %x",
1263 &tridx, cuspal+0, cuspal+1, cuspal+2, cuspal+3) == 5) {
1264 for (i=0; i<4; i++) {
1265 cuspal[i] = vobsub_rgb_to_yuv(cuspal[i]);
1266 if (tridx & (1 << (12-4*i)))
1267 cuspal[i] |= 1 << 31;
1269 this->custom = 1;
1271 } while ((ptr=strchr(ptr,'\n')) && *++ptr);
1273 free(buffer);
1276 void *spudec_new_scaled(unsigned int *palette, unsigned int frame_width, unsigned int frame_height, uint8_t *extradata, int extradata_len)
1278 spudec_handle_t *this = calloc(1, sizeof(spudec_handle_t));
1279 if (this){
1280 this->orig_frame_height = frame_height;
1281 this->orig_frame_width = frame_width;
1282 // set up palette:
1283 if (palette)
1284 memcpy(this->global_palette, palette, sizeof(this->global_palette));
1285 else
1286 this->auto_palette = 1;
1287 if (extradata)
1288 spudec_parse_extradata(this, extradata, extradata_len);
1289 /* XXX Although the video frame is some size, the SPU frame is
1290 always maximum size i.e. 720 wide and 576 or 480 high */
1291 // For HD files in MKV the VobSub resolution can be higher though,
1292 // see largeres_vobsub.mkv
1293 if (this->orig_frame_width <= 720 && this->orig_frame_height <= 576) {
1294 this->orig_frame_width = 720;
1295 if (this->orig_frame_height == 480 || this->orig_frame_height == 240)
1296 this->orig_frame_height = 480;
1297 else
1298 this->orig_frame_height = 576;
1301 else
1302 mp_msg(MSGT_SPUDEC,MSGL_FATAL, "FATAL: spudec_init: calloc");
1303 return this;
1306 void *spudec_new(unsigned int *palette)
1308 return spudec_new_scaled(palette, 0, 0, NULL, 0);
1311 void spudec_free(void *this)
1313 spudec_handle_t *spu = this;
1314 if (spu) {
1315 while (spu->queue_head)
1316 spudec_free_packet(spudec_dequeue_packet(spu));
1317 free(spu->packet);
1318 spu->packet = NULL;
1319 free(spu->scaled_image);
1320 spu->scaled_image = NULL;
1321 free(spu->image);
1322 spu->image = NULL;
1323 spu->aimage = NULL;
1324 free(spu->pal_image);
1325 spu->pal_image = NULL;
1326 spu->image_size = 0;
1327 spu->pal_width = spu->pal_height = 0;
1328 free(spu);
1332 void spudec_set_hw_spu(void *this, struct vo *hw_spu)
1334 spudec_handle_t *spu = this;
1335 if (!spu)
1336 return;
1337 spu->hw_spu = hw_spu;
1338 vo_control(hw_spu, VOCTRL_SET_SPU_PALETTE, spu->global_palette);
1341 #define MP_NOPTS_VALUE (-1LL<<63) //both int64_t and double should be able to represent this exactly
1344 * palette must contain at least 256 32-bit entries, otherwise crashes
1345 * are possible
1347 void spudec_set_paletted(void *this, const uint8_t *pal_img, int pal_stride,
1348 const void *palette,
1349 int x, int y, int w, int h,
1350 double pts, double endpts)
1352 int i;
1353 uint16_t g8a8_pal[256];
1354 packet_t *packet;
1355 const uint32_t *pal = palette;
1356 spudec_handle_t *spu = this;
1357 uint8_t *img;
1358 uint8_t *aimg;
1359 int stride = (w + 7) & ~7;
1360 if ((unsigned)w >= 0x8000 || (unsigned)h > 0x4000)
1361 return;
1362 packet = calloc(1, sizeof(packet_t));
1363 packet->is_decoded = 1;
1364 packet->width = w;
1365 packet->height = h;
1366 packet->stride = stride;
1367 packet->start_col = x;
1368 packet->start_row = y;
1369 packet->data_len = 2 * stride * h;
1370 packet->packet = malloc(packet->data_len);
1371 img = packet->packet;
1372 aimg = packet->packet + stride * h;
1373 for (i = 0; i < 256; i++) {
1374 uint32_t pixel = pal[i];
1375 int alpha = pixel >> 24;
1376 int gray = (((pixel & 0x000000ff) >> 0) +
1377 ((pixel & 0x0000ff00) >> 7) +
1378 ((pixel & 0x00ff0000) >> 16)) >> 2;
1379 gray = FFMIN(gray, alpha);
1380 g8a8_pal[i] = (-alpha << 8) | gray;
1382 pal2gray_alpha(g8a8_pal, pal_img, pal_stride,
1383 img, aimg, stride, w, h);
1384 packet->start_pts = 0;
1385 packet->end_pts = 0x7fffffff;
1386 if (pts != MP_NOPTS_VALUE)
1387 packet->start_pts = pts * 90000;
1388 if (endpts != MP_NOPTS_VALUE)
1389 packet->end_pts = endpts * 90000;
1390 spudec_queue_packet(spu, packet);