rpm: Remove MEncoder from rpm packaging
[mplayer/glamo.git] / spudec.c
blobde7d443ffc10cd470b748128d9ab06763eeed195
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;
73 unsigned int start_row;
74 unsigned int width, height, stride;
75 unsigned int start_pts, end_pts;
76 packet_t *next;
79 struct palette_crop_cache {
80 int valid;
81 uint32_t palette;
82 int sx, sy, ex, ey;
83 int result;
86 typedef struct {
87 packet_t *queue_head;
88 packet_t *queue_tail;
89 unsigned int global_palette[16];
90 unsigned int orig_frame_width, orig_frame_height;
91 unsigned char* packet;
92 size_t packet_reserve; /* size of the memory pointed to by packet */
93 unsigned int packet_offset; /* end of the currently assembled fragment */
94 unsigned int packet_size; /* size of the packet once all fragments are assembled */
95 int packet_pts; /* PTS for this packet */
96 unsigned int palette[4];
97 unsigned int alpha[4];
98 unsigned int cuspal[4];
99 unsigned int custom;
100 unsigned int now_pts;
101 unsigned int start_pts, end_pts;
102 unsigned int start_col;
103 unsigned int start_row;
104 unsigned int width, height, stride;
105 size_t image_size; /* Size of the image buffer */
106 unsigned char *image; /* Grayscale value */
107 unsigned char *aimage; /* Alpha value */
108 unsigned int pal_start_col, pal_start_row;
109 unsigned int pal_width, pal_height;
110 unsigned char *pal_image; /* palette entry value */
111 unsigned int scaled_frame_width, scaled_frame_height;
112 unsigned int scaled_start_col, scaled_start_row;
113 unsigned int scaled_width, scaled_height, scaled_stride;
114 size_t scaled_image_size;
115 unsigned char *scaled_image;
116 unsigned char *scaled_aimage;
117 int auto_palette; /* 1 if we lack a palette and must use an heuristic. */
118 int font_start_level; /* Darkest value used for the computed font */
119 struct vo *hw_spu;
120 int spu_changed;
121 unsigned int forced_subs_only; /* flag: 0=display all subtitle, !0 display only forced subtitles */
122 unsigned int is_forced_sub; /* true if current subtitle is a forced subtitle */
124 struct palette_crop_cache palette_crop_cache;
125 } spudec_handle_t;
127 static void spudec_queue_packet(spudec_handle_t *this, packet_t *packet)
129 if (this->queue_head == NULL)
130 this->queue_head = packet;
131 else
132 this->queue_tail->next = packet;
133 this->queue_tail = packet;
136 static packet_t *spudec_dequeue_packet(spudec_handle_t *this)
138 packet_t *retval = this->queue_head;
140 this->queue_head = retval->next;
141 if (this->queue_head == NULL)
142 this->queue_tail = NULL;
144 return retval;
147 static void spudec_free_packet(packet_t *packet)
149 free(packet->packet);
150 free(packet);
153 static inline unsigned int get_be16(const unsigned char *p)
155 return (p[0] << 8) + p[1];
158 static inline unsigned int get_be24(const unsigned char *p)
160 return (get_be16(p) << 8) + p[2];
163 static void next_line(packet_t *packet)
165 if (packet->current_nibble[packet->deinterlace_oddness] % 2)
166 packet->current_nibble[packet->deinterlace_oddness]++;
167 packet->deinterlace_oddness = (packet->deinterlace_oddness + 1) % 2;
170 static inline unsigned char get_nibble(packet_t *packet)
172 unsigned char nib;
173 unsigned int *nibblep = packet->current_nibble + packet->deinterlace_oddness;
174 if (*nibblep / 2 >= packet->control_start) {
175 mp_msg(MSGT_SPUDEC,MSGL_WARN, "SPUdec: ERROR: get_nibble past end of packet\n");
176 return 0;
178 nib = packet->packet[*nibblep / 2];
179 if (*nibblep % 2)
180 nib &= 0xf;
181 else
182 nib >>= 4;
183 ++*nibblep;
184 return nib;
187 /* Cut the sub to visible part */
188 static inline void spudec_cut_image(spudec_handle_t *this)
190 unsigned int fy, ly;
191 unsigned int first_y, last_y;
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 return;
212 // printf("new h %d new start %d (sz %d st %d)---\n\n", this->height, this->start_row, this->image_size, this->stride);
214 if (first_y > 0) {
215 memmove(this->image, this->image + this->stride * first_y, this->stride * this->height);
216 memmove(this->aimage, this->aimage + this->stride * first_y, this->stride * this->height);
221 static int spudec_alloc_image(spudec_handle_t *this, int stride, int height)
223 if (this->width > stride) // just a safeguard
224 this->width = stride;
225 this->stride = stride;
226 this->height = height;
227 if (this->image_size < this->stride * this->height) {
228 if (this->image != NULL) {
229 free(this->image);
230 free(this->pal_image);
231 this->image_size = 0;
232 this->pal_width = this->pal_height = 0;
234 this->image = malloc(2 * this->stride * this->height);
235 if (this->image) {
236 this->image_size = this->stride * this->height;
237 this->aimage = this->image + this->image_size;
238 // use stride here as well to simplify reallocation checks
239 this->pal_image = malloc(this->stride * this->height);
242 return this->image != NULL;
246 * \param pal palette in MPlayer-style gray-alpha values, i.e.
247 * alpha == 0 means transparent, 1 fully opaque,
248 * gray value <= 256 - alpha.
250 static void pal2gray_alpha(const uint16_t *pal,
251 const uint8_t *src, int src_stride,
252 uint8_t *dst, uint8_t *dsta,
253 int dst_stride, int w, int h)
255 int x, y;
256 for (y = 0; y < h; y++) {
257 for (x = 0; x < w; x++) {
258 uint16_t pixel = pal[src[x]];
259 *dst++ = pixel;
260 *dsta++ = pixel >> 8;
262 for (; x < dst_stride; x++)
263 *dsta++ = *dst++ = 0;
264 src += src_stride;
268 static int apply_palette_crop(spudec_handle_t *this,
269 unsigned crop_x, unsigned crop_y,
270 unsigned crop_w, unsigned crop_h)
272 int i;
273 uint8_t *src;
274 uint16_t pal[4];
275 unsigned stride = (crop_w + 7) & ~7;
276 if (crop_x > this->pal_width || crop_y > this->pal_height ||
277 crop_w > this->pal_width - crop_x || crop_h > this->pal_width - crop_y ||
278 crop_w > 0x8000 || crop_h > 0x8000 ||
279 stride * crop_h > this->image_size) {
280 return 0;
282 for (i = 0; i < 4; ++i) {
283 int color;
284 int alpha = this->alpha[i];
285 // extend 4 -> 8 bit
286 alpha |= alpha << 4;
287 if (this->custom && (this->cuspal[i] >> 31) != 0)
288 alpha = 0;
289 color = this->custom ? this->cuspal[i] :
290 this->global_palette[this->palette[i]];
291 color = (color >> 16) & 0xff;
292 // convert to MPlayer-style gray/alpha palette
293 color = FFMIN(color, alpha);
294 pal[i] = (-alpha << 8) | color;
296 src = this->pal_image + crop_y * this->pal_width + crop_x;
297 pal2gray_alpha(pal, src, this->pal_width,
298 this->image, this->aimage, stride,
299 crop_w, crop_h);
300 this->width = crop_w;
301 this->height = crop_h;
302 this->stride = stride;
303 this->start_col = this->pal_start_col + crop_x;
304 this->start_row = this->pal_start_row + crop_y;
305 spudec_cut_image(this);
307 // reset scaled image
308 this->scaled_frame_width = 0;
309 this->scaled_frame_height = 0;
310 this->palette_crop_cache.valid = 0;
311 return 1;
314 int spudec_apply_palette_crop(void *this, uint32_t palette,
315 int sx, int sy, int ex, int ey)
317 spudec_handle_t *spu = this;
318 struct palette_crop_cache *c = &spu->palette_crop_cache;
319 if (c->valid && c->palette == palette &&
320 c->sx == sx && c->sy == sy && c->ex == ex && c->ey == ey)
321 return c->result;
322 spu->palette[0] = (palette >> 28) & 0xf;
323 spu->palette[1] = (palette >> 24) & 0xf;
324 spu->palette[2] = (palette >> 20) & 0xf;
325 spu->palette[3] = (palette >> 16) & 0xf;
326 spu->alpha[0] = (palette >> 12) & 0xf;
327 spu->alpha[1] = (palette >> 8) & 0xf;
328 spu->alpha[2] = (palette >> 4) & 0xf;
329 spu->alpha[3] = palette & 0xf;
330 spu->spu_changed = 1;
331 c->result = apply_palette_crop(spu,
332 sx - spu->pal_start_col, sy - spu->pal_start_row,
333 ex - sx, ey - sy);
334 c->palette = palette;
335 c->sx = sx; c->sy = sy;
336 c->ex = ex; c->ey = ey;
337 c->valid = 1;
338 return c->result;
341 static void spudec_process_data(spudec_handle_t *this, packet_t *packet)
343 unsigned int i, x, y;
344 uint8_t *dst;
346 if (!spudec_alloc_image(this, packet->stride, packet->height))
347 return;
349 this->pal_start_col = packet->start_col;
350 this->pal_start_row = packet->start_row;
351 this->pal_height = packet->height;
352 this->pal_width = packet->width;
353 this->stride = packet->stride;
354 memcpy(this->palette, packet->palette, sizeof(this->palette));
355 memcpy(this->alpha, packet->alpha, sizeof(this->alpha));
357 i = packet->current_nibble[1];
358 x = 0;
359 y = 0;
360 dst = this->pal_image;
361 while (packet->current_nibble[0] < i
362 && packet->current_nibble[1] / 2 < packet->control_start
363 && y < this->pal_height) {
364 unsigned int len, color;
365 unsigned int rle = 0;
366 rle = get_nibble(packet);
367 if (rle < 0x04) {
368 if (rle == 0) {
369 rle = (rle << 4) | get_nibble(packet);
370 if (rle < 0x04)
371 rle = (rle << 4) | get_nibble(packet);
373 rle = (rle << 4) | get_nibble(packet);
375 color = 3 - (rle & 0x3);
376 len = rle >> 2;
377 x += len;
378 if (len == 0 || x >= this->pal_width) {
379 len += this->pal_width - x;
380 next_line(packet);
381 x = 0;
382 ++y;
384 memset(dst, color, len);
385 dst += len;
387 apply_palette_crop(this, 0, 0, this->pal_width, this->pal_height);
392 This function tries to create a usable palette.
393 It determines how many non-transparent colors are used, and assigns different
394 gray scale values to each color.
395 I tested it with four streams and even got something readable. Half of the
396 times I got black characters with white around and half the reverse.
398 static void compute_palette(spudec_handle_t *this, packet_t *packet)
400 int used[16],i,cused,start,step,color;
402 memset(used, 0, sizeof(used));
403 for (i=0; i<4; i++)
404 if (packet->alpha[i]) /* !Transparent? */
405 used[packet->palette[i]] = 1;
406 for (cused=0, i=0; i<16; i++)
407 if (used[i]) cused++;
408 if (!cused) return;
409 if (cused == 1) {
410 start = 0x80;
411 step = 0;
412 } else {
413 start = this->font_start_level;
414 step = (0xF0-this->font_start_level)/(cused-1);
416 memset(used, 0, sizeof(used));
417 for (i=0; i<4; i++) {
418 color = packet->palette[i];
419 if (packet->alpha[i] && !used[color]) { /* not assigned? */
420 used[color] = 1;
421 this->global_palette[color] = start<<16;
422 start += step;
427 static void spudec_process_control(spudec_handle_t *this, int pts100)
429 int a,b,c,d; /* Temporary vars */
430 unsigned int date, type;
431 unsigned int off;
432 unsigned int start_off = 0;
433 unsigned int next_off;
434 unsigned int start_pts = 0;
435 unsigned int end_pts = 0;
436 unsigned int current_nibble[2] = {0, 0};
437 unsigned int control_start;
438 unsigned int display = 0;
439 unsigned int start_col = 0;
440 unsigned int end_col = 0;
441 unsigned int start_row = 0;
442 unsigned int end_row = 0;
443 unsigned int width = 0;
444 unsigned int height = 0;
445 unsigned int stride = 0;
447 control_start = get_be16(this->packet + 2);
448 next_off = control_start;
449 while (start_off != next_off) {
450 start_off = next_off;
451 date = get_be16(this->packet + start_off) * 1024;
452 next_off = get_be16(this->packet + start_off + 2);
453 mp_msg(MSGT_SPUDEC,MSGL_DBG2, "date=%d\n", date);
454 off = start_off + 4;
455 for (type = this->packet[off++]; type != 0xff; type = this->packet[off++]) {
456 mp_msg(MSGT_SPUDEC,MSGL_DBG2, "cmd=%d ",type);
457 switch(type) {
458 case 0x00:
459 /* Menu ID, 1 byte */
460 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Menu ID\n");
461 /* shouldn't a Menu ID type force display start? */
462 start_pts = pts100 < 0 && -pts100 >= date ? 0 : pts100 + date;
463 end_pts = UINT_MAX;
464 display = 1;
465 this->is_forced_sub=~0; // current subtitle is forced
466 break;
467 case 0x01:
468 /* Start display */
469 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Start display!\n");
470 start_pts = pts100 < 0 && -pts100 >= date ? 0 : pts100 + date;
471 end_pts = UINT_MAX;
472 display = 1;
473 this->is_forced_sub=0;
474 break;
475 case 0x02:
476 /* Stop display */
477 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Stop display!\n");
478 end_pts = pts100 < 0 && -pts100 >= date ? 0 : pts100 + date;
479 break;
480 case 0x03:
481 /* Palette */
482 this->palette[0] = this->packet[off] >> 4;
483 this->palette[1] = this->packet[off] & 0xf;
484 this->palette[2] = this->packet[off + 1] >> 4;
485 this->palette[3] = this->packet[off + 1] & 0xf;
486 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Palette %d, %d, %d, %d\n",
487 this->palette[0], this->palette[1], this->palette[2], this->palette[3]);
488 off+=2;
489 break;
490 case 0x04:
491 /* Alpha */
492 a = this->packet[off] >> 4;
493 b = this->packet[off] & 0xf;
494 c = this->packet[off + 1] >> 4;
495 d = this->packet[off + 1] & 0xf;
496 // Note: some DVDs change these values to create a fade-in/fade-out effect
497 // We can not handle this, so just keep the highest value during the display time.
498 if (display) {
499 a = FFMAX(a, this->alpha[0]);
500 b = FFMAX(b, this->alpha[1]);
501 c = FFMAX(c, this->alpha[2]);
502 d = FFMAX(d, this->alpha[3]);
504 this->alpha[0] = a;
505 this->alpha[1] = b;
506 this->alpha[2] = c;
507 this->alpha[3] = d;
508 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Alpha %d, %d, %d, %d\n",
509 this->alpha[0], this->alpha[1], this->alpha[2], this->alpha[3]);
510 off+=2;
511 break;
512 case 0x05:
513 /* Co-ords */
514 a = get_be24(this->packet + off);
515 b = get_be24(this->packet + off + 3);
516 start_col = a >> 12;
517 end_col = a & 0xfff;
518 width = (end_col < start_col) ? 0 : end_col - start_col + 1;
519 stride = (width + 7) & ~7; /* Kludge: draw_alpha needs width multiple of 8 */
520 start_row = b >> 12;
521 end_row = b & 0xfff;
522 height = (end_row < start_row) ? 0 : end_row - start_row /* + 1 */;
523 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Coords col: %d - %d row: %d - %d (%dx%d)\n",
524 start_col, end_col, start_row, end_row,
525 width, height);
526 off+=6;
527 break;
528 case 0x06:
529 /* Graphic lines */
530 current_nibble[0] = 2 * get_be16(this->packet + off);
531 current_nibble[1] = 2 * get_be16(this->packet + off + 2);
532 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Graphic offset 1: %d offset 2: %d\n",
533 current_nibble[0] / 2, current_nibble[1] / 2);
534 off+=4;
535 break;
536 case 0xff:
537 /* All done, bye-bye */
538 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Done!\n");
539 return;
540 // break;
541 default:
542 mp_msg(MSGT_SPUDEC,MSGL_WARN,"spudec: Error determining control type 0x%02x. Skipping %d bytes.\n",
543 type, next_off - off);
544 goto next_control;
547 next_control:
548 if (!display)
549 continue;
550 if (end_pts == UINT_MAX && start_off != next_off) {
551 end_pts = get_be16(this->packet + next_off) * 1024;
552 end_pts = 1 - pts100 >= end_pts ? 0 : pts100 + end_pts - 1;
554 if (end_pts > 0) {
555 packet_t *packet = calloc(1, sizeof(packet_t));
556 int i;
557 packet->start_pts = start_pts;
558 packet->end_pts = end_pts;
559 packet->current_nibble[0] = current_nibble[0];
560 packet->current_nibble[1] = current_nibble[1];
561 packet->start_row = start_row;
562 packet->start_col = start_col;
563 packet->width = width;
564 packet->height = height;
565 packet->stride = stride;
566 packet->control_start = control_start;
567 for (i=0; i<4; i++) {
568 packet->alpha[i] = this->alpha[i];
569 packet->palette[i] = this->palette[i];
571 packet->packet = malloc(this->packet_size);
572 memcpy(packet->packet, this->packet, this->packet_size);
573 spudec_queue_packet(this, packet);
578 static void spudec_decode(spudec_handle_t *this, int pts100)
580 if (!this->hw_spu)
581 spudec_process_control(this, pts100);
582 else if (pts100 >= 0) {
583 static vo_mpegpes_t packet = { NULL, 0, 0x20, 0 };
584 static vo_mpegpes_t *pkg=&packet;
585 packet.data = this->packet;
586 packet.size = this->packet_size;
587 packet.timestamp = pts100;
588 vo_draw_frame(this->hw_spu, (uint8_t**)&pkg);
592 int spudec_changed(void * this)
594 spudec_handle_t * spu = this;
595 return spu->spu_changed || spu->now_pts > spu->end_pts;
598 void spudec_assemble(void *this, unsigned char *packet, unsigned int len, int pts100)
600 spudec_handle_t *spu = this;
601 // spudec_heartbeat(this, pts100);
602 if (len < 2) {
603 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: packet too short\n");
604 return;
606 spu->packet_pts = pts100;
607 if (spu->packet_offset == 0) {
608 unsigned int len2 = get_be16(packet);
609 // Start new fragment
610 if (spu->packet_reserve < len2) {
611 free(spu->packet);
612 spu->packet = malloc(len2);
613 spu->packet_reserve = spu->packet != NULL ? len2 : 0;
615 if (spu->packet != NULL) {
616 spu->packet_size = len2;
617 if (len > len2) {
618 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: invalid frag len / len2: %d / %d \n", len, len2);
619 return;
621 memcpy(spu->packet, packet, len);
622 spu->packet_offset = len;
623 spu->packet_pts = pts100;
625 } else {
626 // Continue current fragment
627 if (spu->packet_size < spu->packet_offset + len){
628 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: invalid fragment\n");
629 spu->packet_size = spu->packet_offset = 0;
630 return;
631 } else {
632 memcpy(spu->packet + spu->packet_offset, packet, len);
633 spu->packet_offset += len;
636 #if 1
637 // check if we have a complete packet (unfortunatelly packet_size is bad
638 // for some disks)
639 // [cb] packet_size is padded to be even -> may be one byte too long
640 if ((spu->packet_offset == spu->packet_size) ||
641 ((spu->packet_offset + 1) == spu->packet_size)){
642 unsigned int x=0,y;
643 while(x+4<=spu->packet_offset){
644 y=get_be16(spu->packet+x+2); // next control pointer
645 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPUtest: x=%d y=%d off=%d size=%d\n",x,y,spu->packet_offset,spu->packet_size);
646 if(x>=4 && x==y){ // if it points to self - we're done!
647 // we got it!
648 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPUgot: off=%d size=%d \n",spu->packet_offset,spu->packet_size);
649 spudec_decode(spu, pts100);
650 spu->packet_offset = 0;
651 break;
653 if(y<=x || y>=spu->packet_size){ // invalid?
654 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUtest: broken packet!!!!! y=%d < x=%d\n",y,x);
655 spu->packet_size = spu->packet_offset = 0;
656 break;
658 x=y;
660 // [cb] packet is done; start new packet
661 spu->packet_offset = 0;
663 #else
664 if (spu->packet_offset == spu->packet_size) {
665 spudec_decode(spu, pts100);
666 spu->packet_offset = 0;
668 #endif
671 void spudec_reset(void *this) // called after seek
673 spudec_handle_t *spu = this;
674 while (spu->queue_head)
675 spudec_free_packet(spudec_dequeue_packet(spu));
676 spu->now_pts = 0;
677 spu->end_pts = 0;
678 spu->packet_size = spu->packet_offset = 0;
681 void spudec_heartbeat(void *this, unsigned int pts100)
683 spudec_handle_t *spu = this;
684 spu->now_pts = pts100;
686 // TODO: detect and handle broken timestamps (e.g. due to wrapping)
687 while (spu->queue_head != NULL && pts100 >= spu->queue_head->start_pts) {
688 packet_t *packet = spudec_dequeue_packet(spu);
689 spu->start_pts = packet->start_pts;
690 spu->end_pts = packet->end_pts;
691 if (packet->is_decoded) {
692 free(spu->image);
693 spu->image_size = packet->data_len;
694 spu->image = packet->packet;
695 spu->aimage = packet->packet + packet->stride * packet->height;
696 packet->packet = NULL;
697 spu->width = packet->width;
698 spu->height = packet->height;
699 spu->stride = packet->stride;
700 spu->start_col = packet->start_col;
701 spu->start_row = packet->start_row;
703 // reset scaled image
704 spu->scaled_frame_width = 0;
705 spu->scaled_frame_height = 0;
706 } else {
707 if (spu->auto_palette)
708 compute_palette(spu, packet);
709 spudec_process_data(spu, packet);
711 spudec_free_packet(packet);
712 spu->spu_changed = 1;
716 int spudec_visible(void *this){
717 spudec_handle_t *spu = this;
718 int ret=(spu->start_pts <= spu->now_pts &&
719 spu->now_pts < spu->end_pts &&
720 spu->height > 0);
721 // printf("spu visible: %d \n",ret);
722 return ret;
725 void spudec_set_forced_subs_only(void * const this, const unsigned int flag)
727 if(this){
728 ((spudec_handle_t *)this)->forced_subs_only=flag;
729 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPU: Display only forced subs now %s\n", flag ? "enabled": "disabled");
733 void spudec_draw(void *this, void (*draw_alpha)(void *ctx, int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride), void *ctx)
735 spudec_handle_t *spu = this;
736 if (spudec_visible(spu))
738 draw_alpha(ctx, spu->start_col, spu->start_row, spu->width, spu->height,
739 spu->image, spu->aimage, spu->stride);
740 spu->spu_changed = 0;
744 /* calc the bbox for spudec subs */
745 void spudec_calc_bbox(void *me, unsigned int dxs, unsigned int dys, unsigned int* bbox)
747 spudec_handle_t *spu = me;
748 if (spu->orig_frame_width == 0 || spu->orig_frame_height == 0
749 || (spu->orig_frame_width == dxs && spu->orig_frame_height == dys)) {
750 // unscaled
751 bbox[0] = spu->start_col;
752 bbox[1] = spu->start_col + spu->width;
753 bbox[2] = spu->start_row;
754 bbox[3] = spu->start_row + spu->height;
756 else {
757 // scaled
758 unsigned int scalex = 0x100 * dxs / spu->orig_frame_width;
759 unsigned int scaley = 0x100 * dys / spu->orig_frame_height;
760 bbox[0] = spu->start_col * scalex / 0x100;
761 bbox[1] = spu->start_col * scalex / 0x100 + spu->width * scalex / 0x100;
762 switch (spu_alignment) {
763 case 0:
764 bbox[3] = dys*sub_pos/100 + spu->height * scaley / 0x100;
765 if (bbox[3] > dys) bbox[3] = dys;
766 bbox[2] = bbox[3] - spu->height * scaley / 0x100;
767 break;
768 case 1:
769 if (sub_pos < 50) {
770 bbox[2] = dys*sub_pos/100 - spu->height * scaley / 0x200;
771 bbox[3] = bbox[2] + spu->height;
772 } else {
773 bbox[3] = dys*sub_pos/100 + spu->height * scaley / 0x200;
774 if (bbox[3] > dys) bbox[3] = dys;
775 bbox[2] = bbox[3] - spu->height * scaley / 0x100;
777 break;
778 case 2:
779 bbox[2] = dys*sub_pos/100 - spu->height * scaley / 0x100;
780 bbox[3] = bbox[2] + spu->height;
781 break;
782 default: /* -1 */
783 bbox[2] = spu->start_row * scaley / 0x100;
784 bbox[3] = spu->start_row * scaley / 0x100 + spu->height * scaley / 0x100;
785 break;
789 /* transform mplayer's alpha value into an opacity value that is linear */
790 static inline int canon_alpha(int alpha)
792 return (uint8_t)-alpha;
795 typedef struct {
796 unsigned position;
797 unsigned left_up;
798 unsigned right_down;
799 }scale_pixel;
802 static void scale_table(unsigned int start_src, unsigned int start_tar, unsigned int end_src, unsigned int end_tar, scale_pixel * table)
804 unsigned int t;
805 unsigned int delta_src = end_src - start_src;
806 unsigned int delta_tar = end_tar - start_tar;
807 int src = 0;
808 int src_step;
809 if (delta_src == 0 || delta_tar == 0) {
810 return;
812 src_step = (delta_src << 16) / delta_tar >>1;
813 for (t = 0; t<=delta_tar; src += (src_step << 1), t++){
814 table[t].position= FFMIN(src >> 16, end_src - 1);
815 table[t].right_down = src & 0xffff;
816 table[t].left_up = 0x10000 - table[t].right_down;
820 /* bilinear scale, similar to vobsub's code */
821 static void scale_image(int x, int y, scale_pixel* table_x, scale_pixel* table_y, spudec_handle_t * spu)
823 int alpha[4];
824 int color[4];
825 unsigned int scale[4];
826 int base = table_y[y].position * spu->stride + table_x[x].position;
827 int scaled = y * spu->scaled_stride + x;
828 alpha[0] = canon_alpha(spu->aimage[base]);
829 alpha[1] = canon_alpha(spu->aimage[base + 1]);
830 alpha[2] = canon_alpha(spu->aimage[base + spu->stride]);
831 alpha[3] = canon_alpha(spu->aimage[base + spu->stride + 1]);
832 color[0] = spu->image[base];
833 color[1] = spu->image[base + 1];
834 color[2] = spu->image[base + spu->stride];
835 color[3] = spu->image[base + spu->stride + 1];
836 scale[0] = (table_x[x].left_up * table_y[y].left_up >> 16) * alpha[0];
837 if (table_y[y].left_up == 0x10000) // necessary to avoid overflow-case
838 scale[0] = table_x[x].left_up * alpha[0];
839 scale[1] = (table_x[x].right_down * table_y[y].left_up >>16) * alpha[1];
840 scale[2] = (table_x[x].left_up * table_y[y].right_down >> 16) * alpha[2];
841 scale[3] = (table_x[x].right_down * table_y[y].right_down >> 16) * alpha[3];
842 spu->scaled_image[scaled] = (color[0] * scale[0] + color[1] * scale[1] + color[2] * scale[2] + color[3] * scale[3])>>24;
843 spu->scaled_aimage[scaled] = (scale[0] + scale[1] + scale[2] + scale[3]) >> 16;
844 if (spu->scaled_aimage[scaled]){
845 // ensure that MPlayer's simplified alpha-blending can not overflow
846 spu->scaled_image[scaled] = FFMIN(spu->scaled_image[scaled], spu->scaled_aimage[scaled]);
847 // convert to MPlayer-style alpha
848 spu->scaled_aimage[scaled] = -spu->scaled_aimage[scaled];
852 static void sws_spu_image(unsigned char *d1, unsigned char *d2, int dw, int dh,
853 int ds, const unsigned char* s1, unsigned char* s2,
854 int sw, int sh, int ss)
856 struct SwsContext *ctx;
857 static SwsFilter filter;
858 static int firsttime = 1;
859 static float oldvar;
860 int i;
862 if (!firsttime && oldvar != spu_gaussvar) sws_freeVec(filter.lumH);
863 if (firsttime) {
864 filter.lumH = filter.lumV =
865 filter.chrH = filter.chrV = sws_getGaussianVec(spu_gaussvar, 3.0);
866 sws_normalizeVec(filter.lumH, 1.0);
867 firsttime = 0;
868 oldvar = spu_gaussvar;
871 ctx=sws_getContext(sw, sh, PIX_FMT_GRAY8, dw, dh, PIX_FMT_GRAY8, SWS_GAUSS, &filter, NULL, NULL);
872 sws_scale(ctx,&s1,&ss,0,sh,&d1,&ds);
873 for (i=ss*sh-1; i>=0; i--) if (!s2[i]) s2[i] = 255; //else s2[i] = 1;
874 sws_scale(ctx,&s2,&ss,0,sh,&d2,&ds);
875 for (i=ds*dh-1; i>=0; i--) if (d2[i]==0) d2[i] = 1; else if (d2[i]==255) d2[i] = 0;
876 sws_freeContext(ctx);
879 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)
881 spudec_handle_t *spu = me;
882 scale_pixel *table_x;
883 scale_pixel *table_y;
885 if (spudec_visible(spu)) {
887 // check if only forced subtitles are requested
888 if( (spu->forced_subs_only) && !(spu->is_forced_sub) ){
889 return;
892 if (!(spu_aamode&16) && (spu->orig_frame_width == 0 || spu->orig_frame_height == 0
893 || (spu->orig_frame_width == dxs && spu->orig_frame_height == dys))) {
894 spudec_draw(spu, draw_alpha, ctx);
896 else {
897 if (spu->scaled_frame_width != dxs || spu->scaled_frame_height != dys) { /* Resizing is needed */
898 /* scaled_x = scalex * x / 0x100
899 scaled_y = scaley * y / 0x100
900 order of operations is important because of rounding. */
901 unsigned int scalex = 0x100 * dxs / spu->orig_frame_width;
902 unsigned int scaley = 0x100 * dys / spu->orig_frame_height;
903 spu->scaled_start_col = spu->start_col * scalex / 0x100;
904 spu->scaled_start_row = spu->start_row * scaley / 0x100;
905 spu->scaled_width = spu->width * scalex / 0x100;
906 spu->scaled_height = spu->height * scaley / 0x100;
907 /* Kludge: draw_alpha needs width multiple of 8 */
908 spu->scaled_stride = (spu->scaled_width + 7) & ~7;
909 if (spu->scaled_image_size < spu->scaled_stride * spu->scaled_height) {
910 if (spu->scaled_image) {
911 free(spu->scaled_image);
912 spu->scaled_image_size = 0;
914 spu->scaled_image = malloc(2 * spu->scaled_stride * spu->scaled_height);
915 if (spu->scaled_image) {
916 spu->scaled_image_size = spu->scaled_stride * spu->scaled_height;
917 spu->scaled_aimage = spu->scaled_image + spu->scaled_image_size;
920 if (spu->scaled_image) {
921 unsigned int x, y;
922 if (spu->scaled_width <= 1 || spu->scaled_height <= 1) {
923 goto nothing_to_do;
925 switch(spu_aamode&15) {
926 case 4:
927 sws_spu_image(spu->scaled_image, spu->scaled_aimage,
928 spu->scaled_width, spu->scaled_height, spu->scaled_stride,
929 spu->image, spu->aimage, spu->width, spu->height, spu->stride);
930 break;
931 case 3:
932 table_x = calloc(spu->scaled_width, sizeof(scale_pixel));
933 table_y = calloc(spu->scaled_height, sizeof(scale_pixel));
934 if (!table_x || !table_y) {
935 mp_msg(MSGT_SPUDEC, MSGL_FATAL, "Fatal: spudec_draw_scaled: calloc failed\n");
937 scale_table(0, 0, spu->width - 1, spu->scaled_width - 1, table_x);
938 scale_table(0, 0, spu->height - 1, spu->scaled_height - 1, table_y);
939 for (y = 0; y < spu->scaled_height; y++)
940 for (x = 0; x < spu->scaled_width; x++)
941 scale_image(x, y, table_x, table_y, spu);
942 free(table_x);
943 free(table_y);
944 break;
945 case 0:
946 /* no antialiasing */
947 for (y = 0; y < spu->scaled_height; ++y) {
948 int unscaled_y = y * 0x100 / scaley;
949 int strides = spu->stride * unscaled_y;
950 int scaled_strides = spu->scaled_stride * y;
951 for (x = 0; x < spu->scaled_width; ++x) {
952 int unscaled_x = x * 0x100 / scalex;
953 spu->scaled_image[scaled_strides + x] = spu->image[strides + unscaled_x];
954 spu->scaled_aimage[scaled_strides + x] = spu->aimage[strides + unscaled_x];
957 break;
958 case 1:
960 /* Intermediate antialiasing. */
961 for (y = 0; y < spu->scaled_height; ++y) {
962 const unsigned int unscaled_top = y * spu->orig_frame_height / dys;
963 unsigned int unscaled_bottom = (y + 1) * spu->orig_frame_height / dys;
964 if (unscaled_bottom >= spu->height)
965 unscaled_bottom = spu->height - 1;
966 for (x = 0; x < spu->scaled_width; ++x) {
967 const unsigned int unscaled_left = x * spu->orig_frame_width / dxs;
968 unsigned int unscaled_right = (x + 1) * spu->orig_frame_width / dxs;
969 unsigned int color = 0;
970 unsigned int alpha = 0;
971 unsigned int walkx, walky;
972 unsigned int base, tmp;
973 if (unscaled_right >= spu->width)
974 unscaled_right = spu->width - 1;
975 for (walky = unscaled_top; walky <= unscaled_bottom; ++walky)
976 for (walkx = unscaled_left; walkx <= unscaled_right; ++walkx) {
977 base = walky * spu->stride + walkx;
978 tmp = canon_alpha(spu->aimage[base]);
979 alpha += tmp;
980 color += tmp * spu->image[base];
982 base = y * spu->scaled_stride + x;
983 spu->scaled_image[base] = alpha ? color / alpha : 0;
984 spu->scaled_aimage[base] =
985 alpha * (1 + unscaled_bottom - unscaled_top) * (1 + unscaled_right - unscaled_left);
986 /* spu->scaled_aimage[base] =
987 alpha * dxs * dys / spu->orig_frame_width / spu->orig_frame_height; */
988 if (spu->scaled_aimage[base]) {
989 spu->scaled_aimage[base] = 256 - spu->scaled_aimage[base];
990 if (spu->scaled_aimage[base] + spu->scaled_image[base] > 255)
991 spu->scaled_image[base] = 256 - spu->scaled_aimage[base];
996 break;
997 case 2:
999 /* Best antialiasing. Very slow. */
1000 /* Any pixel (x, y) represents pixels from the original
1001 rectangular region comprised between the columns
1002 unscaled_y and unscaled_y + 0x100 / scaley and the rows
1003 unscaled_x and unscaled_x + 0x100 / scalex
1005 The original rectangular region that the scaled pixel
1006 represents is cut in 9 rectangular areas like this:
1008 +---+-----------------+---+
1009 | 1 | 2 | 3 |
1010 +---+-----------------+---+
1011 | | | |
1012 | 4 | 5 | 6 |
1013 | | | |
1014 +---+-----------------+---+
1015 | 7 | 8 | 9 |
1016 +---+-----------------+---+
1018 The width of the left column is at most one pixel and
1019 it is never null and its right column is at a pixel
1020 boundary. The height of the top row is at most one
1021 pixel it is never null and its bottom row is at a
1022 pixel boundary. The width and height of region 5 are
1023 integral values. The width of the right column is
1024 what remains and is less than one pixel. The height
1025 of the bottom row is what remains and is less than
1026 one pixel.
1028 The row above 1, 2, 3 is unscaled_y. The row between
1029 1, 2, 3 and 4, 5, 6 is top_low_row. The row between 4,
1030 5, 6 and 7, 8, 9 is (unsigned int)unscaled_y_bottom.
1031 The row beneath 7, 8, 9 is unscaled_y_bottom.
1033 The column left of 1, 4, 7 is unscaled_x. The column
1034 between 1, 4, 7 and 2, 5, 8 is left_right_column. The
1035 column between 2, 5, 8 and 3, 6, 9 is (unsigned
1036 int)unscaled_x_right. The column right of 3, 6, 9 is
1037 unscaled_x_right. */
1038 const double inv_scalex = (double) 0x100 / scalex;
1039 const double inv_scaley = (double) 0x100 / scaley;
1040 for (y = 0; y < spu->scaled_height; ++y) {
1041 const double unscaled_y = y * inv_scaley;
1042 const double unscaled_y_bottom = unscaled_y + inv_scaley;
1043 const unsigned int top_low_row = FFMIN(unscaled_y_bottom, unscaled_y + 1.0);
1044 const double top = top_low_row - unscaled_y;
1045 const unsigned int height = unscaled_y_bottom > top_low_row
1046 ? (unsigned int) unscaled_y_bottom - top_low_row
1047 : 0;
1048 const double bottom = unscaled_y_bottom > top_low_row
1049 ? unscaled_y_bottom - floor(unscaled_y_bottom)
1050 : 0.0;
1051 for (x = 0; x < spu->scaled_width; ++x) {
1052 const double unscaled_x = x * inv_scalex;
1053 const double unscaled_x_right = unscaled_x + inv_scalex;
1054 const unsigned int left_right_column = FFMIN(unscaled_x_right, unscaled_x + 1.0);
1055 const double left = left_right_column - unscaled_x;
1056 const unsigned int width = unscaled_x_right > left_right_column
1057 ? (unsigned int) unscaled_x_right - left_right_column
1058 : 0;
1059 const double right = unscaled_x_right > left_right_column
1060 ? unscaled_x_right - floor(unscaled_x_right)
1061 : 0.0;
1062 double color = 0.0;
1063 double alpha = 0.0;
1064 double tmp;
1065 unsigned int base;
1066 /* Now use these informations to compute a good alpha,
1067 and lightness. The sum is on each of the 9
1068 region's surface and alpha and lightness.
1070 transformed alpha = sum(surface * alpha) / sum(surface)
1071 transformed color = sum(surface * alpha * color) / sum(surface * alpha)
1073 /* 1: top left part */
1074 base = spu->stride * (unsigned int) unscaled_y;
1075 tmp = left * top * canon_alpha(spu->aimage[base + (unsigned int) unscaled_x]);
1076 alpha += tmp;
1077 color += tmp * spu->image[base + (unsigned int) unscaled_x];
1078 /* 2: top center part */
1079 if (width > 0) {
1080 unsigned int walkx;
1081 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
1082 base = spu->stride * (unsigned int) unscaled_y + walkx;
1083 tmp = /* 1.0 * */ top * canon_alpha(spu->aimage[base]);
1084 alpha += tmp;
1085 color += tmp * spu->image[base];
1088 /* 3: top right part */
1089 if (right > 0.0) {
1090 base = spu->stride * (unsigned int) unscaled_y + (unsigned int) unscaled_x_right;
1091 tmp = right * top * canon_alpha(spu->aimage[base]);
1092 alpha += tmp;
1093 color += tmp * spu->image[base];
1095 /* 4: center left part */
1096 if (height > 0) {
1097 unsigned int walky;
1098 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1099 base = spu->stride * walky + (unsigned int) unscaled_x;
1100 tmp = left /* * 1.0 */ * canon_alpha(spu->aimage[base]);
1101 alpha += tmp;
1102 color += tmp * spu->image[base];
1105 /* 5: center part */
1106 if (width > 0 && height > 0) {
1107 unsigned int walky;
1108 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1109 unsigned int walkx;
1110 base = spu->stride * walky;
1111 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
1112 tmp = /* 1.0 * 1.0 * */ canon_alpha(spu->aimage[base + walkx]);
1113 alpha += tmp;
1114 color += tmp * spu->image[base + walkx];
1118 /* 6: center right part */
1119 if (right > 0.0 && height > 0) {
1120 unsigned int walky;
1121 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1122 base = spu->stride * walky + (unsigned int) unscaled_x_right;
1123 tmp = right /* * 1.0 */ * canon_alpha(spu->aimage[base]);
1124 alpha += tmp;
1125 color += tmp * spu->image[base];
1128 /* 7: bottom left part */
1129 if (bottom > 0.0) {
1130 base = spu->stride * (unsigned int) unscaled_y_bottom + (unsigned int) unscaled_x;
1131 tmp = left * bottom * canon_alpha(spu->aimage[base]);
1132 alpha += tmp;
1133 color += tmp * spu->image[base];
1135 /* 8: bottom center part */
1136 if (width > 0 && bottom > 0.0) {
1137 unsigned int walkx;
1138 base = spu->stride * (unsigned int) unscaled_y_bottom;
1139 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
1140 tmp = /* 1.0 * */ bottom * canon_alpha(spu->aimage[base + walkx]);
1141 alpha += tmp;
1142 color += tmp * spu->image[base + walkx];
1145 /* 9: bottom right part */
1146 if (right > 0.0 && bottom > 0.0) {
1147 base = spu->stride * (unsigned int) unscaled_y_bottom + (unsigned int) unscaled_x_right;
1148 tmp = right * bottom * canon_alpha(spu->aimage[base]);
1149 alpha += tmp;
1150 color += tmp * spu->image[base];
1152 /* Finally mix these transparency and brightness information suitably */
1153 base = spu->scaled_stride * y + x;
1154 spu->scaled_image[base] = alpha > 0 ? color / alpha : 0;
1155 spu->scaled_aimage[base] = alpha * scalex * scaley / 0x10000;
1156 if (spu->scaled_aimage[base]) {
1157 spu->scaled_aimage[base] = 256 - spu->scaled_aimage[base];
1158 if (spu->scaled_aimage[base] + spu->scaled_image[base] > 255)
1159 spu->scaled_image[base] = 256 - spu->scaled_aimage[base];
1165 nothing_to_do:
1166 /* Kludge: draw_alpha needs width multiple of 8. */
1167 if (spu->scaled_width < spu->scaled_stride)
1168 for (y = 0; y < spu->scaled_height; ++y) {
1169 memset(spu->scaled_aimage + y * spu->scaled_stride + spu->scaled_width, 0,
1170 spu->scaled_stride - spu->scaled_width);
1172 spu->scaled_frame_width = dxs;
1173 spu->scaled_frame_height = dys;
1176 if (spu->scaled_image){
1177 switch (spu_alignment) {
1178 case 0:
1179 spu->scaled_start_row = dys*sub_pos/100;
1180 if (spu->scaled_start_row + spu->scaled_height > dys)
1181 spu->scaled_start_row = dys - spu->scaled_height;
1182 break;
1183 case 1:
1184 spu->scaled_start_row = dys*sub_pos/100 - spu->scaled_height/2;
1185 if (sub_pos >= 50 && spu->scaled_start_row + spu->scaled_height > dys)
1186 spu->scaled_start_row = dys - spu->scaled_height;
1187 break;
1188 case 2:
1189 spu->scaled_start_row = dys*sub_pos/100 - spu->scaled_height;
1190 break;
1192 draw_alpha(ctx, spu->scaled_start_col, spu->scaled_start_row, spu->scaled_width, spu->scaled_height,
1193 spu->scaled_image, spu->scaled_aimage, spu->scaled_stride);
1194 spu->spu_changed = 0;
1198 else
1200 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPU not displayed: start_pts=%d end_pts=%d now_pts=%d\n",
1201 spu->start_pts, spu->end_pts, spu->now_pts);
1205 void spudec_update_palette(void * this, unsigned int *palette)
1207 spudec_handle_t *spu = this;
1208 if (spu && palette) {
1209 memcpy(spu->global_palette, palette, sizeof(spu->global_palette));
1210 if(spu->hw_spu)
1211 vo_control(spu->hw_spu, VOCTRL_SET_SPU_PALETTE, spu->global_palette);
1215 void spudec_set_font_factor(void * this, double factor)
1217 spudec_handle_t *spu = this;
1218 spu->font_start_level = (int)(0xF0-(0xE0*factor));
1221 static void spudec_parse_extradata(spudec_handle_t *this,
1222 uint8_t *extradata, int extradata_len)
1224 uint8_t *buffer, *ptr;
1225 unsigned int *pal = this->global_palette, *cuspal = this->cuspal;
1226 unsigned int tridx;
1227 int i;
1229 if (extradata_len == 16*4) {
1230 for (i=0; i<16; i++)
1231 pal[i] = AV_RB32(extradata + i*4);
1232 this->auto_palette = 0;
1233 return;
1236 if (!(ptr = buffer = malloc(extradata_len+1)))
1237 return;
1238 memcpy(buffer, extradata, extradata_len);
1239 buffer[extradata_len] = 0;
1241 do {
1242 if (*ptr == '#')
1243 continue;
1244 if (!strncmp(ptr, "size: ", 6))
1245 sscanf(ptr + 6, "%dx%d", &this->orig_frame_width, &this->orig_frame_height);
1246 if (!strncmp(ptr, "palette: ", 9) &&
1247 sscanf(ptr + 9, "%x, %x, %x, %x, %x, %x, %x, %x, "
1248 "%x, %x, %x, %x, %x, %x, %x, %x",
1249 &pal[ 0], &pal[ 1], &pal[ 2], &pal[ 3],
1250 &pal[ 4], &pal[ 5], &pal[ 6], &pal[ 7],
1251 &pal[ 8], &pal[ 9], &pal[10], &pal[11],
1252 &pal[12], &pal[13], &pal[14], &pal[15]) == 16) {
1253 for (i=0; i<16; i++)
1254 pal[i] = vobsub_palette_to_yuv(pal[i]);
1255 this->auto_palette = 0;
1257 if (!strncasecmp(ptr, "forced subs: on", 15))
1258 this->forced_subs_only = 1;
1259 if (!strncmp(ptr, "custom colors: ON, tridx: ", 26) &&
1260 sscanf(ptr + 26, "%x, colors: %x, %x, %x, %x",
1261 &tridx, cuspal+0, cuspal+1, cuspal+2, cuspal+3) == 5) {
1262 for (i=0; i<4; i++) {
1263 cuspal[i] = vobsub_rgb_to_yuv(cuspal[i]);
1264 if (tridx & (1 << (12-4*i)))
1265 cuspal[i] |= 1 << 31;
1267 this->custom = 1;
1269 } while ((ptr=strchr(ptr,'\n')) && *++ptr);
1271 free(buffer);
1274 void *spudec_new_scaled(unsigned int *palette, unsigned int frame_width, unsigned int frame_height, uint8_t *extradata, int extradata_len)
1276 spudec_handle_t *this = calloc(1, sizeof(spudec_handle_t));
1277 if (this){
1278 this->orig_frame_height = frame_height;
1279 this->orig_frame_width = frame_width;
1280 // set up palette:
1281 if (palette)
1282 memcpy(this->global_palette, palette, sizeof(this->global_palette));
1283 else
1284 this->auto_palette = 1;
1285 if (extradata)
1286 spudec_parse_extradata(this, extradata, extradata_len);
1287 /* XXX Although the video frame is some size, the SPU frame is
1288 always maximum size i.e. 720 wide and 576 or 480 high */
1289 // For HD files in MKV the VobSub resolution can be higher though,
1290 // see largeres_vobsub.mkv
1291 if (this->orig_frame_width <= 720 && this->orig_frame_height <= 576) {
1292 this->orig_frame_width = 720;
1293 if (this->orig_frame_height == 480 || this->orig_frame_height == 240)
1294 this->orig_frame_height = 480;
1295 else
1296 this->orig_frame_height = 576;
1299 else
1300 mp_msg(MSGT_SPUDEC,MSGL_FATAL, "FATAL: spudec_init: calloc");
1301 return this;
1304 void *spudec_new(unsigned int *palette)
1306 return spudec_new_scaled(palette, 0, 0, NULL, 0);
1309 void spudec_free(void *this)
1311 spudec_handle_t *spu = this;
1312 if (spu) {
1313 while (spu->queue_head)
1314 spudec_free_packet(spudec_dequeue_packet(spu));
1315 free(spu->packet);
1316 spu->packet = NULL;
1317 free(spu->scaled_image);
1318 spu->scaled_image = NULL;
1319 free(spu->image);
1320 spu->image = NULL;
1321 spu->aimage = NULL;
1322 free(spu->pal_image);
1323 spu->pal_image = NULL;
1324 spu->image_size = 0;
1325 spu->pal_width = spu->pal_height = 0;
1326 free(spu);
1330 void spudec_set_hw_spu(void *this, struct vo *hw_spu)
1332 spudec_handle_t *spu = this;
1333 if (!spu)
1334 return;
1335 spu->hw_spu = hw_spu;
1336 vo_control(hw_spu, VOCTRL_SET_SPU_PALETTE, spu->global_palette);
1339 #define MP_NOPTS_VALUE (-1LL<<63) //both int64_t and double should be able to represent this exactly
1342 * palette must contain at least 256 32-bit entries, otherwise crashes
1343 * are possible
1345 void spudec_set_paletted(void *this, const uint8_t *pal_img, int pal_stride,
1346 const void *palette,
1347 int x, int y, int w, int h,
1348 double pts, double endpts)
1350 int i;
1351 uint16_t g8a8_pal[256];
1352 packet_t *packet;
1353 const uint32_t *pal = palette;
1354 spudec_handle_t *spu = this;
1355 uint8_t *img;
1356 uint8_t *aimg;
1357 int stride = (w + 7) & ~7;
1358 if ((unsigned)w >= 0x8000 || (unsigned)h > 0x4000)
1359 return;
1360 packet = calloc(1, sizeof(packet_t));
1361 packet->is_decoded = 1;
1362 packet->width = w;
1363 packet->height = h;
1364 packet->stride = stride;
1365 packet->start_col = x;
1366 packet->start_row = y;
1367 packet->data_len = 2 * stride * h;
1368 if (packet->data_len) { // size 0 is a special "clear" packet
1369 packet->packet = malloc(packet->data_len);
1370 img = packet->packet;
1371 aimg = packet->packet + stride * h;
1372 for (i = 0; i < 256; i++) {
1373 uint32_t pixel = pal[i];
1374 int alpha = pixel >> 24;
1375 int gray = (((pixel & 0x000000ff) >> 0) +
1376 ((pixel & 0x0000ff00) >> 7) +
1377 ((pixel & 0x00ff0000) >> 16)) >> 2;
1378 gray = FFMIN(gray, alpha);
1379 g8a8_pal[i] = (-alpha << 8) | gray;
1381 pal2gray_alpha(g8a8_pal, pal_img, pal_stride,
1382 img, aimg, stride, w, h);
1384 packet->start_pts = 0;
1385 packet->end_pts = 0x7fffffff;
1386 if (pts != MP_NOPTS_VALUE)
1387 packet->start_pts = pts * 90000;
1388 if (endpts != MP_NOPTS_VALUE)
1389 packet->end_pts = endpts * 90000;
1390 spudec_queue_packet(spu, packet);