Cosmetics: Fix indentation after last commit.
[mplayer/glamo.git] / spudec.c
blob451269a2e3688d11db2316ad8b0251e52d045d5c
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 unsigned 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 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 (alpha[i] == 0)
235 cmap[i] = 0;
236 else if (this->custom){
237 cmap[i] = ((this->cuspal[i] >> 16) & 0xff);
238 if (cmap[i] + alpha[i] > 255)
239 cmap[i] = 256 - alpha[i];
241 else {
242 cmap[i] = ((this->global_palette[packet->palette[i]] >> 16) & 0xff);
243 if (cmap[i] + alpha[i] > 255)
244 cmap[i] = 256 - alpha[i];
248 if (this->image_size < this->stride * this->height) {
249 if (this->image != NULL) {
250 free(this->image);
251 this->image_size = 0;
253 this->image = malloc(2 * this->stride * this->height);
254 if (this->image) {
255 this->image_size = this->stride * this->height;
256 this->aimage = this->image + this->image_size;
259 if (this->image == NULL)
260 return;
262 /* Kludge: draw_alpha needs width multiple of 8. */
263 if (this->width < this->stride)
264 for (y = 0; y < this->height; ++y) {
265 memset(this->aimage + y * this->stride + this->width, 0, this->stride - this->width);
266 /* FIXME: Why is this one needed? */
267 memset(this->image + y * this->stride + this->width, 0, this->stride - this->width);
270 i = packet->current_nibble[1];
271 x = 0;
272 y = 0;
273 while (packet->current_nibble[0] < i
274 && packet->current_nibble[1] / 2 < packet->control_start
275 && y < this->height) {
276 unsigned int len, color;
277 unsigned int rle = 0;
278 rle = get_nibble(packet);
279 if (rle < 0x04) {
280 rle = (rle << 4) | get_nibble(packet);
281 if (rle < 0x10) {
282 rle = (rle << 4) | get_nibble(packet);
283 if (rle < 0x040) {
284 rle = (rle << 4) | get_nibble(packet);
285 if (rle < 0x0004)
286 rle |= ((this->width - x) << 2);
290 color = 3 - (rle & 0x3);
291 len = rle >> 2;
292 if (len > this->width - x || len == 0)
293 len = this->width - x;
294 /* FIXME have to use palette and alpha map*/
295 memset(this->image + y * this->stride + x, cmap[color], len);
296 memset(this->aimage + y * this->stride + x, alpha[color], len);
297 x += len;
298 if (x >= this->width) {
299 next_line(packet);
300 x = 0;
301 ++y;
304 spudec_cut_image(this);
309 This function tries to create a usable palette.
310 It determines how many non-transparent colors are used, and assigns different
311 gray scale values to each color.
312 I tested it with four streams and even got something readable. Half of the
313 times I got black characters with white around and half the reverse.
315 static void compute_palette(spudec_handle_t *this, packet_t *packet)
317 int used[16],i,cused,start,step,color;
319 memset(used, 0, sizeof(used));
320 for (i=0; i<4; i++)
321 if (packet->alpha[i]) /* !Transparent? */
322 used[packet->palette[i]] = 1;
323 for (cused=0, i=0; i<16; i++)
324 if (used[i]) cused++;
325 if (!cused) return;
326 if (cused == 1) {
327 start = 0x80;
328 step = 0;
329 } else {
330 start = this->font_start_level;
331 step = (0xF0-this->font_start_level)/(cused-1);
333 memset(used, 0, sizeof(used));
334 for (i=0; i<4; i++) {
335 color = packet->palette[i];
336 if (packet->alpha[i] && !used[color]) { /* not assigned? */
337 used[color] = 1;
338 this->global_palette[color] = start<<16;
339 start += step;
344 static void spudec_process_control(spudec_handle_t *this, unsigned int pts100)
346 int a,b; /* Temporary vars */
347 unsigned int date, type;
348 unsigned int off;
349 unsigned int start_off = 0;
350 unsigned int next_off;
351 unsigned int start_pts;
352 unsigned int end_pts;
353 unsigned int current_nibble[2];
354 unsigned int control_start;
355 unsigned int display = 0;
356 unsigned int start_col = 0;
357 unsigned int end_col = 0;
358 unsigned int start_row = 0;
359 unsigned int end_row = 0;
360 unsigned int width = 0;
361 unsigned int height = 0;
362 unsigned int stride = 0;
364 control_start = get_be16(this->packet + 2);
365 next_off = control_start;
366 while (start_off != next_off) {
367 start_off = next_off;
368 date = get_be16(this->packet + start_off) * 1024;
369 next_off = get_be16(this->packet + start_off + 2);
370 mp_msg(MSGT_SPUDEC,MSGL_DBG2, "date=%d\n", date);
371 off = start_off + 4;
372 for (type = this->packet[off++]; type != 0xff; type = this->packet[off++]) {
373 mp_msg(MSGT_SPUDEC,MSGL_DBG2, "cmd=%d ",type);
374 switch(type) {
375 case 0x00:
376 /* Menu ID, 1 byte */
377 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Menu ID\n");
378 /* shouldn't a Menu ID type force display start? */
379 start_pts = pts100 + date;
380 end_pts = UINT_MAX;
381 display = 1;
382 this->is_forced_sub=~0; // current subtitle is forced
383 break;
384 case 0x01:
385 /* Start display */
386 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Start display!\n");
387 start_pts = pts100 + date;
388 end_pts = UINT_MAX;
389 display = 1;
390 this->is_forced_sub=0;
391 break;
392 case 0x02:
393 /* Stop display */
394 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Stop display!\n");
395 end_pts = pts100 + date;
396 break;
397 case 0x03:
398 /* Palette */
399 this->palette[0] = this->packet[off] >> 4;
400 this->palette[1] = this->packet[off] & 0xf;
401 this->palette[2] = this->packet[off + 1] >> 4;
402 this->palette[3] = this->packet[off + 1] & 0xf;
403 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Palette %d, %d, %d, %d\n",
404 this->palette[0], this->palette[1], this->palette[2], this->palette[3]);
405 off+=2;
406 break;
407 case 0x04:
408 /* Alpha */
409 this->alpha[0] = this->packet[off] >> 4;
410 this->alpha[1] = this->packet[off] & 0xf;
411 this->alpha[2] = this->packet[off + 1] >> 4;
412 this->alpha[3] = this->packet[off + 1] & 0xf;
413 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Alpha %d, %d, %d, %d\n",
414 this->alpha[0], this->alpha[1], this->alpha[2], this->alpha[3]);
415 off+=2;
416 break;
417 case 0x05:
418 /* Co-ords */
419 a = get_be24(this->packet + off);
420 b = get_be24(this->packet + off + 3);
421 start_col = a >> 12;
422 end_col = a & 0xfff;
423 width = (end_col < start_col) ? 0 : end_col - start_col + 1;
424 stride = (width + 7) & ~7; /* Kludge: draw_alpha needs width multiple of 8 */
425 start_row = b >> 12;
426 end_row = b & 0xfff;
427 height = (end_row < start_row) ? 0 : end_row - start_row /* + 1 */;
428 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Coords col: %d - %d row: %d - %d (%dx%d)\n",
429 start_col, end_col, start_row, end_row,
430 width, height);
431 off+=6;
432 break;
433 case 0x06:
434 /* Graphic lines */
435 current_nibble[0] = 2 * get_be16(this->packet + off);
436 current_nibble[1] = 2 * get_be16(this->packet + off + 2);
437 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Graphic offset 1: %d offset 2: %d\n",
438 current_nibble[0] / 2, current_nibble[1] / 2);
439 off+=4;
440 break;
441 case 0xff:
442 /* All done, bye-bye */
443 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Done!\n");
444 return;
445 // break;
446 default:
447 mp_msg(MSGT_SPUDEC,MSGL_WARN,"spudec: Error determining control type 0x%02x. Skipping %d bytes.\n",
448 type, next_off - off);
449 goto next_control;
452 next_control:
453 if (display) {
454 packet_t *packet = calloc(1, sizeof(packet_t));
455 int i;
456 packet->start_pts = start_pts;
457 if (end_pts == UINT_MAX && start_off != next_off) {
458 start_pts = pts100 + get_be16(this->packet + next_off) * 1024;
459 packet->end_pts = start_pts - 1;
460 } else packet->end_pts = end_pts;
461 packet->current_nibble[0] = current_nibble[0];
462 packet->current_nibble[1] = current_nibble[1];
463 packet->start_row = start_row;
464 packet->end_row = end_row;
465 packet->start_col = start_col;
466 packet->end_col = end_col;
467 packet->width = width;
468 packet->height = height;
469 packet->stride = stride;
470 packet->control_start = control_start;
471 for (i=0; i<4; i++) {
472 packet->alpha[i] = this->alpha[i];
473 packet->palette[i] = this->palette[i];
475 packet->packet = malloc(this->packet_size);
476 memcpy(packet->packet, this->packet, this->packet_size);
477 spudec_queue_packet(this, packet);
482 static void spudec_decode(spudec_handle_t *this, unsigned int pts100)
484 if(this->hw_spu) {
485 static vo_mpegpes_t packet = { NULL, 0, 0x20, 0 };
486 static vo_mpegpes_t *pkg=&packet;
487 packet.data = this->packet;
488 packet.size = this->packet_size;
489 packet.timestamp = pts100;
490 this->hw_spu->draw_frame((uint8_t**)&pkg);
491 } else
492 spudec_process_control(this, pts100);
495 int spudec_changed(void * this)
497 spudec_handle_t * spu = (spudec_handle_t*)this;
498 return (spu->spu_changed || spu->now_pts > spu->end_pts);
501 void spudec_assemble(void *this, unsigned char *packet, unsigned int len, unsigned int pts100)
503 spudec_handle_t *spu = (spudec_handle_t*)this;
504 // spudec_heartbeat(this, pts100);
505 if (len < 2) {
506 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: packet too short\n");
507 return;
509 #if 0
510 if ((spu->packet_pts + 10000) < pts100) {
511 // [cb] too long since last fragment: force new packet
512 spu->packet_offset = 0;
514 #endif
515 spu->packet_pts = pts100;
516 if (spu->packet_offset == 0) {
517 unsigned int len2 = get_be16(packet);
518 // Start new fragment
519 if (spu->packet_reserve < len2) {
520 if (spu->packet != NULL)
521 free(spu->packet);
522 spu->packet = malloc(len2);
523 spu->packet_reserve = spu->packet != NULL ? len2 : 0;
525 if (spu->packet != NULL) {
526 spu->packet_size = len2;
527 if (len > len2) {
528 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: invalid frag len / len2: %d / %d \n", len, len2);
529 return;
531 memcpy(spu->packet, packet, len);
532 spu->packet_offset = len;
533 spu->packet_pts = pts100;
535 } else {
536 // Continue current fragment
537 if (spu->packet_size < spu->packet_offset + len){
538 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: invalid fragment\n");
539 spu->packet_size = spu->packet_offset = 0;
540 return;
541 } else {
542 memcpy(spu->packet + spu->packet_offset, packet, len);
543 spu->packet_offset += len;
546 #if 1
547 // check if we have a complete packet (unfortunatelly packet_size is bad
548 // for some disks)
549 // [cb] packet_size is padded to be even -> may be one byte too long
550 if ((spu->packet_offset == spu->packet_size) ||
551 ((spu->packet_offset + 1) == spu->packet_size)){
552 unsigned int x=0,y;
553 while(x+4<=spu->packet_offset){
554 y=get_be16(spu->packet+x+2); // next control pointer
555 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPUtest: x=%d y=%d off=%d size=%d\n",x,y,spu->packet_offset,spu->packet_size);
556 if(x>=4 && x==y){ // if it points to self - we're done!
557 // we got it!
558 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPUgot: off=%d size=%d \n",spu->packet_offset,spu->packet_size);
559 spudec_decode(spu, pts100);
560 spu->packet_offset = 0;
561 break;
563 if(y<=x || y>=spu->packet_size){ // invalid?
564 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUtest: broken packet!!!!! y=%d < x=%d\n",y,x);
565 spu->packet_size = spu->packet_offset = 0;
566 break;
568 x=y;
570 // [cb] packet is done; start new packet
571 spu->packet_offset = 0;
573 #else
574 if (spu->packet_offset == spu->packet_size) {
575 spudec_decode(spu, pts100);
576 spu->packet_offset = 0;
578 #endif
581 void spudec_reset(void *this) // called after seek
583 spudec_handle_t *spu = (spudec_handle_t*)this;
584 while (spu->queue_head)
585 spudec_free_packet(spudec_dequeue_packet(spu));
586 spu->now_pts = 0;
587 spu->end_pts = 0;
588 spu->packet_size = spu->packet_offset = 0;
591 void spudec_heartbeat(void *this, unsigned int pts100)
593 spudec_handle_t *spu = (spudec_handle_t*) this;
594 spu->now_pts = pts100;
596 while (spu->queue_head != NULL && pts100 >= spu->queue_head->start_pts) {
597 packet_t *packet = spudec_dequeue_packet(spu);
598 spu->start_pts = packet->start_pts;
599 spu->end_pts = packet->end_pts;
600 if (spu->auto_palette)
601 compute_palette(spu, packet);
602 spudec_process_data(spu, packet);
603 spudec_free_packet(packet);
604 spu->spu_changed = 1;
608 int spudec_visible(void *this){
609 spudec_handle_t *spu = (spudec_handle_t *)this;
610 int ret=(spu->start_pts <= spu->now_pts &&
611 spu->now_pts < spu->end_pts &&
612 spu->height > 0);
613 // printf("spu visible: %d \n",ret);
614 return ret;
617 void spudec_set_forced_subs_only(void * const this, const unsigned int flag)
619 if(this){
620 ((spudec_handle_t *)this)->forced_subs_only=flag;
621 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPU: Display only forced subs now %s\n", flag ? "enabled": "disabled");
625 void spudec_draw(void *this, void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride))
627 spudec_handle_t *spu = (spudec_handle_t *)this;
628 if (spu->start_pts <= spu->now_pts && spu->now_pts < spu->end_pts && spu->image)
630 draw_alpha(spu->start_col, spu->start_row, spu->width, spu->height,
631 spu->image, spu->aimage, spu->stride);
632 spu->spu_changed = 0;
636 /* calc the bbox for spudec subs */
637 void spudec_calc_bbox(void *me, unsigned int dxs, unsigned int dys, unsigned int* bbox)
639 spudec_handle_t *spu;
640 spu = (spudec_handle_t *)me;
641 if (spu->orig_frame_width == 0 || spu->orig_frame_height == 0
642 || (spu->orig_frame_width == dxs && spu->orig_frame_height == dys)) {
643 bbox[0] = spu->start_col;
644 bbox[1] = spu->start_col + spu->width;
645 bbox[2] = spu->start_row;
646 bbox[3] = spu->start_row + spu->height;
648 else if (spu->scaled_frame_width != dxs || spu->scaled_frame_height != dys) {
649 unsigned int scalex = 0x100 * dxs / spu->orig_frame_width;
650 unsigned int scaley = 0x100 * dys / spu->orig_frame_height;
651 bbox[0] = spu->start_col * scalex / 0x100;
652 bbox[1] = spu->start_col * scalex / 0x100 + spu->width * scalex / 0x100;
653 switch (spu_alignment) {
654 case 0:
655 bbox[3] = dys*sub_pos/100 + spu->height * scaley / 0x100;
656 if (bbox[3] > dys) bbox[3] = dys;
657 bbox[2] = bbox[3] - spu->height * scaley / 0x100;
658 break;
659 case 1:
660 if (sub_pos < 50) {
661 bbox[2] = dys*sub_pos/100 - spu->height * scaley / 0x200;
662 if (bbox[2] < 0) bbox[2] = 0;
663 bbox[3] = bbox[2] + spu->height;
664 } else {
665 bbox[3] = dys*sub_pos/100 + spu->height * scaley / 0x200;
666 if (bbox[3] > dys) bbox[3] = dys;
667 bbox[2] = bbox[3] - spu->height * scaley / 0x100;
669 break;
670 case 2:
671 bbox[2] = dys*sub_pos/100 - spu->height * scaley / 0x100;
672 if (bbox[2] < 0) bbox[2] = 0;
673 bbox[3] = bbox[2] + spu->height;
674 break;
675 default: /* -1 */
676 bbox[2] = spu->start_row * scaley / 0x100;
677 bbox[3] = spu->start_row * scaley / 0x100 + spu->height * scaley / 0x100;
678 break;
682 /* transform mplayer's alpha value into an opacity value that is linear */
683 static inline int canon_alpha(int alpha)
685 return alpha ? 256 - alpha : 0;
688 typedef struct {
689 unsigned position;
690 unsigned left_up;
691 unsigned right_down;
692 }scale_pixel;
695 static void scale_table(unsigned int start_src, unsigned int start_tar, unsigned int end_src, unsigned int end_tar, scale_pixel * table)
697 unsigned int t;
698 unsigned int delta_src = end_src - start_src;
699 unsigned int delta_tar = end_tar - start_tar;
700 int src = 0;
701 int src_step;
702 if (delta_src == 0 || delta_tar == 0) {
703 return;
705 src_step = (delta_src << 16) / delta_tar >>1;
706 for (t = 0; t<=delta_tar; src += (src_step << 1), t++){
707 table[t].position= FFMIN(src >> 16, end_src - 1);
708 table[t].right_down = src & 0xffff;
709 table[t].left_up = 0x10000 - table[t].right_down;
713 /* bilinear scale, similar to vobsub's code */
714 static void scale_image(int x, int y, scale_pixel* table_x, scale_pixel* table_y, spudec_handle_t * spu)
716 int alpha[4];
717 int color[4];
718 unsigned int scale[4];
719 int base = table_y[y].position * spu->stride + table_x[x].position;
720 int scaled = y * spu->scaled_stride + x;
721 alpha[0] = canon_alpha(spu->aimage[base]);
722 alpha[1] = canon_alpha(spu->aimage[base + 1]);
723 alpha[2] = canon_alpha(spu->aimage[base + spu->stride]);
724 alpha[3] = canon_alpha(spu->aimage[base + spu->stride + 1]);
725 color[0] = spu->image[base];
726 color[1] = spu->image[base + 1];
727 color[2] = spu->image[base + spu->stride];
728 color[3] = spu->image[base + spu->stride + 1];
729 scale[0] = (table_x[x].left_up * table_y[y].left_up >> 16) * alpha[0];
730 scale[1] = (table_x[x].right_down * table_y[y].left_up >>16) * alpha[1];
731 scale[2] = (table_x[x].left_up * table_y[y].right_down >> 16) * alpha[2];
732 scale[3] = (table_x[x].right_down * table_y[y].right_down >> 16) * alpha[3];
733 spu->scaled_image[scaled] = (color[0] * scale[0] + color[1] * scale[1] + color[2] * scale[2] + color[3] * scale[3])>>24;
734 spu->scaled_aimage[scaled] = (scale[0] + scale[1] + scale[2] + scale[3]) >> 16;
735 if (spu->scaled_aimage[scaled]){
736 spu->scaled_aimage[scaled] = 256 - spu->scaled_aimage[scaled];
737 if(spu->scaled_aimage[scaled] + spu->scaled_image[scaled] > 255)
738 spu->scaled_image[scaled] = 256 - spu->scaled_aimage[scaled];
742 void sws_spu_image(unsigned char *d1, unsigned char *d2, int dw, int dh, int ds,
743 unsigned char *s1, unsigned char *s2, int sw, int sh, int ss)
745 struct SwsContext *ctx;
746 static SwsFilter filter;
747 static int firsttime = 1;
748 static float oldvar;
749 int i;
751 if (!firsttime && oldvar != spu_gaussvar) sws_freeVec(filter.lumH);
752 if (firsttime) {
753 filter.lumH = filter.lumV =
754 filter.chrH = filter.chrV = sws_getGaussianVec(spu_gaussvar, 3.0);
755 sws_normalizeVec(filter.lumH, 1.0);
756 firsttime = 0;
757 oldvar = spu_gaussvar;
760 ctx=sws_getContext(sw, sh, PIX_FMT_GRAY8, dw, dh, PIX_FMT_GRAY8, SWS_GAUSS, &filter, NULL, NULL);
761 sws_scale(ctx,&s1,&ss,0,sh,&d1,&ds);
762 for (i=ss*sh-1; i>=0; i--) if (!s2[i]) s2[i] = 255; //else s2[i] = 1;
763 sws_scale(ctx,&s2,&ss,0,sh,&d2,&ds);
764 for (i=ds*dh-1; i>=0; i--) if (d2[i]==0) d2[i] = 1; else if (d2[i]==255) d2[i] = 0;
765 sws_freeContext(ctx);
768 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))
770 spudec_handle_t *spu = (spudec_handle_t *)me;
771 scale_pixel *table_x;
772 scale_pixel *table_y;
774 if (spu->start_pts <= spu->now_pts && spu->now_pts < spu->end_pts) {
776 // check if only forced subtitles are requested
777 if( (spu->forced_subs_only) && !(spu->is_forced_sub) ){
778 return;
781 if (!(spu_aamode&16) && (spu->orig_frame_width == 0 || spu->orig_frame_height == 0
782 || (spu->orig_frame_width == dxs && spu->orig_frame_height == dys))) {
783 if (spu->image)
785 draw_alpha(spu->start_col, spu->start_row, spu->width, spu->height,
786 spu->image, spu->aimage, spu->stride);
787 spu->spu_changed = 0;
790 else {
791 if (spu->scaled_frame_width != dxs || spu->scaled_frame_height != dys) { /* Resizing is needed */
792 /* scaled_x = scalex * x / 0x100
793 scaled_y = scaley * y / 0x100
794 order of operations is important because of rounding. */
795 unsigned int scalex = 0x100 * dxs / spu->orig_frame_width;
796 unsigned int scaley = 0x100 * dys / spu->orig_frame_height;
797 spu->scaled_start_col = spu->start_col * scalex / 0x100;
798 spu->scaled_start_row = spu->start_row * scaley / 0x100;
799 spu->scaled_width = spu->width * scalex / 0x100;
800 spu->scaled_height = spu->height * scaley / 0x100;
801 /* Kludge: draw_alpha needs width multiple of 8 */
802 spu->scaled_stride = (spu->scaled_width + 7) & ~7;
803 if (spu->scaled_image_size < spu->scaled_stride * spu->scaled_height) {
804 if (spu->scaled_image) {
805 free(spu->scaled_image);
806 spu->scaled_image_size = 0;
808 spu->scaled_image = malloc(2 * spu->scaled_stride * spu->scaled_height);
809 if (spu->scaled_image) {
810 spu->scaled_image_size = spu->scaled_stride * spu->scaled_height;
811 spu->scaled_aimage = spu->scaled_image + spu->scaled_image_size;
814 if (spu->scaled_image) {
815 unsigned int x, y;
816 if (spu->scaled_width <= 1 || spu->scaled_height <= 1) {
817 goto nothing_to_do;
819 switch(spu_aamode&15) {
820 case 4:
821 sws_spu_image(spu->scaled_image, spu->scaled_aimage,
822 spu->scaled_width, spu->scaled_height, spu->scaled_stride,
823 spu->image, spu->aimage, spu->width, spu->height, spu->stride);
824 break;
825 case 3:
826 table_x = calloc(spu->scaled_width, sizeof(scale_pixel));
827 table_y = calloc(spu->scaled_height, sizeof(scale_pixel));
828 if (!table_x || !table_y) {
829 mp_msg(MSGT_SPUDEC, MSGL_FATAL, "Fatal: spudec_draw_scaled: calloc failed\n");
831 scale_table(0, 0, spu->width - 1, spu->scaled_width - 1, table_x);
832 scale_table(0, 0, spu->height - 1, spu->scaled_height - 1, table_y);
833 for (y = 0; y < spu->scaled_height; y++)
834 for (x = 0; x < spu->scaled_width; x++)
835 scale_image(x, y, table_x, table_y, spu);
836 free(table_x);
837 free(table_y);
838 break;
839 case 0:
840 /* no antialiasing */
841 for (y = 0; y < spu->scaled_height; ++y) {
842 int unscaled_y = y * 0x100 / scaley;
843 int strides = spu->stride * unscaled_y;
844 int scaled_strides = spu->scaled_stride * y;
845 for (x = 0; x < spu->scaled_width; ++x) {
846 int unscaled_x = x * 0x100 / scalex;
847 spu->scaled_image[scaled_strides + x] = spu->image[strides + unscaled_x];
848 spu->scaled_aimage[scaled_strides + x] = spu->aimage[strides + unscaled_x];
851 break;
852 case 1:
854 /* Intermediate antialiasing. */
855 for (y = 0; y < spu->scaled_height; ++y) {
856 const unsigned int unscaled_top = y * spu->orig_frame_height / dys;
857 unsigned int unscaled_bottom = (y + 1) * spu->orig_frame_height / dys;
858 if (unscaled_bottom >= spu->height)
859 unscaled_bottom = spu->height - 1;
860 for (x = 0; x < spu->scaled_width; ++x) {
861 const unsigned int unscaled_left = x * spu->orig_frame_width / dxs;
862 unsigned int unscaled_right = (x + 1) * spu->orig_frame_width / dxs;
863 unsigned int color = 0;
864 unsigned int alpha = 0;
865 unsigned int walkx, walky;
866 unsigned int base, tmp;
867 if (unscaled_right >= spu->width)
868 unscaled_right = spu->width - 1;
869 for (walky = unscaled_top; walky <= unscaled_bottom; ++walky)
870 for (walkx = unscaled_left; walkx <= unscaled_right; ++walkx) {
871 base = walky * spu->stride + walkx;
872 tmp = canon_alpha(spu->aimage[base]);
873 alpha += tmp;
874 color += tmp * spu->image[base];
876 base = y * spu->scaled_stride + x;
877 spu->scaled_image[base] = alpha ? color / alpha : 0;
878 spu->scaled_aimage[base] =
879 alpha * (1 + unscaled_bottom - unscaled_top) * (1 + unscaled_right - unscaled_left);
880 /* spu->scaled_aimage[base] =
881 alpha * dxs * dys / spu->orig_frame_width / spu->orig_frame_height; */
882 if (spu->scaled_aimage[base]) {
883 spu->scaled_aimage[base] = 256 - spu->scaled_aimage[base];
884 if (spu->scaled_aimage[base] + spu->scaled_image[base] > 255)
885 spu->scaled_image[base] = 256 - spu->scaled_aimage[base];
890 break;
891 case 2:
893 /* Best antialiasing. Very slow. */
894 /* Any pixel (x, y) represents pixels from the original
895 rectangular region comprised between the columns
896 unscaled_y and unscaled_y + 0x100 / scaley and the rows
897 unscaled_x and unscaled_x + 0x100 / scalex
899 The original rectangular region that the scaled pixel
900 represents is cut in 9 rectangular areas like this:
902 +---+-----------------+---+
903 | 1 | 2 | 3 |
904 +---+-----------------+---+
905 | | | |
906 | 4 | 5 | 6 |
907 | | | |
908 +---+-----------------+---+
909 | 7 | 8 | 9 |
910 +---+-----------------+---+
912 The width of the left column is at most one pixel and
913 it is never null and its right column is at a pixel
914 boundary. The height of the top row is at most one
915 pixel it is never null and its bottom row is at a
916 pixel boundary. The width and height of region 5 are
917 integral values. The width of the right column is
918 what remains and is less than one pixel. The height
919 of the bottom row is what remains and is less than
920 one pixel.
922 The row above 1, 2, 3 is unscaled_y. The row between
923 1, 2, 3 and 4, 5, 6 is top_low_row. The row between 4,
924 5, 6 and 7, 8, 9 is (unsigned int)unscaled_y_bottom.
925 The row beneath 7, 8, 9 is unscaled_y_bottom.
927 The column left of 1, 4, 7 is unscaled_x. The column
928 between 1, 4, 7 and 2, 5, 8 is left_right_column. The
929 column between 2, 5, 8 and 3, 6, 9 is (unsigned
930 int)unscaled_x_right. The column right of 3, 6, 9 is
931 unscaled_x_right. */
932 const double inv_scalex = (double) 0x100 / scalex;
933 const double inv_scaley = (double) 0x100 / scaley;
934 for (y = 0; y < spu->scaled_height; ++y) {
935 const double unscaled_y = y * inv_scaley;
936 const double unscaled_y_bottom = unscaled_y + inv_scaley;
937 const unsigned int top_low_row = FFMIN(unscaled_y_bottom, unscaled_y + 1.0);
938 const double top = top_low_row - unscaled_y;
939 const unsigned int height = unscaled_y_bottom > top_low_row
940 ? (unsigned int) unscaled_y_bottom - top_low_row
941 : 0;
942 const double bottom = unscaled_y_bottom > top_low_row
943 ? unscaled_y_bottom - floor(unscaled_y_bottom)
944 : 0.0;
945 for (x = 0; x < spu->scaled_width; ++x) {
946 const double unscaled_x = x * inv_scalex;
947 const double unscaled_x_right = unscaled_x + inv_scalex;
948 const unsigned int left_right_column = FFMIN(unscaled_x_right, unscaled_x + 1.0);
949 const double left = left_right_column - unscaled_x;
950 const unsigned int width = unscaled_x_right > left_right_column
951 ? (unsigned int) unscaled_x_right - left_right_column
952 : 0;
953 const double right = unscaled_x_right > left_right_column
954 ? unscaled_x_right - floor(unscaled_x_right)
955 : 0.0;
956 double color = 0.0;
957 double alpha = 0.0;
958 double tmp;
959 unsigned int base;
960 /* Now use these informations to compute a good alpha,
961 and lightness. The sum is on each of the 9
962 region's surface and alpha and lightness.
964 transformed alpha = sum(surface * alpha) / sum(surface)
965 transformed color = sum(surface * alpha * color) / sum(surface * alpha)
967 /* 1: top left part */
968 base = spu->stride * (unsigned int) unscaled_y;
969 tmp = left * top * canon_alpha(spu->aimage[base + (unsigned int) unscaled_x]);
970 alpha += tmp;
971 color += tmp * spu->image[base + (unsigned int) unscaled_x];
972 /* 2: top center part */
973 if (width > 0) {
974 unsigned int walkx;
975 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
976 base = spu->stride * (unsigned int) unscaled_y + walkx;
977 tmp = /* 1.0 * */ top * canon_alpha(spu->aimage[base]);
978 alpha += tmp;
979 color += tmp * spu->image[base];
982 /* 3: top right part */
983 if (right > 0.0) {
984 base = spu->stride * (unsigned int) unscaled_y + (unsigned int) unscaled_x_right;
985 tmp = right * top * canon_alpha(spu->aimage[base]);
986 alpha += tmp;
987 color += tmp * spu->image[base];
989 /* 4: center left part */
990 if (height > 0) {
991 unsigned int walky;
992 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
993 base = spu->stride * walky + (unsigned int) unscaled_x;
994 tmp = left /* * 1.0 */ * canon_alpha(spu->aimage[base]);
995 alpha += tmp;
996 color += tmp * spu->image[base];
999 /* 5: center part */
1000 if (width > 0 && height > 0) {
1001 unsigned int walky;
1002 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1003 unsigned int walkx;
1004 base = spu->stride * walky;
1005 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
1006 tmp = /* 1.0 * 1.0 * */ canon_alpha(spu->aimage[base + walkx]);
1007 alpha += tmp;
1008 color += tmp * spu->image[base + walkx];
1012 /* 6: center right part */
1013 if (right > 0.0 && height > 0) {
1014 unsigned int walky;
1015 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1016 base = spu->stride * walky + (unsigned int) unscaled_x_right;
1017 tmp = right /* * 1.0 */ * canon_alpha(spu->aimage[base]);
1018 alpha += tmp;
1019 color += tmp * spu->image[base];
1022 /* 7: bottom left part */
1023 if (bottom > 0.0) {
1024 base = spu->stride * (unsigned int) unscaled_y_bottom + (unsigned int) unscaled_x;
1025 tmp = left * bottom * canon_alpha(spu->aimage[base]);
1026 alpha += tmp;
1027 color += tmp * spu->image[base];
1029 /* 8: bottom center part */
1030 if (width > 0 && bottom > 0.0) {
1031 unsigned int walkx;
1032 base = spu->stride * (unsigned int) unscaled_y_bottom;
1033 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
1034 tmp = /* 1.0 * */ bottom * canon_alpha(spu->aimage[base + walkx]);
1035 alpha += tmp;
1036 color += tmp * spu->image[base + walkx];
1039 /* 9: bottom right part */
1040 if (right > 0.0 && bottom > 0.0) {
1041 base = spu->stride * (unsigned int) unscaled_y_bottom + (unsigned int) unscaled_x_right;
1042 tmp = right * bottom * canon_alpha(spu->aimage[base]);
1043 alpha += tmp;
1044 color += tmp * spu->image[base];
1046 /* Finally mix these transparency and brightness information suitably */
1047 base = spu->scaled_stride * y + x;
1048 spu->scaled_image[base] = alpha > 0 ? color / alpha : 0;
1049 spu->scaled_aimage[base] = alpha * scalex * scaley / 0x10000;
1050 if (spu->scaled_aimage[base]) {
1051 spu->scaled_aimage[base] = 256 - spu->scaled_aimage[base];
1052 if (spu->scaled_aimage[base] + spu->scaled_image[base] > 255)
1053 spu->scaled_image[base] = 256 - spu->scaled_aimage[base];
1059 nothing_to_do:
1060 /* Kludge: draw_alpha needs width multiple of 8. */
1061 if (spu->scaled_width < spu->scaled_stride)
1062 for (y = 0; y < spu->scaled_height; ++y) {
1063 memset(spu->scaled_aimage + y * spu->scaled_stride + spu->scaled_width, 0,
1064 spu->scaled_stride - spu->scaled_width);
1066 spu->scaled_frame_width = dxs;
1067 spu->scaled_frame_height = dys;
1070 if (spu->scaled_image){
1071 switch (spu_alignment) {
1072 case 0:
1073 spu->scaled_start_row = dys*sub_pos/100;
1074 if (spu->scaled_start_row + spu->scaled_height > dys)
1075 spu->scaled_start_row = dys - spu->scaled_height;
1076 break;
1077 case 1:
1078 spu->scaled_start_row = dys*sub_pos/100 - spu->scaled_height/2;
1079 if (sub_pos < 50) {
1080 if (spu->scaled_start_row < 0) spu->scaled_start_row = 0;
1081 } else {
1082 if (spu->scaled_start_row + spu->scaled_height > dys)
1083 spu->scaled_start_row = dys - spu->scaled_height;
1085 break;
1086 case 2:
1087 spu->scaled_start_row = dys*sub_pos/100 - spu->scaled_height;
1088 if (spu->scaled_start_row < 0) spu->scaled_start_row = 0;
1089 break;
1091 draw_alpha(spu->scaled_start_col, spu->scaled_start_row, spu->scaled_width, spu->scaled_height,
1092 spu->scaled_image, spu->scaled_aimage, spu->scaled_stride);
1093 spu->spu_changed = 0;
1097 else
1099 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPU not displayed: start_pts=%d end_pts=%d now_pts=%d\n",
1100 spu->start_pts, spu->end_pts, spu->now_pts);
1104 void spudec_update_palette(void * this, unsigned int *palette)
1106 spudec_handle_t *spu = (spudec_handle_t *) this;
1107 if (spu && palette) {
1108 memcpy(spu->global_palette, palette, sizeof(spu->global_palette));
1109 if(spu->hw_spu)
1110 spu->hw_spu->control(VOCTRL_SET_SPU_PALETTE,spu->global_palette);
1114 void spudec_set_font_factor(void * this, double factor)
1116 spudec_handle_t *spu = (spudec_handle_t *) this;
1117 spu->font_start_level = (int)(0xF0-(0xE0*factor));
1120 void *spudec_new_scaled(unsigned int *palette, unsigned int frame_width, unsigned int frame_height)
1122 return spudec_new_scaled_vobsub(palette, NULL, 0, frame_width, frame_height);
1125 /* get palette custom color, width, height from .idx file */
1126 void *spudec_new_scaled_vobsub(unsigned int *palette, unsigned int *cuspal, unsigned int custom, unsigned int frame_width, unsigned int frame_height)
1128 spudec_handle_t *this = calloc(1, sizeof(spudec_handle_t));
1129 if (this){
1130 //(fprintf(stderr,"VobSub Custom Palette: %d,%d,%d,%d", this->cuspal[0], this->cuspal[1], this->cuspal[2],this->cuspal[3]);
1131 this->packet = NULL;
1132 this->image = NULL;
1133 this->scaled_image = NULL;
1134 /* XXX Although the video frame is some size, the SPU frame is
1135 always maximum size i.e. 720 wide and 576 or 480 high */
1136 this->orig_frame_width = 720;
1137 this->orig_frame_height = (frame_height == 480 || frame_height == 240) ? 480 : 576;
1138 this->custom = custom;
1139 // set up palette:
1140 this->auto_palette = 1;
1141 if (palette){
1142 memcpy(this->global_palette, palette, sizeof(this->global_palette));
1143 this->auto_palette = 0;
1145 this->custom = custom;
1146 if (custom && cuspal) {
1147 memcpy(this->cuspal, cuspal, sizeof(this->cuspal));
1148 this->auto_palette = 0;
1150 // forced subtitles default: show all subtitles
1151 this->forced_subs_only=0;
1152 this->is_forced_sub=0;
1154 else
1155 mp_msg(MSGT_SPUDEC,MSGL_FATAL, "FATAL: spudec_init: calloc");
1156 return this;
1159 void *spudec_new(unsigned int *palette)
1161 return spudec_new_scaled(palette, 0, 0);
1164 void spudec_free(void *this)
1166 spudec_handle_t *spu = (spudec_handle_t*)this;
1167 if (spu) {
1168 while (spu->queue_head)
1169 spudec_free_packet(spudec_dequeue_packet(spu));
1170 if (spu->packet)
1171 free(spu->packet);
1172 if (spu->scaled_image)
1173 free(spu->scaled_image);
1174 if (spu->image)
1175 free(spu->image);
1176 free(spu);
1180 void spudec_set_hw_spu(void *this, vo_functions_t *hw_spu)
1182 spudec_handle_t *spu = (spudec_handle_t*)this;
1183 if (!spu)
1184 return;
1185 spu->hw_spu = hw_spu;
1186 hw_spu->control(VOCTRL_SET_SPU_PALETTE,spu->global_palette);