Mercurial > mplayer.hg
annotate sub/spudec.c @ 35833:dbfedb331095
Keep GUI history untouched upon file select "Cancel".
Currently, when "Cancel" is selected in the file select menu, the
GUI history can be modified nevertheless. Presuming that "Cancel"
shall discard changes, the history should be kept unchanged, too.
Patch by Hans-Dieter Kosch, hdkosch kabelbw de.
author | ib |
---|---|
date | Thu, 28 Feb 2013 11:19:59 +0000 |
parents | d206960484fe |
children | 389d43c448b3 |
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" |
35712
d206960484fe
Add a number of missing libavutil header #includes.
diego
parents:
35253
diff
changeset
|
45 #include "libavutil/common.h" |
32456 | 46 #include "libavutil/intreadwrite.h" |
47 #include "libswscale/swscale.h" | |
48 | |
49 /* Valid values for spu_aamode: | |
50 0: none (fastest, most ugly) | |
51 1: approximate | |
52 2: full (slowest) | |
53 3: bilinear (similiar to vobsub, fast and not too bad) | |
54 4: uses swscaler gaussian (this is the only one that looks good) | |
55 */ | |
56 | |
57 int spu_aamode = 3; | |
58 int spu_alignment = -1; | |
59 float spu_gaussvar = 1.0; | |
60 | |
34784 | 61 typedef struct spu_packet_t packet_t; |
62 struct spu_packet_t { | |
32456 | 63 int is_decoded; |
64 unsigned char *packet; | |
65 int data_len; | |
66 unsigned int palette[4]; | |
67 unsigned int alpha[4]; | |
68 unsigned int control_start; /* index of start of control data */ | |
69 unsigned int current_nibble[2]; /* next data nibble (4 bits) to be | |
70 processed (for RLE decoding) for | |
71 even and odd lines */ | |
72 int deinterlace_oddness; /* 0 or 1, index into current_nibble */ | |
73 unsigned int start_col; | |
74 unsigned int start_row; | |
75 unsigned int width, height, stride; | |
76 unsigned int start_pts, end_pts; | |
77 packet_t *next; | |
78 }; | |
79 | |
80 struct palette_crop_cache { | |
81 int valid; | |
82 uint32_t palette; | |
83 int sx, sy, ex, ey; | |
84 int result; | |
85 }; | |
86 | |
87 typedef struct { | |
88 packet_t *queue_head; | |
89 packet_t *queue_tail; | |
90 unsigned int global_palette[16]; | |
91 unsigned int orig_frame_width, orig_frame_height; | |
92 unsigned char* packet; | |
93 size_t packet_reserve; /* size of the memory pointed to by packet */ | |
94 unsigned int packet_offset; /* end of the currently assembled fragment */ | |
95 unsigned int packet_size; /* size of the packet once all fragments are assembled */ | |
96 int packet_pts; /* PTS for this packet */ | |
97 unsigned int palette[4]; | |
98 unsigned int alpha[4]; | |
99 unsigned int cuspal[4]; | |
100 unsigned int custom; | |
101 unsigned int now_pts; | |
102 unsigned int start_pts, end_pts; | |
103 unsigned int start_col; | |
104 unsigned int start_row; | |
105 unsigned int width, height, stride; | |
106 size_t image_size; /* Size of the image buffer */ | |
107 unsigned char *image; /* Grayscale value */ | |
108 unsigned char *aimage; /* Alpha value */ | |
109 unsigned int pal_start_col, pal_start_row; | |
110 unsigned int pal_width, pal_height; | |
111 unsigned char *pal_image; /* palette entry value */ | |
112 unsigned int scaled_frame_width, scaled_frame_height; | |
113 unsigned int scaled_start_col, scaled_start_row; | |
114 unsigned int scaled_width, scaled_height, scaled_stride; | |
115 size_t scaled_image_size; | |
116 unsigned char *scaled_image; | |
117 unsigned char *scaled_aimage; | |
118 int auto_palette; /* 1 if we lack a palette and must use an heuristic. */ | |
119 int font_start_level; /* Darkest value used for the computed font */ | |
120 const vo_functions_t *hw_spu; | |
121 int spu_changed; | |
122 unsigned int forced_subs_only; /* flag: 0=display all subtitle, !0 display only forced subtitles */ | |
123 unsigned int is_forced_sub; /* true if current subtitle is a forced subtitle */ | |
124 | |
125 struct palette_crop_cache palette_crop_cache; | |
126 } spudec_handle_t; | |
127 | |
128 static void spudec_queue_packet(spudec_handle_t *this, packet_t *packet) | |
129 { | |
130 if (this->queue_head == NULL) | |
131 this->queue_head = packet; | |
132 else | |
133 this->queue_tail->next = packet; | |
134 this->queue_tail = packet; | |
135 } | |
136 | |
137 static packet_t *spudec_dequeue_packet(spudec_handle_t *this) | |
138 { | |
139 packet_t *retval = this->queue_head; | |
140 | |
141 this->queue_head = retval->next; | |
142 if (this->queue_head == NULL) | |
143 this->queue_tail = NULL; | |
144 | |
145 return retval; | |
146 } | |
147 | |
148 static void spudec_free_packet(packet_t *packet) | |
149 { | |
32511
b39155e98ac3
Remove some useless NULL pointer checks before invoking free() on the pointer.
diego
parents:
32467
diff
changeset
|
150 free(packet->packet); |
32456 | 151 free(packet); |
152 } | |
153 | |
154 static inline unsigned int get_be16(const unsigned char *p) | |
155 { | |
156 return (p[0] << 8) + p[1]; | |
157 } | |
158 | |
159 static inline unsigned int get_be24(const unsigned char *p) | |
160 { | |
161 return (get_be16(p) << 8) + p[2]; | |
162 } | |
163 | |
164 static void next_line(packet_t *packet) | |
165 { | |
166 if (packet->current_nibble[packet->deinterlace_oddness] % 2) | |
167 packet->current_nibble[packet->deinterlace_oddness]++; | |
168 packet->deinterlace_oddness = (packet->deinterlace_oddness + 1) % 2; | |
169 } | |
170 | |
171 static inline unsigned char get_nibble(packet_t *packet) | |
172 { | |
173 unsigned char nib; | |
174 unsigned int *nibblep = packet->current_nibble + packet->deinterlace_oddness; | |
175 if (*nibblep / 2 >= packet->control_start) { | |
176 mp_msg(MSGT_SPUDEC,MSGL_WARN, "SPUdec: ERROR: get_nibble past end of packet\n"); | |
177 return 0; | |
178 } | |
179 nib = packet->packet[*nibblep / 2]; | |
180 if (*nibblep % 2) | |
181 nib &= 0xf; | |
182 else | |
183 nib >>= 4; | |
184 ++*nibblep; | |
185 return nib; | |
186 } | |
187 | |
188 /* Cut the sub to visible part */ | |
189 static inline void spudec_cut_image(spudec_handle_t *this) | |
190 { | |
191 unsigned int fy, ly; | |
192 unsigned int first_y, last_y; | |
193 | |
194 if (this->stride == 0 || this->height == 0) { | |
195 return; | |
196 } | |
197 | |
198 for (fy = 0; fy < this->image_size && !this->aimage[fy]; fy++); | |
199 for (ly = this->stride * this->height-1; ly && !this->aimage[ly]; ly--); | |
200 first_y = fy / this->stride; | |
201 last_y = ly / this->stride; | |
202 //printf("first_y: %d, last_y: %d\n", first_y, last_y); | |
203 this->start_row += first_y; | |
204 | |
205 // Some subtitles trigger this condition | |
206 if (last_y + 1 > first_y ) { | |
207 this->height = last_y - first_y +1; | |
208 } else { | |
209 this->height = 0; | |
210 return; | |
211 } | |
212 | |
213 // printf("new h %d new start %d (sz %d st %d)---\n\n", this->height, this->start_row, this->image_size, this->stride); | |
214 | |
215 if (first_y > 0) { | |
216 memmove(this->image, this->image + this->stride * first_y, this->stride * this->height); | |
217 memmove(this->aimage, this->aimage + this->stride * first_y, this->stride * this->height); | |
218 } | |
219 } | |
220 | |
221 | |
222 static int spudec_alloc_image(spudec_handle_t *this, int stride, int height) | |
223 { | |
224 if (this->width > stride) // just a safeguard | |
225 this->width = stride; | |
226 this->stride = stride; | |
227 this->height = height; | |
228 if (this->image_size < this->stride * this->height) { | |
229 if (this->image != NULL) { | |
230 free(this->image); | |
35209 | 231 this->image = NULL; |
32456 | 232 free(this->pal_image); |
35209 | 233 this->pal_image = NULL; |
32456 | 234 this->image_size = 0; |
235 this->pal_width = this->pal_height = 0; | |
236 } | |
237 this->image = malloc(2 * this->stride * this->height); | |
238 if (this->image) { | |
239 this->image_size = this->stride * this->height; | |
240 this->aimage = this->image + this->image_size; | |
241 // use stride here as well to simplify reallocation checks | |
242 this->pal_image = malloc(this->stride * this->height); | |
243 } | |
244 } | |
245 return this->image != NULL; | |
246 } | |
247 | |
248 /** | |
249 * \param pal palette in MPlayer-style gray-alpha values, i.e. | |
250 * alpha == 0 means transparent, 1 fully opaque, | |
251 * gray value <= 256 - alpha. | |
252 */ | |
253 static void pal2gray_alpha(const uint16_t *pal, | |
254 const uint8_t *src, int src_stride, | |
255 uint8_t *dst, uint8_t *dsta, | |
256 int dst_stride, int w, int h) | |
257 { | |
258 int x, y; | |
259 for (y = 0; y < h; y++) { | |
260 for (x = 0; x < w; x++) { | |
261 uint16_t pixel = pal[src[x]]; | |
262 *dst++ = pixel; | |
263 *dsta++ = pixel >> 8; | |
264 } | |
265 for (; x < dst_stride; x++) | |
266 *dsta++ = *dst++ = 0; | |
267 src += src_stride; | |
268 } | |
269 } | |
270 | |
271 static int apply_palette_crop(spudec_handle_t *this, | |
272 unsigned crop_x, unsigned crop_y, | |
273 unsigned crop_w, unsigned crop_h) | |
274 { | |
275 int i; | |
276 uint8_t *src; | |
277 uint16_t pal[4]; | |
278 unsigned stride = (crop_w + 7) & ~7; | |
34778
48310248f892
Ensure that the highlight disappears when switching
reimar
parents:
33143
diff
changeset
|
279 int ret = 1; |
32456 | 280 if (crop_x > this->pal_width || crop_y > this->pal_height || |
281 crop_w > this->pal_width - crop_x || crop_h > this->pal_width - crop_y || | |
282 crop_w > 0x8000 || crop_h > 0x8000 || | |
283 stride * crop_h > this->image_size) { | |
34778
48310248f892
Ensure that the highlight disappears when switching
reimar
parents:
33143
diff
changeset
|
284 // this might be an actual error or just signal that |
48310248f892
Ensure that the highlight disappears when switching
reimar
parents:
33143
diff
changeset
|
285 // the highlight should be removed. |
48310248f892
Ensure that the highlight disappears when switching
reimar
parents:
33143
diff
changeset
|
286 this->width = 0; |
48310248f892
Ensure that the highlight disappears when switching
reimar
parents:
33143
diff
changeset
|
287 this->height = 0; |
48310248f892
Ensure that the highlight disappears when switching
reimar
parents:
33143
diff
changeset
|
288 ret = 0; |
48310248f892
Ensure that the highlight disappears when switching
reimar
parents:
33143
diff
changeset
|
289 goto out; |
32456 | 290 } |
291 for (i = 0; i < 4; ++i) { | |
292 int color; | |
293 int alpha = this->alpha[i]; | |
294 // extend 4 -> 8 bit | |
295 alpha |= alpha << 4; | |
296 if (this->custom && (this->cuspal[i] >> 31) != 0) | |
297 alpha = 0; | |
298 color = this->custom ? this->cuspal[i] : | |
299 this->global_palette[this->palette[i]]; | |
300 color = (color >> 16) & 0xff; | |
301 // convert to MPlayer-style gray/alpha palette | |
302 color = FFMIN(color, alpha); | |
303 pal[i] = (-alpha << 8) | color; | |
304 } | |
305 src = this->pal_image + crop_y * this->pal_width + crop_x; | |
306 pal2gray_alpha(pal, src, this->pal_width, | |
307 this->image, this->aimage, stride, | |
308 crop_w, crop_h); | |
309 this->width = crop_w; | |
310 this->height = crop_h; | |
311 this->stride = stride; | |
312 this->start_col = this->pal_start_col + crop_x; | |
313 this->start_row = this->pal_start_row + crop_y; | |
314 spudec_cut_image(this); | |
315 | |
34778
48310248f892
Ensure that the highlight disappears when switching
reimar
parents:
33143
diff
changeset
|
316 out: |
32456 | 317 // reset scaled image |
318 this->scaled_frame_width = 0; | |
319 this->scaled_frame_height = 0; | |
320 this->palette_crop_cache.valid = 0; | |
321 return 1; | |
322 } | |
323 | |
324 int spudec_apply_palette_crop(void *this, uint32_t palette, | |
325 int sx, int sy, int ex, int ey) | |
326 { | |
327 spudec_handle_t *spu = this; | |
328 struct palette_crop_cache *c = &spu->palette_crop_cache; | |
329 if (c->valid && c->palette == palette && | |
330 c->sx == sx && c->sy == sy && c->ex == ex && c->ey == ey) | |
331 return c->result; | |
332 spu->palette[0] = (palette >> 28) & 0xf; | |
333 spu->palette[1] = (palette >> 24) & 0xf; | |
334 spu->palette[2] = (palette >> 20) & 0xf; | |
335 spu->palette[3] = (palette >> 16) & 0xf; | |
336 spu->alpha[0] = (palette >> 12) & 0xf; | |
337 spu->alpha[1] = (palette >> 8) & 0xf; | |
338 spu->alpha[2] = (palette >> 4) & 0xf; | |
339 spu->alpha[3] = palette & 0xf; | |
340 spu->spu_changed = 1; | |
341 c->result = apply_palette_crop(spu, | |
342 sx - spu->pal_start_col, sy - spu->pal_start_row, | |
343 ex - sx, ey - sy); | |
344 c->palette = palette; | |
345 c->sx = sx; c->sy = sy; | |
346 c->ex = ex; c->ey = ey; | |
347 c->valid = 1; | |
348 return c->result; | |
349 } | |
350 | |
351 static void spudec_process_data(spudec_handle_t *this, packet_t *packet) | |
352 { | |
353 unsigned int i, x, y; | |
354 uint8_t *dst; | |
355 | |
356 if (!spudec_alloc_image(this, packet->stride, packet->height)) | |
357 return; | |
358 | |
359 this->pal_start_col = packet->start_col; | |
360 this->pal_start_row = packet->start_row; | |
361 this->pal_height = packet->height; | |
362 this->pal_width = packet->width; | |
363 this->stride = packet->stride; | |
364 memcpy(this->palette, packet->palette, sizeof(this->palette)); | |
365 memcpy(this->alpha, packet->alpha, sizeof(this->alpha)); | |
366 | |
367 i = packet->current_nibble[1]; | |
368 x = 0; | |
369 y = 0; | |
370 dst = this->pal_image; | |
371 while (packet->current_nibble[0] < i | |
372 && packet->current_nibble[1] / 2 < packet->control_start | |
373 && y < this->pal_height) { | |
374 unsigned int len, color; | |
375 unsigned int rle = 0; | |
376 rle = get_nibble(packet); | |
377 if (rle < 0x04) { | |
378 if (rle == 0) { | |
379 rle = (rle << 4) | get_nibble(packet); | |
380 if (rle < 0x04) | |
381 rle = (rle << 4) | get_nibble(packet); | |
382 } | |
383 rle = (rle << 4) | get_nibble(packet); | |
384 } | |
385 color = 3 - (rle & 0x3); | |
386 len = rle >> 2; | |
387 x += len; | |
388 if (len == 0 || x >= this->pal_width) { | |
389 len += this->pal_width - x; | |
390 next_line(packet); | |
391 x = 0; | |
392 ++y; | |
393 } | |
394 memset(dst, color, len); | |
395 dst += len; | |
396 } | |
397 apply_palette_crop(this, 0, 0, this->pal_width, this->pal_height); | |
398 } | |
399 | |
400 | |
401 /* | |
402 This function tries to create a usable palette. | |
403 It determines how many non-transparent colors are used, and assigns different | |
404 gray scale values to each color. | |
405 I tested it with four streams and even got something readable. Half of the | |
406 times I got black characters with white around and half the reverse. | |
407 */ | |
408 static void compute_palette(spudec_handle_t *this, packet_t *packet) | |
409 { | |
410 int used[16],i,cused,start,step,color; | |
411 | |
412 memset(used, 0, sizeof(used)); | |
413 for (i=0; i<4; i++) | |
414 if (packet->alpha[i]) /* !Transparent? */ | |
415 used[packet->palette[i]] = 1; | |
416 for (cused=0, i=0; i<16; i++) | |
417 if (used[i]) cused++; | |
418 if (!cused) return; | |
419 if (cused == 1) { | |
420 start = 0x80; | |
421 step = 0; | |
422 } else { | |
423 start = this->font_start_level; | |
424 step = (0xF0-this->font_start_level)/(cused-1); | |
425 } | |
426 memset(used, 0, sizeof(used)); | |
427 for (i=0; i<4; i++) { | |
428 color = packet->palette[i]; | |
429 if (packet->alpha[i] && !used[color]) { /* not assigned? */ | |
430 used[color] = 1; | |
431 this->global_palette[color] = start<<16; | |
432 start += step; | |
433 } | |
434 } | |
435 } | |
436 | |
437 static void spudec_process_control(spudec_handle_t *this, int pts100) | |
438 { | |
439 int a,b,c,d; /* Temporary vars */ | |
440 unsigned int date, type; | |
441 unsigned int off; | |
442 unsigned int start_off = 0; | |
443 unsigned int next_off; | |
444 unsigned int start_pts = 0; | |
445 unsigned int end_pts = 0; | |
446 unsigned int current_nibble[2] = {0, 0}; | |
447 unsigned int control_start; | |
448 unsigned int display = 0; | |
449 unsigned int start_col = 0; | |
450 unsigned int end_col = 0; | |
451 unsigned int start_row = 0; | |
452 unsigned int end_row = 0; | |
453 unsigned int width = 0; | |
454 unsigned int height = 0; | |
455 unsigned int stride = 0; | |
456 | |
457 control_start = get_be16(this->packet + 2); | |
458 next_off = control_start; | |
459 while (start_off != next_off) { | |
460 start_off = next_off; | |
461 date = get_be16(this->packet + start_off) * 1024; | |
462 next_off = get_be16(this->packet + start_off + 2); | |
463 mp_msg(MSGT_SPUDEC,MSGL_DBG2, "date=%d\n", date); | |
464 off = start_off + 4; | |
465 for (type = this->packet[off++]; type != 0xff; type = this->packet[off++]) { | |
466 mp_msg(MSGT_SPUDEC,MSGL_DBG2, "cmd=%d ",type); | |
467 switch(type) { | |
468 case 0x00: | |
469 /* Menu ID, 1 byte */ | |
470 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Menu ID\n"); | |
471 /* shouldn't a Menu ID type force display start? */ | |
472 start_pts = pts100 < 0 && -pts100 >= date ? 0 : pts100 + date; | |
473 end_pts = UINT_MAX; | |
474 display = 1; | |
475 this->is_forced_sub=~0; // current subtitle is forced | |
476 break; | |
477 case 0x01: | |
478 /* Start display */ | |
479 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Start display!\n"); | |
480 start_pts = pts100 < 0 && -pts100 >= date ? 0 : pts100 + date; | |
481 end_pts = UINT_MAX; | |
482 display = 1; | |
483 this->is_forced_sub=0; | |
484 break; | |
485 case 0x02: | |
486 /* Stop display */ | |
487 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Stop display!\n"); | |
488 end_pts = pts100 < 0 && -pts100 >= date ? 0 : pts100 + date; | |
489 break; | |
490 case 0x03: | |
491 /* Palette */ | |
492 this->palette[0] = this->packet[off] >> 4; | |
493 this->palette[1] = this->packet[off] & 0xf; | |
494 this->palette[2] = this->packet[off + 1] >> 4; | |
495 this->palette[3] = this->packet[off + 1] & 0xf; | |
496 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Palette %d, %d, %d, %d\n", | |
497 this->palette[0], this->palette[1], this->palette[2], this->palette[3]); | |
498 off+=2; | |
499 break; | |
500 case 0x04: | |
501 /* Alpha */ | |
502 a = this->packet[off] >> 4; | |
503 b = this->packet[off] & 0xf; | |
504 c = this->packet[off + 1] >> 4; | |
505 d = this->packet[off + 1] & 0xf; | |
506 // Note: some DVDs change these values to create a fade-in/fade-out effect | |
507 // We can not handle this, so just keep the highest value during the display time. | |
508 if (display) { | |
509 a = FFMAX(a, this->alpha[0]); | |
510 b = FFMAX(b, this->alpha[1]); | |
511 c = FFMAX(c, this->alpha[2]); | |
512 d = FFMAX(d, this->alpha[3]); | |
513 } | |
514 this->alpha[0] = a; | |
515 this->alpha[1] = b; | |
516 this->alpha[2] = c; | |
517 this->alpha[3] = d; | |
518 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Alpha %d, %d, %d, %d\n", | |
519 this->alpha[0], this->alpha[1], this->alpha[2], this->alpha[3]); | |
520 off+=2; | |
521 break; | |
522 case 0x05: | |
523 /* Co-ords */ | |
524 a = get_be24(this->packet + off); | |
525 b = get_be24(this->packet + off + 3); | |
526 start_col = a >> 12; | |
527 end_col = a & 0xfff; | |
528 width = (end_col < start_col) ? 0 : end_col - start_col + 1; | |
529 stride = (width + 7) & ~7; /* Kludge: draw_alpha needs width multiple of 8 */ | |
530 start_row = b >> 12; | |
531 end_row = b & 0xfff; | |
532 height = (end_row < start_row) ? 0 : end_row - start_row /* + 1 */; | |
533 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Coords col: %d - %d row: %d - %d (%dx%d)\n", | |
534 start_col, end_col, start_row, end_row, | |
535 width, height); | |
536 off+=6; | |
537 break; | |
538 case 0x06: | |
539 /* Graphic lines */ | |
540 current_nibble[0] = 2 * get_be16(this->packet + off); | |
541 current_nibble[1] = 2 * get_be16(this->packet + off + 2); | |
542 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Graphic offset 1: %d offset 2: %d\n", | |
543 current_nibble[0] / 2, current_nibble[1] / 2); | |
544 off+=4; | |
545 break; | |
546 default: | |
547 mp_msg(MSGT_SPUDEC,MSGL_WARN,"spudec: Error determining control type 0x%02x. Skipping %d bytes.\n", | |
548 type, next_off - off); | |
549 goto next_control; | |
550 } | |
551 } | |
552 next_control: | |
553 if (!display) | |
554 continue; | |
555 if (end_pts == UINT_MAX && start_off != next_off) { | |
556 end_pts = get_be16(this->packet + next_off) * 1024; | |
557 end_pts = 1 - pts100 >= end_pts ? 0 : pts100 + end_pts - 1; | |
558 } | |
559 if (end_pts > 0) { | |
560 packet_t *packet = calloc(1, sizeof(packet_t)); | |
561 int i; | |
562 packet->start_pts = start_pts; | |
563 packet->end_pts = end_pts; | |
564 packet->current_nibble[0] = current_nibble[0]; | |
565 packet->current_nibble[1] = current_nibble[1]; | |
566 packet->start_row = start_row; | |
567 packet->start_col = start_col; | |
568 packet->width = width; | |
569 packet->height = height; | |
570 packet->stride = stride; | |
571 packet->control_start = control_start; | |
572 for (i=0; i<4; i++) { | |
573 packet->alpha[i] = this->alpha[i]; | |
574 packet->palette[i] = this->palette[i]; | |
575 } | |
576 packet->packet = malloc(this->packet_size); | |
577 memcpy(packet->packet, this->packet, this->packet_size); | |
578 spudec_queue_packet(this, packet); | |
579 } | |
580 } | |
581 } | |
582 | |
583 static void spudec_decode(spudec_handle_t *this, int pts100) | |
584 { | |
585 if (!this->hw_spu) | |
586 spudec_process_control(this, pts100); | |
587 else if (pts100 >= 0) { | |
588 static vo_mpegpes_t packet = { NULL, 0, 0x20, 0 }; | |
589 static vo_mpegpes_t *pkg=&packet; | |
590 packet.data = this->packet; | |
591 packet.size = this->packet_size; | |
592 packet.timestamp = pts100; | |
593 this->hw_spu->draw_frame((uint8_t**)&pkg); | |
594 } | |
595 } | |
596 | |
597 int spudec_changed(void * this) | |
598 { | |
599 spudec_handle_t * spu = this; | |
600 return spu->spu_changed || spu->now_pts > spu->end_pts; | |
601 } | |
602 | |
603 void spudec_assemble(void *this, unsigned char *packet, unsigned int len, int pts100) | |
604 { | |
605 spudec_handle_t *spu = this; | |
606 // spudec_heartbeat(this, pts100); | |
607 if (len < 2) { | |
608 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: packet too short\n"); | |
609 return; | |
610 } | |
611 spu->packet_pts = pts100; | |
612 if (spu->packet_offset == 0) { | |
613 unsigned int len2 = get_be16(packet); | |
614 // Start new fragment | |
615 if (spu->packet_reserve < len2) { | |
32511
b39155e98ac3
Remove some useless NULL pointer checks before invoking free() on the pointer.
diego
parents:
32467
diff
changeset
|
616 free(spu->packet); |
32456 | 617 spu->packet = malloc(len2); |
618 spu->packet_reserve = spu->packet != NULL ? len2 : 0; | |
619 } | |
620 if (spu->packet != NULL) { | |
621 spu->packet_size = len2; | |
622 if (len > len2) { | |
623 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: invalid frag len / len2: %d / %d \n", len, len2); | |
624 return; | |
625 } | |
626 memcpy(spu->packet, packet, len); | |
627 spu->packet_offset = len; | |
628 spu->packet_pts = pts100; | |
629 } | |
630 } else { | |
631 // Continue current fragment | |
632 if (spu->packet_size < spu->packet_offset + len){ | |
633 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: invalid fragment\n"); | |
634 spu->packet_size = spu->packet_offset = 0; | |
635 return; | |
636 } else { | |
637 memcpy(spu->packet + spu->packet_offset, packet, len); | |
638 spu->packet_offset += len; | |
639 } | |
640 } | |
641 #if 1 | |
642 // check if we have a complete packet (unfortunatelly packet_size is bad | |
643 // for some disks) | |
644 // [cb] packet_size is padded to be even -> may be one byte too long | |
645 if ((spu->packet_offset == spu->packet_size) || | |
646 ((spu->packet_offset + 1) == spu->packet_size)){ | |
647 unsigned int x=0,y; | |
648 while(x+4<=spu->packet_offset){ | |
649 y=get_be16(spu->packet+x+2); // next control pointer | |
650 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPUtest: x=%d y=%d off=%d size=%d\n",x,y,spu->packet_offset,spu->packet_size); | |
651 if(x>=4 && x==y){ // if it points to self - we're done! | |
652 // we got it! | |
653 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPUgot: off=%d size=%d \n",spu->packet_offset,spu->packet_size); | |
654 spudec_decode(spu, pts100); | |
655 spu->packet_offset = 0; | |
656 break; | |
657 } | |
658 if(y<=x || y>=spu->packet_size){ // invalid? | |
659 mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUtest: broken packet!!!!! y=%d < x=%d\n",y,x); | |
660 spu->packet_size = spu->packet_offset = 0; | |
661 break; | |
662 } | |
663 x=y; | |
664 } | |
665 // [cb] packet is done; start new packet | |
666 spu->packet_offset = 0; | |
667 } | |
668 #else | |
669 if (spu->packet_offset == spu->packet_size) { | |
670 spudec_decode(spu, pts100); | |
671 spu->packet_offset = 0; | |
672 } | |
673 #endif | |
674 } | |
675 | |
676 void spudec_reset(void *this) // called after seek | |
677 { | |
678 spudec_handle_t *spu = this; | |
679 while (spu->queue_head) | |
680 spudec_free_packet(spudec_dequeue_packet(spu)); | |
681 spu->now_pts = 0; | |
682 spu->end_pts = 0; | |
683 spu->packet_size = spu->packet_offset = 0; | |
684 } | |
685 | |
686 void spudec_heartbeat(void *this, unsigned int pts100) | |
687 { | |
688 spudec_handle_t *spu = this; | |
689 spu->now_pts = pts100; | |
690 | |
691 // TODO: detect and handle broken timestamps (e.g. due to wrapping) | |
692 while (spu->queue_head != NULL && pts100 >= spu->queue_head->start_pts) { | |
693 packet_t *packet = spudec_dequeue_packet(spu); | |
694 spu->start_pts = packet->start_pts; | |
695 spu->end_pts = packet->end_pts; | |
696 if (packet->is_decoded) { | |
697 free(spu->image); | |
698 spu->image_size = packet->data_len; | |
699 spu->image = packet->packet; | |
700 spu->aimage = packet->packet + packet->stride * packet->height; | |
701 packet->packet = NULL; | |
702 spu->width = packet->width; | |
703 spu->height = packet->height; | |
704 spu->stride = packet->stride; | |
705 spu->start_col = packet->start_col; | |
706 spu->start_row = packet->start_row; | |
707 | |
708 // reset scaled image | |
709 spu->scaled_frame_width = 0; | |
710 spu->scaled_frame_height = 0; | |
711 } else { | |
712 if (spu->auto_palette) | |
713 compute_palette(spu, packet); | |
714 spudec_process_data(spu, packet); | |
715 } | |
716 spudec_free_packet(packet); | |
717 spu->spu_changed = 1; | |
718 } | |
719 } | |
720 | |
721 int spudec_visible(void *this){ | |
722 spudec_handle_t *spu = this; | |
723 int ret=(spu->start_pts <= spu->now_pts && | |
724 spu->now_pts < spu->end_pts && | |
725 spu->height > 0); | |
726 // printf("spu visible: %d \n",ret); | |
727 return ret; | |
728 } | |
729 | |
730 void spudec_set_forced_subs_only(void * const this, const unsigned int flag) | |
731 { | |
732 if(this){ | |
733 ((spudec_handle_t *)this)->forced_subs_only=flag; | |
734 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPU: Display only forced subs now %s\n", flag ? "enabled": "disabled"); | |
735 } | |
736 } | |
737 | |
738 void spudec_draw(void *this, void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride)) | |
739 { | |
740 spudec_handle_t *spu = this; | |
741 if (spudec_visible(spu)) | |
742 { | |
743 draw_alpha(spu->start_col, spu->start_row, spu->width, spu->height, | |
744 spu->image, spu->aimage, spu->stride); | |
745 spu->spu_changed = 0; | |
746 } | |
747 } | |
748 | |
35031 | 749 static void validate_dimensions(spudec_handle_t *spu, unsigned dxs, unsigned dys) |
750 { | |
751 if (spu->orig_frame_width == 0 || spu->orig_frame_height == 0) { | |
752 spu->width = FFMIN(spu->width, dxs); | |
753 spu->height = FFMIN(spu->height, dys); | |
754 spu->start_col = FFMIN(spu->start_col, dxs - spu->width); | |
755 spu->start_row = FFMIN(spu->start_row, dys - spu->height); | |
756 return; | |
757 } | |
758 spu->orig_frame_width = FFMAX(spu->orig_frame_width, spu->start_col + spu->width); | |
759 spu->orig_frame_height = FFMAX(spu->orig_frame_height, spu->start_row + spu->height); | |
760 } | |
761 | |
32456 | 762 /* calc the bbox for spudec subs */ |
763 void spudec_calc_bbox(void *me, unsigned int dxs, unsigned int dys, unsigned int* bbox) | |
764 { | |
765 spudec_handle_t *spu = me; | |
35031 | 766 validate_dimensions(spu, dxs, dys); |
32456 | 767 if (spu->orig_frame_width == 0 || spu->orig_frame_height == 0 |
768 || (spu->orig_frame_width == dxs && spu->orig_frame_height == dys)) { | |
769 // unscaled | |
770 bbox[0] = spu->start_col; | |
771 bbox[1] = spu->start_col + spu->width; | |
772 bbox[2] = spu->start_row; | |
773 bbox[3] = spu->start_row + spu->height; | |
774 } | |
775 else { | |
776 // scaled | |
777 unsigned int scalex = 0x100 * dxs / spu->orig_frame_width; | |
778 unsigned int scaley = 0x100 * dys / spu->orig_frame_height; | |
779 bbox[0] = spu->start_col * scalex / 0x100; | |
780 bbox[1] = spu->start_col * scalex / 0x100 + spu->width * scalex / 0x100; | |
781 switch (spu_alignment) { | |
782 case 0: | |
783 bbox[3] = dys*sub_pos/100 + spu->height * scaley / 0x100; | |
784 if (bbox[3] > dys) bbox[3] = dys; | |
785 bbox[2] = bbox[3] - spu->height * scaley / 0x100; | |
786 break; | |
787 case 1: | |
788 if (sub_pos < 50) { | |
789 bbox[2] = dys*sub_pos/100 - spu->height * scaley / 0x200; | |
790 bbox[3] = bbox[2] + spu->height; | |
791 } else { | |
792 bbox[3] = dys*sub_pos/100 + spu->height * scaley / 0x200; | |
793 if (bbox[3] > dys) bbox[3] = dys; | |
794 bbox[2] = bbox[3] - spu->height * scaley / 0x100; | |
795 } | |
796 break; | |
797 case 2: | |
798 bbox[2] = dys*sub_pos/100 - spu->height * scaley / 0x100; | |
799 bbox[3] = bbox[2] + spu->height; | |
800 break; | |
801 default: /* -1 */ | |
802 bbox[2] = spu->start_row * scaley / 0x100; | |
803 bbox[3] = spu->start_row * scaley / 0x100 + spu->height * scaley / 0x100; | |
804 break; | |
805 } | |
806 } | |
807 } | |
808 /* transform mplayer's alpha value into an opacity value that is linear */ | |
809 static inline int canon_alpha(int alpha) | |
810 { | |
811 return (uint8_t)-alpha; | |
812 } | |
813 | |
814 typedef struct { | |
815 unsigned position; | |
816 unsigned left_up; | |
817 unsigned right_down; | |
818 }scale_pixel; | |
819 | |
820 | |
821 static void scale_table(unsigned int start_src, unsigned int start_tar, unsigned int end_src, unsigned int end_tar, scale_pixel * table) | |
822 { | |
823 unsigned int t; | |
824 unsigned int delta_src = end_src - start_src; | |
825 unsigned int delta_tar = end_tar - start_tar; | |
826 int src = 0; | |
827 int src_step; | |
828 if (delta_src == 0 || delta_tar == 0) { | |
829 return; | |
830 } | |
831 src_step = (delta_src << 16) / delta_tar >>1; | |
832 for (t = 0; t<=delta_tar; src += (src_step << 1), t++){ | |
833 table[t].position= FFMIN(src >> 16, end_src - 1); | |
834 table[t].right_down = src & 0xffff; | |
835 table[t].left_up = 0x10000 - table[t].right_down; | |
836 } | |
837 } | |
838 | |
839 /* bilinear scale, similar to vobsub's code */ | |
840 static void scale_image(int x, int y, scale_pixel* table_x, scale_pixel* table_y, spudec_handle_t * spu) | |
841 { | |
842 int alpha[4]; | |
843 int color[4]; | |
844 unsigned int scale[4]; | |
845 int base = table_y[y].position * spu->stride + table_x[x].position; | |
846 int scaled = y * spu->scaled_stride + x; | |
847 alpha[0] = canon_alpha(spu->aimage[base]); | |
848 alpha[1] = canon_alpha(spu->aimage[base + 1]); | |
849 alpha[2] = canon_alpha(spu->aimage[base + spu->stride]); | |
850 alpha[3] = canon_alpha(spu->aimage[base + spu->stride + 1]); | |
851 color[0] = spu->image[base]; | |
852 color[1] = spu->image[base + 1]; | |
853 color[2] = spu->image[base + spu->stride]; | |
854 color[3] = spu->image[base + spu->stride + 1]; | |
855 scale[0] = (table_x[x].left_up * table_y[y].left_up >> 16) * alpha[0]; | |
856 if (table_y[y].left_up == 0x10000) // necessary to avoid overflow-case | |
857 scale[0] = table_x[x].left_up * alpha[0]; | |
858 scale[1] = (table_x[x].right_down * table_y[y].left_up >>16) * alpha[1]; | |
859 scale[2] = (table_x[x].left_up * table_y[y].right_down >> 16) * alpha[2]; | |
860 scale[3] = (table_x[x].right_down * table_y[y].right_down >> 16) * alpha[3]; | |
861 spu->scaled_image[scaled] = (color[0] * scale[0] + color[1] * scale[1] + color[2] * scale[2] + color[3] * scale[3])>>24; | |
862 spu->scaled_aimage[scaled] = (scale[0] + scale[1] + scale[2] + scale[3]) >> 16; | |
863 if (spu->scaled_aimage[scaled]){ | |
864 // ensure that MPlayer's simplified alpha-blending can not overflow | |
865 spu->scaled_image[scaled] = FFMIN(spu->scaled_image[scaled], spu->scaled_aimage[scaled]); | |
866 // convert to MPlayer-style alpha | |
867 spu->scaled_aimage[scaled] = -spu->scaled_aimage[scaled]; | |
868 } | |
869 } | |
870 | |
871 static void sws_spu_image(unsigned char *d1, unsigned char *d2, int dw, int dh, | |
872 int ds, const unsigned char* s1, unsigned char* s2, | |
873 int sw, int sh, int ss) | |
874 { | |
875 struct SwsContext *ctx; | |
876 static SwsFilter filter; | |
877 static int firsttime = 1; | |
878 static float oldvar; | |
879 int i; | |
880 | |
881 if (!firsttime && oldvar != spu_gaussvar) sws_freeVec(filter.lumH); | |
882 if (firsttime) { | |
883 filter.lumH = filter.lumV = | |
884 filter.chrH = filter.chrV = sws_getGaussianVec(spu_gaussvar, 3.0); | |
885 sws_normalizeVec(filter.lumH, 1.0); | |
886 firsttime = 0; | |
887 oldvar = spu_gaussvar; | |
888 } | |
889 | |
890 ctx=sws_getContext(sw, sh, PIX_FMT_GRAY8, dw, dh, PIX_FMT_GRAY8, SWS_GAUSS, &filter, NULL, NULL); | |
891 sws_scale(ctx,&s1,&ss,0,sh,&d1,&ds); | |
34786 | 892 for (i=ss*sh-1; i>=0; i--) s2[i] = -s2[i]; |
32456 | 893 sws_scale(ctx,&s2,&ss,0,sh,&d2,&ds); |
34786 | 894 for (i=ds*dh-1; i>=0; i--) d2[i] = -d2[i]; |
32456 | 895 sws_freeContext(ctx); |
896 } | |
897 | |
898 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)) | |
899 { | |
900 spudec_handle_t *spu = me; | |
901 scale_pixel *table_x; | |
902 scale_pixel *table_y; | |
903 | |
904 if (spudec_visible(spu)) { | |
905 | |
906 // check if only forced subtitles are requested | |
907 if( (spu->forced_subs_only) && !(spu->is_forced_sub) ){ | |
908 return; | |
909 } | |
910 | |
35031 | 911 validate_dimensions(spu, dxs, dys); |
32456 | 912 if (!(spu_aamode&16) && (spu->orig_frame_width == 0 || spu->orig_frame_height == 0 |
913 || (spu->orig_frame_width == dxs && spu->orig_frame_height == dys))) { | |
914 spudec_draw(spu, draw_alpha); | |
915 } | |
916 else { | |
917 if (spu->scaled_frame_width != dxs || spu->scaled_frame_height != dys) { /* Resizing is needed */ | |
918 /* scaled_x = scalex * x / 0x100 | |
919 scaled_y = scaley * y / 0x100 | |
920 order of operations is important because of rounding. */ | |
921 unsigned int scalex = 0x100 * dxs / spu->orig_frame_width; | |
922 unsigned int scaley = 0x100 * dys / spu->orig_frame_height; | |
923 spu->scaled_start_col = spu->start_col * scalex / 0x100; | |
924 spu->scaled_start_row = spu->start_row * scaley / 0x100; | |
925 spu->scaled_width = spu->width * scalex / 0x100; | |
926 spu->scaled_height = spu->height * scaley / 0x100; | |
927 /* Kludge: draw_alpha needs width multiple of 8 */ | |
928 spu->scaled_stride = (spu->scaled_width + 7) & ~7; | |
929 if (spu->scaled_image_size < spu->scaled_stride * spu->scaled_height) { | |
930 if (spu->scaled_image) { | |
931 free(spu->scaled_image); | |
932 spu->scaled_image_size = 0; | |
933 } | |
934 spu->scaled_image = malloc(2 * spu->scaled_stride * spu->scaled_height); | |
935 if (spu->scaled_image) { | |
936 spu->scaled_image_size = spu->scaled_stride * spu->scaled_height; | |
937 spu->scaled_aimage = spu->scaled_image + spu->scaled_image_size; | |
938 } | |
939 } | |
940 if (spu->scaled_image) { | |
941 unsigned int x, y; | |
33143
1cad23803d94
Fix artefacts at right border of scaled bitmap subtitles by clearing the
reimar
parents:
32511
diff
changeset
|
942 // 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
|
943 // multiple of 8 pixels. TODO: optimize |
1cad23803d94
Fix artefacts at right border of scaled bitmap subtitles by clearing the
reimar
parents:
32511
diff
changeset
|
944 if (spu->scaled_width & 7) |
1cad23803d94
Fix artefacts at right border of scaled bitmap subtitles by clearing the
reimar
parents:
32511
diff
changeset
|
945 memset(spu->scaled_image, 0, 2 * spu->scaled_image_size); |
32456 | 946 if (spu->scaled_width <= 1 || spu->scaled_height <= 1) { |
947 goto nothing_to_do; | |
948 } | |
949 switch(spu_aamode&15) { | |
950 case 4: | |
951 sws_spu_image(spu->scaled_image, spu->scaled_aimage, | |
952 spu->scaled_width, spu->scaled_height, spu->scaled_stride, | |
953 spu->image, spu->aimage, spu->width, spu->height, spu->stride); | |
954 break; | |
955 case 3: | |
956 table_x = calloc(spu->scaled_width, sizeof(scale_pixel)); | |
957 table_y = calloc(spu->scaled_height, sizeof(scale_pixel)); | |
958 if (!table_x || !table_y) { | |
959 mp_msg(MSGT_SPUDEC, MSGL_FATAL, "Fatal: spudec_draw_scaled: calloc failed\n"); | |
35253
48db1b241757
Try to do something sensible when malloc fails instead
reimar
parents:
35231
diff
changeset
|
960 free(table_x); |
48db1b241757
Try to do something sensible when malloc fails instead
reimar
parents:
35231
diff
changeset
|
961 table_x = NULL; |
48db1b241757
Try to do something sensible when malloc fails instead
reimar
parents:
35231
diff
changeset
|
962 free(table_y); |
48db1b241757
Try to do something sensible when malloc fails instead
reimar
parents:
35231
diff
changeset
|
963 table_y = NULL; |
48db1b241757
Try to do something sensible when malloc fails instead
reimar
parents:
35231
diff
changeset
|
964 break; |
32456 | 965 } |
966 scale_table(0, 0, spu->width - 1, spu->scaled_width - 1, table_x); | |
967 scale_table(0, 0, spu->height - 1, spu->scaled_height - 1, table_y); | |
968 for (y = 0; y < spu->scaled_height; y++) | |
969 for (x = 0; x < spu->scaled_width; x++) | |
970 scale_image(x, y, table_x, table_y, spu); | |
971 free(table_x); | |
972 free(table_y); | |
973 break; | |
974 case 0: | |
975 /* no antialiasing */ | |
976 for (y = 0; y < spu->scaled_height; ++y) { | |
977 int unscaled_y = y * 0x100 / scaley; | |
978 int strides = spu->stride * unscaled_y; | |
979 int scaled_strides = spu->scaled_stride * y; | |
980 for (x = 0; x < spu->scaled_width; ++x) { | |
981 int unscaled_x = x * 0x100 / scalex; | |
982 spu->scaled_image[scaled_strides + x] = spu->image[strides + unscaled_x]; | |
983 spu->scaled_aimage[scaled_strides + x] = spu->aimage[strides + unscaled_x]; | |
984 } | |
985 } | |
986 break; | |
987 case 1: | |
988 { | |
989 /* Intermediate antialiasing. */ | |
990 for (y = 0; y < spu->scaled_height; ++y) { | |
991 const unsigned int unscaled_top = y * spu->orig_frame_height / dys; | |
992 unsigned int unscaled_bottom = (y + 1) * spu->orig_frame_height / dys; | |
993 if (unscaled_bottom >= spu->height) | |
994 unscaled_bottom = spu->height - 1; | |
995 for (x = 0; x < spu->scaled_width; ++x) { | |
996 const unsigned int unscaled_left = x * spu->orig_frame_width / dxs; | |
997 unsigned int unscaled_right = (x + 1) * spu->orig_frame_width / dxs; | |
998 unsigned int color = 0; | |
999 unsigned int alpha = 0; | |
1000 unsigned int walkx, walky; | |
1001 unsigned int base, tmp; | |
1002 if (unscaled_right >= spu->width) | |
1003 unscaled_right = spu->width - 1; | |
1004 for (walky = unscaled_top; walky <= unscaled_bottom; ++walky) | |
1005 for (walkx = unscaled_left; walkx <= unscaled_right; ++walkx) { | |
1006 base = walky * spu->stride + walkx; | |
1007 tmp = canon_alpha(spu->aimage[base]); | |
1008 alpha += tmp; | |
1009 color += tmp * spu->image[base]; | |
1010 } | |
1011 base = y * spu->scaled_stride + x; | |
1012 spu->scaled_image[base] = alpha ? color / alpha : 0; | |
1013 spu->scaled_aimage[base] = | |
1014 alpha * (1 + unscaled_bottom - unscaled_top) * (1 + unscaled_right - unscaled_left); | |
1015 /* spu->scaled_aimage[base] = | |
1016 alpha * dxs * dys / spu->orig_frame_width / spu->orig_frame_height; */ | |
1017 if (spu->scaled_aimage[base]) { | |
1018 spu->scaled_aimage[base] = 256 - spu->scaled_aimage[base]; | |
1019 if (spu->scaled_aimage[base] + spu->scaled_image[base] > 255) | |
1020 spu->scaled_image[base] = 256 - spu->scaled_aimage[base]; | |
1021 } | |
1022 } | |
1023 } | |
1024 } | |
1025 break; | |
1026 case 2: | |
1027 { | |
1028 /* Best antialiasing. Very slow. */ | |
1029 /* Any pixel (x, y) represents pixels from the original | |
1030 rectangular region comprised between the columns | |
1031 unscaled_y and unscaled_y + 0x100 / scaley and the rows | |
1032 unscaled_x and unscaled_x + 0x100 / scalex | |
1033 | |
1034 The original rectangular region that the scaled pixel | |
1035 represents is cut in 9 rectangular areas like this: | |
1036 | |
1037 +---+-----------------+---+ | |
1038 | 1 | 2 | 3 | | |
1039 +---+-----------------+---+ | |
1040 | | | | | |
1041 | 4 | 5 | 6 | | |
1042 | | | | | |
1043 +---+-----------------+---+ | |
1044 | 7 | 8 | 9 | | |
1045 +---+-----------------+---+ | |
1046 | |
1047 The width of the left column is at most one pixel and | |
1048 it is never null and its right column is at a pixel | |
1049 boundary. The height of the top row is at most one | |
1050 pixel it is never null and its bottom row is at a | |
1051 pixel boundary. The width and height of region 5 are | |
1052 integral values. The width of the right column is | |
1053 what remains and is less than one pixel. The height | |
1054 of the bottom row is what remains and is less than | |
1055 one pixel. | |
1056 | |
1057 The row above 1, 2, 3 is unscaled_y. The row between | |
1058 1, 2, 3 and 4, 5, 6 is top_low_row. The row between 4, | |
1059 5, 6 and 7, 8, 9 is (unsigned int)unscaled_y_bottom. | |
1060 The row beneath 7, 8, 9 is unscaled_y_bottom. | |
1061 | |
1062 The column left of 1, 4, 7 is unscaled_x. The column | |
1063 between 1, 4, 7 and 2, 5, 8 is left_right_column. The | |
1064 column between 2, 5, 8 and 3, 6, 9 is (unsigned | |
1065 int)unscaled_x_right. The column right of 3, 6, 9 is | |
1066 unscaled_x_right. */ | |
1067 const double inv_scalex = (double) 0x100 / scalex; | |
1068 const double inv_scaley = (double) 0x100 / scaley; | |
1069 for (y = 0; y < spu->scaled_height; ++y) { | |
1070 const double unscaled_y = y * inv_scaley; | |
1071 const double unscaled_y_bottom = unscaled_y + inv_scaley; | |
1072 const unsigned int top_low_row = FFMIN(unscaled_y_bottom, unscaled_y + 1.0); | |
1073 const double top = top_low_row - unscaled_y; | |
1074 const unsigned int height = unscaled_y_bottom > top_low_row | |
1075 ? (unsigned int) unscaled_y_bottom - top_low_row | |
1076 : 0; | |
1077 const double bottom = unscaled_y_bottom > top_low_row | |
1078 ? unscaled_y_bottom - floor(unscaled_y_bottom) | |
1079 : 0.0; | |
1080 for (x = 0; x < spu->scaled_width; ++x) { | |
1081 const double unscaled_x = x * inv_scalex; | |
1082 const double unscaled_x_right = unscaled_x + inv_scalex; | |
1083 const unsigned int left_right_column = FFMIN(unscaled_x_right, unscaled_x + 1.0); | |
1084 const double left = left_right_column - unscaled_x; | |
1085 const unsigned int width = unscaled_x_right > left_right_column | |
1086 ? (unsigned int) unscaled_x_right - left_right_column | |
1087 : 0; | |
1088 const double right = unscaled_x_right > left_right_column | |
1089 ? unscaled_x_right - floor(unscaled_x_right) | |
1090 : 0.0; | |
1091 double color = 0.0; | |
1092 double alpha = 0.0; | |
1093 double tmp; | |
1094 unsigned int base; | |
1095 /* Now use these informations to compute a good alpha, | |
1096 and lightness. The sum is on each of the 9 | |
1097 region's surface and alpha and lightness. | |
1098 | |
1099 transformed alpha = sum(surface * alpha) / sum(surface) | |
1100 transformed color = sum(surface * alpha * color) / sum(surface * alpha) | |
1101 */ | |
1102 /* 1: top left part */ | |
1103 base = spu->stride * (unsigned int) unscaled_y; | |
1104 tmp = left * top * canon_alpha(spu->aimage[base + (unsigned int) unscaled_x]); | |
1105 alpha += tmp; | |
1106 color += tmp * spu->image[base + (unsigned int) unscaled_x]; | |
1107 /* 2: top center part */ | |
1108 if (width > 0) { | |
1109 unsigned int walkx; | |
1110 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) { | |
1111 base = spu->stride * (unsigned int) unscaled_y + walkx; | |
1112 tmp = /* 1.0 * */ top * canon_alpha(spu->aimage[base]); | |
1113 alpha += tmp; | |
1114 color += tmp * spu->image[base]; | |
1115 } | |
1116 } | |
1117 /* 3: top right part */ | |
1118 if (right > 0.0) { | |
1119 base = spu->stride * (unsigned int) unscaled_y + (unsigned int) unscaled_x_right; | |
1120 tmp = right * top * canon_alpha(spu->aimage[base]); | |
1121 alpha += tmp; | |
1122 color += tmp * spu->image[base]; | |
1123 } | |
1124 /* 4: center left part */ | |
1125 if (height > 0) { | |
1126 unsigned int walky; | |
1127 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) { | |
1128 base = spu->stride * walky + (unsigned int) unscaled_x; | |
1129 tmp = left /* * 1.0 */ * canon_alpha(spu->aimage[base]); | |
1130 alpha += tmp; | |
1131 color += tmp * spu->image[base]; | |
1132 } | |
1133 } | |
1134 /* 5: center part */ | |
1135 if (width > 0 && height > 0) { | |
1136 unsigned int walky; | |
1137 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) { | |
1138 unsigned int walkx; | |
1139 base = spu->stride * walky; | |
1140 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) { | |
1141 tmp = /* 1.0 * 1.0 * */ canon_alpha(spu->aimage[base + walkx]); | |
1142 alpha += tmp; | |
1143 color += tmp * spu->image[base + walkx]; | |
1144 } | |
1145 } | |
1146 } | |
1147 /* 6: center right part */ | |
1148 if (right > 0.0 && height > 0) { | |
1149 unsigned int walky; | |
1150 for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) { | |
1151 base = spu->stride * walky + (unsigned int) unscaled_x_right; | |
1152 tmp = right /* * 1.0 */ * canon_alpha(spu->aimage[base]); | |
1153 alpha += tmp; | |
1154 color += tmp * spu->image[base]; | |
1155 } | |
1156 } | |
1157 /* 7: bottom left part */ | |
1158 if (bottom > 0.0) { | |
1159 base = spu->stride * (unsigned int) unscaled_y_bottom + (unsigned int) unscaled_x; | |
1160 tmp = left * bottom * canon_alpha(spu->aimage[base]); | |
1161 alpha += tmp; | |
1162 color += tmp * spu->image[base]; | |
1163 } | |
1164 /* 8: bottom center part */ | |
1165 if (width > 0 && bottom > 0.0) { | |
1166 unsigned int walkx; | |
1167 base = spu->stride * (unsigned int) unscaled_y_bottom; | |
1168 for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) { | |
1169 tmp = /* 1.0 * */ bottom * canon_alpha(spu->aimage[base + walkx]); | |
1170 alpha += tmp; | |
1171 color += tmp * spu->image[base + walkx]; | |
1172 } | |
1173 } | |
1174 /* 9: bottom right part */ | |
1175 if (right > 0.0 && bottom > 0.0) { | |
1176 base = spu->stride * (unsigned int) unscaled_y_bottom + (unsigned int) unscaled_x_right; | |
1177 tmp = right * bottom * canon_alpha(spu->aimage[base]); | |
1178 alpha += tmp; | |
1179 color += tmp * spu->image[base]; | |
1180 } | |
1181 /* Finally mix these transparency and brightness information suitably */ | |
1182 base = spu->scaled_stride * y + x; | |
1183 spu->scaled_image[base] = alpha > 0 ? color / alpha : 0; | |
1184 spu->scaled_aimage[base] = alpha * scalex * scaley / 0x10000; | |
1185 if (spu->scaled_aimage[base]) { | |
1186 spu->scaled_aimage[base] = 256 - spu->scaled_aimage[base]; | |
1187 if (spu->scaled_aimage[base] + spu->scaled_image[base] > 255) | |
1188 spu->scaled_image[base] = 256 - spu->scaled_aimage[base]; | |
1189 } | |
1190 } | |
1191 } | |
1192 } | |
1193 } | |
1194 nothing_to_do: | |
1195 /* Kludge: draw_alpha needs width multiple of 8. */ | |
1196 if (spu->scaled_width < spu->scaled_stride) | |
1197 for (y = 0; y < spu->scaled_height; ++y) { | |
1198 memset(spu->scaled_aimage + y * spu->scaled_stride + spu->scaled_width, 0, | |
1199 spu->scaled_stride - spu->scaled_width); | |
1200 } | |
1201 spu->scaled_frame_width = dxs; | |
1202 spu->scaled_frame_height = dys; | |
1203 } | |
1204 } | |
1205 if (spu->scaled_image){ | |
1206 switch (spu_alignment) { | |
1207 case 0: | |
1208 spu->scaled_start_row = dys*sub_pos/100; | |
1209 if (spu->scaled_start_row + spu->scaled_height > dys) | |
1210 spu->scaled_start_row = dys - spu->scaled_height; | |
1211 break; | |
1212 case 1: | |
1213 spu->scaled_start_row = dys*sub_pos/100 - spu->scaled_height/2; | |
1214 if (sub_pos >= 50 && spu->scaled_start_row + spu->scaled_height > dys) | |
1215 spu->scaled_start_row = dys - spu->scaled_height; | |
1216 break; | |
1217 case 2: | |
1218 spu->scaled_start_row = dys*sub_pos/100 - spu->scaled_height; | |
1219 break; | |
1220 } | |
1221 draw_alpha(spu->scaled_start_col, spu->scaled_start_row, spu->scaled_width, spu->scaled_height, | |
1222 spu->scaled_image, spu->scaled_aimage, spu->scaled_stride); | |
1223 spu->spu_changed = 0; | |
1224 } | |
1225 } | |
1226 } | |
1227 else | |
1228 { | |
1229 mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPU not displayed: start_pts=%d end_pts=%d now_pts=%d\n", | |
1230 spu->start_pts, spu->end_pts, spu->now_pts); | |
1231 } | |
1232 } | |
1233 | |
1234 void spudec_update_palette(void * this, unsigned int *palette) | |
1235 { | |
1236 spudec_handle_t *spu = this; | |
1237 if (spu && palette) { | |
1238 memcpy(spu->global_palette, palette, sizeof(spu->global_palette)); | |
1239 if(spu->hw_spu) | |
1240 spu->hw_spu->control(VOCTRL_SET_SPU_PALETTE,spu->global_palette); | |
1241 } | |
1242 } | |
1243 | |
1244 void spudec_set_font_factor(void * this, double factor) | |
1245 { | |
1246 spudec_handle_t *spu = this; | |
1247 spu->font_start_level = (int)(0xF0-(0xE0*factor)); | |
1248 } | |
1249 | |
1250 static void spudec_parse_extradata(spudec_handle_t *this, | |
1251 uint8_t *extradata, int extradata_len) | |
1252 { | |
1253 uint8_t *buffer, *ptr; | |
1254 unsigned int *pal = this->global_palette, *cuspal = this->cuspal; | |
1255 unsigned int tridx; | |
1256 int i; | |
1257 | |
1258 if (extradata_len == 16*4) { | |
1259 for (i=0; i<16; i++) | |
1260 pal[i] = AV_RB32(extradata + i*4); | |
1261 this->auto_palette = 0; | |
1262 return; | |
1263 } | |
1264 | |
1265 if (!(ptr = buffer = malloc(extradata_len+1))) | |
1266 return; | |
1267 memcpy(buffer, extradata, extradata_len); | |
1268 buffer[extradata_len] = 0; | |
1269 | |
1270 do { | |
1271 if (*ptr == '#') | |
1272 continue; | |
1273 if (!strncmp(ptr, "size: ", 6)) | |
1274 sscanf(ptr + 6, "%dx%d", &this->orig_frame_width, &this->orig_frame_height); | |
1275 if (!strncmp(ptr, "palette: ", 9) && | |
1276 sscanf(ptr + 9, "%x, %x, %x, %x, %x, %x, %x, %x, " | |
1277 "%x, %x, %x, %x, %x, %x, %x, %x", | |
1278 &pal[ 0], &pal[ 1], &pal[ 2], &pal[ 3], | |
1279 &pal[ 4], &pal[ 5], &pal[ 6], &pal[ 7], | |
1280 &pal[ 8], &pal[ 9], &pal[10], &pal[11], | |
1281 &pal[12], &pal[13], &pal[14], &pal[15]) == 16) { | |
1282 for (i=0; i<16; i++) | |
1283 pal[i] = vobsub_palette_to_yuv(pal[i]); | |
1284 this->auto_palette = 0; | |
1285 } | |
1286 if (!strncasecmp(ptr, "forced subs: on", 15)) | |
1287 this->forced_subs_only = 1; | |
1288 if (!strncmp(ptr, "custom colors: ON, tridx: ", 26) && | |
1289 sscanf(ptr + 26, "%x, colors: %x, %x, %x, %x", | |
1290 &tridx, cuspal+0, cuspal+1, cuspal+2, cuspal+3) == 5) { | |
1291 for (i=0; i<4; i++) { | |
1292 cuspal[i] = vobsub_rgb_to_yuv(cuspal[i]); | |
1293 if (tridx & (1 << (12-4*i))) | |
1294 cuspal[i] |= 1 << 31; | |
1295 } | |
1296 this->custom = 1; | |
1297 } | |
1298 } while ((ptr=strchr(ptr,'\n')) && *++ptr); | |
1299 | |
1300 free(buffer); | |
1301 } | |
1302 | |
1303 void *spudec_new_scaled(unsigned int *palette, unsigned int frame_width, unsigned int frame_height, uint8_t *extradata, int extradata_len) | |
1304 { | |
1305 spudec_handle_t *this = calloc(1, sizeof(spudec_handle_t)); | |
1306 if (this){ | |
1307 this->orig_frame_height = frame_height; | |
1308 this->orig_frame_width = frame_width; | |
1309 // set up palette: | |
1310 if (palette) | |
1311 memcpy(this->global_palette, palette, sizeof(this->global_palette)); | |
1312 else | |
1313 this->auto_palette = 1; | |
1314 if (extradata) | |
1315 spudec_parse_extradata(this, extradata, extradata_len); | |
1316 /* XXX Although the video frame is some size, the SPU frame is | |
1317 always maximum size i.e. 720 wide and 576 or 480 high */ | |
1318 // For HD files in MKV the VobSub resolution can be higher though, | |
1319 // see largeres_vobsub.mkv | |
1320 if (this->orig_frame_width <= 720 && this->orig_frame_height <= 576) { | |
1321 this->orig_frame_width = 720; | |
1322 if (this->orig_frame_height == 480 || this->orig_frame_height == 240) | |
1323 this->orig_frame_height = 480; | |
1324 else | |
1325 this->orig_frame_height = 576; | |
1326 } | |
1327 } | |
1328 else | |
1329 mp_msg(MSGT_SPUDEC,MSGL_FATAL, "FATAL: spudec_init: calloc"); | |
1330 return this; | |
1331 } | |
1332 | |
1333 void *spudec_new(unsigned int *palette) | |
1334 { | |
1335 return spudec_new_scaled(palette, 0, 0, NULL, 0); | |
1336 } | |
1337 | |
1338 void spudec_free(void *this) | |
1339 { | |
1340 spudec_handle_t *spu = this; | |
1341 if (spu) { | |
1342 while (spu->queue_head) | |
1343 spudec_free_packet(spudec_dequeue_packet(spu)); | |
1344 free(spu->packet); | |
1345 spu->packet = NULL; | |
1346 free(spu->scaled_image); | |
1347 spu->scaled_image = NULL; | |
1348 free(spu->image); | |
1349 spu->image = NULL; | |
1350 spu->aimage = NULL; | |
1351 free(spu->pal_image); | |
1352 spu->pal_image = NULL; | |
1353 spu->image_size = 0; | |
1354 spu->pal_width = spu->pal_height = 0; | |
1355 free(spu); | |
1356 } | |
1357 } | |
1358 | |
1359 void spudec_set_hw_spu(void *this, const vo_functions_t *hw_spu) | |
1360 { | |
1361 spudec_handle_t *spu = this; | |
1362 if (!spu) | |
1363 return; | |
1364 spu->hw_spu = hw_spu; | |
1365 hw_spu->control(VOCTRL_SET_SPU_PALETTE,spu->global_palette); | |
1366 } | |
1367 | |
1368 #define MP_NOPTS_VALUE (-1LL<<63) //both int64_t and double should be able to represent this exactly | |
1369 | |
34784 | 1370 packet_t *spudec_packet_create(int x, int y, int w, int h) |
32456 | 1371 { |
1372 packet_t *packet; | |
1373 int stride = (w + 7) & ~7; | |
1374 if ((unsigned)w >= 0x8000 || (unsigned)h > 0x4000) | |
34784 | 1375 return NULL; |
32456 | 1376 packet = calloc(1, sizeof(packet_t)); |
1377 packet->is_decoded = 1; | |
1378 packet->width = w; | |
1379 packet->height = h; | |
1380 packet->stride = stride; | |
1381 packet->start_col = x; | |
1382 packet->start_row = y; | |
1383 packet->data_len = 2 * stride * h; | |
1384 if (packet->data_len) { // size 0 is a special "clear" packet | |
34784 | 1385 packet->packet = malloc(packet->data_len); |
1386 if (!packet->packet) { | |
1387 free(packet); | |
1388 packet = NULL; | |
1389 } | |
32456 | 1390 } |
34784 | 1391 return packet; |
1392 } | |
1393 | |
1394 void spudec_packet_clear(packet_t *packet) | |
1395 { | |
1396 /* clear alpha and value, as value is premultiplied */ | |
1397 memset(packet->packet, 0, packet->data_len); | |
1398 } | |
1399 | |
1400 void spudec_packet_fill(packet_t *packet, | |
1401 const uint8_t *pal_img, int pal_stride, | |
1402 const void *palette, | |
1403 int x, int y, int w, int h) | |
1404 { | |
1405 const uint32_t *pal = palette; | |
1406 uint8_t *img = packet->packet + x + y * packet->stride; | |
1407 uint8_t *aimg = img + packet->stride * packet->height; | |
1408 int i; | |
1409 uint16_t g8a8_pal[256]; | |
1410 | |
1411 for (i = 0; i < 256; i++) { | |
1412 uint32_t pixel = pal[i]; | |
1413 int alpha = pixel >> 24; | |
1414 int gray = (((pixel & 0x000000ff) >> 0) + | |
1415 ((pixel & 0x0000ff00) >> 7) + | |
1416 ((pixel & 0x00ff0000) >> 16)) >> 2; | |
1417 gray = FFMIN(gray, alpha); | |
1418 g8a8_pal[i] = (-alpha << 8) | gray; | |
1419 } | |
1420 pal2gray_alpha(g8a8_pal, pal_img, pal_stride, | |
1421 img, aimg, packet->stride, w, h); | |
1422 } | |
1423 | |
1424 void spudec_packet_send(void *spu, packet_t *packet, double pts, double endpts) | |
1425 { | |
32456 | 1426 packet->start_pts = 0; |
1427 packet->end_pts = 0x7fffffff; | |
1428 if (pts != MP_NOPTS_VALUE) | |
1429 packet->start_pts = pts * 90000; | |
1430 if (endpts != MP_NOPTS_VALUE) | |
1431 packet->end_pts = endpts * 90000; | |
1432 spudec_queue_packet(spu, packet); | |
1433 } | |
34784 | 1434 |
1435 /** | |
1436 * palette must contain at least 256 32-bit entries, otherwise crashes | |
1437 * are possible | |
1438 */ | |
1439 void spudec_set_paletted(void *spu, const uint8_t *pal_img, int pal_stride, | |
1440 const void *palette, | |
1441 int x, int y, int w, int h, | |
1442 double pts, double endpts) | |
1443 { | |
1444 packet_t *packet = spudec_packet_create(x, y, w, h); | |
1445 if (!packet) | |
1446 return; | |
1447 if (packet->data_len) // size 0 is a special "clear" packet | |
1448 spudec_packet_fill(packet, pal_img, pal_stride, palette, 0, 0, w, h); | |
1449 spudec_packet_send(spu, packet, pts, endpts); | |
1450 } |