File npv/audio/filt/local/code.frag.c changed (mode: 100644) (index 432cf92..7ce8f1f) |
... |
... |
STATIC bool is_recfg_required(avutil_audio_set_ref_t *src_set) |
34 |
34 |
return true; |
return true; |
35 |
35 |
return false; |
return false; |
36 |
36 |
} |
} |
37 |
|
STATIC void abufsrc_cfg(int chans_n, uint64_t chans_layout, int rate, |
|
38 |
|
enum avutil_audio_fr_fmt_t fmt, bool print_info) |
|
|
37 |
|
STATIC void abufsrc_cfg(avutil_rational_t tb, int chans_n, |
|
38 |
|
uint64_t chans_layout, int rate, enum avutil_audio_fr_fmt_t fmt, |
|
39 |
|
bool print_info) |
39 |
40 |
{ |
{ |
40 |
41 |
int r; |
int r; |
41 |
|
avutil_rational_t time_base; |
|
42 |
42 |
u8 chans_layout_str[STR_SZ]; /* should be overkill */ |
u8 chans_layout_str[STR_SZ]; /* should be overkill */ |
43 |
43 |
|
|
44 |
44 |
abufsrc_l.this = avfilter_get_by_name("abuffer"); |
abufsrc_l.this = avfilter_get_by_name("abuffer"); |
|
... |
... |
STATIC void abufsrc_cfg(int chans_n, uint64_t chans_layout, int rate, |
65 |
65 |
AVUTIL_OPT_SEARCH_CHILDREN); |
AVUTIL_OPT_SEARCH_CHILDREN); |
66 |
66 |
if (r < 0) |
if (r < 0) |
67 |
67 |
fatal("audio buffer source context:unable to set the decoder channel layout option\n"); |
fatal("audio buffer source context:unable to set the decoder channel layout option\n"); |
|
68 |
|
r = avutil_opt_set_q(abufsrc_l.ctx, "time_base", tb, |
|
69 |
|
AVUTIL_OPT_SEARCH_CHILDREN); |
|
70 |
|
if (r < 0) |
|
71 |
|
fatal("audio buffer source context:unable to set the time base option\n"); |
68 |
72 |
r = avfilter_init_str(abufsrc_l.ctx, 0); |
r = avfilter_init_str(abufsrc_l.ctx, 0); |
69 |
73 |
if (r < 0) |
if (r < 0) |
70 |
74 |
fatal("audio buffer source context:unable to initialize\n"); |
fatal("audio buffer source context:unable to initialize\n"); |
|
... |
... |
STATIC void abufsink_cfg(void) |
136 |
140 |
abufsink_l = avfilter_get_by_name("abuffersink"); |
abufsink_l = avfilter_get_by_name("abuffersink"); |
137 |
141 |
if (abufsink_l == 0) |
if (abufsink_l == 0) |
138 |
142 |
fatal("audio buffer sink:could not find the filter\n"); |
fatal("audio buffer sink:could not find the filter\n"); |
139 |
|
abufsink_ctx_l = avfilter_graph_alloc_filt(graph_l, abufsink_l, |
|
|
143 |
|
filt_p.abufsink_ctx = avfilter_graph_alloc_filt(graph_l, abufsink_l, |
140 |
144 |
"sink_abuf"); |
"sink_abuf"); |
141 |
|
if (abufsink_ctx_l == 0) |
|
|
145 |
|
if (filt_p.abufsink_ctx == 0) |
142 |
146 |
fatal("audio buffer sink context:could not allocate the instance in the filter graph\n"); |
fatal("audio buffer sink context:could not allocate the instance in the filter graph\n"); |
143 |
|
r = avfilter_init_str(abufsink_ctx_l, 0); |
|
|
147 |
|
r = avfilter_init_str(filt_p.abufsink_ctx, 0); |
144 |
148 |
if (r < 0) |
if (r < 0) |
145 |
149 |
fatal("audio buffer sink context:unable to initialize\n"); |
fatal("audio buffer sink context:unable to initialize\n"); |
146 |
150 |
} |
} |
|
... |
... |
STATIC void init_once_local(void) |
152 |
156 |
vol_l = 0; |
vol_l = 0; |
153 |
157 |
afmt_ctx_l = 0; |
afmt_ctx_l = 0; |
154 |
158 |
afmt_l = 0; |
afmt_l = 0; |
155 |
|
abufsink_ctx_l = 0; |
|
156 |
159 |
abufsink_l = 0; |
abufsink_l = 0; |
157 |
160 |
/* floating point strs are localized... erk... */ |
/* floating point strs are localized... erk... */ |
158 |
161 |
snprintf(double_zero_l10n_str_l, sizeof(double_zero_l10n_str_l), |
snprintf(double_zero_l10n_str_l, sizeof(double_zero_l10n_str_l), |
|
... |
... |
STATIC void init_once_public(double initial_vol) |
166 |
169 |
filt_p.pcm_written_ufrs_n = 0; |
filt_p.pcm_written_ufrs_n = 0; |
167 |
170 |
filt_p.vol = initial_vol; |
filt_p.vol = initial_vol; |
168 |
171 |
filt_p.muted = false; |
filt_p.muted = false; |
|
172 |
|
filt_p.abufsink_ctx = 0; |
169 |
173 |
} |
} |
File npv/audio/filt/public.h changed (mode: 100644) (index 9ff44ce..2e06c71) |
7 |
7 |
#include <stdbool.h> |
#include <stdbool.h> |
8 |
8 |
#include <libavutil/frame.h> |
#include <libavutil/frame.h> |
9 |
9 |
#include <libavutil/samplefmt.h> |
#include <libavutil/samplefmt.h> |
|
10 |
|
#include <libavfilter/avfilter.h> |
10 |
11 |
#include <alsa/asoundlib.h> |
#include <alsa/asoundlib.h> |
11 |
12 |
#include "npv/c_fixing.h" |
#include "npv/c_fixing.h" |
12 |
13 |
#include "npv/global.h" |
#include "npv/global.h" |
|
19 |
20 |
#include "npv/audio/filt/public/state.frag.h" |
#include "npv/audio/filt/public/state.frag.h" |
20 |
21 |
/*---------------------------------------------------------------------------*/ |
/*---------------------------------------------------------------------------*/ |
21 |
22 |
STATIC void init_once(double initial_vol); |
STATIC void init_once(double initial_vol); |
22 |
|
STATIC void cfg(int src_chans_n, uint64_t src_chans_layout, int src_rate, |
|
|
23 |
|
STATIC void cfg(avutil_rational_t tb, |
|
24 |
|
int src_chans_n, uint64_t src_chans_layout, int src_rate, |
23 |
25 |
enum avutil_audio_fr_fmt_t src_fmt, |
enum avutil_audio_fr_fmt_t src_fmt, |
24 |
26 |
bool muted, double vol, |
bool muted, double vol, |
25 |
27 |
int dst_chans_n, uint64_t dst_chans_layout, int dst_rate, |
int dst_chans_n, uint64_t dst_chans_layout, int dst_rate, |
File npv/audio/filt/public/code.frag.c changed (mode: 100644) (index 77bd9c9..7cb3f17) |
... |
... |
STATIC u8 filt_set_get(void) |
81 |
81 |
* the last dec set should switch the filt in draining mode, and |
* the last dec set should switch the filt in draining mode, and |
82 |
82 |
* filt_p.set won't matter. |
* filt_p.set won't matter. |
83 |
83 |
*/ |
*/ |
84 |
|
r = avfilter_bufsink_get_audio_set(abufsink_ctx_l, filt_p.set); |
|
|
84 |
|
r = avfilter_bufsink_get_audio_set(filt_p.abufsink_ctx, filt_p.set); |
85 |
85 |
if (r >= 0) { |
if (r >= 0) { |
86 |
86 |
filt_p.pcm_written_ufrs_n = 0; |
filt_p.pcm_written_ufrs_n = 0; |
87 |
87 |
return HAVE_FILT_SET; |
return HAVE_FILT_SET; |
|
... |
... |
STATIC void init_once(double initial_vol) |
104 |
104 |
init_once_local(); |
init_once_local(); |
105 |
105 |
init_once_public(initial_vol); |
init_once_public(initial_vol); |
106 |
106 |
} |
} |
107 |
|
STATIC void cfg(int src_chans_n, uint64_t src_chans_layout, int src_rate, |
|
|
107 |
|
STATIC void cfg(avutil_rational_t tb, |
|
108 |
|
int src_chans_n, uint64_t src_chans_layout, int src_rate, |
108 |
109 |
enum avutil_audio_fr_fmt_t src_fmt, |
enum avutil_audio_fr_fmt_t src_fmt, |
109 |
110 |
bool muted, double vol, |
bool muted, double vol, |
110 |
111 |
int dst_chans_n, uint64_t dst_chans_layout, int dst_rate, |
int dst_chans_n, uint64_t dst_chans_layout, int dst_rate, |
|
... |
... |
STATIC void cfg(int src_chans_n, uint64_t src_chans_layout, int src_rate, |
119 |
120 |
graph_l = avfilter_graph_alloc(); |
graph_l = avfilter_graph_alloc(); |
120 |
121 |
if (graph_l == 0) |
if (graph_l == 0) |
121 |
122 |
fatal("unable to create filter graph\n"); |
fatal("unable to create filter graph\n"); |
122 |
|
abufsrc_cfg(src_chans_n, src_chans_layout, src_rate, src_fmt, |
|
|
123 |
|
abufsrc_cfg(tb, src_chans_n, src_chans_layout, src_rate, src_fmt, |
123 |
124 |
print_info); |
print_info); |
124 |
125 |
/*--------------------------------------------------------------------*/ |
/*--------------------------------------------------------------------*/ |
125 |
126 |
abufsrc_l.key.chans_n = src_chans_n; |
abufsrc_l.key.chans_n = src_chans_n; |
|
... |
... |
STATIC void cfg(int src_chans_n, uint64_t src_chans_layout, int src_rate, |
136 |
137 |
r = avfilter_link(vol_ctx_l, 0, afmt_ctx_l, 0); |
r = avfilter_link(vol_ctx_l, 0, afmt_ctx_l, 0); |
137 |
138 |
if (r < 0) |
if (r < 0) |
138 |
139 |
fatal("unable to connect the volume filter to the audio format filter\n"); |
fatal("unable to connect the volume filter to the audio format filter\n"); |
139 |
|
r = avfilter_link(afmt_ctx_l, 0, abufsink_ctx_l, 0); |
|
|
140 |
|
r = avfilter_link(afmt_ctx_l, 0, filt_p.abufsink_ctx, 0); |
140 |
141 |
if (r < 0) |
if (r < 0) |
141 |
142 |
fatal("unable to connect the audio format filter to the audio buffer sink filter\n"); |
fatal("unable to connect the audio format filter to the audio buffer sink filter\n"); |
142 |
143 |
r = avfilter_graph_config(graph_l, 0); |
r = avfilter_graph_config(graph_l, 0); |
File npv/audio/local/code.frag.c changed (mode: 100644) (index 3f827fe..e10e8bd) |
... |
... |
STATIC u8 dec_set_filter(void) |
686 |
686 |
/* FILT_RECFG_REQUIRED */ |
/* FILT_RECFG_REQUIRED */ |
687 |
687 |
pcm2ff_strict(npv_audio_pcm_p, &dst_chans_n, &dst_chans_layout, |
pcm2ff_strict(npv_audio_pcm_p, &dst_chans_n, &dst_chans_layout, |
688 |
688 |
&dst_rate, &dst_fmt, PRINT_INFO); |
&dst_rate, &dst_fmt, PRINT_INFO); |
689 |
|
filt_cfg(new_chans_n, new_chans_layout, new_rate, new_fmt, |
|
|
689 |
|
filt_cfg(st_p.tb, |
|
690 |
|
new_chans_n, new_chans_layout, new_rate, new_fmt, |
690 |
691 |
filt_p.muted, filt_p.vol, |
filt_p.muted, filt_p.vol, |
691 |
692 |
dst_chans_n, dst_chans_layout, dst_rate, dst_fmt, |
dst_chans_n, dst_chans_layout, dst_rate, dst_fmt, |
692 |
693 |
PRINT_INFO); |
PRINT_INFO); |
File npv/clk/public.h changed (mode: 100644) (index bae0b52..cf3cfbe) |
7 |
7 |
#include "npv/namespace/alsa.h" |
#include "npv/namespace/alsa.h" |
8 |
8 |
/*---------------------------------------------------------------------------*/ |
/*---------------------------------------------------------------------------*/ |
9 |
9 |
STATIC void npv_clk_init_once(void); |
STATIC void npv_clk_init_once(void); |
10 |
|
STATIC u8 npv_clk_get_audio_st_ts(s64 *ts); |
|
|
10 |
|
STATIC u8 npv_clk_get_audio_filt_ts(s64 *ts); |
11 |
11 |
STATIC u8 npv_clk_get_video_st_ts(s64 *ts); |
STATIC u8 npv_clk_get_video_st_ts(s64 *ts); |
12 |
|
STATIC void npv_clk_ref_time_point_update(s64 audio_ts, |
|
|
12 |
|
STATIC void npv_clk_ref_time_point_update(s64 audio_filt_ts, |
13 |
13 |
snd_pcm_ufrs_t written_ufrs_n); |
snd_pcm_ufrs_t written_ufrs_n); |
14 |
14 |
STATIC void npv_clk_invalidate(void); |
STATIC void npv_clk_invalidate(void); |
15 |
15 |
STATIC void npv_clk_pause(void); |
STATIC void npv_clk_pause(void); |
File npv/clk/public/code.frag.c changed (mode: 100644) (index c8a4604..84aafba) |
... |
... |
STATIC void npv_clk_init_once(void) |
15 |
15 |
npv_clk_l.paused = false; |
npv_clk_l.paused = false; |
16 |
16 |
} |
} |
17 |
17 |
#define NO_REF_TIME_POINT 1 |
#define NO_REF_TIME_POINT 1 |
18 |
|
STATIC u8 npv_clk_get_audio_st_ts(s64 *ts) |
|
|
18 |
|
STATIC u8 npv_clk_get_audio_filt_ts(s64 *ts) |
19 |
19 |
{ |
{ |
20 |
20 |
int r; |
int r; |
21 |
21 |
snd_pcm_audio_tstamp_config_t ac; |
snd_pcm_audio_tstamp_config_t ac; |
|
... |
... |
STATIC u8 npv_clk_get_audio_st_ts(s64 *ts) |
24 |
24 |
f64 ref_ns; |
f64 ref_ns; |
25 |
25 |
f64 ref_status_ns; |
f64 ref_status_ns; |
26 |
26 |
f64 ref_delay_frs_n; |
f64 ref_delay_frs_n; |
27 |
|
f64 ref_audio_ts; |
|
28 |
|
f64 audio_tb_num; |
|
29 |
|
f64 audio_tb_den; |
|
|
27 |
|
f64 ref_audio_filt_ts; |
|
28 |
|
avutil_rational_t audio_filt_tb; |
|
29 |
|
f64 audio_filt_tb_num; |
|
30 |
|
f64 audio_filt_tb_den; |
30 |
31 |
f64 audio_rate_num; |
f64 audio_rate_num; |
31 |
32 |
unsigned int audio_rate_num_ui; |
unsigned int audio_rate_num_ui; |
32 |
33 |
f64 audio_rate_den; |
f64 audio_rate_den; |
|
... |
... |
STATIC u8 npv_clk_get_audio_st_ts(s64 *ts) |
53 |
54 |
snd_pcm_status_get_audio_htstamp(npv_clk_l.ref.status, &hts); |
snd_pcm_status_get_audio_htstamp(npv_clk_l.ref.status, &hts); |
54 |
55 |
ref_status_ns = (f64)hts.tv_sec * 1e9 + (f64)hts.tv_nsec; |
ref_status_ns = (f64)hts.tv_sec * 1e9 + (f64)hts.tv_nsec; |
55 |
56 |
|
|
56 |
|
ref_audio_ts = (f64)npv_clk_l.ref.audio_st_ts; |
|
|
57 |
|
ref_audio_filt_ts = (f64)npv_clk_l.ref.audio_filt_ts; |
57 |
58 |
ref_delay_frs_n = (f64)snd_pcm_status_get_delay(npv_clk_l.ref.status); |
ref_delay_frs_n = (f64)snd_pcm_status_get_delay(npv_clk_l.ref.status); |
58 |
|
audio_tb_num = (f64)npv_audio_st_p.tb.num; |
|
59 |
|
audio_tb_den = (f64)npv_audio_st_p.tb.den; |
|
|
59 |
|
/* we are writting the output of the filt to the audio pcm */ |
|
60 |
|
audio_filt_tb = avfilter_bufsink_tb_get(npv_audio_filt_p.abufsink_ctx); |
|
61 |
|
audio_filt_tb_num = (f64)audio_filt_tb.num; |
|
62 |
|
audio_filt_tb_den = (f64)audio_filt_tb.den; |
60 |
63 |
/*--------------------------------------------------------------------*/ |
/*--------------------------------------------------------------------*/ |
61 |
64 |
r = snd_pcm_hw_params_current(npv_audio_pcm_p, npv_clk_pcm_hw_params_l); |
r = snd_pcm_hw_params_current(npv_audio_pcm_p, npv_clk_pcm_hw_params_l); |
62 |
65 |
if (r != 0) |
if (r != 0) |
|
... |
... |
STATIC u8 npv_clk_get_audio_st_ts(s64 *ts) |
74 |
77 |
ref_ns = ref_status_ns + (ref_delay_frs_n - written_frs_n) |
ref_ns = ref_status_ns + (ref_delay_frs_n - written_frs_n) |
75 |
78 |
* audio_rate_den * 1e9 / audio_rate_num; |
* audio_rate_den * 1e9 / audio_rate_num; |
76 |
79 |
/* basic linear interpolation */ |
/* basic linear interpolation */ |
77 |
|
now_audio_ts = audio_tb_den * 1e-9 * (now_ns - ref_ns) / audio_tb_num |
|
78 |
|
+ ref_audio_ts; |
|
|
80 |
|
now_audio_ts = audio_filt_tb_den * 1e-9 * (now_ns - ref_ns) |
|
81 |
|
/ audio_filt_tb_num + ref_audio_filt_ts; |
79 |
82 |
*ts = (s64)lrint(now_audio_ts); |
*ts = (s64)lrint(now_audio_ts); |
80 |
83 |
return TS_RETURNED; |
return TS_RETURNED; |
81 |
84 |
} |
} |
82 |
85 |
#undef NO_REF_TIME_POINT |
#undef NO_REF_TIME_POINT |
83 |
86 |
STATIC u8 npv_clk_get_video_st_ts(s64 *ts) |
STATIC u8 npv_clk_get_video_st_ts(s64 *ts) |
84 |
87 |
{ |
{ |
85 |
|
f64 audio_tb_num; |
|
86 |
|
f64 audio_tb_den; |
|
87 |
|
f64 video_tb_num; |
|
88 |
|
f64 video_tb_den; |
|
89 |
|
f64 now_audio_ts; |
|
90 |
|
s64 now_audio_ts_s64; |
|
91 |
|
f64 now_video_ts; |
|
|
88 |
|
avutil_rational_t audio_filt_tb; |
|
89 |
|
s64 now_audio_filt_ts; |
92 |
90 |
u8 r; |
u8 r; |
93 |
91 |
|
|
94 |
|
audio_tb_num = (f64)npv_audio_st_p.tb.num; |
|
95 |
|
audio_tb_den = (f64)npv_audio_st_p.tb.den; |
|
96 |
|
video_tb_num = (f64)npv_video_st_p.tb.num; |
|
97 |
|
video_tb_den = (f64)npv_video_st_p.tb.den; |
|
98 |
|
|
|
99 |
|
r = npv_clk_get_audio_st_ts(&now_audio_ts_s64); |
|
|
92 |
|
audio_filt_tb = avfilter_bufsink_tb_get(npv_audio_filt_p.abufsink_ctx); |
|
93 |
|
r = npv_clk_get_audio_filt_ts(&now_audio_filt_ts); |
100 |
94 |
if (r != TS_RETURNED) |
if (r != TS_RETURNED) |
101 |
95 |
return r; |
return r; |
102 |
|
now_audio_ts = (f64)now_audio_ts_s64; |
|
103 |
|
/* basic conversion */ |
|
104 |
|
now_video_ts = audio_tb_num * video_tb_den * now_audio_ts |
|
105 |
|
/ (audio_tb_den * video_tb_num); |
|
106 |
|
*ts = (s64)lrint(now_video_ts); |
|
|
96 |
|
*ts = avutil_rescale_q(now_audio_filt_ts, audio_filt_tb, |
|
97 |
|
npv_video_st_p.tb); |
107 |
98 |
return TS_RETURNED; |
return TS_RETURNED; |
108 |
99 |
} |
} |
109 |
|
STATIC void npv_clk_ref_time_point_update(s64 audio_ts, |
|
|
100 |
|
STATIC void npv_clk_ref_time_point_update(s64 audio_filt_ts, |
110 |
101 |
snd_pcm_ufrs_t written_ufrs_n) |
snd_pcm_ufrs_t written_ufrs_n) |
111 |
102 |
{ |
{ |
112 |
103 |
int r; |
int r; |
|
... |
... |
STATIC void npv_clk_ref_time_point_update(s64 audio_ts, |
119 |
110 |
r = snd_pcm_status(npv_audio_pcm_p, npv_clk_l.ref.status); |
r = snd_pcm_status(npv_audio_pcm_p, npv_clk_l.ref.status); |
120 |
111 |
if (r < 0) |
if (r < 0) |
121 |
112 |
npv_clk_fatal("unable to sample timing information for reference time point\n"); |
npv_clk_fatal("unable to sample timing information for reference time point\n"); |
122 |
|
npv_clk_l.ref.audio_st_ts = audio_ts; |
|
|
113 |
|
npv_clk_l.ref.audio_filt_ts = audio_filt_ts; |
123 |
114 |
npv_clk_l.ref.written_ufrs_n = written_ufrs_n; |
npv_clk_l.ref.written_ufrs_n = written_ufrs_n; |
124 |
115 |
npv_clk_l.ref_valid = true; |
npv_clk_l.ref_valid = true; |
125 |
116 |
} |
} |
File npv/local/code.frag.c changed (mode: 100644) (index 6ad6944..13f11e5) |
... |
... |
STATIC void seek_x(s64 delta) |
621 |
621 |
{ |
{ |
622 |
622 |
int a; |
int a; |
623 |
623 |
u8 r; |
u8 r; |
624 |
|
s64 new_audio_ts; |
|
625 |
|
s64 new_video_ts; |
|
626 |
|
s64 audio_now; |
|
|
624 |
|
s64 now_audio_filt_ts; |
|
625 |
|
avutil_rational_t audio_filt_tb; |
|
626 |
|
s64 new_audio_filt_ts; |
|
627 |
|
s64 new_audio_st_ts; |
|
628 |
|
s64 now_audio_st_ts; |
627 |
629 |
|
|
628 |
630 |
if (npv_audio_draining_p) { |
if (npv_audio_draining_p) { |
629 |
631 |
warning("seek:audio is draining, seeking disable\n"); |
warning("seek:audio is draining, seeking disable\n"); |
|
... |
... |
STATIC void seek_x(s64 delta) |
636 |
638 |
|
|
637 |
639 |
seek_lock(); |
seek_lock(); |
638 |
640 |
|
|
639 |
|
r = npv_clk_get_audio_st_ts(&audio_now); |
|
|
641 |
|
r = npv_clk_get_audio_filt_ts(&now_audio_filt_ts); |
640 |
642 |
if (r != TS_FROM_CLK_OK) { |
if (r != TS_FROM_CLK_OK) { |
641 |
643 |
warning("seek:audio:clock timestamp unavailable, ignoring command\n"); |
warning("seek:audio:clock timestamp unavailable, ignoring command\n"); |
642 |
644 |
seek_unlock(); |
seek_unlock(); |
643 |
645 |
return; |
return; |
644 |
646 |
} |
} |
645 |
647 |
(void)snd_pcm_drop(npv_audio_pcm_p); |
(void)snd_pcm_drop(npv_audio_pcm_p); |
646 |
|
/* |
|
647 |
|
* XXX: a set of sts can share the same id for seeking. if they share |
|
648 |
|
* the same id then the tbs should be the same. |
|
649 |
|
*/ |
|
|
648 |
|
/* XXX: a set of sts can share the same id for seeking */ |
650 |
649 |
/*--------------------------------------------------------------------*/ |
/*--------------------------------------------------------------------*/ |
651 |
|
new_audio_ts = audio_now + delta * npv_audio_st_p.tb.den |
|
652 |
|
/ npv_audio_st_p.tb.num; |
|
653 |
|
/* rewind capping if possible */ |
|
654 |
|
if (npv_audio_st_p.start_time != AV_NOPTS_VALUE) |
|
655 |
|
if (new_audio_ts < npv_audio_st_p.start_time) |
|
656 |
|
new_audio_ts = npv_audio_st_p.start_time; |
|
657 |
|
pout("trying to seek to %"PRId64" audio stream time base units\n", new_audio_ts); |
|
658 |
|
a = avformat_seek_pkt(npv_fmt_ctx_p, npv_audio_st_p.id, new_audio_ts, |
|
|
650 |
|
audio_filt_tb = avfilter_bufsink_tb_get(npv_audio_filt_p.abufsink_ctx); |
|
651 |
|
new_audio_filt_ts = now_audio_filt_ts + delta * audio_filt_tb.den |
|
652 |
|
/ audio_filt_tb.num; |
|
653 |
|
new_audio_st_ts = avutil_rescale_q(new_audio_filt_ts, audio_filt_tb, |
|
654 |
|
npv_audio_st_p.tb); |
|
655 |
|
pout("trying to seek to %"PRId64" audio filter time base units/%"PRId64" audio stream time base units\n", new_audio_filt_ts, new_audio_st_ts); |
|
656 |
|
a = avformat_seek_pkt(npv_fmt_ctx_p, npv_audio_st_p.id, new_audio_st_ts, |
659 |
657 |
0); |
0); |
660 |
658 |
if (a < 0) { |
if (a < 0) { |
661 |
|
pout("unable to seek to %"PRId64" audio stream time base units\n", new_audio_ts); |
|
|
659 |
|
pout("unable to seek to %"PRId64" audio filter time base units/%"PRId64" audio stream time base units\n", new_audio_filt_ts, new_audio_st_ts); |
662 |
660 |
goto try_restore_audio; |
goto try_restore_audio; |
663 |
661 |
} |
} |
664 |
|
pout("global seek using audio seek to %"PRId64" audio stream time base units\n", new_audio_ts); |
|
|
662 |
|
pout("global seek using audio seek to %"PRId64" audio filter time base units/%"PRId64" audio stream time base units\n", new_audio_filt_ts, new_audio_st_ts); |
665 |
663 |
flush: |
flush: |
666 |
664 |
npv_video_dec_flush(); |
npv_video_dec_flush(); |
667 |
665 |
npv_audio_dec_flush(); |
npv_audio_dec_flush(); |
|
... |
... |
flush: |
682 |
680 |
return; |
return; |
683 |
681 |
|
|
684 |
682 |
try_restore_audio: |
try_restore_audio: |
685 |
|
a = avformat_seek_pkt(npv_fmt_ctx_p, npv_audio_st_p.id, audio_now, 0); |
|
|
683 |
|
now_audio_st_ts = avutil_rescale_q(now_audio_filt_ts, audio_filt_tb, |
|
684 |
|
npv_audio_st_p.tb); |
|
685 |
|
a = avformat_seek_pkt(npv_fmt_ctx_p, npv_audio_st_p.id, now_audio_st_ts, |
|
686 |
|
0); |
686 |
687 |
if (a < 0) /* we don't send an application error */ |
if (a < 0) /* we don't send an application error */ |
687 |
|
exit_ok("unable to restore audio to %"PRId64" audio stream time base units\n", audio_now); |
|
|
688 |
|
exit_ok("unable to restore audio to %"PRId64" audio filter time base units/%"PRId64" audio stream time base units\n", now_audio_filt_ts, now_audio_st_ts); |
688 |
689 |
goto flush; |
goto flush; |
689 |
690 |
} |
} |
690 |
691 |
#undef TS_FROM_CLK_OK |
#undef TS_FROM_CLK_OK |
File npv/namespace/ffmpeg.h changed (mode: 100644) (index 44451b6..1e1b61b) |
35 |
35 |
#define avcodec_pkt_ref_alloc av_packet_alloc |
#define avcodec_pkt_ref_alloc av_packet_alloc |
36 |
36 |
#define avcodec_pkt_ref_t AVPacket |
#define avcodec_pkt_ref_t AVPacket |
37 |
37 |
#define avcodec_pkt_unref av_packet_unref |
#define avcodec_pkt_unref av_packet_unref |
|
38 |
|
#define avfilter_bufsink_tb_get av_buffersink_get_time_base |
38 |
39 |
#define avfilter_filt_t AVFilter |
#define avfilter_filt_t AVFilter |
39 |
40 |
#define avfilter_filt_ctx_t AVFilterContext |
#define avfilter_filt_ctx_t AVFilterContext |
40 |
41 |
#define avfilter_filt_graph_t AVFilterGraph |
#define avfilter_filt_graph_t AVFilterGraph |
|
114 |
115 |
#undef avcodec_pkt_ref_alloc |
#undef avcodec_pkt_ref_alloc |
115 |
116 |
#undef avcodec_pkt_ref_t |
#undef avcodec_pkt_ref_t |
116 |
117 |
#undef avcodec_pkt_unref |
#undef avcodec_pkt_unref |
|
118 |
|
#undef avfilter_bufsink_tb_get |
117 |
119 |
#undef avfilter_filt_t |
#undef avfilter_filt_t |
118 |
120 |
#undef avfilter_filt_ctx_t |
#undef avfilter_filt_ctx_t |
119 |
121 |
#undef avfilter_filt_graph_t |
#undef avfilter_filt_graph_t |
File npv/pipeline/local/code.frag.c changed (mode: 100644) (index 0fa7a21..52d64ed) |
... |
... |
STATIC void *read_thd_entry(void *arg) |
80 |
80 |
/* |
/* |
81 |
81 |
* our alsa audio buf is (rate/4)~0.25s (interactivity like vol processing). |
* our alsa audio buf is (rate/4)~0.25s (interactivity like vol processing). |
82 |
82 |
* then we would like to have ~2 times this buf (~double buf) of decoded audio |
* then we would like to have ~2 times this buf (~double buf) of decoded audio |
83 |
|
* frs. namely we try to have ~(2 *0.25s) of decoded audio frames. we presume |
|
84 |
|
* the audio dec is fine grained enough in order to base our calculation on the |
|
85 |
|
* pts-es of 2 sets of audio frs. |
|
|
83 |
|
* frs. namely we try to have ~(2 *0.25s) of decoded audio frs. |
|
84 |
|
* due to discontinuity with ts and change of audio properties, we account for |
|
85 |
|
* the total amount of us based on the rate and frs n. |
86 |
86 |
*/ |
*/ |
87 |
87 |
STATIC bool have_enough_predecoded_audio_frs(void) |
STATIC bool have_enough_predecoded_audio_frs(void) |
88 |
88 |
{ |
{ |
89 |
|
int64_t pts_min; |
|
90 |
|
int64_t pts_max; |
|
91 |
|
int64_t pts_delta; |
|
92 |
|
int64_t pts_delta_limit; |
|
|
89 |
|
u32 set; |
|
90 |
|
int64_t total_us; |
|
91 |
|
int64_t total_us_threshold; |
93 |
92 |
|
|
94 |
93 |
npv_audio_dec_sets_lock(); |
npv_audio_dec_sets_lock(); |
95 |
94 |
if (npv_audio_dec_sets_p.eof_receive) { |
if (npv_audio_dec_sets_p.eof_receive) { |
|
... |
... |
STATIC bool have_enough_predecoded_audio_frs(void) |
100 |
99 |
return false; |
return false; |
101 |
100 |
} |
} |
102 |
101 |
/* from here we have at least 1 sets of audio frs */ |
/* from here we have at least 1 sets of audio frs */ |
103 |
|
/* we presume the audio sets are in pts order */ |
|
104 |
|
pts_min = npv_audio_dec_sets_p.a[0]->pts; |
|
105 |
|
pts_max = npv_audio_dec_sets_p.a[npv_audio_dec_sets_p.n - 1]->pts; |
|
|
102 |
|
set = 0; |
|
103 |
|
total_us = 0; |
|
104 |
|
loop { |
|
105 |
|
if (set == (npv_audio_dec_sets_p.n - 1)) |
|
106 |
|
break; |
|
107 |
|
total_us += npv_audio_dec_sets_p.a[set]->frs_n * 1000000 |
|
108 |
|
/ npv_audio_dec_sets_p.a[set]->fr_rate; |
|
109 |
|
++set; |
|
110 |
|
} |
106 |
111 |
npv_audio_dec_sets_unlock(); |
npv_audio_dec_sets_unlock(); |
107 |
|
|
|
108 |
|
pts_delta = pts_max - pts_min; |
|
109 |
|
/* 2 * 0.25s = 500 ms */ |
|
110 |
|
pts_delta_limit = 500 * npv_audio_st_p.tb.den / npv_audio_st_p.tb.num |
|
111 |
|
/ 1000; |
|
112 |
|
if (pts_delta >= pts_delta_limit) |
|
|
112 |
|
/* 250 * 2 ms */ |
|
113 |
|
total_us_threshold = 250 * 2 * 1000; |
|
114 |
|
if (total_us >= total_us_threshold) |
113 |
115 |
return true; |
return true; |
114 |
116 |
return false; |
return false; |
115 |
117 |
} |
} |
116 |
118 |
STATIC void audio(void) { loop /* infinite loop */ |
STATIC void audio(void) { loop /* infinite loop */ |
117 |
119 |
{ |
{ |
118 |
120 |
if (have_enough_predecoded_audio_frs()) { |
if (have_enough_predecoded_audio_frs()) { |
119 |
|
wait(250000000); /* (rate/4)~0.25s */ |
|
|
121 |
|
/* human ear is sensitive to ~20ms crack, make it 16ms */ |
|
122 |
|
wait(16000000); |
120 |
123 |
continue; |
continue; |
121 |
124 |
} |
} |
122 |
125 |
/* can be long, finer-grained locking is done in there */ |
/* can be long, finer-grained locking is done in there */ |
|
... |
... |
STATIC void *audio_thd_entry(void *arg) |
139 |
142 |
/* unreachable */ |
/* unreachable */ |
140 |
143 |
} |
} |
141 |
144 |
/* |
/* |
142 |
|
* same heuristics than for audio. there is some sort of sync due to video fr |
|
143 |
|
* dropping based on "audio now" in the main thd |
|
|
145 |
|
* predecoded video frs are expensive from the perspectives of the cpu and the |
|
146 |
|
* mem hierarchy. |
|
147 |
|
* 1920 * 1080 * 4 bytes = 8MB. I like powers of 2, then 4. |
144 |
148 |
*/ |
*/ |
145 |
149 |
STATIC bool have_enough_predecoded_video_frs(void) |
STATIC bool have_enough_predecoded_video_frs(void) |
146 |
150 |
{ |
{ |
147 |
|
int64_t pts_min; |
|
148 |
|
int64_t pts_max; |
|
149 |
|
int64_t pts_delta; |
|
150 |
|
int64_t pts_delta_limit; |
|
|
151 |
|
bool r; |
151 |
152 |
|
|
152 |
153 |
npv_video_dec_frs_lock(); |
npv_video_dec_frs_lock(); |
153 |
154 |
if (npv_video_dec_frs_p.eof_receive) { |
if (npv_video_dec_frs_p.eof_receive) { |
154 |
|
npv_video_dec_frs_unlock(); |
|
155 |
|
return true; |
|
156 |
|
} else if (npv_video_dec_frs_p.n == 0) { |
|
157 |
|
npv_video_dec_frs_unlock(); |
|
158 |
|
return false; |
|
159 |
|
} |
|
160 |
|
/* from here we have at least 1 video fr */ |
|
161 |
|
/* we presume the video frs are in pts order */ |
|
162 |
|
pts_min = npv_video_dec_frs_p.a[0]->pts; |
|
163 |
|
pts_max = npv_video_dec_frs_p.a[npv_video_dec_frs_p.n - 1]->pts; |
|
|
155 |
|
r = true; |
|
156 |
|
} else if (npv_video_dec_frs_p.n < 4) { |
|
157 |
|
r = false; |
|
158 |
|
} else /* >= 4 */ |
|
159 |
|
r = true; |
164 |
160 |
npv_video_dec_frs_unlock(); |
npv_video_dec_frs_unlock(); |
165 |
|
|
|
166 |
|
pts_delta = pts_max - pts_min; |
|
167 |
|
/* 2 * 0.25s = 500 ms */ |
|
168 |
|
pts_delta_limit = 500 * npv_video_st_p.tb.den / npv_video_st_p.tb.num |
|
169 |
|
/ 1000; |
|
170 |
|
if (pts_delta >= pts_delta_limit) |
|
171 |
|
return true; |
|
172 |
|
return false; |
|
|
161 |
|
return r; |
173 |
162 |
} |
} |
174 |
163 |
STATIC void video(void) { loop /* infinite loop */ |
STATIC void video(void) { loop /* infinite loop */ |
175 |
164 |
{ |
{ |
176 |
165 |
if (have_enough_predecoded_video_frs()) { |
if (have_enough_predecoded_video_frs()) { |
177 |
|
wait(250000000); /* (audio rate/4)~0.25s */ |
|
|
166 |
|
wait(8000000); /* 60fps or 16ms, let's check every 8ms */ |
178 |
167 |
continue; |
continue; |
179 |
168 |
} |
} |
180 |
|
/* can be long, finer-grained locking is done in there */ |
|
181 |
|
npv_video_pkts_send(); |
|
|
169 |
|
/* |
|
170 |
|
* can be long, finer-grained locking is done in there. filling the dec |
|
171 |
|
* bufs should be "faster" than decoding, and we may not have enough |
|
172 |
|
* pkts to fill those bufs, then it should exit without filling up |
|
173 |
|
* mem. |
|
174 |
|
*/ |
|
175 |
|
npv_video_pkts_send(); /* fill the dec bufs */ |
182 |
176 |
npv_video_dec_frs_receive_avail(); |
npv_video_dec_frs_receive_avail(); |
183 |
177 |
}} |
}} |
184 |
178 |
STATIC void *video_thd_entry(void *arg) |
STATIC void *video_thd_entry(void *arg) |
File npv/video/local/code.frag.c changed (mode: 100644) (index 48ef6ab..71655cc) |
... |
... |
STATIC void frs_drop(s64 now) |
335 |
335 |
s64 threshold; |
s64 threshold; |
336 |
336 |
u16 fr; |
u16 fr; |
337 |
337 |
|
|
338 |
|
/* audio can be late up to 0.25s, and audio is 'now' */ |
|
339 |
|
threshold = (250 * st_p.tb.den) / (st_p.tb.num * 1000); |
|
|
338 |
|
/* |
|
339 |
|
* https://en.wikipedia.org/wiki/Audio_to_video_synchronization |
|
340 |
|
* we need to make room in the dec a of predecoded frs, based on the |
|
341 |
|
* previous url (20200922), we abitrary choose -30ms. |
|
342 |
|
*/ |
|
343 |
|
threshold = (30 * st_p.tb.den) / (st_p.tb.num * 1000); |
340 |
344 |
low = now - threshold; |
low = now - threshold; |
341 |
345 |
fr = 0; |
fr = 0; |
342 |
346 |
loop { |
loop { |
|
... |
... |
STATIC void frs_drop(s64 now) |
348 |
352 |
|
|
349 |
353 |
pts = dec_frs_p.a[fr]->pts; |
pts = dec_frs_p.a[fr]->pts; |
350 |
354 |
fr_priv = dec_frs_p.priv_a[fr]; |
fr_priv = dec_frs_p.priv_a[fr]; |
351 |
|
|
|
352 |
355 |
/* keep the fr the scaler is related to */ |
/* keep the fr the scaler is related to */ |
353 |
356 |
if ((dec_frs_p.a[fr] != scaler_p.img.fr) && (pts < low)) { |
if ((dec_frs_p.a[fr] != scaler_p.img.fr) && (pts < low)) { |
354 |
357 |
if (dec_frs_p.a[fr] == last_fr_sent_to_pe_l) |
if (dec_frs_p.a[fr] == last_fr_sent_to_pe_l) |