synced with r21537
[mplayer/glamo.git] / spudec.c
blobebaba6bd5fb903a2344b0986d9181a4648fd22cb
1 /* SPUdec.c
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>
14 #include "config.h"
15 #include "mp_msg.h"
17 #include <errno.h>
18 #include <limits.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <string.h>
23 #include <math.h>
24 #include "libvo/video_out.h"
25 #include "spudec.h"
26 #ifdef USE_LIBAVUTIL_SO
27 #include <ffmpeg/avutil.h>
28 #else
29 #include "avutil.h"
30 #endif
31 #include "libswscale/swscale.h"
33 #define MIN(a, b) ((a)<(b)?(a):(b))
35 /* Valid values for spu_aamode:
36 0: none (fastest, most ugly)
37 1: approximate
38 2: full (slowest)
39 3: bilinear (similiar to vobsub, fast and not too bad)
40 4: uses swscaler gaussian (this is the only one that looks good)
43 int spu_aamode = 3;
44 int spu_alignment = -1;
45 float spu_gaussvar = 1.0;
46 extern int sub_pos;
48 typedef struct packet_t packet_t;
49 struct packet_t {
50 unsigned char *packet;
51 unsigned int palette[4];
52 unsigned int alpha[4];
53 unsigned int control_start; /* index of start of control data */
54 unsigned int current_nibble[2]; /* next data nibble (4 bits) to be
55 processed (for RLE decoding) for
56 even and odd lines */
57 int deinterlace_oddness; /* 0 or 1, index into current_nibble */
58 unsigned int start_col, end_col;
59 unsigned int start_row, end_row;
60 unsigned int width, height, stride;
61 unsigned int start_pts, end_pts;
62 packet_t *next;
65 typedef struct {
66 packet_t *queue_head;
67 packet_t *queue_tail;
68 unsigned int global_palette[16];
69 unsigned int orig_frame_width, orig_frame_height;
70 unsigned char* packet;
71 size_t packet_reserve; /* size of the memory pointed to by packet */
72 unsigned int packet_offset; /* end of the currently assembled fragment */
73 unsigned int packet_size; /* size of the packet once all fragments are assembled */
74 unsigned int packet_pts; /* PTS for this packet */
75 unsigned int palette[4];
76 unsigned int alpha[4];
77 unsigned int cuspal[4];
78 unsigned int custom;
79 unsigned int now_pts;
80 unsigned int start_pts, end_pts;
81 unsigned int start_col, end_col;
82 unsigned int start_row, end_row;
83 unsigned int width, height, stride;
84 size_t image_size; /* Size of the image buffer */
85 unsigned char *image; /* Grayscale value */
86 unsigned char *aimage; /* Alpha value */
87 unsigned int scaled_frame_width, scaled_frame_height;
88 unsigned int scaled_start_col, scaled_start_row;
89 unsigned int scaled_width, scaled_height, scaled_stride;
90 size_t scaled_image_size;
91 unsigned char *scaled_image;
92 unsigned char *scaled_aimage;
93 int auto_palette; /* 1 if we lack a palette and must use an heuristic. */
94 int font_start_level; /* Darkest value used for the computed font */
95 vo_functions_t *hw_spu;
96 int spu_changed;
97 unsigned int forced_subs_only; /* flag: 0=display all subtitle, !0 display only forced subtitles */
98 unsigned int is_forced_sub; /* true if current subtitle is a forced subtitle */
99 } spudec_handle_t;
101 static void spudec_queue_packet(spudec_handle_t *this, packet_t *packet)
103 if (this->queue_head == NULL)
104 this->queue_head = packet;
105 else
106 this->queue_tail->next = packet;
107 this->queue_tail = packet;
110 static packet_t *spudec_dequeue_packet(spudec_handle_t *this)
112 packet_t *retval = this->queue_head;
114 this->queue_head = retval->next;
115 if (this->queue_head == NULL)
116 this->queue_tail = NULL;
118 return retval;
121 static void spudec_free_packet(packet_t *packet)
123 if (packet->packet != NULL)
124 free(packet->packet);
125 free(packet);
128 static inline unsigned int get_be16(const unsigned char *p)
130 return (p[0] << 8) + p[1];
133 static inline unsigned int get_be24(const unsigned char *p)
135 return (get_be16(p) << 8) + p[2];
138 static void next_line(packet_t *packet)
140 if (packet->current_nibble[packet->deinterlace_oddness] % 2)
141 packet->current_nibble[packet->deinterlace_oddness]++;
142 packet->deinterlace_oddness = (packet->deinterlace_oddness + 1) % 2;
145 static inline unsigned char get_nibble(packet_t *packet)
147 unsigned char nib;
148 unsigned int *nibblep = packet->current_nibble + packet->deinterlace_oddness;
149 if (*nibblep / 2 >= packet->control_start) {
150 mp_msg(MSGT_SPUDEC,MSGL_WARN, "SPUdec: ERROR: get_nibble past end of packet\n");
151 return 0;
153 nib = packet->packet[*nibblep / 2];
154 if (*nibblep % 2)
155 nib &= 0xf;
156 else
157 nib >>= 4;
158 ++*nibblep;
159 return nib;
162 static inline int mkalpha(int i)
164 /* In mplayer's alpha planes, 0 is transparent, then 1 is nearly
165 opaque upto 255 which is transparent */
166 switch (i) {
167 case 0xf:
168 return 1;
169 case 0:
170 return 0;
171 default:
172 return (0xf - i) << 4;
176 /* Cut the sub to visible part */
177 static inline void spudec_cut_image(spudec_handle_t *this)
179 unsigned int fy, ly;
180 unsigned int first_y, last_y;
181 unsigned char *image;
182 unsigned char *aimage;
184 if (this->stride == 0 || this->height == 0) {
185 return;
188 for (fy = 0; fy < this->image_size && !this->aimage[fy]; fy++);
189 for (ly = this->stride * this->height-1; ly && !this->aimage[ly]; ly--);
190 first_y = fy / this->stride;
191 last_y = ly / this->stride;
192 //printf("first_y: %d, last_y: %d\n", first_y, last_y);
193 this->start_row += first_y;
195 // Some subtitles trigger this condition
196 if (last_y + 1 > first_y ) {
197 this->height = last_y - first_y +1;
198 } else {
199 this->height = 0;
200 this->image_size = 0;
201 return;
204 // printf("new h %d new start %d (sz %d st %d)---\n\n", this->height, this->start_row, this->image_size, this->stride);
206 image = malloc(2 * this->stride * this->height);
207 if(image){
208 this->image_size = this->stride * this->height;
209 aimage = image + this->image_size;
210 memcpy(image, this->image + this->stride * first_y, this->image_size);
211 memcpy(aimage, this->aimage + this->stride * first_y, this->image_size);
212 free(this->image);
213 this->image = image;
214 this->aimage = aimage;
215 } else {
216 mp_msg(MSGT_SPUDEC, MSGL_FATAL, "Fatal: update_spu: malloc requested %d bytes\n", 2 * this->stride * this->height);
220 static void spudec_process_data(spudec_handle_t *this, packet_t *packet)
222 unsigned int cmap[4], alpha[4];
223 unsigned int i, x, y;
225 this->scaled_frame_width = 0;
226 this->scaled_frame_height = 0;
227 this->start_col = packet->start_col;
228 this->end_col = packet->end_col;
229 this->start_row = packet->start_row;
230 this->end_row = packet->end_row;
231 this->height = packet->height;
232 this->width = packet->width;
233 this->stride = packet->stride;
234 for (i = 0; i < 4; ++i) {
235 alpha[i] = mkalpha(packet->alpha[i]);
236 if (alpha[i] == 0)
237 cmap[i] = 0;
238 else if (this->custom){
239 cmap[i] = ((this->cuspal[i] >> 16) & 0xff);
240 if (cmap[i] + alpha[i] > 255)
241 cmap[i] = 256 - alpha[i];
243 else {
244 cmap[i] = ((this->global_palette[packet->palette[i]] >> 16) & 0xff);
245 if (cmap[i] + alpha[i] > 255)
246 cmap[i] = 256 - alpha[i];
250 if (this->image_size < this->stride * this->height) {
251 if (this->image != NULL) {
252 free(this->image);
253 this->image_size = 0;
255 this->image = malloc(2 * this->stride * this->height);
256 if (this->image) {
257 this->image_size = this->stride * this->height;
258 this->aimage = this->image + this->image_size;
261 if (this->image == NULL)
262 return;
264 /* Kludge: draw_alpha needs width multiple of 8. */
265 if (this->width < this->stride)
266 for (y = 0; y < this->height; ++y) {
267 memset(this->aimage + y * this->stride + this->width, 0, this->stride - this->width);
268 /* FIXME: Why is this one needed? */
269 memset(this->image + y * this->stride + this->width, 0, this->stride - this->width);
272 i = packet->current_nibble[1];
273 x = 0;
274 y = 0;
275 while (packet->current_nibble[0] < i
276 && packet->current_nibble[1] / 2 < packet->control_start
277 && y < this->height) {
278 unsigned int len, color;
279 unsigned int rle = 0;
280 rle = get_nibble(packet);
281 if (rle < 0x04) {
282 rle = (rle << 4) | get_nibble(packet);
283 if (rle < 0x10) {
284 rle = (rle << 4) | get_nibble(packet);
285 if (rle < 0x040) {
286 rle = (rle << 4) | get_nibble(packet);
287 if (rle < 0x0004)
288 rle |= ((this->width - x) << 2);
292 color = 3 - (rle & 0x3);
293 len = rle >> 2;
294 if (len > this->width - x || len == 0)
295 len = this->width - x;
296 /* FIXME have to use palette and alpha map*/
297 memset(this->image + y * this->stride + x, cmap[color], len);
298 memset(this->aimage + y * this->stride + x, alpha[color], len);
299 x += len;
300 if (x >= this->width) {
301 next_line(packet);
302 x = 0;
303 ++y;
306 spudec_cut_image(this);
311 This function tries to create a usable palette.
312 It determines how many non-transparent colors are used, and assigns different
313 gray scale values to each color.
314 I tested it with four streams and even got something readable. Half of the
315 times I got black characters with white around and half the reverse.
317 static void compute_palette(spudec_handle_t *this, packet_t *packet)
319 int used[16],i,cused,start,step,color;
321 memset(used, 0, sizeof(used));
322 for (i=0; i<4; i++)
323 if (packet->alpha[i]) /* !Transparent? */
324 used[packet->palette[i]] = 1;
325 for (cused=0, i=0; i<16; i++)
326 if (used[i]) cused++;
327 if (!cused) return;
328 if (cused == 1) {
329 start = 0x80;
330 step = 0;
331 } else {
332 start = this->font_start_level;
333 step = (0xF0-this->font_start_level)/(cused-1);
335 memset(used, 0, sizeof(used));
336 for (i=0; i<4; i++) {
337 color = packet->palette[i];
338 if (packet->alpha[i] && !used[color]) { /* not assigned? */
339 used[color] = 1;
340 this->global_palette[color] = start<<16;
341 start += step;
346 static void spudec_process_control(spudec_handle_t *this, unsigned int pts100)
348 int a,b; /* Temporary vars */
349 unsigned int date, type;
350 unsigned int off;
351 unsigned int start_off = 0;
352 unsigned int next_off;
353 unsigned int start_pts;
354 unsigned int end_pts;
355 unsigned int current_nibble[2];
356 unsigned int control_start;
357 unsigned int display = 0;
358 unsigned int start_col = 0;
359 unsigned int end_col = 0;
360 unsigned int start_row = 0;
361 unsigned int end_row = 0;
362 unsigned int width = 0;
363 unsigned int height = 0;
364 unsigned int stride = 0;
366 control_start = get_be16(this->packet + 2);
367 next_off = control_start;
368 while (start_off != next_off) {
369 start_off = next_off;
370 date = get_be16(this->packet + start_off) * 1024;
371 next_off = get_be16(this->packet + start_off + 2);
372 mp_msg(MSGT_SPUDEC,MSGL_DBG2, "date=%d\n", date);
373 off = start_off + 4;
374 for (type = this->packet[off++]; type != 0xff; type = this->packet[off++]) {
375 mp_msg(MSGT_SPUDEC,MSGL_DBG2, "cmd=%d ",type);
376 switch(type) {
377 case 0x00:
378 /* Menu ID, 1 byte */
379 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Menu ID\n");
380 /* shouldn't a Menu ID type force display start? */
381 start_pts = pts100 + date;
382 end_pts = UINT_MAX;
383 display = 1;
384 this->is_forced_sub=~0; // current subtitle is forced
385 break;
386 case 0x01:
387 /* Start display */
388 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Start display!\n");
389 start_pts = pts100 + date;
390 end_pts = UINT_MAX;
391 display = 1;
392 this->is_forced_sub=0;
393 break;
394 case 0x02:
395 /* Stop display */
396 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Stop display!\n");
397 end_pts = pts100 + date;
398 break;
399 case 0x03:
400 /* Palette */
401 this->palette[0] = this->packet[off] >> 4;
402 this->palette[1] = this->packet[off] & 0xf;
403 this->palette[2] = this->packet[off + 1] >> 4;
404 this->palette[3] = this->packet[off + 1] & 0xf;
405 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Palette %d, %d, %d, %d\n",
406 this->palette[0], this->palette[1], this->palette[2], this->palette[3]);
407 off+=2;
408 break;
409 case 0x04:
410 /* Alpha */
411 this->alpha[0] = this->packet[off] >> 4;
412 this->alpha[1] = this->packet[off] & 0xf;
413 this->alpha[2] = this->packet[off + 1] >> 4;
414 this->alpha[3] = this->packet[off + 1] & 0xf;
415 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Alpha %d, %d, %d, %d\n",
416 this->alpha[0], this->alpha[1], this->alpha[2], this->alpha[3]);
417 off+=2;
418 break;
419 case 0x05:
420 /* Co-ords */
421 a = get_be24(this->packet + off);
422 b = get_be24(this->packet + off + 3);
423 start_col = a >> 12;
424 end_col = a & 0xfff;
425 width = (end_col < start_col) ? 0 : end_col - start_col + 1;
426 stride = (width + 7) & ~7; /* Kludge: draw_alpha needs width multiple of 8 */
427 start_row = b >> 12;
428 end_row = b & 0xfff;
429 height = (end_row < start_row) ? 0 : end_row - start_row /* + 1 */;
430 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Coords col: %d - %d row: %d - %d (%dx%d)\n",
431 start_col, end_col, start_row, end_row,
432 width, height);
433 off+=6;
434 break;
435 case 0x06:
436 /* Graphic lines */
437 current_nibble[0] = 2 * get_be16(this->packet + off);
438 current_nibble[1] = 2 * get_be16(this->packet + off + 2);
439 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Graphic offset 1: %d offset 2: %d\n",
440 current_nibble[0] / 2, current_nibble[1] / 2);
441 off+=4;
442 break;
443 case 0xff:
444 /* All done, bye-bye */
445 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Done!\n");
446 return;
447 // break;
448 default:
449 mp_msg(MSGT_SPUDEC,MSGL_WARN,"spudec: Error determining control type 0x%02x. Skipping %d bytes.\n",
450 type, next_off - off);
451 goto next_control;
454 next_control:
455 if (display) {
456 packet_t *packet = calloc(1, sizeof(packet_t));
457 int i;
458 packet->start_pts = start_pts;
459 if (end_pts == UINT_MAX && start_off != next_off) {
460 start_pts = pts100 + get_be16(this->packet + next_off) * 1024;
461 packet->end_pts = start_pts - 1;
462 } else packet->end_pts = end_pts;
463 packet->current_nibble[0] = current_nibble[0];
464 packet->current_nibble[1] = current_nibble[1];
465 packet->start_row = start_row;
466 packet->end_row = end_row;
467 packet->start_col = start_col;
468 packet->end_col = end_col;
469 packet->width = width;
470 packet->height = height;
471 packet->stride = stride;
472 packet->control_start = control_start;
473 for (i=0; i<4; i++) {
474 packet->alpha[i] = this->alpha[i];
475 packet->palette[i] = this->palette[i];
477 packet->packet = malloc(this->packet_size);
478 memcpy(packet->packet, this->packet, this->packet_size);
479 spudec_queue_packet(this, packet);
484 static void spudec_decode(spudec_handle_t *this, unsigned int pts100)
486 if(this->hw_spu) {
487 static vo_mpegpes_t packet = { NULL, 0, 0x20, 0 };
488 static vo_mpegpes_t *pkg=&packet;
489 packet.data = this->packet;
490 packet.size = this->packet_size;
491 packet.timestamp = pts100;
492 this->hw_spu->draw_frame((uint8_t**)&pkg);
493 } else
494 spudec_process_control(this, pts100);
497 int spudec_changed(void * this)
499 spudec_handle_t * spu = (spudec_handle_t*)this;
500 return (spu->spu_changed || spu->now_pts > spu->end_pts);
503 void spudec_assemble(void *this, unsigned char *packet, unsigned int len, unsigned int pts100)
505 spudec_handle_t *spu = (spudec_handle_t*)this;
506 // spudec_heartbeat(this, pts100);
507 if (len < 2) {
508 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: packet too short\n");
509 return;
511 #if 0
512 if ((spu->packet_pts + 10000) < pts100) {
513 // [cb] too long since last fragment: force new packet
514 spu->packet_offset = 0;
516 #endif
517 spu->packet_pts = pts100;
518 if (spu->packet_offset == 0) {
519 unsigned int len2 = get_be16(packet);
520 // Start new fragment
521 if (spu->packet_reserve < len2) {
522 if (spu->packet != NULL)
523 free(spu->packet);
524 spu->packet = malloc(len2);
525 spu->packet_reserve = spu->packet != NULL ? len2 : 0;
527 if (spu->packet != NULL) {
528 spu->packet_size = len2;
529 if (len > len2) {
530 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: invalid frag len / len2: %d / %d \n", len, len2);
531 return;
533 memcpy(spu->packet, packet, len);
534 spu->packet_offset = len;
535 spu->packet_pts = pts100;
537 } else {
538 // Continue current fragment
539 if (spu->packet_size < spu->packet_offset + len){
540 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: invalid fragment\n");
541 spu->packet_size = spu->packet_offset = 0;
542 return;
543 } else {
544 memcpy(spu->packet + spu->packet_offset, packet, len);
545 spu->packet_offset += len;
548 #if 1
549 // check if we have a complete packet (unfortunatelly packet_size is bad
550 // for some disks)
551 // [cb] packet_size is padded to be even -> may be one byte too long
552 if ((spu->packet_offset == spu->packet_size) ||
553 ((spu->packet_offset + 1) == spu->packet_size)){
554 unsigned int x=0,y;
555 while(x+4<=spu->packet_offset){
556 y=get_be16(spu->packet+x+2); // next control pointer
557 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPUtest: x=%d y=%d off=%d size=%d\n",x,y,spu->packet_offset,spu->packet_size);
558 if(x>=4 && x==y){ // if it points to self - we're done!
559 // we got it!
560 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPUgot: off=%d size=%d \n",spu->packet_offset,spu->packet_size);
561 spudec_decode(spu, pts100);
562 spu->packet_offset = 0;
563 break;
565 if(y<=x || y>=spu->packet_size){ // invalid?
566 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUtest: broken packet!!!!! y=%d < x=%d\n",y,x);
567 spu->packet_size = spu->packet_offset = 0;
568 break;
570 x=y;
572 // [cb] packet is done; start new packet
573 spu->packet_offset = 0;
575 #else
576 if (spu->packet_offset == spu->packet_size) {
577 spudec_decode(spu, pts100);
578 spu->packet_offset = 0;
580 #endif
583 void spudec_reset(void *this) // called after seek
585 spudec_handle_t *spu = (spudec_handle_t*)this;
586 while (spu->queue_head)
587 spudec_free_packet(spudec_dequeue_packet(spu));
588 spu->now_pts = 0;
589 spu->end_pts = 0;
590 spu->packet_size = spu->packet_offset = 0;
593 void spudec_heartbeat(void *this, unsigned int pts100)
595 spudec_handle_t *spu = (spudec_handle_t*) this;
596 spu->now_pts = pts100;
598 while (spu->queue_head != NULL && pts100 >= spu->queue_head->start_pts) {
599 packet_t *packet = spudec_dequeue_packet(spu);
600 spu->start_pts = packet->start_pts;
601 spu->end_pts = packet->end_pts;
602 if (spu->auto_palette)
603 compute_palette(spu, packet);
604 spudec_process_data(spu, packet);
605 spudec_free_packet(packet);
606 spu->spu_changed = 1;
610 int spudec_visible(void *this){
611 spudec_handle_t *spu = (spudec_handle_t *)this;
612 int ret=(spu->start_pts <= spu->now_pts &&
613 spu->now_pts < spu->end_pts &&
614 spu->height > 0);
615 // printf("spu visible: %d \n",ret);
616 return ret;
619 void spudec_set_forced_subs_only(void * const this, const unsigned int flag)
621 if(this){
622 ((spudec_handle_t *)this)->forced_subs_only=flag;
623 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPU: Display only forced subs now %s\n", flag ? "enabled": "disabled");
627 void spudec_draw(void *this, void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride))
629 spudec_handle_t *spu = (spudec_handle_t *)this;
630 if (spu->start_pts <= spu->now_pts && spu->now_pts < spu->end_pts && spu->image)
632 draw_alpha(spu->start_col, spu->start_row, spu->width, spu->height,
633 spu->image, spu->aimage, spu->stride);
634 spu->spu_changed = 0;
638 /* calc the bbox for spudec subs */
639 void spudec_calc_bbox(void *me, unsigned int dxs, unsigned int dys, unsigned int* bbox)
641 spudec_handle_t *spu;
642 spu = (spudec_handle_t *)me;
643 if (spu->orig_frame_width == 0 || spu->orig_frame_height == 0
644 || (spu->orig_frame_width == dxs && spu->orig_frame_height == dys)) {
645 bbox[0] = spu->start_col;
646 bbox[1] = spu->start_col + spu->width;
647 bbox[2] = spu->start_row;
648 bbox[3] = spu->start_row + spu->height;
650 else if (spu->scaled_frame_width != dxs || spu->scaled_frame_height != dys) {
651 unsigned int scalex = 0x100 * dxs / spu->orig_frame_width;
652 unsigned int scaley = 0x100 * dys / spu->orig_frame_height;
653 bbox[0] = spu->start_col * scalex / 0x100;
654 bbox[1] = spu->start_col * scalex / 0x100 + spu->width * scalex / 0x100;
655 switch (spu_alignment) {
656 case 0:
657 bbox[3] = dys*sub_pos/100 + spu->height * scaley / 0x100;
658 if (bbox[3] > dys) bbox[3] = dys;
659 bbox[2] = bbox[3] - spu->height * scaley / 0x100;
660 break;
661 case 1:
662 if (sub_pos < 50) {
663 bbox[2] = dys*sub_pos/100 - spu->height * scaley / 0x200;
664 if (bbox[2] < 0) bbox[2] = 0;
665 bbox[3] = bbox[2] + spu->height;
666 } else {
667 bbox[3] = dys*sub_pos/100 + spu->height * scaley / 0x200;
668 if (bbox[3] > dys) bbox[3] = dys;
669 bbox[2] = bbox[3] - spu->height * scaley / 0x100;
671 break;
672 case 2:
673 bbox[2] = dys*sub_pos/100 - spu->height * scaley / 0x100;
674 if (bbox[2] < 0) bbox[2] = 0;
675 bbox[3] = bbox[2] + spu->height;
676 break;
677 default: /* -1 */
678 bbox[2] = spu->start_row * scaley / 0x100;
679 bbox[3] = spu->start_row * scaley / 0x100 + spu->height * scaley / 0x100;
680 break;
684 /* transform mplayer's alpha value into an opacity value that is linear */
685 static inline int canon_alpha(int alpha)
687 return alpha ? 256 - alpha : 0;
690 typedef struct {
691 unsigned position;
692 unsigned left_up;
693 unsigned right_down;
694 }scale_pixel;
697 static void scale_table(unsigned int start_src, unsigned int start_tar, unsigned int end_src, unsigned int end_tar, scale_pixel * table)
699 unsigned int t;
700 unsigned int delta_src = end_src - start_src;
701 unsigned int delta_tar = end_tar - start_tar;
702 int src = 0;
703 int src_step;
704 if (delta_src == 0 || delta_tar == 0) {
705 return;
707 src_step = (delta_src << 16) / delta_tar >>1;
708 for (t = 0; t<=delta_tar; src += (src_step << 1), t++){
709 table[t].position= MIN(src >> 16, end_src - 1);
710 table[t].right_down = src & 0xffff;
711 table[t].left_up = 0x10000 - table[t].right_down;
715 /* bilinear scale, similar to vobsub's code */
716 static void scale_image(int x, int y, scale_pixel* table_x, scale_pixel* table_y, spudec_handle_t * spu)
718 int alpha[4];
719 int color[4];
720 unsigned int scale[4];
721 int base = table_y[y].position * spu->stride + table_x[x].position;
722 int scaled = y * spu->scaled_stride + x;
723 alpha[0] = canon_alpha(spu->aimage[base]);
724 alpha[1] = canon_alpha(spu->aimage[base + 1]);
725 alpha[2] = canon_alpha(spu->aimage[base + spu->stride]);
726 alpha[3] = canon_alpha(spu->aimage[base + spu->stride + 1]);
727 color[0] = spu->image[base];
728 color[1] = spu->image[base + 1];
729 color[2] = spu->image[base + spu->stride];
730 color[3] = spu->image[base + spu->stride + 1];
731 scale[0] = (table_x[x].left_up * table_y[y].left_up >> 16) * alpha[0];
732 scale[1] = (table_x[x].right_down * table_y[y].left_up >>16) * alpha[1];
733 scale[2] = (table_x[x].left_up * table_y[y].right_down >> 16) * alpha[2];
734 scale[3] = (table_x[x].right_down * table_y[y].right_down >> 16) * alpha[3];
735 spu->scaled_image[scaled] = (color[0] * scale[0] + color[1] * scale[1] + color[2] * scale[2] + color[3] * scale[3])>>24;
736 spu->scaled_aimage[scaled] = (scale[0] + scale[1] + scale[2] + scale[3]) >> 16;
737 if (spu->scaled_aimage[scaled]){
738 spu->scaled_aimage[scaled] = 256 - spu->scaled_aimage[scaled];
739 if(spu->scaled_aimage[scaled] + spu->scaled_image[scaled] > 255)
740 spu->scaled_image[scaled] = 256 - spu->scaled_aimage[scaled];
744 void sws_spu_image(unsigned char *d1, unsigned char *d2, int dw, int dh, int ds,
745 unsigned char *s1, unsigned char *s2, int sw, int sh, int ss)
747 struct SwsContext *ctx;
748 static SwsFilter filter;
749 static int firsttime = 1;
750 static float oldvar;
751 int i;
753 if (!firsttime && oldvar != spu_gaussvar) sws_freeVec(filter.lumH);
754 if (firsttime) {
755 filter.lumH = filter.lumV =
756 filter.chrH = filter.chrV = sws_getGaussianVec(spu_gaussvar, 3.0);
757 sws_normalizeVec(filter.lumH, 1.0);
758 firsttime = 0;
759 oldvar = spu_gaussvar;
762 ctx=sws_getContext(sw, sh, PIX_FMT_GRAY8, dw, dh, PIX_FMT_GRAY8, SWS_GAUSS, &filter, NULL, NULL);
763 sws_scale(ctx,&s1,&ss,0,sh,&d1,&ds);
764 for (i=ss*sh-1; i>=0; i--) if (!s2[i]) s2[i] = 255; //else s2[i] = 1;
765 sws_scale(ctx,&s2,&ss,0,sh,&d2,&ds);
766 for (i=ds*dh-1; i>=0; i--) if (d2[i]==0) d2[i] = 1; else if (d2[i]==255) d2[i] = 0;
767 sws_freeContext(ctx);
770 void spudec_draw_scaled(void *me, unsigned int dxs, unsigned int dys, void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride))
772 spudec_handle_t *spu = (spudec_handle_t *)me;
773 scale_pixel *table_x;
774 scale_pixel *table_y;
776 if (spu->start_pts <= spu->now_pts && spu->now_pts < spu->end_pts) {
778 // check if only forced subtitles are requested
779 if( (spu->forced_subs_only) && !(spu->is_forced_sub) ){
780 return;
783 if (!(spu_aamode&16) && (spu->orig_frame_width == 0 || spu->orig_frame_height == 0
784 || (spu->orig_frame_width == dxs && spu->orig_frame_height == dys))) {
785 if (spu->image)
787 draw_alpha(spu->start_col, spu->start_row, spu->width, spu->height,
788 spu->image, spu->aimage, spu->stride);
789 spu->spu_changed = 0;
792 else {
793 if (spu->scaled_frame_width != dxs || spu->scaled_frame_height != dys) { /* Resizing is needed */
794 /* scaled_x = scalex * x / 0x100
795 scaled_y = scaley * y / 0x100
796 order of operations is important because of rounding. */
797 unsigned int scalex = 0x100 * dxs / spu->orig_frame_width;
798 unsigned int scaley = 0x100 * dys / spu->orig_frame_height;
799 spu->scaled_start_col = spu->start_col * scalex / 0x100;
800 spu->scaled_start_row = spu->start_row * scaley / 0x100;
801 spu->scaled_width = spu->width * scalex / 0x100;
802 spu->scaled_height = spu->height * scaley / 0x100;
803 /* Kludge: draw_alpha needs width multiple of 8 */
804 spu->scaled_stride = (spu->scaled_width + 7) & ~7;
805 if (spu->scaled_image_size < spu->scaled_stride * spu->scaled_height) {
806 if (spu->scaled_image) {
807 free(spu->scaled_image);
808 spu->scaled_image_size = 0;
810 spu->scaled_image = malloc(2 * spu->scaled_stride * spu->scaled_height);
811 if (spu->scaled_image) {
812 spu->scaled_image_size = spu->scaled_stride * spu->scaled_height;
813 spu->scaled_aimage = spu->scaled_image + spu->scaled_image_size;
816 if (spu->scaled_image) {
817 unsigned int x, y;
818 if (spu->scaled_width <= 1 || spu->scaled_height <= 1) {
819 goto nothing_to_do;
821 switch(spu_aamode&15) {
822 case 4:
823 sws_spu_image(spu->scaled_image, spu->scaled_aimage,
824 spu->scaled_width, spu->scaled_height, spu->scaled_stride,
825 spu->image, spu->aimage, spu->width, spu->height, spu->stride);
826 break;
827 case 3:
828 table_x = calloc(spu->scaled_width, sizeof(scale_pixel));
829 table_y = calloc(spu->scaled_height, sizeof(scale_pixel));
830 if (!table_x || !table_y) {
831 mp_msg(MSGT_SPUDEC, MSGL_FATAL, "Fatal: spudec_draw_scaled: calloc failed\n");
833 scale_table(0, 0, spu->width - 1, spu->scaled_width - 1, table_x);
834 scale_table(0, 0, spu->height - 1, spu->scaled_height - 1, table_y);
835 for (y = 0; y < spu->scaled_height; y++)
836 for (x = 0; x < spu->scaled_width; x++)
837 scale_image(x, y, table_x, table_y, spu);
838 free(table_x);
839 free(table_y);
840 break;
841 case 0:
842 /* no antialiasing */
843 for (y = 0; y < spu->scaled_height; ++y) {
844 int unscaled_y = y * 0x100 / scaley;
845 int strides = spu->stride * unscaled_y;
846 int scaled_strides = spu->scaled_stride * y;
847 for (x = 0; x < spu->scaled_width; ++x) {
848 int unscaled_x = x * 0x100 / scalex;
849 spu->scaled_image[scaled_strides + x] = spu->image[strides + unscaled_x];
850 spu->scaled_aimage[scaled_strides + x] = spu->aimage[strides + unscaled_x];
853 break;
854 case 1:
856 /* Intermediate antialiasing. */
857 for (y = 0; y < spu->scaled_height; ++y) {
858 const unsigned int unscaled_top = y * spu->orig_frame_height / dys;
859 unsigned int unscaled_bottom = (y + 1) * spu->orig_frame_height / dys;
860 if (unscaled_bottom >= spu->height)
861 unscaled_bottom = spu->height - 1;
862 for (x = 0; x < spu->scaled_width; ++x) {
863 const unsigned int unscaled_left = x * spu->orig_frame_width / dxs;
864 unsigned int unscaled_right = (x + 1) * spu->orig_frame_width / dxs;
865 unsigned int color = 0;
866 unsigned int alpha = 0;
867 unsigned int walkx, walky;
868 unsigned int base, tmp;
869 if (unscaled_right >= spu->width)
870 unscaled_right = spu->width - 1;
871 for (walky = unscaled_top; walky <= unscaled_bottom; ++walky)
872 for (walkx = unscaled_left; walkx <= unscaled_right; ++walkx) {
873 base = walky * spu->stride + walkx;
874 tmp = canon_alpha(spu->aimage[base]);
875 alpha += tmp;
876 color += tmp * spu->image[base];
878 base = y * spu->scaled_stride + x;
879 spu->scaled_image[base] = alpha ? color / alpha : 0;
880 spu->scaled_aimage[base] =
881 alpha * (1 + unscaled_bottom - unscaled_top) * (1 + unscaled_right - unscaled_left);
882 /* spu->scaled_aimage[base] =
883 alpha * dxs * dys / spu->orig_frame_width / spu->orig_frame_height; */
884 if (spu->scaled_aimage[base]) {
885 spu->scaled_aimage[base] = 256 - spu->scaled_aimage[base];
886 if (spu->scaled_aimage[base] + spu->scaled_image[base] > 255)
887 spu->scaled_image[base] = 256 - spu->scaled_aimage[base];
892 break;
893 case 2:
895 /* Best antialiasing. Very slow. */
896 /* Any pixel (x, y) represents pixels from the original
897 rectangular region comprised between the columns
898 unscaled_y and unscaled_y + 0x100 / scaley and the rows
899 unscaled_x and unscaled_x + 0x100 / scalex
901 The original rectangular region that the scaled pixel
902 represents is cut in 9 rectangular areas like this:
904 +---+-----------------+---+
905 | 1 | 2 | 3 |
906 +---+-----------------+---+
907 | | | |
908 | 4 | 5 | 6 |
909 | | | |
910 +---+-----------------+---+
911 | 7 | 8 | 9 |
912 +---+-----------------+---+
914 The width of the left column is at most one pixel and
915 it is never null and its right column is at a pixel
916 boundary. The height of the top row is at most one
917 pixel it is never null and its bottom row is at a
918 pixel boundary. The width and height of region 5 are
919 integral values. The width of the right column is
920 what remains and is less than one pixel. The height
921 of the bottom row is what remains and is less than
922 one pixel.
924 The row above 1, 2, 3 is unscaled_y. The row between
925 1, 2, 3 and 4, 5, 6 is top_low_row. The row between 4,
926 5, 6 and 7, 8, 9 is (unsigned int)unscaled_y_bottom.
927 The row beneath 7, 8, 9 is unscaled_y_bottom.
929 The column left of 1, 4, 7 is unscaled_x. The column
930 between 1, 4, 7 and 2, 5, 8 is left_right_column. The
931 column between 2, 5, 8 and 3, 6, 9 is (unsigned
932 int)unscaled_x_right. The column right of 3, 6, 9 is
933 unscaled_x_right. */
934 const double inv_scalex = (double) 0x100 / scalex;
935 const double inv_scaley = (double) 0x100 / scaley;
936 for (y = 0; y < spu->scaled_height; ++y) {
937 const double unscaled_y = y * inv_scaley;
938 const double unscaled_y_bottom = unscaled_y + inv_scaley;
939 const unsigned int top_low_row = MIN(unscaled_y_bottom, unscaled_y + 1.0);
940 const double top = top_low_row - unscaled_y;
941 const unsigned int height = unscaled_y_bottom > top_low_row
942 ? (unsigned int) unscaled_y_bottom - top_low_row
943 : 0;
944 const double bottom = unscaled_y_bottom > top_low_row
945 ? unscaled_y_bottom - floor(unscaled_y_bottom)
946 : 0.0;
947 for (x = 0; x < spu->scaled_width; ++x) {
948 const double unscaled_x = x * inv_scalex;
949 const double unscaled_x_right = unscaled_x + inv_scalex;
950 const unsigned int left_right_column = MIN(unscaled_x_right, unscaled_x + 1.0);
951 const double left = left_right_column - unscaled_x;
952 const unsigned int width = unscaled_x_right > left_right_column
953 ? (unsigned int) unscaled_x_right - left_right_column
954 : 0;
955 const double right = unscaled_x_right > left_right_column
956 ? unscaled_x_right - floor(unscaled_x_right)
957 : 0.0;
958 double color = 0.0;
959 double alpha = 0.0;
960 double tmp;
961 unsigned int base;
962 /* Now use these informations to compute a good alpha,
963 and lightness. The sum is on each of the 9
964 region's surface and alpha and lightness.
966 transformed alpha = sum(surface * alpha) / sum(surface)
967 transformed color = sum(surface * alpha * color) / sum(surface * alpha)
969 /* 1: top left part */
970 base = spu->stride * (unsigned int) unscaled_y;
971 tmp = left * top * canon_alpha(spu->aimage[base + (unsigned int) unscaled_x]);
972 alpha += tmp;
973 color += tmp * spu->image[base + (unsigned int) unscaled_x];
974 /* 2: top center part */
975 if (width > 0) {
976 unsigned int walkx;
977 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
978 base = spu->stride * (unsigned int) unscaled_y + walkx;
979 tmp = /* 1.0 * */ top * canon_alpha(spu->aimage[base]);
980 alpha += tmp;
981 color += tmp * spu->image[base];
984 /* 3: top right part */
985 if (right > 0.0) {
986 base = spu->stride * (unsigned int) unscaled_y + (unsigned int) unscaled_x_right;
987 tmp = right * top * canon_alpha(spu->aimage[base]);
988 alpha += tmp;
989 color += tmp * spu->image[base];
991 /* 4: center left part */
992 if (height > 0) {
993 unsigned int walky;
994 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
995 base = spu->stride * walky + (unsigned int) unscaled_x;
996 tmp = left /* * 1.0 */ * canon_alpha(spu->aimage[base]);
997 alpha += tmp;
998 color += tmp * spu->image[base];
1001 /* 5: center part */
1002 if (width > 0 && height > 0) {
1003 unsigned int walky;
1004 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1005 unsigned int walkx;
1006 base = spu->stride * walky;
1007 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
1008 tmp = /* 1.0 * 1.0 * */ canon_alpha(spu->aimage[base + walkx]);
1009 alpha += tmp;
1010 color += tmp * spu->image[base + walkx];
1014 /* 6: center right part */
1015 if (right > 0.0 && height > 0) {
1016 unsigned int walky;
1017 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1018 base = spu->stride * walky + (unsigned int) unscaled_x_right;
1019 tmp = right /* * 1.0 */ * canon_alpha(spu->aimage[base]);
1020 alpha += tmp;
1021 color += tmp * spu->image[base];
1024 /* 7: bottom left part */
1025 if (bottom > 0.0) {
1026 base = spu->stride * (unsigned int) unscaled_y_bottom + (unsigned int) unscaled_x;
1027 tmp = left * bottom * canon_alpha(spu->aimage[base]);
1028 alpha += tmp;
1029 color += tmp * spu->image[base];
1031 /* 8: bottom center part */
1032 if (width > 0 && bottom > 0.0) {
1033 unsigned int walkx;
1034 base = spu->stride * (unsigned int) unscaled_y_bottom;
1035 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
1036 tmp = /* 1.0 * */ bottom * canon_alpha(spu->aimage[base + walkx]);
1037 alpha += tmp;
1038 color += tmp * spu->image[base + walkx];
1041 /* 9: bottom right part */
1042 if (right > 0.0 && bottom > 0.0) {
1043 base = spu->stride * (unsigned int) unscaled_y_bottom + (unsigned int) unscaled_x_right;
1044 tmp = right * bottom * canon_alpha(spu->aimage[base]);
1045 alpha += tmp;
1046 color += tmp * spu->image[base];
1048 /* Finally mix these transparency and brightness information suitably */
1049 base = spu->scaled_stride * y + x;
1050 spu->scaled_image[base] = alpha > 0 ? color / alpha : 0;
1051 spu->scaled_aimage[base] = alpha * scalex * scaley / 0x10000;
1052 if (spu->scaled_aimage[base]) {
1053 spu->scaled_aimage[base] = 256 - spu->scaled_aimage[base];
1054 if (spu->scaled_aimage[base] + spu->scaled_image[base] > 255)
1055 spu->scaled_image[base] = 256 - spu->scaled_aimage[base];
1061 nothing_to_do:
1062 /* Kludge: draw_alpha needs width multiple of 8. */
1063 if (spu->scaled_width < spu->scaled_stride)
1064 for (y = 0; y < spu->scaled_height; ++y) {
1065 memset(spu->scaled_aimage + y * spu->scaled_stride + spu->scaled_width, 0,
1066 spu->scaled_stride - spu->scaled_width);
1068 spu->scaled_frame_width = dxs;
1069 spu->scaled_frame_height = dys;
1072 if (spu->scaled_image){
1073 switch (spu_alignment) {
1074 case 0:
1075 spu->scaled_start_row = dys*sub_pos/100;
1076 if (spu->scaled_start_row + spu->scaled_height > dys)
1077 spu->scaled_start_row = dys - spu->scaled_height;
1078 break;
1079 case 1:
1080 spu->scaled_start_row = dys*sub_pos/100 - spu->scaled_height/2;
1081 if (sub_pos < 50) {
1082 if (spu->scaled_start_row < 0) spu->scaled_start_row = 0;
1083 } else {
1084 if (spu->scaled_start_row + spu->scaled_height > dys)
1085 spu->scaled_start_row = dys - spu->scaled_height;
1087 break;
1088 case 2:
1089 spu->scaled_start_row = dys*sub_pos/100 - spu->scaled_height;
1090 if (spu->scaled_start_row < 0) spu->scaled_start_row = 0;
1091 break;
1093 draw_alpha(spu->scaled_start_col, spu->scaled_start_row, spu->scaled_width, spu->scaled_height,
1094 spu->scaled_image, spu->scaled_aimage, spu->scaled_stride);
1095 spu->spu_changed = 0;
1099 else
1101 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPU not displayed: start_pts=%d end_pts=%d now_pts=%d\n",
1102 spu->start_pts, spu->end_pts, spu->now_pts);
1106 void spudec_update_palette(void * this, unsigned int *palette)
1108 spudec_handle_t *spu = (spudec_handle_t *) this;
1109 if (spu && palette) {
1110 memcpy(spu->global_palette, palette, sizeof(spu->global_palette));
1111 if(spu->hw_spu)
1112 spu->hw_spu->control(VOCTRL_SET_SPU_PALETTE,spu->global_palette);
1116 void spudec_set_font_factor(void * this, double factor)
1118 spudec_handle_t *spu = (spudec_handle_t *) this;
1119 spu->font_start_level = (int)(0xF0-(0xE0*factor));
1122 void *spudec_new_scaled(unsigned int *palette, unsigned int frame_width, unsigned int frame_height)
1124 return spudec_new_scaled_vobsub(palette, NULL, 0, frame_width, frame_height);
1127 /* get palette custom color, width, height from .idx file */
1128 void *spudec_new_scaled_vobsub(unsigned int *palette, unsigned int *cuspal, unsigned int custom, unsigned int frame_width, unsigned int frame_height)
1130 spudec_handle_t *this = calloc(1, sizeof(spudec_handle_t));
1131 if (this){
1132 //(fprintf(stderr,"VobSub Custom Palette: %d,%d,%d,%d", this->cuspal[0], this->cuspal[1], this->cuspal[2],this->cuspal[3]);
1133 this->packet = NULL;
1134 this->image = NULL;
1135 this->scaled_image = NULL;
1136 /* XXX Although the video frame is some size, the SPU frame is
1137 always maximum size i.e. 720 wide and 576 or 480 high */
1138 this->orig_frame_width = 720;
1139 this->orig_frame_height = (frame_height == 480 || frame_height == 240) ? 480 : 576;
1140 this->custom = custom;
1141 // set up palette:
1142 this->auto_palette = 1;
1143 if (palette){
1144 memcpy(this->global_palette, palette, sizeof(this->global_palette));
1145 this->auto_palette = 0;
1147 this->custom = custom;
1148 if (custom && cuspal) {
1149 memcpy(this->cuspal, cuspal, sizeof(this->cuspal));
1150 this->auto_palette = 0;
1152 // forced subtitles default: show all subtitles
1153 this->forced_subs_only=0;
1154 this->is_forced_sub=0;
1156 else
1157 mp_msg(MSGT_SPUDEC,MSGL_FATAL, "FATAL: spudec_init: calloc");
1158 return this;
1161 void *spudec_new(unsigned int *palette)
1163 return spudec_new_scaled(palette, 0, 0);
1166 void spudec_free(void *this)
1168 spudec_handle_t *spu = (spudec_handle_t*)this;
1169 if (spu) {
1170 while (spu->queue_head)
1171 spudec_free_packet(spudec_dequeue_packet(spu));
1172 if (spu->packet)
1173 free(spu->packet);
1174 if (spu->scaled_image)
1175 free(spu->scaled_image);
1176 if (spu->image)
1177 free(spu->image);
1178 free(spu);
1182 void spudec_set_hw_spu(void *this, vo_functions_t *hw_spu)
1184 spudec_handle_t *spu = (spudec_handle_t*)this;
1185 if (!spu)
1186 return;
1187 spu->hw_spu = hw_spu;
1188 hw_spu->control(VOCTRL_SET_SPU_PALETTE,spu->global_palette);