spudec.c: Remove useless NULL checks before free()
[mplayer/glamo.git] / spudec.c
blob500a133e4affbe5398e920041af28fd76a727148
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 char *pal_image; /* palette entry value */
102 unsigned int scaled_frame_width, scaled_frame_height;
103 unsigned int scaled_start_col, scaled_start_row;
104 unsigned int scaled_width, scaled_height, scaled_stride;
105 size_t scaled_image_size;
106 unsigned char *scaled_image;
107 unsigned char *scaled_aimage;
108 int auto_palette; /* 1 if we lack a palette and must use an heuristic. */
109 int font_start_level; /* Darkest value used for the computed font */
110 struct vo *hw_spu;
111 int spu_changed;
112 unsigned int forced_subs_only; /* flag: 0=display all subtitle, !0 display only forced subtitles */
113 unsigned int is_forced_sub; /* true if current subtitle is a forced subtitle */
114 } spudec_handle_t;
116 static void spudec_queue_packet(spudec_handle_t *this, packet_t *packet)
118 if (this->queue_head == NULL)
119 this->queue_head = packet;
120 else
121 this->queue_tail->next = packet;
122 this->queue_tail = packet;
125 static packet_t *spudec_dequeue_packet(spudec_handle_t *this)
127 packet_t *retval = this->queue_head;
129 this->queue_head = retval->next;
130 if (this->queue_head == NULL)
131 this->queue_tail = NULL;
133 return retval;
136 static void spudec_free_packet(packet_t *packet)
138 if (packet->packet != NULL)
139 free(packet->packet);
140 free(packet);
143 static inline unsigned int get_be16(const unsigned char *p)
145 return (p[0] << 8) + p[1];
148 static inline unsigned int get_be24(const unsigned char *p)
150 return (get_be16(p) << 8) + p[2];
153 static void next_line(packet_t *packet)
155 if (packet->current_nibble[packet->deinterlace_oddness] % 2)
156 packet->current_nibble[packet->deinterlace_oddness]++;
157 packet->deinterlace_oddness = (packet->deinterlace_oddness + 1) % 2;
160 static inline unsigned char get_nibble(packet_t *packet)
162 unsigned char nib;
163 unsigned int *nibblep = packet->current_nibble + packet->deinterlace_oddness;
164 if (*nibblep / 2 >= packet->control_start) {
165 mp_msg(MSGT_SPUDEC,MSGL_WARN, "SPUdec: ERROR: get_nibble past end of packet\n");
166 return 0;
168 nib = packet->packet[*nibblep / 2];
169 if (*nibblep % 2)
170 nib &= 0xf;
171 else
172 nib >>= 4;
173 ++*nibblep;
174 return nib;
177 /* Cut the sub to visible part */
178 static inline void spudec_cut_image(spudec_handle_t *this)
180 unsigned int fy, ly;
181 unsigned int first_y, last_y;
182 unsigned char *image;
183 unsigned char *aimage;
185 if (this->stride == 0 || this->height == 0) {
186 return;
189 for (fy = 0; fy < this->image_size && !this->aimage[fy]; fy++);
190 for (ly = this->stride * this->height-1; ly && !this->aimage[ly]; ly--);
191 first_y = fy / this->stride;
192 last_y = ly / this->stride;
193 //printf("first_y: %d, last_y: %d\n", first_y, last_y);
194 this->start_row += first_y;
196 // Some subtitles trigger this condition
197 if (last_y + 1 > first_y ) {
198 this->height = last_y - first_y +1;
199 } else {
200 this->height = 0;
201 this->image_size = 0;
202 return;
205 // printf("new h %d new start %d (sz %d st %d)---\n\n", this->height, this->start_row, this->image_size, this->stride);
207 image = malloc(2 * this->stride * this->height);
208 if(image){
209 this->image_size = this->stride * this->height;
210 aimage = image + this->image_size;
211 memcpy(image, this->image + this->stride * first_y, this->image_size);
212 memcpy(aimage, this->aimage + this->stride * first_y, this->image_size);
213 free(this->image);
214 this->image = image;
215 this->aimage = aimage;
216 } else {
217 mp_msg(MSGT_SPUDEC, MSGL_FATAL, "Fatal: update_spu: malloc requested %d bytes\n", 2 * this->stride * this->height);
222 static int spudec_alloc_image(spudec_handle_t *this, int stride, int height)
224 if (this->width > stride) // just a safeguard
225 this->width = stride;
226 this->stride = stride;
227 this->height = height;
228 if (this->image_size < this->stride * this->height) {
229 if (this->image != NULL) {
230 free(this->image);
231 free(this->pal_image);
232 this->image_size = 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 void spudec_process_data(spudec_handle_t *this, packet_t *packet)
270 uint16_t pal[4];
271 unsigned int i, x, y;
272 uint8_t *dst;
274 this->scaled_frame_width = 0;
275 this->scaled_frame_height = 0;
276 this->start_col = packet->start_col;
277 this->end_col = packet->end_col;
278 this->start_row = packet->start_row;
279 this->end_row = packet->end_row;
280 this->height = packet->height;
281 this->width = packet->width;
282 this->stride = packet->stride;
283 for (i = 0; i < 4; ++i) {
284 int color;
285 int alpha = packet->alpha[i];
286 // extend 4 -> 8 bit
287 alpha |= alpha << 4;
288 if (this->custom && (this->cuspal[i] >> 31) != 0)
289 alpha = 0;
290 color = this->custom ? this->cuspal[i] :
291 this->global_palette[packet->palette[i]];
292 color = (color >> 16) & 0xff;
293 // convert to MPlayer-style gray/alpha palette
294 color = FFMIN(color, alpha);
295 pal[i] = (-alpha << 8) | color;
298 if (!spudec_alloc_image(this, this->stride, this->height))
299 return;
301 i = packet->current_nibble[1];
302 x = 0;
303 y = 0;
304 dst = this->pal_image;
305 while (packet->current_nibble[0] < i
306 && packet->current_nibble[1] / 2 < packet->control_start
307 && y < this->height) {
308 unsigned int len, color;
309 unsigned int rle = 0;
310 rle = get_nibble(packet);
311 if (rle < 0x04) {
312 rle = (rle << 4) | get_nibble(packet);
313 if (rle < 0x10) {
314 rle = (rle << 4) | get_nibble(packet);
315 if (rle < 0x040) {
316 rle = (rle << 4) | get_nibble(packet);
317 if (rle < 0x0004)
318 rle |= ((this->width - x) << 2);
322 color = 3 - (rle & 0x3);
323 len = rle >> 2;
324 x += len;
325 if (len == 0 || x >= this->width) {
326 len += this->width - x;
327 next_line(packet);
328 x = 0;
329 ++y;
331 memset(dst, color, len);
332 dst += len;
334 pal2gray_alpha(pal, this->pal_image, this->width,
335 this->image, this->aimage, this->stride,
336 this->width, this->height);
337 spudec_cut_image(this);
342 This function tries to create a usable palette.
343 It determines how many non-transparent colors are used, and assigns different
344 gray scale values to each color.
345 I tested it with four streams and even got something readable. Half of the
346 times I got black characters with white around and half the reverse.
348 static void compute_palette(spudec_handle_t *this, packet_t *packet)
350 int used[16],i,cused,start,step,color;
352 memset(used, 0, sizeof(used));
353 for (i=0; i<4; i++)
354 if (packet->alpha[i]) /* !Transparent? */
355 used[packet->palette[i]] = 1;
356 for (cused=0, i=0; i<16; i++)
357 if (used[i]) cused++;
358 if (!cused) return;
359 if (cused == 1) {
360 start = 0x80;
361 step = 0;
362 } else {
363 start = this->font_start_level;
364 step = (0xF0-this->font_start_level)/(cused-1);
366 memset(used, 0, sizeof(used));
367 for (i=0; i<4; i++) {
368 color = packet->palette[i];
369 if (packet->alpha[i] && !used[color]) { /* not assigned? */
370 used[color] = 1;
371 this->global_palette[color] = start<<16;
372 start += step;
377 static void spudec_process_control(spudec_handle_t *this, int pts100)
379 int a,b,c,d; /* Temporary vars */
380 unsigned int date, type;
381 unsigned int off;
382 unsigned int start_off = 0;
383 unsigned int next_off;
384 unsigned int start_pts = 0;
385 unsigned int end_pts = 0;
386 unsigned int current_nibble[2] = {0, 0};
387 unsigned int control_start;
388 unsigned int display = 0;
389 unsigned int start_col = 0;
390 unsigned int end_col = 0;
391 unsigned int start_row = 0;
392 unsigned int end_row = 0;
393 unsigned int width = 0;
394 unsigned int height = 0;
395 unsigned int stride = 0;
397 control_start = get_be16(this->packet + 2);
398 next_off = control_start;
399 while (start_off != next_off) {
400 start_off = next_off;
401 date = get_be16(this->packet + start_off) * 1024;
402 next_off = get_be16(this->packet + start_off + 2);
403 mp_msg(MSGT_SPUDEC,MSGL_DBG2, "date=%d\n", date);
404 off = start_off + 4;
405 for (type = this->packet[off++]; type != 0xff; type = this->packet[off++]) {
406 mp_msg(MSGT_SPUDEC,MSGL_DBG2, "cmd=%d ",type);
407 switch(type) {
408 case 0x00:
409 /* Menu ID, 1 byte */
410 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Menu ID\n");
411 /* shouldn't a Menu ID type force display start? */
412 start_pts = pts100 < 0 && -pts100 >= date ? 0 : pts100 + date;
413 end_pts = UINT_MAX;
414 display = 1;
415 this->is_forced_sub=~0; // current subtitle is forced
416 break;
417 case 0x01:
418 /* Start display */
419 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Start display!\n");
420 start_pts = pts100 < 0 && -pts100 >= date ? 0 : pts100 + date;
421 end_pts = UINT_MAX;
422 display = 1;
423 this->is_forced_sub=0;
424 break;
425 case 0x02:
426 /* Stop display */
427 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Stop display!\n");
428 end_pts = pts100 < 0 && -pts100 >= date ? 0 : pts100 + date;
429 break;
430 case 0x03:
431 /* Palette */
432 this->palette[0] = this->packet[off] >> 4;
433 this->palette[1] = this->packet[off] & 0xf;
434 this->palette[2] = this->packet[off + 1] >> 4;
435 this->palette[3] = this->packet[off + 1] & 0xf;
436 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Palette %d, %d, %d, %d\n",
437 this->palette[0], this->palette[1], this->palette[2], this->palette[3]);
438 off+=2;
439 break;
440 case 0x04:
441 /* Alpha */
442 a = this->packet[off] >> 4;
443 b = this->packet[off] & 0xf;
444 c = this->packet[off + 1] >> 4;
445 d = this->packet[off + 1] & 0xf;
446 // Note: some DVDs change these values to create a fade-in/fade-out effect
447 // We can not handle this, so just keep the highest value during the display time.
448 if (display) {
449 a = FFMAX(a, this->alpha[0]);
450 b = FFMAX(b, this->alpha[1]);
451 c = FFMAX(c, this->alpha[2]);
452 d = FFMAX(d, this->alpha[3]);
454 this->alpha[0] = a;
455 this->alpha[1] = b;
456 this->alpha[2] = c;
457 this->alpha[3] = d;
458 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Alpha %d, %d, %d, %d\n",
459 this->alpha[0], this->alpha[1], this->alpha[2], this->alpha[3]);
460 off+=2;
461 break;
462 case 0x05:
463 /* Co-ords */
464 a = get_be24(this->packet + off);
465 b = get_be24(this->packet + off + 3);
466 start_col = a >> 12;
467 end_col = a & 0xfff;
468 width = (end_col < start_col) ? 0 : end_col - start_col + 1;
469 stride = (width + 7) & ~7; /* Kludge: draw_alpha needs width multiple of 8 */
470 start_row = b >> 12;
471 end_row = b & 0xfff;
472 height = (end_row < start_row) ? 0 : end_row - start_row /* + 1 */;
473 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Coords col: %d - %d row: %d - %d (%dx%d)\n",
474 start_col, end_col, start_row, end_row,
475 width, height);
476 off+=6;
477 break;
478 case 0x06:
479 /* Graphic lines */
480 current_nibble[0] = 2 * get_be16(this->packet + off);
481 current_nibble[1] = 2 * get_be16(this->packet + off + 2);
482 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Graphic offset 1: %d offset 2: %d\n",
483 current_nibble[0] / 2, current_nibble[1] / 2);
484 off+=4;
485 break;
486 case 0xff:
487 /* All done, bye-bye */
488 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Done!\n");
489 return;
490 // break;
491 default:
492 mp_msg(MSGT_SPUDEC,MSGL_WARN,"spudec: Error determining control type 0x%02x. Skipping %d bytes.\n",
493 type, next_off - off);
494 goto next_control;
497 next_control:
498 if (!display)
499 continue;
500 if (end_pts == UINT_MAX && start_off != next_off) {
501 end_pts = get_be16(this->packet + next_off) * 1024;
502 end_pts = 1 - pts100 >= end_pts ? 0 : pts100 + end_pts - 1;
504 if (end_pts > 0) {
505 packet_t *packet = calloc(1, sizeof(packet_t));
506 int i;
507 packet->start_pts = start_pts;
508 packet->end_pts = end_pts;
509 packet->current_nibble[0] = current_nibble[0];
510 packet->current_nibble[1] = current_nibble[1];
511 packet->start_row = start_row;
512 packet->end_row = end_row;
513 packet->start_col = start_col;
514 packet->end_col = end_col;
515 packet->width = width;
516 packet->height = height;
517 packet->stride = stride;
518 packet->control_start = control_start;
519 for (i=0; i<4; i++) {
520 packet->alpha[i] = this->alpha[i];
521 packet->palette[i] = this->palette[i];
523 packet->packet = malloc(this->packet_size);
524 memcpy(packet->packet, this->packet, this->packet_size);
525 spudec_queue_packet(this, packet);
530 static void spudec_decode(spudec_handle_t *this, int pts100)
532 if (!this->hw_spu)
533 spudec_process_control(this, pts100);
534 else if (pts100 >= 0) {
535 static vo_mpegpes_t packet = { NULL, 0, 0x20, 0 };
536 static vo_mpegpes_t *pkg=&packet;
537 packet.data = this->packet;
538 packet.size = this->packet_size;
539 packet.timestamp = pts100;
540 vo_draw_frame(this->hw_spu, (uint8_t**)&pkg);
544 int spudec_changed(void * this)
546 spudec_handle_t * spu = this;
547 return spu->spu_changed || spu->now_pts > spu->end_pts;
550 void spudec_assemble(void *this, unsigned char *packet, unsigned int len, int pts100)
552 spudec_handle_t *spu = this;
553 // spudec_heartbeat(this, pts100);
554 if (len < 2) {
555 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: packet too short\n");
556 return;
558 spu->packet_pts = pts100;
559 if (spu->packet_offset == 0) {
560 unsigned int len2 = get_be16(packet);
561 // Start new fragment
562 if (spu->packet_reserve < len2) {
563 if (spu->packet != NULL)
564 free(spu->packet);
565 spu->packet = malloc(len2);
566 spu->packet_reserve = spu->packet != NULL ? len2 : 0;
568 if (spu->packet != NULL) {
569 spu->packet_size = len2;
570 if (len > len2) {
571 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: invalid frag len / len2: %d / %d \n", len, len2);
572 return;
574 memcpy(spu->packet, packet, len);
575 spu->packet_offset = len;
576 spu->packet_pts = pts100;
578 } else {
579 // Continue current fragment
580 if (spu->packet_size < spu->packet_offset + len){
581 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: invalid fragment\n");
582 spu->packet_size = spu->packet_offset = 0;
583 return;
584 } else {
585 memcpy(spu->packet + spu->packet_offset, packet, len);
586 spu->packet_offset += len;
589 #if 1
590 // check if we have a complete packet (unfortunatelly packet_size is bad
591 // for some disks)
592 // [cb] packet_size is padded to be even -> may be one byte too long
593 if ((spu->packet_offset == spu->packet_size) ||
594 ((spu->packet_offset + 1) == spu->packet_size)){
595 unsigned int x=0,y;
596 while(x+4<=spu->packet_offset){
597 y=get_be16(spu->packet+x+2); // next control pointer
598 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPUtest: x=%d y=%d off=%d size=%d\n",x,y,spu->packet_offset,spu->packet_size);
599 if(x>=4 && x==y){ // if it points to self - we're done!
600 // we got it!
601 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPUgot: off=%d size=%d \n",spu->packet_offset,spu->packet_size);
602 spudec_decode(spu, pts100);
603 spu->packet_offset = 0;
604 break;
606 if(y<=x || y>=spu->packet_size){ // invalid?
607 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUtest: broken packet!!!!! y=%d < x=%d\n",y,x);
608 spu->packet_size = spu->packet_offset = 0;
609 break;
611 x=y;
613 // [cb] packet is done; start new packet
614 spu->packet_offset = 0;
616 #else
617 if (spu->packet_offset == spu->packet_size) {
618 spudec_decode(spu, pts100);
619 spu->packet_offset = 0;
621 #endif
624 void spudec_reset(void *this) // called after seek
626 spudec_handle_t *spu = this;
627 while (spu->queue_head)
628 spudec_free_packet(spudec_dequeue_packet(spu));
629 spu->now_pts = 0;
630 spu->end_pts = 0;
631 spu->packet_size = spu->packet_offset = 0;
634 void spudec_heartbeat(void *this, unsigned int pts100)
636 spudec_handle_t *spu = this;
637 spu->now_pts = pts100;
639 // TODO: detect and handle broken timestamps (e.g. due to wrapping)
640 while (spu->queue_head != NULL && pts100 >= spu->queue_head->start_pts) {
641 packet_t *packet = spudec_dequeue_packet(spu);
642 spu->start_pts = packet->start_pts;
643 spu->end_pts = packet->end_pts;
644 if (packet->is_decoded) {
645 free(spu->image);
646 spu->image_size = packet->data_len;
647 spu->image = packet->packet;
648 spu->aimage = packet->packet + packet->stride * packet->height;
649 packet->packet = NULL;
650 spu->width = packet->width;
651 spu->height = packet->height;
652 spu->stride = packet->stride;
653 spu->start_col = packet->start_col;
654 spu->start_row = packet->start_row;
656 // reset scaled image
657 spu->scaled_frame_width = 0;
658 spu->scaled_frame_height = 0;
659 } else {
660 if (spu->auto_palette)
661 compute_palette(spu, packet);
662 spudec_process_data(spu, packet);
664 spudec_free_packet(packet);
665 spu->spu_changed = 1;
669 int spudec_visible(void *this){
670 spudec_handle_t *spu = this;
671 int ret=(spu->start_pts <= spu->now_pts &&
672 spu->now_pts < spu->end_pts &&
673 spu->height > 0);
674 // printf("spu visible: %d \n",ret);
675 return ret;
678 void spudec_set_forced_subs_only(void * const this, const unsigned int flag)
680 if(this){
681 ((spudec_handle_t *)this)->forced_subs_only=flag;
682 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPU: Display only forced subs now %s\n", flag ? "enabled": "disabled");
686 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)
688 spudec_handle_t *spu = this;
689 if (spudec_visible(spu))
691 draw_alpha(ctx, spu->start_col, spu->start_row, spu->width, spu->height,
692 spu->image, spu->aimage, spu->stride);
693 spu->spu_changed = 0;
697 /* calc the bbox for spudec subs */
698 void spudec_calc_bbox(void *me, unsigned int dxs, unsigned int dys, unsigned int* bbox)
700 spudec_handle_t *spu = me;
701 if (spu->orig_frame_width == 0 || spu->orig_frame_height == 0
702 || (spu->orig_frame_width == dxs && spu->orig_frame_height == dys)) {
703 // unscaled
704 bbox[0] = spu->start_col;
705 bbox[1] = spu->start_col + spu->width;
706 bbox[2] = spu->start_row;
707 bbox[3] = spu->start_row + spu->height;
709 else {
710 // scaled
711 unsigned int scalex = 0x100 * dxs / spu->orig_frame_width;
712 unsigned int scaley = 0x100 * dys / spu->orig_frame_height;
713 bbox[0] = spu->start_col * scalex / 0x100;
714 bbox[1] = spu->start_col * scalex / 0x100 + spu->width * scalex / 0x100;
715 switch (spu_alignment) {
716 case 0:
717 bbox[3] = dys*sub_pos/100 + spu->height * scaley / 0x100;
718 if (bbox[3] > dys) bbox[3] = dys;
719 bbox[2] = bbox[3] - spu->height * scaley / 0x100;
720 break;
721 case 1:
722 if (sub_pos < 50) {
723 bbox[2] = dys*sub_pos/100 - spu->height * scaley / 0x200;
724 bbox[3] = bbox[2] + spu->height;
725 } else {
726 bbox[3] = dys*sub_pos/100 + spu->height * scaley / 0x200;
727 if (bbox[3] > dys) bbox[3] = dys;
728 bbox[2] = bbox[3] - spu->height * scaley / 0x100;
730 break;
731 case 2:
732 bbox[2] = dys*sub_pos/100 - spu->height * scaley / 0x100;
733 bbox[3] = bbox[2] + spu->height;
734 break;
735 default: /* -1 */
736 bbox[2] = spu->start_row * scaley / 0x100;
737 bbox[3] = spu->start_row * scaley / 0x100 + spu->height * scaley / 0x100;
738 break;
742 /* transform mplayer's alpha value into an opacity value that is linear */
743 static inline int canon_alpha(int alpha)
745 return (uint8_t)-alpha;
748 typedef struct {
749 unsigned position;
750 unsigned left_up;
751 unsigned right_down;
752 }scale_pixel;
755 static void scale_table(unsigned int start_src, unsigned int start_tar, unsigned int end_src, unsigned int end_tar, scale_pixel * table)
757 unsigned int t;
758 unsigned int delta_src = end_src - start_src;
759 unsigned int delta_tar = end_tar - start_tar;
760 int src = 0;
761 int src_step;
762 if (delta_src == 0 || delta_tar == 0) {
763 return;
765 src_step = (delta_src << 16) / delta_tar >>1;
766 for (t = 0; t<=delta_tar; src += (src_step << 1), t++){
767 table[t].position= FFMIN(src >> 16, end_src - 1);
768 table[t].right_down = src & 0xffff;
769 table[t].left_up = 0x10000 - table[t].right_down;
773 /* bilinear scale, similar to vobsub's code */
774 static void scale_image(int x, int y, scale_pixel* table_x, scale_pixel* table_y, spudec_handle_t * spu)
776 int alpha[4];
777 int color[4];
778 unsigned int scale[4];
779 int base = table_y[y].position * spu->stride + table_x[x].position;
780 int scaled = y * spu->scaled_stride + x;
781 alpha[0] = canon_alpha(spu->aimage[base]);
782 alpha[1] = canon_alpha(spu->aimage[base + 1]);
783 alpha[2] = canon_alpha(spu->aimage[base + spu->stride]);
784 alpha[3] = canon_alpha(spu->aimage[base + spu->stride + 1]);
785 color[0] = spu->image[base];
786 color[1] = spu->image[base + 1];
787 color[2] = spu->image[base + spu->stride];
788 color[3] = spu->image[base + spu->stride + 1];
789 scale[0] = (table_x[x].left_up * table_y[y].left_up >> 16) * alpha[0];
790 if (table_y[y].left_up == 0x10000) // necessary to avoid overflow-case
791 scale[0] = table_x[x].left_up * alpha[0];
792 scale[1] = (table_x[x].right_down * table_y[y].left_up >>16) * alpha[1];
793 scale[2] = (table_x[x].left_up * table_y[y].right_down >> 16) * alpha[2];
794 scale[3] = (table_x[x].right_down * table_y[y].right_down >> 16) * alpha[3];
795 spu->scaled_image[scaled] = (color[0] * scale[0] + color[1] * scale[1] + color[2] * scale[2] + color[3] * scale[3])>>24;
796 spu->scaled_aimage[scaled] = (scale[0] + scale[1] + scale[2] + scale[3]) >> 16;
797 if (spu->scaled_aimage[scaled]){
798 // ensure that MPlayer's simplified alpha-blending can not overflow
799 spu->scaled_image[scaled] = FFMIN(spu->scaled_image[scaled], spu->scaled_aimage[scaled]);
800 // convert to MPlayer-style alpha
801 spu->scaled_aimage[scaled] = -spu->scaled_aimage[scaled];
805 static void sws_spu_image(unsigned char *d1, unsigned char *d2, int dw, int dh,
806 int ds, unsigned char *s1, unsigned char *s2, int sw,
807 int sh, int ss)
809 struct SwsContext *ctx;
810 static SwsFilter filter;
811 static int firsttime = 1;
812 static float oldvar;
813 int i;
815 if (!firsttime && oldvar != spu_gaussvar) sws_freeVec(filter.lumH);
816 if (firsttime) {
817 filter.lumH = filter.lumV =
818 filter.chrH = filter.chrV = sws_getGaussianVec(spu_gaussvar, 3.0);
819 sws_normalizeVec(filter.lumH, 1.0);
820 firsttime = 0;
821 oldvar = spu_gaussvar;
824 ctx=sws_getContext(sw, sh, PIX_FMT_GRAY8, dw, dh, PIX_FMT_GRAY8, SWS_GAUSS, &filter, NULL, NULL);
825 sws_scale(ctx,&s1,&ss,0,sh,&d1,&ds);
826 for (i=ss*sh-1; i>=0; i--) if (!s2[i]) s2[i] = 255; //else s2[i] = 1;
827 sws_scale(ctx,&s2,&ss,0,sh,&d2,&ds);
828 for (i=ds*dh-1; i>=0; i--) if (d2[i]==0) d2[i] = 1; else if (d2[i]==255) d2[i] = 0;
829 sws_freeContext(ctx);
832 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)
834 spudec_handle_t *spu = me;
835 scale_pixel *table_x;
836 scale_pixel *table_y;
838 if (spudec_visible(spu)) {
840 // check if only forced subtitles are requested
841 if( (spu->forced_subs_only) && !(spu->is_forced_sub) ){
842 return;
845 if (!(spu_aamode&16) && (spu->orig_frame_width == 0 || spu->orig_frame_height == 0
846 || (spu->orig_frame_width == dxs && spu->orig_frame_height == dys))) {
847 spudec_draw(spu, draw_alpha, ctx);
849 else {
850 if (spu->scaled_frame_width != dxs || spu->scaled_frame_height != dys) { /* Resizing is needed */
851 /* scaled_x = scalex * x / 0x100
852 scaled_y = scaley * y / 0x100
853 order of operations is important because of rounding. */
854 unsigned int scalex = 0x100 * dxs / spu->orig_frame_width;
855 unsigned int scaley = 0x100 * dys / spu->orig_frame_height;
856 spu->scaled_start_col = spu->start_col * scalex / 0x100;
857 spu->scaled_start_row = spu->start_row * scaley / 0x100;
858 spu->scaled_width = spu->width * scalex / 0x100;
859 spu->scaled_height = spu->height * scaley / 0x100;
860 /* Kludge: draw_alpha needs width multiple of 8 */
861 spu->scaled_stride = (spu->scaled_width + 7) & ~7;
862 if (spu->scaled_image_size < spu->scaled_stride * spu->scaled_height) {
863 if (spu->scaled_image) {
864 free(spu->scaled_image);
865 spu->scaled_image_size = 0;
867 spu->scaled_image = malloc(2 * spu->scaled_stride * spu->scaled_height);
868 if (spu->scaled_image) {
869 spu->scaled_image_size = spu->scaled_stride * spu->scaled_height;
870 spu->scaled_aimage = spu->scaled_image + spu->scaled_image_size;
873 if (spu->scaled_image) {
874 unsigned int x, y;
875 if (spu->scaled_width <= 1 || spu->scaled_height <= 1) {
876 goto nothing_to_do;
878 switch(spu_aamode&15) {
879 case 4:
880 sws_spu_image(spu->scaled_image, spu->scaled_aimage,
881 spu->scaled_width, spu->scaled_height, spu->scaled_stride,
882 spu->image, spu->aimage, spu->width, spu->height, spu->stride);
883 break;
884 case 3:
885 table_x = calloc(spu->scaled_width, sizeof(scale_pixel));
886 table_y = calloc(spu->scaled_height, sizeof(scale_pixel));
887 if (!table_x || !table_y) {
888 mp_msg(MSGT_SPUDEC, MSGL_FATAL, "Fatal: spudec_draw_scaled: calloc failed\n");
890 scale_table(0, 0, spu->width - 1, spu->scaled_width - 1, table_x);
891 scale_table(0, 0, spu->height - 1, spu->scaled_height - 1, table_y);
892 for (y = 0; y < spu->scaled_height; y++)
893 for (x = 0; x < spu->scaled_width; x++)
894 scale_image(x, y, table_x, table_y, spu);
895 free(table_x);
896 free(table_y);
897 break;
898 case 0:
899 /* no antialiasing */
900 for (y = 0; y < spu->scaled_height; ++y) {
901 int unscaled_y = y * 0x100 / scaley;
902 int strides = spu->stride * unscaled_y;
903 int scaled_strides = spu->scaled_stride * y;
904 for (x = 0; x < spu->scaled_width; ++x) {
905 int unscaled_x = x * 0x100 / scalex;
906 spu->scaled_image[scaled_strides + x] = spu->image[strides + unscaled_x];
907 spu->scaled_aimage[scaled_strides + x] = spu->aimage[strides + unscaled_x];
910 break;
911 case 1:
913 /* Intermediate antialiasing. */
914 for (y = 0; y < spu->scaled_height; ++y) {
915 const unsigned int unscaled_top = y * spu->orig_frame_height / dys;
916 unsigned int unscaled_bottom = (y + 1) * spu->orig_frame_height / dys;
917 if (unscaled_bottom >= spu->height)
918 unscaled_bottom = spu->height - 1;
919 for (x = 0; x < spu->scaled_width; ++x) {
920 const unsigned int unscaled_left = x * spu->orig_frame_width / dxs;
921 unsigned int unscaled_right = (x + 1) * spu->orig_frame_width / dxs;
922 unsigned int color = 0;
923 unsigned int alpha = 0;
924 unsigned int walkx, walky;
925 unsigned int base, tmp;
926 if (unscaled_right >= spu->width)
927 unscaled_right = spu->width - 1;
928 for (walky = unscaled_top; walky <= unscaled_bottom; ++walky)
929 for (walkx = unscaled_left; walkx <= unscaled_right; ++walkx) {
930 base = walky * spu->stride + walkx;
931 tmp = canon_alpha(spu->aimage[base]);
932 alpha += tmp;
933 color += tmp * spu->image[base];
935 base = y * spu->scaled_stride + x;
936 spu->scaled_image[base] = alpha ? color / alpha : 0;
937 spu->scaled_aimage[base] =
938 alpha * (1 + unscaled_bottom - unscaled_top) * (1 + unscaled_right - unscaled_left);
939 /* spu->scaled_aimage[base] =
940 alpha * dxs * dys / spu->orig_frame_width / spu->orig_frame_height; */
941 if (spu->scaled_aimage[base]) {
942 spu->scaled_aimage[base] = 256 - spu->scaled_aimage[base];
943 if (spu->scaled_aimage[base] + spu->scaled_image[base] > 255)
944 spu->scaled_image[base] = 256 - spu->scaled_aimage[base];
949 break;
950 case 2:
952 /* Best antialiasing. Very slow. */
953 /* Any pixel (x, y) represents pixels from the original
954 rectangular region comprised between the columns
955 unscaled_y and unscaled_y + 0x100 / scaley and the rows
956 unscaled_x and unscaled_x + 0x100 / scalex
958 The original rectangular region that the scaled pixel
959 represents is cut in 9 rectangular areas like this:
961 +---+-----------------+---+
962 | 1 | 2 | 3 |
963 +---+-----------------+---+
964 | | | |
965 | 4 | 5 | 6 |
966 | | | |
967 +---+-----------------+---+
968 | 7 | 8 | 9 |
969 +---+-----------------+---+
971 The width of the left column is at most one pixel and
972 it is never null and its right column is at a pixel
973 boundary. The height of the top row is at most one
974 pixel it is never null and its bottom row is at a
975 pixel boundary. The width and height of region 5 are
976 integral values. The width of the right column is
977 what remains and is less than one pixel. The height
978 of the bottom row is what remains and is less than
979 one pixel.
981 The row above 1, 2, 3 is unscaled_y. The row between
982 1, 2, 3 and 4, 5, 6 is top_low_row. The row between 4,
983 5, 6 and 7, 8, 9 is (unsigned int)unscaled_y_bottom.
984 The row beneath 7, 8, 9 is unscaled_y_bottom.
986 The column left of 1, 4, 7 is unscaled_x. The column
987 between 1, 4, 7 and 2, 5, 8 is left_right_column. The
988 column between 2, 5, 8 and 3, 6, 9 is (unsigned
989 int)unscaled_x_right. The column right of 3, 6, 9 is
990 unscaled_x_right. */
991 const double inv_scalex = (double) 0x100 / scalex;
992 const double inv_scaley = (double) 0x100 / scaley;
993 for (y = 0; y < spu->scaled_height; ++y) {
994 const double unscaled_y = y * inv_scaley;
995 const double unscaled_y_bottom = unscaled_y + inv_scaley;
996 const unsigned int top_low_row = FFMIN(unscaled_y_bottom, unscaled_y + 1.0);
997 const double top = top_low_row - unscaled_y;
998 const unsigned int height = unscaled_y_bottom > top_low_row
999 ? (unsigned int) unscaled_y_bottom - top_low_row
1000 : 0;
1001 const double bottom = unscaled_y_bottom > top_low_row
1002 ? unscaled_y_bottom - floor(unscaled_y_bottom)
1003 : 0.0;
1004 for (x = 0; x < spu->scaled_width; ++x) {
1005 const double unscaled_x = x * inv_scalex;
1006 const double unscaled_x_right = unscaled_x + inv_scalex;
1007 const unsigned int left_right_column = FFMIN(unscaled_x_right, unscaled_x + 1.0);
1008 const double left = left_right_column - unscaled_x;
1009 const unsigned int width = unscaled_x_right > left_right_column
1010 ? (unsigned int) unscaled_x_right - left_right_column
1011 : 0;
1012 const double right = unscaled_x_right > left_right_column
1013 ? unscaled_x_right - floor(unscaled_x_right)
1014 : 0.0;
1015 double color = 0.0;
1016 double alpha = 0.0;
1017 double tmp;
1018 unsigned int base;
1019 /* Now use these informations to compute a good alpha,
1020 and lightness. The sum is on each of the 9
1021 region's surface and alpha and lightness.
1023 transformed alpha = sum(surface * alpha) / sum(surface)
1024 transformed color = sum(surface * alpha * color) / sum(surface * alpha)
1026 /* 1: top left part */
1027 base = spu->stride * (unsigned int) unscaled_y;
1028 tmp = left * top * canon_alpha(spu->aimage[base + (unsigned int) unscaled_x]);
1029 alpha += tmp;
1030 color += tmp * spu->image[base + (unsigned int) unscaled_x];
1031 /* 2: top center part */
1032 if (width > 0) {
1033 unsigned int walkx;
1034 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
1035 base = spu->stride * (unsigned int) unscaled_y + walkx;
1036 tmp = /* 1.0 * */ top * canon_alpha(spu->aimage[base]);
1037 alpha += tmp;
1038 color += tmp * spu->image[base];
1041 /* 3: top right part */
1042 if (right > 0.0) {
1043 base = spu->stride * (unsigned int) unscaled_y + (unsigned int) unscaled_x_right;
1044 tmp = right * top * canon_alpha(spu->aimage[base]);
1045 alpha += tmp;
1046 color += tmp * spu->image[base];
1048 /* 4: center left part */
1049 if (height > 0) {
1050 unsigned int walky;
1051 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1052 base = spu->stride * walky + (unsigned int) unscaled_x;
1053 tmp = left /* * 1.0 */ * canon_alpha(spu->aimage[base]);
1054 alpha += tmp;
1055 color += tmp * spu->image[base];
1058 /* 5: center part */
1059 if (width > 0 && height > 0) {
1060 unsigned int walky;
1061 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1062 unsigned int walkx;
1063 base = spu->stride * walky;
1064 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
1065 tmp = /* 1.0 * 1.0 * */ canon_alpha(spu->aimage[base + walkx]);
1066 alpha += tmp;
1067 color += tmp * spu->image[base + walkx];
1071 /* 6: center right part */
1072 if (right > 0.0 && height > 0) {
1073 unsigned int walky;
1074 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1075 base = spu->stride * walky + (unsigned int) unscaled_x_right;
1076 tmp = right /* * 1.0 */ * canon_alpha(spu->aimage[base]);
1077 alpha += tmp;
1078 color += tmp * spu->image[base];
1081 /* 7: bottom left part */
1082 if (bottom > 0.0) {
1083 base = spu->stride * (unsigned int) unscaled_y_bottom + (unsigned int) unscaled_x;
1084 tmp = left * bottom * canon_alpha(spu->aimage[base]);
1085 alpha += tmp;
1086 color += tmp * spu->image[base];
1088 /* 8: bottom center part */
1089 if (width > 0 && bottom > 0.0) {
1090 unsigned int walkx;
1091 base = spu->stride * (unsigned int) unscaled_y_bottom;
1092 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
1093 tmp = /* 1.0 * */ bottom * canon_alpha(spu->aimage[base + walkx]);
1094 alpha += tmp;
1095 color += tmp * spu->image[base + walkx];
1098 /* 9: bottom right part */
1099 if (right > 0.0 && bottom > 0.0) {
1100 base = spu->stride * (unsigned int) unscaled_y_bottom + (unsigned int) unscaled_x_right;
1101 tmp = right * bottom * canon_alpha(spu->aimage[base]);
1102 alpha += tmp;
1103 color += tmp * spu->image[base];
1105 /* Finally mix these transparency and brightness information suitably */
1106 base = spu->scaled_stride * y + x;
1107 spu->scaled_image[base] = alpha > 0 ? color / alpha : 0;
1108 spu->scaled_aimage[base] = alpha * scalex * scaley / 0x10000;
1109 if (spu->scaled_aimage[base]) {
1110 spu->scaled_aimage[base] = 256 - spu->scaled_aimage[base];
1111 if (spu->scaled_aimage[base] + spu->scaled_image[base] > 255)
1112 spu->scaled_image[base] = 256 - spu->scaled_aimage[base];
1118 nothing_to_do:
1119 /* Kludge: draw_alpha needs width multiple of 8. */
1120 if (spu->scaled_width < spu->scaled_stride)
1121 for (y = 0; y < spu->scaled_height; ++y) {
1122 memset(spu->scaled_aimage + y * spu->scaled_stride + spu->scaled_width, 0,
1123 spu->scaled_stride - spu->scaled_width);
1125 spu->scaled_frame_width = dxs;
1126 spu->scaled_frame_height = dys;
1129 if (spu->scaled_image){
1130 switch (spu_alignment) {
1131 case 0:
1132 spu->scaled_start_row = dys*sub_pos/100;
1133 if (spu->scaled_start_row + spu->scaled_height > dys)
1134 spu->scaled_start_row = dys - spu->scaled_height;
1135 break;
1136 case 1:
1137 spu->scaled_start_row = dys*sub_pos/100 - spu->scaled_height/2;
1138 if (sub_pos >= 50 && spu->scaled_start_row + spu->scaled_height > dys)
1139 spu->scaled_start_row = dys - spu->scaled_height;
1140 break;
1141 case 2:
1142 spu->scaled_start_row = dys*sub_pos/100 - spu->scaled_height;
1143 break;
1145 draw_alpha(ctx, spu->scaled_start_col, spu->scaled_start_row, spu->scaled_width, spu->scaled_height,
1146 spu->scaled_image, spu->scaled_aimage, spu->scaled_stride);
1147 spu->spu_changed = 0;
1151 else
1153 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPU not displayed: start_pts=%d end_pts=%d now_pts=%d\n",
1154 spu->start_pts, spu->end_pts, spu->now_pts);
1158 void spudec_update_palette(void * this, unsigned int *palette)
1160 spudec_handle_t *spu = this;
1161 if (spu && palette) {
1162 memcpy(spu->global_palette, palette, sizeof(spu->global_palette));
1163 if(spu->hw_spu)
1164 vo_control(spu->hw_spu, VOCTRL_SET_SPU_PALETTE, spu->global_palette);
1168 void spudec_set_font_factor(void * this, double factor)
1170 spudec_handle_t *spu = this;
1171 spu->font_start_level = (int)(0xF0-(0xE0*factor));
1174 static void spudec_parse_extradata(spudec_handle_t *this,
1175 uint8_t *extradata, int extradata_len)
1177 uint8_t *buffer, *ptr;
1178 unsigned int *pal = this->global_palette, *cuspal = this->cuspal;
1179 unsigned int tridx;
1180 int i;
1182 if (extradata_len == 16*4) {
1183 for (i=0; i<16; i++)
1184 pal[i] = AV_RB32(extradata + i*4);
1185 this->auto_palette = 0;
1186 return;
1189 if (!(ptr = buffer = malloc(extradata_len+1)))
1190 return;
1191 memcpy(buffer, extradata, extradata_len);
1192 buffer[extradata_len] = 0;
1194 do {
1195 if (*ptr == '#')
1196 continue;
1197 if (!strncmp(ptr, "size: ", 6))
1198 sscanf(ptr + 6, "%dx%d", &this->orig_frame_width, &this->orig_frame_height);
1199 if (!strncmp(ptr, "palette: ", 9) &&
1200 sscanf(ptr + 9, "%x, %x, %x, %x, %x, %x, %x, %x, "
1201 "%x, %x, %x, %x, %x, %x, %x, %x",
1202 &pal[ 0], &pal[ 1], &pal[ 2], &pal[ 3],
1203 &pal[ 4], &pal[ 5], &pal[ 6], &pal[ 7],
1204 &pal[ 8], &pal[ 9], &pal[10], &pal[11],
1205 &pal[12], &pal[13], &pal[14], &pal[15]) == 16) {
1206 for (i=0; i<16; i++)
1207 pal[i] = vobsub_palette_to_yuv(pal[i]);
1208 this->auto_palette = 0;
1210 if (!strncasecmp(ptr, "forced subs: on", 15))
1211 this->forced_subs_only = 1;
1212 if (!strncmp(ptr, "custom colors: ON, tridx: ", 26) &&
1213 sscanf(ptr + 26, "%x, colors: %x, %x, %x, %x",
1214 &tridx, cuspal+0, cuspal+1, cuspal+2, cuspal+3) == 5) {
1215 for (i=0; i<4; i++) {
1216 cuspal[i] = vobsub_rgb_to_yuv(cuspal[i]);
1217 if (tridx & (1 << (12-4*i)))
1218 cuspal[i] |= 1 << 31;
1220 this->custom = 1;
1222 } while ((ptr=strchr(ptr,'\n')) && *++ptr);
1224 free(buffer);
1227 void *spudec_new_scaled(unsigned int *palette, unsigned int frame_width, unsigned int frame_height, uint8_t *extradata, int extradata_len)
1229 spudec_handle_t *this = calloc(1, sizeof(spudec_handle_t));
1230 if (this){
1231 this->orig_frame_height = frame_height;
1232 this->orig_frame_width = frame_width;
1233 // set up palette:
1234 if (palette)
1235 memcpy(this->global_palette, palette, sizeof(this->global_palette));
1236 else
1237 this->auto_palette = 1;
1238 if (extradata)
1239 spudec_parse_extradata(this, extradata, extradata_len);
1240 /* XXX Although the video frame is some size, the SPU frame is
1241 always maximum size i.e. 720 wide and 576 or 480 high */
1242 // For HD files in MKV the VobSub resolution can be higher though,
1243 // see largeres_vobsub.mkv
1244 if (this->orig_frame_width <= 720 && this->orig_frame_height <= 576) {
1245 this->orig_frame_width = 720;
1246 if (this->orig_frame_height == 480 || this->orig_frame_height == 240)
1247 this->orig_frame_height = 480;
1248 else
1249 this->orig_frame_height = 576;
1252 else
1253 mp_msg(MSGT_SPUDEC,MSGL_FATAL, "FATAL: spudec_init: calloc");
1254 return this;
1257 void *spudec_new(unsigned int *palette)
1259 return spudec_new_scaled(palette, 0, 0, NULL, 0);
1262 void spudec_free(void *this)
1264 spudec_handle_t *spu = this;
1265 if (spu) {
1266 while (spu->queue_head)
1267 spudec_free_packet(spudec_dequeue_packet(spu));
1268 free(spu->packet);
1269 spu->packet = NULL;
1270 free(spu->scaled_image);
1271 spu->scaled_image = NULL;
1272 free(spu->image);
1273 spu->image = NULL;
1274 spu->aimage = NULL;
1275 free(spu->pal_image);
1276 spu->pal_image = NULL;
1277 spu->image_size = 0;
1278 free(spu);
1282 void spudec_set_hw_spu(void *this, struct vo *hw_spu)
1284 spudec_handle_t *spu = this;
1285 if (!spu)
1286 return;
1287 spu->hw_spu = hw_spu;
1288 vo_control(hw_spu, VOCTRL_SET_SPU_PALETTE, spu->global_palette);
1291 #define MP_NOPTS_VALUE (-1LL<<63) //both int64_t and double should be able to represent this exactly
1294 * palette must contain at least 256 32-bit entries, otherwise crashes
1295 * are possible
1297 void spudec_set_paletted(void *this, const uint8_t *pal_img, int pal_stride,
1298 const void *palette,
1299 int x, int y, int w, int h,
1300 double pts, double endpts)
1302 int i;
1303 uint16_t g8a8_pal[256];
1304 packet_t *packet;
1305 const uint32_t *pal = palette;
1306 spudec_handle_t *spu = this;
1307 uint8_t *img;
1308 uint8_t *aimg;
1309 int stride = (w + 7) & ~7;
1310 if ((unsigned)w >= 0x8000 || (unsigned)h > 0x4000)
1311 return;
1312 packet = calloc(1, sizeof(packet_t));
1313 packet->is_decoded = 1;
1314 packet->width = w;
1315 packet->height = h;
1316 packet->stride = stride;
1317 packet->start_col = x;
1318 packet->start_row = y;
1319 packet->data_len = 2 * stride * h;
1320 packet->packet = malloc(packet->data_len);
1321 img = packet->packet;
1322 aimg = packet->packet + stride * h;
1323 for (i = 0; i < 256; i++) {
1324 uint32_t pixel = pal[i];
1325 int alpha = pixel >> 24;
1326 int gray = (((pixel & 0x000000ff) >> 0) +
1327 ((pixel & 0x0000ff00) >> 7) +
1328 ((pixel & 0x00ff0000) >> 16)) >> 2;
1329 gray = FFMIN(gray, alpha);
1330 g8a8_pal[i] = (-alpha << 8) | gray;
1332 pal2gray_alpha(g8a8_pal, pal_img, pal_stride,
1333 img, aimg, stride, w, h);
1334 packet->start_pts = 0;
1335 packet->end_pts = 0x7fffffff;
1336 if (pts != MP_NOPTS_VALUE)
1337 packet->start_pts = pts * 90000;
1338 if (endpts != MP_NOPTS_VALUE)
1339 packet->end_pts = endpts * 90000;
1340 spudec_queue_packet(spu, packet);