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