2 * VP9 compatible video decoder
4 * Copyright (C) 2013 Ronald S. Bultje <rsbultje gmail com>
5 * Copyright (C) 2013 Clément Bœsch <u pkh me>
7 * This file is part of FFmpeg.
9 * FFmpeg is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * FFmpeg is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with FFmpeg; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 #define ROUNDED_DIV_MVx2(a, b) \
25 (VP56mv) { .x = ROUNDED_DIV(a.x + b.x, 2), .y = ROUNDED_DIV(a.y + b.y, 2) }
26 #define ROUNDED_DIV_MVx4(a, b, c, d) \
27 (VP56mv) { .x = ROUNDED_DIV(a.x + b.x + c.x + d.x, 4), \
28 .y = ROUNDED_DIV(a.y + b.y + c.y + d.y, 4) }
30 static void FN(inter_pred)(AVCodecContext *ctx)
32 static const uint8_t bwlog_tab[2][N_BS_SIZES] = {
33 { 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4 },
34 { 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 4 },
36 VP9Context *s = ctx->priv_data;
38 int row = s->row, col = s->col;
39 ThreadFrame *tref1 = &s->refs[s->refidx[b->ref[0]]], *tref2;
40 AVFrame *ref1 = tref1->f, *ref2;
41 int w1 = ref1->width, h1 = ref1->height, w2, h2;
42 ptrdiff_t ls_y = s->y_stride, ls_uv = s->uv_stride;
45 tref2 = &s->refs[s->refidx[b->ref[1]]];
55 if (b->bs == BS_8x4) {
56 mc_luma_dir(s, mc[3][b->filter][0], s->dst[0], ls_y,
57 ref1->data[0], ref1->linesize[0], tref1,
58 row << 3, col << 3, &b->mv[0][0], 8, 4, w1, h1, 0);
59 mc_luma_dir(s, mc[3][b->filter][0],
60 s->dst[0] + 4 * ls_y, ls_y,
61 ref1->data[0], ref1->linesize[0], tref1,
62 (row << 3) + 4, col << 3, &b->mv[2][0], 8, 4, w1, h1, 0);
63 w1 = (w1 + s->ss_h) >> s->ss_h;
66 uvmv = ROUNDED_DIV_MVx2(b->mv[0][0], b->mv[2][0]);
67 mc_chroma_dir(s, mc[3 + s->ss_h][b->filter][0],
68 s->dst[1], s->dst[2], ls_uv,
69 ref1->data[1], ref1->linesize[1],
70 ref1->data[2], ref1->linesize[2], tref1,
71 row << 2, col << (3 - s->ss_h),
72 &uvmv, 8 >> s->ss_h, 4, w1, h1, 0);
74 mc_chroma_dir(s, mc[3 + s->ss_h][b->filter][0],
75 s->dst[1], s->dst[2], ls_uv,
76 ref1->data[1], ref1->linesize[1],
77 ref1->data[2], ref1->linesize[2], tref1,
78 row << 3, col << (3 - s->ss_h),
79 &b->mv[0][0], 8 >> s->ss_h, 4, w1, h1, 0);
80 // BUG for 4:2:2 bs=8x4, libvpx uses the wrong block index
81 // to get the motion vector for the bottom 4x4 block
82 // https://code.google.com/p/webm/issues/detail?id=993
86 uvmv = ROUNDED_DIV_MVx2(b->mv[0][0], b->mv[2][0]);
88 mc_chroma_dir(s, mc[3 + s->ss_h][b->filter][0],
89 s->dst[1] + 4 * ls_uv, s->dst[2] + 4 * ls_uv, ls_uv,
90 ref1->data[1], ref1->linesize[1],
91 ref1->data[2], ref1->linesize[2], tref1,
92 (row << 3) + 4, col << (3 - s->ss_h),
93 &uvmv, 8 >> s->ss_h, 4, w1, h1, 0);
97 mc_luma_dir(s, mc[3][b->filter][1], s->dst[0], ls_y,
98 ref2->data[0], ref2->linesize[0], tref2,
99 row << 3, col << 3, &b->mv[0][1], 8, 4, w2, h2, 1);
100 mc_luma_dir(s, mc[3][b->filter][1],
101 s->dst[0] + 4 * ls_y, ls_y,
102 ref2->data[0], ref2->linesize[0], tref2,
103 (row << 3) + 4, col << 3, &b->mv[2][1], 8, 4, w2, h2, 1);
104 w2 = (w2 + s->ss_h) >> s->ss_h;
107 uvmv = ROUNDED_DIV_MVx2(b->mv[0][1], b->mv[2][1]);
108 mc_chroma_dir(s, mc[3 + s->ss_h][b->filter][1],
109 s->dst[1], s->dst[2], ls_uv,
110 ref2->data[1], ref2->linesize[1],
111 ref2->data[2], ref2->linesize[2], tref2,
112 row << 2, col << (3 - s->ss_h),
113 &uvmv, 8 >> s->ss_h, 4, w2, h2, 1);
115 mc_chroma_dir(s, mc[3 + s->ss_h][b->filter][1],
116 s->dst[1], s->dst[2], ls_uv,
117 ref2->data[1], ref2->linesize[1],
118 ref2->data[2], ref2->linesize[2], tref2,
119 row << 3, col << (3 - s->ss_h),
120 &b->mv[0][1], 8 >> s->ss_h, 4, w2, h2, 1);
121 // BUG for 4:2:2 bs=8x4, libvpx uses the wrong block index
122 // to get the motion vector for the bottom 4x4 block
123 // https://code.google.com/p/webm/issues/detail?id=993
127 uvmv = ROUNDED_DIV_MVx2(b->mv[0][1], b->mv[2][1]);
129 mc_chroma_dir(s, mc[3 + s->ss_h][b->filter][1],
130 s->dst[1] + 4 * ls_uv, s->dst[2] + 4 * ls_uv, ls_uv,
131 ref2->data[1], ref2->linesize[1],
132 ref2->data[2], ref2->linesize[2], tref2,
133 (row << 3) + 4, col << (3 - s->ss_h),
134 &uvmv, 8 >> s->ss_h, 4, w2, h2, 1);
137 } else if (b->bs == BS_4x8) {
138 mc_luma_dir(s, mc[4][b->filter][0], s->dst[0], ls_y,
139 ref1->data[0], ref1->linesize[0], tref1,
140 row << 3, col << 3, &b->mv[0][0], 4, 8, w1, h1, 0);
141 mc_luma_dir(s, mc[4][b->filter][0], s->dst[0] + 4, ls_y,
142 ref1->data[0], ref1->linesize[0], tref1,
143 row << 3, (col << 3) + 4, &b->mv[1][0], 4, 8, w1, h1, 0);
144 h1 = (h1 + s->ss_v) >> s->ss_v;
147 uvmv = ROUNDED_DIV_MVx2(b->mv[0][0], b->mv[1][0]);
148 mc_chroma_dir(s, mc[4][b->filter][0],
149 s->dst[1], s->dst[2], ls_uv,
150 ref1->data[1], ref1->linesize[1],
151 ref1->data[2], ref1->linesize[2], tref1,
152 row << (3 - s->ss_v), col << 2,
153 &uvmv, 4, 8 >> s->ss_v, w1, h1, 0);
155 mc_chroma_dir(s, mc[4][b->filter][0],
156 s->dst[1], s->dst[2], ls_uv,
157 ref1->data[1], ref1->linesize[1],
158 ref1->data[2], ref1->linesize[2], tref1,
159 row << (3 - s->ss_v), col << 3,
160 &b->mv[0][0], 4, 8 >> s->ss_v, w1, h1, 0);
161 mc_chroma_dir(s, mc[4][b->filter][0],
162 s->dst[1] + 4, s->dst[2] + 4, ls_uv,
163 ref1->data[1], ref1->linesize[1],
164 ref1->data[2], ref1->linesize[2], tref1,
165 row << (3 - s->ss_v), (col << 3) + 4,
166 &b->mv[1][0], 4, 8 >> s->ss_v, w1, h1, 0);
170 mc_luma_dir(s, mc[4][b->filter][1], s->dst[0], ls_y,
171 ref2->data[0], ref2->linesize[0], tref2,
172 row << 3, col << 3, &b->mv[0][1], 4, 8, w2, h2, 1);
173 mc_luma_dir(s, mc[4][b->filter][1], s->dst[0] + 4, ls_y,
174 ref2->data[0], ref2->linesize[0], tref2,
175 row << 3, (col << 3) + 4, &b->mv[1][1], 4, 8, w2, h2, 1);
176 h2 = (h2 + s->ss_v) >> s->ss_v;
179 uvmv = ROUNDED_DIV_MVx2(b->mv[0][1], b->mv[1][1]);
180 mc_chroma_dir(s, mc[4][b->filter][1],
181 s->dst[1], s->dst[2], ls_uv,
182 ref2->data[1], ref2->linesize[1],
183 ref2->data[2], ref2->linesize[2], tref2,
184 row << (3 - s->ss_v), col << 2,
185 &uvmv, 4, 8 >> s->ss_v, w2, h2, 1);
187 mc_chroma_dir(s, mc[4][b->filter][1],
188 s->dst[1], s->dst[2], ls_uv,
189 ref2->data[1], ref2->linesize[1],
190 ref2->data[2], ref2->linesize[2], tref2,
191 row << (3 - s->ss_v), col << 3,
192 &b->mv[0][1], 4, 8 >> s->ss_v, w2, h2, 1);
193 mc_chroma_dir(s, mc[4][b->filter][1],
194 s->dst[1] + 4, s->dst[2] + 4, ls_uv,
195 ref2->data[1], ref2->linesize[1],
196 ref2->data[2], ref2->linesize[2], tref2,
197 row << (3 - s->ss_v), (col << 3) + 4,
198 &b->mv[1][1], 4, 8 >> s->ss_v, w2, h2, 1);
202 av_assert2(b->bs == BS_4x4);
204 // FIXME if two horizontally adjacent blocks have the same MV,
205 // do a w8 instead of a w4 call
206 mc_luma_dir(s, mc[4][b->filter][0], s->dst[0], ls_y,
207 ref1->data[0], ref1->linesize[0], tref1,
208 row << 3, col << 3, &b->mv[0][0], 4, 4, w1, h1, 0);
209 mc_luma_dir(s, mc[4][b->filter][0], s->dst[0] + 4, ls_y,
210 ref1->data[0], ref1->linesize[0], tref1,
211 row << 3, (col << 3) + 4, &b->mv[1][0], 4, 4, w1, h1, 0);
212 mc_luma_dir(s, mc[4][b->filter][0],
213 s->dst[0] + 4 * ls_y, ls_y,
214 ref1->data[0], ref1->linesize[0], tref1,
215 (row << 3) + 4, col << 3, &b->mv[2][0], 4, 4, w1, h1, 0);
216 mc_luma_dir(s, mc[4][b->filter][0],
217 s->dst[0] + 4 * ls_y + 4, ls_y,
218 ref1->data[0], ref1->linesize[0], tref1,
219 (row << 3) + 4, (col << 3) + 4, &b->mv[3][0], 4, 4, w1, h1, 0);
224 uvmv = ROUNDED_DIV_MVx4(b->mv[0][0], b->mv[1][0],
225 b->mv[2][0], b->mv[3][0]);
226 mc_chroma_dir(s, mc[4][b->filter][0],
227 s->dst[1], s->dst[2], ls_uv,
228 ref1->data[1], ref1->linesize[1],
229 ref1->data[2], ref1->linesize[2], tref1,
231 &uvmv, 4, 4, w1, h1, 0);
233 uvmv = ROUNDED_DIV_MVx2(b->mv[0][0], b->mv[2][0]);
234 mc_chroma_dir(s, mc[4][b->filter][0],
235 s->dst[1], s->dst[2], ls_uv,
236 ref1->data[1], ref1->linesize[1],
237 ref1->data[2], ref1->linesize[2], tref1,
239 &uvmv, 4, 4, w1, h1, 0);
240 uvmv = ROUNDED_DIV_MVx2(b->mv[1][0], b->mv[3][0]);
241 mc_chroma_dir(s, mc[4][b->filter][0],
242 s->dst[1] + 4, s->dst[2] + 4, ls_uv,
243 ref1->data[1], ref1->linesize[1],
244 ref1->data[2], ref1->linesize[2], tref1,
245 row << 2, (col << 3) + 4,
246 &uvmv, 4, 4, w1, h1, 0);
251 uvmv = ROUNDED_DIV_MVx2(b->mv[0][0], b->mv[1][0]);
252 mc_chroma_dir(s, mc[4][b->filter][0],
253 s->dst[1], s->dst[2], ls_uv,
254 ref1->data[1], ref1->linesize[1],
255 ref1->data[2], ref1->linesize[2], tref1,
257 &uvmv, 4, 4, w1, h1, 0);
258 // BUG libvpx uses wrong block index for 4:2:2 bs=4x4
260 // https://code.google.com/p/webm/issues/detail?id=993
261 uvmv = ROUNDED_DIV_MVx2(b->mv[1][0], b->mv[2][0]);
262 mc_chroma_dir(s, mc[4][b->filter][0],
263 s->dst[1] + 4 * ls_uv, s->dst[2] + 4 * ls_uv, ls_uv,
264 ref1->data[1], ref1->linesize[1],
265 ref1->data[2], ref1->linesize[2], tref1,
266 (row << 3) + 4, col << 2,
267 &uvmv, 4, 4, w1, h1, 0);
269 mc_chroma_dir(s, mc[4][b->filter][0],
270 s->dst[1], s->dst[2], ls_uv,
271 ref1->data[1], ref1->linesize[1],
272 ref1->data[2], ref1->linesize[2], tref1,
274 &b->mv[0][0], 4, 4, w1, h1, 0);
275 mc_chroma_dir(s, mc[4][b->filter][0],
276 s->dst[1] + 4, s->dst[2] + 4, ls_uv,
277 ref1->data[1], ref1->linesize[1],
278 ref1->data[2], ref1->linesize[2], tref1,
279 row << 3, (col << 3) + 4,
280 &b->mv[1][0], 4, 4, w1, h1, 0);
281 mc_chroma_dir(s, mc[4][b->filter][0],
282 s->dst[1] + 4 * ls_uv, s->dst[2] + 4 * ls_uv, ls_uv,
283 ref1->data[1], ref1->linesize[1],
284 ref1->data[2], ref1->linesize[2], tref1,
285 (row << 3) + 4, col << 3,
286 &b->mv[2][0], 4, 4, w1, h1, 0);
287 mc_chroma_dir(s, mc[4][b->filter][0],
288 s->dst[1] + 4 * ls_uv + 4, s->dst[2] + 4 * ls_uv + 4, ls_uv,
289 ref1->data[1], ref1->linesize[1],
290 ref1->data[2], ref1->linesize[2], tref1,
291 (row << 3) + 4, (col << 3) + 4,
292 &b->mv[3][0], 4, 4, w1, h1, 0);
297 mc_luma_dir(s, mc[4][b->filter][1], s->dst[0], ls_y,
298 ref2->data[0], ref2->linesize[0], tref2,
299 row << 3, col << 3, &b->mv[0][1], 4, 4, w2, h2, 1);
300 mc_luma_dir(s, mc[4][b->filter][1], s->dst[0] + 4, ls_y,
301 ref2->data[0], ref2->linesize[0], tref2,
302 row << 3, (col << 3) + 4, &b->mv[1][1], 4, 4, w2, h2, 1);
303 mc_luma_dir(s, mc[4][b->filter][1],
304 s->dst[0] + 4 * ls_y, ls_y,
305 ref2->data[0], ref2->linesize[0], tref2,
306 (row << 3) + 4, col << 3, &b->mv[2][1], 4, 4, w2, h2, 1);
307 mc_luma_dir(s, mc[4][b->filter][1],
308 s->dst[0] + 4 * ls_y + 4, ls_y,
309 ref2->data[0], ref2->linesize[0], tref2,
310 (row << 3) + 4, (col << 3) + 4, &b->mv[3][1], 4, 4, w2, h2, 1);
315 uvmv = ROUNDED_DIV_MVx4(b->mv[0][1], b->mv[1][1],
316 b->mv[2][1], b->mv[3][1]);
317 mc_chroma_dir(s, mc[4][b->filter][1],
318 s->dst[1], s->dst[2], ls_uv,
319 ref2->data[1], ref2->linesize[1],
320 ref2->data[2], ref2->linesize[2], tref2,
322 &uvmv, 4, 4, w2, h2, 1);
324 uvmv = ROUNDED_DIV_MVx2(b->mv[0][1], b->mv[2][1]);
325 mc_chroma_dir(s, mc[4][b->filter][1],
326 s->dst[1], s->dst[2], ls_uv,
327 ref2->data[1], ref2->linesize[1],
328 ref2->data[2], ref2->linesize[2], tref2,
330 &uvmv, 4, 4, w2, h2, 1);
331 uvmv = ROUNDED_DIV_MVx2(b->mv[1][1], b->mv[3][1]);
332 mc_chroma_dir(s, mc[4][b->filter][1],
333 s->dst[1] + 4, s->dst[2] + 4, ls_uv,
334 ref2->data[1], ref2->linesize[1],
335 ref2->data[2], ref2->linesize[2], tref2,
336 row << 2, (col << 3) + 4,
337 &uvmv, 4, 4, w2, h2, 1);
342 uvmv = ROUNDED_DIV_MVx2(b->mv[0][1], b->mv[1][1]);
343 mc_chroma_dir(s, mc[4][b->filter][1],
344 s->dst[1], s->dst[2], ls_uv,
345 ref2->data[1], ref2->linesize[1],
346 ref2->data[2], ref2->linesize[2], tref2,
348 &uvmv, 4, 4, w2, h2, 1);
349 // BUG libvpx uses wrong block index for 4:2:2 bs=4x4
351 // https://code.google.com/p/webm/issues/detail?id=993
352 uvmv = ROUNDED_DIV_MVx2(b->mv[1][1], b->mv[2][1]);
353 mc_chroma_dir(s, mc[4][b->filter][1],
354 s->dst[1] + 4 * ls_uv, s->dst[2] + 4 * ls_uv, ls_uv,
355 ref2->data[1], ref2->linesize[1],
356 ref2->data[2], ref2->linesize[2], tref2,
357 (row << 3) + 4, col << 2,
358 &uvmv, 4, 4, w2, h2, 1);
360 mc_chroma_dir(s, mc[4][b->filter][1],
361 s->dst[1], s->dst[2], ls_uv,
362 ref2->data[1], ref2->linesize[1],
363 ref2->data[2], ref2->linesize[2], tref2,
365 &b->mv[0][1], 4, 4, w2, h2, 1);
366 mc_chroma_dir(s, mc[4][b->filter][1],
367 s->dst[1] + 4, s->dst[2] + 4, ls_uv,
368 ref2->data[1], ref2->linesize[1],
369 ref2->data[2], ref2->linesize[2], tref2,
370 row << 3, (col << 3) + 4,
371 &b->mv[1][1], 4, 4, w2, h2, 1);
372 mc_chroma_dir(s, mc[4][b->filter][1],
373 s->dst[1] + 4 * ls_uv, s->dst[2] + 4 * ls_uv, ls_uv,
374 ref2->data[1], ref2->linesize[1],
375 ref2->data[2], ref2->linesize[2], tref2,
376 (row << 3) + 4, col << 3,
377 &b->mv[2][1], 4, 4, w2, h2, 1);
378 mc_chroma_dir(s, mc[4][b->filter][1],
379 s->dst[1] + 4 * ls_uv + 4, s->dst[2] + 4 * ls_uv + 4, ls_uv,
380 ref2->data[1], ref2->linesize[1],
381 ref2->data[2], ref2->linesize[2], tref2,
382 (row << 3) + 4, (col << 3) + 4,
383 &b->mv[3][1], 4, 4, w2, h2, 1);
389 int bwl = bwlog_tab[0][b->bs];
390 int bw = bwh_tab[0][b->bs][0] * 4, bh = bwh_tab[0][b->bs][1] * 4;
391 int uvbw = bwh_tab[s->ss_h][b->bs][0] * 4, uvbh = bwh_tab[s->ss_v][b->bs][1] * 4;
393 mc_luma_dir(s, mc[bwl][b->filter][0], s->dst[0], ls_y,
394 ref1->data[0], ref1->linesize[0], tref1,
395 row << 3, col << 3, &b->mv[0][0], bw, bh, w1, h1, 0);
396 w1 = (w1 + s->ss_h) >> s->ss_h;
397 h1 = (h1 + s->ss_v) >> s->ss_v;
398 mc_chroma_dir(s, mc[bwl + s->ss_h][b->filter][0],
399 s->dst[1], s->dst[2], ls_uv,
400 ref1->data[1], ref1->linesize[1],
401 ref1->data[2], ref1->linesize[2], tref1,
402 row << (3 - s->ss_v), col << (3 - s->ss_h),
403 &b->mv[0][0], uvbw, uvbh, w1, h1, 0);
406 mc_luma_dir(s, mc[bwl][b->filter][1], s->dst[0], ls_y,
407 ref2->data[0], ref2->linesize[0], tref2,
408 row << 3, col << 3, &b->mv[0][1], bw, bh, w2, h2, 1);
409 w2 = (w2 + s->ss_h) >> s->ss_h;
410 h2 = (h2 + s->ss_v) >> s->ss_v;
411 mc_chroma_dir(s, mc[bwl + s->ss_h][b->filter][1],
412 s->dst[1], s->dst[2], ls_uv,
413 ref2->data[1], ref2->linesize[1],
414 ref2->data[2], ref2->linesize[2], tref2,
415 row << (3 - s->ss_v), col << (3 - s->ss_h),
416 &b->mv[0][1], uvbw, uvbh, w2, h2, 1);