remove useless casts
[mplayer/glamo.git] / spudec.c
blobcec9a1ab75df1a893553f9625af7a1e22f1c8017
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 /* Valid values for spu_aamode:
34 0: none (fastest, most ugly)
35 1: approximate
36 2: full (slowest)
37 3: bilinear (similiar to vobsub, fast and not too bad)
38 4: uses swscaler gaussian (this is the only one that looks good)
41 int spu_aamode = 3;
42 int spu_alignment = -1;
43 float spu_gaussvar = 1.0;
44 extern int sub_pos;
46 typedef struct packet_t packet_t;
47 struct packet_t {
48 unsigned char *packet;
49 unsigned int palette[4];
50 unsigned int alpha[4];
51 unsigned int control_start; /* index of start of control data */
52 unsigned int current_nibble[2]; /* next data nibble (4 bits) to be
53 processed (for RLE decoding) for
54 even and odd lines */
55 int deinterlace_oddness; /* 0 or 1, index into current_nibble */
56 unsigned int start_col, end_col;
57 unsigned int start_row, end_row;
58 unsigned int width, height, stride;
59 unsigned int start_pts, end_pts;
60 packet_t *next;
63 typedef struct {
64 packet_t *queue_head;
65 packet_t *queue_tail;
66 unsigned int global_palette[16];
67 unsigned int orig_frame_width, orig_frame_height;
68 unsigned char* packet;
69 size_t packet_reserve; /* size of the memory pointed to by packet */
70 unsigned int packet_offset; /* end of the currently assembled fragment */
71 unsigned int packet_size; /* size of the packet once all fragments are assembled */
72 int packet_pts; /* PTS for this packet */
73 unsigned int palette[4];
74 unsigned int alpha[4];
75 unsigned int cuspal[4];
76 unsigned int custom;
77 unsigned int now_pts;
78 unsigned int start_pts, end_pts;
79 unsigned int start_col, end_col;
80 unsigned int start_row, end_row;
81 unsigned int width, height, stride;
82 size_t image_size; /* Size of the image buffer */
83 unsigned char *image; /* Grayscale value */
84 unsigned char *aimage; /* Alpha value */
85 unsigned int scaled_frame_width, scaled_frame_height;
86 unsigned int scaled_start_col, scaled_start_row;
87 unsigned int scaled_width, scaled_height, scaled_stride;
88 size_t scaled_image_size;
89 unsigned char *scaled_image;
90 unsigned char *scaled_aimage;
91 int auto_palette; /* 1 if we lack a palette and must use an heuristic. */
92 int font_start_level; /* Darkest value used for the computed font */
93 const vo_functions_t *hw_spu;
94 int spu_changed;
95 unsigned int forced_subs_only; /* flag: 0=display all subtitle, !0 display only forced subtitles */
96 unsigned int is_forced_sub; /* true if current subtitle is a forced subtitle */
97 } spudec_handle_t;
99 static void spudec_queue_packet(spudec_handle_t *this, packet_t *packet)
101 if (this->queue_head == NULL)
102 this->queue_head = packet;
103 else
104 this->queue_tail->next = packet;
105 this->queue_tail = packet;
108 static packet_t *spudec_dequeue_packet(spudec_handle_t *this)
110 packet_t *retval = this->queue_head;
112 this->queue_head = retval->next;
113 if (this->queue_head == NULL)
114 this->queue_tail = NULL;
116 return retval;
119 static void spudec_free_packet(packet_t *packet)
121 if (packet->packet != NULL)
122 free(packet->packet);
123 free(packet);
126 static inline unsigned int get_be16(const unsigned char *p)
128 return (p[0] << 8) + p[1];
131 static inline unsigned int get_be24(const unsigned char *p)
133 return (get_be16(p) << 8) + p[2];
136 static void next_line(packet_t *packet)
138 if (packet->current_nibble[packet->deinterlace_oddness] % 2)
139 packet->current_nibble[packet->deinterlace_oddness]++;
140 packet->deinterlace_oddness = (packet->deinterlace_oddness + 1) % 2;
143 static inline unsigned char get_nibble(packet_t *packet)
145 unsigned char nib;
146 unsigned int *nibblep = packet->current_nibble + packet->deinterlace_oddness;
147 if (*nibblep / 2 >= packet->control_start) {
148 mp_msg(MSGT_SPUDEC,MSGL_WARN, "SPUdec: ERROR: get_nibble past end of packet\n");
149 return 0;
151 nib = packet->packet[*nibblep / 2];
152 if (*nibblep % 2)
153 nib &= 0xf;
154 else
155 nib >>= 4;
156 ++*nibblep;
157 return nib;
160 static inline int mkalpha(int i)
162 /* In mplayer's alpha planes, 0 is transparent, then 1 is nearly
163 opaque upto 255 which is transparent */
164 switch (i) {
165 case 0xf:
166 return 1;
167 case 0:
168 return 0;
169 default:
170 return (0xf - i) << 4;
174 /* Cut the sub to visible part */
175 static inline void spudec_cut_image(spudec_handle_t *this)
177 unsigned int fy, ly;
178 unsigned int first_y, last_y;
179 unsigned char *image;
180 unsigned char *aimage;
182 if (this->stride == 0 || this->height == 0) {
183 return;
186 for (fy = 0; fy < this->image_size && !this->aimage[fy]; fy++);
187 for (ly = this->stride * this->height-1; ly && !this->aimage[ly]; ly--);
188 first_y = fy / this->stride;
189 last_y = ly / this->stride;
190 //printf("first_y: %d, last_y: %d\n", first_y, last_y);
191 this->start_row += first_y;
193 // Some subtitles trigger this condition
194 if (last_y + 1 > first_y ) {
195 this->height = last_y - first_y +1;
196 } else {
197 this->height = 0;
198 this->image_size = 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 image = malloc(2 * this->stride * this->height);
205 if(image){
206 this->image_size = this->stride * this->height;
207 aimage = image + this->image_size;
208 memcpy(image, this->image + this->stride * first_y, this->image_size);
209 memcpy(aimage, this->aimage + this->stride * first_y, this->image_size);
210 free(this->image);
211 this->image = image;
212 this->aimage = aimage;
213 } else {
214 mp_msg(MSGT_SPUDEC, MSGL_FATAL, "Fatal: update_spu: malloc requested %d bytes\n", 2 * this->stride * this->height);
218 static void spudec_process_data(spudec_handle_t *this, packet_t *packet)
220 unsigned int cmap[4], alpha[4];
221 unsigned int i, x, y;
223 this->scaled_frame_width = 0;
224 this->scaled_frame_height = 0;
225 this->start_col = packet->start_col;
226 this->end_col = packet->end_col;
227 this->start_row = packet->start_row;
228 this->end_row = packet->end_row;
229 this->height = packet->height;
230 this->width = packet->width;
231 this->stride = packet->stride;
232 for (i = 0; i < 4; ++i) {
233 alpha[i] = mkalpha(packet->alpha[i]);
234 if (this->custom && (this->cuspal[i] >> 31) != 0)
235 alpha[i] = 0;
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, 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 = 0;
354 unsigned int end_pts = 0;
355 unsigned int current_nibble[2] = {0, 0};
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 < 0 && -pts100 >= date ? 0 : 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 < 0 && -pts100 >= date ? 0 : 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 < 0 && -pts100 >= date ? 0 : 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 continue;
457 if (end_pts == UINT_MAX && start_off != next_off) {
458 end_pts = get_be16(this->packet + next_off) * 1024;
459 end_pts = 1 - pts100 >= end_pts ? 0 : pts100 + end_pts - 1;
461 if (end_pts > 0) {
462 packet_t *packet = calloc(1, sizeof(packet_t));
463 int i;
464 packet->start_pts = start_pts;
465 packet->end_pts = end_pts;
466 packet->current_nibble[0] = current_nibble[0];
467 packet->current_nibble[1] = current_nibble[1];
468 packet->start_row = start_row;
469 packet->end_row = end_row;
470 packet->start_col = start_col;
471 packet->end_col = end_col;
472 packet->width = width;
473 packet->height = height;
474 packet->stride = stride;
475 packet->control_start = control_start;
476 for (i=0; i<4; i++) {
477 packet->alpha[i] = this->alpha[i];
478 packet->palette[i] = this->palette[i];
480 packet->packet = malloc(this->packet_size);
481 memcpy(packet->packet, this->packet, this->packet_size);
482 spudec_queue_packet(this, packet);
487 static void spudec_decode(spudec_handle_t *this, int pts100)
489 if (!this->hw_spu)
490 spudec_process_control(this, pts100);
491 else if (pts100 >= 0) {
492 static vo_mpegpes_t packet = { NULL, 0, 0x20, 0 };
493 static vo_mpegpes_t *pkg=&packet;
494 packet.data = this->packet;
495 packet.size = this->packet_size;
496 packet.timestamp = pts100;
497 this->hw_spu->draw_frame((uint8_t**)&pkg);
501 int spudec_changed(void * this)
503 spudec_handle_t * spu = (spudec_handle_t*)this;
504 return (spu->spu_changed || spu->now_pts > spu->end_pts);
507 void spudec_assemble(void *this, unsigned char *packet, unsigned int len, int pts100)
509 spudec_handle_t *spu = (spudec_handle_t*)this;
510 // spudec_heartbeat(this, pts100);
511 if (len < 2) {
512 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: packet too short\n");
513 return;
515 #if 0
516 if ((spu->packet_pts + 10000) < pts100) {
517 // [cb] too long since last fragment: force new packet
518 spu->packet_offset = 0;
520 #endif
521 spu->packet_pts = pts100;
522 if (spu->packet_offset == 0) {
523 unsigned int len2 = get_be16(packet);
524 // Start new fragment
525 if (spu->packet_reserve < len2) {
526 if (spu->packet != NULL)
527 free(spu->packet);
528 spu->packet = malloc(len2);
529 spu->packet_reserve = spu->packet != NULL ? len2 : 0;
531 if (spu->packet != NULL) {
532 spu->packet_size = len2;
533 if (len > len2) {
534 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: invalid frag len / len2: %d / %d \n", len, len2);
535 return;
537 memcpy(spu->packet, packet, len);
538 spu->packet_offset = len;
539 spu->packet_pts = pts100;
541 } else {
542 // Continue current fragment
543 if (spu->packet_size < spu->packet_offset + len){
544 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: invalid fragment\n");
545 spu->packet_size = spu->packet_offset = 0;
546 return;
547 } else {
548 memcpy(spu->packet + spu->packet_offset, packet, len);
549 spu->packet_offset += len;
552 #if 1
553 // check if we have a complete packet (unfortunatelly packet_size is bad
554 // for some disks)
555 // [cb] packet_size is padded to be even -> may be one byte too long
556 if ((spu->packet_offset == spu->packet_size) ||
557 ((spu->packet_offset + 1) == spu->packet_size)){
558 unsigned int x=0,y;
559 while(x+4<=spu->packet_offset){
560 y=get_be16(spu->packet+x+2); // next control pointer
561 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPUtest: x=%d y=%d off=%d size=%d\n",x,y,spu->packet_offset,spu->packet_size);
562 if(x>=4 && x==y){ // if it points to self - we're done!
563 // we got it!
564 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPUgot: off=%d size=%d \n",spu->packet_offset,spu->packet_size);
565 spudec_decode(spu, pts100);
566 spu->packet_offset = 0;
567 break;
569 if(y<=x || y>=spu->packet_size){ // invalid?
570 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUtest: broken packet!!!!! y=%d < x=%d\n",y,x);
571 spu->packet_size = spu->packet_offset = 0;
572 break;
574 x=y;
576 // [cb] packet is done; start new packet
577 spu->packet_offset = 0;
579 #else
580 if (spu->packet_offset == spu->packet_size) {
581 spudec_decode(spu, pts100);
582 spu->packet_offset = 0;
584 #endif
587 void spudec_reset(void *this) // called after seek
589 spudec_handle_t *spu = (spudec_handle_t*)this;
590 while (spu->queue_head)
591 spudec_free_packet(spudec_dequeue_packet(spu));
592 spu->now_pts = 0;
593 spu->end_pts = 0;
594 spu->packet_size = spu->packet_offset = 0;
597 void spudec_heartbeat(void *this, unsigned int pts100)
599 spudec_handle_t *spu = (spudec_handle_t*) this;
600 spu->now_pts = pts100;
602 while (spu->queue_head != NULL && pts100 >= spu->queue_head->start_pts) {
603 packet_t *packet = spudec_dequeue_packet(spu);
604 spu->start_pts = packet->start_pts;
605 spu->end_pts = packet->end_pts;
606 if (spu->auto_palette)
607 compute_palette(spu, packet);
608 spudec_process_data(spu, packet);
609 spudec_free_packet(packet);
610 spu->spu_changed = 1;
614 int spudec_visible(void *this){
615 spudec_handle_t *spu = (spudec_handle_t *)this;
616 int ret=(spu->start_pts <= spu->now_pts &&
617 spu->now_pts < spu->end_pts &&
618 spu->height > 0);
619 // printf("spu visible: %d \n",ret);
620 return ret;
623 void spudec_set_forced_subs_only(void * const this, const unsigned int flag)
625 if(this){
626 ((spudec_handle_t *)this)->forced_subs_only=flag;
627 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPU: Display only forced subs now %s\n", flag ? "enabled": "disabled");
631 void spudec_draw(void *this, void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride))
633 spudec_handle_t *spu = (spudec_handle_t *)this;
634 if (spu->start_pts <= spu->now_pts && spu->now_pts < spu->end_pts && spu->image)
636 draw_alpha(spu->start_col, spu->start_row, spu->width, spu->height,
637 spu->image, spu->aimage, spu->stride);
638 spu->spu_changed = 0;
642 /* calc the bbox for spudec subs */
643 void spudec_calc_bbox(void *me, unsigned int dxs, unsigned int dys, unsigned int* bbox)
645 spudec_handle_t *spu;
646 spu = (spudec_handle_t *)me;
647 if (spu->orig_frame_width == 0 || spu->orig_frame_height == 0
648 || (spu->orig_frame_width == dxs && spu->orig_frame_height == dys)) {
649 bbox[0] = spu->start_col;
650 bbox[1] = spu->start_col + spu->width;
651 bbox[2] = spu->start_row;
652 bbox[3] = spu->start_row + spu->height;
654 else if (spu->scaled_frame_width != dxs || spu->scaled_frame_height != dys) {
655 unsigned int scalex = 0x100 * dxs / spu->orig_frame_width;
656 unsigned int scaley = 0x100 * dys / spu->orig_frame_height;
657 bbox[0] = spu->start_col * scalex / 0x100;
658 bbox[1] = spu->start_col * scalex / 0x100 + spu->width * scalex / 0x100;
659 switch (spu_alignment) {
660 case 0:
661 bbox[3] = dys*sub_pos/100 + spu->height * scaley / 0x100;
662 if (bbox[3] > dys) bbox[3] = dys;
663 bbox[2] = bbox[3] - spu->height * scaley / 0x100;
664 break;
665 case 1:
666 if (sub_pos < 50) {
667 bbox[2] = dys*sub_pos/100 - spu->height * scaley / 0x200;
668 bbox[3] = bbox[2] + spu->height;
669 } else {
670 bbox[3] = dys*sub_pos/100 + spu->height * scaley / 0x200;
671 if (bbox[3] > dys) bbox[3] = dys;
672 bbox[2] = bbox[3] - spu->height * scaley / 0x100;
674 break;
675 case 2:
676 bbox[2] = dys*sub_pos/100 - spu->height * scaley / 0x100;
677 bbox[3] = bbox[2] + spu->height;
678 break;
679 default: /* -1 */
680 bbox[2] = spu->start_row * scaley / 0x100;
681 bbox[3] = spu->start_row * scaley / 0x100 + spu->height * scaley / 0x100;
682 break;
686 /* transform mplayer's alpha value into an opacity value that is linear */
687 static inline int canon_alpha(int alpha)
689 return alpha ? 256 - alpha : 0;
692 typedef struct {
693 unsigned position;
694 unsigned left_up;
695 unsigned right_down;
696 }scale_pixel;
699 static void scale_table(unsigned int start_src, unsigned int start_tar, unsigned int end_src, unsigned int end_tar, scale_pixel * table)
701 unsigned int t;
702 unsigned int delta_src = end_src - start_src;
703 unsigned int delta_tar = end_tar - start_tar;
704 int src = 0;
705 int src_step;
706 if (delta_src == 0 || delta_tar == 0) {
707 return;
709 src_step = (delta_src << 16) / delta_tar >>1;
710 for (t = 0; t<=delta_tar; src += (src_step << 1), t++){
711 table[t].position= FFMIN(src >> 16, end_src - 1);
712 table[t].right_down = src & 0xffff;
713 table[t].left_up = 0x10000 - table[t].right_down;
717 /* bilinear scale, similar to vobsub's code */
718 static void scale_image(int x, int y, scale_pixel* table_x, scale_pixel* table_y, spudec_handle_t * spu)
720 int alpha[4];
721 int color[4];
722 unsigned int scale[4];
723 int base = table_y[y].position * spu->stride + table_x[x].position;
724 int scaled = y * spu->scaled_stride + x;
725 alpha[0] = canon_alpha(spu->aimage[base]);
726 alpha[1] = canon_alpha(spu->aimage[base + 1]);
727 alpha[2] = canon_alpha(spu->aimage[base + spu->stride]);
728 alpha[3] = canon_alpha(spu->aimage[base + spu->stride + 1]);
729 color[0] = spu->image[base];
730 color[1] = spu->image[base + 1];
731 color[2] = spu->image[base + spu->stride];
732 color[3] = spu->image[base + spu->stride + 1];
733 scale[0] = (table_x[x].left_up * table_y[y].left_up >> 16) * alpha[0];
734 if (table_y[y].left_up == 0x10000) // necessary to avoid overflow-case
735 scale[0] = table_x[x].left_up * alpha[0];
736 scale[1] = (table_x[x].right_down * table_y[y].left_up >>16) * alpha[1];
737 scale[2] = (table_x[x].left_up * table_y[y].right_down >> 16) * alpha[2];
738 scale[3] = (table_x[x].right_down * table_y[y].right_down >> 16) * alpha[3];
739 spu->scaled_image[scaled] = (color[0] * scale[0] + color[1] * scale[1] + color[2] * scale[2] + color[3] * scale[3])>>24;
740 spu->scaled_aimage[scaled] = (scale[0] + scale[1] + scale[2] + scale[3]) >> 16;
741 if (spu->scaled_aimage[scaled]){
742 spu->scaled_aimage[scaled] = 256 - spu->scaled_aimage[scaled];
743 if(spu->scaled_aimage[scaled] + spu->scaled_image[scaled] > 255)
744 spu->scaled_image[scaled] = 256 - spu->scaled_aimage[scaled];
748 void sws_spu_image(unsigned char *d1, unsigned char *d2, int dw, int dh, int ds,
749 unsigned char *s1, unsigned char *s2, int sw, int sh, int ss)
751 struct SwsContext *ctx;
752 static SwsFilter filter;
753 static int firsttime = 1;
754 static float oldvar;
755 int i;
757 if (!firsttime && oldvar != spu_gaussvar) sws_freeVec(filter.lumH);
758 if (firsttime) {
759 filter.lumH = filter.lumV =
760 filter.chrH = filter.chrV = sws_getGaussianVec(spu_gaussvar, 3.0);
761 sws_normalizeVec(filter.lumH, 1.0);
762 firsttime = 0;
763 oldvar = spu_gaussvar;
766 ctx=sws_getContext(sw, sh, PIX_FMT_GRAY8, dw, dh, PIX_FMT_GRAY8, SWS_GAUSS, &filter, NULL, NULL);
767 sws_scale(ctx,&s1,&ss,0,sh,&d1,&ds);
768 for (i=ss*sh-1; i>=0; i--) if (!s2[i]) s2[i] = 255; //else s2[i] = 1;
769 sws_scale(ctx,&s2,&ss,0,sh,&d2,&ds);
770 for (i=ds*dh-1; i>=0; i--) if (d2[i]==0) d2[i] = 1; else if (d2[i]==255) d2[i] = 0;
771 sws_freeContext(ctx);
774 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))
776 spudec_handle_t *spu = (spudec_handle_t *)me;
777 scale_pixel *table_x;
778 scale_pixel *table_y;
780 if (spu->start_pts <= spu->now_pts && spu->now_pts < spu->end_pts) {
782 // check if only forced subtitles are requested
783 if( (spu->forced_subs_only) && !(spu->is_forced_sub) ){
784 return;
787 if (!(spu_aamode&16) && (spu->orig_frame_width == 0 || spu->orig_frame_height == 0
788 || (spu->orig_frame_width == dxs && spu->orig_frame_height == dys))) {
789 if (spu->image)
791 draw_alpha(spu->start_col, spu->start_row, spu->width, spu->height,
792 spu->image, spu->aimage, spu->stride);
793 spu->spu_changed = 0;
796 else {
797 if (spu->scaled_frame_width != dxs || spu->scaled_frame_height != dys) { /* Resizing is needed */
798 /* scaled_x = scalex * x / 0x100
799 scaled_y = scaley * y / 0x100
800 order of operations is important because of rounding. */
801 unsigned int scalex = 0x100 * dxs / spu->orig_frame_width;
802 unsigned int scaley = 0x100 * dys / spu->orig_frame_height;
803 spu->scaled_start_col = spu->start_col * scalex / 0x100;
804 spu->scaled_start_row = spu->start_row * scaley / 0x100;
805 spu->scaled_width = spu->width * scalex / 0x100;
806 spu->scaled_height = spu->height * scaley / 0x100;
807 /* Kludge: draw_alpha needs width multiple of 8 */
808 spu->scaled_stride = (spu->scaled_width + 7) & ~7;
809 if (spu->scaled_image_size < spu->scaled_stride * spu->scaled_height) {
810 if (spu->scaled_image) {
811 free(spu->scaled_image);
812 spu->scaled_image_size = 0;
814 spu->scaled_image = malloc(2 * spu->scaled_stride * spu->scaled_height);
815 if (spu->scaled_image) {
816 spu->scaled_image_size = spu->scaled_stride * spu->scaled_height;
817 spu->scaled_aimage = spu->scaled_image + spu->scaled_image_size;
820 if (spu->scaled_image) {
821 unsigned int x, y;
822 if (spu->scaled_width <= 1 || spu->scaled_height <= 1) {
823 goto nothing_to_do;
825 switch(spu_aamode&15) {
826 case 4:
827 sws_spu_image(spu->scaled_image, spu->scaled_aimage,
828 spu->scaled_width, spu->scaled_height, spu->scaled_stride,
829 spu->image, spu->aimage, spu->width, spu->height, spu->stride);
830 break;
831 case 3:
832 table_x = calloc(spu->scaled_width, sizeof(scale_pixel));
833 table_y = calloc(spu->scaled_height, sizeof(scale_pixel));
834 if (!table_x || !table_y) {
835 mp_msg(MSGT_SPUDEC, MSGL_FATAL, "Fatal: spudec_draw_scaled: calloc failed\n");
837 scale_table(0, 0, spu->width - 1, spu->scaled_width - 1, table_x);
838 scale_table(0, 0, spu->height - 1, spu->scaled_height - 1, table_y);
839 for (y = 0; y < spu->scaled_height; y++)
840 for (x = 0; x < spu->scaled_width; x++)
841 scale_image(x, y, table_x, table_y, spu);
842 free(table_x);
843 free(table_y);
844 break;
845 case 0:
846 /* no antialiasing */
847 for (y = 0; y < spu->scaled_height; ++y) {
848 int unscaled_y = y * 0x100 / scaley;
849 int strides = spu->stride * unscaled_y;
850 int scaled_strides = spu->scaled_stride * y;
851 for (x = 0; x < spu->scaled_width; ++x) {
852 int unscaled_x = x * 0x100 / scalex;
853 spu->scaled_image[scaled_strides + x] = spu->image[strides + unscaled_x];
854 spu->scaled_aimage[scaled_strides + x] = spu->aimage[strides + unscaled_x];
857 break;
858 case 1:
860 /* Intermediate antialiasing. */
861 for (y = 0; y < spu->scaled_height; ++y) {
862 const unsigned int unscaled_top = y * spu->orig_frame_height / dys;
863 unsigned int unscaled_bottom = (y + 1) * spu->orig_frame_height / dys;
864 if (unscaled_bottom >= spu->height)
865 unscaled_bottom = spu->height - 1;
866 for (x = 0; x < spu->scaled_width; ++x) {
867 const unsigned int unscaled_left = x * spu->orig_frame_width / dxs;
868 unsigned int unscaled_right = (x + 1) * spu->orig_frame_width / dxs;
869 unsigned int color = 0;
870 unsigned int alpha = 0;
871 unsigned int walkx, walky;
872 unsigned int base, tmp;
873 if (unscaled_right >= spu->width)
874 unscaled_right = spu->width - 1;
875 for (walky = unscaled_top; walky <= unscaled_bottom; ++walky)
876 for (walkx = unscaled_left; walkx <= unscaled_right; ++walkx) {
877 base = walky * spu->stride + walkx;
878 tmp = canon_alpha(spu->aimage[base]);
879 alpha += tmp;
880 color += tmp * spu->image[base];
882 base = y * spu->scaled_stride + x;
883 spu->scaled_image[base] = alpha ? color / alpha : 0;
884 spu->scaled_aimage[base] =
885 alpha * (1 + unscaled_bottom - unscaled_top) * (1 + unscaled_right - unscaled_left);
886 /* spu->scaled_aimage[base] =
887 alpha * dxs * dys / spu->orig_frame_width / spu->orig_frame_height; */
888 if (spu->scaled_aimage[base]) {
889 spu->scaled_aimage[base] = 256 - spu->scaled_aimage[base];
890 if (spu->scaled_aimage[base] + spu->scaled_image[base] > 255)
891 spu->scaled_image[base] = 256 - spu->scaled_aimage[base];
896 break;
897 case 2:
899 /* Best antialiasing. Very slow. */
900 /* Any pixel (x, y) represents pixels from the original
901 rectangular region comprised between the columns
902 unscaled_y and unscaled_y + 0x100 / scaley and the rows
903 unscaled_x and unscaled_x + 0x100 / scalex
905 The original rectangular region that the scaled pixel
906 represents is cut in 9 rectangular areas like this:
908 +---+-----------------+---+
909 | 1 | 2 | 3 |
910 +---+-----------------+---+
911 | | | |
912 | 4 | 5 | 6 |
913 | | | |
914 +---+-----------------+---+
915 | 7 | 8 | 9 |
916 +---+-----------------+---+
918 The width of the left column is at most one pixel and
919 it is never null and its right column is at a pixel
920 boundary. The height of the top row is at most one
921 pixel it is never null and its bottom row is at a
922 pixel boundary. The width and height of region 5 are
923 integral values. The width of the right column is
924 what remains and is less than one pixel. The height
925 of the bottom row is what remains and is less than
926 one pixel.
928 The row above 1, 2, 3 is unscaled_y. The row between
929 1, 2, 3 and 4, 5, 6 is top_low_row. The row between 4,
930 5, 6 and 7, 8, 9 is (unsigned int)unscaled_y_bottom.
931 The row beneath 7, 8, 9 is unscaled_y_bottom.
933 The column left of 1, 4, 7 is unscaled_x. The column
934 between 1, 4, 7 and 2, 5, 8 is left_right_column. The
935 column between 2, 5, 8 and 3, 6, 9 is (unsigned
936 int)unscaled_x_right. The column right of 3, 6, 9 is
937 unscaled_x_right. */
938 const double inv_scalex = (double) 0x100 / scalex;
939 const double inv_scaley = (double) 0x100 / scaley;
940 for (y = 0; y < spu->scaled_height; ++y) {
941 const double unscaled_y = y * inv_scaley;
942 const double unscaled_y_bottom = unscaled_y + inv_scaley;
943 const unsigned int top_low_row = FFMIN(unscaled_y_bottom, unscaled_y + 1.0);
944 const double top = top_low_row - unscaled_y;
945 const unsigned int height = unscaled_y_bottom > top_low_row
946 ? (unsigned int) unscaled_y_bottom - top_low_row
947 : 0;
948 const double bottom = unscaled_y_bottom > top_low_row
949 ? unscaled_y_bottom - floor(unscaled_y_bottom)
950 : 0.0;
951 for (x = 0; x < spu->scaled_width; ++x) {
952 const double unscaled_x = x * inv_scalex;
953 const double unscaled_x_right = unscaled_x + inv_scalex;
954 const unsigned int left_right_column = FFMIN(unscaled_x_right, unscaled_x + 1.0);
955 const double left = left_right_column - unscaled_x;
956 const unsigned int width = unscaled_x_right > left_right_column
957 ? (unsigned int) unscaled_x_right - left_right_column
958 : 0;
959 const double right = unscaled_x_right > left_right_column
960 ? unscaled_x_right - floor(unscaled_x_right)
961 : 0.0;
962 double color = 0.0;
963 double alpha = 0.0;
964 double tmp;
965 unsigned int base;
966 /* Now use these informations to compute a good alpha,
967 and lightness. The sum is on each of the 9
968 region's surface and alpha and lightness.
970 transformed alpha = sum(surface * alpha) / sum(surface)
971 transformed color = sum(surface * alpha * color) / sum(surface * alpha)
973 /* 1: top left part */
974 base = spu->stride * (unsigned int) unscaled_y;
975 tmp = left * top * canon_alpha(spu->aimage[base + (unsigned int) unscaled_x]);
976 alpha += tmp;
977 color += tmp * spu->image[base + (unsigned int) unscaled_x];
978 /* 2: top center part */
979 if (width > 0) {
980 unsigned int walkx;
981 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
982 base = spu->stride * (unsigned int) unscaled_y + walkx;
983 tmp = /* 1.0 * */ top * canon_alpha(spu->aimage[base]);
984 alpha += tmp;
985 color += tmp * spu->image[base];
988 /* 3: top right part */
989 if (right > 0.0) {
990 base = spu->stride * (unsigned int) unscaled_y + (unsigned int) unscaled_x_right;
991 tmp = right * top * canon_alpha(spu->aimage[base]);
992 alpha += tmp;
993 color += tmp * spu->image[base];
995 /* 4: center left part */
996 if (height > 0) {
997 unsigned int walky;
998 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
999 base = spu->stride * walky + (unsigned int) unscaled_x;
1000 tmp = left /* * 1.0 */ * canon_alpha(spu->aimage[base]);
1001 alpha += tmp;
1002 color += tmp * spu->image[base];
1005 /* 5: center part */
1006 if (width > 0 && height > 0) {
1007 unsigned int walky;
1008 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1009 unsigned int walkx;
1010 base = spu->stride * walky;
1011 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
1012 tmp = /* 1.0 * 1.0 * */ canon_alpha(spu->aimage[base + walkx]);
1013 alpha += tmp;
1014 color += tmp * spu->image[base + walkx];
1018 /* 6: center right part */
1019 if (right > 0.0 && height > 0) {
1020 unsigned int walky;
1021 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1022 base = spu->stride * walky + (unsigned int) unscaled_x_right;
1023 tmp = right /* * 1.0 */ * canon_alpha(spu->aimage[base]);
1024 alpha += tmp;
1025 color += tmp * spu->image[base];
1028 /* 7: bottom left part */
1029 if (bottom > 0.0) {
1030 base = spu->stride * (unsigned int) unscaled_y_bottom + (unsigned int) unscaled_x;
1031 tmp = left * bottom * canon_alpha(spu->aimage[base]);
1032 alpha += tmp;
1033 color += tmp * spu->image[base];
1035 /* 8: bottom center part */
1036 if (width > 0 && bottom > 0.0) {
1037 unsigned int walkx;
1038 base = spu->stride * (unsigned int) unscaled_y_bottom;
1039 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
1040 tmp = /* 1.0 * */ bottom * canon_alpha(spu->aimage[base + walkx]);
1041 alpha += tmp;
1042 color += tmp * spu->image[base + walkx];
1045 /* 9: bottom right part */
1046 if (right > 0.0 && bottom > 0.0) {
1047 base = spu->stride * (unsigned int) unscaled_y_bottom + (unsigned int) unscaled_x_right;
1048 tmp = right * bottom * canon_alpha(spu->aimage[base]);
1049 alpha += tmp;
1050 color += tmp * spu->image[base];
1052 /* Finally mix these transparency and brightness information suitably */
1053 base = spu->scaled_stride * y + x;
1054 spu->scaled_image[base] = alpha > 0 ? color / alpha : 0;
1055 spu->scaled_aimage[base] = alpha * scalex * scaley / 0x10000;
1056 if (spu->scaled_aimage[base]) {
1057 spu->scaled_aimage[base] = 256 - spu->scaled_aimage[base];
1058 if (spu->scaled_aimage[base] + spu->scaled_image[base] > 255)
1059 spu->scaled_image[base] = 256 - spu->scaled_aimage[base];
1065 nothing_to_do:
1066 /* Kludge: draw_alpha needs width multiple of 8. */
1067 if (spu->scaled_width < spu->scaled_stride)
1068 for (y = 0; y < spu->scaled_height; ++y) {
1069 memset(spu->scaled_aimage + y * spu->scaled_stride + spu->scaled_width, 0,
1070 spu->scaled_stride - spu->scaled_width);
1072 spu->scaled_frame_width = dxs;
1073 spu->scaled_frame_height = dys;
1076 if (spu->scaled_image){
1077 switch (spu_alignment) {
1078 case 0:
1079 spu->scaled_start_row = dys*sub_pos/100;
1080 if (spu->scaled_start_row + spu->scaled_height > dys)
1081 spu->scaled_start_row = dys - spu->scaled_height;
1082 break;
1083 case 1:
1084 spu->scaled_start_row = dys*sub_pos/100 - spu->scaled_height/2;
1085 if (sub_pos >= 50 && spu->scaled_start_row + spu->scaled_height > dys)
1086 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 break;
1092 draw_alpha(spu->scaled_start_col, spu->scaled_start_row, spu->scaled_width, spu->scaled_height,
1093 spu->scaled_image, spu->scaled_aimage, spu->scaled_stride);
1094 spu->spu_changed = 0;
1098 else
1100 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPU not displayed: start_pts=%d end_pts=%d now_pts=%d\n",
1101 spu->start_pts, spu->end_pts, spu->now_pts);
1105 void spudec_update_palette(void * this, unsigned int *palette)
1107 spudec_handle_t *spu = (spudec_handle_t *) this;
1108 if (spu && palette) {
1109 memcpy(spu->global_palette, palette, sizeof(spu->global_palette));
1110 if(spu->hw_spu)
1111 spu->hw_spu->control(VOCTRL_SET_SPU_PALETTE,spu->global_palette);
1115 void spudec_set_font_factor(void * this, double factor)
1117 spudec_handle_t *spu = (spudec_handle_t *) this;
1118 spu->font_start_level = (int)(0xF0-(0xE0*factor));
1121 void *spudec_new_scaled(unsigned int *palette, unsigned int frame_width, unsigned int frame_height)
1123 return spudec_new_scaled_vobsub(palette, NULL, 0, frame_width, frame_height);
1126 /* get palette custom color, width, height from .idx file */
1127 void *spudec_new_scaled_vobsub(unsigned int *palette, unsigned int *cuspal, unsigned int custom, unsigned int frame_width, unsigned int frame_height)
1129 spudec_handle_t *this = calloc(1, sizeof(spudec_handle_t));
1130 if (this){
1131 //(fprintf(stderr,"VobSub Custom Palette: %d,%d,%d,%d", this->cuspal[0], this->cuspal[1], this->cuspal[2],this->cuspal[3]);
1132 this->packet = NULL;
1133 this->image = NULL;
1134 this->scaled_image = NULL;
1135 /* XXX Although the video frame is some size, the SPU frame is
1136 always maximum size i.e. 720 wide and 576 or 480 high */
1137 this->orig_frame_width = 720;
1138 this->orig_frame_height = (frame_height == 480 || frame_height == 240) ? 480 : 576;
1139 this->custom = custom;
1140 // set up palette:
1141 this->auto_palette = 1;
1142 if (palette){
1143 memcpy(this->global_palette, palette, sizeof(this->global_palette));
1144 this->auto_palette = 0;
1146 this->custom = custom;
1147 if (custom && cuspal) {
1148 memcpy(this->cuspal, cuspal, sizeof(this->cuspal));
1149 this->auto_palette = 0;
1151 // forced subtitles default: show all subtitles
1152 this->forced_subs_only=0;
1153 this->is_forced_sub=0;
1155 else
1156 mp_msg(MSGT_SPUDEC,MSGL_FATAL, "FATAL: spudec_init: calloc");
1157 return this;
1160 void *spudec_new(unsigned int *palette)
1162 return spudec_new_scaled(palette, 0, 0);
1165 void spudec_free(void *this)
1167 spudec_handle_t *spu = (spudec_handle_t*)this;
1168 if (spu) {
1169 while (spu->queue_head)
1170 spudec_free_packet(spudec_dequeue_packet(spu));
1171 if (spu->packet)
1172 free(spu->packet);
1173 if (spu->scaled_image)
1174 free(spu->scaled_image);
1175 if (spu->image)
1176 free(spu->image);
1177 free(spu);
1181 void spudec_set_hw_spu(void *this, const vo_functions_t *hw_spu)
1183 spudec_handle_t *spu = (spudec_handle_t*)this;
1184 if (!spu)
1185 return;
1186 spu->hw_spu = hw_spu;
1187 hw_spu->control(VOCTRL_SET_SPU_PALETTE,spu->global_palette);