1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
24 | |
25 | |
26 | |
27 | |
28 | |
29 | |
30 | #include "config.h" |
31 | |
32 | #include "compat.h" |
33 | |
34 | #include "subglobals.h" |
35 | #include "subrender.h" |
36 | #include "subfont.h" |
37 | |
38 | #define NEW_SPLITTING |
39 | |
40 | typedef struct mp_osd_bbox_s |
41 | { |
42 | int x1, y1; |
43 | int x2, y2; |
44 | } mp_osd_bbox_t; |
45 | |
46 | #define MAX_UCS1600 1600 |
47 | #define MAX_UCSLINES16 16 |
48 | |
49 | typedef struct |
50 | { |
51 | int topy; |
52 | mp_osd_bbox_t bbox; |
53 | union |
54 | { |
55 | struct |
56 | { |
57 | int utbl[MAX_UCS1600 + 1]; |
58 | int xtbl[MAX_UCSLINES16]; |
59 | int lines; |
60 | } subtitle; |
61 | } params; |
62 | int stride; |
63 | int allocated; |
64 | unsigned char *bitmap_buffer; |
65 | } mp_osd_obj_t; |
66 | |
67 | static int sub_pos=100; |
68 | |
69 | |
70 | int sub_justify=1; |
71 | int sub_left_margin=60; |
72 | int sub_right_margin=60; |
73 | int sub_bottom_margin=30; |
74 | int sub_top_margin=20; |
75 | int h_sub_alignment = H_SUB_ALIGNMENT_LEFT; |
76 | int v_sub_alignment = V_SUB_ALIGNMENT_BOTTOM; |
77 | |
78 | float movie_fps = 0.0; |
79 | int movie_width = 0; |
80 | int movie_height = 0; |
81 | |
82 | unsigned char *textsub_image_buffer; |
83 | size_t textsub_image_buffer_size; |
84 | |
85 | |
86 | int sub_max_chars; |
87 | int sub_max_lines; |
88 | int sub_max_font_height; |
89 | int sub_max_bottom_font_height; |
90 | |
91 | static mp_osd_obj_t* vo_osd = NULL((void*)0); |
92 | |
93 | static inline void vo_draw_subtitle_line |
94 | ( |
95 | int w, |
96 | int h, |
97 | const unsigned char * srcbase, |
98 | int srcstride, |
99 | unsigned char * dstbase, |
100 | int dststride |
101 | ) |
102 | |
103 | |
104 | { |
105 | int y; |
106 | for (y = 0; y < h; y++) |
107 | { |
108 | const register unsigned char * src = srcbase; |
109 | register unsigned char * dst = dstbase; |
110 | register int x; |
111 | for (x = 0; x < w; x++) |
112 | { |
113 | *dst++ = *src++; |
114 | *dst++ = *src++; |
115 | *dst++ = *src++; |
116 | *dst++ = *src++; |
117 | } |
118 | srcbase += srcstride; |
119 | dstbase += dststride; |
120 | } |
121 | } |
122 | |
123 | static void draw_glyph |
124 | ( |
125 | mp_osd_obj_t * obj, |
126 | int x0, |
127 | int y0, |
128 | int w, |
129 | int h, |
130 | const unsigned char * src, |
131 | const colorspec * srccolors, |
132 | int stride |
133 | ) |
134 | |
135 | |
136 | { |
137 | int dststride = obj->stride; |
138 | int dstskip = obj->stride - w * 4; |
139 | int srcskip = stride - w; |
140 | int i, j; |
141 | unsigned char * bdst = |
142 | obj->bitmap_buffer |
143 | + |
144 | (y0 - obj->bbox.y1) * dststride |
145 | + |
146 | (x0 - obj->bbox.x1) * 4; |
147 | const unsigned char * bsrc = src; |
148 | |
149 | if (x0 < obj->bbox.x1 || x0 + w > obj->bbox.x2 || y0 < obj->bbox.y1 || y0 + h > obj->bbox.y2) |
150 | { |
151 | fprintf |
152 | ( |
153 | stderrstderr, |
154 | "WARN: Text out of range: bbox [%d %d %d %d], txt [%d %d %d %d]\n", |
155 | obj->bbox.x1, obj->bbox.x2, obj->bbox.y1, obj->bbox.y2, |
156 | x0, x0 + w, y0, y0 + h |
157 | ); |
158 | return; |
159 | } |
160 | for (i = 0; i < h; i++) |
161 | { |
162 | for (j = 0; j < w; j++) |
163 | { |
164 | const colorspec srccolor = srccolors[*bsrc++]; |
165 | if (srccolor.a != 0) |
166 | { |
167 | *bdst++ = srccolor.r; |
168 | *bdst++ = srccolor.g; |
169 | *bdst++ = srccolor.b; |
170 | *bdst++ = srccolor.a; |
171 | } |
172 | else |
173 | { |
174 | bdst += 4; |
175 | } |
176 | } |
177 | bdst += dstskip; |
178 | bsrc += srcskip; |
179 | } |
180 | } |
181 | |
182 | static void alloc_buf(mp_osd_obj_t * obj) |
183 | |
184 | { |
185 | int len; |
186 | |
187 | if (obj->bbox.x2 < obj->bbox.x1) |
188 | obj->bbox.x2 = obj->bbox.x1; |
189 | if (obj->bbox.y2 < obj->bbox.y1) |
190 | obj->bbox.y2 = obj->bbox.y1; |
191 | obj->stride = (obj->bbox.x2 - obj->bbox.x1) * 4 + 7 & ~7; |
192 | len = obj->stride * (obj->bbox.y2 - obj->bbox.y1); |
193 | if (obj->allocated < len) |
194 | { |
195 | |
196 | obj->allocated = len; |
197 | free(obj->bitmap_buffer); |
198 | obj->bitmap_buffer = (unsigned char *)malloc(len); |
199 | } |
200 | memset(obj->bitmap_buffer, 0, len); |
201 | } |
202 | |
203 | inline static void vo_update_text_sub |
204 | ( |
205 | mp_osd_obj_t * obj, |
206 | const subtitle_elt * the_sub |
207 | ) |
208 | |
209 | |
210 | { |
211 | |
212 | |
213 | |
214 | struct osd_text_word |
215 | { |
216 | int osd_kerning; |
217 | int osd_length; |
218 | int text_length; |
219 | int *text; |
220 | struct osd_text_word *prev, *next; |
221 | }; |
222 | struct osd_text_line |
223 | { |
224 | int linewidth; |
225 | struct osd_text_word *words; |
226 | struct osd_text_line *prev, *next; |
227 | }; |
228 | int linedone, linesleft; |
229 | bool_Bool warn_overlong_word; |
230 | int textlen, sub_totallen; |
231 | |
232 | const int widthlimit = movie_width - sub_right_margin - sub_left_margin; |
233 | |
234 | |
235 | int xmin = widthlimit, xmax = 0; |
236 | int max_line_height; |
237 | int xtblc, utblc; |
238 | |
239 | if (!the_sub || !vo_font) |
| 1 | Assuming 'the_sub' is non-null | |
|
| 2 | | Assuming 'vo_font' is non-null | |
|
| |
240 | { |
241 | return; |
242 | } |
243 | obj->bbox.y2 = obj->topy = movie_height - sub_bottom_margin; |
244 | obj->params.subtitle.lines = 0; |
245 | |
246 | |
247 | linedone = sub_totallen = 0; |
248 | max_line_height = vo_font->height; |
249 | |
250 | linesleft = the_sub->lines; |
251 | { |
252 | struct osd_text_line |
253 | |
254 | *otp_sub = NULL((void*)0), |
255 | *otp_sub_last = NULL((void*)0); |
256 | int *wordbuf = NULL((void*)0); |
257 | while (linesleft) |
| 4 | | Loop condition is true. Entering loop body | |
|
258 | { |
259 | struct osd_text_word |
260 | *osl, |
261 | *osl_tail; |
262 | int chindex, prevch, wordlen; |
263 | const unsigned char *text; |
264 | int xsize = -vo_font->charspace; |
265 | |
266 | linesleft--; |
267 | text = (const unsigned char *)the_sub->text[linedone++]; |
268 | textlen = strlen((const char *)text); |
269 | wordlen = 0; |
270 | wordbuf = (int *)realloc(wordbuf, textlen * sizeof(int)); |
271 | prevch = -1; |
272 | osl = NULL((void*)0); |
273 | osl_tail = NULL((void*)0); |
274 | warn_overlong_word = true1; |
275 | |
276 | chindex = 0; |
277 | for (;;) |
| 5 | | Loop condition is true. Entering loop body | |
|
278 | { |
279 | int curch; |
280 | if (chindex < textlen) |
| 6 | | Assuming 'chindex' is >= 'textlen' | |
|
| |
281 | { |
282 | curch = text[chindex]; |
283 | if (curch >= 0x80) |
284 | { |
285 | |
286 | if ((curch & 0xe0) == 0xc0) |
287 | curch = (curch & 0x1f) << 6 | (text[++chindex] & 0x3f); |
288 | else if ((curch & 0xf0) == 0xe0) |
289 | { |
290 | curch = (((curch & 0x0f) << 6) | (text[++chindex] & 0x3f)) << 6; |
291 | curch |= text[++chindex] & 0x3f; |
292 | } |
293 | } |
294 | if (sub_totallen == MAX_UCS1600) |
295 | { |
296 | textlen = chindex; |
297 | fprintf(stderrstderr, "WARN: MAX_UCS exceeded!\n"); |
298 | } |
299 | if (!curch) |
300 | curch++; |
301 | render_one_glyph(vo_font, curch); |
302 | } |
303 | if (chindex >= textlen || curch == ' ') |
304 | { |
305 | |
306 | struct osd_text_word * const newelt = |
307 | (struct osd_text_word *)calloc(1, sizeof(struct osd_text_word)); |
308 | int counter; |
309 | if (osl == NULL((void*)0)) |
| |
310 | { |
311 | |
312 | osl = newelt; |
313 | } |
314 | else |
315 | { |
316 | |
317 | newelt->prev = osl_tail; |
318 | osl_tail->next = newelt; |
319 | newelt->osd_kerning = vo_font->charspace + vo_font->width[' ']; |
320 | } |
321 | osl_tail = newelt; |
322 | newelt->osd_length = xsize; |
323 | newelt->text_length = wordlen; |
324 | newelt->text = (int *)malloc(wordlen * sizeof(int)); |
| 9 | | Call to 'malloc' has an allocation size of 0 bytes |
|
325 | for (counter = 0; counter < wordlen; ++counter) |
326 | newelt->text[counter] = wordbuf[counter]; |
327 | wordlen = 0; |
328 | if (chindex == textlen) |
329 | break; |
330 | xsize = 0; |
331 | prevch = curch; |
332 | } |
333 | else |
334 | { |
335 | |
336 | const int delta_xsize = |
337 | vo_font->width[curch] |
338 | + |
339 | vo_font->charspace |
340 | + |
341 | kerning(vo_font, prevch, curch); |
342 | |
343 | if (xsize + delta_xsize <= widthlimit) |
344 | { |
345 | |
346 | if (!warn_overlong_word) |
347 | warn_overlong_word = true1; |
348 | prevch = curch; |
349 | wordbuf[wordlen++] = curch; |
350 | xsize += delta_xsize; |
351 | if (!suboverlap_enabled) |
352 | { |
353 | |
354 | const int font = vo_font->font[curch]; |
355 | if (font >= 0 && vo_font->pic_b[font]->h > max_line_height) |
356 | { |
357 | max_line_height = vo_font->pic_b[font]->h; |
358 | } |
359 | } |
360 | } |
361 | else |
362 | { |
363 | |
364 | if (warn_overlong_word) |
365 | { |
366 | fprintf(stderrstderr, "WARN: Subtitle word '%s' too long!\n", text); |
367 | warn_overlong_word = false0; |
368 | } |
369 | } |
370 | } |
371 | ++chindex; |
372 | } |
373 | |
374 | if (osl != NULL((void*)0)) |
375 | { |
376 | |
377 | |
378 | int linewidth = 0, linewidth_variation = 0; |
379 | struct osd_text_line *lastnewelt; |
380 | struct osd_text_word *curword; |
381 | struct osd_text_line *otp_new; |
382 | |
383 | otp_new = lastnewelt = (struct osd_text_line *)calloc(1, sizeof(struct osd_text_line)); |
384 | lastnewelt->words = osl; |
385 | curword = lastnewelt->words; |
386 | for (;;) |
387 | { |
388 | while |
389 | ( |
390 | curword != NULL((void*)0) |
391 | && |
392 | linewidth + curword->osd_kerning + curword->osd_length <= widthlimit |
393 | ) |
394 | { |
395 | |
396 | linewidth += curword->osd_kerning + curword->osd_length; |
397 | curword = curword->next; |
398 | } |
399 | if |
400 | ( |
401 | curword != NULL((void*)0) |
402 | && |
403 | curword != lastnewelt->words |
404 | |
405 | ) |
406 | { |
407 | |
408 | struct osd_text_line * const nextnewelt = |
409 | (struct osd_text_line *)calloc(1, sizeof(struct osd_text_line)); |
410 | lastnewelt->linewidth = linewidth; |
411 | lastnewelt->next = nextnewelt; |
412 | nextnewelt->prev = lastnewelt; |
413 | lastnewelt = nextnewelt; |
414 | lastnewelt->words = curword; |
415 | linewidth = -2 * vo_font->charspace - vo_font->width[' ']; |
416 | } |
417 | else |
418 | { |
419 | lastnewelt->linewidth = linewidth; |
420 | break; |
421 | } |
422 | } |
423 | #ifdef NEW_SPLITTING |
424 | |
425 | |
426 | |
427 | |
428 | { |
429 | struct osd_text_line *tmp_otp; |
430 | for (tmp_otp = otp_new; tmp_otp->next != NULL((void*)0); tmp_otp = tmp_otp->next) |
431 | { |
432 | const struct osd_text_line * pmt = tmp_otp->next; |
433 | while (pmt != NULL((void*)0)) |
434 | { |
435 | linewidth_variation += abs(tmp_otp->linewidth - pmt->linewidth); |
436 | pmt = pmt->next; |
437 | } |
438 | } |
439 | } |
440 | if (otp_new->next != NULL((void*)0)) |
441 | { |
442 | |
443 | |
444 | for (;;) |
445 | |
446 | |
447 | { |
448 | struct osd_text_line *this_display_line; |
449 | bool_Bool exit1 = true1; |
450 | struct osd_text_line *rebalance_line = NULL((void*)0); |
451 | |
452 | |
453 | for |
454 | ( |
455 | this_display_line = otp_new; |
456 | this_display_line->next != NULL((void*)0); |
457 | this_display_line = this_display_line->next |
458 | ) |
459 | { |
460 | struct osd_text_line *next_display_line = this_display_line->next; |
461 | struct osd_text_word *prev_word; |
462 | for |
463 | ( |
464 | prev_word = this_display_line->words; |
465 | prev_word->next != next_display_line->words; |
466 | prev_word = prev_word->next |
467 | ) |
468 | ; |
469 | |
470 | |
471 | if |
472 | ( |
473 | next_display_line->linewidth |
474 | + |
475 | prev_word->osd_length |
476 | + |
477 | next_display_line->words->osd_kerning |
478 | <= |
479 | widthlimit |
480 | ) |
481 | { |
482 | |
483 | |
484 | struct osd_text_line *that_display_line; |
485 | int new_variation; |
486 | int prev_line_width, cur_line_width; |
487 | prev_line_width = this_display_line->linewidth; |
488 | cur_line_width = next_display_line->linewidth; |
489 | |
490 | this_display_line->linewidth = |
491 | prev_line_width |
492 | - |
493 | prev_word->osd_length |
494 | - |
495 | prev_word->osd_kerning; |
496 | next_display_line->linewidth = |
497 | cur_line_width |
498 | + |
499 | prev_word->osd_length |
500 | + |
501 | next_display_line->words->osd_kerning; |
502 | new_variation = 0; |
503 | for |
504 | ( |
505 | that_display_line = otp_new; |
506 | that_display_line->next != NULL((void*)0); |
507 | that_display_line = that_display_line->next |
508 | ) |
509 | { |
510 | next_display_line = that_display_line->next; |
511 | while (next_display_line != NULL((void*)0)) |
512 | { |
513 | new_variation += |
514 | abs |
515 | ( |
516 | that_display_line->linewidth |
517 | - |
518 | next_display_line->linewidth |
519 | ); |
520 | next_display_line = next_display_line->next; |
521 | } |
522 | } |
523 | if (new_variation < linewidth_variation) |
524 | { |
525 | |
526 | linewidth_variation = new_variation; |
527 | rebalance_line = this_display_line; |
528 | exit1 = false0; |
529 | } |
530 | |
531 | this_display_line->linewidth = prev_line_width; |
532 | this_display_line->next->linewidth = cur_line_width; |
533 | } |
534 | } |
535 | |
536 | if (exit1) |
537 | break; |
538 | { |
539 | |
540 | struct osd_text_word *word_to_move; |
541 | struct osd_text_line *next_display_line; |
542 | this_display_line = rebalance_line; |
543 | next_display_line = this_display_line->next; |
544 | for |
545 | ( |
546 | word_to_move = this_display_line->words; |
547 | word_to_move->next != next_display_line->words; |
548 | word_to_move = word_to_move->next |
549 | ) |
550 | ; |
551 | |
552 | |
553 | |
554 | this_display_line->linewidth -= |
555 | word_to_move->osd_length + word_to_move->osd_kerning; |
556 | next_display_line->linewidth += |
557 | word_to_move->osd_length + next_display_line->words->osd_kerning; |
558 | next_display_line->words = word_to_move; |
559 | } |
560 | } |
561 | } |
562 | #endif |
563 | |
564 | if (otp_sub == NULL((void*)0)) |
565 | { |
566 | otp_sub = otp_new; |
567 | for |
568 | ( |
569 | otp_sub_last = otp_sub; |
570 | otp_sub_last->next != NULL((void*)0); |
571 | otp_sub_last = otp_sub_last->next |
572 | ) |
573 | ; |
574 | } |
575 | else |
576 | { |
577 | |
578 | struct osd_text_word * ott_last = otp_sub->words; |
579 | while (ott_last->next != NULL((void*)0)) |
580 | ott_last = ott_last->next; |
581 | ott_last->next = otp_new->words; |
582 | otp_new->words->prev = ott_last; |
583 | |
584 | otp_sub_last->next = otp_new; |
585 | otp_new->prev = otp_sub_last; |
586 | do |
587 | otp_sub_last = otp_sub_last->next; |
588 | while (otp_sub_last->next != NULL((void*)0)); |
589 | } |
590 | } |
591 | } |
592 | free(wordbuf); |
593 | |
594 | xtblc = 0; |
595 | utblc = 0; |
596 | obj->topy = movie_height - sub_bottom_margin; |
597 | obj->params.subtitle.lines = 0; |
598 | { |
599 | |
600 | |
601 | struct osd_text_line *this_display_line; |
602 | for |
603 | ( |
604 | this_display_line = otp_sub; |
605 | this_display_line != NULL((void*)0); |
606 | this_display_line = this_display_line->next |
607 | ) |
608 | { |
609 | struct osd_text_word *this_word, *next_line_words; |
610 | int xsize; |
611 | if (obj->params.subtitle.lines++ >= MAX_UCSLINES16) |
612 | { |
613 | fprintf(stderrstderr, "WARN: max_ucs_lines\n"); |
614 | break; |
615 | } |
616 | if (max_line_height + sub_top_margin > obj->topy) |
617 | { |
618 | obj->topy += vo_font->height; |
619 | fprintf(stderrstderr, "WARN: Out of screen at Y: %d\n", obj->topy); |
620 | obj->params.subtitle.lines -= 1; |
621 | |
622 | break; |
623 | } |
624 | xsize = this_display_line->linewidth; |
625 | obj->params.subtitle.xtbl[xtblc++] = (widthlimit - xsize) / 2 + sub_left_margin; |
626 | if (xmin > (widthlimit - xsize) / 2 + sub_left_margin) |
627 | xmin = (widthlimit - xsize) / 2 + sub_left_margin; |
628 | if (xmax < (widthlimit + xsize) / 2 + sub_left_margin) |
629 | xmax = (widthlimit + xsize) / 2 + sub_left_margin; |
630 | |
631 | next_line_words = |
632 | this_display_line->next == NULL((void*)0) ? |
633 | NULL((void*)0) |
634 | : |
635 | this_display_line->next->words; |
636 | for |
637 | ( |
638 | this_word = this_display_line->words; |
639 | this_word != next_line_words; |
640 | this_word = this_word->next |
641 | ) |
642 | { |
643 | |
644 | int chindex = 0; |
645 | for (;;) |
646 | { |
647 | int curch; |
648 | if (chindex == this_word->text_length) |
649 | break; |
650 | if (utblc > MAX_UCS1600) |
651 | break; |
652 | curch = this_word->text[chindex]; |
653 | render_one_glyph(vo_font, curch); |
654 | obj->params.subtitle.utbl[utblc++] = curch; |
655 | sub_totallen++; |
656 | ++chindex; |
657 | } |
658 | obj->params.subtitle.utbl[utblc++] = ' '; |
659 | } |
660 | obj->params.subtitle.utbl[utblc - 1] = 0; |
661 | |
662 | obj->topy -= vo_font->height; |
663 | |
664 | |
665 | } |
666 | } |
667 | if (sub_max_lines < obj->params.subtitle.lines) |
668 | sub_max_lines = obj->params.subtitle.lines; |
669 | if (sub_max_font_height < vo_font->height) |
670 | sub_max_font_height = vo_font->height; |
671 | if (sub_max_bottom_font_height < vo_font->pic_b[vo_font->font[40]]->h) |
672 | sub_max_bottom_font_height = vo_font->pic_b[vo_font->font[40]]->h; |
673 | if (obj->params.subtitle.lines) |
674 | obj->topy = movie_height - sub_bottom_margin - (obj->params.subtitle.lines * vo_font->height); |
675 | |
676 | |
677 | if (otp_sub != NULL((void*)0)) |
678 | { |
679 | struct osd_text_word *tmp; |
680 | struct osd_text_line *pmt; |
681 | for (tmp = otp_sub->words; tmp->next != NULL((void*)0); free(tmp->prev)) |
682 | { |
683 | free(tmp->text); |
684 | tmp = tmp->next; |
685 | } |
686 | free(tmp->text); |
687 | free(tmp); |
688 | for (pmt = otp_sub; pmt->next != NULL((void*)0); free(pmt->prev)) |
689 | { |
690 | pmt = pmt->next; |
691 | } |
692 | free(pmt); |
693 | } |
694 | else |
695 | { |
696 | fprintf(stderrstderr, "WARN: Subtitles requested but not found.\n"); |
697 | } |
698 | } |
699 | { |
700 | |
701 | const int subs_height = |
702 | (obj->params.subtitle.lines - 1) * vo_font->height |
703 | + |
704 | vo_font->pic_b[vo_font->font[40]]->h; |
705 | |
706 | if (v_sub_alignment == V_SUB_ALIGNMENT_BOTTOM) |
707 | obj->topy = movie_height * sub_pos / 100 - sub_bottom_margin - subs_height; |
708 | else if (v_sub_alignment == V_SUB_ALIGNMENT_CENTER) |
709 | obj->topy = |
710 | ( |
711 | movie_height * sub_pos / 100 |
712 | - |
713 | sub_bottom_margin |
714 | - |
715 | sub_top_margin |
716 | - |
717 | subs_height |
718 | + |
719 | vo_font->height |
720 | ) |
721 | / |
722 | 2; |
723 | else |
724 | obj->topy = sub_top_margin; |
725 | if (obj->topy < sub_top_margin) |
726 | obj->topy = sub_top_margin; |
727 | if (obj->topy > movie_height - sub_bottom_margin - vo_font->height) |
728 | obj->topy = movie_height - sub_bottom_margin - vo_font->height; |
729 | obj->bbox.y2 = obj->topy + subs_height + 3; |
730 | |
731 | if (sub_justify) |
732 | xmin = sub_left_margin; |
733 | obj->bbox.x1 = xmin - 3; |
734 | obj->bbox.x2 = xmax + 3 + vo_font->spacewidth; |
735 | |
736 | |
737 | |
738 | |
739 | obj->bbox.y1 = obj->topy - 3; |
740 | |
741 | alloc_buf(obj); |
742 | |
743 | } |
744 | { |
745 | |
746 | int i, chindex, prev_line_end; |
747 | chindex = prev_line_end = 0; |
748 | linesleft = obj->params.subtitle.lines; |
749 | if (linesleft != 0) |
750 | { |
751 | int xtbl_min, x; |
752 | int y = obj->topy; |
753 | for (xtbl_min = widthlimit; linedone < linesleft; ++linedone) |
754 | if (obj->params.subtitle.xtbl[linedone] < xtbl_min) |
755 | xtbl_min = obj->params.subtitle.xtbl[linedone]; |
756 | for (i = 0; i < linesleft; ++i) |
757 | { |
758 | int prevch, curch; |
759 | switch (the_sub->alignment) |
760 | { |
761 | case H_SUB_ALIGNMENT_LEFT: |
762 | if (sub_justify) |
763 | x = xmin; |
764 | else |
765 | x = xtbl_min; |
766 | break; |
767 | case H_SUB_ALIGNMENT_RIGHT: |
768 | x = |
769 | 2 * obj->params.subtitle.xtbl[i] |
770 | - |
771 | xtbl_min |
772 | - |
773 | (obj->params.subtitle.xtbl[i] == xtbl_min ? 0 : 1); |
774 | break; |
775 | case H_SUB_ALIGNMENT_CENTER: |
776 | default: |
777 | x = obj->params.subtitle.xtbl[i]; |
778 | break; |
779 | } |
780 | prevch = -1; |
781 | while ((curch = obj->params.subtitle.utbl[chindex++]) != 0) |
782 | { |
783 | |
784 | const int font = vo_font->font[curch]; |
785 | x += kerning(vo_font, prevch, curch); |
786 | if (font >= 0) |
787 | { |
788 | |
789 | draw_glyph |
790 | ( |
791 | obj, |
792 | x, |
793 | y, |
794 | vo_font->width[curch], |
795 | |
796 | vo_font->pic_b[font]->h + y < movie_height - sub_bottom_margin ? |
797 | vo_font->pic_b[font]->h |
798 | : |
799 | movie_height - sub_bottom_margin - y, |
800 | vo_font->pic_b[font]->bmp + vo_font->start[curch], |
801 | vo_font->pic_b[font]->pal, |
802 | vo_font->pic_b[font]->w |
803 | ); |
804 | } |
805 | x += vo_font->width[curch] + vo_font->charspace; |
806 | prevch = curch; |
807 | } |
808 | if (sub_max_chars < chindex - prev_line_end) |
809 | sub_max_chars = chindex - prev_line_end; |
810 | prev_line_end = chindex; |
811 | y += vo_font->height; |
812 | } |
813 | |
814 | } |
815 | } |
816 | } |
817 | |
818 | void vo_update_osd(const subtitle_elt * vo_sub) |
819 | { |
820 | memset(textsub_image_buffer, 0, textsub_image_buffer_size); |
821 | |
822 | vo_update_text_sub(vo_osd, vo_sub); |
823 | vo_draw_subtitle_line |
824 | ( |
825 | vo_osd->bbox.x2 - vo_osd->bbox.x1, |
826 | vo_osd->bbox.y2 - vo_osd->bbox.y1, |
827 | vo_osd->bitmap_buffer, |
828 | vo_osd->stride, |
829 | |
830 | textsub_image_buffer |
831 | + |
832 | 4 * vo_osd->bbox.x1 |
833 | + |
834 | 4 * vo_osd->bbox.y1 * movie_width, |
835 | movie_width * 4 |
836 | ); |
837 | } |
838 | |
839 | void vo_init_osd() |
840 | { |
841 | vo_finish_osd(); |
842 | switch (default_video_format) |
843 | { |
844 | case VF_NTSC: |
845 | if (movie_fps == 0.0) |
846 | { |
847 | movie_fps = 29.97; |
848 | } |
849 | if (movie_width == 0) |
850 | { |
851 | movie_width = 720; |
852 | } |
853 | if (movie_height == 0) |
854 | { |
855 | movie_height = 478; |
856 | } |
857 | break; |
858 | case VF_PAL: |
859 | if (movie_fps == 0.0) |
860 | { |
861 | movie_fps = 25.0; |
862 | } |
863 | if (movie_width == 0) |
864 | { |
865 | movie_width = 720; |
866 | } |
867 | if (movie_height == 0) |
868 | { |
869 | movie_height = 574; |
870 | } |
871 | break; |
872 | default: |
873 | fprintf(stderrstderr, "ERR: cannot determine default video size and frame rate--no video format specified\n"); |
874 | exit(1); |
875 | } |
876 | textsub_image_buffer_size = sizeof(uint8_t) * 4 * movie_height * movie_width; |
877 | textsub_image_buffer = malloc(textsub_image_buffer_size); |
878 | |
879 | if (textsub_image_buffer == NULL((void*)0)) |
880 | { |
881 | fprintf(stderrstderr, "ERR: Failed to allocate memory\n"); |
882 | exit(1); |
883 | } |
884 | #ifdef HAVE_FREETYPE1 |
885 | init_freetype(); |
886 | load_font_ft(); |
887 | #endif |
888 | sub_max_chars = 0; |
889 | sub_max_lines = 0; |
890 | sub_max_font_height = 0; |
891 | sub_max_bottom_font_height = 0; |
892 | vo_osd = malloc(sizeof(mp_osd_obj_t)); |
893 | memset(vo_osd, 0, sizeof(mp_osd_obj_t)); |
894 | vo_osd->bitmap_buffer = NULL((void*)0); |
895 | vo_osd->allocated = -1; |
896 | } |
897 | |
898 | void vo_finish_osd() |
899 | |
900 | { |
901 | if (vo_osd) |
902 | { |
903 | free(vo_osd->bitmap_buffer); |
904 | } |
905 | free(vo_osd); |
906 | vo_osd = NULL((void*)0); |
907 | #ifdef HAVE_FREETYPE1 |
908 | done_freetype(); |
909 | #endif |
910 | free(textsub_image_buffer); |
911 | textsub_image_buffer = NULL((void*)0); |
912 | } |