Rename exit_player() use outside core to exit_player_bad()
[mplayer.git] / spudec.c
bloba086227d224bdc76a955add12ad2518fe2a556fb
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 "libavutil/avutil.h"
27 #include "libswscale/swscale.h"
29 /* Valid values for spu_aamode:
30 0: none (fastest, most ugly)
31 1: approximate
32 2: full (slowest)
33 3: bilinear (similiar to vobsub, fast and not too bad)
34 4: uses swscaler gaussian (this is the only one that looks good)
37 int spu_aamode = 3;
38 int spu_alignment = -1;
39 float spu_gaussvar = 1.0;
40 extern int sub_pos;
42 typedef struct packet_t packet_t;
43 struct packet_t {
44 unsigned char *packet;
45 unsigned int palette[4];
46 unsigned int alpha[4];
47 unsigned int control_start; /* index of start of control data */
48 unsigned int current_nibble[2]; /* next data nibble (4 bits) to be
49 processed (for RLE decoding) for
50 even and odd lines */
51 int deinterlace_oddness; /* 0 or 1, index into current_nibble */
52 unsigned int start_col, end_col;
53 unsigned int start_row, end_row;
54 unsigned int width, height, stride;
55 unsigned int start_pts, end_pts;
56 packet_t *next;
59 typedef struct {
60 packet_t *queue_head;
61 packet_t *queue_tail;
62 unsigned int global_palette[16];
63 unsigned int orig_frame_width, orig_frame_height;
64 unsigned char* packet;
65 size_t packet_reserve; /* size of the memory pointed to by packet */
66 unsigned int packet_offset; /* end of the currently assembled fragment */
67 unsigned int packet_size; /* size of the packet once all fragments are assembled */
68 int packet_pts; /* PTS for this packet */
69 unsigned int palette[4];
70 unsigned int alpha[4];
71 unsigned int cuspal[4];
72 unsigned int custom;
73 unsigned int now_pts;
74 unsigned int start_pts, end_pts;
75 unsigned int start_col, end_col;
76 unsigned int start_row, end_row;
77 unsigned int width, height, stride;
78 size_t image_size; /* Size of the image buffer */
79 unsigned char *image; /* Grayscale value */
80 unsigned char *aimage; /* Alpha value */
81 unsigned int scaled_frame_width, scaled_frame_height;
82 unsigned int scaled_start_col, scaled_start_row;
83 unsigned int scaled_width, scaled_height, scaled_stride;
84 size_t scaled_image_size;
85 unsigned char *scaled_image;
86 unsigned char *scaled_aimage;
87 int auto_palette; /* 1 if we lack a palette and must use an heuristic. */
88 int font_start_level; /* Darkest value used for the computed font */
89 struct vo *hw_spu;
90 int spu_changed;
91 unsigned int forced_subs_only; /* flag: 0=display all subtitle, !0 display only forced subtitles */
92 unsigned int is_forced_sub; /* true if current subtitle is a forced subtitle */
93 } spudec_handle_t;
95 static void spudec_queue_packet(spudec_handle_t *this, packet_t *packet)
97 if (this->queue_head == NULL)
98 this->queue_head = packet;
99 else
100 this->queue_tail->next = packet;
101 this->queue_tail = packet;
104 static packet_t *spudec_dequeue_packet(spudec_handle_t *this)
106 packet_t *retval = this->queue_head;
108 this->queue_head = retval->next;
109 if (this->queue_head == NULL)
110 this->queue_tail = NULL;
112 return retval;
115 static void spudec_free_packet(packet_t *packet)
117 if (packet->packet != NULL)
118 free(packet->packet);
119 free(packet);
122 static inline unsigned int get_be16(const unsigned char *p)
124 return (p[0] << 8) + p[1];
127 static inline unsigned int get_be24(const unsigned char *p)
129 return (get_be16(p) << 8) + p[2];
132 static void next_line(packet_t *packet)
134 if (packet->current_nibble[packet->deinterlace_oddness] % 2)
135 packet->current_nibble[packet->deinterlace_oddness]++;
136 packet->deinterlace_oddness = (packet->deinterlace_oddness + 1) % 2;
139 static inline unsigned char get_nibble(packet_t *packet)
141 unsigned char nib;
142 unsigned int *nibblep = packet->current_nibble + packet->deinterlace_oddness;
143 if (*nibblep / 2 >= packet->control_start) {
144 mp_msg(MSGT_SPUDEC,MSGL_WARN, "SPUdec: ERROR: get_nibble past end of packet\n");
145 return 0;
147 nib = packet->packet[*nibblep / 2];
148 if (*nibblep % 2)
149 nib &= 0xf;
150 else
151 nib >>= 4;
152 ++*nibblep;
153 return nib;
156 static inline int mkalpha(int i)
158 /* In mplayer's alpha planes, 0 is transparent, then 1 is nearly
159 opaque upto 255 which is transparent */
160 switch (i) {
161 case 0xf:
162 return 1;
163 case 0:
164 return 0;
165 default:
166 return (0xf - i) << 4;
170 /* Cut the sub to visible part */
171 static inline void spudec_cut_image(spudec_handle_t *this)
173 unsigned int fy, ly;
174 unsigned int first_y, last_y;
175 unsigned char *image;
176 unsigned char *aimage;
178 if (this->stride == 0 || this->height == 0) {
179 return;
182 for (fy = 0; fy < this->image_size && !this->aimage[fy]; fy++);
183 for (ly = this->stride * this->height-1; ly && !this->aimage[ly]; ly--);
184 first_y = fy / this->stride;
185 last_y = ly / this->stride;
186 //printf("first_y: %d, last_y: %d\n", first_y, last_y);
187 this->start_row += first_y;
189 // Some subtitles trigger this condition
190 if (last_y + 1 > first_y ) {
191 this->height = last_y - first_y +1;
192 } else {
193 this->height = 0;
194 this->image_size = 0;
195 return;
198 // printf("new h %d new start %d (sz %d st %d)---\n\n", this->height, this->start_row, this->image_size, this->stride);
200 image = malloc(2 * this->stride * this->height);
201 if(image){
202 this->image_size = this->stride * this->height;
203 aimage = image + this->image_size;
204 memcpy(image, this->image + this->stride * first_y, this->image_size);
205 memcpy(aimage, this->aimage + this->stride * first_y, this->image_size);
206 free(this->image);
207 this->image = image;
208 this->aimage = aimage;
209 } else {
210 mp_msg(MSGT_SPUDEC, MSGL_FATAL, "Fatal: update_spu: malloc requested %d bytes\n", 2 * this->stride * this->height);
214 static void spudec_process_data(spudec_handle_t *this, packet_t *packet)
216 unsigned int cmap[4], alpha[4];
217 unsigned int i, x, y;
219 this->scaled_frame_width = 0;
220 this->scaled_frame_height = 0;
221 this->start_col = packet->start_col;
222 this->end_col = packet->end_col;
223 this->start_row = packet->start_row;
224 this->end_row = packet->end_row;
225 this->height = packet->height;
226 this->width = packet->width;
227 this->stride = packet->stride;
228 for (i = 0; i < 4; ++i) {
229 alpha[i] = mkalpha(packet->alpha[i]);
230 if (this->custom && (this->cuspal[i] >> 31) != 0)
231 alpha[i] = 0;
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, 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 = 0;
350 unsigned int end_pts = 0;
351 unsigned int current_nibble[2] = {0, 0};
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 < 0 && -pts100 >= date ? 0 : 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 < 0 && -pts100 >= date ? 0 : 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 < 0 && -pts100 >= date ? 0 : 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 continue;
453 if (end_pts == UINT_MAX && start_off != next_off) {
454 end_pts = get_be16(this->packet + next_off) * 1024;
455 end_pts = 1 - pts100 >= end_pts ? 0 : pts100 + end_pts - 1;
457 if (end_pts > 0) {
458 packet_t *packet = calloc(1, sizeof(packet_t));
459 int i;
460 packet->start_pts = start_pts;
461 packet->end_pts = end_pts;
462 packet->current_nibble[0] = current_nibble[0];
463 packet->current_nibble[1] = current_nibble[1];
464 packet->start_row = start_row;
465 packet->end_row = end_row;
466 packet->start_col = start_col;
467 packet->end_col = end_col;
468 packet->width = width;
469 packet->height = height;
470 packet->stride = stride;
471 packet->control_start = control_start;
472 for (i=0; i<4; i++) {
473 packet->alpha[i] = this->alpha[i];
474 packet->palette[i] = this->palette[i];
476 packet->packet = malloc(this->packet_size);
477 memcpy(packet->packet, this->packet, this->packet_size);
478 spudec_queue_packet(this, packet);
483 static void spudec_decode(spudec_handle_t *this, int pts100)
485 if (!this->hw_spu)
486 spudec_process_control(this, pts100);
487 else if (pts100 >= 0) {
488 static vo_mpegpes_t packet = { NULL, 0, 0x20, 0 };
489 static vo_mpegpes_t *pkg=&packet;
490 packet.data = this->packet;
491 packet.size = this->packet_size;
492 packet.timestamp = pts100;
493 vo_draw_frame(this->hw_spu, (uint8_t**)&pkg);
497 int spudec_changed(void * this)
499 spudec_handle_t * spu = (spudec_handle_t*)this;
500 return spu->spu_changed || spu->now_pts > spu->end_pts;
503 void spudec_assemble(void *this, unsigned char *packet, unsigned int len, int pts100)
505 spudec_handle_t *spu = (spudec_handle_t*)this;
506 // spudec_heartbeat(this, pts100);
507 if (len < 2) {
508 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: packet too short\n");
509 return;
511 #if 0
512 if ((spu->packet_pts + 10000) < pts100) {
513 // [cb] too long since last fragment: force new packet
514 spu->packet_offset = 0;
516 #endif
517 spu->packet_pts = pts100;
518 if (spu->packet_offset == 0) {
519 unsigned int len2 = get_be16(packet);
520 // Start new fragment
521 if (spu->packet_reserve < len2) {
522 if (spu->packet != NULL)
523 free(spu->packet);
524 spu->packet = malloc(len2);
525 spu->packet_reserve = spu->packet != NULL ? len2 : 0;
527 if (spu->packet != NULL) {
528 spu->packet_size = len2;
529 if (len > len2) {
530 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: invalid frag len / len2: %d / %d \n", len, len2);
531 return;
533 memcpy(spu->packet, packet, len);
534 spu->packet_offset = len;
535 spu->packet_pts = pts100;
537 } else {
538 // Continue current fragment
539 if (spu->packet_size < spu->packet_offset + len){
540 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: invalid fragment\n");
541 spu->packet_size = spu->packet_offset = 0;
542 return;
543 } else {
544 memcpy(spu->packet + spu->packet_offset, packet, len);
545 spu->packet_offset += len;
548 #if 1
549 // check if we have a complete packet (unfortunatelly packet_size is bad
550 // for some disks)
551 // [cb] packet_size is padded to be even -> may be one byte too long
552 if ((spu->packet_offset == spu->packet_size) ||
553 ((spu->packet_offset + 1) == spu->packet_size)){
554 unsigned int x=0,y;
555 while(x+4<=spu->packet_offset){
556 y=get_be16(spu->packet+x+2); // next control pointer
557 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPUtest: x=%d y=%d off=%d size=%d\n",x,y,spu->packet_offset,spu->packet_size);
558 if(x>=4 && x==y){ // if it points to self - we're done!
559 // we got it!
560 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPUgot: off=%d size=%d \n",spu->packet_offset,spu->packet_size);
561 spudec_decode(spu, pts100);
562 spu->packet_offset = 0;
563 break;
565 if(y<=x || y>=spu->packet_size){ // invalid?
566 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUtest: broken packet!!!!! y=%d < x=%d\n",y,x);
567 spu->packet_size = spu->packet_offset = 0;
568 break;
570 x=y;
572 // [cb] packet is done; start new packet
573 spu->packet_offset = 0;
575 #else
576 if (spu->packet_offset == spu->packet_size) {
577 spudec_decode(spu, pts100);
578 spu->packet_offset = 0;
580 #endif
583 void spudec_reset(void *this) // called after seek
585 spudec_handle_t *spu = (spudec_handle_t*)this;
586 while (spu->queue_head)
587 spudec_free_packet(spudec_dequeue_packet(spu));
588 spu->now_pts = 0;
589 spu->end_pts = 0;
590 spu->packet_size = spu->packet_offset = 0;
593 void spudec_heartbeat(void *this, unsigned int pts100)
595 spudec_handle_t *spu = (spudec_handle_t*) this;
596 spu->now_pts = pts100;
598 while (spu->queue_head != NULL && pts100 >= spu->queue_head->start_pts) {
599 packet_t *packet = spudec_dequeue_packet(spu);
600 spu->start_pts = packet->start_pts;
601 spu->end_pts = packet->end_pts;
602 if (spu->auto_palette)
603 compute_palette(spu, packet);
604 spudec_process_data(spu, packet);
605 spudec_free_packet(packet);
606 spu->spu_changed = 1;
610 int spudec_visible(void *this){
611 spudec_handle_t *spu = (spudec_handle_t *)this;
612 int ret=(spu->start_pts <= spu->now_pts &&
613 spu->now_pts < spu->end_pts &&
614 spu->height > 0);
615 // printf("spu visible: %d \n",ret);
616 return ret;
619 void spudec_set_forced_subs_only(void * const this, const unsigned int flag)
621 if(this){
622 ((spudec_handle_t *)this)->forced_subs_only=flag;
623 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPU: Display only forced subs now %s\n", flag ? "enabled": "disabled");
627 void spudec_draw(void *this, void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride))
629 spudec_handle_t *spu = (spudec_handle_t *)this;
630 if (spu->start_pts <= spu->now_pts && spu->now_pts < spu->end_pts && spu->image)
632 draw_alpha(spu->start_col, spu->start_row, spu->width, spu->height,
633 spu->image, spu->aimage, spu->stride);
634 spu->spu_changed = 0;
638 /* calc the bbox for spudec subs */
639 void spudec_calc_bbox(void *me, unsigned int dxs, unsigned int dys, unsigned int* bbox)
641 spudec_handle_t *spu;
642 spu = (spudec_handle_t *)me;
643 if (spu->orig_frame_width == 0 || spu->orig_frame_height == 0
644 || (spu->orig_frame_width == dxs && spu->orig_frame_height == dys)) {
645 bbox[0] = spu->start_col;
646 bbox[1] = spu->start_col + spu->width;
647 bbox[2] = spu->start_row;
648 bbox[3] = spu->start_row + spu->height;
650 else if (spu->scaled_frame_width != dxs || spu->scaled_frame_height != dys) {
651 unsigned int scalex = 0x100 * dxs / spu->orig_frame_width;
652 unsigned int scaley = 0x100 * dys / spu->orig_frame_height;
653 bbox[0] = spu->start_col * scalex / 0x100;
654 bbox[1] = spu->start_col * scalex / 0x100 + spu->width * scalex / 0x100;
655 switch (spu_alignment) {
656 case 0:
657 bbox[3] = dys*sub_pos/100 + spu->height * scaley / 0x100;
658 if (bbox[3] > dys) bbox[3] = dys;
659 bbox[2] = bbox[3] - spu->height * scaley / 0x100;
660 break;
661 case 1:
662 if (sub_pos < 50) {
663 bbox[2] = dys*sub_pos/100 - spu->height * scaley / 0x200;
664 bbox[3] = bbox[2] + spu->height;
665 } else {
666 bbox[3] = dys*sub_pos/100 + spu->height * scaley / 0x200;
667 if (bbox[3] > dys) bbox[3] = dys;
668 bbox[2] = bbox[3] - spu->height * scaley / 0x100;
670 break;
671 case 2:
672 bbox[2] = dys*sub_pos/100 - spu->height * scaley / 0x100;
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 if (table_y[y].left_up == 0x10000) // necessary to avoid overflow-case
731 scale[0] = table_x[x].left_up * alpha[0];
732 scale[1] = (table_x[x].right_down * table_y[y].left_up >>16) * alpha[1];
733 scale[2] = (table_x[x].left_up * table_y[y].right_down >> 16) * alpha[2];
734 scale[3] = (table_x[x].right_down * table_y[y].right_down >> 16) * alpha[3];
735 spu->scaled_image[scaled] = (color[0] * scale[0] + color[1] * scale[1] + color[2] * scale[2] + color[3] * scale[3])>>24;
736 spu->scaled_aimage[scaled] = (scale[0] + scale[1] + scale[2] + scale[3]) >> 16;
737 if (spu->scaled_aimage[scaled]){
738 spu->scaled_aimage[scaled] = 256 - spu->scaled_aimage[scaled];
739 if(spu->scaled_aimage[scaled] + spu->scaled_image[scaled] > 255)
740 spu->scaled_image[scaled] = 256 - spu->scaled_aimage[scaled];
744 static void sws_spu_image(unsigned char *d1, unsigned char *d2, int dw, int dh,
745 int ds, unsigned char *s1, unsigned char *s2, int sw,
746 int sh, int ss)
748 struct SwsContext *ctx;
749 static SwsFilter filter;
750 static int firsttime = 1;
751 static float oldvar;
752 int i;
754 if (!firsttime && oldvar != spu_gaussvar) sws_freeVec(filter.lumH);
755 if (firsttime) {
756 filter.lumH = filter.lumV =
757 filter.chrH = filter.chrV = sws_getGaussianVec(spu_gaussvar, 3.0);
758 sws_normalizeVec(filter.lumH, 1.0);
759 firsttime = 0;
760 oldvar = spu_gaussvar;
763 ctx=sws_getContext(sw, sh, PIX_FMT_GRAY8, dw, dh, PIX_FMT_GRAY8, SWS_GAUSS, &filter, NULL, NULL);
764 sws_scale(ctx,&s1,&ss,0,sh,&d1,&ds);
765 for (i=ss*sh-1; i>=0; i--) if (!s2[i]) s2[i] = 255; //else s2[i] = 1;
766 sws_scale(ctx,&s2,&ss,0,sh,&d2,&ds);
767 for (i=ds*dh-1; i>=0; i--) if (d2[i]==0) d2[i] = 1; else if (d2[i]==255) d2[i] = 0;
768 sws_freeContext(ctx);
771 void spudec_draw_scaled(void *me, unsigned int dxs, unsigned int dys, void (*draw_alpha)(void *ctx, int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride), void *ctx)
773 spudec_handle_t *spu = (spudec_handle_t *)me;
774 scale_pixel *table_x;
775 scale_pixel *table_y;
777 if (spu->start_pts <= spu->now_pts && spu->now_pts < spu->end_pts) {
779 // check if only forced subtitles are requested
780 if( (spu->forced_subs_only) && !(spu->is_forced_sub) ){
781 return;
784 if (!(spu_aamode&16) && (spu->orig_frame_width == 0 || spu->orig_frame_height == 0
785 || (spu->orig_frame_width == dxs && spu->orig_frame_height == dys))) {
786 if (spu->image)
788 draw_alpha(ctx, spu->start_col, spu->start_row, spu->width, spu->height,
789 spu->image, spu->aimage, spu->stride);
790 spu->spu_changed = 0;
793 else {
794 if (spu->scaled_frame_width != dxs || spu->scaled_frame_height != dys) { /* Resizing is needed */
795 /* scaled_x = scalex * x / 0x100
796 scaled_y = scaley * y / 0x100
797 order of operations is important because of rounding. */
798 unsigned int scalex = 0x100 * dxs / spu->orig_frame_width;
799 unsigned int scaley = 0x100 * dys / spu->orig_frame_height;
800 spu->scaled_start_col = spu->start_col * scalex / 0x100;
801 spu->scaled_start_row = spu->start_row * scaley / 0x100;
802 spu->scaled_width = spu->width * scalex / 0x100;
803 spu->scaled_height = spu->height * scaley / 0x100;
804 /* Kludge: draw_alpha needs width multiple of 8 */
805 spu->scaled_stride = (spu->scaled_width + 7) & ~7;
806 if (spu->scaled_image_size < spu->scaled_stride * spu->scaled_height) {
807 if (spu->scaled_image) {
808 free(spu->scaled_image);
809 spu->scaled_image_size = 0;
811 spu->scaled_image = malloc(2 * spu->scaled_stride * spu->scaled_height);
812 if (spu->scaled_image) {
813 spu->scaled_image_size = spu->scaled_stride * spu->scaled_height;
814 spu->scaled_aimage = spu->scaled_image + spu->scaled_image_size;
817 if (spu->scaled_image) {
818 unsigned int x, y;
819 if (spu->scaled_width <= 1 || spu->scaled_height <= 1) {
820 goto nothing_to_do;
822 switch(spu_aamode&15) {
823 case 4:
824 sws_spu_image(spu->scaled_image, spu->scaled_aimage,
825 spu->scaled_width, spu->scaled_height, spu->scaled_stride,
826 spu->image, spu->aimage, spu->width, spu->height, spu->stride);
827 break;
828 case 3:
829 table_x = calloc(spu->scaled_width, sizeof(scale_pixel));
830 table_y = calloc(spu->scaled_height, sizeof(scale_pixel));
831 if (!table_x || !table_y) {
832 mp_msg(MSGT_SPUDEC, MSGL_FATAL, "Fatal: spudec_draw_scaled: calloc failed\n");
834 scale_table(0, 0, spu->width - 1, spu->scaled_width - 1, table_x);
835 scale_table(0, 0, spu->height - 1, spu->scaled_height - 1, table_y);
836 for (y = 0; y < spu->scaled_height; y++)
837 for (x = 0; x < spu->scaled_width; x++)
838 scale_image(x, y, table_x, table_y, spu);
839 free(table_x);
840 free(table_y);
841 break;
842 case 0:
843 /* no antialiasing */
844 for (y = 0; y < spu->scaled_height; ++y) {
845 int unscaled_y = y * 0x100 / scaley;
846 int strides = spu->stride * unscaled_y;
847 int scaled_strides = spu->scaled_stride * y;
848 for (x = 0; x < spu->scaled_width; ++x) {
849 int unscaled_x = x * 0x100 / scalex;
850 spu->scaled_image[scaled_strides + x] = spu->image[strides + unscaled_x];
851 spu->scaled_aimage[scaled_strides + x] = spu->aimage[strides + unscaled_x];
854 break;
855 case 1:
857 /* Intermediate antialiasing. */
858 for (y = 0; y < spu->scaled_height; ++y) {
859 const unsigned int unscaled_top = y * spu->orig_frame_height / dys;
860 unsigned int unscaled_bottom = (y + 1) * spu->orig_frame_height / dys;
861 if (unscaled_bottom >= spu->height)
862 unscaled_bottom = spu->height - 1;
863 for (x = 0; x < spu->scaled_width; ++x) {
864 const unsigned int unscaled_left = x * spu->orig_frame_width / dxs;
865 unsigned int unscaled_right = (x + 1) * spu->orig_frame_width / dxs;
866 unsigned int color = 0;
867 unsigned int alpha = 0;
868 unsigned int walkx, walky;
869 unsigned int base, tmp;
870 if (unscaled_right >= spu->width)
871 unscaled_right = spu->width - 1;
872 for (walky = unscaled_top; walky <= unscaled_bottom; ++walky)
873 for (walkx = unscaled_left; walkx <= unscaled_right; ++walkx) {
874 base = walky * spu->stride + walkx;
875 tmp = canon_alpha(spu->aimage[base]);
876 alpha += tmp;
877 color += tmp * spu->image[base];
879 base = y * spu->scaled_stride + x;
880 spu->scaled_image[base] = alpha ? color / alpha : 0;
881 spu->scaled_aimage[base] =
882 alpha * (1 + unscaled_bottom - unscaled_top) * (1 + unscaled_right - unscaled_left);
883 /* spu->scaled_aimage[base] =
884 alpha * dxs * dys / spu->orig_frame_width / spu->orig_frame_height; */
885 if (spu->scaled_aimage[base]) {
886 spu->scaled_aimage[base] = 256 - spu->scaled_aimage[base];
887 if (spu->scaled_aimage[base] + spu->scaled_image[base] > 255)
888 spu->scaled_image[base] = 256 - spu->scaled_aimage[base];
893 break;
894 case 2:
896 /* Best antialiasing. Very slow. */
897 /* Any pixel (x, y) represents pixels from the original
898 rectangular region comprised between the columns
899 unscaled_y and unscaled_y + 0x100 / scaley and the rows
900 unscaled_x and unscaled_x + 0x100 / scalex
902 The original rectangular region that the scaled pixel
903 represents is cut in 9 rectangular areas like this:
905 +---+-----------------+---+
906 | 1 | 2 | 3 |
907 +---+-----------------+---+
908 | | | |
909 | 4 | 5 | 6 |
910 | | | |
911 +---+-----------------+---+
912 | 7 | 8 | 9 |
913 +---+-----------------+---+
915 The width of the left column is at most one pixel and
916 it is never null and its right column is at a pixel
917 boundary. The height of the top row is at most one
918 pixel it is never null and its bottom row is at a
919 pixel boundary. The width and height of region 5 are
920 integral values. The width of the right column is
921 what remains and is less than one pixel. The height
922 of the bottom row is what remains and is less than
923 one pixel.
925 The row above 1, 2, 3 is unscaled_y. The row between
926 1, 2, 3 and 4, 5, 6 is top_low_row. The row between 4,
927 5, 6 and 7, 8, 9 is (unsigned int)unscaled_y_bottom.
928 The row beneath 7, 8, 9 is unscaled_y_bottom.
930 The column left of 1, 4, 7 is unscaled_x. The column
931 between 1, 4, 7 and 2, 5, 8 is left_right_column. The
932 column between 2, 5, 8 and 3, 6, 9 is (unsigned
933 int)unscaled_x_right. The column right of 3, 6, 9 is
934 unscaled_x_right. */
935 const double inv_scalex = (double) 0x100 / scalex;
936 const double inv_scaley = (double) 0x100 / scaley;
937 for (y = 0; y < spu->scaled_height; ++y) {
938 const double unscaled_y = y * inv_scaley;
939 const double unscaled_y_bottom = unscaled_y + inv_scaley;
940 const unsigned int top_low_row = FFMIN(unscaled_y_bottom, unscaled_y + 1.0);
941 const double top = top_low_row - unscaled_y;
942 const unsigned int height = unscaled_y_bottom > top_low_row
943 ? (unsigned int) unscaled_y_bottom - top_low_row
944 : 0;
945 const double bottom = unscaled_y_bottom > top_low_row
946 ? unscaled_y_bottom - floor(unscaled_y_bottom)
947 : 0.0;
948 for (x = 0; x < spu->scaled_width; ++x) {
949 const double unscaled_x = x * inv_scalex;
950 const double unscaled_x_right = unscaled_x + inv_scalex;
951 const unsigned int left_right_column = FFMIN(unscaled_x_right, unscaled_x + 1.0);
952 const double left = left_right_column - unscaled_x;
953 const unsigned int width = unscaled_x_right > left_right_column
954 ? (unsigned int) unscaled_x_right - left_right_column
955 : 0;
956 const double right = unscaled_x_right > left_right_column
957 ? unscaled_x_right - floor(unscaled_x_right)
958 : 0.0;
959 double color = 0.0;
960 double alpha = 0.0;
961 double tmp;
962 unsigned int base;
963 /* Now use these informations to compute a good alpha,
964 and lightness. The sum is on each of the 9
965 region's surface and alpha and lightness.
967 transformed alpha = sum(surface * alpha) / sum(surface)
968 transformed color = sum(surface * alpha * color) / sum(surface * alpha)
970 /* 1: top left part */
971 base = spu->stride * (unsigned int) unscaled_y;
972 tmp = left * top * canon_alpha(spu->aimage[base + (unsigned int) unscaled_x]);
973 alpha += tmp;
974 color += tmp * spu->image[base + (unsigned int) unscaled_x];
975 /* 2: top center part */
976 if (width > 0) {
977 unsigned int walkx;
978 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
979 base = spu->stride * (unsigned int) unscaled_y + walkx;
980 tmp = /* 1.0 * */ top * canon_alpha(spu->aimage[base]);
981 alpha += tmp;
982 color += tmp * spu->image[base];
985 /* 3: top right part */
986 if (right > 0.0) {
987 base = spu->stride * (unsigned int) unscaled_y + (unsigned int) unscaled_x_right;
988 tmp = right * top * canon_alpha(spu->aimage[base]);
989 alpha += tmp;
990 color += tmp * spu->image[base];
992 /* 4: center left part */
993 if (height > 0) {
994 unsigned int walky;
995 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
996 base = spu->stride * walky + (unsigned int) unscaled_x;
997 tmp = left /* * 1.0 */ * canon_alpha(spu->aimage[base]);
998 alpha += tmp;
999 color += tmp * spu->image[base];
1002 /* 5: center part */
1003 if (width > 0 && height > 0) {
1004 unsigned int walky;
1005 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1006 unsigned int walkx;
1007 base = spu->stride * walky;
1008 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
1009 tmp = /* 1.0 * 1.0 * */ canon_alpha(spu->aimage[base + walkx]);
1010 alpha += tmp;
1011 color += tmp * spu->image[base + walkx];
1015 /* 6: center right part */
1016 if (right > 0.0 && height > 0) {
1017 unsigned int walky;
1018 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1019 base = spu->stride * walky + (unsigned int) unscaled_x_right;
1020 tmp = right /* * 1.0 */ * canon_alpha(spu->aimage[base]);
1021 alpha += tmp;
1022 color += tmp * spu->image[base];
1025 /* 7: bottom left part */
1026 if (bottom > 0.0) {
1027 base = spu->stride * (unsigned int) unscaled_y_bottom + (unsigned int) unscaled_x;
1028 tmp = left * bottom * canon_alpha(spu->aimage[base]);
1029 alpha += tmp;
1030 color += tmp * spu->image[base];
1032 /* 8: bottom center part */
1033 if (width > 0 && bottom > 0.0) {
1034 unsigned int walkx;
1035 base = spu->stride * (unsigned int) unscaled_y_bottom;
1036 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
1037 tmp = /* 1.0 * */ bottom * canon_alpha(spu->aimage[base + walkx]);
1038 alpha += tmp;
1039 color += tmp * spu->image[base + walkx];
1042 /* 9: bottom right part */
1043 if (right > 0.0 && bottom > 0.0) {
1044 base = spu->stride * (unsigned int) unscaled_y_bottom + (unsigned int) unscaled_x_right;
1045 tmp = right * bottom * canon_alpha(spu->aimage[base]);
1046 alpha += tmp;
1047 color += tmp * spu->image[base];
1049 /* Finally mix these transparency and brightness information suitably */
1050 base = spu->scaled_stride * y + x;
1051 spu->scaled_image[base] = alpha > 0 ? color / alpha : 0;
1052 spu->scaled_aimage[base] = alpha * scalex * scaley / 0x10000;
1053 if (spu->scaled_aimage[base]) {
1054 spu->scaled_aimage[base] = 256 - spu->scaled_aimage[base];
1055 if (spu->scaled_aimage[base] + spu->scaled_image[base] > 255)
1056 spu->scaled_image[base] = 256 - spu->scaled_aimage[base];
1062 nothing_to_do:
1063 /* Kludge: draw_alpha needs width multiple of 8. */
1064 if (spu->scaled_width < spu->scaled_stride)
1065 for (y = 0; y < spu->scaled_height; ++y) {
1066 memset(spu->scaled_aimage + y * spu->scaled_stride + spu->scaled_width, 0,
1067 spu->scaled_stride - spu->scaled_width);
1069 spu->scaled_frame_width = dxs;
1070 spu->scaled_frame_height = dys;
1073 if (spu->scaled_image){
1074 switch (spu_alignment) {
1075 case 0:
1076 spu->scaled_start_row = dys*sub_pos/100;
1077 if (spu->scaled_start_row + spu->scaled_height > dys)
1078 spu->scaled_start_row = dys - spu->scaled_height;
1079 break;
1080 case 1:
1081 spu->scaled_start_row = dys*sub_pos/100 - spu->scaled_height/2;
1082 if (sub_pos >= 50 && spu->scaled_start_row + spu->scaled_height > dys)
1083 spu->scaled_start_row = dys - spu->scaled_height;
1084 break;
1085 case 2:
1086 spu->scaled_start_row = dys*sub_pos/100 - spu->scaled_height;
1087 break;
1089 draw_alpha(ctx, 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 vo_control(spu->hw_spu, 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, struct vo *hw_spu)
1180 spudec_handle_t *spu = (spudec_handle_t*)this;
1181 if (!spu)
1182 return;
1183 spu->hw_spu = hw_spu;
1184 vo_control(hw_spu, VOCTRL_SET_SPU_PALETTE, spu->global_palette);