File npv/config.h changed (mode: 100644) (index 375df09..e28b352) |
2 |
2 |
#define NPV_CONFIG_H |
#define NPV_CONFIG_H |
3 |
3 |
#include <stdlib.h> |
#include <stdlib.h> |
4 |
4 |
#include "npv/c_fixing.h" |
#include "npv/c_fixing.h" |
|
5 |
|
/* NotoSansSymbols2 is the only one with the play and pause symbols */ |
|
6 |
|
STATIC u8 *npv_faces[] = { |
|
7 |
|
"/share/fonts/noto/NotoMono-Regular.ttf", |
|
8 |
|
"/share/fonts/noto/NotoSansSymbols-Regular.ttf", |
|
9 |
|
"/share/fonts/noto/NotoSansSymbols2-Regular.ttf", |
|
10 |
|
"/usr/share/fonts/truetype/noto/NotoMono-Regular.ttf", |
|
11 |
|
"/usr/share/fonts/truetype/noto/NotoSansSymbols-Regular.ttf", |
|
12 |
|
"/usr/share/fonts/truetype/noto/NotoSansSymbols2-Regular.ttf", |
|
13 |
|
0 |
|
14 |
|
}; |
5 |
15 |
/* we don't use a xkb state machine, only bear 8bits truncated raw keycodes */ |
/* we don't use a xkb state machine, only bear 8bits truncated raw keycodes */ |
6 |
16 |
/*----------------------------------------------------------------------------*/ |
/*----------------------------------------------------------------------------*/ |
7 |
17 |
STATIC void npv_cmd_quit(void); |
STATIC void npv_cmd_quit(void); |
|
... |
... |
STATIC void npv_cmd_fastforward_big(void); |
12 |
22 |
STATIC void npv_cmd_vol_up(void); |
STATIC void npv_cmd_vol_up(void); |
13 |
23 |
STATIC void npv_cmd_vol_down(void); |
STATIC void npv_cmd_vol_down(void); |
14 |
24 |
STATIC void npv_cmd_mute(void); |
STATIC void npv_cmd_mute(void); |
15 |
|
STATIC void npv_cmd_info(void); |
|
|
25 |
|
STATIC void npv_cmd_osd_timer_toggle(void); |
16 |
26 |
STATIC void npv_cmd_pause(void); |
STATIC void npv_cmd_pause(void); |
17 |
27 |
STATIC void npv_cmd_fullscreen_toggle(void); |
STATIC void npv_cmd_fullscreen_toggle(void); |
18 |
28 |
/*----------------------------------------------------------------------------*/ |
/*----------------------------------------------------------------------------*/ |
|
... |
... |
struct npv_x11_bind_t npv_x11_binds[] = { |
39 |
49 |
X11_BIND(0x6f, "arrow up", npv_cmd_vol_up), |
X11_BIND(0x6f, "arrow up", npv_cmd_vol_up), |
40 |
50 |
X11_BIND(0x74, "arrow down", npv_cmd_vol_down), |
X11_BIND(0x74, "arrow down", npv_cmd_vol_down), |
41 |
51 |
X11_BIND(0x48, "f6", npv_cmd_mute), |
X11_BIND(0x48, "f6", npv_cmd_mute), |
42 |
|
X11_BIND(0x43, "f1", npv_cmd_info), |
|
|
52 |
|
X11_BIND(0x43, "f1", npv_cmd_osd_timer_toggle), |
43 |
53 |
X11_BIND(0x5f, "f11", npv_cmd_fullscreen_toggle) |
X11_BIND(0x5f, "f11", npv_cmd_fullscreen_toggle) |
44 |
54 |
}; |
}; |
45 |
55 |
#undef X11_BIND |
#undef X11_BIND |
File npv/local/code.frag.c changed (mode: 100644) (index 407220a..70847d5) |
... |
... |
STATIC void opts_parse(int argc, u8 **args, u8 **url, bool* start_fullscreen, |
430 |
430 |
STATIC void init_once(u8 *url, bool start_fullscreen, double initial_vol, |
STATIC void init_once(u8 *url, bool start_fullscreen, double initial_vol, |
431 |
431 |
u16 win_width, u16 win_height, u8 *pcm_str, |
u16 win_width, u16 win_height, u8 *pcm_str, |
432 |
432 |
avcodec_params_t **audio_codec_params, |
avcodec_params_t **audio_codec_params, |
433 |
|
avcodec_params_t **video_codec_params) |
|
|
433 |
|
avcodec_params_t **video_codec_params, |
|
434 |
|
u8 **faces) |
434 |
435 |
{ |
{ |
435 |
436 |
avutil_rational_t *audio_st_tb; |
avutil_rational_t *audio_st_tb; |
436 |
437 |
avutil_rational_t *video_st_tb; |
avutil_rational_t *video_st_tb; |
|
... |
... |
STATIC void init_once(u8 *url, bool start_fullscreen, double initial_vol, |
442 |
443 |
/* before audio_st_idx_p is actually used */ |
/* before audio_st_idx_p is actually used */ |
443 |
444 |
npv_audio_init_once(pcm_str); |
npv_audio_init_once(pcm_str); |
444 |
445 |
npv_video_init_once(); /* before video_st_idx_p is actually used */ |
npv_video_init_once(); /* before video_st_idx_p is actually used */ |
|
446 |
|
npv_video_osd_init_once(faces); |
445 |
447 |
npv_clk_init_once(); |
npv_clk_init_once(); |
446 |
448 |
npv_pipeline_init_once(); |
npv_pipeline_init_once(); |
447 |
449 |
|
|
|
... |
... |
STATIC void prepare(double initial_vol, u8 pkts_prefill_percent, |
497 |
499 |
|
|
498 |
500 |
evt_add_all_fds(); |
evt_add_all_fds(); |
499 |
501 |
} |
} |
500 |
|
/*==== while waiting for the osd -- start ====================================*/ |
|
501 |
|
STATIC u8 *duration_estimate_to_str(enum AVDurationEstimationMethod m) |
|
502 |
|
{ |
|
503 |
|
switch (m) { |
|
504 |
|
case AVFMT_DURATION_FROM_PTS: |
|
505 |
|
return "from PTS(Presentation TimeStamp)"; |
|
506 |
|
case AVFMT_DURATION_FROM_STREAM: |
|
507 |
|
return "from stream"; |
|
508 |
|
case AVFMT_DURATION_FROM_BITRATE: |
|
509 |
|
return "from bitrate"; |
|
510 |
|
default: |
|
511 |
|
return "unkwown"; |
|
512 |
|
} |
|
513 |
|
} |
|
514 |
|
STATIC u8 *ts_to_str(int64_t ts, avutil_rational_t time_base, |
|
515 |
|
int64_t *remaining) |
|
516 |
|
{ |
|
517 |
|
static u8 str[sizeof("~S00:00:00.000 remains S9223372036854775807 time base units")]; |
|
518 |
|
bool is_neg; |
|
519 |
|
int64_t hours_n; |
|
520 |
|
int64_t mins_n; |
|
521 |
|
int64_t secs_n; |
|
522 |
|
int64_t msecs_n; |
|
523 |
|
int64_t one_hour; /* in ffmpeg time_base units */ |
|
524 |
|
int64_t one_min; /* in ffmpeg time_base units */ |
|
525 |
|
int64_t one_sec; /* in ffmpeg time_base units */ |
|
526 |
|
int64_t one_msec; /* in ffmpeg time_base units */ |
|
527 |
|
|
|
528 |
|
if (ts < 0) { |
|
529 |
|
ts = -ts; |
|
530 |
|
is_neg = true; |
|
531 |
|
} else |
|
532 |
|
is_neg = false; |
|
533 |
|
|
|
534 |
|
one_hour = INT64_C(3600) * (int64_t)time_base.den |
|
535 |
|
/ (int64_t)time_base.num; |
|
536 |
|
one_min = INT64_C(60) * (int64_t)time_base.den |
|
537 |
|
/ (int64_t)time_base.num; |
|
538 |
|
one_sec = (int64_t)time_base.den / (int64_t)time_base.num; |
|
539 |
|
one_msec = one_sec / INT64_C(1000); |
|
540 |
|
|
|
541 |
|
hours_n = ts / one_hour; |
|
542 |
|
|
|
543 |
|
*remaining = ts % one_hour; |
|
544 |
|
mins_n = *remaining / one_min; |
|
545 |
|
|
|
546 |
|
*remaining = *remaining % one_min; |
|
547 |
|
secs_n = *remaining / one_sec; |
|
548 |
|
|
|
549 |
|
*remaining = *remaining % one_sec; |
|
550 |
|
msecs_n = *remaining / one_msec; |
|
551 |
|
|
|
552 |
|
/* account for all rounding errors */ |
|
553 |
|
*remaining = ts - (hours_n * one_hour + mins_n * one_min |
|
554 |
|
+ secs_n * one_sec + msecs_n * one_msec); |
|
555 |
|
if (!is_neg) |
|
556 |
|
snprintf(str, sizeof(str), "%02"PRId64":%02"PRId64":%02"PRId64".%03"PRId64, hours_n, mins_n, secs_n, msecs_n); |
|
557 |
|
else { |
|
558 |
|
str[0] = '-'; |
|
559 |
|
snprintf(str + 1, sizeof(str) - 1, "%02"PRId64":%02"PRId64":%02"PRId64".%03"PRId64, hours_n, mins_n, secs_n, msecs_n); |
|
560 |
|
} |
|
561 |
|
return str; |
|
562 |
|
} |
|
563 |
|
#define RED if (stdout_is_tty) pout("\x1b[38;2;255;0;0m") |
|
564 |
|
#define GREEN if (stdout_is_tty) pout("\x1b[38;2;0;255;0m") |
|
565 |
|
#define BLUE if (stdout_is_tty) pout("\x1b[38;2;0;0;255m") |
|
566 |
|
#define PURPLE if (stdout_is_tty) pout("\x1b[38;2;255;0;255m") |
|
567 |
|
#define RESTORE if (stdout_is_tty) pout("\x1b[39;49m"); |
|
568 |
|
#define TS_FROM_CLK_OK 0 |
|
569 |
|
/* we don't lock anything as an act of faith */ |
|
570 |
|
STATIC void npv_cmd_info(void) |
|
571 |
|
{ |
|
572 |
|
int ri; |
|
573 |
|
u8 r8; |
|
574 |
|
s64 audio_now; |
|
575 |
|
bool stdout_is_tty; |
|
576 |
|
u8 *ts_str; |
|
577 |
|
int64_t remaining; |
|
578 |
|
u8 duration_str[sizeof("S9223372036854775807")]; |
|
579 |
|
|
|
580 |
|
ri = isatty(1); |
|
581 |
|
if (ri == 0) |
|
582 |
|
stdout_is_tty = false; |
|
583 |
|
else |
|
584 |
|
stdout_is_tty = true; |
|
585 |
|
|
|
586 |
|
RESTORE; |
|
587 |
|
GREEN;pout("================================================================================\n");RESTORE; |
|
588 |
|
PURPLE;pout("%s\n", npv_fmt_ctx_p->url);RESTORE; |
|
589 |
|
|
|
590 |
|
r8 = npv_clk_get_audio_st_ts(&audio_now); |
|
591 |
|
if (r8 != TS_FROM_CLK_OK) { |
|
592 |
|
pout("information unavailable at the time of the command due to an unavailable audio clock\n"); |
|
593 |
|
return; |
|
594 |
|
} |
|
595 |
|
ts_str = ts_to_str(audio_now, npv_audio_st_p.tb, &remaining); |
|
596 |
|
RED;pout("%s", ts_str);RESTORE; |
|
597 |
|
if (remaining != 0) |
|
598 |
|
pout(" remaining %"PRId64" time base units", remaining); |
|
599 |
|
else |
|
600 |
|
pout("\n"); |
|
601 |
|
pout("\t%"PRId64" stream time base units (%d/%d seconds)\n", |
|
602 |
|
audio_now, npv_audio_st_p.tb.num, npv_audio_st_p.tb.den); |
|
603 |
|
BLUE;pout("--------------------------------------------------------------------------------\n");RESTORE; |
|
604 |
|
pout("format:"); |
|
605 |
|
if (npv_fmt_ctx_p->duration == AV_NOPTS_VALUE) { |
|
606 |
|
pout("duration is not provided\n"); |
|
607 |
|
} else { |
|
608 |
|
snprintf(duration_str, sizeof(duration_str), "%"PRId64, |
|
609 |
|
npv_fmt_ctx_p->duration); |
|
610 |
|
ts_str = ts_to_str(npv_fmt_ctx_p->duration, AV_TIME_BASE_Q, |
|
611 |
|
&remaining); |
|
612 |
|
pout("duration=");RED;pout("%s", ts_str);RESTORE; |
|
613 |
|
if (remaining != 0) |
|
614 |
|
pout(" remaining %"PRId64" av_time_base units\n", |
|
615 |
|
remaining); |
|
616 |
|
else |
|
617 |
|
pout("\n"); |
|
618 |
|
pout("\t%s av_time_base units (1/%d seconds)\n\testimation method is %s\n", |
|
619 |
|
duration_str, AV_TIME_BASE, duration_estimate_to_str( |
|
620 |
|
npv_fmt_ctx_p->duration_estimation_method)); |
|
621 |
|
} |
|
622 |
|
BLUE;pout("--------------------------------------------------------------------------------\n");RESTORE; |
|
623 |
|
pout("stream:audio_id=%d", npv_audio_st_p.id); |
|
624 |
|
if (npv_fmt_ctx_p->streams[npv_audio_st_p.idx]->duration == AV_NOPTS_VALUE) { |
|
625 |
|
pout(";duration is not provided\n"); |
|
626 |
|
} else { |
|
627 |
|
snprintf(duration_str, sizeof(duration_str), "%"PRId64, |
|
628 |
|
npv_fmt_ctx_p->streams[npv_audio_st_p.idx]->duration); |
|
629 |
|
ts_str = ts_to_str( |
|
630 |
|
npv_fmt_ctx_p->streams[npv_audio_st_p.idx]->duration, |
|
631 |
|
npv_audio_st_p.tb, &remaining); |
|
632 |
|
pout(";duration=");RED;pout("%s\n", ts_str);RESTORE; |
|
633 |
|
if (remaining != 0) |
|
634 |
|
pout(" remaining %"PRId64" stream time base units\n", |
|
635 |
|
remaining); |
|
636 |
|
else |
|
637 |
|
pout("\n"); |
|
638 |
|
pout("\t%s stream time base units (%d/%d seconds)\n", |
|
639 |
|
duration_str, npv_audio_st_p.tb.num, |
|
640 |
|
npv_audio_st_p.tb.den); |
|
641 |
|
} |
|
642 |
|
BLUE;pout("--------------------------------------------------------------------------------\n");RESTORE; |
|
643 |
|
GREEN;pout("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");RESTORE; |
|
644 |
|
} |
|
645 |
|
#undef TS_FROM_CLK_OK |
|
646 |
|
#undef RED |
|
647 |
|
#undef GREEN |
|
648 |
|
#undef BLUE |
|
649 |
|
#undef PURPLE |
|
650 |
|
#undef RESTORE |
|
651 |
|
/*==== while waiting for the osd -- end ======================================*/ |
|
652 |
502 |
STATIC void npv_cmd_quit(void) |
STATIC void npv_cmd_quit(void) |
653 |
503 |
{ |
{ |
654 |
504 |
exit_ok("quit command received\n"); |
exit_ok("quit command received\n"); |
|
... |
... |
int main(int argc, u8 **args) |
847 |
697 |
&pcm_str, &initial_vol, |
&pcm_str, &initial_vol, |
848 |
698 |
&npv_pipeline_limits_p.pkts.prefill.percent); |
&npv_pipeline_limits_p.pkts.prefill.percent); |
849 |
699 |
init_once(url, start_fullscreen, initial_vol, win_width, win_height, |
init_once(url, start_fullscreen, initial_vol, win_width, win_height, |
850 |
|
pcm_str, &audio_codec_params, &video_codec_params); |
|
|
700 |
|
pcm_str, &audio_codec_params, &video_codec_params, npv_faces); |
851 |
701 |
prepare(initial_vol, npv_pipeline_limits_p.pkts.prefill.percent, |
prepare(initial_vol, npv_pipeline_limits_p.pkts.prefill.percent, |
852 |
702 |
audio_codec_params, video_codec_params); |
audio_codec_params, video_codec_params); |
853 |
703 |
|
|
File npv/video/local/code.frag.c changed (mode: 100644) (index 0ccccd2..9c78014) |
... |
... |
STATIC u8 send_to_pe(u32 swpchn_img) |
598 |
598 |
STATIC void start_scaling(avutil_video_fr_ref_t *fr, |
STATIC void start_scaling(avutil_video_fr_ref_t *fr, |
599 |
599 |
struct dec_fr_priv_t *fr_priv, bool *scaler_dims_changed) |
struct dec_fr_priv_t *fr_priv, bool *scaler_dims_changed) |
600 |
600 |
{ |
{ |
601 |
|
u32 scaled_line_bytes_n; |
|
602 |
|
|
|
603 |
601 |
if (scaler_p.ctx->cfg.width != fr->width |
if (scaler_p.ctx->cfg.width != fr->width |
604 |
602 |
|| scaler_p.ctx->cfg.height != fr->height) { |
|| scaler_p.ctx->cfg.height != fr->height) { |
605 |
603 |
if (scaler_p.img.vk != 0) |
if (scaler_p.img.vk != 0) |
|
... |
... |
STATIC void start_scaling(avutil_video_fr_ref_t *fr, |
615 |
613 |
*scaler_dims_changed = true; |
*scaler_dims_changed = true; |
616 |
614 |
scaler_p.ctx->cfg.width = fr->width; |
scaler_p.ctx->cfg.width = fr->width; |
617 |
615 |
scaler_p.ctx->cfg.height = fr->height; |
scaler_p.ctx->cfg.height = fr->height; |
|
616 |
|
npv_video_osd_update_dimensions(scaler_p.img.data, |
|
617 |
|
(u16)fr->width, (u16)fr->height, |
|
618 |
|
(u32)scaler_p.img.layout.row_pitch); |
618 |
619 |
} else |
} else |
619 |
620 |
*scaler_dims_changed = false; |
*scaler_dims_changed = false; |
620 |
621 |
scaler_p.ctx->cfg.src_fmt = fr->fmt; |
scaler_p.ctx->cfg.src_fmt = fr->fmt; |
621 |
622 |
scaler_p.ctx->cfg.dst_fmt = AVUTIL_PIX_FMT_RGB32; |
scaler_p.ctx->cfg.dst_fmt = AVUTIL_PIX_FMT_RGB32; |
622 |
623 |
scaler_p.ctx->cfg.flags = SWS_POINT; /* | SWS_PRINT_INFO */ |
scaler_p.ctx->cfg.flags = SWS_POINT; /* | SWS_PRINT_INFO */ |
623 |
624 |
|
|
624 |
|
scaled_line_bytes_n = (u32)scaler_p.img.layout.row_pitch; |
|
625 |
625 |
scaler_p.ctx->scale.src_slices = fr->data; |
scaler_p.ctx->scale.src_slices = fr->data; |
626 |
626 |
scaler_p.ctx->scale.src_strides = fr->linesize; |
scaler_p.ctx->scale.src_strides = fr->linesize; |
627 |
627 |
scaler_p.ctx->scale.dst_slice = scaler_p.img.data; |
scaler_p.ctx->scale.dst_slice = scaler_p.img.data; |
628 |
|
scaler_p.ctx->scale.dst_stride = scaled_line_bytes_n; |
|
|
628 |
|
scaler_p.ctx->scale.dst_stride = (u32)scaler_p.img.layout.row_pitch; |
629 |
629 |
npv_thdsws_run(scaler_p.ctx); |
npv_thdsws_run(scaler_p.ctx); |
630 |
630 |
scaler_p.img.fr = fr; |
scaler_p.img.fr = fr; |
|
631 |
|
/* |
|
632 |
|
* saved pixs for restoration are now irrelevant since we did |
|
633 |
|
* overwrite everything |
|
634 |
|
*/ |
|
635 |
|
npv_video_osd_clear_dirty(); |
631 |
636 |
} |
} |
632 |
637 |
STATIC void timer_ack(void) |
STATIC void timer_ack(void) |
633 |
638 |
{ |
{ |
|
... |
... |
STATIC void timer_ack(void) |
637 |
642 |
exps_n = 0; |
exps_n = 0; |
638 |
643 |
r = read(timer_fd_p, &exps_n, sizeof(exps_n)); |
r = read(timer_fd_p, &exps_n, sizeof(exps_n)); |
639 |
644 |
if (r == -1) |
if (r == -1) |
640 |
|
fatal("unable to read the number of timer expirations\n"); |
|
|
645 |
|
warning("unable to read the number of timer expirations\n"); |
641 |
646 |
} |
} |
File npv/video/osd/local/code.frag.c added (mode: 100644) (index 0000000..3fe63eb) |
|
1 |
|
STATIC void fatal(void *fmt, ...) |
|
2 |
|
{ |
|
3 |
|
va_list ap; |
|
4 |
|
|
|
5 |
|
npv_perr("osd:"); |
|
6 |
|
va_start(ap, fmt); |
|
7 |
|
npv_vfatal(fmt, ap); |
|
8 |
|
va_end(ap); |
|
9 |
|
exit(EXIT_FAILURE); |
|
10 |
|
} |
|
11 |
|
STATIC void warning(void *fmt, ...) |
|
12 |
|
{ |
|
13 |
|
va_list ap; |
|
14 |
|
|
|
15 |
|
npv_perr("osd:"); |
|
16 |
|
va_start(ap, fmt); |
|
17 |
|
npv_vwarning(fmt,ap); |
|
18 |
|
va_end(ap); |
|
19 |
|
} |
|
20 |
|
STATIC void pout(void *fmt, ...) |
|
21 |
|
{ |
|
22 |
|
va_list ap; |
|
23 |
|
|
|
24 |
|
npv_pout("osd:"); |
|
25 |
|
va_start(ap, fmt); |
|
26 |
|
npv_vpout(fmt, ap); |
|
27 |
|
va_end(ap); |
|
28 |
|
} |
|
29 |
|
/*NSPC*/ |
|
30 |
|
STATIC void cache_nodes_release(void) |
|
31 |
|
{ |
|
32 |
|
u8 i; |
|
33 |
|
|
|
34 |
|
i = 0; |
|
35 |
|
loop { |
|
36 |
|
if (i == GS_N) |
|
37 |
|
break; |
|
38 |
|
if (cache_l.gs[i].node != 0) { |
|
39 |
|
FTC_Node_Unref(cache_l.gs[i].node, cache_l.manager); |
|
40 |
|
cache_l.gs[i].node = 0; |
|
41 |
|
} |
|
42 |
|
++i; |
|
43 |
|
} |
|
44 |
|
} |
|
45 |
|
/*NSPC*/ |
|
46 |
|
STATIC void finalizer(void *object) |
|
47 |
|
{ |
|
48 |
|
FT_Face f; |
|
49 |
|
FT_Face *f_ptr; |
|
50 |
|
|
|
51 |
|
f = object; |
|
52 |
|
f_ptr = f->generic.data; /* we need to zero our pointer */ |
|
53 |
|
*f_ptr = 0; |
|
54 |
|
} |
|
55 |
|
/*NSPC*/ |
|
56 |
|
STATIC void face_lookup(FT_Face *f, u8 i) |
|
57 |
|
{ |
|
58 |
|
FT_Error ft_r; |
|
59 |
|
|
|
60 |
|
if (cache_l.faces.ft[i] != 0) { |
|
61 |
|
*f = cache_l.faces.ft[i]; |
|
62 |
|
return; |
|
63 |
|
} |
|
64 |
|
ft_r = FTC_Manager_LookupFace(cache_l.manager, &cache_l.faces.ids[i], |
|
65 |
|
f); |
|
66 |
|
if (ft_r != FT_Err_Ok) |
|
67 |
|
fatal("freetype:cache_l:unable to lookup for face %s\n", cache_l.faces.files[i]); |
|
68 |
|
} |
|
69 |
|
/*NSPC*/ |
|
70 |
|
STATIC void gs_init_once(void) |
|
71 |
|
{ |
|
72 |
|
u8 i; |
|
73 |
|
|
|
74 |
|
cache_l.gs[G_PERCENT_SIGN].unicode = 0x25; |
|
75 |
|
cache_l.gs[G_SOLIDUS].unicode = 0x2f; |
|
76 |
|
cache_l.gs[G_0].unicode = 0x30; |
|
77 |
|
cache_l.gs[G_1].unicode = 0x31; |
|
78 |
|
cache_l.gs[G_2].unicode = 0x32; |
|
79 |
|
cache_l.gs[G_3].unicode = 0x33; |
|
80 |
|
cache_l.gs[G_4].unicode = 0x34; |
|
81 |
|
cache_l.gs[G_5].unicode = 0x35; |
|
82 |
|
cache_l.gs[G_6].unicode = 0x36; |
|
83 |
|
cache_l.gs[G_7].unicode = 0x37; |
|
84 |
|
cache_l.gs[G_8].unicode = 0x38; |
|
85 |
|
cache_l.gs[G_9].unicode = 0x39; |
|
86 |
|
cache_l.gs[G_COLON].unicode = 0x3a; |
|
87 |
|
cache_l.gs[G_QUESTION_MARK].unicode = 0x3f; |
|
88 |
|
cache_l.gs[G_MINUS].unicode = 0x2212; |
|
89 |
|
cache_l.gs[G_PLAY].unicode = 0x23f5; |
|
90 |
|
cache_l.gs[G_PAUSE].unicode = 0x23f8; |
|
91 |
|
cache_l.gs[G_BLACK_LOWER_RIGHT_TRIANGLE].unicode= 0x25e2; |
|
92 |
|
|
|
93 |
|
i = 0; |
|
94 |
|
loop { |
|
95 |
|
u8 j; |
|
96 |
|
|
|
97 |
|
if (i == GS_N) |
|
98 |
|
break; |
|
99 |
|
j = 0; |
|
100 |
|
loop { |
|
101 |
|
FT_Face f; |
|
102 |
|
|
|
103 |
|
if (j == cache_l.faces.n) { |
|
104 |
|
warning("freetype:unable to find a valid glyph index for our glyph %u\n", i); |
|
105 |
|
cache_l.gs[i].face_id = 0; |
|
106 |
|
break; |
|
107 |
|
} |
|
108 |
|
face_lookup(&f, j); |
|
109 |
|
cache_l.gs[i].idx = FT_Get_Char_Index(f, |
|
110 |
|
cache_l.gs[i].unicode); |
|
111 |
|
if (cache_l.gs[i].idx != 0) { |
|
112 |
|
cache_l.gs[i].face_id = j; |
|
113 |
|
break; |
|
114 |
|
} |
|
115 |
|
++j; |
|
116 |
|
} |
|
117 |
|
++i; |
|
118 |
|
} |
|
119 |
|
} |
|
120 |
|
STATIC void out_tt_interpreters(FT_UInt iv) |
|
121 |
|
{ |
|
122 |
|
if ((TT_INTERPRETER_VERSION_35 & iv) != 0) |
|
123 |
|
pout("freetype:truetype:hinting interpreter version 35 available\n"); |
|
124 |
|
if ((TT_INTERPRETER_VERSION_38 & iv) != 0) |
|
125 |
|
pout("freetype:truetype:hinting interpreter version 38 available\n"); |
|
126 |
|
if ((TT_INTERPRETER_VERSION_40 & iv) != 0) |
|
127 |
|
pout("freetype:truetype:hinting interpreter version 40 available\n"); |
|
128 |
|
} |
|
129 |
|
STATIC u8 *hinting_engine_str(FT_Int32 he) |
|
130 |
|
{ |
|
131 |
|
if (he == FT_HINTING_FREETYPE) |
|
132 |
|
return "freetype"; |
|
133 |
|
else if (he == FT_HINTING_ADOBE) |
|
134 |
|
return "adobe"; |
|
135 |
|
else |
|
136 |
|
return "unknown"; |
|
137 |
|
} |
|
138 |
|
/* the id is the idx in the faces/fonts arrays */ |
|
139 |
|
STATIC FT_Error face_requester(FTC_FaceID face_id, FT_Library lib, |
|
140 |
|
FT_Pointer unused, FT_Face *aface) |
|
141 |
|
{ |
|
142 |
|
FT_Error ft_r; |
|
143 |
|
u8 *id; |
|
144 |
|
|
|
145 |
|
id = face_id; |
|
146 |
|
if (id == 0) { |
|
147 |
|
warning("freetype:cache_l:requester:no face id\n"); |
|
148 |
|
return FT_Err_Invalid_Argument; |
|
149 |
|
} |
|
150 |
|
/* presume ptr equality means the same */ |
|
151 |
|
if (lib != library_l) { |
|
152 |
|
warning("freetype:cache_l:requester:wrong lib\n"); |
|
153 |
|
return FT_Err_Invalid_Library_Handle; |
|
154 |
|
} |
|
155 |
|
if (cache_l.faces.ft[*id] != NULL) |
|
156 |
|
goto exit; |
|
157 |
|
ft_r = FT_New_Face(lib, cache_l.faces.files[*id], -1, |
|
158 |
|
&cache_l.faces.ft[*id]); |
|
159 |
|
if (ft_r != FT_Err_Ok) { |
|
160 |
|
warning("freetype:unable to load the face(s) %s:%d\n", cache_l.faces.files[*id], ft_r); |
|
161 |
|
return ft_r; |
|
162 |
|
} |
|
163 |
|
pout("freetype:face %s has %ld faces\n", cache_l.faces.files[*id], cache_l.faces.ft[*id]->num_faces); |
|
164 |
|
ft_r = FT_Done_Face(cache_l.faces.ft[*id]); |
|
165 |
|
if (ft_r != FT_Err_Ok) { |
|
166 |
|
warning("freetype:unable to unload the face(s) %s:%d\n", cache_l.faces.files[*id], ft_r); |
|
167 |
|
return ft_r; |
|
168 |
|
} |
|
169 |
|
pout("freetype:opening face 0 of %s\n", cache_l.faces.files[*id]); |
|
170 |
|
ft_r = FT_New_Face(lib, cache_l.faces.files[*id], 0, |
|
171 |
|
&cache_l.faces.ft[*id]); |
|
172 |
|
if (ft_r != FT_Err_Ok) { |
|
173 |
|
warning("freetype:unable to open the face 0 from %s:%d\n", cache_l.faces.files[*id], ft_r); |
|
174 |
|
return ft_r; |
|
175 |
|
} |
|
176 |
|
/* install finalizer, to know when the cache let it go */ |
|
177 |
|
cache_l.faces.ft[*id]->generic.finalizer = finalizer; |
|
178 |
|
cache_l.faces.ft[*id]->generic.data = &cache_l.faces.ft[*id]; |
|
179 |
|
|
|
180 |
|
pout("freetype:face 0 of %s:\n", cache_l.faces.files[*id]); |
|
181 |
|
pout("freetype:\tnumber of glyphs = %ld\n", cache_l.faces.ft[*id]->num_glyphs); |
|
182 |
|
pout("freetype:\tfamily name=%s\n", cache_l.faces.ft[*id]->family_name); |
|
183 |
|
if (cache_l.faces.ft[*id]->style_name != 0) |
|
184 |
|
pout("freetype:\tstyle name=%s\n", cache_l.faces.ft[*id]->style_name); |
|
185 |
|
exit: |
|
186 |
|
*aface = cache_l.faces.ft[*id]; |
|
187 |
|
return FT_Err_Ok; |
|
188 |
|
} |
|
189 |
|
/*NSPC*/ |
|
190 |
|
STATIC void timer_baseline_compute(void) |
|
191 |
|
{ |
|
192 |
|
FT_Int max; |
|
193 |
|
u8 i; |
|
194 |
|
/* |
|
195 |
|
* get the max distance, in n of lines, from the baseline, _excluded_, |
|
196 |
|
* of the _rendered_ gs: play/pause, 0..9 and colon |
|
197 |
|
*/ |
|
198 |
|
max = cache_l.gs[G_PLAY].bg->top; |
|
199 |
|
if (cache_l.gs[G_PAUSE].bg->top > max) |
|
200 |
|
max = cache_l.gs[G_PAUSE].bg->top; |
|
201 |
|
i = G_0; |
|
202 |
|
loop { |
|
203 |
|
if (i > G_COLON) |
|
204 |
|
break; |
|
205 |
|
if (cache_l.gs[i].bg->top > max) |
|
206 |
|
max = cache_l.gs[i].bg->top; |
|
207 |
|
++i; |
|
208 |
|
} |
|
209 |
|
pout("timer:baseline:max top=%d\n", max); |
|
210 |
|
timer_baseline_l = (u16)max; |
|
211 |
|
} |
|
212 |
|
/*NSPC*/ |
|
213 |
|
STATIC u32 digit_advance_max(void) |
|
214 |
|
{ |
|
215 |
|
u8 i; |
|
216 |
|
u32 max; |
|
217 |
|
u16 max_i; |
|
218 |
|
u16 max_f; |
|
219 |
|
|
|
220 |
|
max = cache_l.gs[G_0].bg->root.advance.x; |
|
221 |
|
max_i = (u16)(max >> 16); |
|
222 |
|
max_f = (u16)(max & 0xffff); |
|
223 |
|
i = G_1; |
|
224 |
|
loop { |
|
225 |
|
u32 digit_advance; |
|
226 |
|
u16 digit_advance_i; |
|
227 |
|
u16 digit_advance_f; |
|
228 |
|
|
|
229 |
|
if (i > G_9) |
|
230 |
|
break; |
|
231 |
|
digit_advance = (u32)(cache_l.gs[i].bg->root.advance.x); |
|
232 |
|
digit_advance_i = (u16)(digit_advance >> 16); |
|
233 |
|
digit_advance_f = (u16)(digit_advance & 0xffff); |
|
234 |
|
if (digit_advance_i > max_i) { |
|
235 |
|
max_i = digit_advance_i; |
|
236 |
|
max_f = digit_advance_f; |
|
237 |
|
} else if (digit_advance_i == max_i) { |
|
238 |
|
if (digit_advance_f > max_f) { |
|
239 |
|
max_i = digit_advance_i; |
|
240 |
|
max_f = digit_advance_f; |
|
241 |
|
} |
|
242 |
|
} |
|
243 |
|
++i; |
|
244 |
|
} |
|
245 |
|
return max; |
|
246 |
|
} |
|
247 |
|
/* template:S100% where S is the a volume symbol */ |
|
248 |
|
/*NSPC*/ |
|
249 |
|
STATIC void volume_pen_start_location_compute(u16 width, u16 height) |
|
250 |
|
{ |
|
251 |
|
u16 steps; |
|
252 |
|
u16 indicator_start_column; |
|
253 |
|
s16 indicator_width; /* we can start as a negative number */ |
|
254 |
|
u32 advance; |
|
255 |
|
u16 advance_i; |
|
256 |
|
u16 advance_f; |
|
257 |
|
/* |
|
258 |
|
* we must take into account the "full" width of the left glyph, namely |
|
259 |
|
* the volume symbol, and the "full" width of the right glyph, namely |
|
260 |
|
* the percent glyph |
|
261 |
|
*/ |
|
262 |
|
/* |
|
263 |
|
* we add or remove some colums, that depends on the "left" position of |
|
264 |
|
* the glyph bitmap from the pen position: if the left border of the |
|
265 |
|
* bitmap is "before" the pen position ("left" is <0), we add some |
|
266 |
|
* colmuns. if the left border of the bitmap is "after" the pen |
|
267 |
|
* position ("left is >=0), we remove some columns. (yes, this is |
|
268 |
|
* excessive brain f*ckage) |
|
269 |
|
*/ |
|
270 |
|
indicator_width = (s16)(-cache_l.gs[G_PERCENT_SIGN].bg->left); |
|
271 |
|
advance = (u32)cache_l.gs[G_PERCENT_SIGN].bg->root.advance.x; |
|
272 |
|
advance_i = (u16)(advance >> 16); |
|
273 |
|
advance_f = (u16)(advance & 0xffff); |
|
274 |
|
indicator_width += (s16)(advance_i + (advance_f != 0 ? 1 : 0)); |
|
275 |
|
/* for the digits, we account only the advance width */ |
|
276 |
|
advance = (u32)cache_l.gs[G_1].bg->root.advance.x; |
|
277 |
|
advance_i = (u16)(advance >> 16); |
|
278 |
|
advance_f = (u16)(advance & 0xffff); |
|
279 |
|
indicator_width += (s16)(advance_i + (advance_f != 0 ? 1 : 0)); |
|
280 |
|
advance = digit_advance_max(); |
|
281 |
|
advance_i = (u16)(advance >> 16); |
|
282 |
|
advance_f = (u16)(advance & 0xffff); |
|
283 |
|
indicator_width += 2 * (advance_i + (advance_f != 0 ? 1 : 0)); |
|
284 |
|
/* we must account of the "full width of the last symbol */ |
|
285 |
|
indicator_width += (s16)cache_l.gs[G_PERCENT_SIGN].bg->left; |
|
286 |
|
/* divided by 3, because the bitmap is lcd decimated, see freetype doc*/ |
|
287 |
|
indicator_width += (s16)(cache_l.gs[G_PERCENT_SIGN].bg->bitmap.width |
|
288 |
|
/ 3); |
|
289 |
|
volume_l.baseline = height / 2; /* ~ middle of the screen */ |
|
290 |
|
/* |
|
291 |
|
* should be "enough", and we re-adjust the start pen position based |
|
292 |
|
* on the columns we did add or remove |
|
293 |
|
*/ |
|
294 |
|
volume_l.start_column = (width - (u16)indicator_width) / 2; |
|
295 |
|
volume_l.start_column = (u16)((s16)volume_l.start_column |
|
296 |
|
- (s16)cache_l.gs[G_PERCENT_SIGN].bg->left); |
|
297 |
|
} |
|
298 |
|
/* |
|
299 |
|
* in order: |
|
300 |
|
* - fmt |
|
301 |
|
* - audio st (we are audio driven) |
|
302 |
|
* - video st |
|
303 |
|
*/ |
|
304 |
|
/*NSPC*/ |
|
305 |
|
STATIC bool duration_resolve(int64_t *duration, avutil_rational_t *tb) |
|
306 |
|
{ |
|
307 |
|
if (npv_fmt_ctx_p->duration != AV_NOPTS_VALUE) { |
|
308 |
|
*duration = npv_fmt_ctx_p->duration; |
|
309 |
|
memcpy(tb, &AV_TIME_BASE_Q, sizeof(*tb)); |
|
310 |
|
return true; |
|
311 |
|
} |
|
312 |
|
if (npv_fmt_ctx_p->streams[npv_audio_st_p.idx]->duration != AV_NOPTS_VALUE) { |
|
313 |
|
*duration = |
|
314 |
|
npv_fmt_ctx_p->streams[npv_audio_st_p.idx]->duration; |
|
315 |
|
memcpy(tb, &(npv_fmt_ctx_p->streams[npv_audio_st_p.idx]->tb), |
|
316 |
|
sizeof(*tb)); |
|
317 |
|
return true; |
|
318 |
|
} |
|
319 |
|
if (npv_fmt_ctx_p->streams[npv_video_st_p.idx]->duration != AV_NOPTS_VALUE) { |
|
320 |
|
*duration = |
|
321 |
|
npv_fmt_ctx_p->streams[npv_video_st_p.idx]->duration; |
|
322 |
|
memcpy(tb, &(npv_fmt_ctx_p->streams[npv_video_st_p.idx]->tb), |
|
323 |
|
sizeof(*tb)); |
|
324 |
|
return true; |
|
325 |
|
} |
|
326 |
|
return false; |
|
327 |
|
} |
|
328 |
|
/*NSPC*/ |
|
329 |
|
STATIC u8 *timer_to_gs(int64_t ts, avutil_rational_t tb) |
|
330 |
|
{ |
|
331 |
|
/* P = Play, S = minus Sign */ |
|
332 |
|
static u8 gs[sizeof(TIMER_TMPL)]; |
|
333 |
|
u8 i; |
|
334 |
|
bool is_neg; |
|
335 |
|
int64_t remaining; |
|
336 |
|
int64_t hours_n; |
|
337 |
|
int64_t hours_d; |
|
338 |
|
int64_t hours_dx; |
|
339 |
|
int64_t mins_n; |
|
340 |
|
int64_t secs_n; |
|
341 |
|
int64_t msecs_n; |
|
342 |
|
int64_t one_hour; /* in ffmpeg time_base units */ |
|
343 |
|
int64_t one_min; /* in ffmpeg time_base units */ |
|
344 |
|
int64_t one_sec; /* in ffmpeg time_base units */ |
|
345 |
|
int64_t one_msec; /* in ffmpeg time_base units */ |
|
346 |
|
int64_t duration; |
|
347 |
|
avutil_rational_t duration_tb; |
|
348 |
|
|
|
349 |
|
i = 0; |
|
350 |
|
if (npv_paused_p) |
|
351 |
|
gs[i++] = G_PAUSE; |
|
352 |
|
else |
|
353 |
|
gs[i++] = G_PLAY; |
|
354 |
|
|
|
355 |
|
if (ts < 0) { |
|
356 |
|
ts = -ts; |
|
357 |
|
is_neg = true; |
|
358 |
|
gs[i++] = G_MINUS; |
|
359 |
|
} else |
|
360 |
|
is_neg = false; |
|
361 |
|
|
|
362 |
|
one_hour = INT64_C(3600) * (int64_t)tb.den / (int64_t)tb.num; |
|
363 |
|
one_min = INT64_C(60) * (int64_t)tb.den / (int64_t)tb.num; |
|
364 |
|
one_sec = (int64_t)tb.den / (int64_t)tb.num; |
|
365 |
|
one_msec = one_sec / INT64_C(1000); |
|
366 |
|
|
|
367 |
|
hours_n = ts / one_hour; |
|
368 |
|
if (hours_n >= 100) { |
|
369 |
|
gs[i++] = G_QUESTION_MARK; |
|
370 |
|
gs[i++] = G_QUESTION_MARK; |
|
371 |
|
} else { |
|
372 |
|
gs[i++] = hours_n / 10 + G_0; |
|
373 |
|
gs[i++] = hours_n % 10 + G_0; |
|
374 |
|
} |
|
375 |
|
gs[i++] = G_COLON; |
|
376 |
|
|
|
377 |
|
remaining = ts % one_hour; |
|
378 |
|
mins_n = remaining / one_min; |
|
379 |
|
gs[i++] = mins_n / 10 + G_0; |
|
380 |
|
gs[i++] = mins_n % 10 + G_0; |
|
381 |
|
|
|
382 |
|
gs[i++] = G_COLON; |
|
383 |
|
|
|
384 |
|
remaining = remaining % one_min; |
|
385 |
|
secs_n = remaining / one_sec; |
|
386 |
|
gs[i++] = secs_n / 10 + G_0; |
|
387 |
|
gs[i++] = secs_n % 10 + G_0; |
|
388 |
|
|
|
389 |
|
gs[i++] = G_SOLIDUS; |
|
390 |
|
/*--------------------------------------------------------------------*/ |
|
391 |
|
/* duration */ |
|
392 |
|
if (!duration_resolve(&duration, &duration_tb)) { |
|
393 |
|
gs[i++] = G_QUESTION_MARK; |
|
394 |
|
gs[i++] = G_QUESTION_MARK; |
|
395 |
|
gs[i++] = G_COLON; |
|
396 |
|
gs[i++] = G_QUESTION_MARK; |
|
397 |
|
gs[i++] = G_QUESTION_MARK; |
|
398 |
|
gs[i++] = G_COLON; |
|
399 |
|
gs[i++] = G_QUESTION_MARK; |
|
400 |
|
gs[i++] = G_QUESTION_MARK; |
|
401 |
|
goto exit; |
|
402 |
|
} |
|
403 |
|
one_hour = INT64_C(3600) * (int64_t)duration_tb.den |
|
404 |
|
/ (int64_t)duration_tb.num; |
|
405 |
|
one_min = INT64_C(60) * (int64_t)duration_tb.den |
|
406 |
|
/ (int64_t)duration_tb.num; |
|
407 |
|
one_sec = (int64_t)duration_tb.den / (int64_t)duration_tb.num; |
|
408 |
|
one_msec = one_sec / INT64_C(1000); |
|
409 |
|
|
|
410 |
|
hours_n = duration / one_hour; |
|
411 |
|
if (hours_n >= 100) { |
|
412 |
|
gs[i++] = G_QUESTION_MARK; |
|
413 |
|
gs[i++] = G_QUESTION_MARK; |
|
414 |
|
} else { |
|
415 |
|
gs[i++] = hours_n / 10 + G_0; |
|
416 |
|
gs[i++] = hours_n % 10 + G_0; |
|
417 |
|
} |
|
418 |
|
gs[i++] = G_COLON; |
|
419 |
|
|
|
420 |
|
remaining = duration % one_hour; |
|
421 |
|
mins_n = remaining / one_min; |
|
422 |
|
gs[i++] = mins_n / 10 + G_0; |
|
423 |
|
gs[i++] = mins_n % 10 + G_0; |
|
424 |
|
|
|
425 |
|
gs[i++] = G_COLON; |
|
426 |
|
|
|
427 |
|
remaining = remaining % one_min; |
|
428 |
|
secs_n = remaining / one_sec; |
|
429 |
|
gs[i++] = secs_n / 10 + G_0; |
|
430 |
|
gs[i++] = secs_n % 10 + G_0; |
|
431 |
|
/*--------------------------------------------------------------------*/ |
|
432 |
|
exit: |
|
433 |
|
gs[i] = GS_N; /* perfect hash ! (ahah) */ |
|
434 |
|
return gs; |
|
435 |
|
} |
|
436 |
|
/*NSPC*/ |
|
437 |
|
struct pen_t { |
|
438 |
|
s16 x; |
|
439 |
|
s16 y; |
|
440 |
|
}; |
|
441 |
|
/* FT_BitmapGlyph is a ptr */ |
|
442 |
|
#define BLEND 0 |
|
443 |
|
/*NSPC*/ |
|
444 |
|
static void g_x(bool mode, FT_BitmapGlyph gb, struct pen_t *p) |
|
445 |
|
{ |
|
446 |
|
u8 *fr_row; |
|
447 |
|
u8 *gb_row; |
|
448 |
|
u8 *gb_rows_end; /* ptr on the row past the last one */ |
|
449 |
|
s16 x; |
|
450 |
|
s16 y; |
|
451 |
|
|
|
452 |
|
gb_row = gb->bitmap.buffer; |
|
453 |
|
gb_rows_end = gb->bitmap.buffer + gb->bitmap.rows * gb->bitmap.pitch; |
|
454 |
|
/* if top is 0, the bitmap top line is the baseline */ |
|
455 |
|
y = p->y - gb->top; |
|
456 |
|
loop { |
|
457 |
|
u8 *png_column; |
|
458 |
|
u8 *gb_column; |
|
459 |
|
u8 *gb_columns_end; /* ptr on the column past the last one */ |
|
460 |
|
|
|
461 |
|
if (gb_row == gb_rows_end) |
|
462 |
|
break; |
|
463 |
|
gb_column = gb_row; |
|
464 |
|
/* fu... "decimation" */ |
|
465 |
|
gb_columns_end = gb_row + gb->bitmap.width; |
|
466 |
|
x = p->x + gb->left; |
|
467 |
|
loop { |
|
468 |
|
|
|
469 |
|
if (gb_column == gb_columns_end) |
|
470 |
|
break; |
|
471 |
|
if (x >= 0 && y >= 0 && x < restore_l.width |
|
472 |
|
&& y < restore_l.height) { |
|
473 |
|
u8 p; |
|
474 |
|
u8 *scaler_pix; |
|
475 |
|
u8 *restore_pix; |
|
476 |
|
u32 offset; |
|
477 |
|
|
|
478 |
|
offset = restore_l.line_bytes_n * y + (3 + 1) |
|
479 |
|
* x; |
|
480 |
|
scaler_pix = (u8*)restore_l.scaler_pixs |
|
481 |
|
+ offset; |
|
482 |
|
restore_pix = (u8*)restore_l.pixs + offset; |
|
483 |
|
/* |
|
484 |
|
* the img is sRGB encoded, we "cheat" here, |
|
485 |
|
* using glyph bitmap linear RGB |
|
486 |
|
*/ |
|
487 |
|
p = 0; |
|
488 |
|
loop { |
|
489 |
|
if (p == 3) |
|
490 |
|
break; |
|
491 |
|
if (gb_column[p] != 0) { |
|
492 |
|
if (mode == BLEND) { |
|
493 |
|
restore_pix[p] = |
|
494 |
|
scaler_pix[p]; |
|
495 |
|
scaler_pix[p] = |
|
496 |
|
gb_column[p]; |
|
497 |
|
} else /* RESTORE */ |
|
498 |
|
scaler_pix[p] = |
|
499 |
|
restore_pix[p]; |
|
500 |
|
} |
|
501 |
|
++p; |
|
502 |
|
} |
|
503 |
|
/* |
|
504 |
|
* don't know how vulkan hw will interpret the |
|
505 |
|
* alpha channel |
|
506 |
|
*/ |
|
507 |
|
if (gb_column[0] != 0 || gb_column[1] != 0 |
|
508 |
|
|| gb_column[2] != 0 ) { |
|
509 |
|
if (mode == BLEND) { |
|
510 |
|
restore_pix[3] = scaler_pix[3]; |
|
511 |
|
scaler_pix[3] = 0xff; |
|
512 |
|
} else /* RESTORE */ |
|
513 |
|
scaler_pix[3] = restore_pix[3]; |
|
514 |
|
} |
|
515 |
|
} |
|
516 |
|
gb_column += 3; |
|
517 |
|
++x; |
|
518 |
|
} |
|
519 |
|
gb_row += gb->bitmap.pitch; |
|
520 |
|
++y; |
|
521 |
|
} |
|
522 |
|
} |
|
523 |
|
#undef BLEND |
|
524 |
|
#define BLEND 0 |
|
525 |
|
/*NSPC*/ |
|
526 |
|
STATIC void rop_x(u8 mode, u8 *gs) |
|
527 |
|
{ |
|
528 |
|
struct pen_t pen; |
|
529 |
|
u8 i; |
|
530 |
|
|
|
531 |
|
if (mode == BLEND) |
|
532 |
|
memcpy(restore_l.timer_gs, gs, sizeof(TIMER_TMPL)); |
|
533 |
|
pen.x = 0; |
|
534 |
|
pen.y = timer_baseline_l; |
|
535 |
|
i = 0; |
|
536 |
|
loop { |
|
537 |
|
FT_BitmapGlyph bg; |
|
538 |
|
u32 advance_x; |
|
539 |
|
s16 advance_x_i; |
|
540 |
|
u16 advance_x_f; |
|
541 |
|
|
|
542 |
|
if (gs[i] == GS_N) |
|
543 |
|
break; |
|
544 |
|
bg = cache_l.gs[gs[i]].bg; |
|
545 |
|
g_x(mode, bg, &pen); |
|
546 |
|
advance_x = bg->root.advance.x; |
|
547 |
|
advance_x_i = advance_x >> 16; |
|
548 |
|
advance_x_f = advance_x & 0xffff; |
|
549 |
|
pen.x += advance_x_i + (s16)(advance_x_f != 0 ? 1 : 0); |
|
550 |
|
++i; |
|
551 |
|
} |
|
552 |
|
} |
|
553 |
|
#undef BLEND |
File npv/video/osd/public/code.frag.c added (mode: 100644) (index 0000000..c06e9ab) |
|
1 |
|
STATIC void init_once(u8 **faces_files) |
|
2 |
|
{ |
|
3 |
|
FT_Error ft_r; |
|
4 |
|
/* adobe or legacy freetype */ |
|
5 |
|
FT_UInt cff; |
|
6 |
|
FT_UInt type1; |
|
7 |
|
FT_UInt t1cid; |
|
8 |
|
/* the different versions of freetype truetype hinters */ |
|
9 |
|
FT_UInt tt_interpreters; |
|
10 |
|
u8 id; /* face cache_l id, idx in the arrays */ |
|
11 |
|
|
|
12 |
|
memset(&cache_l, 0, sizeof(cache_l)); |
|
13 |
|
ft_r = FT_Init_FreeType(&library_l); |
|
14 |
|
if (ft_r != FT_Err_Ok) |
|
15 |
|
fatal("freetype:unable to get a freetype2 library_l handle:%d\n", ft_r); |
|
16 |
|
ft_r = FTC_Manager_New(library_l, 0, 0, 0, face_requester, 0, |
|
17 |
|
&cache_l.manager); |
|
18 |
|
if (ft_r != 0) |
|
19 |
|
fatal("freetype:unable to new a cache_l manager\n"); |
|
20 |
|
ft_r = FTC_ImageCache_New(cache_l.manager, &cache_l.img_cache); |
|
21 |
|
if (ft_r != 0) |
|
22 |
|
fatal("freetype:unable to new a image cache_l\n"); |
|
23 |
|
/* ccf, type1 and t1cid hinting engines */ |
|
24 |
|
ft_r = FT_Property_Get(library_l, "cff", "hinting-engine", &cff); |
|
25 |
|
if (ft_r != FT_Err_Ok) |
|
26 |
|
warning("freetype:no cff module or no hinting engine property\n"); |
|
27 |
|
else |
|
28 |
|
pout("freetype:ccf:using the %s hinting engine\n", hinting_engine_str(cff)); |
|
29 |
|
ft_r = FT_Property_Get(library_l, "type1", "hinting-engine", &type1); |
|
30 |
|
if (ft_r != FT_Err_Ok) |
|
31 |
|
warning("freetype:no type1 module or no hinting engine property\n"); |
|
32 |
|
else |
|
33 |
|
pout("freetype:type1:using the %s hinting engine\n", hinting_engine_str(type1)); |
|
34 |
|
ft_r = FT_Property_Get(library_l, "t1cid", "hinting-engine", &t1cid); |
|
35 |
|
if (ft_r != FT_Err_Ok) |
|
36 |
|
warning("freetype:no t1cid module or no hinting engine property\n"); |
|
37 |
|
else |
|
38 |
|
pout("freetype:t1cid:using the %s hinting engine\n", hinting_engine_str(t1cid)); |
|
39 |
|
/* truetype various hinting engines */ |
|
40 |
|
ft_r = FT_Property_Get(library_l, "truetype", "interpreter-version", |
|
41 |
|
&tt_interpreters); |
|
42 |
|
if (ft_r != FT_Err_Ok) |
|
43 |
|
warning("freetype:no truetype module or no truetype hinting interpreter version\n"); |
|
44 |
|
else { |
|
45 |
|
pout("freetype:truetype:hinting interpreters 0x%x\n", tt_interpreters); |
|
46 |
|
out_tt_interpreters(tt_interpreters); |
|
47 |
|
} |
|
48 |
|
/* we leave all defaults for the various hinting engines */ |
|
49 |
|
/* |
|
50 |
|
* the lcd filtering stuff (_rendering_ and _not hinting_) must be |
|
51 |
|
* explicitely enabled, if available |
|
52 |
|
*/ |
|
53 |
|
ft_r = FT_Library_SetLcdFilter(library_l, FT_LCD_FILTER_DEFAULT); |
|
54 |
|
if (ft_r != FT_Err_Ok) |
|
55 |
|
warning("freetype:no lcd filtering in this freetype library_l:%d\n", ft_r); |
|
56 |
|
else |
|
57 |
|
pout("freetype:default lcd filtering enabled\n"); |
|
58 |
|
/*====================================================================*/ |
|
59 |
|
/* prepare our side of the font cache */ |
|
60 |
|
cache_l.faces.files = faces_files; |
|
61 |
|
id = 0; |
|
62 |
|
loop { /* count the font files */ |
|
63 |
|
if (cache_l.faces.files[id] == 0) |
|
64 |
|
break; |
|
65 |
|
pout("font file:%s\n", cache_l.faces.files[id]); |
|
66 |
|
++id; |
|
67 |
|
} |
|
68 |
|
pout("%u font files provided\n", id); |
|
69 |
|
cache_l.faces.n = id; |
|
70 |
|
cache_l.faces.ft = calloc(cache_l.faces.n, sizeof(*cache_l.faces.ft)); |
|
71 |
|
if (cache_l.faces.ft == 0) |
|
72 |
|
fatal("unable to allocate an array of %u freetype sets of faces\n", cache_l.faces.n); |
|
73 |
|
/*--------------------------------------------------------------------*/ |
|
74 |
|
/* freetype cache wants face id pointers to be uniq in memory... */ |
|
75 |
|
cache_l.faces.ids = calloc(cache_l.faces.n, sizeof(*cache_l.faces.ids)); |
|
76 |
|
if (cache_l.faces.ids == 0) |
|
77 |
|
fatal("unable to allocate an array of %u ids\n", cache_l.faces.n); |
|
78 |
|
id = 0; |
|
79 |
|
loop { |
|
80 |
|
if (id == cache_l.faces.n) |
|
81 |
|
break; |
|
82 |
|
cache_l.faces.ids[id] = id; /* we did miss something */ |
|
83 |
|
++id; |
|
84 |
|
} |
|
85 |
|
/*====================================================================*/ |
|
86 |
|
gs_init_once(); |
|
87 |
|
memset(&restore_l, 0, sizeof(restore_l)); |
|
88 |
|
timer_on = false; |
|
89 |
|
} |
|
90 |
|
STATIC void update_dimensions(void *scaler_pixs, u16 width, u16 height, |
|
91 |
|
u32 line_bytes_n) |
|
92 |
|
{ |
|
93 |
|
FT_Error ft_r; |
|
94 |
|
FT_Face f; |
|
95 |
|
FTC_ScalerRec scaler_rec; |
|
96 |
|
u8 i; |
|
97 |
|
|
|
98 |
|
cache_nodes_release(); |
|
99 |
|
/* |
|
100 |
|
* choices which may end up in the config file: |
|
101 |
|
* XXX: ascender in most font files ~ em height |
|
102 |
|
* XXX: ascender ~ 1/16 height |
|
103 |
|
* XXX: em box height/width ratio ~ 4/3 |
|
104 |
|
*/ |
|
105 |
|
scaler_rec.height = height / 16; |
|
106 |
|
scaler_rec.width = scaler_rec.height * 3 / 4; |
|
107 |
|
pout("scaler:em to %ux%u pixels\n", scaler_rec.width, scaler_rec.height); |
|
108 |
|
i = 0; |
|
109 |
|
loop { |
|
110 |
|
FT_Glyph g; |
|
111 |
|
|
|
112 |
|
if (i == GS_N) |
|
113 |
|
break; |
|
114 |
|
memset(&scaler_rec, 0, sizeof(scaler_rec)); |
|
115 |
|
/* XXX: freetype cache wants ids with uniq ptrs */ |
|
116 |
|
scaler_rec.face_id = |
|
117 |
|
&(cache_l.faces.ids[cache_l.gs[i].face_id]); |
|
118 |
|
scaler_rec.height = height / 16; |
|
119 |
|
scaler_rec.width = scaler_rec.height * 3 / 4; |
|
120 |
|
scaler_rec.pixel = 1; |
|
121 |
|
ft_r = FTC_ImageCache_LookupScaler(cache_l.img_cache, |
|
122 |
|
&scaler_rec, FT_LOAD_RENDER | FT_LOAD_TARGET_LCD, |
|
123 |
|
cache_l.gs[i].idx, &g, &cache_l.gs[i].node); |
|
124 |
|
if (ft_r != FT_Err_Ok) |
|
125 |
|
fatal("freetype:cache_l:failed to look for glyph %u with our target size:0x%02x\n", i, ft_r); |
|
126 |
|
if (g->format != FT_GLYPH_FORMAT_BITMAP) |
|
127 |
|
fatal("freetype:the glyph %u was not rendered in bitmap\n", i); |
|
128 |
|
cache_l.gs[i].bg = (FT_BitmapGlyph)g; |
|
129 |
|
++i; |
|
130 |
|
} |
|
131 |
|
timer_baseline_compute(); |
|
132 |
|
volume_pen_start_location_compute(width, height); |
|
133 |
|
restore_l.scaler_pixs = scaler_pixs; |
|
134 |
|
free(restore_l.pixs); |
|
135 |
|
restore_l.pixs = calloc(4, (u32)height * line_bytes_n); |
|
136 |
|
restore_l.width = width; |
|
137 |
|
restore_l.height = height; |
|
138 |
|
restore_l.line_bytes_n = line_bytes_n; |
|
139 |
|
restore_l.dirty = false; |
|
140 |
|
} |
|
141 |
|
#define BLEND 0 |
|
142 |
|
STATIC void rop_blend(s64 now) |
|
143 |
|
{ |
|
144 |
|
u8 *timer_gs; |
|
145 |
|
|
|
146 |
|
if (!timer_on || restore_l.dirty) |
|
147 |
|
return; |
|
148 |
|
timer_gs = timer_to_gs(now, |
|
149 |
|
npv_fmt_ctx_p->streams[npv_video_st_p.idx]->tb); |
|
150 |
|
rop_x(BLEND, timer_gs); |
|
151 |
|
restore_l.dirty = true; |
|
152 |
|
} |
|
153 |
|
#undef BLEND |
|
154 |
|
#define RESTORE 1 |
|
155 |
|
STATIC void rop_restore(void) |
|
156 |
|
{ |
|
157 |
|
if (!restore_l.dirty) |
|
158 |
|
return; |
|
159 |
|
rop_x(RESTORE, restore_l.timer_gs); |
|
160 |
|
restore_l.dirty = false; |
|
161 |
|
} |
|
162 |
|
#undef RESTORE |
|
163 |
|
STATIC void clear_dirty(void) |
|
164 |
|
{ |
|
165 |
|
restore_l.dirty = false; |
|
166 |
|
} |
|
167 |
|
STATIC void npv_cmd_osd_timer_toggle(void) |
|
168 |
|
{ |
|
169 |
|
if (timer_on) { |
|
170 |
|
timer_on = false; |
|
171 |
|
pout("timer off\n"); |
|
172 |
|
} else { |
|
173 |
|
timer_on = true; |
|
174 |
|
pout("timer on\n"); |
|
175 |
|
} |
|
176 |
|
} |