spudec.c: Remove useless end_col/end_row variables
[mplayer/glamo.git] / spudec.c
blobb57ac4b6b0cd914e53646e6a0ee2f8e7e2ce76f6
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 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;
96 unsigned int start_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->start_row = packet->start_row;
267 this->height = packet->height;
268 this->width = packet->width;
269 this->stride = packet->stride;
270 for (i = 0; i < 4; ++i) {
271 int color;
272 int alpha = packet->alpha[i];
273 // extend 4 -> 8 bit
274 alpha |= alpha << 4;
275 if (this->custom && (this->cuspal[i] >> 31) != 0)
276 alpha = 0;
277 color = this->custom ? this->cuspal[i] :
278 this->global_palette[packet->palette[i]];
279 color = (color >> 16) & 0xff;
280 // convert to MPlayer-style gray/alpha palette
281 color = FFMIN(color, alpha);
282 pal[i] = (-alpha << 8) | color;
285 if (!spudec_alloc_image(this, this->stride, this->height))
286 return;
288 i = packet->current_nibble[1];
289 x = 0;
290 y = 0;
291 dst = this->pal_image;
292 while (packet->current_nibble[0] < i
293 && packet->current_nibble[1] / 2 < packet->control_start
294 && y < this->height) {
295 unsigned int len, color;
296 unsigned int rle = 0;
297 rle = get_nibble(packet);
298 if (rle < 0x04) {
299 if (rle == 0) {
300 rle = (rle << 4) | get_nibble(packet);
301 if (rle < 0x04)
302 rle = (rle << 4) | get_nibble(packet);
304 rle = (rle << 4) | get_nibble(packet);
306 color = 3 - (rle & 0x3);
307 len = rle >> 2;
308 x += len;
309 if (len == 0 || x >= this->width) {
310 len += this->width - x;
311 next_line(packet);
312 x = 0;
313 ++y;
315 memset(dst, color, len);
316 dst += len;
318 pal2gray_alpha(pal, this->pal_image, this->width,
319 this->image, this->aimage, this->stride,
320 this->width, this->height);
321 spudec_cut_image(this);
326 This function tries to create a usable palette.
327 It determines how many non-transparent colors are used, and assigns different
328 gray scale values to each color.
329 I tested it with four streams and even got something readable. Half of the
330 times I got black characters with white around and half the reverse.
332 static void compute_palette(spudec_handle_t *this, packet_t *packet)
334 int used[16],i,cused,start,step,color;
336 memset(used, 0, sizeof(used));
337 for (i=0; i<4; i++)
338 if (packet->alpha[i]) /* !Transparent? */
339 used[packet->palette[i]] = 1;
340 for (cused=0, i=0; i<16; i++)
341 if (used[i]) cused++;
342 if (!cused) return;
343 if (cused == 1) {
344 start = 0x80;
345 step = 0;
346 } else {
347 start = this->font_start_level;
348 step = (0xF0-this->font_start_level)/(cused-1);
350 memset(used, 0, sizeof(used));
351 for (i=0; i<4; i++) {
352 color = packet->palette[i];
353 if (packet->alpha[i] && !used[color]) { /* not assigned? */
354 used[color] = 1;
355 this->global_palette[color] = start<<16;
356 start += step;
361 static void spudec_process_control(spudec_handle_t *this, int pts100)
363 int a,b,c,d; /* Temporary vars */
364 unsigned int date, type;
365 unsigned int off;
366 unsigned int start_off = 0;
367 unsigned int next_off;
368 unsigned int start_pts = 0;
369 unsigned int end_pts = 0;
370 unsigned int current_nibble[2] = {0, 0};
371 unsigned int control_start;
372 unsigned int display = 0;
373 unsigned int start_col = 0;
374 unsigned int end_col = 0;
375 unsigned int start_row = 0;
376 unsigned int end_row = 0;
377 unsigned int width = 0;
378 unsigned int height = 0;
379 unsigned int stride = 0;
381 control_start = get_be16(this->packet + 2);
382 next_off = control_start;
383 while (start_off != next_off) {
384 start_off = next_off;
385 date = get_be16(this->packet + start_off) * 1024;
386 next_off = get_be16(this->packet + start_off + 2);
387 mp_msg(MSGT_SPUDEC,MSGL_DBG2, "date=%d\n", date);
388 off = start_off + 4;
389 for (type = this->packet[off++]; type != 0xff; type = this->packet[off++]) {
390 mp_msg(MSGT_SPUDEC,MSGL_DBG2, "cmd=%d ",type);
391 switch(type) {
392 case 0x00:
393 /* Menu ID, 1 byte */
394 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Menu ID\n");
395 /* shouldn't a Menu ID type force display start? */
396 start_pts = pts100 < 0 && -pts100 >= date ? 0 : pts100 + date;
397 end_pts = UINT_MAX;
398 display = 1;
399 this->is_forced_sub=~0; // current subtitle is forced
400 break;
401 case 0x01:
402 /* Start display */
403 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Start display!\n");
404 start_pts = pts100 < 0 && -pts100 >= date ? 0 : pts100 + date;
405 end_pts = UINT_MAX;
406 display = 1;
407 this->is_forced_sub=0;
408 break;
409 case 0x02:
410 /* Stop display */
411 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Stop display!\n");
412 end_pts = pts100 < 0 && -pts100 >= date ? 0 : pts100 + date;
413 break;
414 case 0x03:
415 /* Palette */
416 this->palette[0] = this->packet[off] >> 4;
417 this->palette[1] = this->packet[off] & 0xf;
418 this->palette[2] = this->packet[off + 1] >> 4;
419 this->palette[3] = this->packet[off + 1] & 0xf;
420 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Palette %d, %d, %d, %d\n",
421 this->palette[0], this->palette[1], this->palette[2], this->palette[3]);
422 off+=2;
423 break;
424 case 0x04:
425 /* Alpha */
426 a = this->packet[off] >> 4;
427 b = this->packet[off] & 0xf;
428 c = this->packet[off + 1] >> 4;
429 d = this->packet[off + 1] & 0xf;
430 // Note: some DVDs change these values to create a fade-in/fade-out effect
431 // We can not handle this, so just keep the highest value during the display time.
432 if (display) {
433 a = FFMAX(a, this->alpha[0]);
434 b = FFMAX(b, this->alpha[1]);
435 c = FFMAX(c, this->alpha[2]);
436 d = FFMAX(d, this->alpha[3]);
438 this->alpha[0] = a;
439 this->alpha[1] = b;
440 this->alpha[2] = c;
441 this->alpha[3] = d;
442 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Alpha %d, %d, %d, %d\n",
443 this->alpha[0], this->alpha[1], this->alpha[2], this->alpha[3]);
444 off+=2;
445 break;
446 case 0x05:
447 /* Co-ords */
448 a = get_be24(this->packet + off);
449 b = get_be24(this->packet + off + 3);
450 start_col = a >> 12;
451 end_col = a & 0xfff;
452 width = (end_col < start_col) ? 0 : end_col - start_col + 1;
453 stride = (width + 7) & ~7; /* Kludge: draw_alpha needs width multiple of 8 */
454 start_row = b >> 12;
455 end_row = b & 0xfff;
456 height = (end_row < start_row) ? 0 : end_row - start_row /* + 1 */;
457 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Coords col: %d - %d row: %d - %d (%dx%d)\n",
458 start_col, end_col, start_row, end_row,
459 width, height);
460 off+=6;
461 break;
462 case 0x06:
463 /* Graphic lines */
464 current_nibble[0] = 2 * get_be16(this->packet + off);
465 current_nibble[1] = 2 * get_be16(this->packet + off + 2);
466 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Graphic offset 1: %d offset 2: %d\n",
467 current_nibble[0] / 2, current_nibble[1] / 2);
468 off+=4;
469 break;
470 case 0xff:
471 /* All done, bye-bye */
472 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Done!\n");
473 return;
474 // break;
475 default:
476 mp_msg(MSGT_SPUDEC,MSGL_WARN,"spudec: Error determining control type 0x%02x. Skipping %d bytes.\n",
477 type, next_off - off);
478 goto next_control;
481 next_control:
482 if (!display)
483 continue;
484 if (end_pts == UINT_MAX && start_off != next_off) {
485 end_pts = get_be16(this->packet + next_off) * 1024;
486 end_pts = 1 - pts100 >= end_pts ? 0 : pts100 + end_pts - 1;
488 if (end_pts > 0) {
489 packet_t *packet = calloc(1, sizeof(packet_t));
490 int i;
491 packet->start_pts = start_pts;
492 packet->end_pts = end_pts;
493 packet->current_nibble[0] = current_nibble[0];
494 packet->current_nibble[1] = current_nibble[1];
495 packet->start_row = start_row;
496 packet->start_col = start_col;
497 packet->width = width;
498 packet->height = height;
499 packet->stride = stride;
500 packet->control_start = control_start;
501 for (i=0; i<4; i++) {
502 packet->alpha[i] = this->alpha[i];
503 packet->palette[i] = this->palette[i];
505 packet->packet = malloc(this->packet_size);
506 memcpy(packet->packet, this->packet, this->packet_size);
507 spudec_queue_packet(this, packet);
512 static void spudec_decode(spudec_handle_t *this, int pts100)
514 if (!this->hw_spu)
515 spudec_process_control(this, pts100);
516 else if (pts100 >= 0) {
517 static vo_mpegpes_t packet = { NULL, 0, 0x20, 0 };
518 static vo_mpegpes_t *pkg=&packet;
519 packet.data = this->packet;
520 packet.size = this->packet_size;
521 packet.timestamp = pts100;
522 vo_draw_frame(this->hw_spu, (uint8_t**)&pkg);
526 int spudec_changed(void * this)
528 spudec_handle_t * spu = this;
529 return spu->spu_changed || spu->now_pts > spu->end_pts;
532 void spudec_assemble(void *this, unsigned char *packet, unsigned int len, int pts100)
534 spudec_handle_t *spu = this;
535 // spudec_heartbeat(this, pts100);
536 if (len < 2) {
537 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: packet too short\n");
538 return;
540 spu->packet_pts = pts100;
541 if (spu->packet_offset == 0) {
542 unsigned int len2 = get_be16(packet);
543 // Start new fragment
544 if (spu->packet_reserve < len2) {
545 if (spu->packet != NULL)
546 free(spu->packet);
547 spu->packet = malloc(len2);
548 spu->packet_reserve = spu->packet != NULL ? len2 : 0;
550 if (spu->packet != NULL) {
551 spu->packet_size = len2;
552 if (len > len2) {
553 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: invalid frag len / len2: %d / %d \n", len, len2);
554 return;
556 memcpy(spu->packet, packet, len);
557 spu->packet_offset = len;
558 spu->packet_pts = pts100;
560 } else {
561 // Continue current fragment
562 if (spu->packet_size < spu->packet_offset + len){
563 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: invalid fragment\n");
564 spu->packet_size = spu->packet_offset = 0;
565 return;
566 } else {
567 memcpy(spu->packet + spu->packet_offset, packet, len);
568 spu->packet_offset += len;
571 #if 1
572 // check if we have a complete packet (unfortunatelly packet_size is bad
573 // for some disks)
574 // [cb] packet_size is padded to be even -> may be one byte too long
575 if ((spu->packet_offset == spu->packet_size) ||
576 ((spu->packet_offset + 1) == spu->packet_size)){
577 unsigned int x=0,y;
578 while(x+4<=spu->packet_offset){
579 y=get_be16(spu->packet+x+2); // next control pointer
580 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPUtest: x=%d y=%d off=%d size=%d\n",x,y,spu->packet_offset,spu->packet_size);
581 if(x>=4 && x==y){ // if it points to self - we're done!
582 // we got it!
583 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPUgot: off=%d size=%d \n",spu->packet_offset,spu->packet_size);
584 spudec_decode(spu, pts100);
585 spu->packet_offset = 0;
586 break;
588 if(y<=x || y>=spu->packet_size){ // invalid?
589 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUtest: broken packet!!!!! y=%d < x=%d\n",y,x);
590 spu->packet_size = spu->packet_offset = 0;
591 break;
593 x=y;
595 // [cb] packet is done; start new packet
596 spu->packet_offset = 0;
598 #else
599 if (spu->packet_offset == spu->packet_size) {
600 spudec_decode(spu, pts100);
601 spu->packet_offset = 0;
603 #endif
606 void spudec_reset(void *this) // called after seek
608 spudec_handle_t *spu = this;
609 while (spu->queue_head)
610 spudec_free_packet(spudec_dequeue_packet(spu));
611 spu->now_pts = 0;
612 spu->end_pts = 0;
613 spu->packet_size = spu->packet_offset = 0;
616 void spudec_heartbeat(void *this, unsigned int pts100)
618 spudec_handle_t *spu = this;
619 spu->now_pts = pts100;
621 // TODO: detect and handle broken timestamps (e.g. due to wrapping)
622 while (spu->queue_head != NULL && pts100 >= spu->queue_head->start_pts) {
623 packet_t *packet = spudec_dequeue_packet(spu);
624 spu->start_pts = packet->start_pts;
625 spu->end_pts = packet->end_pts;
626 if (packet->is_decoded) {
627 free(spu->image);
628 spu->image_size = packet->data_len;
629 spu->image = packet->packet;
630 spu->aimage = packet->packet + packet->stride * packet->height;
631 packet->packet = NULL;
632 spu->width = packet->width;
633 spu->height = packet->height;
634 spu->stride = packet->stride;
635 spu->start_col = packet->start_col;
636 spu->start_row = packet->start_row;
638 // reset scaled image
639 spu->scaled_frame_width = 0;
640 spu->scaled_frame_height = 0;
641 } else {
642 if (spu->auto_palette)
643 compute_palette(spu, packet);
644 spudec_process_data(spu, packet);
646 spudec_free_packet(packet);
647 spu->spu_changed = 1;
651 int spudec_visible(void *this){
652 spudec_handle_t *spu = this;
653 int ret=(spu->start_pts <= spu->now_pts &&
654 spu->now_pts < spu->end_pts &&
655 spu->height > 0);
656 // printf("spu visible: %d \n",ret);
657 return ret;
660 void spudec_set_forced_subs_only(void * const this, const unsigned int flag)
662 if(this){
663 ((spudec_handle_t *)this)->forced_subs_only=flag;
664 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPU: Display only forced subs now %s\n", flag ? "enabled": "disabled");
668 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)
670 spudec_handle_t *spu = this;
671 if (spudec_visible(spu))
673 draw_alpha(ctx, spu->start_col, spu->start_row, spu->width, spu->height,
674 spu->image, spu->aimage, spu->stride);
675 spu->spu_changed = 0;
679 /* calc the bbox for spudec subs */
680 void spudec_calc_bbox(void *me, unsigned int dxs, unsigned int dys, unsigned int* bbox)
682 spudec_handle_t *spu = me;
683 if (spu->orig_frame_width == 0 || spu->orig_frame_height == 0
684 || (spu->orig_frame_width == dxs && spu->orig_frame_height == dys)) {
685 // unscaled
686 bbox[0] = spu->start_col;
687 bbox[1] = spu->start_col + spu->width;
688 bbox[2] = spu->start_row;
689 bbox[3] = spu->start_row + spu->height;
691 else {
692 // scaled
693 unsigned int scalex = 0x100 * dxs / spu->orig_frame_width;
694 unsigned int scaley = 0x100 * dys / spu->orig_frame_height;
695 bbox[0] = spu->start_col * scalex / 0x100;
696 bbox[1] = spu->start_col * scalex / 0x100 + spu->width * scalex / 0x100;
697 switch (spu_alignment) {
698 case 0:
699 bbox[3] = dys*sub_pos/100 + spu->height * scaley / 0x100;
700 if (bbox[3] > dys) bbox[3] = dys;
701 bbox[2] = bbox[3] - spu->height * scaley / 0x100;
702 break;
703 case 1:
704 if (sub_pos < 50) {
705 bbox[2] = dys*sub_pos/100 - spu->height * scaley / 0x200;
706 bbox[3] = bbox[2] + spu->height;
707 } else {
708 bbox[3] = dys*sub_pos/100 + spu->height * scaley / 0x200;
709 if (bbox[3] > dys) bbox[3] = dys;
710 bbox[2] = bbox[3] - spu->height * scaley / 0x100;
712 break;
713 case 2:
714 bbox[2] = dys*sub_pos/100 - spu->height * scaley / 0x100;
715 bbox[3] = bbox[2] + spu->height;
716 break;
717 default: /* -1 */
718 bbox[2] = spu->start_row * scaley / 0x100;
719 bbox[3] = spu->start_row * scaley / 0x100 + spu->height * scaley / 0x100;
720 break;
724 /* transform mplayer's alpha value into an opacity value that is linear */
725 static inline int canon_alpha(int alpha)
727 return (uint8_t)-alpha;
730 typedef struct {
731 unsigned position;
732 unsigned left_up;
733 unsigned right_down;
734 }scale_pixel;
737 static void scale_table(unsigned int start_src, unsigned int start_tar, unsigned int end_src, unsigned int end_tar, scale_pixel * table)
739 unsigned int t;
740 unsigned int delta_src = end_src - start_src;
741 unsigned int delta_tar = end_tar - start_tar;
742 int src = 0;
743 int src_step;
744 if (delta_src == 0 || delta_tar == 0) {
745 return;
747 src_step = (delta_src << 16) / delta_tar >>1;
748 for (t = 0; t<=delta_tar; src += (src_step << 1), t++){
749 table[t].position= FFMIN(src >> 16, end_src - 1);
750 table[t].right_down = src & 0xffff;
751 table[t].left_up = 0x10000 - table[t].right_down;
755 /* bilinear scale, similar to vobsub's code */
756 static void scale_image(int x, int y, scale_pixel* table_x, scale_pixel* table_y, spudec_handle_t * spu)
758 int alpha[4];
759 int color[4];
760 unsigned int scale[4];
761 int base = table_y[y].position * spu->stride + table_x[x].position;
762 int scaled = y * spu->scaled_stride + x;
763 alpha[0] = canon_alpha(spu->aimage[base]);
764 alpha[1] = canon_alpha(spu->aimage[base + 1]);
765 alpha[2] = canon_alpha(spu->aimage[base + spu->stride]);
766 alpha[3] = canon_alpha(spu->aimage[base + spu->stride + 1]);
767 color[0] = spu->image[base];
768 color[1] = spu->image[base + 1];
769 color[2] = spu->image[base + spu->stride];
770 color[3] = spu->image[base + spu->stride + 1];
771 scale[0] = (table_x[x].left_up * table_y[y].left_up >> 16) * alpha[0];
772 if (table_y[y].left_up == 0x10000) // necessary to avoid overflow-case
773 scale[0] = table_x[x].left_up * alpha[0];
774 scale[1] = (table_x[x].right_down * table_y[y].left_up >>16) * alpha[1];
775 scale[2] = (table_x[x].left_up * table_y[y].right_down >> 16) * alpha[2];
776 scale[3] = (table_x[x].right_down * table_y[y].right_down >> 16) * alpha[3];
777 spu->scaled_image[scaled] = (color[0] * scale[0] + color[1] * scale[1] + color[2] * scale[2] + color[3] * scale[3])>>24;
778 spu->scaled_aimage[scaled] = (scale[0] + scale[1] + scale[2] + scale[3]) >> 16;
779 if (spu->scaled_aimage[scaled]){
780 // ensure that MPlayer's simplified alpha-blending can not overflow
781 spu->scaled_image[scaled] = FFMIN(spu->scaled_image[scaled], spu->scaled_aimage[scaled]);
782 // convert to MPlayer-style alpha
783 spu->scaled_aimage[scaled] = -spu->scaled_aimage[scaled];
787 static void sws_spu_image(unsigned char *d1, unsigned char *d2, int dw, int dh,
788 int ds, unsigned char *s1, unsigned char *s2, int sw,
789 int sh, int ss)
791 struct SwsContext *ctx;
792 static SwsFilter filter;
793 static int firsttime = 1;
794 static float oldvar;
795 int i;
797 if (!firsttime && oldvar != spu_gaussvar) sws_freeVec(filter.lumH);
798 if (firsttime) {
799 filter.lumH = filter.lumV =
800 filter.chrH = filter.chrV = sws_getGaussianVec(spu_gaussvar, 3.0);
801 sws_normalizeVec(filter.lumH, 1.0);
802 firsttime = 0;
803 oldvar = spu_gaussvar;
806 ctx=sws_getContext(sw, sh, PIX_FMT_GRAY8, dw, dh, PIX_FMT_GRAY8, SWS_GAUSS, &filter, NULL, NULL);
807 sws_scale(ctx,&s1,&ss,0,sh,&d1,&ds);
808 for (i=ss*sh-1; i>=0; i--) if (!s2[i]) s2[i] = 255; //else s2[i] = 1;
809 sws_scale(ctx,&s2,&ss,0,sh,&d2,&ds);
810 for (i=ds*dh-1; i>=0; i--) if (d2[i]==0) d2[i] = 1; else if (d2[i]==255) d2[i] = 0;
811 sws_freeContext(ctx);
814 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)
816 spudec_handle_t *spu = me;
817 scale_pixel *table_x;
818 scale_pixel *table_y;
820 if (spudec_visible(spu)) {
822 // check if only forced subtitles are requested
823 if( (spu->forced_subs_only) && !(spu->is_forced_sub) ){
824 return;
827 if (!(spu_aamode&16) && (spu->orig_frame_width == 0 || spu->orig_frame_height == 0
828 || (spu->orig_frame_width == dxs && spu->orig_frame_height == dys))) {
829 spudec_draw(spu, draw_alpha, ctx);
831 else {
832 if (spu->scaled_frame_width != dxs || spu->scaled_frame_height != dys) { /* Resizing is needed */
833 /* scaled_x = scalex * x / 0x100
834 scaled_y = scaley * y / 0x100
835 order of operations is important because of rounding. */
836 unsigned int scalex = 0x100 * dxs / spu->orig_frame_width;
837 unsigned int scaley = 0x100 * dys / spu->orig_frame_height;
838 spu->scaled_start_col = spu->start_col * scalex / 0x100;
839 spu->scaled_start_row = spu->start_row * scaley / 0x100;
840 spu->scaled_width = spu->width * scalex / 0x100;
841 spu->scaled_height = spu->height * scaley / 0x100;
842 /* Kludge: draw_alpha needs width multiple of 8 */
843 spu->scaled_stride = (spu->scaled_width + 7) & ~7;
844 if (spu->scaled_image_size < spu->scaled_stride * spu->scaled_height) {
845 if (spu->scaled_image) {
846 free(spu->scaled_image);
847 spu->scaled_image_size = 0;
849 spu->scaled_image = malloc(2 * spu->scaled_stride * spu->scaled_height);
850 if (spu->scaled_image) {
851 spu->scaled_image_size = spu->scaled_stride * spu->scaled_height;
852 spu->scaled_aimage = spu->scaled_image + spu->scaled_image_size;
855 if (spu->scaled_image) {
856 unsigned int x, y;
857 if (spu->scaled_width <= 1 || spu->scaled_height <= 1) {
858 goto nothing_to_do;
860 switch(spu_aamode&15) {
861 case 4:
862 sws_spu_image(spu->scaled_image, spu->scaled_aimage,
863 spu->scaled_width, spu->scaled_height, spu->scaled_stride,
864 spu->image, spu->aimage, spu->width, spu->height, spu->stride);
865 break;
866 case 3:
867 table_x = calloc(spu->scaled_width, sizeof(scale_pixel));
868 table_y = calloc(spu->scaled_height, sizeof(scale_pixel));
869 if (!table_x || !table_y) {
870 mp_msg(MSGT_SPUDEC, MSGL_FATAL, "Fatal: spudec_draw_scaled: calloc failed\n");
872 scale_table(0, 0, spu->width - 1, spu->scaled_width - 1, table_x);
873 scale_table(0, 0, spu->height - 1, spu->scaled_height - 1, table_y);
874 for (y = 0; y < spu->scaled_height; y++)
875 for (x = 0; x < spu->scaled_width; x++)
876 scale_image(x, y, table_x, table_y, spu);
877 free(table_x);
878 free(table_y);
879 break;
880 case 0:
881 /* no antialiasing */
882 for (y = 0; y < spu->scaled_height; ++y) {
883 int unscaled_y = y * 0x100 / scaley;
884 int strides = spu->stride * unscaled_y;
885 int scaled_strides = spu->scaled_stride * y;
886 for (x = 0; x < spu->scaled_width; ++x) {
887 int unscaled_x = x * 0x100 / scalex;
888 spu->scaled_image[scaled_strides + x] = spu->image[strides + unscaled_x];
889 spu->scaled_aimage[scaled_strides + x] = spu->aimage[strides + unscaled_x];
892 break;
893 case 1:
895 /* Intermediate antialiasing. */
896 for (y = 0; y < spu->scaled_height; ++y) {
897 const unsigned int unscaled_top = y * spu->orig_frame_height / dys;
898 unsigned int unscaled_bottom = (y + 1) * spu->orig_frame_height / dys;
899 if (unscaled_bottom >= spu->height)
900 unscaled_bottom = spu->height - 1;
901 for (x = 0; x < spu->scaled_width; ++x) {
902 const unsigned int unscaled_left = x * spu->orig_frame_width / dxs;
903 unsigned int unscaled_right = (x + 1) * spu->orig_frame_width / dxs;
904 unsigned int color = 0;
905 unsigned int alpha = 0;
906 unsigned int walkx, walky;
907 unsigned int base, tmp;
908 if (unscaled_right >= spu->width)
909 unscaled_right = spu->width - 1;
910 for (walky = unscaled_top; walky <= unscaled_bottom; ++walky)
911 for (walkx = unscaled_left; walkx <= unscaled_right; ++walkx) {
912 base = walky * spu->stride + walkx;
913 tmp = canon_alpha(spu->aimage[base]);
914 alpha += tmp;
915 color += tmp * spu->image[base];
917 base = y * spu->scaled_stride + x;
918 spu->scaled_image[base] = alpha ? color / alpha : 0;
919 spu->scaled_aimage[base] =
920 alpha * (1 + unscaled_bottom - unscaled_top) * (1 + unscaled_right - unscaled_left);
921 /* spu->scaled_aimage[base] =
922 alpha * dxs * dys / spu->orig_frame_width / spu->orig_frame_height; */
923 if (spu->scaled_aimage[base]) {
924 spu->scaled_aimage[base] = 256 - spu->scaled_aimage[base];
925 if (spu->scaled_aimage[base] + spu->scaled_image[base] > 255)
926 spu->scaled_image[base] = 256 - spu->scaled_aimage[base];
931 break;
932 case 2:
934 /* Best antialiasing. Very slow. */
935 /* Any pixel (x, y) represents pixels from the original
936 rectangular region comprised between the columns
937 unscaled_y and unscaled_y + 0x100 / scaley and the rows
938 unscaled_x and unscaled_x + 0x100 / scalex
940 The original rectangular region that the scaled pixel
941 represents is cut in 9 rectangular areas like this:
943 +---+-----------------+---+
944 | 1 | 2 | 3 |
945 +---+-----------------+---+
946 | | | |
947 | 4 | 5 | 6 |
948 | | | |
949 +---+-----------------+---+
950 | 7 | 8 | 9 |
951 +---+-----------------+---+
953 The width of the left column is at most one pixel and
954 it is never null and its right column is at a pixel
955 boundary. The height of the top row is at most one
956 pixel it is never null and its bottom row is at a
957 pixel boundary. The width and height of region 5 are
958 integral values. The width of the right column is
959 what remains and is less than one pixel. The height
960 of the bottom row is what remains and is less than
961 one pixel.
963 The row above 1, 2, 3 is unscaled_y. The row between
964 1, 2, 3 and 4, 5, 6 is top_low_row. The row between 4,
965 5, 6 and 7, 8, 9 is (unsigned int)unscaled_y_bottom.
966 The row beneath 7, 8, 9 is unscaled_y_bottom.
968 The column left of 1, 4, 7 is unscaled_x. The column
969 between 1, 4, 7 and 2, 5, 8 is left_right_column. The
970 column between 2, 5, 8 and 3, 6, 9 is (unsigned
971 int)unscaled_x_right. The column right of 3, 6, 9 is
972 unscaled_x_right. */
973 const double inv_scalex = (double) 0x100 / scalex;
974 const double inv_scaley = (double) 0x100 / scaley;
975 for (y = 0; y < spu->scaled_height; ++y) {
976 const double unscaled_y = y * inv_scaley;
977 const double unscaled_y_bottom = unscaled_y + inv_scaley;
978 const unsigned int top_low_row = FFMIN(unscaled_y_bottom, unscaled_y + 1.0);
979 const double top = top_low_row - unscaled_y;
980 const unsigned int height = unscaled_y_bottom > top_low_row
981 ? (unsigned int) unscaled_y_bottom - top_low_row
982 : 0;
983 const double bottom = unscaled_y_bottom > top_low_row
984 ? unscaled_y_bottom - floor(unscaled_y_bottom)
985 : 0.0;
986 for (x = 0; x < spu->scaled_width; ++x) {
987 const double unscaled_x = x * inv_scalex;
988 const double unscaled_x_right = unscaled_x + inv_scalex;
989 const unsigned int left_right_column = FFMIN(unscaled_x_right, unscaled_x + 1.0);
990 const double left = left_right_column - unscaled_x;
991 const unsigned int width = unscaled_x_right > left_right_column
992 ? (unsigned int) unscaled_x_right - left_right_column
993 : 0;
994 const double right = unscaled_x_right > left_right_column
995 ? unscaled_x_right - floor(unscaled_x_right)
996 : 0.0;
997 double color = 0.0;
998 double alpha = 0.0;
999 double tmp;
1000 unsigned int base;
1001 /* Now use these informations to compute a good alpha,
1002 and lightness. The sum is on each of the 9
1003 region's surface and alpha and lightness.
1005 transformed alpha = sum(surface * alpha) / sum(surface)
1006 transformed color = sum(surface * alpha * color) / sum(surface * alpha)
1008 /* 1: top left part */
1009 base = spu->stride * (unsigned int) unscaled_y;
1010 tmp = left * top * canon_alpha(spu->aimage[base + (unsigned int) unscaled_x]);
1011 alpha += tmp;
1012 color += tmp * spu->image[base + (unsigned int) unscaled_x];
1013 /* 2: top center part */
1014 if (width > 0) {
1015 unsigned int walkx;
1016 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
1017 base = spu->stride * (unsigned int) unscaled_y + walkx;
1018 tmp = /* 1.0 * */ top * canon_alpha(spu->aimage[base]);
1019 alpha += tmp;
1020 color += tmp * spu->image[base];
1023 /* 3: top right part */
1024 if (right > 0.0) {
1025 base = spu->stride * (unsigned int) unscaled_y + (unsigned int) unscaled_x_right;
1026 tmp = right * top * canon_alpha(spu->aimage[base]);
1027 alpha += tmp;
1028 color += tmp * spu->image[base];
1030 /* 4: center left part */
1031 if (height > 0) {
1032 unsigned int walky;
1033 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1034 base = spu->stride * walky + (unsigned int) unscaled_x;
1035 tmp = left /* * 1.0 */ * canon_alpha(spu->aimage[base]);
1036 alpha += tmp;
1037 color += tmp * spu->image[base];
1040 /* 5: center part */
1041 if (width > 0 && height > 0) {
1042 unsigned int walky;
1043 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1044 unsigned int walkx;
1045 base = spu->stride * walky;
1046 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
1047 tmp = /* 1.0 * 1.0 * */ canon_alpha(spu->aimage[base + walkx]);
1048 alpha += tmp;
1049 color += tmp * spu->image[base + walkx];
1053 /* 6: center right part */
1054 if (right > 0.0 && height > 0) {
1055 unsigned int walky;
1056 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1057 base = spu->stride * walky + (unsigned int) unscaled_x_right;
1058 tmp = right /* * 1.0 */ * canon_alpha(spu->aimage[base]);
1059 alpha += tmp;
1060 color += tmp * spu->image[base];
1063 /* 7: bottom left part */
1064 if (bottom > 0.0) {
1065 base = spu->stride * (unsigned int) unscaled_y_bottom + (unsigned int) unscaled_x;
1066 tmp = left * bottom * canon_alpha(spu->aimage[base]);
1067 alpha += tmp;
1068 color += tmp * spu->image[base];
1070 /* 8: bottom center part */
1071 if (width > 0 && bottom > 0.0) {
1072 unsigned int walkx;
1073 base = spu->stride * (unsigned int) unscaled_y_bottom;
1074 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
1075 tmp = /* 1.0 * */ bottom * canon_alpha(spu->aimage[base + walkx]);
1076 alpha += tmp;
1077 color += tmp * spu->image[base + walkx];
1080 /* 9: bottom right part */
1081 if (right > 0.0 && bottom > 0.0) {
1082 base = spu->stride * (unsigned int) unscaled_y_bottom + (unsigned int) unscaled_x_right;
1083 tmp = right * bottom * canon_alpha(spu->aimage[base]);
1084 alpha += tmp;
1085 color += tmp * spu->image[base];
1087 /* Finally mix these transparency and brightness information suitably */
1088 base = spu->scaled_stride * y + x;
1089 spu->scaled_image[base] = alpha > 0 ? color / alpha : 0;
1090 spu->scaled_aimage[base] = alpha * scalex * scaley / 0x10000;
1091 if (spu->scaled_aimage[base]) {
1092 spu->scaled_aimage[base] = 256 - spu->scaled_aimage[base];
1093 if (spu->scaled_aimage[base] + spu->scaled_image[base] > 255)
1094 spu->scaled_image[base] = 256 - spu->scaled_aimage[base];
1100 nothing_to_do:
1101 /* Kludge: draw_alpha needs width multiple of 8. */
1102 if (spu->scaled_width < spu->scaled_stride)
1103 for (y = 0; y < spu->scaled_height; ++y) {
1104 memset(spu->scaled_aimage + y * spu->scaled_stride + spu->scaled_width, 0,
1105 spu->scaled_stride - spu->scaled_width);
1107 spu->scaled_frame_width = dxs;
1108 spu->scaled_frame_height = dys;
1111 if (spu->scaled_image){
1112 switch (spu_alignment) {
1113 case 0:
1114 spu->scaled_start_row = dys*sub_pos/100;
1115 if (spu->scaled_start_row + spu->scaled_height > dys)
1116 spu->scaled_start_row = dys - spu->scaled_height;
1117 break;
1118 case 1:
1119 spu->scaled_start_row = dys*sub_pos/100 - spu->scaled_height/2;
1120 if (sub_pos >= 50 && spu->scaled_start_row + spu->scaled_height > dys)
1121 spu->scaled_start_row = dys - spu->scaled_height;
1122 break;
1123 case 2:
1124 spu->scaled_start_row = dys*sub_pos/100 - spu->scaled_height;
1125 break;
1127 draw_alpha(ctx, spu->scaled_start_col, spu->scaled_start_row, spu->scaled_width, spu->scaled_height,
1128 spu->scaled_image, spu->scaled_aimage, spu->scaled_stride);
1129 spu->spu_changed = 0;
1133 else
1135 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPU not displayed: start_pts=%d end_pts=%d now_pts=%d\n",
1136 spu->start_pts, spu->end_pts, spu->now_pts);
1140 void spudec_update_palette(void * this, unsigned int *palette)
1142 spudec_handle_t *spu = this;
1143 if (spu && palette) {
1144 memcpy(spu->global_palette, palette, sizeof(spu->global_palette));
1145 if(spu->hw_spu)
1146 vo_control(spu->hw_spu, VOCTRL_SET_SPU_PALETTE, spu->global_palette);
1150 void spudec_set_font_factor(void * this, double factor)
1152 spudec_handle_t *spu = this;
1153 spu->font_start_level = (int)(0xF0-(0xE0*factor));
1156 static void spudec_parse_extradata(spudec_handle_t *this,
1157 uint8_t *extradata, int extradata_len)
1159 uint8_t *buffer, *ptr;
1160 unsigned int *pal = this->global_palette, *cuspal = this->cuspal;
1161 unsigned int tridx;
1162 int i;
1164 if (extradata_len == 16*4) {
1165 for (i=0; i<16; i++)
1166 pal[i] = AV_RB32(extradata + i*4);
1167 this->auto_palette = 0;
1168 return;
1171 if (!(ptr = buffer = malloc(extradata_len+1)))
1172 return;
1173 memcpy(buffer, extradata, extradata_len);
1174 buffer[extradata_len] = 0;
1176 do {
1177 if (*ptr == '#')
1178 continue;
1179 if (!strncmp(ptr, "size: ", 6))
1180 sscanf(ptr + 6, "%dx%d", &this->orig_frame_width, &this->orig_frame_height);
1181 if (!strncmp(ptr, "palette: ", 9) &&
1182 sscanf(ptr + 9, "%x, %x, %x, %x, %x, %x, %x, %x, "
1183 "%x, %x, %x, %x, %x, %x, %x, %x",
1184 &pal[ 0], &pal[ 1], &pal[ 2], &pal[ 3],
1185 &pal[ 4], &pal[ 5], &pal[ 6], &pal[ 7],
1186 &pal[ 8], &pal[ 9], &pal[10], &pal[11],
1187 &pal[12], &pal[13], &pal[14], &pal[15]) == 16) {
1188 for (i=0; i<16; i++)
1189 pal[i] = vobsub_palette_to_yuv(pal[i]);
1190 this->auto_palette = 0;
1192 if (!strncasecmp(ptr, "forced subs: on", 15))
1193 this->forced_subs_only = 1;
1194 if (!strncmp(ptr, "custom colors: ON, tridx: ", 26) &&
1195 sscanf(ptr + 26, "%x, colors: %x, %x, %x, %x",
1196 &tridx, cuspal+0, cuspal+1, cuspal+2, cuspal+3) == 5) {
1197 for (i=0; i<4; i++) {
1198 cuspal[i] = vobsub_rgb_to_yuv(cuspal[i]);
1199 if (tridx & (1 << (12-4*i)))
1200 cuspal[i] |= 1 << 31;
1202 this->custom = 1;
1204 } while ((ptr=strchr(ptr,'\n')) && *++ptr);
1206 free(buffer);
1209 void *spudec_new_scaled(unsigned int *palette, unsigned int frame_width, unsigned int frame_height, uint8_t *extradata, int extradata_len)
1211 spudec_handle_t *this = calloc(1, sizeof(spudec_handle_t));
1212 if (this){
1213 this->orig_frame_height = frame_height;
1214 this->orig_frame_width = frame_width;
1215 // set up palette:
1216 if (palette)
1217 memcpy(this->global_palette, palette, sizeof(this->global_palette));
1218 else
1219 this->auto_palette = 1;
1220 if (extradata)
1221 spudec_parse_extradata(this, extradata, extradata_len);
1222 /* XXX Although the video frame is some size, the SPU frame is
1223 always maximum size i.e. 720 wide and 576 or 480 high */
1224 // For HD files in MKV the VobSub resolution can be higher though,
1225 // see largeres_vobsub.mkv
1226 if (this->orig_frame_width <= 720 && this->orig_frame_height <= 576) {
1227 this->orig_frame_width = 720;
1228 if (this->orig_frame_height == 480 || this->orig_frame_height == 240)
1229 this->orig_frame_height = 480;
1230 else
1231 this->orig_frame_height = 576;
1234 else
1235 mp_msg(MSGT_SPUDEC,MSGL_FATAL, "FATAL: spudec_init: calloc");
1236 return this;
1239 void *spudec_new(unsigned int *palette)
1241 return spudec_new_scaled(palette, 0, 0, NULL, 0);
1244 void spudec_free(void *this)
1246 spudec_handle_t *spu = this;
1247 if (spu) {
1248 while (spu->queue_head)
1249 spudec_free_packet(spudec_dequeue_packet(spu));
1250 free(spu->packet);
1251 spu->packet = NULL;
1252 free(spu->scaled_image);
1253 spu->scaled_image = NULL;
1254 free(spu->image);
1255 spu->image = NULL;
1256 spu->aimage = NULL;
1257 free(spu->pal_image);
1258 spu->pal_image = NULL;
1259 spu->image_size = 0;
1260 free(spu);
1264 void spudec_set_hw_spu(void *this, struct vo *hw_spu)
1266 spudec_handle_t *spu = this;
1267 if (!spu)
1268 return;
1269 spu->hw_spu = hw_spu;
1270 vo_control(hw_spu, VOCTRL_SET_SPU_PALETTE, spu->global_palette);
1273 #define MP_NOPTS_VALUE (-1LL<<63) //both int64_t and double should be able to represent this exactly
1276 * palette must contain at least 256 32-bit entries, otherwise crashes
1277 * are possible
1279 void spudec_set_paletted(void *this, const uint8_t *pal_img, int pal_stride,
1280 const void *palette,
1281 int x, int y, int w, int h,
1282 double pts, double endpts)
1284 int i;
1285 uint16_t g8a8_pal[256];
1286 packet_t *packet;
1287 const uint32_t *pal = palette;
1288 spudec_handle_t *spu = this;
1289 uint8_t *img;
1290 uint8_t *aimg;
1291 int stride = (w + 7) & ~7;
1292 if ((unsigned)w >= 0x8000 || (unsigned)h > 0x4000)
1293 return;
1294 packet = calloc(1, sizeof(packet_t));
1295 packet->is_decoded = 1;
1296 packet->width = w;
1297 packet->height = h;
1298 packet->stride = stride;
1299 packet->start_col = x;
1300 packet->start_row = y;
1301 packet->data_len = 2 * stride * h;
1302 packet->packet = malloc(packet->data_len);
1303 img = packet->packet;
1304 aimg = packet->packet + stride * h;
1305 for (i = 0; i < 256; i++) {
1306 uint32_t pixel = pal[i];
1307 int alpha = pixel >> 24;
1308 int gray = (((pixel & 0x000000ff) >> 0) +
1309 ((pixel & 0x0000ff00) >> 7) +
1310 ((pixel & 0x00ff0000) >> 16)) >> 2;
1311 gray = FFMIN(gray, alpha);
1312 g8a8_pal[i] = (-alpha << 8) | gray;
1314 pal2gray_alpha(g8a8_pal, pal_img, pal_stride,
1315 img, aimg, stride, w, h);
1316 packet->start_pts = 0;
1317 packet->end_pts = 0x7fffffff;
1318 if (pts != MP_NOPTS_VALUE)
1319 packet->start_pts = pts * 90000;
1320 if (endpts != MP_NOPTS_VALUE)
1321 packet->end_pts = endpts * 90000;
1322 spudec_queue_packet(spu, packet);