asfheader, demux_audio: Remove some pointless be2me/le2me
[mplayer/glamo.git] / spudec.c
blob6c5213bc926add390bc1d543c426208358bd336c
1 /*
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>
13 * This file is part of MPlayer.
15 * MPlayer is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
20 * MPlayer is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License along
26 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
27 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
30 #include "config.h"
31 #include "mp_msg.h"
33 #include <errno.h>
34 #include <limits.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <unistd.h>
38 #include <string.h>
39 #include <math.h>
40 #include "libvo/video_out.h"
41 #include "spudec.h"
42 #include "vobsub.h"
43 #include "libavutil/avutil.h"
44 #include "ffmpeg_files/intreadwrite.h"
45 #include "libswscale/swscale.h"
47 /* Valid values for spu_aamode:
48 0: none (fastest, most ugly)
49 1: approximate
50 2: full (slowest)
51 3: bilinear (similiar to vobsub, fast and not too bad)
52 4: uses swscaler gaussian (this is the only one that looks good)
55 int spu_aamode = 3;
56 int spu_alignment = -1;
57 float spu_gaussvar = 1.0;
58 extern int sub_pos;
60 typedef struct packet_t packet_t;
61 struct packet_t {
62 int is_decoded;
63 unsigned char *packet;
64 int data_len;
65 unsigned int palette[4];
66 unsigned int alpha[4];
67 unsigned int control_start; /* index of start of control data */
68 unsigned int current_nibble[2]; /* next data nibble (4 bits) to be
69 processed (for RLE decoding) for
70 even and odd lines */
71 int deinterlace_oddness; /* 0 or 1, index into current_nibble */
72 unsigned int start_col, end_col;
73 unsigned int start_row, end_row;
74 unsigned int width, height, stride;
75 unsigned int start_pts, end_pts;
76 packet_t *next;
79 typedef struct {
80 packet_t *queue_head;
81 packet_t *queue_tail;
82 unsigned int global_palette[16];
83 unsigned int orig_frame_width, orig_frame_height;
84 unsigned char* packet;
85 size_t packet_reserve; /* size of the memory pointed to by packet */
86 unsigned int packet_offset; /* end of the currently assembled fragment */
87 unsigned int packet_size; /* size of the packet once all fragments are assembled */
88 int packet_pts; /* PTS for this packet */
89 unsigned int palette[4];
90 unsigned int alpha[4];
91 unsigned int cuspal[4];
92 unsigned int custom;
93 unsigned int now_pts;
94 unsigned int start_pts, end_pts;
95 unsigned int start_col, end_col;
96 unsigned int start_row, end_row;
97 unsigned int width, height, stride;
98 size_t image_size; /* Size of the image buffer */
99 unsigned char *image; /* Grayscale value */
100 unsigned char *aimage; /* Alpha value */
101 unsigned int scaled_frame_width, scaled_frame_height;
102 unsigned int scaled_start_col, scaled_start_row;
103 unsigned int scaled_width, scaled_height, scaled_stride;
104 size_t scaled_image_size;
105 unsigned char *scaled_image;
106 unsigned char *scaled_aimage;
107 int auto_palette; /* 1 if we lack a palette and must use an heuristic. */
108 int font_start_level; /* Darkest value used for the computed font */
109 struct vo *hw_spu;
110 int spu_changed;
111 unsigned int forced_subs_only; /* flag: 0=display all subtitle, !0 display only forced subtitles */
112 unsigned int is_forced_sub; /* true if current subtitle is a forced subtitle */
113 } spudec_handle_t;
115 static void spudec_queue_packet(spudec_handle_t *this, packet_t *packet)
117 if (this->queue_head == NULL)
118 this->queue_head = packet;
119 else
120 this->queue_tail->next = packet;
121 this->queue_tail = packet;
124 static packet_t *spudec_dequeue_packet(spudec_handle_t *this)
126 packet_t *retval = this->queue_head;
128 this->queue_head = retval->next;
129 if (this->queue_head == NULL)
130 this->queue_tail = NULL;
132 return retval;
135 static void spudec_free_packet(packet_t *packet)
137 if (packet->packet != NULL)
138 free(packet->packet);
139 free(packet);
142 static inline unsigned int get_be16(const unsigned char *p)
144 return (p[0] << 8) + p[1];
147 static inline unsigned int get_be24(const unsigned char *p)
149 return (get_be16(p) << 8) + p[2];
152 static void next_line(packet_t *packet)
154 if (packet->current_nibble[packet->deinterlace_oddness] % 2)
155 packet->current_nibble[packet->deinterlace_oddness]++;
156 packet->deinterlace_oddness = (packet->deinterlace_oddness + 1) % 2;
159 static inline unsigned char get_nibble(packet_t *packet)
161 unsigned char nib;
162 unsigned int *nibblep = packet->current_nibble + packet->deinterlace_oddness;
163 if (*nibblep / 2 >= packet->control_start) {
164 mp_msg(MSGT_SPUDEC,MSGL_WARN, "SPUdec: ERROR: get_nibble past end of packet\n");
165 return 0;
167 nib = packet->packet[*nibblep / 2];
168 if (*nibblep % 2)
169 nib &= 0xf;
170 else
171 nib >>= 4;
172 ++*nibblep;
173 return nib;
176 static inline int mkalpha(int i)
178 /* In mplayer's alpha planes, 0 is transparent, then 1 is nearly
179 opaque upto 255 which is fully opaque */
180 // extend 4 -> 8 bit
181 i |= i << 4;
182 return (uint8_t)(-i);
185 /* Cut the sub to visible part */
186 static inline void spudec_cut_image(spudec_handle_t *this)
188 unsigned int fy, ly;
189 unsigned int first_y, last_y;
190 unsigned char *image;
191 unsigned char *aimage;
193 if (this->stride == 0 || this->height == 0) {
194 return;
197 for (fy = 0; fy < this->image_size && !this->aimage[fy]; fy++);
198 for (ly = this->stride * this->height-1; ly && !this->aimage[ly]; ly--);
199 first_y = fy / this->stride;
200 last_y = ly / this->stride;
201 //printf("first_y: %d, last_y: %d\n", first_y, last_y);
202 this->start_row += first_y;
204 // Some subtitles trigger this condition
205 if (last_y + 1 > first_y ) {
206 this->height = last_y - first_y +1;
207 } else {
208 this->height = 0;
209 this->image_size = 0;
210 return;
213 // printf("new h %d new start %d (sz %d st %d)---\n\n", this->height, this->start_row, this->image_size, this->stride);
215 image = malloc(2 * this->stride * this->height);
216 if(image){
217 this->image_size = this->stride * this->height;
218 aimage = image + this->image_size;
219 memcpy(image, this->image + this->stride * first_y, this->image_size);
220 memcpy(aimage, this->aimage + this->stride * first_y, this->image_size);
221 free(this->image);
222 this->image = image;
223 this->aimage = aimage;
224 } else {
225 mp_msg(MSGT_SPUDEC, MSGL_FATAL, "Fatal: update_spu: malloc requested %d bytes\n", 2 * this->stride * this->height);
230 static int spudec_alloc_image(spudec_handle_t *this, int stride, int height)
232 if (this->width > stride) // just a safeguard
233 this->width = stride;
234 this->stride = stride;
235 this->height = height;
236 if (this->image_size < this->stride * this->height) {
237 if (this->image != NULL) {
238 free(this->image);
239 this->image_size = 0;
241 this->image = malloc(2 * this->stride * this->height);
242 if (this->image) {
243 this->image_size = this->stride * this->height;
244 this->aimage = this->image + this->image_size;
247 return this->image != NULL;
250 static void spudec_process_data(spudec_handle_t *this, packet_t *packet)
252 unsigned int cmap[4], alpha[4];
253 unsigned int i, x, y;
255 this->scaled_frame_width = 0;
256 this->scaled_frame_height = 0;
257 this->start_col = packet->start_col;
258 this->end_col = packet->end_col;
259 this->start_row = packet->start_row;
260 this->end_row = packet->end_row;
261 this->height = packet->height;
262 this->width = packet->width;
263 this->stride = packet->stride;
264 for (i = 0; i < 4; ++i) {
265 alpha[i] = mkalpha(packet->alpha[i]);
266 if (this->custom && (this->cuspal[i] >> 31) != 0)
267 alpha[i] = 0;
268 if (alpha[i] == 0)
269 cmap[i] = 0;
270 else if (this->custom){
271 cmap[i] = ((this->cuspal[i] >> 16) & 0xff);
272 if (cmap[i] + alpha[i] > 255)
273 cmap[i] = 256 - alpha[i];
275 else {
276 cmap[i] = ((this->global_palette[packet->palette[i]] >> 16) & 0xff);
277 if (cmap[i] + alpha[i] > 255)
278 cmap[i] = 256 - alpha[i];
282 if (!spudec_alloc_image(this, this->stride, this->height))
283 return;
285 /* Kludge: draw_alpha needs width multiple of 8. */
286 if (this->width < this->stride)
287 for (y = 0; y < this->height; ++y) {
288 memset(this->aimage + y * this->stride + this->width, 0, this->stride - this->width);
289 /* FIXME: Why is this one needed? */
290 memset(this->image + y * this->stride + this->width, 0, this->stride - this->width);
293 i = packet->current_nibble[1];
294 x = 0;
295 y = 0;
296 while (packet->current_nibble[0] < i
297 && packet->current_nibble[1] / 2 < packet->control_start
298 && y < this->height) {
299 unsigned int len, color;
300 unsigned int rle = 0;
301 rle = get_nibble(packet);
302 if (rle < 0x04) {
303 rle = (rle << 4) | get_nibble(packet);
304 if (rle < 0x10) {
305 rle = (rle << 4) | get_nibble(packet);
306 if (rle < 0x040) {
307 rle = (rle << 4) | get_nibble(packet);
308 if (rle < 0x0004)
309 rle |= ((this->width - x) << 2);
313 color = 3 - (rle & 0x3);
314 len = rle >> 2;
315 if (len > this->width - x || len == 0)
316 len = this->width - x;
317 /* FIXME have to use palette and alpha map*/
318 memset(this->image + y * this->stride + x, cmap[color], len);
319 memset(this->aimage + y * this->stride + x, alpha[color], len);
320 x += len;
321 if (x >= this->width) {
322 next_line(packet);
323 x = 0;
324 ++y;
327 spudec_cut_image(this);
332 This function tries to create a usable palette.
333 It determines how many non-transparent colors are used, and assigns different
334 gray scale values to each color.
335 I tested it with four streams and even got something readable. Half of the
336 times I got black characters with white around and half the reverse.
338 static void compute_palette(spudec_handle_t *this, packet_t *packet)
340 int used[16],i,cused,start,step,color;
342 memset(used, 0, sizeof(used));
343 for (i=0; i<4; i++)
344 if (packet->alpha[i]) /* !Transparent? */
345 used[packet->palette[i]] = 1;
346 for (cused=0, i=0; i<16; i++)
347 if (used[i]) cused++;
348 if (!cused) return;
349 if (cused == 1) {
350 start = 0x80;
351 step = 0;
352 } else {
353 start = this->font_start_level;
354 step = (0xF0-this->font_start_level)/(cused-1);
356 memset(used, 0, sizeof(used));
357 for (i=0; i<4; i++) {
358 color = packet->palette[i];
359 if (packet->alpha[i] && !used[color]) { /* not assigned? */
360 used[color] = 1;
361 this->global_palette[color] = start<<16;
362 start += step;
367 static void spudec_process_control(spudec_handle_t *this, int pts100)
369 int a,b,c,d; /* Temporary vars */
370 unsigned int date, type;
371 unsigned int off;
372 unsigned int start_off = 0;
373 unsigned int next_off;
374 unsigned int start_pts = 0;
375 unsigned int end_pts = 0;
376 unsigned int current_nibble[2] = {0, 0};
377 unsigned int control_start;
378 unsigned int display = 0;
379 unsigned int start_col = 0;
380 unsigned int end_col = 0;
381 unsigned int start_row = 0;
382 unsigned int end_row = 0;
383 unsigned int width = 0;
384 unsigned int height = 0;
385 unsigned int stride = 0;
387 control_start = get_be16(this->packet + 2);
388 next_off = control_start;
389 while (start_off != next_off) {
390 start_off = next_off;
391 date = get_be16(this->packet + start_off) * 1024;
392 next_off = get_be16(this->packet + start_off + 2);
393 mp_msg(MSGT_SPUDEC,MSGL_DBG2, "date=%d\n", date);
394 off = start_off + 4;
395 for (type = this->packet[off++]; type != 0xff; type = this->packet[off++]) {
396 mp_msg(MSGT_SPUDEC,MSGL_DBG2, "cmd=%d ",type);
397 switch(type) {
398 case 0x00:
399 /* Menu ID, 1 byte */
400 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Menu ID\n");
401 /* shouldn't a Menu ID type force display start? */
402 start_pts = pts100 < 0 && -pts100 >= date ? 0 : pts100 + date;
403 end_pts = UINT_MAX;
404 display = 1;
405 this->is_forced_sub=~0; // current subtitle is forced
406 break;
407 case 0x01:
408 /* Start display */
409 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Start display!\n");
410 start_pts = pts100 < 0 && -pts100 >= date ? 0 : pts100 + date;
411 end_pts = UINT_MAX;
412 display = 1;
413 this->is_forced_sub=0;
414 break;
415 case 0x02:
416 /* Stop display */
417 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Stop display!\n");
418 end_pts = pts100 < 0 && -pts100 >= date ? 0 : pts100 + date;
419 break;
420 case 0x03:
421 /* Palette */
422 this->palette[0] = this->packet[off] >> 4;
423 this->palette[1] = this->packet[off] & 0xf;
424 this->palette[2] = this->packet[off + 1] >> 4;
425 this->palette[3] = this->packet[off + 1] & 0xf;
426 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Palette %d, %d, %d, %d\n",
427 this->palette[0], this->palette[1], this->palette[2], this->palette[3]);
428 off+=2;
429 break;
430 case 0x04:
431 /* Alpha */
432 a = this->packet[off] >> 4;
433 b = this->packet[off] & 0xf;
434 c = this->packet[off + 1] >> 4;
435 d = this->packet[off + 1] & 0xf;
436 // Note: some DVDs change these values to create a fade-in/fade-out effect
437 // We can not handle this, so just keep the highest value during the display time.
438 if (display) {
439 a = FFMAX(a, this->alpha[0]);
440 b = FFMAX(b, this->alpha[1]);
441 c = FFMAX(c, this->alpha[2]);
442 d = FFMAX(d, this->alpha[3]);
444 this->alpha[0] = a;
445 this->alpha[1] = b;
446 this->alpha[2] = c;
447 this->alpha[3] = d;
448 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Alpha %d, %d, %d, %d\n",
449 this->alpha[0], this->alpha[1], this->alpha[2], this->alpha[3]);
450 off+=2;
451 break;
452 case 0x05:
453 /* Co-ords */
454 a = get_be24(this->packet + off);
455 b = get_be24(this->packet + off + 3);
456 start_col = a >> 12;
457 end_col = a & 0xfff;
458 width = (end_col < start_col) ? 0 : end_col - start_col + 1;
459 stride = (width + 7) & ~7; /* Kludge: draw_alpha needs width multiple of 8 */
460 start_row = b >> 12;
461 end_row = b & 0xfff;
462 height = (end_row < start_row) ? 0 : end_row - start_row /* + 1 */;
463 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Coords col: %d - %d row: %d - %d (%dx%d)\n",
464 start_col, end_col, start_row, end_row,
465 width, height);
466 off+=6;
467 break;
468 case 0x06:
469 /* Graphic lines */
470 current_nibble[0] = 2 * get_be16(this->packet + off);
471 current_nibble[1] = 2 * get_be16(this->packet + off + 2);
472 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Graphic offset 1: %d offset 2: %d\n",
473 current_nibble[0] / 2, current_nibble[1] / 2);
474 off+=4;
475 break;
476 case 0xff:
477 /* All done, bye-bye */
478 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Done!\n");
479 return;
480 // break;
481 default:
482 mp_msg(MSGT_SPUDEC,MSGL_WARN,"spudec: Error determining control type 0x%02x. Skipping %d bytes.\n",
483 type, next_off - off);
484 goto next_control;
487 next_control:
488 if (!display)
489 continue;
490 if (end_pts == UINT_MAX && start_off != next_off) {
491 end_pts = get_be16(this->packet + next_off) * 1024;
492 end_pts = 1 - pts100 >= end_pts ? 0 : pts100 + end_pts - 1;
494 if (end_pts > 0) {
495 packet_t *packet = calloc(1, sizeof(packet_t));
496 int i;
497 packet->start_pts = start_pts;
498 packet->end_pts = end_pts;
499 packet->current_nibble[0] = current_nibble[0];
500 packet->current_nibble[1] = current_nibble[1];
501 packet->start_row = start_row;
502 packet->end_row = end_row;
503 packet->start_col = start_col;
504 packet->end_col = end_col;
505 packet->width = width;
506 packet->height = height;
507 packet->stride = stride;
508 packet->control_start = control_start;
509 for (i=0; i<4; i++) {
510 packet->alpha[i] = this->alpha[i];
511 packet->palette[i] = this->palette[i];
513 packet->packet = malloc(this->packet_size);
514 memcpy(packet->packet, this->packet, this->packet_size);
515 spudec_queue_packet(this, packet);
520 static void spudec_decode(spudec_handle_t *this, int pts100)
522 if (!this->hw_spu)
523 spudec_process_control(this, pts100);
524 else if (pts100 >= 0) {
525 static vo_mpegpes_t packet = { NULL, 0, 0x20, 0 };
526 static vo_mpegpes_t *pkg=&packet;
527 packet.data = this->packet;
528 packet.size = this->packet_size;
529 packet.timestamp = pts100;
530 vo_draw_frame(this->hw_spu, (uint8_t**)&pkg);
534 int spudec_changed(void * this)
536 spudec_handle_t * spu = (spudec_handle_t*)this;
537 return spu->spu_changed || spu->now_pts > spu->end_pts;
540 void spudec_assemble(void *this, unsigned char *packet, unsigned int len, int pts100)
542 spudec_handle_t *spu = (spudec_handle_t*)this;
543 // spudec_heartbeat(this, pts100);
544 if (len < 2) {
545 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: packet too short\n");
546 return;
548 spu->packet_pts = pts100;
549 if (spu->packet_offset == 0) {
550 unsigned int len2 = get_be16(packet);
551 // Start new fragment
552 if (spu->packet_reserve < len2) {
553 if (spu->packet != NULL)
554 free(spu->packet);
555 spu->packet = malloc(len2);
556 spu->packet_reserve = spu->packet != NULL ? len2 : 0;
558 if (spu->packet != NULL) {
559 spu->packet_size = len2;
560 if (len > len2) {
561 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: invalid frag len / len2: %d / %d \n", len, len2);
562 return;
564 memcpy(spu->packet, packet, len);
565 spu->packet_offset = len;
566 spu->packet_pts = pts100;
568 } else {
569 // Continue current fragment
570 if (spu->packet_size < spu->packet_offset + len){
571 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: invalid fragment\n");
572 spu->packet_size = spu->packet_offset = 0;
573 return;
574 } else {
575 memcpy(spu->packet + spu->packet_offset, packet, len);
576 spu->packet_offset += len;
579 #if 1
580 // check if we have a complete packet (unfortunatelly packet_size is bad
581 // for some disks)
582 // [cb] packet_size is padded to be even -> may be one byte too long
583 if ((spu->packet_offset == spu->packet_size) ||
584 ((spu->packet_offset + 1) == spu->packet_size)){
585 unsigned int x=0,y;
586 while(x+4<=spu->packet_offset){
587 y=get_be16(spu->packet+x+2); // next control pointer
588 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPUtest: x=%d y=%d off=%d size=%d\n",x,y,spu->packet_offset,spu->packet_size);
589 if(x>=4 && x==y){ // if it points to self - we're done!
590 // we got it!
591 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPUgot: off=%d size=%d \n",spu->packet_offset,spu->packet_size);
592 spudec_decode(spu, pts100);
593 spu->packet_offset = 0;
594 break;
596 if(y<=x || y>=spu->packet_size){ // invalid?
597 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUtest: broken packet!!!!! y=%d < x=%d\n",y,x);
598 spu->packet_size = spu->packet_offset = 0;
599 break;
601 x=y;
603 // [cb] packet is done; start new packet
604 spu->packet_offset = 0;
606 #else
607 if (spu->packet_offset == spu->packet_size) {
608 spudec_decode(spu, pts100);
609 spu->packet_offset = 0;
611 #endif
614 void spudec_reset(void *this) // called after seek
616 spudec_handle_t *spu = (spudec_handle_t*)this;
617 while (spu->queue_head)
618 spudec_free_packet(spudec_dequeue_packet(spu));
619 spu->now_pts = 0;
620 spu->end_pts = 0;
621 spu->packet_size = spu->packet_offset = 0;
624 void spudec_heartbeat(void *this, unsigned int pts100)
626 spudec_handle_t *spu = (spudec_handle_t*) this;
627 spu->now_pts = pts100;
629 // TODO: detect and handle broken timestamps (e.g. due to wrapping)
630 while (spu->queue_head != NULL && pts100 >= spu->queue_head->start_pts) {
631 packet_t *packet = spudec_dequeue_packet(spu);
632 spu->start_pts = packet->start_pts;
633 spu->end_pts = packet->end_pts;
634 if (packet->is_decoded) {
635 free(spu->image);
636 spu->image_size = packet->data_len;
637 spu->image = packet->packet;
638 spu->aimage = packet->packet + packet->stride * packet->height;
639 packet->packet = NULL;
640 spu->width = packet->width;
641 spu->height = packet->height;
642 spu->stride = packet->stride;
643 spu->start_col = packet->start_col;
644 spu->start_row = packet->start_row;
646 // TODO use correct values
647 spu->scaled_frame_width = 0;
648 spu->scaled_frame_height = 0;
649 spu->orig_frame_width = 1920;
650 spu->orig_frame_height = 1080;
651 } else {
652 if (spu->auto_palette)
653 compute_palette(spu, packet);
654 spudec_process_data(spu, packet);
656 spudec_free_packet(packet);
657 spu->spu_changed = 1;
661 int spudec_visible(void *this){
662 spudec_handle_t *spu = (spudec_handle_t *)this;
663 int ret=(spu->start_pts <= spu->now_pts &&
664 spu->now_pts < spu->end_pts &&
665 spu->height > 0);
666 // printf("spu visible: %d \n",ret);
667 return ret;
670 void spudec_set_forced_subs_only(void * const this, const unsigned int flag)
672 if(this){
673 ((spudec_handle_t *)this)->forced_subs_only=flag;
674 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPU: Display only forced subs now %s\n", flag ? "enabled": "disabled");
678 void spudec_draw(void *this, void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride))
680 spudec_handle_t *spu = (spudec_handle_t *)this;
681 if (spudec_visible(spu))
683 draw_alpha(spu->start_col, spu->start_row, spu->width, spu->height,
684 spu->image, spu->aimage, spu->stride);
685 spu->spu_changed = 0;
689 /* calc the bbox for spudec subs */
690 void spudec_calc_bbox(void *me, unsigned int dxs, unsigned int dys, unsigned int* bbox)
692 spudec_handle_t *spu;
693 spu = (spudec_handle_t *)me;
694 if (spu->orig_frame_width == 0 || spu->orig_frame_height == 0
695 || (spu->orig_frame_width == dxs && spu->orig_frame_height == dys)) {
696 bbox[0] = spu->start_col;
697 bbox[1] = spu->start_col + spu->width;
698 bbox[2] = spu->start_row;
699 bbox[3] = spu->start_row + spu->height;
701 else if (spu->scaled_frame_width != dxs || spu->scaled_frame_height != dys) {
702 unsigned int scalex = 0x100 * dxs / spu->orig_frame_width;
703 unsigned int scaley = 0x100 * dys / spu->orig_frame_height;
704 bbox[0] = spu->start_col * scalex / 0x100;
705 bbox[1] = spu->start_col * scalex / 0x100 + spu->width * scalex / 0x100;
706 switch (spu_alignment) {
707 case 0:
708 bbox[3] = dys*sub_pos/100 + spu->height * scaley / 0x100;
709 if (bbox[3] > dys) bbox[3] = dys;
710 bbox[2] = bbox[3] - spu->height * scaley / 0x100;
711 break;
712 case 1:
713 if (sub_pos < 50) {
714 bbox[2] = dys*sub_pos/100 - spu->height * scaley / 0x200;
715 bbox[3] = bbox[2] + spu->height;
716 } else {
717 bbox[3] = dys*sub_pos/100 + spu->height * scaley / 0x200;
718 if (bbox[3] > dys) bbox[3] = dys;
719 bbox[2] = bbox[3] - spu->height * scaley / 0x100;
721 break;
722 case 2:
723 bbox[2] = dys*sub_pos/100 - spu->height * scaley / 0x100;
724 bbox[3] = bbox[2] + spu->height;
725 break;
726 default: /* -1 */
727 bbox[2] = spu->start_row * scaley / 0x100;
728 bbox[3] = spu->start_row * scaley / 0x100 + spu->height * scaley / 0x100;
729 break;
731 } else {
732 mp_msg(MSGT_SPUDEC, MSGL_ERR, "Bad values in spudec_calc_bbox\n");
733 bbox[0] = bbox[1] = bbox[2] = bbox[3] = 0;
736 /* transform mplayer's alpha value into an opacity value that is linear */
737 static inline int canon_alpha(int alpha)
739 return alpha ? 256 - alpha : 0;
742 typedef struct {
743 unsigned position;
744 unsigned left_up;
745 unsigned right_down;
746 }scale_pixel;
749 static void scale_table(unsigned int start_src, unsigned int start_tar, unsigned int end_src, unsigned int end_tar, scale_pixel * table)
751 unsigned int t;
752 unsigned int delta_src = end_src - start_src;
753 unsigned int delta_tar = end_tar - start_tar;
754 int src = 0;
755 int src_step;
756 if (delta_src == 0 || delta_tar == 0) {
757 return;
759 src_step = (delta_src << 16) / delta_tar >>1;
760 for (t = 0; t<=delta_tar; src += (src_step << 1), t++){
761 table[t].position= FFMIN(src >> 16, end_src - 1);
762 table[t].right_down = src & 0xffff;
763 table[t].left_up = 0x10000 - table[t].right_down;
767 /* bilinear scale, similar to vobsub's code */
768 static void scale_image(int x, int y, scale_pixel* table_x, scale_pixel* table_y, spudec_handle_t * spu)
770 int alpha[4];
771 int color[4];
772 unsigned int scale[4];
773 int base = table_y[y].position * spu->stride + table_x[x].position;
774 int scaled = y * spu->scaled_stride + x;
775 alpha[0] = canon_alpha(spu->aimage[base]);
776 alpha[1] = canon_alpha(spu->aimage[base + 1]);
777 alpha[2] = canon_alpha(spu->aimage[base + spu->stride]);
778 alpha[3] = canon_alpha(spu->aimage[base + spu->stride + 1]);
779 color[0] = spu->image[base];
780 color[1] = spu->image[base + 1];
781 color[2] = spu->image[base + spu->stride];
782 color[3] = spu->image[base + spu->stride + 1];
783 scale[0] = (table_x[x].left_up * table_y[y].left_up >> 16) * alpha[0];
784 if (table_y[y].left_up == 0x10000) // necessary to avoid overflow-case
785 scale[0] = table_x[x].left_up * alpha[0];
786 scale[1] = (table_x[x].right_down * table_y[y].left_up >>16) * alpha[1];
787 scale[2] = (table_x[x].left_up * table_y[y].right_down >> 16) * alpha[2];
788 scale[3] = (table_x[x].right_down * table_y[y].right_down >> 16) * alpha[3];
789 spu->scaled_image[scaled] = (color[0] * scale[0] + color[1] * scale[1] + color[2] * scale[2] + color[3] * scale[3])>>24;
790 spu->scaled_aimage[scaled] = (scale[0] + scale[1] + scale[2] + scale[3]) >> 16;
791 if (spu->scaled_aimage[scaled]){
792 // ensure that MPlayer's simplified alpha-blending can not overflow
793 spu->scaled_image[scaled] = FFMIN(spu->scaled_image[scaled], spu->scaled_aimage[scaled]);
794 // convert to MPlayer-style alpha
795 spu->scaled_aimage[scaled] = -spu->scaled_aimage[scaled];
799 static void sws_spu_image(unsigned char *d1, unsigned char *d2, int dw, int dh,
800 int ds, unsigned char *s1, unsigned char *s2, int sw,
801 int sh, int ss)
803 struct SwsContext *ctx;
804 static SwsFilter filter;
805 static int firsttime = 1;
806 static float oldvar;
807 int i;
809 if (!firsttime && oldvar != spu_gaussvar) sws_freeVec(filter.lumH);
810 if (firsttime) {
811 filter.lumH = filter.lumV =
812 filter.chrH = filter.chrV = sws_getGaussianVec(spu_gaussvar, 3.0);
813 sws_normalizeVec(filter.lumH, 1.0);
814 firsttime = 0;
815 oldvar = spu_gaussvar;
818 ctx=sws_getContext(sw, sh, PIX_FMT_GRAY8, dw, dh, PIX_FMT_GRAY8, SWS_GAUSS, &filter, NULL, NULL);
819 sws_scale(ctx,&s1,&ss,0,sh,&d1,&ds);
820 for (i=ss*sh-1; i>=0; i--) if (!s2[i]) s2[i] = 255; //else s2[i] = 1;
821 sws_scale(ctx,&s2,&ss,0,sh,&d2,&ds);
822 for (i=ds*dh-1; i>=0; i--) if (d2[i]==0) d2[i] = 1; else if (d2[i]==255) d2[i] = 0;
823 sws_freeContext(ctx);
826 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)
828 spudec_handle_t *spu = (spudec_handle_t *)me;
829 scale_pixel *table_x;
830 scale_pixel *table_y;
832 if (spudec_visible(spu)) {
834 // check if only forced subtitles are requested
835 if( (spu->forced_subs_only) && !(spu->is_forced_sub) ){
836 return;
839 if (!(spu_aamode&16) && (spu->orig_frame_width == 0 || spu->orig_frame_height == 0
840 || (spu->orig_frame_width == dxs && spu->orig_frame_height == dys))) {
841 if (spu->image)
843 draw_alpha(ctx, spu->start_col, spu->start_row, spu->width, spu->height,
844 spu->image, spu->aimage, spu->stride);
845 spu->spu_changed = 0;
848 else {
849 if (spu->scaled_frame_width != dxs || spu->scaled_frame_height != dys) { /* Resizing is needed */
850 /* scaled_x = scalex * x / 0x100
851 scaled_y = scaley * y / 0x100
852 order of operations is important because of rounding. */
853 unsigned int scalex = 0x100 * dxs / spu->orig_frame_width;
854 unsigned int scaley = 0x100 * dys / spu->orig_frame_height;
855 spu->scaled_start_col = spu->start_col * scalex / 0x100;
856 spu->scaled_start_row = spu->start_row * scaley / 0x100;
857 spu->scaled_width = spu->width * scalex / 0x100;
858 spu->scaled_height = spu->height * scaley / 0x100;
859 /* Kludge: draw_alpha needs width multiple of 8 */
860 spu->scaled_stride = (spu->scaled_width + 7) & ~7;
861 if (spu->scaled_image_size < spu->scaled_stride * spu->scaled_height) {
862 if (spu->scaled_image) {
863 free(spu->scaled_image);
864 spu->scaled_image_size = 0;
866 spu->scaled_image = malloc(2 * spu->scaled_stride * spu->scaled_height);
867 if (spu->scaled_image) {
868 spu->scaled_image_size = spu->scaled_stride * spu->scaled_height;
869 spu->scaled_aimage = spu->scaled_image + spu->scaled_image_size;
872 if (spu->scaled_image) {
873 unsigned int x, y;
874 if (spu->scaled_width <= 1 || spu->scaled_height <= 1) {
875 goto nothing_to_do;
877 switch(spu_aamode&15) {
878 case 4:
879 sws_spu_image(spu->scaled_image, spu->scaled_aimage,
880 spu->scaled_width, spu->scaled_height, spu->scaled_stride,
881 spu->image, spu->aimage, spu->width, spu->height, spu->stride);
882 break;
883 case 3:
884 table_x = calloc(spu->scaled_width, sizeof(scale_pixel));
885 table_y = calloc(spu->scaled_height, sizeof(scale_pixel));
886 if (!table_x || !table_y) {
887 mp_msg(MSGT_SPUDEC, MSGL_FATAL, "Fatal: spudec_draw_scaled: calloc failed\n");
889 scale_table(0, 0, spu->width - 1, spu->scaled_width - 1, table_x);
890 scale_table(0, 0, spu->height - 1, spu->scaled_height - 1, table_y);
891 for (y = 0; y < spu->scaled_height; y++)
892 for (x = 0; x < spu->scaled_width; x++)
893 scale_image(x, y, table_x, table_y, spu);
894 free(table_x);
895 free(table_y);
896 break;
897 case 0:
898 /* no antialiasing */
899 for (y = 0; y < spu->scaled_height; ++y) {
900 int unscaled_y = y * 0x100 / scaley;
901 int strides = spu->stride * unscaled_y;
902 int scaled_strides = spu->scaled_stride * y;
903 for (x = 0; x < spu->scaled_width; ++x) {
904 int unscaled_x = x * 0x100 / scalex;
905 spu->scaled_image[scaled_strides + x] = spu->image[strides + unscaled_x];
906 spu->scaled_aimage[scaled_strides + x] = spu->aimage[strides + unscaled_x];
909 break;
910 case 1:
912 /* Intermediate antialiasing. */
913 for (y = 0; y < spu->scaled_height; ++y) {
914 const unsigned int unscaled_top = y * spu->orig_frame_height / dys;
915 unsigned int unscaled_bottom = (y + 1) * spu->orig_frame_height / dys;
916 if (unscaled_bottom >= spu->height)
917 unscaled_bottom = spu->height - 1;
918 for (x = 0; x < spu->scaled_width; ++x) {
919 const unsigned int unscaled_left = x * spu->orig_frame_width / dxs;
920 unsigned int unscaled_right = (x + 1) * spu->orig_frame_width / dxs;
921 unsigned int color = 0;
922 unsigned int alpha = 0;
923 unsigned int walkx, walky;
924 unsigned int base, tmp;
925 if (unscaled_right >= spu->width)
926 unscaled_right = spu->width - 1;
927 for (walky = unscaled_top; walky <= unscaled_bottom; ++walky)
928 for (walkx = unscaled_left; walkx <= unscaled_right; ++walkx) {
929 base = walky * spu->stride + walkx;
930 tmp = canon_alpha(spu->aimage[base]);
931 alpha += tmp;
932 color += tmp * spu->image[base];
934 base = y * spu->scaled_stride + x;
935 spu->scaled_image[base] = alpha ? color / alpha : 0;
936 spu->scaled_aimage[base] =
937 alpha * (1 + unscaled_bottom - unscaled_top) * (1 + unscaled_right - unscaled_left);
938 /* spu->scaled_aimage[base] =
939 alpha * dxs * dys / spu->orig_frame_width / spu->orig_frame_height; */
940 if (spu->scaled_aimage[base]) {
941 spu->scaled_aimage[base] = 256 - spu->scaled_aimage[base];
942 if (spu->scaled_aimage[base] + spu->scaled_image[base] > 255)
943 spu->scaled_image[base] = 256 - spu->scaled_aimage[base];
948 break;
949 case 2:
951 /* Best antialiasing. Very slow. */
952 /* Any pixel (x, y) represents pixels from the original
953 rectangular region comprised between the columns
954 unscaled_y and unscaled_y + 0x100 / scaley and the rows
955 unscaled_x and unscaled_x + 0x100 / scalex
957 The original rectangular region that the scaled pixel
958 represents is cut in 9 rectangular areas like this:
960 +---+-----------------+---+
961 | 1 | 2 | 3 |
962 +---+-----------------+---+
963 | | | |
964 | 4 | 5 | 6 |
965 | | | |
966 +---+-----------------+---+
967 | 7 | 8 | 9 |
968 +---+-----------------+---+
970 The width of the left column is at most one pixel and
971 it is never null and its right column is at a pixel
972 boundary. The height of the top row is at most one
973 pixel it is never null and its bottom row is at a
974 pixel boundary. The width and height of region 5 are
975 integral values. The width of the right column is
976 what remains and is less than one pixel. The height
977 of the bottom row is what remains and is less than
978 one pixel.
980 The row above 1, 2, 3 is unscaled_y. The row between
981 1, 2, 3 and 4, 5, 6 is top_low_row. The row between 4,
982 5, 6 and 7, 8, 9 is (unsigned int)unscaled_y_bottom.
983 The row beneath 7, 8, 9 is unscaled_y_bottom.
985 The column left of 1, 4, 7 is unscaled_x. The column
986 between 1, 4, 7 and 2, 5, 8 is left_right_column. The
987 column between 2, 5, 8 and 3, 6, 9 is (unsigned
988 int)unscaled_x_right. The column right of 3, 6, 9 is
989 unscaled_x_right. */
990 const double inv_scalex = (double) 0x100 / scalex;
991 const double inv_scaley = (double) 0x100 / scaley;
992 for (y = 0; y < spu->scaled_height; ++y) {
993 const double unscaled_y = y * inv_scaley;
994 const double unscaled_y_bottom = unscaled_y + inv_scaley;
995 const unsigned int top_low_row = FFMIN(unscaled_y_bottom, unscaled_y + 1.0);
996 const double top = top_low_row - unscaled_y;
997 const unsigned int height = unscaled_y_bottom > top_low_row
998 ? (unsigned int) unscaled_y_bottom - top_low_row
999 : 0;
1000 const double bottom = unscaled_y_bottom > top_low_row
1001 ? unscaled_y_bottom - floor(unscaled_y_bottom)
1002 : 0.0;
1003 for (x = 0; x < spu->scaled_width; ++x) {
1004 const double unscaled_x = x * inv_scalex;
1005 const double unscaled_x_right = unscaled_x + inv_scalex;
1006 const unsigned int left_right_column = FFMIN(unscaled_x_right, unscaled_x + 1.0);
1007 const double left = left_right_column - unscaled_x;
1008 const unsigned int width = unscaled_x_right > left_right_column
1009 ? (unsigned int) unscaled_x_right - left_right_column
1010 : 0;
1011 const double right = unscaled_x_right > left_right_column
1012 ? unscaled_x_right - floor(unscaled_x_right)
1013 : 0.0;
1014 double color = 0.0;
1015 double alpha = 0.0;
1016 double tmp;
1017 unsigned int base;
1018 /* Now use these informations to compute a good alpha,
1019 and lightness. The sum is on each of the 9
1020 region's surface and alpha and lightness.
1022 transformed alpha = sum(surface * alpha) / sum(surface)
1023 transformed color = sum(surface * alpha * color) / sum(surface * alpha)
1025 /* 1: top left part */
1026 base = spu->stride * (unsigned int) unscaled_y;
1027 tmp = left * top * canon_alpha(spu->aimage[base + (unsigned int) unscaled_x]);
1028 alpha += tmp;
1029 color += tmp * spu->image[base + (unsigned int) unscaled_x];
1030 /* 2: top center part */
1031 if (width > 0) {
1032 unsigned int walkx;
1033 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
1034 base = spu->stride * (unsigned int) unscaled_y + walkx;
1035 tmp = /* 1.0 * */ top * canon_alpha(spu->aimage[base]);
1036 alpha += tmp;
1037 color += tmp * spu->image[base];
1040 /* 3: top right part */
1041 if (right > 0.0) {
1042 base = spu->stride * (unsigned int) unscaled_y + (unsigned int) unscaled_x_right;
1043 tmp = right * top * canon_alpha(spu->aimage[base]);
1044 alpha += tmp;
1045 color += tmp * spu->image[base];
1047 /* 4: center left part */
1048 if (height > 0) {
1049 unsigned int walky;
1050 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1051 base = spu->stride * walky + (unsigned int) unscaled_x;
1052 tmp = left /* * 1.0 */ * canon_alpha(spu->aimage[base]);
1053 alpha += tmp;
1054 color += tmp * spu->image[base];
1057 /* 5: center part */
1058 if (width > 0 && height > 0) {
1059 unsigned int walky;
1060 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1061 unsigned int walkx;
1062 base = spu->stride * walky;
1063 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
1064 tmp = /* 1.0 * 1.0 * */ canon_alpha(spu->aimage[base + walkx]);
1065 alpha += tmp;
1066 color += tmp * spu->image[base + walkx];
1070 /* 6: center right part */
1071 if (right > 0.0 && height > 0) {
1072 unsigned int walky;
1073 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1074 base = spu->stride * walky + (unsigned int) unscaled_x_right;
1075 tmp = right /* * 1.0 */ * canon_alpha(spu->aimage[base]);
1076 alpha += tmp;
1077 color += tmp * spu->image[base];
1080 /* 7: bottom left part */
1081 if (bottom > 0.0) {
1082 base = spu->stride * (unsigned int) unscaled_y_bottom + (unsigned int) unscaled_x;
1083 tmp = left * bottom * canon_alpha(spu->aimage[base]);
1084 alpha += tmp;
1085 color += tmp * spu->image[base];
1087 /* 8: bottom center part */
1088 if (width > 0 && bottom > 0.0) {
1089 unsigned int walkx;
1090 base = spu->stride * (unsigned int) unscaled_y_bottom;
1091 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
1092 tmp = /* 1.0 * */ bottom * canon_alpha(spu->aimage[base + walkx]);
1093 alpha += tmp;
1094 color += tmp * spu->image[base + walkx];
1097 /* 9: bottom right part */
1098 if (right > 0.0 && bottom > 0.0) {
1099 base = spu->stride * (unsigned int) unscaled_y_bottom + (unsigned int) unscaled_x_right;
1100 tmp = right * bottom * canon_alpha(spu->aimage[base]);
1101 alpha += tmp;
1102 color += tmp * spu->image[base];
1104 /* Finally mix these transparency and brightness information suitably */
1105 base = spu->scaled_stride * y + x;
1106 spu->scaled_image[base] = alpha > 0 ? color / alpha : 0;
1107 spu->scaled_aimage[base] = alpha * scalex * scaley / 0x10000;
1108 if (spu->scaled_aimage[base]) {
1109 spu->scaled_aimage[base] = 256 - spu->scaled_aimage[base];
1110 if (spu->scaled_aimage[base] + spu->scaled_image[base] > 255)
1111 spu->scaled_image[base] = 256 - spu->scaled_aimage[base];
1117 nothing_to_do:
1118 /* Kludge: draw_alpha needs width multiple of 8. */
1119 if (spu->scaled_width < spu->scaled_stride)
1120 for (y = 0; y < spu->scaled_height; ++y) {
1121 memset(spu->scaled_aimage + y * spu->scaled_stride + spu->scaled_width, 0,
1122 spu->scaled_stride - spu->scaled_width);
1124 spu->scaled_frame_width = dxs;
1125 spu->scaled_frame_height = dys;
1128 if (spu->scaled_image){
1129 switch (spu_alignment) {
1130 case 0:
1131 spu->scaled_start_row = dys*sub_pos/100;
1132 if (spu->scaled_start_row + spu->scaled_height > dys)
1133 spu->scaled_start_row = dys - spu->scaled_height;
1134 break;
1135 case 1:
1136 spu->scaled_start_row = dys*sub_pos/100 - spu->scaled_height/2;
1137 if (sub_pos >= 50 && spu->scaled_start_row + spu->scaled_height > dys)
1138 spu->scaled_start_row = dys - spu->scaled_height;
1139 break;
1140 case 2:
1141 spu->scaled_start_row = dys*sub_pos/100 - spu->scaled_height;
1142 break;
1144 draw_alpha(ctx, spu->scaled_start_col, spu->scaled_start_row, spu->scaled_width, spu->scaled_height,
1145 spu->scaled_image, spu->scaled_aimage, spu->scaled_stride);
1146 spu->spu_changed = 0;
1150 else
1152 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPU not displayed: start_pts=%d end_pts=%d now_pts=%d\n",
1153 spu->start_pts, spu->end_pts, spu->now_pts);
1157 void spudec_update_palette(void * this, unsigned int *palette)
1159 spudec_handle_t *spu = (spudec_handle_t *) this;
1160 if (spu && palette) {
1161 memcpy(spu->global_palette, palette, sizeof(spu->global_palette));
1162 if(spu->hw_spu)
1163 vo_control(spu->hw_spu, VOCTRL_SET_SPU_PALETTE, spu->global_palette);
1167 void spudec_set_font_factor(void * this, double factor)
1169 spudec_handle_t *spu = (spudec_handle_t *) this;
1170 spu->font_start_level = (int)(0xF0-(0xE0*factor));
1173 static void spudec_parse_extradata(spudec_handle_t *this,
1174 uint8_t *extradata, int extradata_len)
1176 uint8_t *buffer, *ptr;
1177 unsigned int *pal = this->global_palette, *cuspal = this->cuspal;
1178 unsigned int tridx;
1179 int i;
1181 if (extradata_len == 16*4) {
1182 for (i=0; i<16; i++)
1183 pal[i] = AV_RB32(extradata + i*4);
1184 this->auto_palette = 0;
1185 return;
1188 if (!(ptr = buffer = malloc(extradata_len+1)))
1189 return;
1190 memcpy(buffer, extradata, extradata_len);
1191 buffer[extradata_len] = 0;
1193 do {
1194 if (*ptr == '#')
1195 continue;
1196 if (!strncmp(ptr, "size: ", 6))
1197 sscanf(ptr + 6, "%dx%d", &this->orig_frame_width, &this->orig_frame_height);
1198 if (!strncmp(ptr, "palette: ", 9) &&
1199 sscanf(ptr + 9, "%x, %x, %x, %x, %x, %x, %x, %x, "
1200 "%x, %x, %x, %x, %x, %x, %x, %x",
1201 &pal[ 0], &pal[ 1], &pal[ 2], &pal[ 3],
1202 &pal[ 4], &pal[ 5], &pal[ 6], &pal[ 7],
1203 &pal[ 8], &pal[ 9], &pal[10], &pal[11],
1204 &pal[12], &pal[13], &pal[14], &pal[15]) == 16) {
1205 for (i=0; i<16; i++)
1206 pal[i] = vobsub_palette_to_yuv(pal[i]);
1207 this->auto_palette = 0;
1209 if (!strncasecmp(ptr, "forced subs: on", 15))
1210 this->forced_subs_only = 1;
1211 if (!strncmp(ptr, "custom colors: ON, tridx: ", 26) &&
1212 sscanf(ptr + 26, "%x, colors: %x, %x, %x, %x",
1213 &tridx, cuspal+0, cuspal+1, cuspal+2, cuspal+3) == 5) {
1214 for (i=0; i<4; i++) {
1215 cuspal[i] = vobsub_rgb_to_yuv(cuspal[i]);
1216 if (tridx & (1 << (12-4*i)))
1217 cuspal[i] |= 1 << 31;
1219 this->custom = 1;
1221 } while ((ptr=strchr(ptr,'\n')) && *++ptr);
1223 free(buffer);
1226 void *spudec_new_scaled(unsigned int *palette, unsigned int frame_width, unsigned int frame_height, uint8_t *extradata, int extradata_len)
1228 spudec_handle_t *this = calloc(1, sizeof(spudec_handle_t));
1229 if (this){
1230 this->orig_frame_height = frame_height;
1231 // set up palette:
1232 if (palette)
1233 memcpy(this->global_palette, palette, sizeof(this->global_palette));
1234 else
1235 this->auto_palette = 1;
1236 if (extradata)
1237 spudec_parse_extradata(this, extradata, extradata_len);
1238 /* XXX Although the video frame is some size, the SPU frame is
1239 always maximum size i.e. 720 wide and 576 or 480 high */
1240 // For HD files in MKV the VobSub resolution can be higher though,
1241 // see largeres_vobsub.mkv
1242 if (this->orig_frame_width <= 720 && this->orig_frame_height <= 576) {
1243 this->orig_frame_width = 720;
1244 if (this->orig_frame_height == 480 || this->orig_frame_height == 240)
1245 this->orig_frame_height = 480;
1246 else
1247 this->orig_frame_height = 576;
1250 else
1251 mp_msg(MSGT_SPUDEC,MSGL_FATAL, "FATAL: spudec_init: calloc");
1252 return this;
1255 void *spudec_new(unsigned int *palette)
1257 return spudec_new_scaled(palette, 0, 0, NULL, 0);
1260 void spudec_free(void *this)
1262 spudec_handle_t *spu = (spudec_handle_t*)this;
1263 if (spu) {
1264 while (spu->queue_head)
1265 spudec_free_packet(spudec_dequeue_packet(spu));
1266 if (spu->packet)
1267 free(spu->packet);
1268 if (spu->scaled_image)
1269 free(spu->scaled_image);
1270 if (spu->image)
1271 free(spu->image);
1272 free(spu);
1276 void spudec_set_hw_spu(void *this, struct vo *hw_spu)
1278 spudec_handle_t *spu = (spudec_handle_t*)this;
1279 if (!spu)
1280 return;
1281 spu->hw_spu = hw_spu;
1282 vo_control(hw_spu, VOCTRL_SET_SPU_PALETTE, spu->global_palette);
1285 #define MP_NOPTS_VALUE (-1LL<<63) //both int64_t and double should be able to represent this exactly
1288 * palette must contain at least 256 32-bit entries, otherwise crashes
1289 * are possible
1291 void spudec_set_paletted(void *this, const uint8_t *pal_img, int pal_stride,
1292 const void *palette,
1293 int x, int y, int w, int h,
1294 double pts, double endpts)
1296 packet_t *packet;
1297 const uint32_t *pal = palette;
1298 spudec_handle_t *spu = this;
1299 uint8_t *img;
1300 uint8_t *aimg;
1301 int stride = (w + 7) & ~7;
1302 if ((unsigned)w >= 0x8000 || (unsigned)h > 0x4000)
1303 return;
1304 packet = calloc(1, sizeof(packet_t));
1305 packet->is_decoded = 1;
1306 packet->width = w;
1307 packet->height = h;
1308 packet->stride = stride;
1309 packet->start_col = x;
1310 packet->start_row = y;
1311 packet->data_len = 2 * stride * h;
1312 packet->packet = malloc(packet->data_len);
1313 img = packet->packet;
1314 aimg = packet->packet + stride * h;
1315 for (y = 0; y < h; y++) {
1316 for (x = 0; x < w; x++) {
1317 uint32_t pixel = pal[pal_img[x]];
1318 *aimg++ = -(pixel >> 24);
1319 *img++ = (((pixel & 0x000000ff) >> 0) +
1320 ((pixel & 0x0000ff00) >> 7) +
1321 ((pixel & 0x00ff0000) >> 16)) >> 2;
1323 for (; x < stride; x++)
1324 *aimg++ = *img++ = 0;
1325 pal_img += pal_stride;
1327 packet->start_pts = 0;
1328 packet->end_pts = 0x7fffffff;
1329 if (pts != MP_NOPTS_VALUE)
1330 packet->start_pts = pts * 90000;
1331 if (endpts != MP_NOPTS_VALUE)
1332 packet->end_pts = endpts * 90000;
1333 spudec_queue_packet(spu, packet);