vo_corevideo: Simplify update_screen_info
[mplayer/glamo.git] / spudec.c
blob17ed1ceb0f31cebe6be17fd595b9a4b846fac60d
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;
183 if (this->stride == 0 || this->height == 0) {
184 return;
187 for (fy = 0; fy < this->image_size && !this->aimage[fy]; fy++);
188 for (ly = this->stride * this->height-1; ly && !this->aimage[ly]; ly--);
189 first_y = fy / this->stride;
190 last_y = ly / this->stride;
191 //printf("first_y: %d, last_y: %d\n", first_y, last_y);
192 this->start_row += first_y;
194 // Some subtitles trigger this condition
195 if (last_y + 1 > first_y ) {
196 this->height = last_y - first_y +1;
197 } else {
198 this->height = 0;
199 return;
202 // printf("new h %d new start %d (sz %d st %d)---\n\n", this->height, this->start_row, this->image_size, this->stride);
204 if (first_y > 0) {
205 memmove(this->image, this->image + this->stride * first_y, this->stride * this->height);
206 memmove(this->aimage, this->aimage + this->stride * first_y, this->stride * this->height);
211 static int spudec_alloc_image(spudec_handle_t *this, int stride, int height)
213 if (this->width > stride) // just a safeguard
214 this->width = stride;
215 this->stride = stride;
216 this->height = height;
217 if (this->image_size < this->stride * this->height) {
218 if (this->image != NULL) {
219 free(this->image);
220 free(this->pal_image);
221 this->image_size = 0;
223 this->image = malloc(2 * this->stride * this->height);
224 if (this->image) {
225 this->image_size = this->stride * this->height;
226 this->aimage = this->image + this->image_size;
227 // use stride here as well to simplify reallocation checks
228 this->pal_image = malloc(this->stride * this->height);
231 return this->image != NULL;
235 * \param pal palette in MPlayer-style gray-alpha values, i.e.
236 * alpha == 0 means transparent, 1 fully opaque,
237 * gray value <= 256 - alpha.
239 static void pal2gray_alpha(const uint16_t *pal,
240 const uint8_t *src, int src_stride,
241 uint8_t *dst, uint8_t *dsta,
242 int dst_stride, int w, int h)
244 int x, y;
245 for (y = 0; y < h; y++) {
246 for (x = 0; x < w; x++) {
247 uint16_t pixel = pal[src[x]];
248 *dst++ = pixel;
249 *dsta++ = pixel >> 8;
251 for (; x < dst_stride; x++)
252 *dsta++ = *dst++ = 0;
253 src += src_stride;
257 static void spudec_process_data(spudec_handle_t *this, packet_t *packet)
259 uint16_t pal[4];
260 unsigned int i, x, y;
261 uint8_t *dst;
263 this->scaled_frame_width = 0;
264 this->scaled_frame_height = 0;
265 this->start_col = packet->start_col;
266 this->end_col = packet->end_col;
267 this->start_row = packet->start_row;
268 this->end_row = packet->end_row;
269 this->height = packet->height;
270 this->width = packet->width;
271 this->stride = packet->stride;
272 for (i = 0; i < 4; ++i) {
273 int color;
274 int alpha = packet->alpha[i];
275 // extend 4 -> 8 bit
276 alpha |= alpha << 4;
277 if (this->custom && (this->cuspal[i] >> 31) != 0)
278 alpha = 0;
279 color = this->custom ? this->cuspal[i] :
280 this->global_palette[packet->palette[i]];
281 color = (color >> 16) & 0xff;
282 // convert to MPlayer-style gray/alpha palette
283 color = FFMIN(color, alpha);
284 pal[i] = (-alpha << 8) | color;
287 if (!spudec_alloc_image(this, this->stride, this->height))
288 return;
290 i = packet->current_nibble[1];
291 x = 0;
292 y = 0;
293 dst = this->pal_image;
294 while (packet->current_nibble[0] < i
295 && packet->current_nibble[1] / 2 < packet->control_start
296 && y < this->height) {
297 unsigned int len, color;
298 unsigned int rle = 0;
299 rle = get_nibble(packet);
300 if (rle < 0x04) {
301 if (rle == 0) {
302 rle = (rle << 4) | get_nibble(packet);
303 if (rle < 0x04)
304 rle = (rle << 4) | get_nibble(packet);
306 rle = (rle << 4) | get_nibble(packet);
308 color = 3 - (rle & 0x3);
309 len = rle >> 2;
310 x += len;
311 if (len == 0 || x >= this->width) {
312 len += this->width - x;
313 next_line(packet);
314 x = 0;
315 ++y;
317 memset(dst, color, len);
318 dst += len;
320 pal2gray_alpha(pal, this->pal_image, this->width,
321 this->image, this->aimage, this->stride,
322 this->width, this->height);
323 spudec_cut_image(this);
328 This function tries to create a usable palette.
329 It determines how many non-transparent colors are used, and assigns different
330 gray scale values to each color.
331 I tested it with four streams and even got something readable. Half of the
332 times I got black characters with white around and half the reverse.
334 static void compute_palette(spudec_handle_t *this, packet_t *packet)
336 int used[16],i,cused,start,step,color;
338 memset(used, 0, sizeof(used));
339 for (i=0; i<4; i++)
340 if (packet->alpha[i]) /* !Transparent? */
341 used[packet->palette[i]] = 1;
342 for (cused=0, i=0; i<16; i++)
343 if (used[i]) cused++;
344 if (!cused) return;
345 if (cused == 1) {
346 start = 0x80;
347 step = 0;
348 } else {
349 start = this->font_start_level;
350 step = (0xF0-this->font_start_level)/(cused-1);
352 memset(used, 0, sizeof(used));
353 for (i=0; i<4; i++) {
354 color = packet->palette[i];
355 if (packet->alpha[i] && !used[color]) { /* not assigned? */
356 used[color] = 1;
357 this->global_palette[color] = start<<16;
358 start += step;
363 static void spudec_process_control(spudec_handle_t *this, int pts100)
365 int a,b,c,d; /* Temporary vars */
366 unsigned int date, type;
367 unsigned int off;
368 unsigned int start_off = 0;
369 unsigned int next_off;
370 unsigned int start_pts = 0;
371 unsigned int end_pts = 0;
372 unsigned int current_nibble[2] = {0, 0};
373 unsigned int control_start;
374 unsigned int display = 0;
375 unsigned int start_col = 0;
376 unsigned int end_col = 0;
377 unsigned int start_row = 0;
378 unsigned int end_row = 0;
379 unsigned int width = 0;
380 unsigned int height = 0;
381 unsigned int stride = 0;
383 control_start = get_be16(this->packet + 2);
384 next_off = control_start;
385 while (start_off != next_off) {
386 start_off = next_off;
387 date = get_be16(this->packet + start_off) * 1024;
388 next_off = get_be16(this->packet + start_off + 2);
389 mp_msg(MSGT_SPUDEC,MSGL_DBG2, "date=%d\n", date);
390 off = start_off + 4;
391 for (type = this->packet[off++]; type != 0xff; type = this->packet[off++]) {
392 mp_msg(MSGT_SPUDEC,MSGL_DBG2, "cmd=%d ",type);
393 switch(type) {
394 case 0x00:
395 /* Menu ID, 1 byte */
396 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Menu ID\n");
397 /* shouldn't a Menu ID type force display start? */
398 start_pts = pts100 < 0 && -pts100 >= date ? 0 : pts100 + date;
399 end_pts = UINT_MAX;
400 display = 1;
401 this->is_forced_sub=~0; // current subtitle is forced
402 break;
403 case 0x01:
404 /* Start display */
405 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Start display!\n");
406 start_pts = pts100 < 0 && -pts100 >= date ? 0 : pts100 + date;
407 end_pts = UINT_MAX;
408 display = 1;
409 this->is_forced_sub=0;
410 break;
411 case 0x02:
412 /* Stop display */
413 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Stop display!\n");
414 end_pts = pts100 < 0 && -pts100 >= date ? 0 : pts100 + date;
415 break;
416 case 0x03:
417 /* Palette */
418 this->palette[0] = this->packet[off] >> 4;
419 this->palette[1] = this->packet[off] & 0xf;
420 this->palette[2] = this->packet[off + 1] >> 4;
421 this->palette[3] = this->packet[off + 1] & 0xf;
422 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Palette %d, %d, %d, %d\n",
423 this->palette[0], this->palette[1], this->palette[2], this->palette[3]);
424 off+=2;
425 break;
426 case 0x04:
427 /* Alpha */
428 a = this->packet[off] >> 4;
429 b = this->packet[off] & 0xf;
430 c = this->packet[off + 1] >> 4;
431 d = this->packet[off + 1] & 0xf;
432 // Note: some DVDs change these values to create a fade-in/fade-out effect
433 // We can not handle this, so just keep the highest value during the display time.
434 if (display) {
435 a = FFMAX(a, this->alpha[0]);
436 b = FFMAX(b, this->alpha[1]);
437 c = FFMAX(c, this->alpha[2]);
438 d = FFMAX(d, this->alpha[3]);
440 this->alpha[0] = a;
441 this->alpha[1] = b;
442 this->alpha[2] = c;
443 this->alpha[3] = d;
444 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Alpha %d, %d, %d, %d\n",
445 this->alpha[0], this->alpha[1], this->alpha[2], this->alpha[3]);
446 off+=2;
447 break;
448 case 0x05:
449 /* Co-ords */
450 a = get_be24(this->packet + off);
451 b = get_be24(this->packet + off + 3);
452 start_col = a >> 12;
453 end_col = a & 0xfff;
454 width = (end_col < start_col) ? 0 : end_col - start_col + 1;
455 stride = (width + 7) & ~7; /* Kludge: draw_alpha needs width multiple of 8 */
456 start_row = b >> 12;
457 end_row = b & 0xfff;
458 height = (end_row < start_row) ? 0 : end_row - start_row /* + 1 */;
459 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Coords col: %d - %d row: %d - %d (%dx%d)\n",
460 start_col, end_col, start_row, end_row,
461 width, height);
462 off+=6;
463 break;
464 case 0x06:
465 /* Graphic lines */
466 current_nibble[0] = 2 * get_be16(this->packet + off);
467 current_nibble[1] = 2 * get_be16(this->packet + off + 2);
468 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Graphic offset 1: %d offset 2: %d\n",
469 current_nibble[0] / 2, current_nibble[1] / 2);
470 off+=4;
471 break;
472 case 0xff:
473 /* All done, bye-bye */
474 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Done!\n");
475 return;
476 // break;
477 default:
478 mp_msg(MSGT_SPUDEC,MSGL_WARN,"spudec: Error determining control type 0x%02x. Skipping %d bytes.\n",
479 type, next_off - off);
480 goto next_control;
483 next_control:
484 if (!display)
485 continue;
486 if (end_pts == UINT_MAX && start_off != next_off) {
487 end_pts = get_be16(this->packet + next_off) * 1024;
488 end_pts = 1 - pts100 >= end_pts ? 0 : pts100 + end_pts - 1;
490 if (end_pts > 0) {
491 packet_t *packet = calloc(1, sizeof(packet_t));
492 int i;
493 packet->start_pts = start_pts;
494 packet->end_pts = end_pts;
495 packet->current_nibble[0] = current_nibble[0];
496 packet->current_nibble[1] = current_nibble[1];
497 packet->start_row = start_row;
498 packet->end_row = end_row;
499 packet->start_col = start_col;
500 packet->end_col = end_col;
501 packet->width = width;
502 packet->height = height;
503 packet->stride = stride;
504 packet->control_start = control_start;
505 for (i=0; i<4; i++) {
506 packet->alpha[i] = this->alpha[i];
507 packet->palette[i] = this->palette[i];
509 packet->packet = malloc(this->packet_size);
510 memcpy(packet->packet, this->packet, this->packet_size);
511 spudec_queue_packet(this, packet);
516 static void spudec_decode(spudec_handle_t *this, int pts100)
518 if (!this->hw_spu)
519 spudec_process_control(this, pts100);
520 else if (pts100 >= 0) {
521 static vo_mpegpes_t packet = { NULL, 0, 0x20, 0 };
522 static vo_mpegpes_t *pkg=&packet;
523 packet.data = this->packet;
524 packet.size = this->packet_size;
525 packet.timestamp = pts100;
526 vo_draw_frame(this->hw_spu, (uint8_t**)&pkg);
530 int spudec_changed(void * this)
532 spudec_handle_t * spu = this;
533 return spu->spu_changed || spu->now_pts > spu->end_pts;
536 void spudec_assemble(void *this, unsigned char *packet, unsigned int len, int pts100)
538 spudec_handle_t *spu = this;
539 // spudec_heartbeat(this, pts100);
540 if (len < 2) {
541 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: packet too short\n");
542 return;
544 spu->packet_pts = pts100;
545 if (spu->packet_offset == 0) {
546 unsigned int len2 = get_be16(packet);
547 // Start new fragment
548 if (spu->packet_reserve < len2) {
549 if (spu->packet != NULL)
550 free(spu->packet);
551 spu->packet = malloc(len2);
552 spu->packet_reserve = spu->packet != NULL ? len2 : 0;
554 if (spu->packet != NULL) {
555 spu->packet_size = len2;
556 if (len > len2) {
557 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: invalid frag len / len2: %d / %d \n", len, len2);
558 return;
560 memcpy(spu->packet, packet, len);
561 spu->packet_offset = len;
562 spu->packet_pts = pts100;
564 } else {
565 // Continue current fragment
566 if (spu->packet_size < spu->packet_offset + len){
567 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: invalid fragment\n");
568 spu->packet_size = spu->packet_offset = 0;
569 return;
570 } else {
571 memcpy(spu->packet + spu->packet_offset, packet, len);
572 spu->packet_offset += len;
575 #if 1
576 // check if we have a complete packet (unfortunatelly packet_size is bad
577 // for some disks)
578 // [cb] packet_size is padded to be even -> may be one byte too long
579 if ((spu->packet_offset == spu->packet_size) ||
580 ((spu->packet_offset + 1) == spu->packet_size)){
581 unsigned int x=0,y;
582 while(x+4<=spu->packet_offset){
583 y=get_be16(spu->packet+x+2); // next control pointer
584 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPUtest: x=%d y=%d off=%d size=%d\n",x,y,spu->packet_offset,spu->packet_size);
585 if(x>=4 && x==y){ // if it points to self - we're done!
586 // we got it!
587 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPUgot: off=%d size=%d \n",spu->packet_offset,spu->packet_size);
588 spudec_decode(spu, pts100);
589 spu->packet_offset = 0;
590 break;
592 if(y<=x || y>=spu->packet_size){ // invalid?
593 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUtest: broken packet!!!!! y=%d < x=%d\n",y,x);
594 spu->packet_size = spu->packet_offset = 0;
595 break;
597 x=y;
599 // [cb] packet is done; start new packet
600 spu->packet_offset = 0;
602 #else
603 if (spu->packet_offset == spu->packet_size) {
604 spudec_decode(spu, pts100);
605 spu->packet_offset = 0;
607 #endif
610 void spudec_reset(void *this) // called after seek
612 spudec_handle_t *spu = this;
613 while (spu->queue_head)
614 spudec_free_packet(spudec_dequeue_packet(spu));
615 spu->now_pts = 0;
616 spu->end_pts = 0;
617 spu->packet_size = spu->packet_offset = 0;
620 void spudec_heartbeat(void *this, unsigned int pts100)
622 spudec_handle_t *spu = this;
623 spu->now_pts = pts100;
625 // TODO: detect and handle broken timestamps (e.g. due to wrapping)
626 while (spu->queue_head != NULL && pts100 >= spu->queue_head->start_pts) {
627 packet_t *packet = spudec_dequeue_packet(spu);
628 spu->start_pts = packet->start_pts;
629 spu->end_pts = packet->end_pts;
630 if (packet->is_decoded) {
631 free(spu->image);
632 spu->image_size = packet->data_len;
633 spu->image = packet->packet;
634 spu->aimage = packet->packet + packet->stride * packet->height;
635 packet->packet = NULL;
636 spu->width = packet->width;
637 spu->height = packet->height;
638 spu->stride = packet->stride;
639 spu->start_col = packet->start_col;
640 spu->start_row = packet->start_row;
642 // reset scaled image
643 spu->scaled_frame_width = 0;
644 spu->scaled_frame_height = 0;
645 } else {
646 if (spu->auto_palette)
647 compute_palette(spu, packet);
648 spudec_process_data(spu, packet);
650 spudec_free_packet(packet);
651 spu->spu_changed = 1;
655 int spudec_visible(void *this){
656 spudec_handle_t *spu = this;
657 int ret=(spu->start_pts <= spu->now_pts &&
658 spu->now_pts < spu->end_pts &&
659 spu->height > 0);
660 // printf("spu visible: %d \n",ret);
661 return ret;
664 void spudec_set_forced_subs_only(void * const this, const unsigned int flag)
666 if(this){
667 ((spudec_handle_t *)this)->forced_subs_only=flag;
668 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPU: Display only forced subs now %s\n", flag ? "enabled": "disabled");
672 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)
674 spudec_handle_t *spu = this;
675 if (spudec_visible(spu))
677 draw_alpha(ctx, spu->start_col, spu->start_row, spu->width, spu->height,
678 spu->image, spu->aimage, spu->stride);
679 spu->spu_changed = 0;
683 /* calc the bbox for spudec subs */
684 void spudec_calc_bbox(void *me, unsigned int dxs, unsigned int dys, unsigned int* bbox)
686 spudec_handle_t *spu = me;
687 if (spu->orig_frame_width == 0 || spu->orig_frame_height == 0
688 || (spu->orig_frame_width == dxs && spu->orig_frame_height == dys)) {
689 // unscaled
690 bbox[0] = spu->start_col;
691 bbox[1] = spu->start_col + spu->width;
692 bbox[2] = spu->start_row;
693 bbox[3] = spu->start_row + spu->height;
695 else {
696 // scaled
697 unsigned int scalex = 0x100 * dxs / spu->orig_frame_width;
698 unsigned int scaley = 0x100 * dys / spu->orig_frame_height;
699 bbox[0] = spu->start_col * scalex / 0x100;
700 bbox[1] = spu->start_col * scalex / 0x100 + spu->width * scalex / 0x100;
701 switch (spu_alignment) {
702 case 0:
703 bbox[3] = dys*sub_pos/100 + spu->height * scaley / 0x100;
704 if (bbox[3] > dys) bbox[3] = dys;
705 bbox[2] = bbox[3] - spu->height * scaley / 0x100;
706 break;
707 case 1:
708 if (sub_pos < 50) {
709 bbox[2] = dys*sub_pos/100 - spu->height * scaley / 0x200;
710 bbox[3] = bbox[2] + spu->height;
711 } else {
712 bbox[3] = dys*sub_pos/100 + spu->height * scaley / 0x200;
713 if (bbox[3] > dys) bbox[3] = dys;
714 bbox[2] = bbox[3] - spu->height * scaley / 0x100;
716 break;
717 case 2:
718 bbox[2] = dys*sub_pos/100 - spu->height * scaley / 0x100;
719 bbox[3] = bbox[2] + spu->height;
720 break;
721 default: /* -1 */
722 bbox[2] = spu->start_row * scaley / 0x100;
723 bbox[3] = spu->start_row * scaley / 0x100 + spu->height * scaley / 0x100;
724 break;
728 /* transform mplayer's alpha value into an opacity value that is linear */
729 static inline int canon_alpha(int alpha)
731 return (uint8_t)-alpha;
734 typedef struct {
735 unsigned position;
736 unsigned left_up;
737 unsigned right_down;
738 }scale_pixel;
741 static void scale_table(unsigned int start_src, unsigned int start_tar, unsigned int end_src, unsigned int end_tar, scale_pixel * table)
743 unsigned int t;
744 unsigned int delta_src = end_src - start_src;
745 unsigned int delta_tar = end_tar - start_tar;
746 int src = 0;
747 int src_step;
748 if (delta_src == 0 || delta_tar == 0) {
749 return;
751 src_step = (delta_src << 16) / delta_tar >>1;
752 for (t = 0; t<=delta_tar; src += (src_step << 1), t++){
753 table[t].position= FFMIN(src >> 16, end_src - 1);
754 table[t].right_down = src & 0xffff;
755 table[t].left_up = 0x10000 - table[t].right_down;
759 /* bilinear scale, similar to vobsub's code */
760 static void scale_image(int x, int y, scale_pixel* table_x, scale_pixel* table_y, spudec_handle_t * spu)
762 int alpha[4];
763 int color[4];
764 unsigned int scale[4];
765 int base = table_y[y].position * spu->stride + table_x[x].position;
766 int scaled = y * spu->scaled_stride + x;
767 alpha[0] = canon_alpha(spu->aimage[base]);
768 alpha[1] = canon_alpha(spu->aimage[base + 1]);
769 alpha[2] = canon_alpha(spu->aimage[base + spu->stride]);
770 alpha[3] = canon_alpha(spu->aimage[base + spu->stride + 1]);
771 color[0] = spu->image[base];
772 color[1] = spu->image[base + 1];
773 color[2] = spu->image[base + spu->stride];
774 color[3] = spu->image[base + spu->stride + 1];
775 scale[0] = (table_x[x].left_up * table_y[y].left_up >> 16) * alpha[0];
776 if (table_y[y].left_up == 0x10000) // necessary to avoid overflow-case
777 scale[0] = table_x[x].left_up * alpha[0];
778 scale[1] = (table_x[x].right_down * table_y[y].left_up >>16) * alpha[1];
779 scale[2] = (table_x[x].left_up * table_y[y].right_down >> 16) * alpha[2];
780 scale[3] = (table_x[x].right_down * table_y[y].right_down >> 16) * alpha[3];
781 spu->scaled_image[scaled] = (color[0] * scale[0] + color[1] * scale[1] + color[2] * scale[2] + color[3] * scale[3])>>24;
782 spu->scaled_aimage[scaled] = (scale[0] + scale[1] + scale[2] + scale[3]) >> 16;
783 if (spu->scaled_aimage[scaled]){
784 // ensure that MPlayer's simplified alpha-blending can not overflow
785 spu->scaled_image[scaled] = FFMIN(spu->scaled_image[scaled], spu->scaled_aimage[scaled]);
786 // convert to MPlayer-style alpha
787 spu->scaled_aimage[scaled] = -spu->scaled_aimage[scaled];
791 static void sws_spu_image(unsigned char *d1, unsigned char *d2, int dw, int dh,
792 int ds, unsigned char *s1, unsigned char *s2, int sw,
793 int sh, int ss)
795 struct SwsContext *ctx;
796 static SwsFilter filter;
797 static int firsttime = 1;
798 static float oldvar;
799 int i;
801 if (!firsttime && oldvar != spu_gaussvar) sws_freeVec(filter.lumH);
802 if (firsttime) {
803 filter.lumH = filter.lumV =
804 filter.chrH = filter.chrV = sws_getGaussianVec(spu_gaussvar, 3.0);
805 sws_normalizeVec(filter.lumH, 1.0);
806 firsttime = 0;
807 oldvar = spu_gaussvar;
810 ctx=sws_getContext(sw, sh, PIX_FMT_GRAY8, dw, dh, PIX_FMT_GRAY8, SWS_GAUSS, &filter, NULL, NULL);
811 sws_scale(ctx,&s1,&ss,0,sh,&d1,&ds);
812 for (i=ss*sh-1; i>=0; i--) if (!s2[i]) s2[i] = 255; //else s2[i] = 1;
813 sws_scale(ctx,&s2,&ss,0,sh,&d2,&ds);
814 for (i=ds*dh-1; i>=0; i--) if (d2[i]==0) d2[i] = 1; else if (d2[i]==255) d2[i] = 0;
815 sws_freeContext(ctx);
818 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)
820 spudec_handle_t *spu = me;
821 scale_pixel *table_x;
822 scale_pixel *table_y;
824 if (spudec_visible(spu)) {
826 // check if only forced subtitles are requested
827 if( (spu->forced_subs_only) && !(spu->is_forced_sub) ){
828 return;
831 if (!(spu_aamode&16) && (spu->orig_frame_width == 0 || spu->orig_frame_height == 0
832 || (spu->orig_frame_width == dxs && spu->orig_frame_height == dys))) {
833 spudec_draw(spu, draw_alpha, ctx);
835 else {
836 if (spu->scaled_frame_width != dxs || spu->scaled_frame_height != dys) { /* Resizing is needed */
837 /* scaled_x = scalex * x / 0x100
838 scaled_y = scaley * y / 0x100
839 order of operations is important because of rounding. */
840 unsigned int scalex = 0x100 * dxs / spu->orig_frame_width;
841 unsigned int scaley = 0x100 * dys / spu->orig_frame_height;
842 spu->scaled_start_col = spu->start_col * scalex / 0x100;
843 spu->scaled_start_row = spu->start_row * scaley / 0x100;
844 spu->scaled_width = spu->width * scalex / 0x100;
845 spu->scaled_height = spu->height * scaley / 0x100;
846 /* Kludge: draw_alpha needs width multiple of 8 */
847 spu->scaled_stride = (spu->scaled_width + 7) & ~7;
848 if (spu->scaled_image_size < spu->scaled_stride * spu->scaled_height) {
849 if (spu->scaled_image) {
850 free(spu->scaled_image);
851 spu->scaled_image_size = 0;
853 spu->scaled_image = malloc(2 * spu->scaled_stride * spu->scaled_height);
854 if (spu->scaled_image) {
855 spu->scaled_image_size = spu->scaled_stride * spu->scaled_height;
856 spu->scaled_aimage = spu->scaled_image + spu->scaled_image_size;
859 if (spu->scaled_image) {
860 unsigned int x, y;
861 if (spu->scaled_width <= 1 || spu->scaled_height <= 1) {
862 goto nothing_to_do;
864 switch(spu_aamode&15) {
865 case 4:
866 sws_spu_image(spu->scaled_image, spu->scaled_aimage,
867 spu->scaled_width, spu->scaled_height, spu->scaled_stride,
868 spu->image, spu->aimage, spu->width, spu->height, spu->stride);
869 break;
870 case 3:
871 table_x = calloc(spu->scaled_width, sizeof(scale_pixel));
872 table_y = calloc(spu->scaled_height, sizeof(scale_pixel));
873 if (!table_x || !table_y) {
874 mp_msg(MSGT_SPUDEC, MSGL_FATAL, "Fatal: spudec_draw_scaled: calloc failed\n");
876 scale_table(0, 0, spu->width - 1, spu->scaled_width - 1, table_x);
877 scale_table(0, 0, spu->height - 1, spu->scaled_height - 1, table_y);
878 for (y = 0; y < spu->scaled_height; y++)
879 for (x = 0; x < spu->scaled_width; x++)
880 scale_image(x, y, table_x, table_y, spu);
881 free(table_x);
882 free(table_y);
883 break;
884 case 0:
885 /* no antialiasing */
886 for (y = 0; y < spu->scaled_height; ++y) {
887 int unscaled_y = y * 0x100 / scaley;
888 int strides = spu->stride * unscaled_y;
889 int scaled_strides = spu->scaled_stride * y;
890 for (x = 0; x < spu->scaled_width; ++x) {
891 int unscaled_x = x * 0x100 / scalex;
892 spu->scaled_image[scaled_strides + x] = spu->image[strides + unscaled_x];
893 spu->scaled_aimage[scaled_strides + x] = spu->aimage[strides + unscaled_x];
896 break;
897 case 1:
899 /* Intermediate antialiasing. */
900 for (y = 0; y < spu->scaled_height; ++y) {
901 const unsigned int unscaled_top = y * spu->orig_frame_height / dys;
902 unsigned int unscaled_bottom = (y + 1) * spu->orig_frame_height / dys;
903 if (unscaled_bottom >= spu->height)
904 unscaled_bottom = spu->height - 1;
905 for (x = 0; x < spu->scaled_width; ++x) {
906 const unsigned int unscaled_left = x * spu->orig_frame_width / dxs;
907 unsigned int unscaled_right = (x + 1) * spu->orig_frame_width / dxs;
908 unsigned int color = 0;
909 unsigned int alpha = 0;
910 unsigned int walkx, walky;
911 unsigned int base, tmp;
912 if (unscaled_right >= spu->width)
913 unscaled_right = spu->width - 1;
914 for (walky = unscaled_top; walky <= unscaled_bottom; ++walky)
915 for (walkx = unscaled_left; walkx <= unscaled_right; ++walkx) {
916 base = walky * spu->stride + walkx;
917 tmp = canon_alpha(spu->aimage[base]);
918 alpha += tmp;
919 color += tmp * spu->image[base];
921 base = y * spu->scaled_stride + x;
922 spu->scaled_image[base] = alpha ? color / alpha : 0;
923 spu->scaled_aimage[base] =
924 alpha * (1 + unscaled_bottom - unscaled_top) * (1 + unscaled_right - unscaled_left);
925 /* spu->scaled_aimage[base] =
926 alpha * dxs * dys / spu->orig_frame_width / spu->orig_frame_height; */
927 if (spu->scaled_aimage[base]) {
928 spu->scaled_aimage[base] = 256 - spu->scaled_aimage[base];
929 if (spu->scaled_aimage[base] + spu->scaled_image[base] > 255)
930 spu->scaled_image[base] = 256 - spu->scaled_aimage[base];
935 break;
936 case 2:
938 /* Best antialiasing. Very slow. */
939 /* Any pixel (x, y) represents pixels from the original
940 rectangular region comprised between the columns
941 unscaled_y and unscaled_y + 0x100 / scaley and the rows
942 unscaled_x and unscaled_x + 0x100 / scalex
944 The original rectangular region that the scaled pixel
945 represents is cut in 9 rectangular areas like this:
947 +---+-----------------+---+
948 | 1 | 2 | 3 |
949 +---+-----------------+---+
950 | | | |
951 | 4 | 5 | 6 |
952 | | | |
953 +---+-----------------+---+
954 | 7 | 8 | 9 |
955 +---+-----------------+---+
957 The width of the left column is at most one pixel and
958 it is never null and its right column is at a pixel
959 boundary. The height of the top row is at most one
960 pixel it is never null and its bottom row is at a
961 pixel boundary. The width and height of region 5 are
962 integral values. The width of the right column is
963 what remains and is less than one pixel. The height
964 of the bottom row is what remains and is less than
965 one pixel.
967 The row above 1, 2, 3 is unscaled_y. The row between
968 1, 2, 3 and 4, 5, 6 is top_low_row. The row between 4,
969 5, 6 and 7, 8, 9 is (unsigned int)unscaled_y_bottom.
970 The row beneath 7, 8, 9 is unscaled_y_bottom.
972 The column left of 1, 4, 7 is unscaled_x. The column
973 between 1, 4, 7 and 2, 5, 8 is left_right_column. The
974 column between 2, 5, 8 and 3, 6, 9 is (unsigned
975 int)unscaled_x_right. The column right of 3, 6, 9 is
976 unscaled_x_right. */
977 const double inv_scalex = (double) 0x100 / scalex;
978 const double inv_scaley = (double) 0x100 / scaley;
979 for (y = 0; y < spu->scaled_height; ++y) {
980 const double unscaled_y = y * inv_scaley;
981 const double unscaled_y_bottom = unscaled_y + inv_scaley;
982 const unsigned int top_low_row = FFMIN(unscaled_y_bottom, unscaled_y + 1.0);
983 const double top = top_low_row - unscaled_y;
984 const unsigned int height = unscaled_y_bottom > top_low_row
985 ? (unsigned int) unscaled_y_bottom - top_low_row
986 : 0;
987 const double bottom = unscaled_y_bottom > top_low_row
988 ? unscaled_y_bottom - floor(unscaled_y_bottom)
989 : 0.0;
990 for (x = 0; x < spu->scaled_width; ++x) {
991 const double unscaled_x = x * inv_scalex;
992 const double unscaled_x_right = unscaled_x + inv_scalex;
993 const unsigned int left_right_column = FFMIN(unscaled_x_right, unscaled_x + 1.0);
994 const double left = left_right_column - unscaled_x;
995 const unsigned int width = unscaled_x_right > left_right_column
996 ? (unsigned int) unscaled_x_right - left_right_column
997 : 0;
998 const double right = unscaled_x_right > left_right_column
999 ? unscaled_x_right - floor(unscaled_x_right)
1000 : 0.0;
1001 double color = 0.0;
1002 double alpha = 0.0;
1003 double tmp;
1004 unsigned int base;
1005 /* Now use these informations to compute a good alpha,
1006 and lightness. The sum is on each of the 9
1007 region's surface and alpha and lightness.
1009 transformed alpha = sum(surface * alpha) / sum(surface)
1010 transformed color = sum(surface * alpha * color) / sum(surface * alpha)
1012 /* 1: top left part */
1013 base = spu->stride * (unsigned int) unscaled_y;
1014 tmp = left * top * canon_alpha(spu->aimage[base + (unsigned int) unscaled_x]);
1015 alpha += tmp;
1016 color += tmp * spu->image[base + (unsigned int) unscaled_x];
1017 /* 2: top center part */
1018 if (width > 0) {
1019 unsigned int walkx;
1020 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
1021 base = spu->stride * (unsigned int) unscaled_y + walkx;
1022 tmp = /* 1.0 * */ top * canon_alpha(spu->aimage[base]);
1023 alpha += tmp;
1024 color += tmp * spu->image[base];
1027 /* 3: top right part */
1028 if (right > 0.0) {
1029 base = spu->stride * (unsigned int) unscaled_y + (unsigned int) unscaled_x_right;
1030 tmp = right * top * canon_alpha(spu->aimage[base]);
1031 alpha += tmp;
1032 color += tmp * spu->image[base];
1034 /* 4: center left part */
1035 if (height > 0) {
1036 unsigned int walky;
1037 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1038 base = spu->stride * walky + (unsigned int) unscaled_x;
1039 tmp = left /* * 1.0 */ * canon_alpha(spu->aimage[base]);
1040 alpha += tmp;
1041 color += tmp * spu->image[base];
1044 /* 5: center part */
1045 if (width > 0 && height > 0) {
1046 unsigned int walky;
1047 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1048 unsigned int walkx;
1049 base = spu->stride * walky;
1050 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
1051 tmp = /* 1.0 * 1.0 * */ canon_alpha(spu->aimage[base + walkx]);
1052 alpha += tmp;
1053 color += tmp * spu->image[base + walkx];
1057 /* 6: center right part */
1058 if (right > 0.0 && height > 0) {
1059 unsigned int walky;
1060 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1061 base = spu->stride * walky + (unsigned int) unscaled_x_right;
1062 tmp = right /* * 1.0 */ * canon_alpha(spu->aimage[base]);
1063 alpha += tmp;
1064 color += tmp * spu->image[base];
1067 /* 7: bottom left part */
1068 if (bottom > 0.0) {
1069 base = spu->stride * (unsigned int) unscaled_y_bottom + (unsigned int) unscaled_x;
1070 tmp = left * bottom * canon_alpha(spu->aimage[base]);
1071 alpha += tmp;
1072 color += tmp * spu->image[base];
1074 /* 8: bottom center part */
1075 if (width > 0 && bottom > 0.0) {
1076 unsigned int walkx;
1077 base = spu->stride * (unsigned int) unscaled_y_bottom;
1078 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
1079 tmp = /* 1.0 * */ bottom * canon_alpha(spu->aimage[base + walkx]);
1080 alpha += tmp;
1081 color += tmp * spu->image[base + walkx];
1084 /* 9: bottom right part */
1085 if (right > 0.0 && bottom > 0.0) {
1086 base = spu->stride * (unsigned int) unscaled_y_bottom + (unsigned int) unscaled_x_right;
1087 tmp = right * bottom * canon_alpha(spu->aimage[base]);
1088 alpha += tmp;
1089 color += tmp * spu->image[base];
1091 /* Finally mix these transparency and brightness information suitably */
1092 base = spu->scaled_stride * y + x;
1093 spu->scaled_image[base] = alpha > 0 ? color / alpha : 0;
1094 spu->scaled_aimage[base] = alpha * scalex * scaley / 0x10000;
1095 if (spu->scaled_aimage[base]) {
1096 spu->scaled_aimage[base] = 256 - spu->scaled_aimage[base];
1097 if (spu->scaled_aimage[base] + spu->scaled_image[base] > 255)
1098 spu->scaled_image[base] = 256 - spu->scaled_aimage[base];
1104 nothing_to_do:
1105 /* Kludge: draw_alpha needs width multiple of 8. */
1106 if (spu->scaled_width < spu->scaled_stride)
1107 for (y = 0; y < spu->scaled_height; ++y) {
1108 memset(spu->scaled_aimage + y * spu->scaled_stride + spu->scaled_width, 0,
1109 spu->scaled_stride - spu->scaled_width);
1111 spu->scaled_frame_width = dxs;
1112 spu->scaled_frame_height = dys;
1115 if (spu->scaled_image){
1116 switch (spu_alignment) {
1117 case 0:
1118 spu->scaled_start_row = dys*sub_pos/100;
1119 if (spu->scaled_start_row + spu->scaled_height > dys)
1120 spu->scaled_start_row = dys - spu->scaled_height;
1121 break;
1122 case 1:
1123 spu->scaled_start_row = dys*sub_pos/100 - spu->scaled_height/2;
1124 if (sub_pos >= 50 && spu->scaled_start_row + spu->scaled_height > dys)
1125 spu->scaled_start_row = dys - spu->scaled_height;
1126 break;
1127 case 2:
1128 spu->scaled_start_row = dys*sub_pos/100 - spu->scaled_height;
1129 break;
1131 draw_alpha(ctx, spu->scaled_start_col, spu->scaled_start_row, spu->scaled_width, spu->scaled_height,
1132 spu->scaled_image, spu->scaled_aimage, spu->scaled_stride);
1133 spu->spu_changed = 0;
1137 else
1139 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPU not displayed: start_pts=%d end_pts=%d now_pts=%d\n",
1140 spu->start_pts, spu->end_pts, spu->now_pts);
1144 void spudec_update_palette(void * this, unsigned int *palette)
1146 spudec_handle_t *spu = this;
1147 if (spu && palette) {
1148 memcpy(spu->global_palette, palette, sizeof(spu->global_palette));
1149 if(spu->hw_spu)
1150 vo_control(spu->hw_spu, VOCTRL_SET_SPU_PALETTE, spu->global_palette);
1154 void spudec_set_font_factor(void * this, double factor)
1156 spudec_handle_t *spu = this;
1157 spu->font_start_level = (int)(0xF0-(0xE0*factor));
1160 static void spudec_parse_extradata(spudec_handle_t *this,
1161 uint8_t *extradata, int extradata_len)
1163 uint8_t *buffer, *ptr;
1164 unsigned int *pal = this->global_palette, *cuspal = this->cuspal;
1165 unsigned int tridx;
1166 int i;
1168 if (extradata_len == 16*4) {
1169 for (i=0; i<16; i++)
1170 pal[i] = AV_RB32(extradata + i*4);
1171 this->auto_palette = 0;
1172 return;
1175 if (!(ptr = buffer = malloc(extradata_len+1)))
1176 return;
1177 memcpy(buffer, extradata, extradata_len);
1178 buffer[extradata_len] = 0;
1180 do {
1181 if (*ptr == '#')
1182 continue;
1183 if (!strncmp(ptr, "size: ", 6))
1184 sscanf(ptr + 6, "%dx%d", &this->orig_frame_width, &this->orig_frame_height);
1185 if (!strncmp(ptr, "palette: ", 9) &&
1186 sscanf(ptr + 9, "%x, %x, %x, %x, %x, %x, %x, %x, "
1187 "%x, %x, %x, %x, %x, %x, %x, %x",
1188 &pal[ 0], &pal[ 1], &pal[ 2], &pal[ 3],
1189 &pal[ 4], &pal[ 5], &pal[ 6], &pal[ 7],
1190 &pal[ 8], &pal[ 9], &pal[10], &pal[11],
1191 &pal[12], &pal[13], &pal[14], &pal[15]) == 16) {
1192 for (i=0; i<16; i++)
1193 pal[i] = vobsub_palette_to_yuv(pal[i]);
1194 this->auto_palette = 0;
1196 if (!strncasecmp(ptr, "forced subs: on", 15))
1197 this->forced_subs_only = 1;
1198 if (!strncmp(ptr, "custom colors: ON, tridx: ", 26) &&
1199 sscanf(ptr + 26, "%x, colors: %x, %x, %x, %x",
1200 &tridx, cuspal+0, cuspal+1, cuspal+2, cuspal+3) == 5) {
1201 for (i=0; i<4; i++) {
1202 cuspal[i] = vobsub_rgb_to_yuv(cuspal[i]);
1203 if (tridx & (1 << (12-4*i)))
1204 cuspal[i] |= 1 << 31;
1206 this->custom = 1;
1208 } while ((ptr=strchr(ptr,'\n')) && *++ptr);
1210 free(buffer);
1213 void *spudec_new_scaled(unsigned int *palette, unsigned int frame_width, unsigned int frame_height, uint8_t *extradata, int extradata_len)
1215 spudec_handle_t *this = calloc(1, sizeof(spudec_handle_t));
1216 if (this){
1217 this->orig_frame_height = frame_height;
1218 this->orig_frame_width = frame_width;
1219 // set up palette:
1220 if (palette)
1221 memcpy(this->global_palette, palette, sizeof(this->global_palette));
1222 else
1223 this->auto_palette = 1;
1224 if (extradata)
1225 spudec_parse_extradata(this, extradata, extradata_len);
1226 /* XXX Although the video frame is some size, the SPU frame is
1227 always maximum size i.e. 720 wide and 576 or 480 high */
1228 // For HD files in MKV the VobSub resolution can be higher though,
1229 // see largeres_vobsub.mkv
1230 if (this->orig_frame_width <= 720 && this->orig_frame_height <= 576) {
1231 this->orig_frame_width = 720;
1232 if (this->orig_frame_height == 480 || this->orig_frame_height == 240)
1233 this->orig_frame_height = 480;
1234 else
1235 this->orig_frame_height = 576;
1238 else
1239 mp_msg(MSGT_SPUDEC,MSGL_FATAL, "FATAL: spudec_init: calloc");
1240 return this;
1243 void *spudec_new(unsigned int *palette)
1245 return spudec_new_scaled(palette, 0, 0, NULL, 0);
1248 void spudec_free(void *this)
1250 spudec_handle_t *spu = this;
1251 if (spu) {
1252 while (spu->queue_head)
1253 spudec_free_packet(spudec_dequeue_packet(spu));
1254 free(spu->packet);
1255 spu->packet = NULL;
1256 free(spu->scaled_image);
1257 spu->scaled_image = NULL;
1258 free(spu->image);
1259 spu->image = NULL;
1260 spu->aimage = NULL;
1261 free(spu->pal_image);
1262 spu->pal_image = NULL;
1263 spu->image_size = 0;
1264 free(spu);
1268 void spudec_set_hw_spu(void *this, struct vo *hw_spu)
1270 spudec_handle_t *spu = this;
1271 if (!spu)
1272 return;
1273 spu->hw_spu = hw_spu;
1274 vo_control(hw_spu, VOCTRL_SET_SPU_PALETTE, spu->global_palette);
1277 #define MP_NOPTS_VALUE (-1LL<<63) //both int64_t and double should be able to represent this exactly
1280 * palette must contain at least 256 32-bit entries, otherwise crashes
1281 * are possible
1283 void spudec_set_paletted(void *this, const uint8_t *pal_img, int pal_stride,
1284 const void *palette,
1285 int x, int y, int w, int h,
1286 double pts, double endpts)
1288 int i;
1289 uint16_t g8a8_pal[256];
1290 packet_t *packet;
1291 const uint32_t *pal = palette;
1292 spudec_handle_t *spu = this;
1293 uint8_t *img;
1294 uint8_t *aimg;
1295 int stride = (w + 7) & ~7;
1296 if ((unsigned)w >= 0x8000 || (unsigned)h > 0x4000)
1297 return;
1298 packet = calloc(1, sizeof(packet_t));
1299 packet->is_decoded = 1;
1300 packet->width = w;
1301 packet->height = h;
1302 packet->stride = stride;
1303 packet->start_col = x;
1304 packet->start_row = y;
1305 packet->data_len = 2 * stride * h;
1306 packet->packet = malloc(packet->data_len);
1307 img = packet->packet;
1308 aimg = packet->packet + stride * h;
1309 for (i = 0; i < 256; i++) {
1310 uint32_t pixel = pal[i];
1311 int alpha = pixel >> 24;
1312 int gray = (((pixel & 0x000000ff) >> 0) +
1313 ((pixel & 0x0000ff00) >> 7) +
1314 ((pixel & 0x00ff0000) >> 16)) >> 2;
1315 gray = FFMIN(gray, alpha);
1316 g8a8_pal[i] = (-alpha << 8) | gray;
1318 pal2gray_alpha(g8a8_pal, pal_img, pal_stride,
1319 img, aimg, stride, w, h);
1320 packet->start_pts = 0;
1321 packet->end_pts = 0x7fffffff;
1322 if (pts != MP_NOPTS_VALUE)
1323 packet->start_pts = pts * 90000;
1324 if (endpts != MP_NOPTS_VALUE)
1325 packet->end_pts = endpts * 90000;
1326 spudec_queue_packet(spu, packet);