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