spudec: Slightly simplify dvd subtitle RLE decoding
[mplayer/glamo.git] / spudec.c
blob6ac30c32c7caad7e93737102fe0ae9f808632f3a
1 /*
2 * Skeleton of function spudec_process_controll() is from xine sources.
3 * Further works:
4 * LGB,... (yeah, try to improve it and insert your name here! ;-)
6 * Kim Minh Kaplan
7 * implement fragments reassembly, RLE decoding.
8 * read brightness from the IFO.
10 * For information on SPU format see <URL:http://sam.zoy.org/doc/dvd/subtitles/>
11 * and <URL:http://members.aol.com/mpucoder/DVD/spu.html>
13 * This file is part of MPlayer.
15 * MPlayer is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
20 * MPlayer is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License along
26 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
27 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
30 #include "config.h"
31 #include "mp_msg.h"
33 #include <errno.h>
34 #include <limits.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <unistd.h>
38 #include <string.h>
39 #include <math.h>
40 #include "libvo/video_out.h"
41 #include "spudec.h"
42 #include "vobsub.h"
43 #include "libavutil/avutil.h"
44 #include "ffmpeg_files/intreadwrite.h"
45 #include "libswscale/swscale.h"
47 /* Valid values for spu_aamode:
48 0: none (fastest, most ugly)
49 1: approximate
50 2: full (slowest)
51 3: bilinear (similiar to vobsub, fast and not too bad)
52 4: uses swscaler gaussian (this is the only one that looks good)
55 int spu_aamode = 3;
56 int spu_alignment = -1;
57 float spu_gaussvar = 1.0;
58 extern int sub_pos;
60 typedef struct packet_t packet_t;
61 struct packet_t {
62 int is_decoded;
63 unsigned char *packet;
64 int data_len;
65 unsigned int palette[4];
66 unsigned int alpha[4];
67 unsigned int control_start; /* index of start of control data */
68 unsigned int current_nibble[2]; /* next data nibble (4 bits) to be
69 processed (for RLE decoding) for
70 even and odd lines */
71 int deinterlace_oddness; /* 0 or 1, index into current_nibble */
72 unsigned int start_col, end_col;
73 unsigned int start_row, end_row;
74 unsigned int width, height, stride;
75 unsigned int start_pts, end_pts;
76 packet_t *next;
79 typedef struct {
80 packet_t *queue_head;
81 packet_t *queue_tail;
82 unsigned int global_palette[16];
83 unsigned int orig_frame_width, orig_frame_height;
84 unsigned char* packet;
85 size_t packet_reserve; /* size of the memory pointed to by packet */
86 unsigned int packet_offset; /* end of the currently assembled fragment */
87 unsigned int packet_size; /* size of the packet once all fragments are assembled */
88 int packet_pts; /* PTS for this packet */
89 unsigned int palette[4];
90 unsigned int alpha[4];
91 unsigned int cuspal[4];
92 unsigned int custom;
93 unsigned int now_pts;
94 unsigned int start_pts, end_pts;
95 unsigned int start_col, end_col;
96 unsigned int start_row, end_row;
97 unsigned int width, height, stride;
98 size_t image_size; /* Size of the image buffer */
99 unsigned char *image; /* Grayscale value */
100 unsigned char *aimage; /* Alpha value */
101 unsigned char *pal_image; /* palette entry value */
102 unsigned int scaled_frame_width, scaled_frame_height;
103 unsigned int scaled_start_col, scaled_start_row;
104 unsigned int scaled_width, scaled_height, scaled_stride;
105 size_t scaled_image_size;
106 unsigned char *scaled_image;
107 unsigned char *scaled_aimage;
108 int auto_palette; /* 1 if we lack a palette and must use an heuristic. */
109 int font_start_level; /* Darkest value used for the computed font */
110 struct vo *hw_spu;
111 int spu_changed;
112 unsigned int forced_subs_only; /* flag: 0=display all subtitle, !0 display only forced subtitles */
113 unsigned int is_forced_sub; /* true if current subtitle is a forced subtitle */
114 } spudec_handle_t;
116 static void spudec_queue_packet(spudec_handle_t *this, packet_t *packet)
118 if (this->queue_head == NULL)
119 this->queue_head = packet;
120 else
121 this->queue_tail->next = packet;
122 this->queue_tail = packet;
125 static packet_t *spudec_dequeue_packet(spudec_handle_t *this)
127 packet_t *retval = this->queue_head;
129 this->queue_head = retval->next;
130 if (this->queue_head == NULL)
131 this->queue_tail = NULL;
133 return retval;
136 static void spudec_free_packet(packet_t *packet)
138 if (packet->packet != NULL)
139 free(packet->packet);
140 free(packet);
143 static inline unsigned int get_be16(const unsigned char *p)
145 return (p[0] << 8) + p[1];
148 static inline unsigned int get_be24(const unsigned char *p)
150 return (get_be16(p) << 8) + p[2];
153 static void next_line(packet_t *packet)
155 if (packet->current_nibble[packet->deinterlace_oddness] % 2)
156 packet->current_nibble[packet->deinterlace_oddness]++;
157 packet->deinterlace_oddness = (packet->deinterlace_oddness + 1) % 2;
160 static inline unsigned char get_nibble(packet_t *packet)
162 unsigned char nib;
163 unsigned int *nibblep = packet->current_nibble + packet->deinterlace_oddness;
164 if (*nibblep / 2 >= packet->control_start) {
165 mp_msg(MSGT_SPUDEC,MSGL_WARN, "SPUdec: ERROR: get_nibble past end of packet\n");
166 return 0;
168 nib = packet->packet[*nibblep / 2];
169 if (*nibblep % 2)
170 nib &= 0xf;
171 else
172 nib >>= 4;
173 ++*nibblep;
174 return nib;
177 /* Cut the sub to visible part */
178 static inline void spudec_cut_image(spudec_handle_t *this)
180 unsigned int fy, ly;
181 unsigned int first_y, last_y;
182 unsigned char *image;
183 unsigned char *aimage;
185 if (this->stride == 0 || this->height == 0) {
186 return;
189 for (fy = 0; fy < this->image_size && !this->aimage[fy]; fy++);
190 for (ly = this->stride * this->height-1; ly && !this->aimage[ly]; ly--);
191 first_y = fy / this->stride;
192 last_y = ly / this->stride;
193 //printf("first_y: %d, last_y: %d\n", first_y, last_y);
194 this->start_row += first_y;
196 // Some subtitles trigger this condition
197 if (last_y + 1 > first_y ) {
198 this->height = last_y - first_y +1;
199 } else {
200 this->height = 0;
201 this->image_size = 0;
202 return;
205 // printf("new h %d new start %d (sz %d st %d)---\n\n", this->height, this->start_row, this->image_size, this->stride);
207 image = malloc(2 * this->stride * this->height);
208 if(image){
209 this->image_size = this->stride * this->height;
210 aimage = image + this->image_size;
211 memcpy(image, this->image + this->stride * first_y, this->image_size);
212 memcpy(aimage, this->aimage + this->stride * first_y, this->image_size);
213 free(this->image);
214 this->image = image;
215 this->aimage = aimage;
216 } else {
217 mp_msg(MSGT_SPUDEC, MSGL_FATAL, "Fatal: update_spu: malloc requested %d bytes\n", 2 * 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 this->image_size = 0;
233 this->image = malloc(3 * this->stride * this->height);
234 if (this->image) {
235 this->image_size = this->stride * this->height;
236 this->aimage = this->image + this->image_size;
237 this->pal_image = this->aimage + this->image_size;
240 return this->image != NULL;
244 * \param pal palette in MPlayer-style gray-alpha values, i.e.
245 * alpha == 0 means transparent, 1 fully opaque,
246 * gray value <= 256 - alpha.
248 static void pal2gray_alpha(const uint16_t *pal,
249 const uint8_t *src, int src_stride,
250 uint8_t *dst, uint8_t *dsta,
251 int dst_stride, int w, int h)
253 int x, y;
254 for (y = 0; y < h; y++) {
255 for (x = 0; x < w; x++) {
256 uint16_t pixel = pal[src[x]];
257 *dst++ = pixel;
258 *dsta++ = pixel >> 8;
260 for (; x < dst_stride; x++)
261 *dsta++ = *dst++ = 0;
262 src += src_stride;
266 static void spudec_process_data(spudec_handle_t *this, packet_t *packet)
268 uint16_t pal[4];
269 unsigned int i, x, y;
270 uint8_t *dst;
272 this->scaled_frame_width = 0;
273 this->scaled_frame_height = 0;
274 this->start_col = packet->start_col;
275 this->end_col = packet->end_col;
276 this->start_row = packet->start_row;
277 this->end_row = packet->end_row;
278 this->height = packet->height;
279 this->width = packet->width;
280 this->stride = packet->stride;
281 for (i = 0; i < 4; ++i) {
282 int color;
283 int alpha = packet->alpha[i];
284 // extend 4 -> 8 bit
285 alpha |= alpha << 4;
286 if (this->custom && (this->cuspal[i] >> 31) != 0)
287 alpha = 0;
288 color = this->custom ? this->cuspal[i] :
289 this->global_palette[packet->palette[i]];
290 color = (color >> 16) & 0xff;
291 // convert to MPlayer-style gray/alpha palette
292 color = FFMIN(color, alpha);
293 pal[i] = (-alpha << 8) | color;
296 if (!spudec_alloc_image(this, this->stride, this->height))
297 return;
299 i = packet->current_nibble[1];
300 x = 0;
301 y = 0;
302 dst = this->pal_image;
303 while (packet->current_nibble[0] < i
304 && packet->current_nibble[1] / 2 < packet->control_start
305 && y < this->height) {
306 unsigned int len, color;
307 unsigned int rle = 0;
308 rle = get_nibble(packet);
309 if (rle < 0x04) {
310 rle = (rle << 4) | get_nibble(packet);
311 if (rle < 0x10) {
312 rle = (rle << 4) | get_nibble(packet);
313 if (rle < 0x040) {
314 rle = (rle << 4) | get_nibble(packet);
315 if (rle < 0x0004)
316 rle |= ((this->width - x) << 2);
320 color = 3 - (rle & 0x3);
321 len = rle >> 2;
322 x += len;
323 if (len == 0 || x >= this->width) {
324 len += this->width - x;
325 next_line(packet);
326 x = 0;
327 ++y;
329 memset(dst, color, len);
330 dst += len;
332 pal2gray_alpha(pal, this->pal_image, this->width,
333 this->image, this->aimage, this->stride,
334 this->width, this->height);
335 spudec_cut_image(this);
340 This function tries to create a usable palette.
341 It determines how many non-transparent colors are used, and assigns different
342 gray scale values to each color.
343 I tested it with four streams and even got something readable. Half of the
344 times I got black characters with white around and half the reverse.
346 static void compute_palette(spudec_handle_t *this, packet_t *packet)
348 int used[16],i,cused,start,step,color;
350 memset(used, 0, sizeof(used));
351 for (i=0; i<4; i++)
352 if (packet->alpha[i]) /* !Transparent? */
353 used[packet->palette[i]] = 1;
354 for (cused=0, i=0; i<16; i++)
355 if (used[i]) cused++;
356 if (!cused) return;
357 if (cused == 1) {
358 start = 0x80;
359 step = 0;
360 } else {
361 start = this->font_start_level;
362 step = (0xF0-this->font_start_level)/(cused-1);
364 memset(used, 0, sizeof(used));
365 for (i=0; i<4; i++) {
366 color = packet->palette[i];
367 if (packet->alpha[i] && !used[color]) { /* not assigned? */
368 used[color] = 1;
369 this->global_palette[color] = start<<16;
370 start += step;
375 static void spudec_process_control(spudec_handle_t *this, int pts100)
377 int a,b,c,d; /* Temporary vars */
378 unsigned int date, type;
379 unsigned int off;
380 unsigned int start_off = 0;
381 unsigned int next_off;
382 unsigned int start_pts = 0;
383 unsigned int end_pts = 0;
384 unsigned int current_nibble[2] = {0, 0};
385 unsigned int control_start;
386 unsigned int display = 0;
387 unsigned int start_col = 0;
388 unsigned int end_col = 0;
389 unsigned int start_row = 0;
390 unsigned int end_row = 0;
391 unsigned int width = 0;
392 unsigned int height = 0;
393 unsigned int stride = 0;
395 control_start = get_be16(this->packet + 2);
396 next_off = control_start;
397 while (start_off != next_off) {
398 start_off = next_off;
399 date = get_be16(this->packet + start_off) * 1024;
400 next_off = get_be16(this->packet + start_off + 2);
401 mp_msg(MSGT_SPUDEC,MSGL_DBG2, "date=%d\n", date);
402 off = start_off + 4;
403 for (type = this->packet[off++]; type != 0xff; type = this->packet[off++]) {
404 mp_msg(MSGT_SPUDEC,MSGL_DBG2, "cmd=%d ",type);
405 switch(type) {
406 case 0x00:
407 /* Menu ID, 1 byte */
408 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Menu ID\n");
409 /* shouldn't a Menu ID type force display start? */
410 start_pts = pts100 < 0 && -pts100 >= date ? 0 : pts100 + date;
411 end_pts = UINT_MAX;
412 display = 1;
413 this->is_forced_sub=~0; // current subtitle is forced
414 break;
415 case 0x01:
416 /* Start display */
417 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Start display!\n");
418 start_pts = pts100 < 0 && -pts100 >= date ? 0 : pts100 + date;
419 end_pts = UINT_MAX;
420 display = 1;
421 this->is_forced_sub=0;
422 break;
423 case 0x02:
424 /* Stop display */
425 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Stop display!\n");
426 end_pts = pts100 < 0 && -pts100 >= date ? 0 : pts100 + date;
427 break;
428 case 0x03:
429 /* Palette */
430 this->palette[0] = this->packet[off] >> 4;
431 this->palette[1] = this->packet[off] & 0xf;
432 this->palette[2] = this->packet[off + 1] >> 4;
433 this->palette[3] = this->packet[off + 1] & 0xf;
434 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Palette %d, %d, %d, %d\n",
435 this->palette[0], this->palette[1], this->palette[2], this->palette[3]);
436 off+=2;
437 break;
438 case 0x04:
439 /* Alpha */
440 a = this->packet[off] >> 4;
441 b = this->packet[off] & 0xf;
442 c = this->packet[off + 1] >> 4;
443 d = this->packet[off + 1] & 0xf;
444 // Note: some DVDs change these values to create a fade-in/fade-out effect
445 // We can not handle this, so just keep the highest value during the display time.
446 if (display) {
447 a = FFMAX(a, this->alpha[0]);
448 b = FFMAX(b, this->alpha[1]);
449 c = FFMAX(c, this->alpha[2]);
450 d = FFMAX(d, this->alpha[3]);
452 this->alpha[0] = a;
453 this->alpha[1] = b;
454 this->alpha[2] = c;
455 this->alpha[3] = d;
456 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Alpha %d, %d, %d, %d\n",
457 this->alpha[0], this->alpha[1], this->alpha[2], this->alpha[3]);
458 off+=2;
459 break;
460 case 0x05:
461 /* Co-ords */
462 a = get_be24(this->packet + off);
463 b = get_be24(this->packet + off + 3);
464 start_col = a >> 12;
465 end_col = a & 0xfff;
466 width = (end_col < start_col) ? 0 : end_col - start_col + 1;
467 stride = (width + 7) & ~7; /* Kludge: draw_alpha needs width multiple of 8 */
468 start_row = b >> 12;
469 end_row = b & 0xfff;
470 height = (end_row < start_row) ? 0 : end_row - start_row /* + 1 */;
471 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Coords col: %d - %d row: %d - %d (%dx%d)\n",
472 start_col, end_col, start_row, end_row,
473 width, height);
474 off+=6;
475 break;
476 case 0x06:
477 /* Graphic lines */
478 current_nibble[0] = 2 * get_be16(this->packet + off);
479 current_nibble[1] = 2 * get_be16(this->packet + off + 2);
480 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Graphic offset 1: %d offset 2: %d\n",
481 current_nibble[0] / 2, current_nibble[1] / 2);
482 off+=4;
483 break;
484 case 0xff:
485 /* All done, bye-bye */
486 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Done!\n");
487 return;
488 // break;
489 default:
490 mp_msg(MSGT_SPUDEC,MSGL_WARN,"spudec: Error determining control type 0x%02x. Skipping %d bytes.\n",
491 type, next_off - off);
492 goto next_control;
495 next_control:
496 if (!display)
497 continue;
498 if (end_pts == UINT_MAX && start_off != next_off) {
499 end_pts = get_be16(this->packet + next_off) * 1024;
500 end_pts = 1 - pts100 >= end_pts ? 0 : pts100 + end_pts - 1;
502 if (end_pts > 0) {
503 packet_t *packet = calloc(1, sizeof(packet_t));
504 int i;
505 packet->start_pts = start_pts;
506 packet->end_pts = end_pts;
507 packet->current_nibble[0] = current_nibble[0];
508 packet->current_nibble[1] = current_nibble[1];
509 packet->start_row = start_row;
510 packet->end_row = end_row;
511 packet->start_col = start_col;
512 packet->end_col = end_col;
513 packet->width = width;
514 packet->height = height;
515 packet->stride = stride;
516 packet->control_start = control_start;
517 for (i=0; i<4; i++) {
518 packet->alpha[i] = this->alpha[i];
519 packet->palette[i] = this->palette[i];
521 packet->packet = malloc(this->packet_size);
522 memcpy(packet->packet, this->packet, this->packet_size);
523 spudec_queue_packet(this, packet);
528 static void spudec_decode(spudec_handle_t *this, int pts100)
530 if (!this->hw_spu)
531 spudec_process_control(this, pts100);
532 else if (pts100 >= 0) {
533 static vo_mpegpes_t packet = { NULL, 0, 0x20, 0 };
534 static vo_mpegpes_t *pkg=&packet;
535 packet.data = this->packet;
536 packet.size = this->packet_size;
537 packet.timestamp = pts100;
538 vo_draw_frame(this->hw_spu, (uint8_t**)&pkg);
542 int spudec_changed(void * this)
544 spudec_handle_t * spu = this;
545 return spu->spu_changed || spu->now_pts > spu->end_pts;
548 void spudec_assemble(void *this, unsigned char *packet, unsigned int len, int pts100)
550 spudec_handle_t *spu = this;
551 // spudec_heartbeat(this, pts100);
552 if (len < 2) {
553 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: packet too short\n");
554 return;
556 spu->packet_pts = pts100;
557 if (spu->packet_offset == 0) {
558 unsigned int len2 = get_be16(packet);
559 // Start new fragment
560 if (spu->packet_reserve < len2) {
561 if (spu->packet != NULL)
562 free(spu->packet);
563 spu->packet = malloc(len2);
564 spu->packet_reserve = spu->packet != NULL ? len2 : 0;
566 if (spu->packet != NULL) {
567 spu->packet_size = len2;
568 if (len > len2) {
569 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: invalid frag len / len2: %d / %d \n", len, len2);
570 return;
572 memcpy(spu->packet, packet, len);
573 spu->packet_offset = len;
574 spu->packet_pts = pts100;
576 } else {
577 // Continue current fragment
578 if (spu->packet_size < spu->packet_offset + len){
579 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: invalid fragment\n");
580 spu->packet_size = spu->packet_offset = 0;
581 return;
582 } else {
583 memcpy(spu->packet + spu->packet_offset, packet, len);
584 spu->packet_offset += len;
587 #if 1
588 // check if we have a complete packet (unfortunatelly packet_size is bad
589 // for some disks)
590 // [cb] packet_size is padded to be even -> may be one byte too long
591 if ((spu->packet_offset == spu->packet_size) ||
592 ((spu->packet_offset + 1) == spu->packet_size)){
593 unsigned int x=0,y;
594 while(x+4<=spu->packet_offset){
595 y=get_be16(spu->packet+x+2); // next control pointer
596 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPUtest: x=%d y=%d off=%d size=%d\n",x,y,spu->packet_offset,spu->packet_size);
597 if(x>=4 && x==y){ // if it points to self - we're done!
598 // we got it!
599 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPUgot: off=%d size=%d \n",spu->packet_offset,spu->packet_size);
600 spudec_decode(spu, pts100);
601 spu->packet_offset = 0;
602 break;
604 if(y<=x || y>=spu->packet_size){ // invalid?
605 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUtest: broken packet!!!!! y=%d < x=%d\n",y,x);
606 spu->packet_size = spu->packet_offset = 0;
607 break;
609 x=y;
611 // [cb] packet is done; start new packet
612 spu->packet_offset = 0;
614 #else
615 if (spu->packet_offset == spu->packet_size) {
616 spudec_decode(spu, pts100);
617 spu->packet_offset = 0;
619 #endif
622 void spudec_reset(void *this) // called after seek
624 spudec_handle_t *spu = this;
625 while (spu->queue_head)
626 spudec_free_packet(spudec_dequeue_packet(spu));
627 spu->now_pts = 0;
628 spu->end_pts = 0;
629 spu->packet_size = spu->packet_offset = 0;
632 void spudec_heartbeat(void *this, unsigned int pts100)
634 spudec_handle_t *spu = this;
635 spu->now_pts = pts100;
637 // TODO: detect and handle broken timestamps (e.g. due to wrapping)
638 while (spu->queue_head != NULL && pts100 >= spu->queue_head->start_pts) {
639 packet_t *packet = spudec_dequeue_packet(spu);
640 spu->start_pts = packet->start_pts;
641 spu->end_pts = packet->end_pts;
642 if (packet->is_decoded) {
643 free(spu->image);
644 spu->image_size = packet->data_len;
645 spu->image = packet->packet;
646 spu->aimage = packet->packet + packet->stride * packet->height;
647 packet->packet = NULL;
648 spu->width = packet->width;
649 spu->height = packet->height;
650 spu->stride = packet->stride;
651 spu->start_col = packet->start_col;
652 spu->start_row = packet->start_row;
654 // reset scaled image
655 spu->scaled_frame_width = 0;
656 spu->scaled_frame_height = 0;
657 } else {
658 if (spu->auto_palette)
659 compute_palette(spu, packet);
660 spudec_process_data(spu, packet);
662 spudec_free_packet(packet);
663 spu->spu_changed = 1;
667 int spudec_visible(void *this){
668 spudec_handle_t *spu = this;
669 int ret=(spu->start_pts <= spu->now_pts &&
670 spu->now_pts < spu->end_pts &&
671 spu->height > 0);
672 // printf("spu visible: %d \n",ret);
673 return ret;
676 void spudec_set_forced_subs_only(void * const this, const unsigned int flag)
678 if(this){
679 ((spudec_handle_t *)this)->forced_subs_only=flag;
680 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPU: Display only forced subs now %s\n", flag ? "enabled": "disabled");
684 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)
686 spudec_handle_t *spu = this;
687 if (spudec_visible(spu))
689 draw_alpha(ctx, spu->start_col, spu->start_row, spu->width, spu->height,
690 spu->image, spu->aimage, spu->stride);
691 spu->spu_changed = 0;
695 /* calc the bbox for spudec subs */
696 void spudec_calc_bbox(void *me, unsigned int dxs, unsigned int dys, unsigned int* bbox)
698 spudec_handle_t *spu = me;
699 if (spu->orig_frame_width == 0 || spu->orig_frame_height == 0
700 || (spu->orig_frame_width == dxs && spu->orig_frame_height == dys)) {
701 // unscaled
702 bbox[0] = spu->start_col;
703 bbox[1] = spu->start_col + spu->width;
704 bbox[2] = spu->start_row;
705 bbox[3] = spu->start_row + spu->height;
707 else {
708 // scaled
709 unsigned int scalex = 0x100 * dxs / spu->orig_frame_width;
710 unsigned int scaley = 0x100 * dys / spu->orig_frame_height;
711 bbox[0] = spu->start_col * scalex / 0x100;
712 bbox[1] = spu->start_col * scalex / 0x100 + spu->width * scalex / 0x100;
713 switch (spu_alignment) {
714 case 0:
715 bbox[3] = dys*sub_pos/100 + spu->height * scaley / 0x100;
716 if (bbox[3] > dys) bbox[3] = dys;
717 bbox[2] = bbox[3] - spu->height * scaley / 0x100;
718 break;
719 case 1:
720 if (sub_pos < 50) {
721 bbox[2] = dys*sub_pos/100 - spu->height * scaley / 0x200;
722 bbox[3] = bbox[2] + spu->height;
723 } else {
724 bbox[3] = dys*sub_pos/100 + spu->height * scaley / 0x200;
725 if (bbox[3] > dys) bbox[3] = dys;
726 bbox[2] = bbox[3] - spu->height * scaley / 0x100;
728 break;
729 case 2:
730 bbox[2] = dys*sub_pos/100 - spu->height * scaley / 0x100;
731 bbox[3] = bbox[2] + spu->height;
732 break;
733 default: /* -1 */
734 bbox[2] = spu->start_row * scaley / 0x100;
735 bbox[3] = spu->start_row * scaley / 0x100 + spu->height * scaley / 0x100;
736 break;
740 /* transform mplayer's alpha value into an opacity value that is linear */
741 static inline int canon_alpha(int alpha)
743 return (uint8_t)-alpha;
746 typedef struct {
747 unsigned position;
748 unsigned left_up;
749 unsigned right_down;
750 }scale_pixel;
753 static void scale_table(unsigned int start_src, unsigned int start_tar, unsigned int end_src, unsigned int end_tar, scale_pixel * table)
755 unsigned int t;
756 unsigned int delta_src = end_src - start_src;
757 unsigned int delta_tar = end_tar - start_tar;
758 int src = 0;
759 int src_step;
760 if (delta_src == 0 || delta_tar == 0) {
761 return;
763 src_step = (delta_src << 16) / delta_tar >>1;
764 for (t = 0; t<=delta_tar; src += (src_step << 1), t++){
765 table[t].position= FFMIN(src >> 16, end_src - 1);
766 table[t].right_down = src & 0xffff;
767 table[t].left_up = 0x10000 - table[t].right_down;
771 /* bilinear scale, similar to vobsub's code */
772 static void scale_image(int x, int y, scale_pixel* table_x, scale_pixel* table_y, spudec_handle_t * spu)
774 int alpha[4];
775 int color[4];
776 unsigned int scale[4];
777 int base = table_y[y].position * spu->stride + table_x[x].position;
778 int scaled = y * spu->scaled_stride + x;
779 alpha[0] = canon_alpha(spu->aimage[base]);
780 alpha[1] = canon_alpha(spu->aimage[base + 1]);
781 alpha[2] = canon_alpha(spu->aimage[base + spu->stride]);
782 alpha[3] = canon_alpha(spu->aimage[base + spu->stride + 1]);
783 color[0] = spu->image[base];
784 color[1] = spu->image[base + 1];
785 color[2] = spu->image[base + spu->stride];
786 color[3] = spu->image[base + spu->stride + 1];
787 scale[0] = (table_x[x].left_up * table_y[y].left_up >> 16) * alpha[0];
788 if (table_y[y].left_up == 0x10000) // necessary to avoid overflow-case
789 scale[0] = table_x[x].left_up * alpha[0];
790 scale[1] = (table_x[x].right_down * table_y[y].left_up >>16) * alpha[1];
791 scale[2] = (table_x[x].left_up * table_y[y].right_down >> 16) * alpha[2];
792 scale[3] = (table_x[x].right_down * table_y[y].right_down >> 16) * alpha[3];
793 spu->scaled_image[scaled] = (color[0] * scale[0] + color[1] * scale[1] + color[2] * scale[2] + color[3] * scale[3])>>24;
794 spu->scaled_aimage[scaled] = (scale[0] + scale[1] + scale[2] + scale[3]) >> 16;
795 if (spu->scaled_aimage[scaled]){
796 // ensure that MPlayer's simplified alpha-blending can not overflow
797 spu->scaled_image[scaled] = FFMIN(spu->scaled_image[scaled], spu->scaled_aimage[scaled]);
798 // convert to MPlayer-style alpha
799 spu->scaled_aimage[scaled] = -spu->scaled_aimage[scaled];
803 static void sws_spu_image(unsigned char *d1, unsigned char *d2, int dw, int dh,
804 int ds, unsigned char *s1, unsigned char *s2, int sw,
805 int sh, int ss)
807 struct SwsContext *ctx;
808 static SwsFilter filter;
809 static int firsttime = 1;
810 static float oldvar;
811 int i;
813 if (!firsttime && oldvar != spu_gaussvar) sws_freeVec(filter.lumH);
814 if (firsttime) {
815 filter.lumH = filter.lumV =
816 filter.chrH = filter.chrV = sws_getGaussianVec(spu_gaussvar, 3.0);
817 sws_normalizeVec(filter.lumH, 1.0);
818 firsttime = 0;
819 oldvar = spu_gaussvar;
822 ctx=sws_getContext(sw, sh, PIX_FMT_GRAY8, dw, dh, PIX_FMT_GRAY8, SWS_GAUSS, &filter, NULL, NULL);
823 sws_scale(ctx,&s1,&ss,0,sh,&d1,&ds);
824 for (i=ss*sh-1; i>=0; i--) if (!s2[i]) s2[i] = 255; //else s2[i] = 1;
825 sws_scale(ctx,&s2,&ss,0,sh,&d2,&ds);
826 for (i=ds*dh-1; i>=0; i--) if (d2[i]==0) d2[i] = 1; else if (d2[i]==255) d2[i] = 0;
827 sws_freeContext(ctx);
830 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)
832 spudec_handle_t *spu = me;
833 scale_pixel *table_x;
834 scale_pixel *table_y;
836 if (spudec_visible(spu)) {
838 // check if only forced subtitles are requested
839 if( (spu->forced_subs_only) && !(spu->is_forced_sub) ){
840 return;
843 if (!(spu_aamode&16) && (spu->orig_frame_width == 0 || spu->orig_frame_height == 0
844 || (spu->orig_frame_width == dxs && spu->orig_frame_height == dys))) {
845 spudec_draw(spu, draw_alpha, ctx);
847 else {
848 if (spu->scaled_frame_width != dxs || spu->scaled_frame_height != dys) { /* Resizing is needed */
849 /* scaled_x = scalex * x / 0x100
850 scaled_y = scaley * y / 0x100
851 order of operations is important because of rounding. */
852 unsigned int scalex = 0x100 * dxs / spu->orig_frame_width;
853 unsigned int scaley = 0x100 * dys / spu->orig_frame_height;
854 spu->scaled_start_col = spu->start_col * scalex / 0x100;
855 spu->scaled_start_row = spu->start_row * scaley / 0x100;
856 spu->scaled_width = spu->width * scalex / 0x100;
857 spu->scaled_height = spu->height * scaley / 0x100;
858 /* Kludge: draw_alpha needs width multiple of 8 */
859 spu->scaled_stride = (spu->scaled_width + 7) & ~7;
860 if (spu->scaled_image_size < spu->scaled_stride * spu->scaled_height) {
861 if (spu->scaled_image) {
862 free(spu->scaled_image);
863 spu->scaled_image_size = 0;
865 spu->scaled_image = malloc(2 * spu->scaled_stride * spu->scaled_height);
866 if (spu->scaled_image) {
867 spu->scaled_image_size = spu->scaled_stride * spu->scaled_height;
868 spu->scaled_aimage = spu->scaled_image + spu->scaled_image_size;
871 if (spu->scaled_image) {
872 unsigned int x, y;
873 if (spu->scaled_width <= 1 || spu->scaled_height <= 1) {
874 goto nothing_to_do;
876 switch(spu_aamode&15) {
877 case 4:
878 sws_spu_image(spu->scaled_image, spu->scaled_aimage,
879 spu->scaled_width, spu->scaled_height, spu->scaled_stride,
880 spu->image, spu->aimage, spu->width, spu->height, spu->stride);
881 break;
882 case 3:
883 table_x = calloc(spu->scaled_width, sizeof(scale_pixel));
884 table_y = calloc(spu->scaled_height, sizeof(scale_pixel));
885 if (!table_x || !table_y) {
886 mp_msg(MSGT_SPUDEC, MSGL_FATAL, "Fatal: spudec_draw_scaled: calloc failed\n");
888 scale_table(0, 0, spu->width - 1, spu->scaled_width - 1, table_x);
889 scale_table(0, 0, spu->height - 1, spu->scaled_height - 1, table_y);
890 for (y = 0; y < spu->scaled_height; y++)
891 for (x = 0; x < spu->scaled_width; x++)
892 scale_image(x, y, table_x, table_y, spu);
893 free(table_x);
894 free(table_y);
895 break;
896 case 0:
897 /* no antialiasing */
898 for (y = 0; y < spu->scaled_height; ++y) {
899 int unscaled_y = y * 0x100 / scaley;
900 int strides = spu->stride * unscaled_y;
901 int scaled_strides = spu->scaled_stride * y;
902 for (x = 0; x < spu->scaled_width; ++x) {
903 int unscaled_x = x * 0x100 / scalex;
904 spu->scaled_image[scaled_strides + x] = spu->image[strides + unscaled_x];
905 spu->scaled_aimage[scaled_strides + x] = spu->aimage[strides + unscaled_x];
908 break;
909 case 1:
911 /* Intermediate antialiasing. */
912 for (y = 0; y < spu->scaled_height; ++y) {
913 const unsigned int unscaled_top = y * spu->orig_frame_height / dys;
914 unsigned int unscaled_bottom = (y + 1) * spu->orig_frame_height / dys;
915 if (unscaled_bottom >= spu->height)
916 unscaled_bottom = spu->height - 1;
917 for (x = 0; x < spu->scaled_width; ++x) {
918 const unsigned int unscaled_left = x * spu->orig_frame_width / dxs;
919 unsigned int unscaled_right = (x + 1) * spu->orig_frame_width / dxs;
920 unsigned int color = 0;
921 unsigned int alpha = 0;
922 unsigned int walkx, walky;
923 unsigned int base, tmp;
924 if (unscaled_right >= spu->width)
925 unscaled_right = spu->width - 1;
926 for (walky = unscaled_top; walky <= unscaled_bottom; ++walky)
927 for (walkx = unscaled_left; walkx <= unscaled_right; ++walkx) {
928 base = walky * spu->stride + walkx;
929 tmp = canon_alpha(spu->aimage[base]);
930 alpha += tmp;
931 color += tmp * spu->image[base];
933 base = y * spu->scaled_stride + x;
934 spu->scaled_image[base] = alpha ? color / alpha : 0;
935 spu->scaled_aimage[base] =
936 alpha * (1 + unscaled_bottom - unscaled_top) * (1 + unscaled_right - unscaled_left);
937 /* spu->scaled_aimage[base] =
938 alpha * dxs * dys / spu->orig_frame_width / spu->orig_frame_height; */
939 if (spu->scaled_aimage[base]) {
940 spu->scaled_aimage[base] = 256 - spu->scaled_aimage[base];
941 if (spu->scaled_aimage[base] + spu->scaled_image[base] > 255)
942 spu->scaled_image[base] = 256 - spu->scaled_aimage[base];
947 break;
948 case 2:
950 /* Best antialiasing. Very slow. */
951 /* Any pixel (x, y) represents pixels from the original
952 rectangular region comprised between the columns
953 unscaled_y and unscaled_y + 0x100 / scaley and the rows
954 unscaled_x and unscaled_x + 0x100 / scalex
956 The original rectangular region that the scaled pixel
957 represents is cut in 9 rectangular areas like this:
959 +---+-----------------+---+
960 | 1 | 2 | 3 |
961 +---+-----------------+---+
962 | | | |
963 | 4 | 5 | 6 |
964 | | | |
965 +---+-----------------+---+
966 | 7 | 8 | 9 |
967 +---+-----------------+---+
969 The width of the left column is at most one pixel and
970 it is never null and its right column is at a pixel
971 boundary. The height of the top row is at most one
972 pixel it is never null and its bottom row is at a
973 pixel boundary. The width and height of region 5 are
974 integral values. The width of the right column is
975 what remains and is less than one pixel. The height
976 of the bottom row is what remains and is less than
977 one pixel.
979 The row above 1, 2, 3 is unscaled_y. The row between
980 1, 2, 3 and 4, 5, 6 is top_low_row. The row between 4,
981 5, 6 and 7, 8, 9 is (unsigned int)unscaled_y_bottom.
982 The row beneath 7, 8, 9 is unscaled_y_bottom.
984 The column left of 1, 4, 7 is unscaled_x. The column
985 between 1, 4, 7 and 2, 5, 8 is left_right_column. The
986 column between 2, 5, 8 and 3, 6, 9 is (unsigned
987 int)unscaled_x_right. The column right of 3, 6, 9 is
988 unscaled_x_right. */
989 const double inv_scalex = (double) 0x100 / scalex;
990 const double inv_scaley = (double) 0x100 / scaley;
991 for (y = 0; y < spu->scaled_height; ++y) {
992 const double unscaled_y = y * inv_scaley;
993 const double unscaled_y_bottom = unscaled_y + inv_scaley;
994 const unsigned int top_low_row = FFMIN(unscaled_y_bottom, unscaled_y + 1.0);
995 const double top = top_low_row - unscaled_y;
996 const unsigned int height = unscaled_y_bottom > top_low_row
997 ? (unsigned int) unscaled_y_bottom - top_low_row
998 : 0;
999 const double bottom = unscaled_y_bottom > top_low_row
1000 ? unscaled_y_bottom - floor(unscaled_y_bottom)
1001 : 0.0;
1002 for (x = 0; x < spu->scaled_width; ++x) {
1003 const double unscaled_x = x * inv_scalex;
1004 const double unscaled_x_right = unscaled_x + inv_scalex;
1005 const unsigned int left_right_column = FFMIN(unscaled_x_right, unscaled_x + 1.0);
1006 const double left = left_right_column - unscaled_x;
1007 const unsigned int width = unscaled_x_right > left_right_column
1008 ? (unsigned int) unscaled_x_right - left_right_column
1009 : 0;
1010 const double right = unscaled_x_right > left_right_column
1011 ? unscaled_x_right - floor(unscaled_x_right)
1012 : 0.0;
1013 double color = 0.0;
1014 double alpha = 0.0;
1015 double tmp;
1016 unsigned int base;
1017 /* Now use these informations to compute a good alpha,
1018 and lightness. The sum is on each of the 9
1019 region's surface and alpha and lightness.
1021 transformed alpha = sum(surface * alpha) / sum(surface)
1022 transformed color = sum(surface * alpha * color) / sum(surface * alpha)
1024 /* 1: top left part */
1025 base = spu->stride * (unsigned int) unscaled_y;
1026 tmp = left * top * canon_alpha(spu->aimage[base + (unsigned int) unscaled_x]);
1027 alpha += tmp;
1028 color += tmp * spu->image[base + (unsigned int) unscaled_x];
1029 /* 2: top center part */
1030 if (width > 0) {
1031 unsigned int walkx;
1032 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
1033 base = spu->stride * (unsigned int) unscaled_y + walkx;
1034 tmp = /* 1.0 * */ top * canon_alpha(spu->aimage[base]);
1035 alpha += tmp;
1036 color += tmp * spu->image[base];
1039 /* 3: top right part */
1040 if (right > 0.0) {
1041 base = spu->stride * (unsigned int) unscaled_y + (unsigned int) unscaled_x_right;
1042 tmp = right * top * canon_alpha(spu->aimage[base]);
1043 alpha += tmp;
1044 color += tmp * spu->image[base];
1046 /* 4: center left part */
1047 if (height > 0) {
1048 unsigned int walky;
1049 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1050 base = spu->stride * walky + (unsigned int) unscaled_x;
1051 tmp = left /* * 1.0 */ * canon_alpha(spu->aimage[base]);
1052 alpha += tmp;
1053 color += tmp * spu->image[base];
1056 /* 5: center part */
1057 if (width > 0 && height > 0) {
1058 unsigned int walky;
1059 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1060 unsigned int walkx;
1061 base = spu->stride * walky;
1062 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
1063 tmp = /* 1.0 * 1.0 * */ canon_alpha(spu->aimage[base + walkx]);
1064 alpha += tmp;
1065 color += tmp * spu->image[base + walkx];
1069 /* 6: center right part */
1070 if (right > 0.0 && height > 0) {
1071 unsigned int walky;
1072 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1073 base = spu->stride * walky + (unsigned int) unscaled_x_right;
1074 tmp = right /* * 1.0 */ * canon_alpha(spu->aimage[base]);
1075 alpha += tmp;
1076 color += tmp * spu->image[base];
1079 /* 7: bottom left part */
1080 if (bottom > 0.0) {
1081 base = spu->stride * (unsigned int) unscaled_y_bottom + (unsigned int) unscaled_x;
1082 tmp = left * bottom * canon_alpha(spu->aimage[base]);
1083 alpha += tmp;
1084 color += tmp * spu->image[base];
1086 /* 8: bottom center part */
1087 if (width > 0 && bottom > 0.0) {
1088 unsigned int walkx;
1089 base = spu->stride * (unsigned int) unscaled_y_bottom;
1090 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
1091 tmp = /* 1.0 * */ bottom * canon_alpha(spu->aimage[base + walkx]);
1092 alpha += tmp;
1093 color += tmp * spu->image[base + walkx];
1096 /* 9: bottom right part */
1097 if (right > 0.0 && bottom > 0.0) {
1098 base = spu->stride * (unsigned int) unscaled_y_bottom + (unsigned int) unscaled_x_right;
1099 tmp = right * bottom * canon_alpha(spu->aimage[base]);
1100 alpha += tmp;
1101 color += tmp * spu->image[base];
1103 /* Finally mix these transparency and brightness information suitably */
1104 base = spu->scaled_stride * y + x;
1105 spu->scaled_image[base] = alpha > 0 ? color / alpha : 0;
1106 spu->scaled_aimage[base] = alpha * scalex * scaley / 0x10000;
1107 if (spu->scaled_aimage[base]) {
1108 spu->scaled_aimage[base] = 256 - spu->scaled_aimage[base];
1109 if (spu->scaled_aimage[base] + spu->scaled_image[base] > 255)
1110 spu->scaled_image[base] = 256 - spu->scaled_aimage[base];
1116 nothing_to_do:
1117 /* Kludge: draw_alpha needs width multiple of 8. */
1118 if (spu->scaled_width < spu->scaled_stride)
1119 for (y = 0; y < spu->scaled_height; ++y) {
1120 memset(spu->scaled_aimage + y * spu->scaled_stride + spu->scaled_width, 0,
1121 spu->scaled_stride - spu->scaled_width);
1123 spu->scaled_frame_width = dxs;
1124 spu->scaled_frame_height = dys;
1127 if (spu->scaled_image){
1128 switch (spu_alignment) {
1129 case 0:
1130 spu->scaled_start_row = dys*sub_pos/100;
1131 if (spu->scaled_start_row + spu->scaled_height > dys)
1132 spu->scaled_start_row = dys - spu->scaled_height;
1133 break;
1134 case 1:
1135 spu->scaled_start_row = dys*sub_pos/100 - spu->scaled_height/2;
1136 if (sub_pos >= 50 && spu->scaled_start_row + spu->scaled_height > dys)
1137 spu->scaled_start_row = dys - spu->scaled_height;
1138 break;
1139 case 2:
1140 spu->scaled_start_row = dys*sub_pos/100 - spu->scaled_height;
1141 break;
1143 draw_alpha(ctx, spu->scaled_start_col, spu->scaled_start_row, spu->scaled_width, spu->scaled_height,
1144 spu->scaled_image, spu->scaled_aimage, spu->scaled_stride);
1145 spu->spu_changed = 0;
1149 else
1151 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPU not displayed: start_pts=%d end_pts=%d now_pts=%d\n",
1152 spu->start_pts, spu->end_pts, spu->now_pts);
1156 void spudec_update_palette(void * this, unsigned int *palette)
1158 spudec_handle_t *spu = this;
1159 if (spu && palette) {
1160 memcpy(spu->global_palette, palette, sizeof(spu->global_palette));
1161 if(spu->hw_spu)
1162 vo_control(spu->hw_spu, VOCTRL_SET_SPU_PALETTE, spu->global_palette);
1166 void spudec_set_font_factor(void * this, double factor)
1168 spudec_handle_t *spu = this;
1169 spu->font_start_level = (int)(0xF0-(0xE0*factor));
1172 static void spudec_parse_extradata(spudec_handle_t *this,
1173 uint8_t *extradata, int extradata_len)
1175 uint8_t *buffer, *ptr;
1176 unsigned int *pal = this->global_palette, *cuspal = this->cuspal;
1177 unsigned int tridx;
1178 int i;
1180 if (extradata_len == 16*4) {
1181 for (i=0; i<16; i++)
1182 pal[i] = AV_RB32(extradata + i*4);
1183 this->auto_palette = 0;
1184 return;
1187 if (!(ptr = buffer = malloc(extradata_len+1)))
1188 return;
1189 memcpy(buffer, extradata, extradata_len);
1190 buffer[extradata_len] = 0;
1192 do {
1193 if (*ptr == '#')
1194 continue;
1195 if (!strncmp(ptr, "size: ", 6))
1196 sscanf(ptr + 6, "%dx%d", &this->orig_frame_width, &this->orig_frame_height);
1197 if (!strncmp(ptr, "palette: ", 9) &&
1198 sscanf(ptr + 9, "%x, %x, %x, %x, %x, %x, %x, %x, "
1199 "%x, %x, %x, %x, %x, %x, %x, %x",
1200 &pal[ 0], &pal[ 1], &pal[ 2], &pal[ 3],
1201 &pal[ 4], &pal[ 5], &pal[ 6], &pal[ 7],
1202 &pal[ 8], &pal[ 9], &pal[10], &pal[11],
1203 &pal[12], &pal[13], &pal[14], &pal[15]) == 16) {
1204 for (i=0; i<16; i++)
1205 pal[i] = vobsub_palette_to_yuv(pal[i]);
1206 this->auto_palette = 0;
1208 if (!strncasecmp(ptr, "forced subs: on", 15))
1209 this->forced_subs_only = 1;
1210 if (!strncmp(ptr, "custom colors: ON, tridx: ", 26) &&
1211 sscanf(ptr + 26, "%x, colors: %x, %x, %x, %x",
1212 &tridx, cuspal+0, cuspal+1, cuspal+2, cuspal+3) == 5) {
1213 for (i=0; i<4; i++) {
1214 cuspal[i] = vobsub_rgb_to_yuv(cuspal[i]);
1215 if (tridx & (1 << (12-4*i)))
1216 cuspal[i] |= 1 << 31;
1218 this->custom = 1;
1220 } while ((ptr=strchr(ptr,'\n')) && *++ptr);
1222 free(buffer);
1225 void *spudec_new_scaled(unsigned int *palette, unsigned int frame_width, unsigned int frame_height, uint8_t *extradata, int extradata_len)
1227 spudec_handle_t *this = calloc(1, sizeof(spudec_handle_t));
1228 if (this){
1229 this->orig_frame_height = frame_height;
1230 this->orig_frame_width = frame_width;
1231 // set up palette:
1232 if (palette)
1233 memcpy(this->global_palette, palette, sizeof(this->global_palette));
1234 else
1235 this->auto_palette = 1;
1236 if (extradata)
1237 spudec_parse_extradata(this, extradata, extradata_len);
1238 /* XXX Although the video frame is some size, the SPU frame is
1239 always maximum size i.e. 720 wide and 576 or 480 high */
1240 // For HD files in MKV the VobSub resolution can be higher though,
1241 // see largeres_vobsub.mkv
1242 if (this->orig_frame_width <= 720 && this->orig_frame_height <= 576) {
1243 this->orig_frame_width = 720;
1244 if (this->orig_frame_height == 480 || this->orig_frame_height == 240)
1245 this->orig_frame_height = 480;
1246 else
1247 this->orig_frame_height = 576;
1250 else
1251 mp_msg(MSGT_SPUDEC,MSGL_FATAL, "FATAL: spudec_init: calloc");
1252 return this;
1255 void *spudec_new(unsigned int *palette)
1257 return spudec_new_scaled(palette, 0, 0, NULL, 0);
1260 void spudec_free(void *this)
1262 spudec_handle_t *spu = this;
1263 if (spu) {
1264 while (spu->queue_head)
1265 spudec_free_packet(spudec_dequeue_packet(spu));
1266 if (spu->packet)
1267 free(spu->packet);
1268 if (spu->scaled_image)
1269 free(spu->scaled_image);
1270 if (spu->image)
1271 free(spu->image);
1272 free(spu);
1276 void spudec_set_hw_spu(void *this, struct vo *hw_spu)
1278 spudec_handle_t *spu = this;
1279 if (!spu)
1280 return;
1281 spu->hw_spu = hw_spu;
1282 vo_control(hw_spu, VOCTRL_SET_SPU_PALETTE, spu->global_palette);
1285 #define MP_NOPTS_VALUE (-1LL<<63) //both int64_t and double should be able to represent this exactly
1288 * palette must contain at least 256 32-bit entries, otherwise crashes
1289 * are possible
1291 void spudec_set_paletted(void *this, const uint8_t *pal_img, int pal_stride,
1292 const void *palette,
1293 int x, int y, int w, int h,
1294 double pts, double endpts)
1296 int i;
1297 uint16_t g8a8_pal[256];
1298 packet_t *packet;
1299 const uint32_t *pal = palette;
1300 spudec_handle_t *spu = this;
1301 uint8_t *img;
1302 uint8_t *aimg;
1303 int stride = (w + 7) & ~7;
1304 if ((unsigned)w >= 0x8000 || (unsigned)h > 0x4000)
1305 return;
1306 packet = calloc(1, sizeof(packet_t));
1307 packet->is_decoded = 1;
1308 packet->width = w;
1309 packet->height = h;
1310 packet->stride = stride;
1311 packet->start_col = x;
1312 packet->start_row = y;
1313 packet->data_len = 2 * stride * h;
1314 packet->packet = malloc(packet->data_len);
1315 img = packet->packet;
1316 aimg = packet->packet + stride * h;
1317 for (i = 0; i < 256; i++) {
1318 uint32_t pixel = pal[i];
1319 int alpha = pixel >> 24;
1320 int gray = (((pixel & 0x000000ff) >> 0) +
1321 ((pixel & 0x0000ff00) >> 7) +
1322 ((pixel & 0x00ff0000) >> 16)) >> 2;
1323 gray = FFMIN(gray, alpha);
1324 g8a8_pal[i] = (-alpha << 8) | gray;
1326 pal2gray_alpha(g8a8_pal, pal_img, pal_stride,
1327 img, aimg, stride, w, h);
1328 packet->start_pts = 0;
1329 packet->end_pts = 0x7fffffff;
1330 if (pts != MP_NOPTS_VALUE)
1331 packet->start_pts = pts * 90000;
1332 if (endpts != MP_NOPTS_VALUE)
1333 packet->end_pts = endpts * 90000;
1334 spudec_queue_packet(spu, packet);