npv:osd:timer, will add more if pertinent
[nyanmp.git] / npv / video / public / code.frag.c
blobabea91c7ebb136f0ec5a0c2ea796fc2e9d32e282
1 #define NO_FR 0
2 STATIC void init_once_public(void)
4 int r;
6 /* linux bug: still no CLOCK_MONOTONIC_RAW for timerfd */
7 errno = 0;
8 timer_fd_p = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
9 if (timer_fd_p == -1)
10 fatal("unable to get a timer file descriptor:%s\n", strerror(errno));
11 memset(&st_p, 0, sizeof(st_p));
12 pkt_q_p = npv_pkt_q_new("video");
13 dec_ctx_p = 0;
14 r = pthread_mutex_init(&dec_ctx_mutex_l, 0);
15 if (r != 0)
16 fatal("unable to create the mutex for the decoder context\n");
18 dec_frs_p.eof_receive = false;
19 dec_frs_p.n_max = 0;
20 dec_frs_p.n = 0;
21 dec_frs_p.a = 0;
22 dec_frs_p.priv_a = 0;
23 r = pthread_mutex_init(&dec_frs_p.mutex, 0);
24 if (r != 0)
25 fatal("unable to create the mutex for the array of frames\n");
27 scaler_p.img.vk = 0;
28 memset(&scaler_p.img.layout, 0, sizeof(scaler_p.img.layout));
29 scaler_p.img.dev_mem = 0;
30 scaler_p.img.data = 0;
31 scaler_p.img.fr = NO_FR;
33 last_fr_sent_to_pe_l = NO_FR;
35 aspect_ratio.width = 0;
36 aspect_ratio.height = 0;
38 /* we are targetting AVUTIL_PIX_FMT_RGB32/sRGB */
39 scaler_p.ctx = npv_thdsws_init_once();
40 if (scaler_p.ctx == 0)
41 fatalff("scaler:unable to initialize\n");
43 #undef NO_FR
44 STATIC void init_once(void)
46 init_once_public();
47 init_once_local();
49 STATIC void dec_ctx_cfg(avcodec_params_t *params)
51 int r;
53 dec_l = avcodec_find_dec(params->codec_id);
54 if (dec_l == 0)
55 fatalff("unable to find a proper decoder\n");
56 avcodec_free_context(&dec_ctx_p);
57 dec_ctx_p = avcodec_alloc_ctx(dec_l);
58 if (dec_ctx_p == 0)
59 fatalff("unable to allocate an decoder context\n");
60 /* XXX: useless ? */
61 r = avcodec_params_to_ctx(dec_ctx_p, params);
62 if (r < 0)
63 fatalff("unable to apply stream codec parameters in codec context\n");
64 /* XXX: ffmpeg thread count default is 1, set to 0 = auto */
65 dec_ctx_p->thread_count = 0;
66 r = avcodec_open2(dec_ctx_p, dec_l, 0);
67 if (r < 0)
68 fatalff("unable to open the decoder context\n");
70 /* we will define the video aspect ratio with those values */
71 aspect_ratio.width = params->width;
72 aspect_ratio.height = params->height;
74 STATIC void timer_start(void)
76 struct itimerspec t;
77 int r;
79 memset(&t, 0, sizeof(t));
80 /* initial and interval */
81 t.it_value.tv_nsec = 1; /* asap */
82 t.it_interval.tv_nsec = 2000000; /* 2ms */
83 r = timerfd_settime(timer_fd_p, 0, &t, 0);
84 if (r == -1)
85 fatal("unable to arm the timer\n");
87 STATIC void timer_slow_start(void)
89 struct itimerspec t;
90 int r;
92 memset(&t, 0, sizeof(t));
93 /* initial and interval */
94 t.it_value.tv_nsec = 1; /* asap */
95 t.it_interval.tv_nsec = 100000000; /* 100ms */
96 r = timerfd_settime(timer_fd_p, 0, &t, 0);
97 if (r == -1)
98 fatal("unable to arm the timer\n");
100 #define AGAIN 0
101 #define HAVE_FR 1
102 #define EOF_DEC 2
103 STATIC u8 dec_fr_try_receive(void)
105 int r;
107 dec_ctx_lock();
108 r = avcodec_receive_video_fr(dec_ctx_p, receive_fr_l);
109 dec_ctx_unlock();
110 if (r == AVUTIL_AVERROR(EAGAIN))
111 return AGAIN;
112 else if (r == 0) {
113 u16 last;
115 dec_frs_lock();
116 if (dec_frs_p.n == dec_frs_p.n_max)
117 dec_a_grow();
118 last = dec_frs_p.n;
119 avutil_video_fr_ref_move(dec_frs_p.a[last], receive_fr_l);
120 memset(dec_frs_p.priv_a[last], 0, sizeof(**dec_frs_p.priv_a));
121 ++dec_frs_p.n;
122 dec_frs_unlock();
123 return HAVE_FR;
124 } else if (r == AVUTIL_AVERROR_EOF) {
125 poutff("last decoder frame reached (receiving)\n");
126 dec_frs_lock();
127 dec_frs_p.eof_receive = true;
128 dec_frs_unlock();
129 return EOF_DEC;
131 fatalff("error while receiving frame from the decoder\n");
133 #undef AGAIN
134 #undef HAVE_FR
135 #undef EOF_DEC
136 #define AGAIN 0
137 #define HAVE_FR 1
138 #define EOF_DEC 2
139 STATIC void dec_frs_receive_avail(void) { loop
141 u8 r;
143 r = dec_fr_try_receive();
144 if (r == HAVE_FR)
145 continue;
146 else if (r == AGAIN || r == EOF_DEC)
147 break;
149 #undef AGAIN
150 #undef HAVE_FR
151 #undef EOF_DEC
152 #define NO_FR 0
153 STATIC void dec_flush(void)
155 npv_pkt_q_unref_all(pkt_q_p);
156 frs_reset();
157 dec_frs_p.eof_receive = false;
158 last_fr_sent_to_pe_l = NO_FR;
159 avcodec_flush_bufs(dec_ctx_p);
161 #undef NO_FR
162 STATIC void dec_ctx_lock(void)
164 int r;
166 r = pthread_mutex_lock(&dec_ctx_mutex_l);
167 if (r != 0)
168 fatal("%d:unable to lock the video decoder context\n", r);
170 STATIC void dec_ctx_unlock(void)
172 int r;
174 r = pthread_mutex_unlock(&dec_ctx_mutex_l);
175 if (r != 0)
176 fatal("%d:unable to unlock the video decoder context\n", r);
178 STATIC void dec_frs_lock(void)
180 int r;
182 r = pthread_mutex_lock(&dec_frs_p.mutex);
183 if (r != 0)
184 fatal("%d:unable to lock the array of decoder frames\n", r);
186 STATIC void dec_frs_unlock(void)
188 int r;
190 r = pthread_mutex_unlock(&dec_frs_p.mutex);
191 if (r != 0)
192 fatal("%d:unable to unlock the array of decoder frames\n", r);
194 /* go non-blocking or a worker thread is needed */
195 #define NO_FR 0
196 #define TS_FROM_CLK_OK 0
197 #define READY 0
198 #define NOT_READY 1
199 #define SENT 0
200 /* XXX: we do want to lock the frs q the least amount of time as possible */
201 STATIC void timer_evt(void)
203 u8 r;
204 s64 now;
205 avutil_video_fr_ref_t *fr;
206 struct dec_fr_priv_t *fr_priv;
207 bool scaler_dims_changed;
208 u32 swpchn_img;
210 timer_ack();
211 r = npv_clk_get_video_st_ts(&now);
212 if (r != TS_FROM_CLK_OK)
213 return;
214 /* lock --------------------------------------------------------------*/
215 dec_frs_lock();
216 if (dec_frs_p.n == 0) {
217 dec_frs_unlock();
218 return;
220 frs_drop(now);
221 select_fr(now, &fr, &fr_priv);
222 dec_frs_unlock();
223 /* unlock ------------------------------------------------------------*/
224 if (fr == NO_FR)
225 return;
226 /* in pause, we "redraw" the same img all the time */
227 if (!npv_paused_p && fr == last_fr_sent_to_pe_l)
228 return;
229 if (npv_thdsws_is_busy(scaler_p.ctx))
230 return;
231 if (scaler_p.img.fr != fr) {
232 start_scaling(fr, fr_priv, &scaler_dims_changed);
233 return;
235 if (npv_paused_p)
236 npv_video_osd_rop_restore();
237 npv_video_osd_rop_blend(now);
238 loop { /* because the swpchn can change, aka "the win changed" */
239 r = swpchn_next_img(&swpchn_img);
240 if (r == NOT_READY)
241 return;
242 blit_setup(swpchn_img, scaler_dims_changed);
243 r = send_to_pe(swpchn_img);
244 if (r == SENT)
245 break;
246 /* r == SWPCHN_UPDATED */
248 last_fr_sent_to_pe_l = fr;
249 fr_priv->was_qed_to_pe = true; /* drop detection */
251 #undef NO_FR
252 #undef TS_FROM_CLK_OK
253 #undef READY
254 #undef NOT_READY
255 #undef SENT
256 /* we do per-loop fine-grained locking */
257 #define sz size
258 STATIC void pkts_send(void) { loop
260 int r;
261 avcodec_pkt_ref_t *pr;
263 npv_pkt_q_lock(pkt_q_p);
264 if (pkt_q_p->n == 0)
265 goto unlock_and_return;
266 pr = pkt_q_p->q[0];
267 dec_ctx_lock();
268 r = avcodec_send_pkt(dec_ctx_p, pr);
269 dec_ctx_unlock();
270 if (r == AVERROR(EAGAIN)) /* dec is full and the pkt is rejected */
271 goto unlock_and_return;
272 else if (r == AVUTIL_AVERROR_EOF) /* the dec is in draining mode */
273 goto unlock_and_return;
274 else if (r != 0)
275 fatal("error while sending a packet to the decoder\n");
276 /* r == 0 */
277 npv_pipeline_limits_lock();
278 npv_pipeline_limits_p.pkts.video_bytes_n -= pr->sz;
279 npv_pipeline_limits_unlock();
281 npv_pkt_q_deq(pkt_q_p);
282 avcodec_pkt_unref(pr);
283 npv_pkt_q_unlock(pkt_q_p);
284 continue;
286 unlock_and_return:
287 npv_pkt_q_unlock(pkt_q_p);
288 return;
290 #undef sz