Commit files by Steinar Gunderson, forgotten in r30866.
[mplayer.git] / spudec.c
bloba79d708e38525020b499c7ee70eeae314c18aa9b
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 "libavutil/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 unsigned char *packet;
63 unsigned int palette[4];
64 unsigned int alpha[4];
65 unsigned int control_start; /* index of start of control data */
66 unsigned int current_nibble[2]; /* next data nibble (4 bits) to be
67 processed (for RLE decoding) for
68 even and odd lines */
69 int deinterlace_oddness; /* 0 or 1, index into current_nibble */
70 unsigned int start_col, end_col;
71 unsigned int start_row, end_row;
72 unsigned int width, height, stride;
73 unsigned int start_pts, end_pts;
74 packet_t *next;
77 typedef struct {
78 packet_t *queue_head;
79 packet_t *queue_tail;
80 unsigned int global_palette[16];
81 unsigned int orig_frame_width, orig_frame_height;
82 unsigned char* packet;
83 size_t packet_reserve; /* size of the memory pointed to by packet */
84 unsigned int packet_offset; /* end of the currently assembled fragment */
85 unsigned int packet_size; /* size of the packet once all fragments are assembled */
86 int packet_pts; /* PTS for this packet */
87 unsigned int palette[4];
88 unsigned int alpha[4];
89 unsigned int cuspal[4];
90 unsigned int custom;
91 unsigned int now_pts;
92 unsigned int start_pts, end_pts;
93 unsigned int start_col, end_col;
94 unsigned int start_row, end_row;
95 unsigned int width, height, stride;
96 size_t image_size; /* Size of the image buffer */
97 unsigned char *image; /* Grayscale value */
98 unsigned char *aimage; /* Alpha value */
99 unsigned int scaled_frame_width, scaled_frame_height;
100 unsigned int scaled_start_col, scaled_start_row;
101 unsigned int scaled_width, scaled_height, scaled_stride;
102 size_t scaled_image_size;
103 unsigned char *scaled_image;
104 unsigned char *scaled_aimage;
105 int auto_palette; /* 1 if we lack a palette and must use an heuristic. */
106 int font_start_level; /* Darkest value used for the computed font */
107 const vo_functions_t *hw_spu;
108 int spu_changed;
109 unsigned int forced_subs_only; /* flag: 0=display all subtitle, !0 display only forced subtitles */
110 unsigned int is_forced_sub; /* true if current subtitle is a forced subtitle */
111 } spudec_handle_t;
113 static void spudec_queue_packet(spudec_handle_t *this, packet_t *packet)
115 if (this->queue_head == NULL)
116 this->queue_head = packet;
117 else
118 this->queue_tail->next = packet;
119 this->queue_tail = packet;
122 static packet_t *spudec_dequeue_packet(spudec_handle_t *this)
124 packet_t *retval = this->queue_head;
126 this->queue_head = retval->next;
127 if (this->queue_head == NULL)
128 this->queue_tail = NULL;
130 return retval;
133 static void spudec_free_packet(packet_t *packet)
135 if (packet->packet != NULL)
136 free(packet->packet);
137 free(packet);
140 static inline unsigned int get_be16(const unsigned char *p)
142 return (p[0] << 8) + p[1];
145 static inline unsigned int get_be24(const unsigned char *p)
147 return (get_be16(p) << 8) + p[2];
150 static void next_line(packet_t *packet)
152 if (packet->current_nibble[packet->deinterlace_oddness] % 2)
153 packet->current_nibble[packet->deinterlace_oddness]++;
154 packet->deinterlace_oddness = (packet->deinterlace_oddness + 1) % 2;
157 static inline unsigned char get_nibble(packet_t *packet)
159 unsigned char nib;
160 unsigned int *nibblep = packet->current_nibble + packet->deinterlace_oddness;
161 if (*nibblep / 2 >= packet->control_start) {
162 mp_msg(MSGT_SPUDEC,MSGL_WARN, "SPUdec: ERROR: get_nibble past end of packet\n");
163 return 0;
165 nib = packet->packet[*nibblep / 2];
166 if (*nibblep % 2)
167 nib &= 0xf;
168 else
169 nib >>= 4;
170 ++*nibblep;
171 return nib;
174 static inline int mkalpha(int i)
176 /* In mplayer's alpha planes, 0 is transparent, then 1 is nearly
177 opaque upto 255 which is transparent */
178 // extend 4 -> 8 bit
179 i |= i << 4;
180 return (uint8_t)(-i);
183 /* Cut the sub to visible part */
184 static inline void spudec_cut_image(spudec_handle_t *this)
186 unsigned int fy, ly;
187 unsigned int first_y, last_y;
188 unsigned char *image;
189 unsigned char *aimage;
191 if (this->stride == 0 || this->height == 0) {
192 return;
195 for (fy = 0; fy < this->image_size && !this->aimage[fy]; fy++);
196 for (ly = this->stride * this->height-1; ly && !this->aimage[ly]; ly--);
197 first_y = fy / this->stride;
198 last_y = ly / this->stride;
199 //printf("first_y: %d, last_y: %d\n", first_y, last_y);
200 this->start_row += first_y;
202 // Some subtitles trigger this condition
203 if (last_y + 1 > first_y ) {
204 this->height = last_y - first_y +1;
205 } else {
206 this->height = 0;
207 this->image_size = 0;
208 return;
211 // printf("new h %d new start %d (sz %d st %d)---\n\n", this->height, this->start_row, this->image_size, this->stride);
213 image = malloc(2 * this->stride * this->height);
214 if(image){
215 this->image_size = this->stride * this->height;
216 aimage = image + this->image_size;
217 memcpy(image, this->image + this->stride * first_y, this->image_size);
218 memcpy(aimage, this->aimage + this->stride * first_y, this->image_size);
219 free(this->image);
220 this->image = image;
221 this->aimage = aimage;
222 } else {
223 mp_msg(MSGT_SPUDEC, MSGL_FATAL, "Fatal: update_spu: malloc requested %d bytes\n", 2 * this->stride * this->height);
227 static void spudec_process_data(spudec_handle_t *this, packet_t *packet)
229 unsigned int cmap[4], alpha[4];
230 unsigned int i, x, y;
232 this->scaled_frame_width = 0;
233 this->scaled_frame_height = 0;
234 this->start_col = packet->start_col;
235 this->end_col = packet->end_col;
236 this->start_row = packet->start_row;
237 this->end_row = packet->end_row;
238 this->height = packet->height;
239 this->width = packet->width;
240 this->stride = packet->stride;
241 for (i = 0; i < 4; ++i) {
242 alpha[i] = mkalpha(packet->alpha[i]);
243 if (this->custom && (this->cuspal[i] >> 31) != 0)
244 alpha[i] = 0;
245 if (alpha[i] == 0)
246 cmap[i] = 0;
247 else if (this->custom){
248 cmap[i] = ((this->cuspal[i] >> 16) & 0xff);
249 if (cmap[i] + alpha[i] > 255)
250 cmap[i] = 256 - alpha[i];
252 else {
253 cmap[i] = ((this->global_palette[packet->palette[i]] >> 16) & 0xff);
254 if (cmap[i] + alpha[i] > 255)
255 cmap[i] = 256 - alpha[i];
259 if (this->image_size < this->stride * this->height) {
260 if (this->image != NULL) {
261 free(this->image);
262 this->image_size = 0;
264 this->image = malloc(2 * this->stride * this->height);
265 if (this->image) {
266 this->image_size = this->stride * this->height;
267 this->aimage = this->image + this->image_size;
270 if (this->image == NULL)
271 return;
273 /* Kludge: draw_alpha needs width multiple of 8. */
274 if (this->width < this->stride)
275 for (y = 0; y < this->height; ++y) {
276 memset(this->aimage + y * this->stride + this->width, 0, this->stride - this->width);
277 /* FIXME: Why is this one needed? */
278 memset(this->image + y * this->stride + this->width, 0, this->stride - this->width);
281 i = packet->current_nibble[1];
282 x = 0;
283 y = 0;
284 while (packet->current_nibble[0] < i
285 && packet->current_nibble[1] / 2 < packet->control_start
286 && y < this->height) {
287 unsigned int len, color;
288 unsigned int rle = 0;
289 rle = get_nibble(packet);
290 if (rle < 0x04) {
291 rle = (rle << 4) | get_nibble(packet);
292 if (rle < 0x10) {
293 rle = (rle << 4) | get_nibble(packet);
294 if (rle < 0x040) {
295 rle = (rle << 4) | get_nibble(packet);
296 if (rle < 0x0004)
297 rle |= ((this->width - x) << 2);
301 color = 3 - (rle & 0x3);
302 len = rle >> 2;
303 if (len > this->width - x || len == 0)
304 len = this->width - x;
305 /* FIXME have to use palette and alpha map*/
306 memset(this->image + y * this->stride + x, cmap[color], len);
307 memset(this->aimage + y * this->stride + x, alpha[color], len);
308 x += len;
309 if (x >= this->width) {
310 next_line(packet);
311 x = 0;
312 ++y;
315 spudec_cut_image(this);
320 This function tries to create a usable palette.
321 It determines how many non-transparent colors are used, and assigns different
322 gray scale values to each color.
323 I tested it with four streams and even got something readable. Half of the
324 times I got black characters with white around and half the reverse.
326 static void compute_palette(spudec_handle_t *this, packet_t *packet)
328 int used[16],i,cused,start,step,color;
330 memset(used, 0, sizeof(used));
331 for (i=0; i<4; i++)
332 if (packet->alpha[i]) /* !Transparent? */
333 used[packet->palette[i]] = 1;
334 for (cused=0, i=0; i<16; i++)
335 if (used[i]) cused++;
336 if (!cused) return;
337 if (cused == 1) {
338 start = 0x80;
339 step = 0;
340 } else {
341 start = this->font_start_level;
342 step = (0xF0-this->font_start_level)/(cused-1);
344 memset(used, 0, sizeof(used));
345 for (i=0; i<4; i++) {
346 color = packet->palette[i];
347 if (packet->alpha[i] && !used[color]) { /* not assigned? */
348 used[color] = 1;
349 this->global_palette[color] = start<<16;
350 start += step;
355 static void spudec_process_control(spudec_handle_t *this, int pts100)
357 int a,b,c,d; /* Temporary vars */
358 unsigned int date, type;
359 unsigned int off;
360 unsigned int start_off = 0;
361 unsigned int next_off;
362 unsigned int start_pts = 0;
363 unsigned int end_pts = 0;
364 unsigned int current_nibble[2] = {0, 0};
365 unsigned int control_start;
366 unsigned int display = 0;
367 unsigned int start_col = 0;
368 unsigned int end_col = 0;
369 unsigned int start_row = 0;
370 unsigned int end_row = 0;
371 unsigned int width = 0;
372 unsigned int height = 0;
373 unsigned int stride = 0;
375 control_start = get_be16(this->packet + 2);
376 next_off = control_start;
377 while (start_off != next_off) {
378 start_off = next_off;
379 date = get_be16(this->packet + start_off) * 1024;
380 next_off = get_be16(this->packet + start_off + 2);
381 mp_msg(MSGT_SPUDEC,MSGL_DBG2, "date=%d\n", date);
382 off = start_off + 4;
383 for (type = this->packet[off++]; type != 0xff; type = this->packet[off++]) {
384 mp_msg(MSGT_SPUDEC,MSGL_DBG2, "cmd=%d ",type);
385 switch(type) {
386 case 0x00:
387 /* Menu ID, 1 byte */
388 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Menu ID\n");
389 /* shouldn't a Menu ID type force display start? */
390 start_pts = pts100 < 0 && -pts100 >= date ? 0 : pts100 + date;
391 end_pts = UINT_MAX;
392 display = 1;
393 this->is_forced_sub=~0; // current subtitle is forced
394 break;
395 case 0x01:
396 /* Start display */
397 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Start display!\n");
398 start_pts = pts100 < 0 && -pts100 >= date ? 0 : pts100 + date;
399 end_pts = UINT_MAX;
400 display = 1;
401 this->is_forced_sub=0;
402 break;
403 case 0x02:
404 /* Stop display */
405 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Stop display!\n");
406 end_pts = pts100 < 0 && -pts100 >= date ? 0 : pts100 + date;
407 break;
408 case 0x03:
409 /* Palette */
410 this->palette[0] = this->packet[off] >> 4;
411 this->palette[1] = this->packet[off] & 0xf;
412 this->palette[2] = this->packet[off + 1] >> 4;
413 this->palette[3] = this->packet[off + 1] & 0xf;
414 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Palette %d, %d, %d, %d\n",
415 this->palette[0], this->palette[1], this->palette[2], this->palette[3]);
416 off+=2;
417 break;
418 case 0x04:
419 /* Alpha */
420 a = this->packet[off] >> 4;
421 b = this->packet[off] & 0xf;
422 c = this->packet[off + 1] >> 4;
423 d = this->packet[off + 1] & 0xf;
424 // Note: some DVDs change these values to create a fade-in/fade-out effect
425 // We can not handle this, so just keep the highest value during the display time.
426 if (display) {
427 a = FFMAX(a, this->alpha[0]);
428 b = FFMAX(b, this->alpha[1]);
429 c = FFMAX(c, this->alpha[2]);
430 d = FFMAX(d, this->alpha[3]);
432 this->alpha[0] = a;
433 this->alpha[1] = b;
434 this->alpha[2] = c;
435 this->alpha[3] = d;
436 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Alpha %d, %d, %d, %d\n",
437 this->alpha[0], this->alpha[1], this->alpha[2], this->alpha[3]);
438 off+=2;
439 break;
440 case 0x05:
441 /* Co-ords */
442 a = get_be24(this->packet + off);
443 b = get_be24(this->packet + off + 3);
444 start_col = a >> 12;
445 end_col = a & 0xfff;
446 width = (end_col < start_col) ? 0 : end_col - start_col + 1;
447 stride = (width + 7) & ~7; /* Kludge: draw_alpha needs width multiple of 8 */
448 start_row = b >> 12;
449 end_row = b & 0xfff;
450 height = (end_row < start_row) ? 0 : end_row - start_row /* + 1 */;
451 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Coords col: %d - %d row: %d - %d (%dx%d)\n",
452 start_col, end_col, start_row, end_row,
453 width, height);
454 off+=6;
455 break;
456 case 0x06:
457 /* Graphic lines */
458 current_nibble[0] = 2 * get_be16(this->packet + off);
459 current_nibble[1] = 2 * get_be16(this->packet + off + 2);
460 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Graphic offset 1: %d offset 2: %d\n",
461 current_nibble[0] / 2, current_nibble[1] / 2);
462 off+=4;
463 break;
464 case 0xff:
465 /* All done, bye-bye */
466 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Done!\n");
467 return;
468 // break;
469 default:
470 mp_msg(MSGT_SPUDEC,MSGL_WARN,"spudec: Error determining control type 0x%02x. Skipping %d bytes.\n",
471 type, next_off - off);
472 goto next_control;
475 next_control:
476 if (!display)
477 continue;
478 if (end_pts == UINT_MAX && start_off != next_off) {
479 end_pts = get_be16(this->packet + next_off) * 1024;
480 end_pts = 1 - pts100 >= end_pts ? 0 : pts100 + end_pts - 1;
482 if (end_pts > 0) {
483 packet_t *packet = calloc(1, sizeof(packet_t));
484 int i;
485 packet->start_pts = start_pts;
486 packet->end_pts = end_pts;
487 packet->current_nibble[0] = current_nibble[0];
488 packet->current_nibble[1] = current_nibble[1];
489 packet->start_row = start_row;
490 packet->end_row = end_row;
491 packet->start_col = start_col;
492 packet->end_col = end_col;
493 packet->width = width;
494 packet->height = height;
495 packet->stride = stride;
496 packet->control_start = control_start;
497 for (i=0; i<4; i++) {
498 packet->alpha[i] = this->alpha[i];
499 packet->palette[i] = this->palette[i];
501 packet->packet = malloc(this->packet_size);
502 memcpy(packet->packet, this->packet, this->packet_size);
503 spudec_queue_packet(this, packet);
508 static void spudec_decode(spudec_handle_t *this, int pts100)
510 if (!this->hw_spu)
511 spudec_process_control(this, pts100);
512 else if (pts100 >= 0) {
513 static vo_mpegpes_t packet = { NULL, 0, 0x20, 0 };
514 static vo_mpegpes_t *pkg=&packet;
515 packet.data = this->packet;
516 packet.size = this->packet_size;
517 packet.timestamp = pts100;
518 this->hw_spu->draw_frame((uint8_t**)&pkg);
522 int spudec_changed(void * this)
524 spudec_handle_t * spu = (spudec_handle_t*)this;
525 return spu->spu_changed || spu->now_pts > spu->end_pts;
528 void spudec_assemble(void *this, unsigned char *packet, unsigned int len, int pts100)
530 spudec_handle_t *spu = (spudec_handle_t*)this;
531 // spudec_heartbeat(this, pts100);
532 if (len < 2) {
533 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: packet too short\n");
534 return;
536 #if 0
537 if ((spu->packet_pts + 10000) < pts100) {
538 // [cb] too long since last fragment: force new packet
539 spu->packet_offset = 0;
541 #endif
542 spu->packet_pts = pts100;
543 if (spu->packet_offset == 0) {
544 unsigned int len2 = get_be16(packet);
545 // Start new fragment
546 if (spu->packet_reserve < len2) {
547 if (spu->packet != NULL)
548 free(spu->packet);
549 spu->packet = malloc(len2);
550 spu->packet_reserve = spu->packet != NULL ? len2 : 0;
552 if (spu->packet != NULL) {
553 spu->packet_size = len2;
554 if (len > len2) {
555 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: invalid frag len / len2: %d / %d \n", len, len2);
556 return;
558 memcpy(spu->packet, packet, len);
559 spu->packet_offset = len;
560 spu->packet_pts = pts100;
562 } else {
563 // Continue current fragment
564 if (spu->packet_size < spu->packet_offset + len){
565 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: invalid fragment\n");
566 spu->packet_size = spu->packet_offset = 0;
567 return;
568 } else {
569 memcpy(spu->packet + spu->packet_offset, packet, len);
570 spu->packet_offset += len;
573 #if 1
574 // check if we have a complete packet (unfortunatelly packet_size is bad
575 // for some disks)
576 // [cb] packet_size is padded to be even -> may be one byte too long
577 if ((spu->packet_offset == spu->packet_size) ||
578 ((spu->packet_offset + 1) == spu->packet_size)){
579 unsigned int x=0,y;
580 while(x+4<=spu->packet_offset){
581 y=get_be16(spu->packet+x+2); // next control pointer
582 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPUtest: x=%d y=%d off=%d size=%d\n",x,y,spu->packet_offset,spu->packet_size);
583 if(x>=4 && x==y){ // if it points to self - we're done!
584 // we got it!
585 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPUgot: off=%d size=%d \n",spu->packet_offset,spu->packet_size);
586 spudec_decode(spu, pts100);
587 spu->packet_offset = 0;
588 break;
590 if(y<=x || y>=spu->packet_size){ // invalid?
591 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUtest: broken packet!!!!! y=%d < x=%d\n",y,x);
592 spu->packet_size = spu->packet_offset = 0;
593 break;
595 x=y;
597 // [cb] packet is done; start new packet
598 spu->packet_offset = 0;
600 #else
601 if (spu->packet_offset == spu->packet_size) {
602 spudec_decode(spu, pts100);
603 spu->packet_offset = 0;
605 #endif
608 void spudec_reset(void *this) // called after seek
610 spudec_handle_t *spu = (spudec_handle_t*)this;
611 while (spu->queue_head)
612 spudec_free_packet(spudec_dequeue_packet(spu));
613 spu->now_pts = 0;
614 spu->end_pts = 0;
615 spu->packet_size = spu->packet_offset = 0;
618 void spudec_heartbeat(void *this, unsigned int pts100)
620 spudec_handle_t *spu = (spudec_handle_t*) this;
621 spu->now_pts = pts100;
623 while (spu->queue_head != NULL && pts100 >= spu->queue_head->start_pts) {
624 packet_t *packet = spudec_dequeue_packet(spu);
625 spu->start_pts = packet->start_pts;
626 spu->end_pts = packet->end_pts;
627 if (spu->auto_palette)
628 compute_palette(spu, packet);
629 spudec_process_data(spu, packet);
630 spudec_free_packet(packet);
631 spu->spu_changed = 1;
635 int spudec_visible(void *this){
636 spudec_handle_t *spu = (spudec_handle_t *)this;
637 int ret=(spu->start_pts <= spu->now_pts &&
638 spu->now_pts < spu->end_pts &&
639 spu->height > 0);
640 // printf("spu visible: %d \n",ret);
641 return ret;
644 void spudec_set_forced_subs_only(void * const this, const unsigned int flag)
646 if(this){
647 ((spudec_handle_t *)this)->forced_subs_only=flag;
648 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPU: Display only forced subs now %s\n", flag ? "enabled": "disabled");
652 void spudec_draw(void *this, void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride))
654 spudec_handle_t *spu = (spudec_handle_t *)this;
655 if (spu->start_pts <= spu->now_pts && spu->now_pts < spu->end_pts && spu->image)
657 draw_alpha(spu->start_col, spu->start_row, spu->width, spu->height,
658 spu->image, spu->aimage, spu->stride);
659 spu->spu_changed = 0;
663 /* calc the bbox for spudec subs */
664 void spudec_calc_bbox(void *me, unsigned int dxs, unsigned int dys, unsigned int* bbox)
666 spudec_handle_t *spu;
667 spu = (spudec_handle_t *)me;
668 if (spu->orig_frame_width == 0 || spu->orig_frame_height == 0
669 || (spu->orig_frame_width == dxs && spu->orig_frame_height == dys)) {
670 bbox[0] = spu->start_col;
671 bbox[1] = spu->start_col + spu->width;
672 bbox[2] = spu->start_row;
673 bbox[3] = spu->start_row + spu->height;
675 else if (spu->scaled_frame_width != dxs || spu->scaled_frame_height != dys) {
676 unsigned int scalex = 0x100 * dxs / spu->orig_frame_width;
677 unsigned int scaley = 0x100 * dys / spu->orig_frame_height;
678 bbox[0] = spu->start_col * scalex / 0x100;
679 bbox[1] = spu->start_col * scalex / 0x100 + spu->width * scalex / 0x100;
680 switch (spu_alignment) {
681 case 0:
682 bbox[3] = dys*sub_pos/100 + spu->height * scaley / 0x100;
683 if (bbox[3] > dys) bbox[3] = dys;
684 bbox[2] = bbox[3] - spu->height * scaley / 0x100;
685 break;
686 case 1:
687 if (sub_pos < 50) {
688 bbox[2] = dys*sub_pos/100 - spu->height * scaley / 0x200;
689 bbox[3] = bbox[2] + spu->height;
690 } else {
691 bbox[3] = dys*sub_pos/100 + spu->height * scaley / 0x200;
692 if (bbox[3] > dys) bbox[3] = dys;
693 bbox[2] = bbox[3] - spu->height * scaley / 0x100;
695 break;
696 case 2:
697 bbox[2] = dys*sub_pos/100 - spu->height * scaley / 0x100;
698 bbox[3] = bbox[2] + spu->height;
699 break;
700 default: /* -1 */
701 bbox[2] = spu->start_row * scaley / 0x100;
702 bbox[3] = spu->start_row * scaley / 0x100 + spu->height * scaley / 0x100;
703 break;
707 /* transform mplayer's alpha value into an opacity value that is linear */
708 static inline int canon_alpha(int alpha)
710 return alpha ? 256 - alpha : 0;
713 typedef struct {
714 unsigned position;
715 unsigned left_up;
716 unsigned right_down;
717 }scale_pixel;
720 static void scale_table(unsigned int start_src, unsigned int start_tar, unsigned int end_src, unsigned int end_tar, scale_pixel * table)
722 unsigned int t;
723 unsigned int delta_src = end_src - start_src;
724 unsigned int delta_tar = end_tar - start_tar;
725 int src = 0;
726 int src_step;
727 if (delta_src == 0 || delta_tar == 0) {
728 return;
730 src_step = (delta_src << 16) / delta_tar >>1;
731 for (t = 0; t<=delta_tar; src += (src_step << 1), t++){
732 table[t].position= FFMIN(src >> 16, end_src - 1);
733 table[t].right_down = src & 0xffff;
734 table[t].left_up = 0x10000 - table[t].right_down;
738 /* bilinear scale, similar to vobsub's code */
739 static void scale_image(int x, int y, scale_pixel* table_x, scale_pixel* table_y, spudec_handle_t * spu)
741 int alpha[4];
742 int color[4];
743 unsigned int scale[4];
744 int base = table_y[y].position * spu->stride + table_x[x].position;
745 int scaled = y * spu->scaled_stride + x;
746 alpha[0] = canon_alpha(spu->aimage[base]);
747 alpha[1] = canon_alpha(spu->aimage[base + 1]);
748 alpha[2] = canon_alpha(spu->aimage[base + spu->stride]);
749 alpha[3] = canon_alpha(spu->aimage[base + spu->stride + 1]);
750 color[0] = spu->image[base];
751 color[1] = spu->image[base + 1];
752 color[2] = spu->image[base + spu->stride];
753 color[3] = spu->image[base + spu->stride + 1];
754 scale[0] = (table_x[x].left_up * table_y[y].left_up >> 16) * alpha[0];
755 if (table_y[y].left_up == 0x10000) // necessary to avoid overflow-case
756 scale[0] = table_x[x].left_up * alpha[0];
757 scale[1] = (table_x[x].right_down * table_y[y].left_up >>16) * alpha[1];
758 scale[2] = (table_x[x].left_up * table_y[y].right_down >> 16) * alpha[2];
759 scale[3] = (table_x[x].right_down * table_y[y].right_down >> 16) * alpha[3];
760 spu->scaled_image[scaled] = (color[0] * scale[0] + color[1] * scale[1] + color[2] * scale[2] + color[3] * scale[3])>>24;
761 spu->scaled_aimage[scaled] = (scale[0] + scale[1] + scale[2] + scale[3]) >> 16;
762 if (spu->scaled_aimage[scaled]){
763 // ensure that MPlayer's simplified alpha-blending can not overflow
764 spu->scaled_image[scaled] = FFMIN(spu->scaled_image[scaled], spu->scaled_aimage[scaled]);
765 // convert to MPlayer-style alpha
766 spu->scaled_aimage[scaled] = -spu->scaled_aimage[scaled];
770 static void sws_spu_image(unsigned char *d1, unsigned char *d2, int dw, int dh,
771 int ds, unsigned char *s1, unsigned char *s2, int sw,
772 int sh, int ss)
774 struct SwsContext *ctx;
775 static SwsFilter filter;
776 static int firsttime = 1;
777 static float oldvar;
778 int i;
780 if (!firsttime && oldvar != spu_gaussvar) sws_freeVec(filter.lumH);
781 if (firsttime) {
782 filter.lumH = filter.lumV =
783 filter.chrH = filter.chrV = sws_getGaussianVec(spu_gaussvar, 3.0);
784 sws_normalizeVec(filter.lumH, 1.0);
785 firsttime = 0;
786 oldvar = spu_gaussvar;
789 ctx=sws_getContext(sw, sh, PIX_FMT_GRAY8, dw, dh, PIX_FMT_GRAY8, SWS_GAUSS, &filter, NULL, NULL);
790 sws_scale(ctx,&s1,&ss,0,sh,&d1,&ds);
791 for (i=ss*sh-1; i>=0; i--) if (!s2[i]) s2[i] = 255; //else s2[i] = 1;
792 sws_scale(ctx,&s2,&ss,0,sh,&d2,&ds);
793 for (i=ds*dh-1; i>=0; i--) if (d2[i]==0) d2[i] = 1; else if (d2[i]==255) d2[i] = 0;
794 sws_freeContext(ctx);
797 void spudec_draw_scaled(void *me, unsigned int dxs, unsigned int dys, void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride))
799 spudec_handle_t *spu = (spudec_handle_t *)me;
800 scale_pixel *table_x;
801 scale_pixel *table_y;
803 if (spu->start_pts <= spu->now_pts && spu->now_pts < spu->end_pts) {
805 // check if only forced subtitles are requested
806 if( (spu->forced_subs_only) && !(spu->is_forced_sub) ){
807 return;
810 if (!(spu_aamode&16) && (spu->orig_frame_width == 0 || spu->orig_frame_height == 0
811 || (spu->orig_frame_width == dxs && spu->orig_frame_height == dys))) {
812 if (spu->image)
814 draw_alpha(spu->start_col, spu->start_row, spu->width, spu->height,
815 spu->image, spu->aimage, spu->stride);
816 spu->spu_changed = 0;
819 else {
820 if (spu->scaled_frame_width != dxs || spu->scaled_frame_height != dys) { /* Resizing is needed */
821 /* scaled_x = scalex * x / 0x100
822 scaled_y = scaley * y / 0x100
823 order of operations is important because of rounding. */
824 unsigned int scalex = 0x100 * dxs / spu->orig_frame_width;
825 unsigned int scaley = 0x100 * dys / spu->orig_frame_height;
826 spu->scaled_start_col = spu->start_col * scalex / 0x100;
827 spu->scaled_start_row = spu->start_row * scaley / 0x100;
828 spu->scaled_width = spu->width * scalex / 0x100;
829 spu->scaled_height = spu->height * scaley / 0x100;
830 /* Kludge: draw_alpha needs width multiple of 8 */
831 spu->scaled_stride = (spu->scaled_width + 7) & ~7;
832 if (spu->scaled_image_size < spu->scaled_stride * spu->scaled_height) {
833 if (spu->scaled_image) {
834 free(spu->scaled_image);
835 spu->scaled_image_size = 0;
837 spu->scaled_image = malloc(2 * spu->scaled_stride * spu->scaled_height);
838 if (spu->scaled_image) {
839 spu->scaled_image_size = spu->scaled_stride * spu->scaled_height;
840 spu->scaled_aimage = spu->scaled_image + spu->scaled_image_size;
843 if (spu->scaled_image) {
844 unsigned int x, y;
845 if (spu->scaled_width <= 1 || spu->scaled_height <= 1) {
846 goto nothing_to_do;
848 switch(spu_aamode&15) {
849 case 4:
850 sws_spu_image(spu->scaled_image, spu->scaled_aimage,
851 spu->scaled_width, spu->scaled_height, spu->scaled_stride,
852 spu->image, spu->aimage, spu->width, spu->height, spu->stride);
853 break;
854 case 3:
855 table_x = calloc(spu->scaled_width, sizeof(scale_pixel));
856 table_y = calloc(spu->scaled_height, sizeof(scale_pixel));
857 if (!table_x || !table_y) {
858 mp_msg(MSGT_SPUDEC, MSGL_FATAL, "Fatal: spudec_draw_scaled: calloc failed\n");
860 scale_table(0, 0, spu->width - 1, spu->scaled_width - 1, table_x);
861 scale_table(0, 0, spu->height - 1, spu->scaled_height - 1, table_y);
862 for (y = 0; y < spu->scaled_height; y++)
863 for (x = 0; x < spu->scaled_width; x++)
864 scale_image(x, y, table_x, table_y, spu);
865 free(table_x);
866 free(table_y);
867 break;
868 case 0:
869 /* no antialiasing */
870 for (y = 0; y < spu->scaled_height; ++y) {
871 int unscaled_y = y * 0x100 / scaley;
872 int strides = spu->stride * unscaled_y;
873 int scaled_strides = spu->scaled_stride * y;
874 for (x = 0; x < spu->scaled_width; ++x) {
875 int unscaled_x = x * 0x100 / scalex;
876 spu->scaled_image[scaled_strides + x] = spu->image[strides + unscaled_x];
877 spu->scaled_aimage[scaled_strides + x] = spu->aimage[strides + unscaled_x];
880 break;
881 case 1:
883 /* Intermediate antialiasing. */
884 for (y = 0; y < spu->scaled_height; ++y) {
885 const unsigned int unscaled_top = y * spu->orig_frame_height / dys;
886 unsigned int unscaled_bottom = (y + 1) * spu->orig_frame_height / dys;
887 if (unscaled_bottom >= spu->height)
888 unscaled_bottom = spu->height - 1;
889 for (x = 0; x < spu->scaled_width; ++x) {
890 const unsigned int unscaled_left = x * spu->orig_frame_width / dxs;
891 unsigned int unscaled_right = (x + 1) * spu->orig_frame_width / dxs;
892 unsigned int color = 0;
893 unsigned int alpha = 0;
894 unsigned int walkx, walky;
895 unsigned int base, tmp;
896 if (unscaled_right >= spu->width)
897 unscaled_right = spu->width - 1;
898 for (walky = unscaled_top; walky <= unscaled_bottom; ++walky)
899 for (walkx = unscaled_left; walkx <= unscaled_right; ++walkx) {
900 base = walky * spu->stride + walkx;
901 tmp = canon_alpha(spu->aimage[base]);
902 alpha += tmp;
903 color += tmp * spu->image[base];
905 base = y * spu->scaled_stride + x;
906 spu->scaled_image[base] = alpha ? color / alpha : 0;
907 spu->scaled_aimage[base] =
908 alpha * (1 + unscaled_bottom - unscaled_top) * (1 + unscaled_right - unscaled_left);
909 /* spu->scaled_aimage[base] =
910 alpha * dxs * dys / spu->orig_frame_width / spu->orig_frame_height; */
911 if (spu->scaled_aimage[base]) {
912 spu->scaled_aimage[base] = 256 - spu->scaled_aimage[base];
913 if (spu->scaled_aimage[base] + spu->scaled_image[base] > 255)
914 spu->scaled_image[base] = 256 - spu->scaled_aimage[base];
919 break;
920 case 2:
922 /* Best antialiasing. Very slow. */
923 /* Any pixel (x, y) represents pixels from the original
924 rectangular region comprised between the columns
925 unscaled_y and unscaled_y + 0x100 / scaley and the rows
926 unscaled_x and unscaled_x + 0x100 / scalex
928 The original rectangular region that the scaled pixel
929 represents is cut in 9 rectangular areas like this:
931 +---+-----------------+---+
932 | 1 | 2 | 3 |
933 +---+-----------------+---+
934 | | | |
935 | 4 | 5 | 6 |
936 | | | |
937 +---+-----------------+---+
938 | 7 | 8 | 9 |
939 +---+-----------------+---+
941 The width of the left column is at most one pixel and
942 it is never null and its right column is at a pixel
943 boundary. The height of the top row is at most one
944 pixel it is never null and its bottom row is at a
945 pixel boundary. The width and height of region 5 are
946 integral values. The width of the right column is
947 what remains and is less than one pixel. The height
948 of the bottom row is what remains and is less than
949 one pixel.
951 The row above 1, 2, 3 is unscaled_y. The row between
952 1, 2, 3 and 4, 5, 6 is top_low_row. The row between 4,
953 5, 6 and 7, 8, 9 is (unsigned int)unscaled_y_bottom.
954 The row beneath 7, 8, 9 is unscaled_y_bottom.
956 The column left of 1, 4, 7 is unscaled_x. The column
957 between 1, 4, 7 and 2, 5, 8 is left_right_column. The
958 column between 2, 5, 8 and 3, 6, 9 is (unsigned
959 int)unscaled_x_right. The column right of 3, 6, 9 is
960 unscaled_x_right. */
961 const double inv_scalex = (double) 0x100 / scalex;
962 const double inv_scaley = (double) 0x100 / scaley;
963 for (y = 0; y < spu->scaled_height; ++y) {
964 const double unscaled_y = y * inv_scaley;
965 const double unscaled_y_bottom = unscaled_y + inv_scaley;
966 const unsigned int top_low_row = FFMIN(unscaled_y_bottom, unscaled_y + 1.0);
967 const double top = top_low_row - unscaled_y;
968 const unsigned int height = unscaled_y_bottom > top_low_row
969 ? (unsigned int) unscaled_y_bottom - top_low_row
970 : 0;
971 const double bottom = unscaled_y_bottom > top_low_row
972 ? unscaled_y_bottom - floor(unscaled_y_bottom)
973 : 0.0;
974 for (x = 0; x < spu->scaled_width; ++x) {
975 const double unscaled_x = x * inv_scalex;
976 const double unscaled_x_right = unscaled_x + inv_scalex;
977 const unsigned int left_right_column = FFMIN(unscaled_x_right, unscaled_x + 1.0);
978 const double left = left_right_column - unscaled_x;
979 const unsigned int width = unscaled_x_right > left_right_column
980 ? (unsigned int) unscaled_x_right - left_right_column
981 : 0;
982 const double right = unscaled_x_right > left_right_column
983 ? unscaled_x_right - floor(unscaled_x_right)
984 : 0.0;
985 double color = 0.0;
986 double alpha = 0.0;
987 double tmp;
988 unsigned int base;
989 /* Now use these informations to compute a good alpha,
990 and lightness. The sum is on each of the 9
991 region's surface and alpha and lightness.
993 transformed alpha = sum(surface * alpha) / sum(surface)
994 transformed color = sum(surface * alpha * color) / sum(surface * alpha)
996 /* 1: top left part */
997 base = spu->stride * (unsigned int) unscaled_y;
998 tmp = left * top * canon_alpha(spu->aimage[base + (unsigned int) unscaled_x]);
999 alpha += tmp;
1000 color += tmp * spu->image[base + (unsigned int) unscaled_x];
1001 /* 2: top center part */
1002 if (width > 0) {
1003 unsigned int walkx;
1004 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
1005 base = spu->stride * (unsigned int) unscaled_y + walkx;
1006 tmp = /* 1.0 * */ top * canon_alpha(spu->aimage[base]);
1007 alpha += tmp;
1008 color += tmp * spu->image[base];
1011 /* 3: top right part */
1012 if (right > 0.0) {
1013 base = spu->stride * (unsigned int) unscaled_y + (unsigned int) unscaled_x_right;
1014 tmp = right * top * canon_alpha(spu->aimage[base]);
1015 alpha += tmp;
1016 color += tmp * spu->image[base];
1018 /* 4: center left part */
1019 if (height > 0) {
1020 unsigned int walky;
1021 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1022 base = spu->stride * walky + (unsigned int) unscaled_x;
1023 tmp = left /* * 1.0 */ * canon_alpha(spu->aimage[base]);
1024 alpha += tmp;
1025 color += tmp * spu->image[base];
1028 /* 5: center part */
1029 if (width > 0 && height > 0) {
1030 unsigned int walky;
1031 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1032 unsigned int walkx;
1033 base = spu->stride * walky;
1034 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
1035 tmp = /* 1.0 * 1.0 * */ canon_alpha(spu->aimage[base + walkx]);
1036 alpha += tmp;
1037 color += tmp * spu->image[base + walkx];
1041 /* 6: center right part */
1042 if (right > 0.0 && height > 0) {
1043 unsigned int walky;
1044 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) {
1045 base = spu->stride * walky + (unsigned int) unscaled_x_right;
1046 tmp = right /* * 1.0 */ * canon_alpha(spu->aimage[base]);
1047 alpha += tmp;
1048 color += tmp * spu->image[base];
1051 /* 7: bottom left part */
1052 if (bottom > 0.0) {
1053 base = spu->stride * (unsigned int) unscaled_y_bottom + (unsigned int) unscaled_x;
1054 tmp = left * bottom * canon_alpha(spu->aimage[base]);
1055 alpha += tmp;
1056 color += tmp * spu->image[base];
1058 /* 8: bottom center part */
1059 if (width > 0 && bottom > 0.0) {
1060 unsigned int walkx;
1061 base = spu->stride * (unsigned int) unscaled_y_bottom;
1062 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
1063 tmp = /* 1.0 * */ bottom * canon_alpha(spu->aimage[base + walkx]);
1064 alpha += tmp;
1065 color += tmp * spu->image[base + walkx];
1068 /* 9: bottom right part */
1069 if (right > 0.0 && bottom > 0.0) {
1070 base = spu->stride * (unsigned int) unscaled_y_bottom + (unsigned int) unscaled_x_right;
1071 tmp = right * bottom * canon_alpha(spu->aimage[base]);
1072 alpha += tmp;
1073 color += tmp * spu->image[base];
1075 /* Finally mix these transparency and brightness information suitably */
1076 base = spu->scaled_stride * y + x;
1077 spu->scaled_image[base] = alpha > 0 ? color / alpha : 0;
1078 spu->scaled_aimage[base] = alpha * scalex * scaley / 0x10000;
1079 if (spu->scaled_aimage[base]) {
1080 spu->scaled_aimage[base] = 256 - spu->scaled_aimage[base];
1081 if (spu->scaled_aimage[base] + spu->scaled_image[base] > 255)
1082 spu->scaled_image[base] = 256 - spu->scaled_aimage[base];
1088 nothing_to_do:
1089 /* Kludge: draw_alpha needs width multiple of 8. */
1090 if (spu->scaled_width < spu->scaled_stride)
1091 for (y = 0; y < spu->scaled_height; ++y) {
1092 memset(spu->scaled_aimage + y * spu->scaled_stride + spu->scaled_width, 0,
1093 spu->scaled_stride - spu->scaled_width);
1095 spu->scaled_frame_width = dxs;
1096 spu->scaled_frame_height = dys;
1099 if (spu->scaled_image){
1100 switch (spu_alignment) {
1101 case 0:
1102 spu->scaled_start_row = dys*sub_pos/100;
1103 if (spu->scaled_start_row + spu->scaled_height > dys)
1104 spu->scaled_start_row = dys - spu->scaled_height;
1105 break;
1106 case 1:
1107 spu->scaled_start_row = dys*sub_pos/100 - spu->scaled_height/2;
1108 if (sub_pos >= 50 && spu->scaled_start_row + spu->scaled_height > dys)
1109 spu->scaled_start_row = dys - spu->scaled_height;
1110 break;
1111 case 2:
1112 spu->scaled_start_row = dys*sub_pos/100 - spu->scaled_height;
1113 break;
1115 draw_alpha(spu->scaled_start_col, spu->scaled_start_row, spu->scaled_width, spu->scaled_height,
1116 spu->scaled_image, spu->scaled_aimage, spu->scaled_stride);
1117 spu->spu_changed = 0;
1121 else
1123 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPU not displayed: start_pts=%d end_pts=%d now_pts=%d\n",
1124 spu->start_pts, spu->end_pts, spu->now_pts);
1128 void spudec_update_palette(void * this, unsigned int *palette)
1130 spudec_handle_t *spu = (spudec_handle_t *) this;
1131 if (spu && palette) {
1132 memcpy(spu->global_palette, palette, sizeof(spu->global_palette));
1133 if(spu->hw_spu)
1134 spu->hw_spu->control(VOCTRL_SET_SPU_PALETTE,spu->global_palette);
1138 void spudec_set_font_factor(void * this, double factor)
1140 spudec_handle_t *spu = (spudec_handle_t *) this;
1141 spu->font_start_level = (int)(0xF0-(0xE0*factor));
1144 static void spudec_parse_extradata(spudec_handle_t *this,
1145 uint8_t *extradata, int extradata_len)
1147 uint8_t *buffer, *ptr;
1148 unsigned int *pal = this->global_palette, *cuspal = this->cuspal;
1149 unsigned int tridx;
1150 int i;
1152 if (extradata_len == 16*4) {
1153 for (i=0; i<16; i++)
1154 pal[i] = AV_RB32(extradata + i*4);
1155 this->auto_palette = 0;
1156 return;
1159 if (!(ptr = buffer = malloc(extradata_len+1)))
1160 return;
1161 memcpy(buffer, extradata, extradata_len);
1162 buffer[extradata_len] = 0;
1164 do {
1165 if (*ptr == '#')
1166 continue;
1167 if (!strncmp(ptr, "size: ", 6))
1168 sscanf(ptr + 6, "%dx%d", &this->orig_frame_width, &this->orig_frame_height);
1169 if (!strncmp(ptr, "palette: ", 9) &&
1170 sscanf(ptr + 9, "%x, %x, %x, %x, %x, %x, %x, %x, "
1171 "%x, %x, %x, %x, %x, %x, %x, %x",
1172 &pal[ 0], &pal[ 1], &pal[ 2], &pal[ 3],
1173 &pal[ 4], &pal[ 5], &pal[ 6], &pal[ 7],
1174 &pal[ 8], &pal[ 9], &pal[10], &pal[11],
1175 &pal[12], &pal[13], &pal[14], &pal[15]) == 16) {
1176 for (i=0; i<16; i++)
1177 pal[i] = vobsub_palette_to_yuv(pal[i]);
1178 this->auto_palette = 0;
1180 if (!strncasecmp(ptr, "forced subs: on", 15))
1181 this->forced_subs_only = 1;
1182 if (!strncmp(ptr, "custom colors: ON, tridx: ", 26) &&
1183 sscanf(ptr + 26, "%x, colors: %x, %x, %x, %x",
1184 &tridx, cuspal+0, cuspal+1, cuspal+2, cuspal+3) == 5) {
1185 for (i=0; i<4; i++) {
1186 cuspal[i] = vobsub_rgb_to_yuv(cuspal[i]);
1187 if (tridx & (1 << (12-4*i)))
1188 cuspal[i] |= 1 << 31;
1190 this->custom = 1;
1192 } while ((ptr=strchr(ptr,'\n')) && *++ptr);
1194 free(buffer);
1197 void *spudec_new_scaled(unsigned int *palette, unsigned int frame_width, unsigned int frame_height, uint8_t *extradata, int extradata_len)
1199 spudec_handle_t *this = calloc(1, sizeof(spudec_handle_t));
1200 if (this){
1201 this->orig_frame_height = frame_height;
1202 // set up palette:
1203 if (palette)
1204 memcpy(this->global_palette, palette, sizeof(this->global_palette));
1205 else
1206 this->auto_palette = 1;
1207 if (extradata)
1208 spudec_parse_extradata(this, extradata, extradata_len);
1209 /* XXX Although the video frame is some size, the SPU frame is
1210 always maximum size i.e. 720 wide and 576 or 480 high */
1211 this->orig_frame_width = 720;
1212 if (this->orig_frame_height == 480 || this->orig_frame_height == 240)
1213 this->orig_frame_height = 480;
1214 else
1215 this->orig_frame_height = 576;
1217 else
1218 mp_msg(MSGT_SPUDEC,MSGL_FATAL, "FATAL: spudec_init: calloc");
1219 return this;
1222 void *spudec_new(unsigned int *palette)
1224 return spudec_new_scaled(palette, 0, 0, NULL, 0);
1227 void spudec_free(void *this)
1229 spudec_handle_t *spu = (spudec_handle_t*)this;
1230 if (spu) {
1231 while (spu->queue_head)
1232 spudec_free_packet(spudec_dequeue_packet(spu));
1233 if (spu->packet)
1234 free(spu->packet);
1235 if (spu->scaled_image)
1236 free(spu->scaled_image);
1237 if (spu->image)
1238 free(spu->image);
1239 free(spu);
1243 void spudec_set_hw_spu(void *this, const vo_functions_t *hw_spu)
1245 spudec_handle_t *spu = (spudec_handle_t*)this;
1246 if (!spu)
1247 return;
1248 spu->hw_spu = hw_spu;
1249 hw_spu->control(VOCTRL_SET_SPU_PALETTE,spu->global_palette);