Mercurial > mplayer.hg
annotate sub/spudec.c @ 33874:e1bec41397bb
Don't let VCD track number and guiInfo.Track differ.
Internally use guiInfo.Track for the track without offset now and
externally speak of "titles" to the user. The titles are given minus
the VCD metadata track. (The dynamic label variable $t isn't affected.)
This also fixes some strange behavior when using the prev/next buttons
when no VCD could be loaded.
Rename MSGTR_VCDTrack MSGTR_Title to reflect the change.
author | ib |
---|---|
date | Wed, 10 Aug 2011 14:48:49 +0000 |
parents | 1cad23803d94 |
children | 48310248f892 |
rev | line source |
---|---|
32456 | 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! ;-) | |
5 * | |
6 * Kim Minh Kaplan | |
7 * implement fragments reassembly, RLE decoding. | |
8 * read brightness from the IFO. | |
9 * | |
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> | |
12 * | |
13 * This file is part of MPlayer. | |
14 * | |
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. | |
19 * | |
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. | |
24 * | |
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. | |
28 */ | |
29 | |
30 #include "config.h" | |
31 #include "mp_msg.h" | |
32 | |
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> | |
32467 | 40 #include "sub.h" |
32456 | 41 #include "libvo/video_out.h" |
32464
22888a8cb312
Do not use a path for including files in the same directory.
reimar
parents:
32459
diff
changeset
|
42 #include "spudec.h" |
22888a8cb312
Do not use a path for including files in the same directory.
reimar
parents:
32459
diff
changeset
|
43 #include "vobsub.h" |
32456 | 44 #include "libavutil/avutil.h" |
45 #include "libavutil/intreadwrite.h" | |
46 #include "libswscale/swscale.h" | |
47 | |
48 /* Valid values for spu_aamode: | |
49 0: none (fastest, most ugly) | |
50 1: approximate | |
51 2: full (slowest) | |
52 3: bilinear (similiar to vobsub, fast and not too bad) | |
53 4: uses swscaler gaussian (this is the only one that looks good) | |
54 */ | |
55 | |
56 int spu_aamode = 3; | |
57 int spu_alignment = -1; | |
58 float spu_gaussvar = 1.0; | |
59 | |
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; | |
77 }; | |
78 | |
79 struct palette_crop_cache { | |
80 int valid; | |
81 uint32_t palette; | |
82 int sx, sy, ex, ey; | |
83 int result; | |
84 }; | |
85 | |
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 const vo_functions_t *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 */ | |
123 | |
124 struct palette_crop_cache palette_crop_cache; | |
125 } spudec_handle_t; | |
126 | |
127 static void spudec_queue_packet(spudec_handle_t *this, packet_t *packet) | |
128 { | |
129 if (this->queue_head == NULL) | |
130 this->queue_head = packet; | |
131 else | |
132 this->queue_tail->next = packet; | |
133 this->queue_tail = packet; | |
134 } | |
135 | |
136 static packet_t *spudec_dequeue_packet(spudec_handle_t *this) | |
137 { | |
138 packet_t *retval = this->queue_head; | |
139 | |
140 this->queue_head = retval->next; | |
141 if (this->queue_head == NULL) | |
142 this->queue_tail = NULL; | |
143 | |
144 return retval; | |
145 } | |
146 | |
147 static void spudec_free_packet(packet_t *packet) | |
148 { | |
32511
b39155e98ac3
Remove some useless NULL pointer checks before invoking free() on the pointer.
diego
parents:
32467
diff
changeset
|
149 free(packet->packet); |
32456 | 150 free(packet); |
151 } | |
152 | |
153 static inline unsigned int get_be16(const unsigned char *p) | |
154 { | |
155 return (p[0] << 8) + p[1]; | |
156 } | |
157 | |
158 static inline unsigned int get_be24(const unsigned char *p) | |
159 { | |
160 return (get_be16(p) << 8) + p[2]; | |
161 } | |
162 | |
163 static void next_line(packet_t *packet) | |
164 { | |
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; | |
168 } | |
169 | |
170 static inline unsigned char get_nibble(packet_t *packet) | |
171 { | |
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; | |
177 } | |
178 nib = packet->packet[*nibblep / 2]; | |
179 if (*nibblep % 2) | |
180 nib &= 0xf; | |
181 else | |
182 nib >>= 4; | |
183 ++*nibblep; | |
184 return nib; | |
185 } | |
186 | |
187 /* Cut the sub to visible part */ | |
188 static inline void spudec_cut_image(spudec_handle_t *this) | |
189 { | |
190 unsigned int fy, ly; | |
191 unsigned int first_y, last_y; | |
192 | |
193 if (this->stride == 0 || this->height == 0) { | |
194 return; | |
195 } | |
196 | |
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; | |
203 | |
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; | |
210 } | |
211 | |
212 // printf("new h %d new start %d (sz %d st %d)---\n\n", this->height, this->start_row, this->image_size, this->stride); | |
213 | |
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); | |
217 } | |
218 } | |
219 | |
220 | |
221 static int spudec_alloc_image(spudec_handle_t *this, int stride, int height) | |
222 { | |
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; | |
233 } | |
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); | |
240 } | |
241 } | |
242 return this->image != NULL; | |
243 } | |
244 | |
245 /** | |
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. | |
249 */ | |
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) | |
254 { | |
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; | |
261 } | |
262 for (; x < dst_stride; x++) | |
263 *dsta++ = *dst++ = 0; | |
264 src += src_stride; | |
265 } | |
266 } | |
267 | |
268 static int apply_palette_crop(spudec_handle_t *this, | |
269 unsigned crop_x, unsigned crop_y, | |
270 unsigned crop_w, unsigned crop_h) | |
271 { | |
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; | |
281 } | |
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; | |
295 } | |
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); | |
306 | |
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; | |
312 } | |
313 | |
314 int spudec_apply_palette_crop(void *this, uint32_t palette, | |
315 int sx, int sy, int ex, int ey) | |
316 { | |
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; | |
339 } | |
340 | |
341 static void spudec_process_data(spudec_handle_t *this, packet_t *packet) | |
342 { | |
343 unsigned int i, x, y; | |
344 uint8_t *dst; | |
345 | |
346 if (!spudec_alloc_image(this, packet->stride, packet->height)) | |
347 return; | |
348 | |
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)); | |
356 | |
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); | |
372 } | |
373 rle = (rle << 4) | get_nibble(packet); | |
374 } | |
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; | |
383 } | |
384 memset(dst, color, len); | |
385 dst += len; | |
386 } | |
387 apply_palette_crop(this, 0, 0, this->pal_width, this->pal_height); | |
388 } | |
389 | |
390 | |
391 /* | |
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. | |
397 */ | |
398 static void compute_palette(spudec_handle_t *this, packet_t *packet) | |
399 { | |
400 int used[16],i,cused,start,step,color; | |
401 | |
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); | |
415 } | |
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; | |
423 } | |
424 } | |
425 } | |
426 | |
427 static void spudec_process_control(spudec_handle_t *this, int pts100) | |
428 { | |
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; | |
446 | |
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]); | |
503 } | |
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; | |
545 } | |
546 } | |
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; | |
553 } | |
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]; | |
570 } | |
571 packet->packet = malloc(this->packet_size); | |
572 memcpy(packet->packet, this->packet, this->packet_size); | |
573 spudec_queue_packet(this, packet); | |
574 } | |
575 } | |
576 } | |
577 | |
578 static void spudec_decode(spudec_handle_t *this, int pts100) | |
579 { | |
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 this->hw_spu->draw_frame((uint8_t**)&pkg); | |
589 } | |
590 } | |
591 | |
592 int spudec_changed(void * this) | |
593 { | |
594 spudec_handle_t * spu = this; | |
595 return spu->spu_changed || spu->now_pts > spu->end_pts; | |
596 } | |
597 | |
598 void spudec_assemble(void *this, unsigned char *packet, unsigned int len, int pts100) | |
599 { | |
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; | |
605 } | |
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) { | |
32511
b39155e98ac3
Remove some useless NULL pointer checks before invoking free() on the pointer.
diego
parents:
32467
diff
changeset
|
611 free(spu->packet); |
32456 | 612 spu->packet = malloc(len2); |
613 spu->packet_reserve = spu->packet != NULL ? len2 : 0; | |
614 } | |
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; | |
620 } | |
621 memcpy(spu->packet, packet, len); | |
622 spu->packet_offset = len; | |
623 spu->packet_pts = pts100; | |
624 } | |
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; | |
634 } | |
635 } | |
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; | |
652 } | |
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; | |
657 } | |
658 x=y; | |
659 } | |
660 // [cb] packet is done; start new packet | |
661 spu->packet_offset = 0; | |
662 } | |
663 #else | |
664 if (spu->packet_offset == spu->packet_size) { | |
665 spudec_decode(spu, pts100); | |
666 spu->packet_offset = 0; | |
667 } | |
668 #endif | |
669 } | |
670 | |
671 void spudec_reset(void *this) // called after seek | |
672 { | |
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; | |
679 } | |
680 | |
681 void spudec_heartbeat(void *this, unsigned int pts100) | |
682 { | |
683 spudec_handle_t *spu = this; | |
684 spu->now_pts = pts100; | |
685 | |
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; | |
702 | |
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); | |
710 } | |
711 spudec_free_packet(packet); | |
712 spu->spu_changed = 1; | |
713 } | |
714 } | |
715 | |
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; | |
723 } | |
724 | |
725 void spudec_set_forced_subs_only(void * const this, const unsigned int flag) | |
726 { | |
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"); | |
730 } | |
731 } | |
732 | |
733 void spudec_draw(void *this, void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride)) | |
734 { | |
735 spudec_handle_t *spu = this; | |
736 if (spudec_visible(spu)) | |
737 { | |
738 draw_alpha(spu->start_col, spu->start_row, spu->width, spu->height, | |
739 spu->image, spu->aimage, spu->stride); | |
740 spu->spu_changed = 0; | |
741 } | |
742 } | |
743 | |
744 /* calc the bbox for spudec subs */ | |
745 void spudec_calc_bbox(void *me, unsigned int dxs, unsigned int dys, unsigned int* bbox) | |
746 { | |
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; | |
755 } | |
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; | |
776 } | |
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; | |
786 } | |
787 } | |
788 } | |
789 /* transform mplayer's alpha value into an opacity value that is linear */ | |
790 static inline int canon_alpha(int alpha) | |
791 { | |
792 return (uint8_t)-alpha; | |
793 } | |
794 | |
795 typedef struct { | |
796 unsigned position; | |
797 unsigned left_up; | |
798 unsigned right_down; | |
799 }scale_pixel; | |
800 | |
801 | |
802 static void scale_table(unsigned int start_src, unsigned int start_tar, unsigned int end_src, unsigned int end_tar, scale_pixel * table) | |
803 { | |
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; | |
811 } | |
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; | |
817 } | |
818 } | |
819 | |
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) | |
822 { | |
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]; | |
849 } | |
850 } | |
851 | |
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) | |
855 { | |
856 struct SwsContext *ctx; | |
857 static SwsFilter filter; | |
858 static int firsttime = 1; | |
859 static float oldvar; | |
860 int i; | |
861 | |
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; | |
869 } | |
870 | |
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); | |
877 } | |
878 | |
879 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)) | |
880 { | |
881 spudec_handle_t *spu = me; | |
882 scale_pixel *table_x; | |
883 scale_pixel *table_y; | |
884 | |
885 if (spudec_visible(spu)) { | |
886 | |
887 // check if only forced subtitles are requested | |
888 if( (spu->forced_subs_only) && !(spu->is_forced_sub) ){ | |
889 return; | |
890 } | |
891 | |
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); | |
895 } | |
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; | |
913 } | |
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; | |
918 } | |
919 } | |
920 if (spu->scaled_image) { | |
921 unsigned int x, y; | |
33143
1cad23803d94
Fix artefacts at right border of scaled bitmap subtitles by clearing the
reimar
parents:
32511
diff
changeset
|
922 // needs to be 0-initialized because draw_alpha draws always a |
1cad23803d94
Fix artefacts at right border of scaled bitmap subtitles by clearing the
reimar
parents:
32511
diff
changeset
|
923 // multiple of 8 pixels. TODO: optimize |
1cad23803d94
Fix artefacts at right border of scaled bitmap subtitles by clearing the
reimar
parents:
32511
diff
changeset
|
924 if (spu->scaled_width & 7) |
1cad23803d94
Fix artefacts at right border of scaled bitmap subtitles by clearing the
reimar
parents:
32511
diff
changeset
|
925 memset(spu->scaled_image, 0, 2 * spu->scaled_image_size); |
32456 | 926 if (spu->scaled_width <= 1 || spu->scaled_height <= 1) { |
927 goto nothing_to_do; | |
928 } | |
929 switch(spu_aamode&15) { | |
930 case 4: | |
931 sws_spu_image(spu->scaled_image, spu->scaled_aimage, | |
932 spu->scaled_width, spu->scaled_height, spu->scaled_stride, | |
933 spu->image, spu->aimage, spu->width, spu->height, spu->stride); | |
934 break; | |
935 case 3: | |
936 table_x = calloc(spu->scaled_width, sizeof(scale_pixel)); | |
937 table_y = calloc(spu->scaled_height, sizeof(scale_pixel)); | |
938 if (!table_x || !table_y) { | |
939 mp_msg(MSGT_SPUDEC, MSGL_FATAL, "Fatal: spudec_draw_scaled: calloc failed\n"); | |
940 } | |
941 scale_table(0, 0, spu->width - 1, spu->scaled_width - 1, table_x); | |
942 scale_table(0, 0, spu->height - 1, spu->scaled_height - 1, table_y); | |
943 for (y = 0; y < spu->scaled_height; y++) | |
944 for (x = 0; x < spu->scaled_width; x++) | |
945 scale_image(x, y, table_x, table_y, spu); | |
946 free(table_x); | |
947 free(table_y); | |
948 break; | |
949 case 0: | |
950 /* no antialiasing */ | |
951 for (y = 0; y < spu->scaled_height; ++y) { | |
952 int unscaled_y = y * 0x100 / scaley; | |
953 int strides = spu->stride * unscaled_y; | |
954 int scaled_strides = spu->scaled_stride * y; | |
955 for (x = 0; x < spu->scaled_width; ++x) { | |
956 int unscaled_x = x * 0x100 / scalex; | |
957 spu->scaled_image[scaled_strides + x] = spu->image[strides + unscaled_x]; | |
958 spu->scaled_aimage[scaled_strides + x] = spu->aimage[strides + unscaled_x]; | |
959 } | |
960 } | |
961 break; | |
962 case 1: | |
963 { | |
964 /* Intermediate antialiasing. */ | |
965 for (y = 0; y < spu->scaled_height; ++y) { | |
966 const unsigned int unscaled_top = y * spu->orig_frame_height / dys; | |
967 unsigned int unscaled_bottom = (y + 1) * spu->orig_frame_height / dys; | |
968 if (unscaled_bottom >= spu->height) | |
969 unscaled_bottom = spu->height - 1; | |
970 for (x = 0; x < spu->scaled_width; ++x) { | |
971 const unsigned int unscaled_left = x * spu->orig_frame_width / dxs; | |
972 unsigned int unscaled_right = (x + 1) * spu->orig_frame_width / dxs; | |
973 unsigned int color = 0; | |
974 unsigned int alpha = 0; | |
975 unsigned int walkx, walky; | |
976 unsigned int base, tmp; | |
977 if (unscaled_right >= spu->width) | |
978 unscaled_right = spu->width - 1; | |
979 for (walky = unscaled_top; walky <= unscaled_bottom; ++walky) | |
980 for (walkx = unscaled_left; walkx <= unscaled_right; ++walkx) { | |
981 base = walky * spu->stride + walkx; | |
982 tmp = canon_alpha(spu->aimage[base]); | |
983 alpha += tmp; | |
984 color += tmp * spu->image[base]; | |
985 } | |
986 base = y * spu->scaled_stride + x; | |
987 spu->scaled_image[base] = alpha ? color / alpha : 0; | |
988 spu->scaled_aimage[base] = | |
989 alpha * (1 + unscaled_bottom - unscaled_top) * (1 + unscaled_right - unscaled_left); | |
990 /* spu->scaled_aimage[base] = | |
991 alpha * dxs * dys / spu->orig_frame_width / spu->orig_frame_height; */ | |
992 if (spu->scaled_aimage[base]) { | |
993 spu->scaled_aimage[base] = 256 - spu->scaled_aimage[base]; | |
994 if (spu->scaled_aimage[base] + spu->scaled_image[base] > 255) | |
995 spu->scaled_image[base] = 256 - spu->scaled_aimage[base]; | |
996 } | |
997 } | |
998 } | |
999 } | |
1000 break; | |
1001 case 2: | |
1002 { | |
1003 /* Best antialiasing. Very slow. */ | |
1004 /* Any pixel (x, y) represents pixels from the original | |
1005 rectangular region comprised between the columns | |
1006 unscaled_y and unscaled_y + 0x100 / scaley and the rows | |
1007 unscaled_x and unscaled_x + 0x100 / scalex | |
1008 | |
1009 The original rectangular region that the scaled pixel | |
1010 represents is cut in 9 rectangular areas like this: | |
1011 | |
1012 +---+-----------------+---+ | |
1013 | 1 | 2 | 3 | | |
1014 +---+-----------------+---+ | |
1015 | | | | | |
1016 | 4 | 5 | 6 | | |
1017 | | | | | |
1018 +---+-----------------+---+ | |
1019 | 7 | 8 | 9 | | |
1020 +---+-----------------+---+ | |
1021 | |
1022 The width of the left column is at most one pixel and | |
1023 it is never null and its right column is at a pixel | |
1024 boundary. The height of the top row is at most one | |
1025 pixel it is never null and its bottom row is at a | |
1026 pixel boundary. The width and height of region 5 are | |
1027 integral values. The width of the right column is | |
1028 what remains and is less than one pixel. The height | |
1029 of the bottom row is what remains and is less than | |
1030 one pixel. | |
1031 | |
1032 The row above 1, 2, 3 is unscaled_y. The row between | |
1033 1, 2, 3 and 4, 5, 6 is top_low_row. The row between 4, | |
1034 5, 6 and 7, 8, 9 is (unsigned int)unscaled_y_bottom. | |
1035 The row beneath 7, 8, 9 is unscaled_y_bottom. | |
1036 | |
1037 The column left of 1, 4, 7 is unscaled_x. The column | |
1038 between 1, 4, 7 and 2, 5, 8 is left_right_column. The | |
1039 column between 2, 5, 8 and 3, 6, 9 is (unsigned | |
1040 int)unscaled_x_right. The column right of 3, 6, 9 is | |
1041 unscaled_x_right. */ | |
1042 const double inv_scalex = (double) 0x100 / scalex; | |
1043 const double inv_scaley = (double) 0x100 / scaley; | |
1044 for (y = 0; y < spu->scaled_height; ++y) { | |
1045 const double unscaled_y = y * inv_scaley; | |
1046 const double unscaled_y_bottom = unscaled_y + inv_scaley; | |
1047 const unsigned int top_low_row = FFMIN(unscaled_y_bottom, unscaled_y + 1.0); | |
1048 const double top = top_low_row - unscaled_y; | |
1049 const unsigned int height = unscaled_y_bottom > top_low_row | |
1050 ? (unsigned int) unscaled_y_bottom - top_low_row | |
1051 : 0; | |
1052 const double bottom = unscaled_y_bottom > top_low_row | |
1053 ? unscaled_y_bottom - floor(unscaled_y_bottom) | |
1054 : 0.0; | |
1055 for (x = 0; x < spu->scaled_width; ++x) { | |
1056 const double unscaled_x = x * inv_scalex; | |
1057 const double unscaled_x_right = unscaled_x + inv_scalex; | |
1058 const unsigned int left_right_column = FFMIN(unscaled_x_right, unscaled_x + 1.0); | |
1059 const double left = left_right_column - unscaled_x; | |
1060 const unsigned int width = unscaled_x_right > left_right_column | |
1061 ? (unsigned int) unscaled_x_right - left_right_column | |
1062 : 0; | |
1063 const double right = unscaled_x_right > left_right_column | |
1064 ? unscaled_x_right - floor(unscaled_x_right) | |
1065 : 0.0; | |
1066 double color = 0.0; | |
1067 double alpha = 0.0; | |
1068 double tmp; | |
1069 unsigned int base; | |
1070 /* Now use these informations to compute a good alpha, | |
1071 and lightness. The sum is on each of the 9 | |
1072 region's surface and alpha and lightness. | |
1073 | |
1074 transformed alpha = sum(surface * alpha) / sum(surface) | |
1075 transformed color = sum(surface * alpha * color) / sum(surface * alpha) | |
1076 */ | |
1077 /* 1: top left part */ | |
1078 base = spu->stride * (unsigned int) unscaled_y; | |
1079 tmp = left * top * canon_alpha(spu->aimage[base + (unsigned int) unscaled_x]); | |
1080 alpha += tmp; | |
1081 color += tmp * spu->image[base + (unsigned int) unscaled_x]; | |
1082 /* 2: top center part */ | |
1083 if (width > 0) { | |
1084 unsigned int walkx; | |
1085 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) { | |
1086 base = spu->stride * (unsigned int) unscaled_y + walkx; | |
1087 tmp = /* 1.0 * */ top * canon_alpha(spu->aimage[base]); | |
1088 alpha += tmp; | |
1089 color += tmp * spu->image[base]; | |
1090 } | |
1091 } | |
1092 /* 3: top right part */ | |
1093 if (right > 0.0) { | |
1094 base = spu->stride * (unsigned int) unscaled_y + (unsigned int) unscaled_x_right; | |
1095 tmp = right * top * canon_alpha(spu->aimage[base]); | |
1096 alpha += tmp; | |
1097 color += tmp * spu->image[base]; | |
1098 } | |
1099 /* 4: center left part */ | |
1100 if (height > 0) { | |
1101 unsigned int walky; | |
1102 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) { | |
1103 base = spu->stride * walky + (unsigned int) unscaled_x; | |
1104 tmp = left /* * 1.0 */ * canon_alpha(spu->aimage[base]); | |
1105 alpha += tmp; | |
1106 color += tmp * spu->image[base]; | |
1107 } | |
1108 } | |
1109 /* 5: center part */ | |
1110 if (width > 0 && height > 0) { | |
1111 unsigned int walky; | |
1112 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) { | |
1113 unsigned int walkx; | |
1114 base = spu->stride * walky; | |
1115 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) { | |
1116 tmp = /* 1.0 * 1.0 * */ canon_alpha(spu->aimage[base + walkx]); | |
1117 alpha += tmp; | |
1118 color += tmp * spu->image[base + walkx]; | |
1119 } | |
1120 } | |
1121 } | |
1122 /* 6: center right part */ | |
1123 if (right > 0.0 && height > 0) { | |
1124 unsigned int walky; | |
1125 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) { | |
1126 base = spu->stride * walky + (unsigned int) unscaled_x_right; | |
1127 tmp = right /* * 1.0 */ * canon_alpha(spu->aimage[base]); | |
1128 alpha += tmp; | |
1129 color += tmp * spu->image[base]; | |
1130 } | |
1131 } | |
1132 /* 7: bottom left part */ | |
1133 if (bottom > 0.0) { | |
1134 base = spu->stride * (unsigned int) unscaled_y_bottom + (unsigned int) unscaled_x; | |
1135 tmp = left * bottom * canon_alpha(spu->aimage[base]); | |
1136 alpha += tmp; | |
1137 color += tmp * spu->image[base]; | |
1138 } | |
1139 /* 8: bottom center part */ | |
1140 if (width > 0 && bottom > 0.0) { | |
1141 unsigned int walkx; | |
1142 base = spu->stride * (unsigned int) unscaled_y_bottom; | |
1143 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) { | |
1144 tmp = /* 1.0 * */ bottom * canon_alpha(spu->aimage[base + walkx]); | |
1145 alpha += tmp; | |
1146 color += tmp * spu->image[base + walkx]; | |
1147 } | |
1148 } | |
1149 /* 9: bottom right part */ | |
1150 if (right > 0.0 && bottom > 0.0) { | |
1151 base = spu->stride * (unsigned int) unscaled_y_bottom + (unsigned int) unscaled_x_right; | |
1152 tmp = right * bottom * canon_alpha(spu->aimage[base]); | |
1153 alpha += tmp; | |
1154 color += tmp * spu->image[base]; | |
1155 } | |
1156 /* Finally mix these transparency and brightness information suitably */ | |
1157 base = spu->scaled_stride * y + x; | |
1158 spu->scaled_image[base] = alpha > 0 ? color / alpha : 0; | |
1159 spu->scaled_aimage[base] = alpha * scalex * scaley / 0x10000; | |
1160 if (spu->scaled_aimage[base]) { | |
1161 spu->scaled_aimage[base] = 256 - spu->scaled_aimage[base]; | |
1162 if (spu->scaled_aimage[base] + spu->scaled_image[base] > 255) | |
1163 spu->scaled_image[base] = 256 - spu->scaled_aimage[base]; | |
1164 } | |
1165 } | |
1166 } | |
1167 } | |
1168 } | |
1169 nothing_to_do: | |
1170 /* Kludge: draw_alpha needs width multiple of 8. */ | |
1171 if (spu->scaled_width < spu->scaled_stride) | |
1172 for (y = 0; y < spu->scaled_height; ++y) { | |
1173 memset(spu->scaled_aimage + y * spu->scaled_stride + spu->scaled_width, 0, | |
1174 spu->scaled_stride - spu->scaled_width); | |
1175 } | |
1176 spu->scaled_frame_width = dxs; | |
1177 spu->scaled_frame_height = dys; | |
1178 } | |
1179 } | |
1180 if (spu->scaled_image){ | |
1181 switch (spu_alignment) { | |
1182 case 0: | |
1183 spu->scaled_start_row = dys*sub_pos/100; | |
1184 if (spu->scaled_start_row + spu->scaled_height > dys) | |
1185 spu->scaled_start_row = dys - spu->scaled_height; | |
1186 break; | |
1187 case 1: | |
1188 spu->scaled_start_row = dys*sub_pos/100 - spu->scaled_height/2; | |
1189 if (sub_pos >= 50 && spu->scaled_start_row + spu->scaled_height > dys) | |
1190 spu->scaled_start_row = dys - spu->scaled_height; | |
1191 break; | |
1192 case 2: | |
1193 spu->scaled_start_row = dys*sub_pos/100 - spu->scaled_height; | |
1194 break; | |
1195 } | |
1196 draw_alpha(spu->scaled_start_col, spu->scaled_start_row, spu->scaled_width, spu->scaled_height, | |
1197 spu->scaled_image, spu->scaled_aimage, spu->scaled_stride); | |
1198 spu->spu_changed = 0; | |
1199 } | |
1200 } | |
1201 } | |
1202 else | |
1203 { | |
1204 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPU not displayed: start_pts=%d end_pts=%d now_pts=%d\n", | |
1205 spu->start_pts, spu->end_pts, spu->now_pts); | |
1206 } | |
1207 } | |
1208 | |
1209 void spudec_update_palette(void * this, unsigned int *palette) | |
1210 { | |
1211 spudec_handle_t *spu = this; | |
1212 if (spu && palette) { | |
1213 memcpy(spu->global_palette, palette, sizeof(spu->global_palette)); | |
1214 if(spu->hw_spu) | |
1215 spu->hw_spu->control(VOCTRL_SET_SPU_PALETTE,spu->global_palette); | |
1216 } | |
1217 } | |
1218 | |
1219 void spudec_set_font_factor(void * this, double factor) | |
1220 { | |
1221 spudec_handle_t *spu = this; | |
1222 spu->font_start_level = (int)(0xF0-(0xE0*factor)); | |
1223 } | |
1224 | |
1225 static void spudec_parse_extradata(spudec_handle_t *this, | |
1226 uint8_t *extradata, int extradata_len) | |
1227 { | |
1228 uint8_t *buffer, *ptr; | |
1229 unsigned int *pal = this->global_palette, *cuspal = this->cuspal; | |
1230 unsigned int tridx; | |
1231 int i; | |
1232 | |
1233 if (extradata_len == 16*4) { | |
1234 for (i=0; i<16; i++) | |
1235 pal[i] = AV_RB32(extradata + i*4); | |
1236 this->auto_palette = 0; | |
1237 return; | |
1238 } | |
1239 | |
1240 if (!(ptr = buffer = malloc(extradata_len+1))) | |
1241 return; | |
1242 memcpy(buffer, extradata, extradata_len); | |
1243 buffer[extradata_len] = 0; | |
1244 | |
1245 do { | |
1246 if (*ptr == '#') | |
1247 continue; | |
1248 if (!strncmp(ptr, "size: ", 6)) | |
1249 sscanf(ptr + 6, "%dx%d", &this->orig_frame_width, &this->orig_frame_height); | |
1250 if (!strncmp(ptr, "palette: ", 9) && | |
1251 sscanf(ptr + 9, "%x, %x, %x, %x, %x, %x, %x, %x, " | |
1252 "%x, %x, %x, %x, %x, %x, %x, %x", | |
1253 &pal[ 0], &pal[ 1], &pal[ 2], &pal[ 3], | |
1254 &pal[ 4], &pal[ 5], &pal[ 6], &pal[ 7], | |
1255 &pal[ 8], &pal[ 9], &pal[10], &pal[11], | |
1256 &pal[12], &pal[13], &pal[14], &pal[15]) == 16) { | |
1257 for (i=0; i<16; i++) | |
1258 pal[i] = vobsub_palette_to_yuv(pal[i]); | |
1259 this->auto_palette = 0; | |
1260 } | |
1261 if (!strncasecmp(ptr, "forced subs: on", 15)) | |
1262 this->forced_subs_only = 1; | |
1263 if (!strncmp(ptr, "custom colors: ON, tridx: ", 26) && | |
1264 sscanf(ptr + 26, "%x, colors: %x, %x, %x, %x", | |
1265 &tridx, cuspal+0, cuspal+1, cuspal+2, cuspal+3) == 5) { | |
1266 for (i=0; i<4; i++) { | |
1267 cuspal[i] = vobsub_rgb_to_yuv(cuspal[i]); | |
1268 if (tridx & (1 << (12-4*i))) | |
1269 cuspal[i] |= 1 << 31; | |
1270 } | |
1271 this->custom = 1; | |
1272 } | |
1273 } while ((ptr=strchr(ptr,'\n')) && *++ptr); | |
1274 | |
1275 free(buffer); | |
1276 } | |
1277 | |
1278 void *spudec_new_scaled(unsigned int *palette, unsigned int frame_width, unsigned int frame_height, uint8_t *extradata, int extradata_len) | |
1279 { | |
1280 spudec_handle_t *this = calloc(1, sizeof(spudec_handle_t)); | |
1281 if (this){ | |
1282 this->orig_frame_height = frame_height; | |
1283 this->orig_frame_width = frame_width; | |
1284 // set up palette: | |
1285 if (palette) | |
1286 memcpy(this->global_palette, palette, sizeof(this->global_palette)); | |
1287 else | |
1288 this->auto_palette = 1; | |
1289 if (extradata) | |
1290 spudec_parse_extradata(this, extradata, extradata_len); | |
1291 /* XXX Although the video frame is some size, the SPU frame is | |
1292 always maximum size i.e. 720 wide and 576 or 480 high */ | |
1293 // For HD files in MKV the VobSub resolution can be higher though, | |
1294 // see largeres_vobsub.mkv | |
1295 if (this->orig_frame_width <= 720 && this->orig_frame_height <= 576) { | |
1296 this->orig_frame_width = 720; | |
1297 if (this->orig_frame_height == 480 || this->orig_frame_height == 240) | |
1298 this->orig_frame_height = 480; | |
1299 else | |
1300 this->orig_frame_height = 576; | |
1301 } | |
1302 } | |
1303 else | |
1304 mp_msg(MSGT_SPUDEC,MSGL_FATAL, "FATAL: spudec_init: calloc"); | |
1305 return this; | |
1306 } | |
1307 | |
1308 void *spudec_new(unsigned int *palette) | |
1309 { | |
1310 return spudec_new_scaled(palette, 0, 0, NULL, 0); | |
1311 } | |
1312 | |
1313 void spudec_free(void *this) | |
1314 { | |
1315 spudec_handle_t *spu = this; | |
1316 if (spu) { | |
1317 while (spu->queue_head) | |
1318 spudec_free_packet(spudec_dequeue_packet(spu)); | |
1319 free(spu->packet); | |
1320 spu->packet = NULL; | |
1321 free(spu->scaled_image); | |
1322 spu->scaled_image = NULL; | |
1323 free(spu->image); | |
1324 spu->image = NULL; | |
1325 spu->aimage = NULL; | |
1326 free(spu->pal_image); | |
1327 spu->pal_image = NULL; | |
1328 spu->image_size = 0; | |
1329 spu->pal_width = spu->pal_height = 0; | |
1330 free(spu); | |
1331 } | |
1332 } | |
1333 | |
1334 void spudec_set_hw_spu(void *this, const vo_functions_t *hw_spu) | |
1335 { | |
1336 spudec_handle_t *spu = this; | |
1337 if (!spu) | |
1338 return; | |
1339 spu->hw_spu = hw_spu; | |
1340 hw_spu->control(VOCTRL_SET_SPU_PALETTE,spu->global_palette); | |
1341 } | |
1342 | |
1343 #define MP_NOPTS_VALUE (-1LL<<63) //both int64_t and double should be able to represent this exactly | |
1344 | |
1345 /** | |
1346 * palette must contain at least 256 32-bit entries, otherwise crashes | |
1347 * are possible | |
1348 */ | |
1349 void spudec_set_paletted(void *this, const uint8_t *pal_img, int pal_stride, | |
1350 const void *palette, | |
1351 int x, int y, int w, int h, | |
1352 double pts, double endpts) | |
1353 { | |
1354 int i; | |
1355 uint16_t g8a8_pal[256]; | |
1356 packet_t *packet; | |
1357 const uint32_t *pal = palette; | |
1358 spudec_handle_t *spu = this; | |
1359 uint8_t *img; | |
1360 uint8_t *aimg; | |
1361 int stride = (w + 7) & ~7; | |
1362 if ((unsigned)w >= 0x8000 || (unsigned)h > 0x4000) | |
1363 return; | |
1364 packet = calloc(1, sizeof(packet_t)); | |
1365 packet->is_decoded = 1; | |
1366 packet->width = w; | |
1367 packet->height = h; | |
1368 packet->stride = stride; | |
1369 packet->start_col = x; | |
1370 packet->start_row = y; | |
1371 packet->data_len = 2 * stride * h; | |
1372 if (packet->data_len) { // size 0 is a special "clear" packet | |
1373 packet->packet = malloc(packet->data_len); | |
1374 img = packet->packet; | |
1375 aimg = packet->packet + stride * h; | |
1376 for (i = 0; i < 256; i++) { | |
1377 uint32_t pixel = pal[i]; | |
1378 int alpha = pixel >> 24; | |
1379 int gray = (((pixel & 0x000000ff) >> 0) + | |
1380 ((pixel & 0x0000ff00) >> 7) + | |
1381 ((pixel & 0x00ff0000) >> 16)) >> 2; | |
1382 gray = FFMIN(gray, alpha); | |
1383 g8a8_pal[i] = (-alpha << 8) | gray; | |
1384 } | |
1385 pal2gray_alpha(g8a8_pal, pal_img, pal_stride, | |
1386 img, aimg, stride, w, h); | |
1387 } | |
1388 packet->start_pts = 0; | |
1389 packet->end_pts = 0x7fffffff; | |
1390 if (pts != MP_NOPTS_VALUE) | |
1391 packet->start_pts = pts * 90000; | |
1392 if (endpts != MP_NOPTS_VALUE) | |
1393 packet->end_pts = endpts * 90000; | |
1394 spudec_queue_packet(spu, packet); | |
1395 } |