npv:aspect ratio handling
[nyanmp.git] / npv / video / public / code.frag.c
blob94fbe1f78331e990f7227364024e06eb23c7a012
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 FATALV("unable to get a timer file descriptor:%s\n", strerror(errno));
11 memset(&st_p, 0, sizeof(st_p));
12 pkt_q_p = pkt_q_new("video");
13 dec_ctx_p = 0;
14 r = pthread_mutex_init(&dec_ctx_mutex_l, 0);
15 if (r != 0)
16 FATALV("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 FATALV("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 = NO_FR;
35 aspect.width = 0;
36 aspect.height = 0;
38 /* we are targetting AVUTIL_PIX_FMT_RGB32/sRGB */
39 scaler_p.ctx = thdsws_init_once();
40 if (scaler_p.ctx == 0)
41 FATALVFF("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 FATALVFF("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 FATALVFF("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 FATALVFF("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 FATALVFF("unable to open the decoder context\n");
70 /* we will define the video aspect ratio with those values */
71 aspect.width = params->width;
72 aspect.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 FATALV("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 FATALV("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);
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);
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 POUTVFF("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 FATALVFF("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 pkt_q_unref_all(pkt_q_p);
156 frs_reset();
157 dec_frs_p.eof_receive = false;
158 last_fr_sent_to_pe = 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 FATALV("%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 FATALV("%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 FATALV("%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 FATALV("%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 = 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)
228 return;
229 if (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 loop { /* because the swpchn can change, aka "the win changed" */
236 r = swpchn_next_img(&swpchn_img);
237 if (r == NOT_READY)
238 return;
239 blit_setup(swpchn_img, scaler_dims_changed);
240 r = send_to_pe(swpchn_img);
241 if (r == SENT)
242 break;
243 /* r == SWPCHN_UPDATED */
245 last_fr_sent_to_pe = fr;
246 fr_priv->was_qed_to_pe = true; /* drop detection */
248 #undef NO_FR
249 #undef TS_FROM_CLK_OK
250 #undef READY
251 #undef NOT_READY
252 #undef SENT
253 /* we do per-loop fine-grained locking */
254 #define sz size
255 static void pkts_send(void) { loop
257 int r;
258 avcodec_pkt_ref_t *pr;
260 pkt_q_lock(pkt_q_p);
261 if (pkt_q_p->n == 0)
262 goto unlock_and_return;
263 pr = pkt_q_p->q[0];
264 dec_ctx_lock();
265 r = avcodec_send_pkt(dec_ctx_p, pr);
266 dec_ctx_unlock();
267 if (r == AVERROR(EAGAIN)) /* dec is full and the pkt is rejected */
268 goto unlock_and_return;
269 else if (r == AVUTIL_AVERROR_EOF) /* the dec is in draining mode */
270 goto unlock_and_return;
271 else if (r != 0)
272 FATALV("error while sending a packet to the decoder\n");
273 /* r == 0 */
274 pipeline_limits_lock();
275 pipeline_limits_p.pkts.video_bytes_n -= pr->sz;
276 pipeline_limits_unlock();
278 pkt_q_deq(pkt_q_p);
279 avcodec_pkt_unref(pr);
280 pkt_q_unlock(pkt_q_p);
281 continue;
283 unlock_and_return:
284 pkt_q_unlock(pkt_q_p);
285 return;
287 #undef sz