Changed code that used pts=0 in demux packets to indicate "not known".
[mplayer.git] / spudec.c
blobf5eb20f7862865ab7e0b2f6051fae5f1a4ac11f0
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 #include "avutil.h"
27 #include "libswscale/swscale.h"
29 #define MIN(a, b) ((a)<(b)?(a):(b))
31 /* Valid values for spu_aamode:
32 0: none (fastest, most ugly)
33 1: approximate
34 2: full (slowest)
35 3: bilinear (similiar to vobsub, fast and not too bad)
36 4: uses swscaler gaussian (this is the only one that looks good)
39 int spu_aamode = 3;
40 int spu_alignment = -1;
41 float spu_gaussvar = 1.0;
42 extern int sub_pos;
44 typedef struct packet_t packet_t;
45 struct packet_t {
46 unsigned char *packet;
47 unsigned int palette[4];
48 unsigned int alpha[4];
49 unsigned int control_start; /* index of start of control data */
50 unsigned int current_nibble[2]; /* next data nibble (4 bits) to be
51 processed (for RLE decoding) for
52 even and odd lines */
53 int deinterlace_oddness; /* 0 or 1, index into current_nibble */
54 unsigned int start_col, end_col;
55 unsigned int start_row, end_row;
56 unsigned int width, height, stride;
57 unsigned int start_pts, end_pts;
58 packet_t *next;
61 typedef struct {
62 packet_t *queue_head;
63 packet_t *queue_tail;
64 unsigned int global_palette[16];
65 unsigned int orig_frame_width, orig_frame_height;
66 unsigned char* packet;
67 size_t packet_reserve; /* size of the memory pointed to by packet */
68 unsigned int packet_offset; /* end of the currently assembled fragment */
69 unsigned int packet_size; /* size of the packet once all fragments are assembled */
70 unsigned int packet_pts; /* PTS for this packet */
71 unsigned int palette[4];
72 unsigned int alpha[4];
73 unsigned int cuspal[4];
74 unsigned int custom;
75 unsigned int now_pts;
76 unsigned int start_pts, end_pts;
77 unsigned int start_col, end_col;
78 unsigned int start_row, end_row;
79 unsigned int width, height, stride;
80 size_t image_size; /* Size of the image buffer */
81 unsigned char *image; /* Grayscale value */
82 unsigned char *aimage; /* Alpha value */
83 unsigned int scaled_frame_width, scaled_frame_height;
84 unsigned int scaled_start_col, scaled_start_row;
85 unsigned int scaled_width, scaled_height, scaled_stride;
86 size_t scaled_image_size;
87 unsigned char *scaled_image;
88 unsigned char *scaled_aimage;
89 int auto_palette; /* 1 if we lack a palette and must use an heuristic. */
90 int font_start_level; /* Darkest value used for the computed font */
91 vo_functions_t *hw_spu;
92 int spu_changed;
93 unsigned int forced_subs_only; /* flag: 0=display all subtitle, !0 display only forced subtitles */
94 unsigned int is_forced_sub; /* true if current subtitle is a forced subtitle */
95 } spudec_handle_t;
97 static void spudec_queue_packet(spudec_handle_t *this, packet_t *packet)
99 if (this->queue_head == NULL)
100 this->queue_head = packet;
101 else
102 this->queue_tail->next = packet;
103 this->queue_tail = packet;
106 static packet_t *spudec_dequeue_packet(spudec_handle_t *this)
108 packet_t *retval = this->queue_head;
110 this->queue_head = retval->next;
111 if (this->queue_head == NULL)
112 this->queue_tail = NULL;
114 return retval;
117 static void spudec_free_packet(packet_t *packet)
119 if (packet->packet != NULL)
120 free(packet->packet);
121 free(packet);
124 static inline unsigned int get_be16(const unsigned char *p)
126 return (p[0] << 8) + p[1];
129 static inline unsigned int get_be24(const unsigned char *p)
131 return (get_be16(p) << 8) + p[2];
134 static void next_line(packet_t *packet)
136 if (packet->current_nibble[packet->deinterlace_oddness] % 2)
137 packet->current_nibble[packet->deinterlace_oddness]++;
138 packet->deinterlace_oddness = (packet->deinterlace_oddness + 1) % 2;
141 static inline unsigned char get_nibble(packet_t *packet)
143 unsigned char nib;
144 unsigned int *nibblep = packet->current_nibble + packet->deinterlace_oddness;
145 if (*nibblep / 2 >= packet->control_start) {
146 mp_msg(MSGT_SPUDEC,MSGL_WARN, "SPUdec: ERROR: get_nibble past end of packet\n");
147 return 0;
149 nib = packet->packet[*nibblep / 2];
150 if (*nibblep % 2)
151 nib &= 0xf;
152 else
153 nib >>= 4;
154 ++*nibblep;
155 return nib;
158 static inline int mkalpha(int i)
160 /* In mplayer's alpha planes, 0 is transparent, then 1 is nearly
161 opaque upto 255 which is transparent */
162 switch (i) {
163 case 0xf:
164 return 1;
165 case 0:
166 return 0;
167 default:
168 return (0xf - i) << 4;
172 /* Cut the sub to visible part */
173 static inline void spudec_cut_image(spudec_handle_t *this)
175 unsigned int fy, ly;
176 unsigned int first_y, last_y;
177 unsigned char *image;
178 unsigned char *aimage;
180 if (this->stride == 0 || this->height == 0) {
181 return;
184 for (fy = 0; fy < this->image_size && !this->aimage[fy]; fy++);
185 for (ly = this->stride * this->height-1; ly && !this->aimage[ly]; ly--);
186 first_y = fy / this->stride;
187 last_y = ly / this->stride;
188 //printf("first_y: %d, last_y: %d\n", first_y, last_y);
189 this->start_row += first_y;
191 // Some subtitles trigger this condition
192 if (last_y + 1 > first_y ) {
193 this->height = last_y - first_y +1;
194 } else {
195 this->height = 0;
196 this->image_size = 0;
197 return;
200 // printf("new h %d new start %d (sz %d st %d)---\n\n", this->height, this->start_row, this->image_size, this->stride);
202 image = malloc(2 * this->stride * this->height);
203 if(image){
204 this->image_size = this->stride * this->height;
205 aimage = image + this->image_size;
206 memcpy(image, this->image + this->stride * first_y, this->image_size);
207 memcpy(aimage, this->aimage + this->stride * first_y, this->image_size);
208 free(this->image);
209 this->image = image;
210 this->aimage = aimage;
211 } else {
212 mp_msg(MSGT_SPUDEC, MSGL_FATAL, "Fatal: update_spu: malloc requested %d bytes\n", 2 * this->stride * this->height);
216 static void spudec_process_data(spudec_handle_t *this, packet_t *packet)
218 unsigned int cmap[4], alpha[4];
219 unsigned int i, x, y;
221 this->scaled_frame_width = 0;
222 this->scaled_frame_height = 0;
223 this->start_col = packet->start_col;
224 this->end_col = packet->end_col;
225 this->start_row = packet->start_row;
226 this->end_row = packet->end_row;
227 this->height = packet->height;
228 this->width = packet->width;
229 this->stride = packet->stride;
230 for (i = 0; i < 4; ++i) {
231 alpha[i] = mkalpha(packet->alpha[i]);
232 if (alpha[i] == 0)
233 cmap[i] = 0;
234 else if (this->custom){
235 cmap[i] = ((this->cuspal[i] >> 16) & 0xff);
236 if (cmap[i] + alpha[i] > 255)
237 cmap[i] = 256 - alpha[i];
239 else {
240 cmap[i] = ((this->global_palette[packet->palette[i]] >> 16) & 0xff);
241 if (cmap[i] + alpha[i] > 255)
242 cmap[i] = 256 - alpha[i];
246 if (this->image_size < this->stride * this->height) {
247 if (this->image != NULL) {
248 free(this->image);
249 this->image_size = 0;
251 this->image = malloc(2 * this->stride * this->height);
252 if (this->image) {
253 this->image_size = this->stride * this->height;
254 this->aimage = this->image + this->image_size;
257 if (this->image == NULL)
258 return;
260 /* Kludge: draw_alpha needs width multiple of 8. */
261 if (this->width < this->stride)
262 for (y = 0; y < this->height; ++y) {
263 memset(this->aimage + y * this->stride + this->width, 0, this->stride - this->width);
264 /* FIXME: Why is this one needed? */
265 memset(this->image + y * this->stride + this->width, 0, this->stride - this->width);
268 i = packet->current_nibble[1];
269 x = 0;
270 y = 0;
271 while (packet->current_nibble[0] < i
272 && packet->current_nibble[1] / 2 < packet->control_start
273 && y < this->height) {
274 unsigned int len, color;
275 unsigned int rle = 0;
276 rle = get_nibble(packet);
277 if (rle < 0x04) {
278 rle = (rle << 4) | get_nibble(packet);
279 if (rle < 0x10) {
280 rle = (rle << 4) | get_nibble(packet);
281 if (rle < 0x040) {
282 rle = (rle << 4) | get_nibble(packet);
283 if (rle < 0x0004)
284 rle |= ((this->width - x) << 2);
288 color = 3 - (rle & 0x3);
289 len = rle >> 2;
290 if (len > this->width - x || len == 0)
291 len = this->width - x;
292 /* FIXME have to use palette and alpha map*/
293 memset(this->image + y * this->stride + x, cmap[color], len);
294 memset(this->aimage + y * this->stride + x, alpha[color], len);
295 x += len;
296 if (x >= this->width) {
297 next_line(packet);
298 x = 0;
299 ++y;
302 spudec_cut_image(this);
307 This function tries to create a usable palette.
308 It determines how many non-transparent colors are used, and assigns different
309 gray scale values to each color.
310 I tested it with four streams and even got something readable. Half of the
311 times I got black characters with white around and half the reverse.
313 static void compute_palette(spudec_handle_t *this, packet_t *packet)
315 int used[16],i,cused,start,step,color;
317 memset(used, 0, sizeof(used));
318 for (i=0; i<4; i++)
319 if (packet->alpha[i]) /* !Transparent? */
320 used[packet->palette[i]] = 1;
321 for (cused=0, i=0; i<16; i++)
322 if (used[i]) cused++;
323 if (!cused) return;
324 if (cused == 1) {
325 start = 0x80;
326 step = 0;
327 } else {
328 start = this->font_start_level;
329 step = (0xF0-this->font_start_level)/(cused-1);
331 memset(used, 0, sizeof(used));
332 for (i=0; i<4; i++) {
333 color = packet->palette[i];
334 if (packet->alpha[i] && !used[color]) { /* not assigned? */
335 used[color] = 1;
336 this->global_palette[color] = start<<16;
337 start += step;
342 static void spudec_process_control(spudec_handle_t *this, unsigned int pts100)
344 int a,b; /* Temporary vars */
345 unsigned int date, type;
346 unsigned int off;
347 unsigned int start_off = 0;
348 unsigned int next_off;
349 unsigned int start_pts;
350 unsigned int end_pts;
351 unsigned int current_nibble[2];
352 unsigned int control_start;
353 unsigned int display = 0;
354 unsigned int start_col = 0;
355 unsigned int end_col = 0;
356 unsigned int start_row = 0;
357 unsigned int end_row = 0;
358 unsigned int width = 0;
359 unsigned int height = 0;
360 unsigned int stride = 0;
362 control_start = get_be16(this->packet + 2);
363 next_off = control_start;
364 while (start_off != next_off) {
365 start_off = next_off;
366 date = get_be16(this->packet + start_off) * 1024;
367 next_off = get_be16(this->packet + start_off + 2);
368 mp_msg(MSGT_SPUDEC,MSGL_DBG2, "date=%d\n", date);
369 off = start_off + 4;
370 for (type = this->packet[off++]; type != 0xff; type = this->packet[off++]) {
371 mp_msg(MSGT_SPUDEC,MSGL_DBG2, "cmd=%d ",type);
372 switch(type) {
373 case 0x00:
374 /* Menu ID, 1 byte */
375 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Menu ID\n");
376 /* shouldn't a Menu ID type force display start? */
377 start_pts = pts100 + date;
378 end_pts = UINT_MAX;
379 display = 1;
380 this->is_forced_sub=~0; // current subtitle is forced
381 break;
382 case 0x01:
383 /* Start display */
384 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Start display!\n");
385 start_pts = pts100 + date;
386 end_pts = UINT_MAX;
387 display = 1;
388 this->is_forced_sub=0;
389 break;
390 case 0x02:
391 /* Stop display */
392 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Stop display!\n");
393 end_pts = pts100 + date;
394 break;
395 case 0x03:
396 /* Palette */
397 this->palette[0] = this->packet[off] >> 4;
398 this->palette[1] = this->packet[off] & 0xf;
399 this->palette[2] = this->packet[off + 1] >> 4;
400 this->palette[3] = this->packet[off + 1] & 0xf;
401 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Palette %d, %d, %d, %d\n",
402 this->palette[0], this->palette[1], this->palette[2], this->palette[3]);
403 off+=2;
404 break;
405 case 0x04:
406 /* Alpha */
407 this->alpha[0] = this->packet[off] >> 4;
408 this->alpha[1] = this->packet[off] & 0xf;
409 this->alpha[2] = this->packet[off + 1] >> 4;
410 this->alpha[3] = this->packet[off + 1] & 0xf;
411 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Alpha %d, %d, %d, %d\n",
412 this->alpha[0], this->alpha[1], this->alpha[2], this->alpha[3]);
413 off+=2;
414 break;
415 case 0x05:
416 /* Co-ords */
417 a = get_be24(this->packet + off);
418 b = get_be24(this->packet + off + 3);
419 start_col = a >> 12;
420 end_col = a & 0xfff;
421 width = (end_col < start_col) ? 0 : end_col - start_col + 1;
422 stride = (width + 7) & ~7; /* Kludge: draw_alpha needs width multiple of 8 */
423 start_row = b >> 12;
424 end_row = b & 0xfff;
425 height = (end_row < start_row) ? 0 : end_row - start_row /* + 1 */;
426 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Coords col: %d - %d row: %d - %d (%dx%d)\n",
427 start_col, end_col, start_row, end_row,
428 width, height);
429 off+=6;
430 break;
431 case 0x06:
432 /* Graphic lines */
433 current_nibble[0] = 2 * get_be16(this->packet + off);
434 current_nibble[1] = 2 * get_be16(this->packet + off + 2);
435 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Graphic offset 1: %d offset 2: %d\n",
436 current_nibble[0] / 2, current_nibble[1] / 2);
437 off+=4;
438 break;
439 case 0xff:
440 /* All done, bye-bye */
441 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Done!\n");
442 return;
443 // break;
444 default:
445 mp_msg(MSGT_SPUDEC,MSGL_WARN,"spudec: Error determining control type 0x%02x. Skipping %d bytes.\n",
446 type, next_off - off);
447 goto next_control;
450 next_control:
451 if (display) {
452 packet_t *packet = calloc(1, sizeof(packet_t));
453 int i;
454 packet->start_pts = start_pts;
455 if (end_pts == UINT_MAX && start_off != next_off) {
456 start_pts = pts100 + get_be16(this->packet + next_off) * 1024;
457 packet->end_pts = start_pts - 1;
458 } else packet->end_pts = end_pts;
459 packet->current_nibble[0] = current_nibble[0];
460 packet->current_nibble[1] = current_nibble[1];
461 packet->start_row = start_row;
462 packet->end_row = end_row;
463 packet->start_col = start_col;
464 packet->end_col = end_col;
465 packet->width = width;
466 packet->height = height;
467 packet->stride = stride;
468 packet->control_start = control_start;
469 for (i=0; i<4; i++) {
470 packet->alpha[i] = this->alpha[i];
471 packet->palette[i] = this->palette[i];
473 packet->packet = malloc(this->packet_size);
474 memcpy(packet->packet, this->packet, this->packet_size);
475 spudec_queue_packet(this, packet);
480 static void spudec_decode(spudec_handle_t *this, unsigned int pts100)
482 if(this->hw_spu) {
483 static vo_mpegpes_t packet = { NULL, 0, 0x20, 0 };
484 static vo_mpegpes_t *pkg=&packet;
485 packet.data = this->packet;
486 packet.size = this->packet_size;
487 packet.timestamp = pts100;
488 this->hw_spu->draw_frame((uint8_t**)&pkg);
489 } else
490 spudec_process_control(this, pts100);
493 int spudec_changed(void * this)
495 spudec_handle_t * spu = (spudec_handle_t*)this;
496 return (spu->spu_changed || spu->now_pts > spu->end_pts);
499 void spudec_assemble(void *this, unsigned char *packet, unsigned int len, unsigned int pts100)
501 spudec_handle_t *spu = (spudec_handle_t*)this;
502 // spudec_heartbeat(this, pts100);
503 if (len < 2) {
504 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: packet too short\n");
505 return;
507 #if 0
508 if ((spu->packet_pts + 10000) < pts100) {
509 // [cb] too long since last fragment: force new packet
510 spu->packet_offset = 0;
512 #endif
513 spu->packet_pts = pts100;
514 if (spu->packet_offset == 0) {
515 unsigned int len2 = get_be16(packet);
516 // Start new fragment
517 if (spu->packet_reserve < len2) {
518 if (spu->packet != NULL)
519 free(spu->packet);
520 spu->packet = malloc(len2);
521 spu->packet_reserve = spu->packet != NULL ? len2 : 0;
523 if (spu->packet != NULL) {
524 spu->packet_size = len2;
525 if (len > len2) {
526 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: invalid frag len / len2: %d / %d \n", len, len2);
527 return;
529 memcpy(spu->packet, packet, len);
530 spu->packet_offset = len;
531 spu->packet_pts = pts100;
533 } else {
534 // Continue current fragment
535 if (spu->packet_size < spu->packet_offset + len){
536 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: invalid fragment\n");
537 spu->packet_size = spu->packet_offset = 0;
538 return;
539 } else {
540 memcpy(spu->packet + spu->packet_offset, packet, len);
541 spu->packet_offset += len;
544 #if 1
545 // check if we have a complete packet (unfortunatelly packet_size is bad
546 // for some disks)
547 // [cb] packet_size is padded to be even -> may be one byte too long
548 if ((spu->packet_offset == spu->packet_size) ||
549 ((spu->packet_offset + 1) == spu->packet_size)){
550 unsigned int x=0,y;
551 while(x+4<=spu->packet_offset){
552 y=get_be16(spu->packet+x+2); // next control pointer
553 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPUtest: x=%d y=%d off=%d size=%d\n",x,y,spu->packet_offset,spu->packet_size);
554 if(x>=4 && x==y){ // if it points to self - we're done!
555 // we got it!
556 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPUgot: off=%d size=%d \n",spu->packet_offset,spu->packet_size);
557 spudec_decode(spu, pts100);
558 spu->packet_offset = 0;
559 break;
561 if(y<=x || y>=spu->packet_size){ // invalid?
562 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUtest: broken packet!!!!! y=%d < x=%d\n",y,x);
563 spu->packet_size = spu->packet_offset = 0;
564 break;
566 x=y;
568 // [cb] packet is done; start new packet
569 spu->packet_offset = 0;
571 #else
572 if (spu->packet_offset == spu->packet_size) {
573 spudec_decode(spu, pts100);
574 spu->packet_offset = 0;
576 #endif
579 void spudec_reset(void *this) // called after seek
581 spudec_handle_t *spu = (spudec_handle_t*)this;
582 while (spu->queue_head)
583 spudec_free_packet(spudec_dequeue_packet(spu));
584 spu->now_pts = 0;
585 spu->end_pts = 0;
586 spu->packet_size = spu->packet_offset = 0;
589 void spudec_heartbeat(void *this, unsigned int pts100)
591 spudec_handle_t *spu = (spudec_handle_t*) this;
592 spu->now_pts = pts100;
594 while (spu->queue_head != NULL && pts100 >= spu->queue_head->start_pts) {
595 packet_t *packet = spudec_dequeue_packet(spu);
596 spu->start_pts = packet->start_pts;
597 spu->end_pts = packet->end_pts;
598 if (spu->auto_palette)
599 compute_palette(spu, packet);
600 spudec_process_data(spu, packet);
601 spudec_free_packet(packet);
602 spu->spu_changed = 1;
606 int spudec_visible(void *this){
607 spudec_handle_t *spu = (spudec_handle_t *)this;
608 int ret=(spu->start_pts <= spu->now_pts &&
609 spu->now_pts < spu->end_pts &&
610 spu->height > 0);
611 // printf("spu visible: %d \n",ret);
612 return ret;
615 void spudec_set_forced_subs_only(void * const this, const unsigned int flag)
617 if(this){
618 ((spudec_handle_t *)this)->forced_subs_only=flag;
619 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPU: Display only forced subs now %s\n", flag ? "enabled": "disabled");
623 void spudec_draw(void *this, void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride))
625 spudec_handle_t *spu = (spudec_handle_t *)this;
626 if (spu->start_pts <= spu->now_pts && spu->now_pts < spu->end_pts && spu->image)
628 draw_alpha(spu->start_col, spu->start_row, spu->width, spu->height,
629 spu->image, spu->aimage, spu->stride);
630 spu->spu_changed = 0;
634 /* calc the bbox for spudec subs */
635 void spudec_calc_bbox(void *me, unsigned int dxs, unsigned int dys, unsigned int* bbox)
637 spudec_handle_t *spu;
638 spu = (spudec_handle_t *)me;
639 if (spu->orig_frame_width == 0 || spu->orig_frame_height == 0
640 || (spu->orig_frame_width == dxs && spu->orig_frame_height == dys)) {
641 bbox[0] = spu->start_col;
642 bbox[1] = spu->start_col + spu->width;
643 bbox[2] = spu->start_row;
644 bbox[3] = spu->start_row + spu->height;
646 else if (spu->scaled_frame_width != dxs || spu->scaled_frame_height != dys) {
647 unsigned int scalex = 0x100 * dxs / spu->orig_frame_width;
648 unsigned int scaley = 0x100 * dys / spu->orig_frame_height;
649 bbox[0] = spu->start_col * scalex / 0x100;
650 bbox[1] = spu->start_col * scalex / 0x100 + spu->width * scalex / 0x100;
651 switch (spu_alignment) {
652 case 0:
653 bbox[3] = dys*sub_pos/100 + spu->height * scaley / 0x100;
654 if (bbox[3] > dys) bbox[3] = dys;
655 bbox[2] = bbox[3] - spu->height * scaley / 0x100;
656 break;
657 case 1:
658 if (sub_pos < 50) {
659 bbox[2] = dys*sub_pos/100 - spu->height * scaley / 0x200;
660 if (bbox[2] < 0) bbox[2] = 0;
661 bbox[3] = bbox[2] + spu->height;
662 } else {
663 bbox[3] = dys*sub_pos/100 + spu->height * scaley / 0x200;
664 if (bbox[3] > dys) bbox[3] = dys;
665 bbox[2] = bbox[3] - spu->height * scaley / 0x100;
667 break;
668 case 2:
669 bbox[2] = dys*sub_pos/100 - spu->height * scaley / 0x100;
670 if (bbox[2] < 0) bbox[2] = 0;
671 bbox[3] = bbox[2] + spu->height;
672 break;
673 default: /* -1 */
674 bbox[2] = spu->start_row * scaley / 0x100;
675 bbox[3] = spu->start_row * scaley / 0x100 + spu->height * scaley / 0x100;
676 break;
680 /* transform mplayer's alpha value into an opacity value that is linear */
681 static inline int canon_alpha(int alpha)
683 return alpha ? 256 - alpha : 0;
686 typedef struct {
687 unsigned position;
688 unsigned left_up;
689 unsigned right_down;
690 }scale_pixel;
693 static void scale_table(unsigned int start_src, unsigned int start_tar, unsigned int end_src, unsigned int end_tar, scale_pixel * table)
695 unsigned int t;
696 unsigned int delta_src = end_src - start_src;
697 unsigned int delta_tar = end_tar - start_tar;
698 int src = 0;
699 int src_step;
700 if (delta_src == 0 || delta_tar == 0) {
701 return;
703 src_step = (delta_src << 16) / delta_tar >>1;
704 for (t = 0; t<=delta_tar; src += (src_step << 1), t++){
705 table[t].position= MIN(src >> 16, end_src - 1);
706 table[t].right_down = src & 0xffff;
707 table[t].left_up = 0x10000 - table[t].right_down;
711 /* bilinear scale, similar to vobsub's code */
712 static void scale_image(int x, int y, scale_pixel* table_x, scale_pixel* table_y, spudec_handle_t * spu)
714 int alpha[4];
715 int color[4];
716 unsigned int scale[4];
717 int base = table_y[y].position * spu->stride + table_x[x].position;
718 int scaled = y * spu->scaled_stride + x;
719 alpha[0] = canon_alpha(spu->aimage[base]);
720 alpha[1] = canon_alpha(spu->aimage[base + 1]);
721 alpha[2] = canon_alpha(spu->aimage[base + spu->stride]);
722 alpha[3] = canon_alpha(spu->aimage[base + spu->stride + 1]);
723 color[0] = spu->image[base];
724 color[1] = spu->image[base + 1];
725 color[2] = spu->image[base + spu->stride];
726 color[3] = spu->image[base + spu->stride + 1];
727 scale[0] = (table_x[x].left_up * table_y[y].left_up >> 16) * alpha[0];
728 scale[1] = (table_x[x].right_down * table_y[y].left_up >>16) * alpha[1];
729 scale[2] = (table_x[x].left_up * table_y[y].right_down >> 16) * alpha[2];
730 scale[3] = (table_x[x].right_down * table_y[y].right_down >> 16) * alpha[3];
731 spu->scaled_image[scaled] = (color[0] * scale[0] + color[1] * scale[1] + color[2] * scale[2] + color[3] * scale[3])>>24;
732 spu->scaled_aimage[scaled] = (scale[0] + scale[1] + scale[2] + scale[3]) >> 16;
733 if (spu->scaled_aimage[scaled]){
734 spu->scaled_aimage[scaled] = 256 - spu->scaled_aimage[scaled];
735 if(spu->scaled_aimage[scaled] + spu->scaled_image[scaled] > 255)
736 spu->scaled_image[scaled] = 256 - spu->scaled_aimage[scaled];
740 void sws_spu_image(unsigned char *d1, unsigned char *d2, int dw, int dh, int ds,
741 unsigned char *s1, unsigned char *s2, int sw, int sh, int ss)
743 struct SwsContext *ctx;
744 static SwsFilter filter;
745 static int firsttime = 1;
746 static float oldvar;
747 int i;
749 if (!firsttime && oldvar != spu_gaussvar) sws_freeVec(filter.lumH);
750 if (firsttime) {
751 filter.lumH = filter.lumV =
752 filter.chrH = filter.chrV = sws_getGaussianVec(spu_gaussvar, 3.0);
753 sws_normalizeVec(filter.lumH, 1.0);
754 firsttime = 0;
755 oldvar = spu_gaussvar;
758 ctx=sws_getContext(sw, sh, PIX_FMT_GRAY8, dw, dh, PIX_FMT_GRAY8, SWS_GAUSS, &filter, NULL, NULL);
759 sws_scale(ctx,&s1,&ss,0,sh,&d1,&ds);
760 for (i=ss*sh-1; i>=0; i--) if (!s2[i]) s2[i] = 255; //else s2[i] = 1;
761 sws_scale(ctx,&s2,&ss,0,sh,&d2,&ds);
762 for (i=ds*dh-1; i>=0; i--) if (d2[i]==0) d2[i] = 1; else if (d2[i]==255) d2[i] = 0;
763 sws_freeContext(ctx);
766 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))
768 spudec_handle_t *spu = (spudec_handle_t *)me;
769 scale_pixel *table_x;
770 scale_pixel *table_y;
772 if (spu->start_pts <= spu->now_pts && spu->now_pts < spu->end_pts) {
774 // check if only forced subtitles are requested
775 if( (spu->forced_subs_only) && !(spu->is_forced_sub) ){
776 return;
779 if (!(spu_aamode&16) && (spu->orig_frame_width == 0 || spu->orig_frame_height == 0
780 || (spu->orig_frame_width == dxs && spu->orig_frame_height == dys))) {
781 if (spu->image)
783 draw_alpha(spu->start_col, spu->start_row, spu->width, spu->height,
784 spu->image, spu->aimage, spu->stride);
785 spu->spu_changed = 0;
788 else {
789 if (spu->scaled_frame_width != dxs || spu->scaled_frame_height != dys) { /* Resizing is needed */
790 /* scaled_x = scalex * x / 0x100
791 scaled_y = scaley * y / 0x100
792 order of operations is important because of rounding. */
793 unsigned int scalex = 0x100 * dxs / spu->orig_frame_width;
794 unsigned int scaley = 0x100 * dys / spu->orig_frame_height;
795 spu->scaled_start_col = spu->start_col * scalex / 0x100;
796 spu->scaled_start_row = spu->start_row * scaley / 0x100;
797 spu->scaled_width = spu->width * scalex / 0x100;
798 spu->scaled_height = spu->height * scaley / 0x100;
799 /* Kludge: draw_alpha needs width multiple of 8 */
800 spu->scaled_stride = (spu->scaled_width + 7) & ~7;
801 if (spu->scaled_image_size < spu->scaled_stride * spu->scaled_height) {
802 if (spu->scaled_image) {
803 free(spu->scaled_image);
804 spu->scaled_image_size = 0;
806 spu->scaled_image = malloc(2 * spu->scaled_stride * spu->scaled_height);
807 if (spu->scaled_image) {
808 spu->scaled_image_size = spu->scaled_stride * spu->scaled_height;
809 spu->scaled_aimage = spu->scaled_image + spu->scaled_image_size;
812 if (spu->scaled_image) {
813 unsigned int x, y;
814 if (spu->scaled_width <= 1 || spu->scaled_height <= 1) {
815 goto nothing_to_do;
817 switch(spu_aamode&15) {
818 case 4:
819 sws_spu_image(spu->scaled_image, spu->scaled_aimage,
820 spu->scaled_width, spu->scaled_height, spu->scaled_stride,
821 spu->image, spu->aimage, spu->width, spu->height, spu->stride);
822 break;
823 case 3:
824 table_x = calloc(spu->scaled_width, sizeof(scale_pixel));
825 table_y = calloc(spu->scaled_height, sizeof(scale_pixel));
826 if (!table_x || !table_y) {
827 mp_msg(MSGT_SPUDEC, MSGL_FATAL, "Fatal: spudec_draw_scaled: calloc failed\n");
829 scale_table(0, 0, spu->width - 1, spu->scaled_width - 1, table_x);
830 scale_table(0, 0, spu->height - 1, spu->scaled_height - 1, table_y);
831 for (y = 0; y < spu->scaled_height; y++)
832 for (x = 0; x < spu->scaled_width; x++)
833 scale_image(x, y, table_x, table_y, spu);
834 free(table_x);
835 free(table_y);
836 break;
837 case 0:
838 /* no antialiasing */
839 for (y = 0; y < spu->scaled_height; ++y) {
840 int unscaled_y = y * 0x100 / scaley;
841 int strides = spu->stride * unscaled_y;
842 int scaled_strides = spu->scaled_stride * y;
843 for (x = 0; x < spu->scaled_width; ++x) {
844 int unscaled_x = x * 0x100 / scalex;
845 spu->scaled_image[scaled_strides + x] = spu->image[strides + unscaled_x];
846 spu->scaled_aimage[scaled_strides + x] = spu->aimage[strides + unscaled_x];
849 break;
850 case 1:
852 /* Intermediate antialiasing. */
853 for (y = 0; y < spu->scaled_height; ++y) {
854 const unsigned int unscaled_top = y * spu->orig_frame_height / dys;
855 unsigned int unscaled_bottom = (y + 1) * spu->orig_frame_height / dys;
856 if (unscaled_bottom >= spu->height)
857 unscaled_bottom = spu->height - 1;
858 for (x = 0; x < spu->scaled_width; ++x) {
859 const unsigned int unscaled_left = x * spu->orig_frame_width / dxs;
860 unsigned int unscaled_right = (x + 1) * spu->orig_frame_width / dxs;
861 unsigned int color = 0;
862 unsigned int alpha = 0;
863 unsigned int walkx, walky;
864 unsigned int base, tmp;
865 if (unscaled_right >= spu->width)
866 unscaled_right = spu->width - 1;
867 for (walky = unscaled_top; walky <= unscaled_bottom; ++walky)
868 for (walkx = unscaled_left; walkx <= unscaled_right; ++walkx) {
869 base = walky * spu->stride + walkx;
870 tmp = canon_alpha(spu->aimage[base]);
871 alpha += tmp;
872 color += tmp * spu->image[base];
874 base = y * spu->scaled_stride + x;
875 spu->scaled_image[base] = alpha ? color / alpha : 0;
876 spu->scaled_aimage[base] =
877 alpha * (1 + unscaled_bottom - unscaled_top) * (1 + unscaled_right - unscaled_left);
878 /* spu->scaled_aimage[base] =
879 alpha * dxs * dys / spu->orig_frame_width / spu->orig_frame_height; */
880 if (spu->scaled_aimage[base]) {
881 spu->scaled_aimage[base] = 256 - spu->scaled_aimage[base];
882 if (spu->scaled_aimage[base] + spu->scaled_image[base] > 255)
883 spu->scaled_image[base] = 256 - spu->scaled_aimage[base];
888 break;
889 case 2:
891 /* Best antialiasing. Very slow. */
892 /* Any pixel (x, y) represents pixels from the original
893 rectangular region comprised between the columns
894 unscaled_y and unscaled_y + 0x100 / scaley and the rows
895 unscaled_x and unscaled_x + 0x100 / scalex
897 The original rectangular region that the scaled pixel
898 represents is cut in 9 rectangular areas like this:
900 +---+-----------------+---+
901 | 1 | 2 | 3 |
902 +---+-----------------+---+
903 | | | |
904 | 4 | 5 | 6 |
905 | | | |
906 +---+-----------------+---+
907 | 7 | 8 | 9 |
908 +---+-----------------+---+
910 The width of the left column is at most one pixel and
911 it is never null and its right column is at a pixel
912 boundary. The height of the top row is at most one
913 pixel it is never null and its bottom row is at a
914 pixel boundary. The width and height of region 5 are
915 integral values. The width of the right column is
916 what remains and is less than one pixel. The height
917 of the bottom row is what remains and is less than
918 one pixel.
920 The row above 1, 2, 3 is unscaled_y. The row between
921 1, 2, 3 and 4, 5, 6 is top_low_row. The row between 4,
922 5, 6 and 7, 8, 9 is (unsigned int)unscaled_y_bottom.
923 The row beneath 7, 8, 9 is unscaled_y_bottom.
925 The column left of 1, 4, 7 is unscaled_x. The column
926 between 1, 4, 7 and 2, 5, 8 is left_right_column. The
927 column between 2, 5, 8 and 3, 6, 9 is (unsigned
928 int)unscaled_x_right. The column right of 3, 6, 9 is
929 unscaled_x_right. */
930 const double inv_scalex = (double) 0x100 / scalex;
931 const double inv_scaley = (double) 0x100 / scaley;
932 for (y = 0; y < spu->scaled_height; ++y) {
933 const double unscaled_y = y * inv_scaley;
934 const double unscaled_y_bottom = unscaled_y + inv_scaley;
935 const unsigned int top_low_row = MIN(unscaled_y_bottom, unscaled_y + 1.0);
936 const double top = top_low_row - unscaled_y;
937 const unsigned int height = unscaled_y_bottom > top_low_row
938 ? (unsigned int) unscaled_y_bottom - top_low_row
939 : 0;
940 const double bottom = unscaled_y_bottom > top_low_row
941 ? unscaled_y_bottom - floor(unscaled_y_bottom)
942 : 0.0;
943 for (x = 0; x < spu->scaled_width; ++x) {
944 const double unscaled_x = x * inv_scalex;
945 const double unscaled_x_right = unscaled_x + inv_scalex;
946 const unsigned int left_right_column = MIN(unscaled_x_right, unscaled_x + 1.0);
947 const double left = left_right_column - unscaled_x;
948 const unsigned int width = unscaled_x_right > left_right_column
949 ? (unsigned int) unscaled_x_right - left_right_column
950 : 0;
951 const double right = unscaled_x_right > left_right_column
952 ? unscaled_x_right - floor(unscaled_x_right)
953 : 0.0;
954 double color = 0.0;
955 double alpha = 0.0;
956 double tmp;
957 unsigned int base;
958 /* Now use these informations to compute a good alpha,
959 and lightness. The sum is on each of the 9
960 region's surface and alpha and lightness.
962 transformed alpha = sum(surface * alpha) / sum(surface)
963 transformed color = sum(surface * alpha * color) / sum(surface * alpha)
965 /* 1: top left part */
966 base = spu->stride * (unsigned int) unscaled_y;
967 tmp = left * top * canon_alpha(spu->aimage[base + (unsigned int) unscaled_x]);
968 alpha += tmp;
969 color += tmp * spu->image[base + (unsigned int) unscaled_x];
970 /* 2: top center part */
971 if (width > 0) {
972 unsigned int walkx;
973 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
974 base = spu->stride * (unsigned int) unscaled_y + walkx;
975 tmp = /* 1.0 * */ top * canon_alpha(spu->aimage[base]);
976 alpha += tmp;
977 color += tmp * spu->image[base];
980 /* 3: top right part */
981 if (right > 0.0) {
982 base = spu->stride * (unsigned int) unscaled_y + (unsigned int) unscaled_x_right;
983 tmp = right * top * canon_alpha(spu->aimage[base]);
984 alpha += tmp;
985 color += tmp * spu->image[base];
987 /* 4: center left part */
988 if (height > 0) {
989 unsigned int walky;
990 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
991 base = spu->stride * walky + (unsigned int) unscaled_x;
992 tmp = left /* * 1.0 */ * canon_alpha(spu->aimage[base]);
993 alpha += tmp;
994 color += tmp * spu->image[base];
997 /* 5: center part */
998 if (width > 0 && height > 0) {
999 unsigned int walky;
1000 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1001 unsigned int walkx;
1002 base = spu->stride * walky;
1003 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
1004 tmp = /* 1.0 * 1.0 * */ canon_alpha(spu->aimage[base + walkx]);
1005 alpha += tmp;
1006 color += tmp * spu->image[base + walkx];
1010 /* 6: center right part */
1011 if (right > 0.0 && height > 0) {
1012 unsigned int walky;
1013 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1014 base = spu->stride * walky + (unsigned int) unscaled_x_right;
1015 tmp = right /* * 1.0 */ * canon_alpha(spu->aimage[base]);
1016 alpha += tmp;
1017 color += tmp * spu->image[base];
1020 /* 7: bottom left part */
1021 if (bottom > 0.0) {
1022 base = spu->stride * (unsigned int) unscaled_y_bottom + (unsigned int) unscaled_x;
1023 tmp = left * bottom * canon_alpha(spu->aimage[base]);
1024 alpha += tmp;
1025 color += tmp * spu->image[base];
1027 /* 8: bottom center part */
1028 if (width > 0 && bottom > 0.0) {
1029 unsigned int walkx;
1030 base = spu->stride * (unsigned int) unscaled_y_bottom;
1031 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
1032 tmp = /* 1.0 * */ bottom * canon_alpha(spu->aimage[base + walkx]);
1033 alpha += tmp;
1034 color += tmp * spu->image[base + walkx];
1037 /* 9: bottom right part */
1038 if (right > 0.0 && bottom > 0.0) {
1039 base = spu->stride * (unsigned int) unscaled_y_bottom + (unsigned int) unscaled_x_right;
1040 tmp = right * bottom * canon_alpha(spu->aimage[base]);
1041 alpha += tmp;
1042 color += tmp * spu->image[base];
1044 /* Finally mix these transparency and brightness information suitably */
1045 base = spu->scaled_stride * y + x;
1046 spu->scaled_image[base] = alpha > 0 ? color / alpha : 0;
1047 spu->scaled_aimage[base] = alpha * scalex * scaley / 0x10000;
1048 if (spu->scaled_aimage[base]) {
1049 spu->scaled_aimage[base] = 256 - spu->scaled_aimage[base];
1050 if (spu->scaled_aimage[base] + spu->scaled_image[base] > 255)
1051 spu->scaled_image[base] = 256 - spu->scaled_aimage[base];
1057 nothing_to_do:
1058 /* Kludge: draw_alpha needs width multiple of 8. */
1059 if (spu->scaled_width < spu->scaled_stride)
1060 for (y = 0; y < spu->scaled_height; ++y) {
1061 memset(spu->scaled_aimage + y * spu->scaled_stride + spu->scaled_width, 0,
1062 spu->scaled_stride - spu->scaled_width);
1064 spu->scaled_frame_width = dxs;
1065 spu->scaled_frame_height = dys;
1068 if (spu->scaled_image){
1069 switch (spu_alignment) {
1070 case 0:
1071 spu->scaled_start_row = dys*sub_pos/100;
1072 if (spu->scaled_start_row + spu->scaled_height > dys)
1073 spu->scaled_start_row = dys - spu->scaled_height;
1074 break;
1075 case 1:
1076 spu->scaled_start_row = dys*sub_pos/100 - spu->scaled_height/2;
1077 if (sub_pos < 50) {
1078 if (spu->scaled_start_row < 0) spu->scaled_start_row = 0;
1079 } else {
1080 if (spu->scaled_start_row + spu->scaled_height > dys)
1081 spu->scaled_start_row = dys - spu->scaled_height;
1083 break;
1084 case 2:
1085 spu->scaled_start_row = dys*sub_pos/100 - spu->scaled_height;
1086 if (spu->scaled_start_row < 0) spu->scaled_start_row = 0;
1087 break;
1089 draw_alpha(spu->scaled_start_col, spu->scaled_start_row, spu->scaled_width, spu->scaled_height,
1090 spu->scaled_image, spu->scaled_aimage, spu->scaled_stride);
1091 spu->spu_changed = 0;
1095 else
1097 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPU not displayed: start_pts=%d end_pts=%d now_pts=%d\n",
1098 spu->start_pts, spu->end_pts, spu->now_pts);
1102 void spudec_update_palette(void * this, unsigned int *palette)
1104 spudec_handle_t *spu = (spudec_handle_t *) this;
1105 if (spu && palette) {
1106 memcpy(spu->global_palette, palette, sizeof(spu->global_palette));
1107 if(spu->hw_spu)
1108 spu->hw_spu->control(VOCTRL_SET_SPU_PALETTE,spu->global_palette);
1112 void spudec_set_font_factor(void * this, double factor)
1114 spudec_handle_t *spu = (spudec_handle_t *) this;
1115 spu->font_start_level = (int)(0xF0-(0xE0*factor));
1118 void *spudec_new_scaled(unsigned int *palette, unsigned int frame_width, unsigned int frame_height)
1120 return spudec_new_scaled_vobsub(palette, NULL, 0, frame_width, frame_height);
1123 /* get palette custom color, width, height from .idx file */
1124 void *spudec_new_scaled_vobsub(unsigned int *palette, unsigned int *cuspal, unsigned int custom, unsigned int frame_width, unsigned int frame_height)
1126 spudec_handle_t *this = calloc(1, sizeof(spudec_handle_t));
1127 if (this){
1128 //(fprintf(stderr,"VobSub Custom Palette: %d,%d,%d,%d", this->cuspal[0], this->cuspal[1], this->cuspal[2],this->cuspal[3]);
1129 this->packet = NULL;
1130 this->image = NULL;
1131 this->scaled_image = NULL;
1132 /* XXX Although the video frame is some size, the SPU frame is
1133 always maximum size i.e. 720 wide and 576 or 480 high */
1134 this->orig_frame_width = 720;
1135 this->orig_frame_height = (frame_height == 480 || frame_height == 240) ? 480 : 576;
1136 this->custom = custom;
1137 // set up palette:
1138 this->auto_palette = 1;
1139 if (palette){
1140 memcpy(this->global_palette, palette, sizeof(this->global_palette));
1141 this->auto_palette = 0;
1143 this->custom = custom;
1144 if (custom && cuspal) {
1145 memcpy(this->cuspal, cuspal, sizeof(this->cuspal));
1146 this->auto_palette = 0;
1148 // forced subtitles default: show all subtitles
1149 this->forced_subs_only=0;
1150 this->is_forced_sub=0;
1152 else
1153 mp_msg(MSGT_SPUDEC,MSGL_FATAL, "FATAL: spudec_init: calloc");
1154 return this;
1157 void *spudec_new(unsigned int *palette)
1159 return spudec_new_scaled(palette, 0, 0);
1162 void spudec_free(void *this)
1164 spudec_handle_t *spu = (spudec_handle_t*)this;
1165 if (spu) {
1166 while (spu->queue_head)
1167 spudec_free_packet(spudec_dequeue_packet(spu));
1168 if (spu->packet)
1169 free(spu->packet);
1170 if (spu->scaled_image)
1171 free(spu->scaled_image);
1172 if (spu->image)
1173 free(spu->image);
1174 free(spu);
1178 void spudec_set_hw_spu(void *this, vo_functions_t *hw_spu)
1180 spudec_handle_t *spu = (spudec_handle_t*)this;
1181 if (!spu)
1182 return;
1183 spu->hw_spu = hw_spu;
1184 hw_spu->control(VOCTRL_SET_SPU_PALETTE,spu->global_palette);