Coverage Report

Created: 2026-05-30 06:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/libde265/libde265/motion.cc
Line
Count
Source
1
/*
2
 * H.265 video codec.
3
 * Copyright (c) 2013-2014 struktur AG, Dirk Farin <farin@struktur.de>
4
 *
5
 * This file is part of libde265.
6
 *
7
 * libde265 is free software: you can redistribute it and/or modify
8
 * it under the terms of the GNU Lesser General Public License as
9
 * published by the Free Software Foundation, either version 3 of
10
 * the License, or (at your option) any later version.
11
 *
12
 * libde265 is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public License
18
 * along with libde265.  If not, see <http://www.gnu.org/licenses/>.
19
 */
20
21
#include "motion.h"
22
#include "decctx.h"
23
#include "util.h"
24
#include "dpb.h"
25
26
#include <assert.h>
27
28
29
#include <sys/types.h>
30
#include <signal.h>
31
#include <string.h>
32
33
#if defined(_MSC_VER) || defined(__MINGW32__)
34
# include <malloc.h>
35
#elif defined(HAVE_ALLOCA_H)
36
# include <alloca.h>
37
#endif
38
39
40
0
#define MAX_CU_SIZE 64
41
42
43
static int extra_before[4] = { 0,3,3,2 };
44
static int extra_after [4] = { 0,3,4,4 };
45
46
47
48
template <class pixel_t>
49
void mc_luma(const base_context* ctx,
50
             const seq_parameter_set* sps, int mv_x, int mv_y,
51
             int xP,int yP,
52
             int16_t* out, int out_stride,
53
             const pixel_t* ref, int ref_stride,
54
             int nPbW, int nPbH, int bitDepth_L)
55
0
{
56
0
  int xFracL = mv_x & 3;
57
0
  int yFracL = mv_y & 3;
58
59
0
  int xIntOffsL = xP + (mv_x>>2);
60
0
  int yIntOffsL = yP + (mv_y>>2);
61
62
  // luma sample interpolation process (8.5.3.2.2.1)
63
64
  //const int shift1 = sps->BitDepth_Y-8;
65
  //const int shift2 = 6;
66
0
  const int shift3 = std::max(2, 14 - sps->BitDepth_Y);
67
68
0
  int w = sps->pic_width_in_luma_samples;
69
0
  int h = sps->pic_height_in_luma_samples;
70
71
0
  ALIGNED_16(int16_t) mcbuffer[MAX_CU_SIZE * (MAX_CU_SIZE+7)];
72
73
0
  if (xFracL==0 && yFracL==0) {
74
75
0
    if (xIntOffsL >= 0 && yIntOffsL >= 0 &&
76
0
        nPbW+xIntOffsL <= w && nPbH+yIntOffsL <= h) {
77
78
0
      ctx->acceleration.put_hevc_qpel(out, out_stride,
79
0
                                      &ref[yIntOffsL*ref_stride + xIntOffsL],
80
0
                                      ref_stride /* sizeof(pixel_t)*/,
81
0
                                      nPbW,nPbH, mcbuffer, 0,0, bitDepth_L);
82
0
    }
83
0
    else {
84
0
      for (int y=0;y<nPbH;y++)
85
0
        for (int x=0;x<nPbW;x++) {
86
87
0
          int xA = Clip3(0,w-1,x + xIntOffsL);
88
0
          int yA = Clip3(0,h-1,y + yIntOffsL);
89
90
0
          out[y*out_stride+x] = ref[ xA + yA*ref_stride ] << shift3;
91
0
        }
92
0
    }
93
94
#ifdef DE265_LOG_TRACE
95
    logtrace(LogMotion,"---MC luma %d %d = direct---\n",xFracL,yFracL);
96
97
    for (int y=0;y<nPbH;y++) {
98
      for (int x=0;x<nPbW;x++) {
99
100
        int xA = Clip3(0,w-1,x + xIntOffsL);
101
        int yA = Clip3(0,h-1,y + yIntOffsL);
102
103
        logtrace(LogMotion,"%02x ", ref[ xA + yA*ref_stride ]);
104
      }
105
      logtrace(LogMotion,"\n");
106
    }
107
108
    logtrace(LogMotion," -> \n");
109
110
    for (int y=0;y<nPbH;y++) {
111
      for (int x=0;x<nPbW;x++) {
112
113
        logtrace(LogMotion,"%02x ",out[y*out_stride+x] >> 6); // 6 will be used when summing predictions
114
      }
115
      logtrace(LogMotion,"\n");
116
    }
117
#endif
118
0
  }
119
0
  else {
120
0
    int extra_left   = extra_before[xFracL];
121
0
    int extra_right  = extra_after [xFracL];
122
0
    int extra_top    = extra_before[yFracL];
123
0
    int extra_bottom = extra_after [yFracL];
124
125
    //int nPbW_extra = extra_left + nPbW + extra_right;
126
    //int nPbH_extra = extra_top  + nPbH + extra_bottom;
127
128
129
0
    pixel_t padbuf[(MAX_CU_SIZE+16)*(MAX_CU_SIZE+7)];
130
131
0
    const pixel_t* src_ptr;
132
0
    int src_stride;
133
134
0
    if (-extra_left + xIntOffsL >= 0 &&
135
0
        -extra_top  + yIntOffsL >= 0 &&
136
0
        nPbW+extra_right  + xIntOffsL < w &&
137
0
        nPbH+extra_bottom + yIntOffsL < h) {
138
0
      src_ptr = &ref[xIntOffsL + yIntOffsL*ref_stride];
139
0
      src_stride = ref_stride;
140
0
    }
141
0
    else {
142
      // Extend fill width to a multiple of 16 so that SIMD over-reads
143
      // in qpel interpolation hit valid (edge-clamped) data.
144
0
      int fill_width = ((extra_left + nPbW + extra_right + 15) & ~15);
145
0
      if (fill_width > MAX_CU_SIZE+16) fill_width = MAX_CU_SIZE+16;
146
147
0
      for (int y=-extra_top;y<nPbH+extra_bottom;y++) {
148
0
        for (int x=-extra_left;x<fill_width - extra_left;x++) {
149
150
0
          int xA = Clip3(0,w-1,x + xIntOffsL);
151
0
          int yA = Clip3(0,h-1,y + yIntOffsL);
152
153
0
          padbuf[x+extra_left + (y+extra_top)*(MAX_CU_SIZE+16)] = ref[ xA + yA*ref_stride ];
154
0
        }
155
0
      }
156
157
0
      src_ptr = &padbuf[extra_top*(MAX_CU_SIZE+16) + extra_left];
158
0
      src_stride = MAX_CU_SIZE+16;
159
0
    }
160
161
0
    ctx->acceleration.put_hevc_qpel(out, out_stride,
162
0
                                    src_ptr, src_stride /* sizeof(pixel_t) */,
163
0
                                    nPbW,nPbH, mcbuffer, xFracL,yFracL, bitDepth_L);
164
165
166
0
    logtrace(LogMotion,"---V---\n");
167
0
    for (int y=0;y<nPbH;y++) {
168
0
      for (int x=0;x<nPbW;x++) {
169
0
        logtrace(LogMotion,"%04x ",out[x+y*out_stride]);
170
0
      }
171
0
      logtrace(LogMotion,"\n");
172
0
    }
173
0
  }
174
0
}
Unexecuted instantiation: void mc_luma<unsigned short>(base_context const*, seq_parameter_set const*, int, int, int, int, short*, int, unsigned short const*, int, int, int, int)
Unexecuted instantiation: void mc_luma<unsigned char>(base_context const*, seq_parameter_set const*, int, int, int, int, short*, int, unsigned char const*, int, int, int, int)
175
176
177
178
template <class pixel_t>
179
void mc_chroma(const base_context* ctx,
180
               const seq_parameter_set* sps,
181
               int mv_x, int mv_y,
182
               int xP,int yP,
183
               int16_t* out, int out_stride,
184
               const pixel_t* ref, int ref_stride,
185
               int nPbWC, int nPbHC, int bit_depth_C)
186
0
{
187
  // chroma sample interpolation process (8.5.3.2.2.2)
188
189
  //const int shift1 = sps->BitDepth_C-8;
190
  //const int shift2 = 6;
191
0
  const int shift3 = std::max(2, 14 - sps->BitDepth_C);
192
193
0
  int wC = sps->pic_width_in_luma_samples /sps->SubWidthC;
194
0
  int hC = sps->pic_height_in_luma_samples/sps->SubHeightC;
195
196
0
  mv_x *= 2 / sps->SubWidthC;
197
0
  mv_y *= 2 / sps->SubHeightC;
198
199
0
  int xFracC = mv_x & 7;
200
0
  int yFracC = mv_y & 7;
201
202
0
  int xIntOffsC = xP/sps->SubWidthC  + (mv_x>>3);
203
0
  int yIntOffsC = yP/sps->SubHeightC + (mv_y>>3);
204
205
0
  ALIGNED_32(int16_t mcbuffer[MAX_CU_SIZE*(MAX_CU_SIZE+7)]);
206
207
0
  if (xFracC == 0 && yFracC == 0) {
208
0
    if (xIntOffsC>=0 && nPbWC+xIntOffsC<=wC &&
209
0
        yIntOffsC>=0 && nPbHC+yIntOffsC<=hC) {
210
0
      ctx->acceleration.put_hevc_epel(out, out_stride,
211
0
                                      &ref[xIntOffsC + yIntOffsC*ref_stride], ref_stride,
212
0
                                      nPbWC,nPbHC, 0,0, nullptr, bit_depth_C);
213
0
    }
214
0
    else
215
0
      {
216
0
        for (int y=0;y<nPbHC;y++)
217
0
          for (int x=0;x<nPbWC;x++) {
218
219
0
            int xB = Clip3(0,wC-1,x + xIntOffsC);
220
0
            int yB = Clip3(0,hC-1,y + yIntOffsC);
221
222
0
            out[y*out_stride+x] = ref[ xB + yB*ref_stride ] << shift3;
223
0
          }
224
0
      }
225
0
  }
226
0
  else {
227
0
    pixel_t padbuf[(MAX_CU_SIZE+16)*(MAX_CU_SIZE+3)];
228
229
0
    const pixel_t* src_ptr;
230
0
    int src_stride;
231
232
0
    int extra_top  = 1;
233
0
    int extra_left = 1;
234
0
    int extra_right  = 2;
235
0
    int extra_bottom = 2;
236
237
0
    if (xIntOffsC>=1 && nPbWC+xIntOffsC<=wC-2 &&
238
0
        yIntOffsC>=1 && nPbHC+yIntOffsC<=hC-2) {
239
0
      src_ptr = &ref[xIntOffsC + yIntOffsC*ref_stride];
240
0
      src_stride = ref_stride;
241
0
    }
242
0
    else {
243
      // Extend fill width to a multiple of 16 so that SIMD over-reads
244
      // in epel interpolation hit valid (edge-clamped) data.
245
0
      int fill_width = ((extra_left + nPbWC + extra_right + 15) & ~15);
246
0
      if (fill_width > MAX_CU_SIZE+16) fill_width = MAX_CU_SIZE+16;
247
248
0
      for (int y=-extra_top;y<nPbHC+extra_bottom;y++) {
249
0
        for (int x=-extra_left;x<fill_width - extra_left;x++) {
250
251
0
          int xA = Clip3(0,wC-1,x + xIntOffsC);
252
0
          int yA = Clip3(0,hC-1,y + yIntOffsC);
253
254
0
          padbuf[x+extra_left + (y+extra_top)*(MAX_CU_SIZE+16)] = ref[ xA + yA*ref_stride ];
255
0
        }
256
0
      }
257
258
0
      src_ptr = &padbuf[extra_left + extra_top*(MAX_CU_SIZE+16)];
259
0
      src_stride = MAX_CU_SIZE+16;
260
0
    }
261
262
263
0
    if (xFracC && yFracC) {
264
0
      ctx->acceleration.put_hevc_epel_hv(out, out_stride,
265
0
                                         src_ptr, src_stride,
266
0
                                         nPbWC,nPbHC, xFracC,yFracC, mcbuffer, bit_depth_C);
267
0
    }
268
0
    else if (xFracC) {
269
0
      ctx->acceleration.put_hevc_epel_h(out, out_stride,
270
0
                                        src_ptr, src_stride,
271
0
                                        nPbWC,nPbHC, xFracC,yFracC, mcbuffer, bit_depth_C);
272
0
    }
273
0
    else if (yFracC) {
274
0
      ctx->acceleration.put_hevc_epel_v(out, out_stride,
275
0
                                        src_ptr, src_stride,
276
0
                                        nPbWC,nPbHC, xFracC,yFracC, mcbuffer, bit_depth_C);
277
0
    }
278
0
    else {
279
0
      assert(false); // full-pel shifts are handled above
280
0
    }
281
0
  }
282
0
}
Unexecuted instantiation: void mc_chroma<unsigned short>(base_context const*, seq_parameter_set const*, int, int, int, int, short*, int, unsigned short const*, int, int, int, int)
Unexecuted instantiation: void mc_chroma<unsigned char>(base_context const*, seq_parameter_set const*, int, int, int, int, short*, int, unsigned char const*, int, int, int, int)
283
284
285
286
// 8.5.3.2
287
// NOTE: for full-pel shifts, we can introduce a fast path, simply copying without shifts
288
void generate_inter_prediction_samples(base_context* ctx,
289
                                       const slice_segment_header* shdr,
290
                                       de265_image* img,
291
                                       int xC,int yC,
292
                                       int xB,int yB,
293
                                       int nCS, int nPbW,int nPbH,
294
                                       const PBMotion* vi)
295
0
{
296
0
  int xP = xC+xB;
297
0
  int yP = yC+yB;
298
299
0
  void*  pixels[3];
300
0
  int    stride[3];
301
302
0
  const pic_parameter_set* pps = shdr->pps.get();
303
0
  const seq_parameter_set* sps = pps->sps.get();
304
305
0
  if (sps->BitDepth_Y != img->get_bit_depth(0) ||
306
0
      sps->BitDepth_C != img->get_bit_depth(1)) {
307
0
    img->integrity = INTEGRITY_DECODING_ERRORS;
308
0
    ctx->add_warning(DE265_WARNING_BIT_DEPTH_OF_CURRENT_IMAGE_DOES_NOT_MATCH_SPS, false);
309
0
    return;
310
0
  }
311
312
0
  if (sps->chroma_format_idc != img->get_chroma_format()) {
313
0
    img->integrity = INTEGRITY_DECODING_ERRORS;
314
0
    ctx->add_warning(DE265_WARNING_CHROMA_OF_CURRENT_IMAGE_DOES_NOT_MATCH_SPS, false);
315
0
    return;
316
0
  }
317
318
0
  const int SubWidthC  = sps->SubWidthC;
319
0
  const int SubHeightC = sps->SubHeightC;
320
321
0
  pixels[0] = img->get_image_plane_at_pos_any_depth(0,xP,yP);
322
0
  stride[0] = img->get_image_stride(0);
323
324
0
  pixels[1] = img->get_image_plane_at_pos_any_depth(1,xP/SubWidthC,yP/SubHeightC);
325
0
  stride[1] = img->get_image_stride(1);
326
327
0
  pixels[2] = img->get_image_plane_at_pos_any_depth(2,xP/SubWidthC,yP/SubHeightC);
328
0
  stride[2] = img->get_image_stride(2);
329
330
331
0
  ALIGNED_16(int16_t) predSamplesL                 [2 /* LX */][MAX_CU_SIZE* MAX_CU_SIZE];
332
0
  ALIGNED_16(int16_t) predSamplesC[2 /* chroma */ ][2 /* LX */][MAX_CU_SIZE* MAX_CU_SIZE];
333
334
  //int xP = xC+xB;
335
  //int yP = yC+yB;
336
337
0
  int predFlag[2];
338
0
  predFlag[0] = vi->predFlag[0];
339
0
  predFlag[1] = vi->predFlag[1];
340
341
0
  const int bit_depth_L = sps->BitDepth_Y;
342
0
  const int bit_depth_C = sps->BitDepth_C;
343
344
  // Some encoders use bi-prediction with two similar MVs.
345
  // Identify this case and use only one MV.
346
347
  // do this only without weighted prediction, because the weights/offsets may be different
348
0
  if (pps->weighted_pred_flag==0) {
349
0
    if (predFlag[0] && predFlag[1]) {
350
0
      if (vi->mv[0].x == vi->mv[1].x &&
351
0
          vi->mv[0].y == vi->mv[1].y &&
352
0
          shdr->RefPicList[0][vi->refIdx[0]] ==
353
0
          shdr->RefPicList[1][vi->refIdx[1]]) {
354
0
        predFlag[1] = 0;
355
0
      }
356
0
    }
357
0
  }
358
359
360
  // Fill prediction samples with mid-grey in intermediate precision.
361
  // Used on error paths where the reference picture is unavailable or mismatched.
362
0
  auto fill_pred_samples = [&](int l) {
363
0
    const int16_t fill = 1 << 13; // mid-grey: (1 << (bd-1)) << (14-bd) for any bd
364
0
    for (int y = 0; y < nPbH; y++)
365
0
      for (int x = 0; x < nPbW; x++)
366
0
        predSamplesL[l][y * nCS + x] = fill;
367
0
    if (img->get_chroma_format() != de265_chroma_mono) {
368
0
      int cW = nPbW / SubWidthC;
369
0
      int cH = nPbH / SubHeightC;
370
0
      for (int y = 0; y < cH; y++)
371
0
        for (int x = 0; x < cW; x++) {
372
0
          predSamplesC[0][l][y * nCS + x] = fill;
373
0
          predSamplesC[1][l][y * nCS + x] = fill;
374
0
        }
375
0
    }
376
0
  };
377
378
0
  for (int l=0;l<2;l++) {
379
0
    if (predFlag[l]) {
380
      // 8.5.3.2.1
381
382
0
      const de265_image* refPic = ctx->get_image(shdr->RefPicList[l][vi->refIdx[l]]);
383
384
0
      logtrace(LogMotion, "refIdx: %d -> dpb[%d]\n", vi->refIdx[l], shdr->RefPicList[l][vi->refIdx[l]]);
385
386
0
      if (!refPic || refPic->PicState == UnusedForReference) {
387
0
        img->integrity = INTEGRITY_DECODING_ERRORS;
388
0
        ctx->add_warning(DE265_WARNING_NONEXISTING_REFERENCE_PICTURE_ACCESSED, false);
389
0
        fill_pred_samples(l);
390
0
      }
391
0
      else if (refPic->get_width(0) != sps->pic_width_in_luma_samples ||
392
0
               refPic->get_height(0) != sps->pic_height_in_luma_samples ||
393
0
               img->get_chroma_format() != refPic->get_chroma_format()) {
394
0
        img->integrity = INTEGRITY_DECODING_ERRORS;
395
0
        ctx->add_warning(DE265_WARNING_REFERENCE_IMAGE_SIZE_DOES_NOT_MATCH_SPS, false);
396
0
        fill_pred_samples(l);
397
0
      }
398
0
      else if (img->get_bit_depth(0) != refPic->get_bit_depth(0) ||
399
0
               img->get_bit_depth(1) != refPic->get_bit_depth(1)) {
400
0
        img->integrity = INTEGRITY_DECODING_ERRORS;
401
0
        ctx->add_warning(DE265_WARNING_REFERENCE_IMAGE_BIT_DEPTH_DOES_NOT_MATCH, false);
402
0
        fill_pred_samples(l);
403
0
      }
404
0
      else if (img->get_chroma_format() != refPic->get_chroma_format()) {
405
0
        img->integrity = INTEGRITY_DECODING_ERRORS;
406
0
        ctx->add_warning(DE265_WARNING_REFERENCE_IMAGE_CHROMA_FORMAT_DOES_NOT_MATCH, false);
407
0
        fill_pred_samples(l);
408
0
      }
409
0
      else {
410
        // 8.5.3.2.2
411
412
0
        logtrace(LogMotion,"do MC: L%d,MV=%d;%d RefPOC=%d\n",
413
0
                 l,vi->mv[l].x,vi->mv[l].y,refPic->PicOrderCntVal);
414
415
416
        // TODO: must predSamples stride really be nCS or can it be something smaller like nPbW?
417
418
0
        if (img->high_bit_depth(0)) {
419
0
          mc_luma(ctx, sps, vi->mv[l].x, vi->mv[l].y, xP,yP,
420
0
                  predSamplesL[l],nCS,
421
0
                  (const uint16_t*)refPic->get_image_plane(0),
422
0
                  refPic->get_luma_stride(), nPbW,nPbH, bit_depth_L);
423
0
        }
424
0
        else {
425
0
          mc_luma(ctx, sps, vi->mv[l].x, vi->mv[l].y, xP,yP,
426
0
                  predSamplesL[l],nCS,
427
0
                  (const uint8_t*)refPic->get_image_plane(0),
428
0
                  refPic->get_luma_stride(), nPbW,nPbH, bit_depth_L);
429
0
        }
430
431
0
        if (img->get_chroma_format() != de265_chroma_mono) {
432
0
          if (img->high_bit_depth(1)) {
433
0
            mc_chroma(ctx, sps, vi->mv[l].x, vi->mv[l].y, xP, yP,
434
0
                      predSamplesC[0][l], nCS, (const uint16_t*) refPic->get_image_plane(1),
435
0
                      refPic->get_chroma_stride(), nPbW / SubWidthC, nPbH / SubHeightC, bit_depth_C);
436
0
            mc_chroma(ctx, sps, vi->mv[l].x, vi->mv[l].y, xP, yP,
437
0
                      predSamplesC[1][l], nCS, (const uint16_t*) refPic->get_image_plane(2),
438
0
                      refPic->get_chroma_stride(), nPbW / SubWidthC, nPbH / SubHeightC, bit_depth_C);
439
0
          }
440
0
          else {
441
0
            mc_chroma(ctx, sps, vi->mv[l].x, vi->mv[l].y, xP, yP,
442
0
                      predSamplesC[0][l], nCS, (const uint8_t*) refPic->get_image_plane(1),
443
0
                      refPic->get_chroma_stride(), nPbW / SubWidthC, nPbH / SubHeightC, bit_depth_C);
444
0
            mc_chroma(ctx, sps, vi->mv[l].x, vi->mv[l].y, xP, yP,
445
0
                      predSamplesC[1][l], nCS, (const uint8_t*) refPic->get_image_plane(2),
446
0
                      refPic->get_chroma_stride(), nPbW / SubWidthC, nPbH / SubHeightC, bit_depth_C);
447
0
          }
448
0
        }
449
0
      }
450
0
    }
451
0
  }
452
453
454
  // weighted sample prediction  (8.5.3.2.3)
455
456
0
  const int shift1_L = std::max(2,14-sps->BitDepth_Y);
457
0
  const int offset_shift1_L = img->get_sps().WpOffsetBdShiftY;
458
0
  const int shift1_C = std::max(2,14-sps->BitDepth_C);
459
0
  const int offset_shift1_C = img->get_sps().WpOffsetBdShiftC;
460
461
  /*
462
  const int shift1_L = 14-img->sps.BitDepth_Y;
463
  const int offset_shift1_L = img->sps.BitDepth_Y-8;
464
  const int shift1_C = 14-img->sps.BitDepth_C;
465
  const int offset_shift1_C = img->sps.BitDepth_C-8;
466
  */
467
468
  /*
469
  if (0)
470
  printf("%d/%d %d/%d %d/%d %d/%d\n",
471
         shift1_L,
472
         Nshift1_L,
473
         offset_shift1_L,
474
         Noffset_shift1_L,
475
         shift1_C,
476
         Nshift1_C,
477
         offset_shift1_C,
478
         Noffset_shift1_C);
479
480
  assert(shift1_L==
481
         Nshift1_L);
482
  assert(offset_shift1_L==
483
         Noffset_shift1_L);
484
  assert(shift1_C==
485
         Nshift1_C);
486
  assert(offset_shift1_C==
487
         Noffset_shift1_C);
488
  */
489
490
491
0
  logtrace(LogMotion,"predFlags (modified): %d %d\n", predFlag[0], predFlag[1]);
492
493
0
  if (shdr->slice_type == SLICE_TYPE_P) {
494
0
    if (pps->weighted_pred_flag==0) {
495
0
      if (predFlag[0]==1 && predFlag[1]==0) {
496
0
        ctx->acceleration.put_unweighted_pred(pixels[0], stride[0],
497
0
                                              predSamplesL[0],nCS, nPbW,nPbH, bit_depth_L);
498
499
0
        if (img->get_chroma_format() != de265_chroma_mono) {
500
0
          ctx->acceleration.put_unweighted_pred(pixels[1], stride[1],
501
0
                                                predSamplesC[0][0], nCS,
502
0
                                                nPbW / SubWidthC, nPbH / SubHeightC, bit_depth_C);
503
0
          ctx->acceleration.put_unweighted_pred(pixels[2], stride[2],
504
0
                                                predSamplesC[1][0], nCS,
505
0
                                                nPbW / SubWidthC, nPbH / SubHeightC, bit_depth_C);
506
0
        }
507
0
      }
508
0
      else {
509
0
        ctx->add_warning(DE265_WARNING_BOTH_PREDFLAGS_ZERO, false);
510
0
        img->integrity = INTEGRITY_DECODING_ERRORS;
511
0
      }
512
0
    }
513
0
    else {
514
      // weighted prediction
515
516
0
      if (predFlag[0]==1 && predFlag[1]==0) {
517
518
0
        int refIdx0 = vi->refIdx[0];
519
520
0
        int luma_log2WD   = shdr->luma_log2_weight_denom + shift1_L;
521
0
        int chroma_log2WD = shdr->ChromaLog2WeightDenom  + shift1_C;
522
523
0
        int luma_w0 = shdr->LumaWeight[0][refIdx0];
524
0
        int luma_o0 = shdr->luma_offset[0][refIdx0] * (1<<(offset_shift1_L));
525
526
0
        int chroma0_w0 = shdr->ChromaWeight[0][refIdx0][0];
527
0
        int chroma0_o0 = shdr->ChromaOffset[0][refIdx0][0] * (1<<(offset_shift1_C));
528
0
        int chroma1_w0 = shdr->ChromaWeight[0][refIdx0][1];
529
0
        int chroma1_o0 = shdr->ChromaOffset[0][refIdx0][1] * (1<<(offset_shift1_C));
530
531
0
        logtrace(LogMotion,"weighted-0 [%d] %d %d %d  %dx%d\n", refIdx0, luma_log2WD-6,luma_w0,luma_o0,nPbW,nPbH);
532
533
0
        ctx->acceleration.put_weighted_pred(pixels[0], stride[0],
534
0
                                            predSamplesL[0],nCS, nPbW,nPbH,
535
0
                                            luma_w0, luma_o0, luma_log2WD, bit_depth_L);
536
0
        if (img->get_chroma_format() != de265_chroma_mono) {
537
0
          ctx->acceleration.put_weighted_pred(pixels[1], stride[1],
538
0
                                              predSamplesC[0][0], nCS, nPbW / SubWidthC, nPbH / SubHeightC,
539
0
                                              chroma0_w0, chroma0_o0, chroma_log2WD, bit_depth_C);
540
0
          ctx->acceleration.put_weighted_pred(pixels[2], stride[2],
541
0
                                              predSamplesC[1][0], nCS, nPbW / SubWidthC, nPbH / SubHeightC,
542
0
                                              chroma1_w0, chroma1_o0, chroma_log2WD, bit_depth_C);
543
0
        }
544
0
      }
545
0
      else {
546
0
        ctx->add_warning(DE265_WARNING_BOTH_PREDFLAGS_ZERO, false);
547
0
        img->integrity = INTEGRITY_DECODING_ERRORS;
548
0
      }
549
0
    }
550
0
  }
551
0
  else {
552
0
    assert(shdr->slice_type == SLICE_TYPE_B);
553
554
0
    if (predFlag[0]==1 && predFlag[1]==1) {
555
0
      if (pps->weighted_bipred_flag==0) {
556
        //const int shift2  = 15-8; // TODO: real bit depth
557
        //const int offset2 = 1<<(shift2-1);
558
559
0
        int16_t* in0 = predSamplesL[0];
560
0
        int16_t* in1 = predSamplesL[1];
561
562
0
        ctx->acceleration.put_weighted_pred_avg(pixels[0], stride[0],
563
0
                                                in0,in1, nCS, nPbW, nPbH, bit_depth_L);
564
565
0
        int16_t* in00 = predSamplesC[0][0];
566
0
        int16_t* in01 = predSamplesC[0][1];
567
0
        int16_t* in10 = predSamplesC[1][0];
568
0
        int16_t* in11 = predSamplesC[1][1];
569
570
0
        if (img->get_chroma_format() != de265_chroma_mono) {
571
0
          ctx->acceleration.put_weighted_pred_avg(pixels[1], stride[1],
572
0
                                                  in00, in01, nCS,
573
0
                                                  nPbW / SubWidthC, nPbH / SubHeightC, bit_depth_C);
574
0
          ctx->acceleration.put_weighted_pred_avg(pixels[2], stride[2],
575
0
                                                  in10, in11, nCS,
576
0
                                                  nPbW / SubWidthC, nPbH / SubHeightC, bit_depth_C);
577
0
        }
578
0
      }
579
0
      else {
580
        // weighted prediction
581
582
0
        int refIdx0 = vi->refIdx[0];
583
0
        int refIdx1 = vi->refIdx[1];
584
585
0
        int luma_log2WD   = shdr->luma_log2_weight_denom + shift1_L;
586
0
        int chroma_log2WD = shdr->ChromaLog2WeightDenom + shift1_C;
587
588
0
        int luma_w0 = shdr->LumaWeight[0][refIdx0];
589
0
        int luma_o0 = shdr->luma_offset[0][refIdx0] * (1<<(offset_shift1_L));
590
0
        int luma_w1 = shdr->LumaWeight[1][refIdx1];
591
0
        int luma_o1 = shdr->luma_offset[1][refIdx1] * (1<<(offset_shift1_L));
592
593
0
        int chroma0_w0 = shdr->ChromaWeight[0][refIdx0][0];
594
0
        int chroma0_o0 = shdr->ChromaOffset[0][refIdx0][0] * (1<<(offset_shift1_C));
595
0
        int chroma1_w0 = shdr->ChromaWeight[0][refIdx0][1];
596
0
        int chroma1_o0 = shdr->ChromaOffset[0][refIdx0][1] * (1<<(offset_shift1_C));
597
0
        int chroma0_w1 = shdr->ChromaWeight[1][refIdx1][0];
598
0
        int chroma0_o1 = shdr->ChromaOffset[1][refIdx1][0] * (1<<(offset_shift1_C));
599
0
        int chroma1_w1 = shdr->ChromaWeight[1][refIdx1][1];
600
0
        int chroma1_o1 = shdr->ChromaOffset[1][refIdx1][1] * (1<<(offset_shift1_C));
601
602
0
        logtrace(LogMotion,"weighted-BI-0 [%d] %d %d %d  %dx%d\n", refIdx0, luma_log2WD-6,luma_w0,luma_o0,nPbW,nPbH);
603
0
        logtrace(LogMotion,"weighted-BI-1 [%d] %d %d %d  %dx%d\n", refIdx1, luma_log2WD-6,luma_w1,luma_o1,nPbW,nPbH);
604
605
0
        int16_t* in0 = predSamplesL[0];
606
0
        int16_t* in1 = predSamplesL[1];
607
608
0
        ctx->acceleration.put_weighted_bipred(pixels[0], stride[0],
609
0
                                              in0,in1, nCS, nPbW, nPbH,
610
0
                                              luma_w0,luma_o0,
611
0
                                              luma_w1,luma_o1,
612
0
                                              luma_log2WD, bit_depth_L);
613
614
0
        int16_t* in00 = predSamplesC[0][0];
615
0
        int16_t* in01 = predSamplesC[0][1];
616
0
        int16_t* in10 = predSamplesC[1][0];
617
0
        int16_t* in11 = predSamplesC[1][1];
618
619
0
        if (img->get_chroma_format() != de265_chroma_mono) {
620
0
          ctx->acceleration.put_weighted_bipred(pixels[1], stride[1],
621
0
                                                in00, in01, nCS, nPbW / SubWidthC, nPbH / SubHeightC,
622
0
                                                chroma0_w0, chroma0_o0,
623
0
                                                chroma0_w1, chroma0_o1,
624
0
                                                chroma_log2WD, bit_depth_C);
625
0
          ctx->acceleration.put_weighted_bipred(pixels[2], stride[2],
626
0
                                                in10, in11, nCS, nPbW / SubWidthC, nPbH / SubHeightC,
627
0
                                                chroma1_w0, chroma1_o0,
628
0
                                                chroma1_w1, chroma1_o1,
629
0
                                                chroma_log2WD, bit_depth_C);
630
0
        }
631
0
      }
632
0
    }
633
0
    else if (predFlag[0]==1 || predFlag[1]==1) {
634
0
      int l = predFlag[0] ? 0 : 1;
635
636
0
      if (pps->weighted_bipred_flag==0) {
637
0
        ctx->acceleration.put_unweighted_pred(pixels[0], stride[0],
638
0
                                              predSamplesL[l],nCS, nPbW,nPbH, bit_depth_L);
639
640
0
        if (img->get_chroma_format() != de265_chroma_mono) {
641
0
          ctx->acceleration.put_unweighted_pred(pixels[1], stride[1],
642
0
                                                predSamplesC[0][l], nCS,
643
0
                                                nPbW / SubWidthC, nPbH / SubHeightC, bit_depth_C);
644
0
          ctx->acceleration.put_unweighted_pred(pixels[2], stride[2],
645
0
                                                predSamplesC[1][l], nCS,
646
0
                                                nPbW / SubWidthC, nPbH / SubHeightC, bit_depth_C);
647
0
        }
648
0
      }
649
0
      else {
650
0
        int refIdx = vi->refIdx[l];
651
652
0
        int luma_log2WD   = shdr->luma_log2_weight_denom + shift1_L;
653
0
        int chroma_log2WD = shdr->ChromaLog2WeightDenom  + shift1_C;
654
655
0
        int luma_w = shdr->LumaWeight[l][refIdx];
656
0
        int luma_o = shdr->luma_offset[l][refIdx] * (1<<(offset_shift1_L));
657
658
0
        int chroma0_w = shdr->ChromaWeight[l][refIdx][0];
659
0
        int chroma0_o = shdr->ChromaOffset[l][refIdx][0] * (1<<(offset_shift1_C));
660
0
        int chroma1_w = shdr->ChromaWeight[l][refIdx][1];
661
0
        int chroma1_o = shdr->ChromaOffset[l][refIdx][1] * (1<<(offset_shift1_C));
662
663
0
        logtrace(LogMotion,"weighted-B-L%d [%d] %d %d %d  %dx%d\n", l, refIdx, luma_log2WD-6,luma_w,luma_o,nPbW,nPbH);
664
665
0
        ctx->acceleration.put_weighted_pred(pixels[0], stride[0],
666
0
                                            predSamplesL[l],nCS, nPbW,nPbH,
667
0
                                            luma_w, luma_o, luma_log2WD, bit_depth_L);
668
669
0
        if (img->get_chroma_format() != de265_chroma_mono) {
670
0
          ctx->acceleration.put_weighted_pred(pixels[1], stride[1],
671
0
                                              predSamplesC[0][l], nCS,
672
0
                                              nPbW / SubWidthC, nPbH / SubHeightC,
673
0
                                              chroma0_w, chroma0_o, chroma_log2WD, bit_depth_C);
674
0
          ctx->acceleration.put_weighted_pred(pixels[2], stride[2],
675
0
                                              predSamplesC[1][l], nCS,
676
0
                                              nPbW / SubWidthC, nPbH / SubHeightC,
677
0
                                              chroma1_w, chroma1_o, chroma_log2WD, bit_depth_C);
678
0
        }
679
0
      }
680
0
    }
681
0
    else {
682
      // TODO: check why it can actually happen that both predFlags[] are false.
683
      // For now, we ignore this and continue decoding.
684
685
0
      ctx->add_warning(DE265_WARNING_BOTH_PREDFLAGS_ZERO, false);
686
0
      img->integrity = INTEGRITY_DECODING_ERRORS;
687
0
    }
688
0
  }
689
690
#if defined(DE265_LOG_TRACE) && 0
691
  logtrace(LogTransform,"MC pixels (luma), position %d %d:\n", xP,yP);
692
693
  for (int y=0;y<nPbH;y++) {
694
    logtrace(LogTransform,"MC-y-%d-%d ",xP,yP+y);
695
696
    for (int x=0;x<nPbW;x++) {
697
      logtrace(LogTransform,"*%02x ", pixels[0][x+y*stride[0]]);
698
    }
699
700
    logtrace(LogTransform,"*\n");
701
  }
702
703
704
  logtrace(LogTransform,"MC pixels (chroma cb), position %d %d:\n", xP/2,yP/2);
705
706
  for (int y=0;y<nPbH/2;y++) {
707
    logtrace(LogTransform,"MC-cb-%d-%d ",xP/2,yP/2+y);
708
709
    for (int x=0;x<nPbW/2;x++) {
710
      logtrace(LogTransform,"*%02x ", pixels[1][x+y*stride[1]]);
711
    }
712
713
    logtrace(LogTransform,"*\n");
714
  }
715
716
717
  logtrace(LogTransform,"MC pixels (chroma cr), position %d %d:\n", xP/2,yP/2);
718
719
  for (int y=0;y<nPbH/2;y++) {
720
    logtrace(LogTransform,"MC-cr-%d-%d ",xP/2,yP/2+y);
721
722
    for (int x=0;x<nPbW/2;x++) {
723
      logtrace(LogTransform,"*%02x ", pixels[2][x+y*stride[2]]);
724
    }
725
726
    logtrace(LogTransform,"*\n");
727
  }
728
#endif
729
0
}
730
731
732
#ifdef DE265_LOG_TRACE
733
void logmvcand(const PBMotion& p)
734
{
735
  for (int v=0;v<2;v++) {
736
    if (p.predFlag[v]) {
737
      logtrace(LogMotion,"  %d: %s  %d;%d ref=%d\n", v, p.predFlag[v] ? "yes":"no ",
738
               p.mv[v].x,p.mv[v].y, p.refIdx[v]);
739
    } else {
740
      logtrace(LogMotion,"  %d: %s  --;-- ref=--\n", v, p.predFlag[v] ? "yes":"no ");
741
    }
742
  }
743
}
744
#else
745
#define logmvcand(p)
746
#endif
747
748
749
bool PBMotion::operator==(const PBMotion& b) const
750
0
{
751
0
  const PBMotion& a = *this;
752
753
  // TODO: is this really correct? no check for predFlag? Standard says so... (p.127)
754
755
0
  for (int i=0;i<2;i++) {
756
0
    if (a.predFlag[i] != b.predFlag[i]) return false;
757
758
0
    if (a.predFlag[i]) {
759
0
      if (a.mv[i].x != b.mv[i].x) return false;
760
0
      if (a.mv[i].y != b.mv[i].y) return false;
761
0
      if (a.refIdx[i] != b.refIdx[i]) return false;
762
0
    }
763
0
  }
764
765
0
  return true;
766
0
}
767
768
769
class MotionVectorAccess_de265_image : public MotionVectorAccess
770
{
771
public:
772
0
  MotionVectorAccess_de265_image(const de265_image* i) : img(i) { }
773
774
0
  enum PartMode get_PartMode(int x,int y) const override { return img->get_PartMode(x,y); }
775
0
  const PBMotion& get_mv_info(int x,int y) const override { return img->get_mv_info(x,y); }
776
777
private:
778
  const de265_image* img;
779
};
780
781
782
783
/*
784
  +--+                +--+--+
785
  |B2|                |B1|B0|
786
  +--+----------------+--+--+
787
     |                   |
788
     |                   |
789
     |                   |
790
     |                   |
791
     |        PB         |
792
     |                   |
793
     |                   |
794
  +--+                   |
795
  |A1|                   |
796
  +--+-------------------+
797
  |A0|
798
  +--+
799
*/
800
801
802
// 8.5.3.1.2
803
// TODO: check: can we fill the candidate list directly in this function and omit to copy later
804
/*
805
  xC/yC:  CB position
806
  nCS:    CB size                 (probably modified because of singleMCLFlag)
807
  xP/yP:  PB position (absolute)  (probably modified because of singleMCLFlag)
808
  singleMCLFlag
809
  nPbW/nPbH: PB size
810
  partIdx
811
  out_cand: merging candidate vectors
812
813
  Add these candidates:
814
  - A1
815
  - B1  (if != A1)
816
  - B0  (if != B1)
817
  - A0  (if != A1)
818
  - B2  (if != A1 and != B1)
819
820
  A maximum of 4 candidates are generated.
821
822
  Note 1: For a CB split into two PBs, it does not make sense to merge the
823
  second part to the parameters of the first part, since then, we could use 2Nx2N
824
  right away. -> Exclude this candidate.
825
*/
826
int derive_spatial_merging_candidates(//const de265_image* img,
827
                                      const MotionVectorAccess& mvaccess,
828
                                      const de265_image* img,
829
                                      int xC, int yC, int nCS, int xP, int yP,
830
                                      uint8_t singleMCLFlag,
831
                                      int nPbW, int nPbH,
832
                                      int partIdx,
833
                                      PBMotion* out_cand,
834
                                      int maxCandidates)
835
0
{
836
0
  const pic_parameter_set* pps = &img->get_pps();
837
0
  const int log2_parallel_merge_level = pps->log2_parallel_merge_level;
838
839
0
  enum PartMode PartMode = mvaccess.get_PartMode(xC,yC);
840
841
  /*
842
  const int A0 = SpatialMergingCandidates::PRED_A0;
843
  const int A1 = SpatialMergingCandidates::PRED_A1;
844
  const int B0 = SpatialMergingCandidates::PRED_B0;
845
  const int B1 = SpatialMergingCandidates::PRED_B1;
846
  const int B2 = SpatialMergingCandidates::PRED_B2;
847
  */
848
849
  // --- A1 ---
850
851
  // a pixel within A1 (bottom right of A1)
852
0
  int xA1 = xP-1;
853
0
  int yA1 = yP+nPbH-1;
854
855
0
  bool availableA1;
856
0
  int idxA1;
857
858
0
  int computed_candidates = 0;
859
860
  // check if candidate is in same motion-estimation region (MER) -> discard
861
0
  if ((xP>>log2_parallel_merge_level) == (xA1>>log2_parallel_merge_level) &&
862
0
      (yP>>log2_parallel_merge_level) == (yA1>>log2_parallel_merge_level)) {
863
0
    availableA1 = false;
864
0
    logtrace(LogMotion,"spatial merging candidate A1: below parallel merge level\n");
865
0
  }
866
  // redundant candidate? (Note 1) -> discard
867
0
  else if (// !singleMCLFlag &&    automatically true when partIdx==1
868
0
           partIdx==1 &&
869
0
           (PartMode==PART_Nx2N ||
870
0
            PartMode==PART_nLx2N ||
871
0
            PartMode==PART_nRx2N)) {
872
0
    availableA1 = false;
873
0
    logtrace(LogMotion,"spatial merging candidate A1: second part ignore\n");
874
0
  }
875
  // MV available in A1
876
0
  else {
877
0
    availableA1 = img->available_pred_blk(xC,yC, nCS, xP,yP, nPbW,nPbH,partIdx, xA1,yA1);
878
0
    if (!availableA1) logtrace(LogMotion,"spatial merging candidate A1: unavailable\n");
879
0
  }
880
881
0
  if (availableA1) {
882
0
    idxA1 = computed_candidates++;
883
0
    out_cand[idxA1] = mvaccess.get_mv_info(xA1,yA1);
884
885
0
    logtrace(LogMotion,"spatial merging candidate A1:\n");
886
0
    logmvcand(out_cand[idxA1]);
887
0
  }
888
889
0
  if (computed_candidates>=maxCandidates) return computed_candidates;
890
891
892
  // --- B1 ---
893
894
0
  int xB1 = xP+nPbW-1;
895
0
  int yB1 = yP-1;
896
897
0
  bool availableB1;
898
0
  int idxB1;
899
900
  // same MER -> discard
901
0
  if ((xP>>log2_parallel_merge_level) == (xB1>>log2_parallel_merge_level) &&
902
0
      (yP>>log2_parallel_merge_level) == (yB1>>log2_parallel_merge_level)) {
903
0
    availableB1 = false;
904
0
    logtrace(LogMotion,"spatial merging candidate B1: below parallel merge level\n");
905
0
  }
906
  // redundant candidate (Note 1) -> discard
907
0
  else if (// !singleMCLFlag &&    automatically true when partIdx==1
908
0
           partIdx==1 &&
909
0
           (PartMode==PART_2NxN ||
910
0
            PartMode==PART_2NxnU ||
911
0
            PartMode==PART_2NxnD)) {
912
0
    availableB1 = false;
913
0
    logtrace(LogMotion,"spatial merging candidate B1: second part ignore\n");
914
0
  }
915
  // MV available in B1
916
0
  else {
917
0
    availableB1 = img->available_pred_blk(xC,yC, nCS, xP,yP, nPbW,nPbH,partIdx, xB1,yB1);
918
0
    if (!availableB1) logtrace(LogMotion,"spatial merging candidate B1: unavailable\n");
919
0
  }
920
921
0
  if (availableB1) {
922
0
    const PBMotion& b1 = img->get_mv_info(xB1,yB1);
923
924
    // B1 == A1 -> discard B1
925
0
    if (availableA1 && out_cand[idxA1] == b1) {
926
0
      idxB1 = idxA1;
927
0
      logtrace(LogMotion,"spatial merging candidate B1: redundant to A1\n");
928
0
    }
929
0
    else {
930
0
      idxB1 = computed_candidates++;
931
0
      out_cand[idxB1] = b1;
932
933
0
      logtrace(LogMotion,"spatial merging candidate B1:\n");
934
0
      logmvcand(out_cand[idxB1]);
935
0
    }
936
0
  }
937
938
0
  if (computed_candidates>=maxCandidates) return computed_candidates;
939
940
941
  // --- B0 ---
942
943
0
  int xB0 = xP+nPbW;
944
0
  int yB0 = yP-1;
945
946
0
  bool availableB0;
947
0
  int idxB0;
948
949
0
  if ((xP>>log2_parallel_merge_level) == (xB0>>log2_parallel_merge_level) &&
950
0
      (yP>>log2_parallel_merge_level) == (yB0>>log2_parallel_merge_level)) {
951
0
    availableB0 = false;
952
0
    logtrace(LogMotion,"spatial merging candidate B0: below parallel merge level\n");
953
0
  }
954
0
  else {
955
0
    availableB0 = img->available_pred_blk(xC,yC, nCS, xP,yP, nPbW,nPbH,partIdx, xB0,yB0);
956
0
    if (!availableB0) logtrace(LogMotion,"spatial merging candidate B0: unavailable\n");
957
0
  }
958
959
0
  if (availableB0) {
960
0
    const PBMotion& b0 = img->get_mv_info(xB0,yB0);
961
962
    // B0 == B1 -> discard B0
963
0
    if (availableB1 && out_cand[idxB1]==b0) {
964
0
      idxB0 = idxB1;
965
0
      logtrace(LogMotion,"spatial merging candidate B0: redundant to B1\n");
966
0
    }
967
0
    else {
968
0
      idxB0 = computed_candidates++;
969
0
      out_cand[idxB0] = b0;
970
0
      logtrace(LogMotion,"spatial merging candidate B0:\n");
971
0
      logmvcand(out_cand[idxB0]);
972
0
    }
973
0
  }
974
975
0
  if (computed_candidates>=maxCandidates) return computed_candidates;
976
977
978
  // --- A0 ---
979
980
0
  int xA0 = xP-1;
981
0
  int yA0 = yP+nPbH;
982
983
0
  bool availableA0;
984
0
  int idxA0;
985
986
0
  if ((xP>>log2_parallel_merge_level) == (xA0>>log2_parallel_merge_level) &&
987
0
      (yP>>log2_parallel_merge_level) == (yA0>>log2_parallel_merge_level)) {
988
0
    availableA0 = false;
989
0
    logtrace(LogMotion,"spatial merging candidate A0: below parallel merge level\n");
990
0
  }
991
0
  else {
992
0
    availableA0 = img->available_pred_blk(xC,yC, nCS, xP,yP, nPbW,nPbH,partIdx, xA0,yA0);
993
0
    if (!availableA0) logtrace(LogMotion,"spatial merging candidate A0: unavailable\n");
994
0
  }
995
996
0
  if (availableA0) {
997
0
    const PBMotion& a0 = img->get_mv_info(xA0,yA0);
998
999
    // A0 == A1 -> discard A0
1000
0
    if (availableA1 && out_cand[idxA1]==a0) {
1001
0
      idxA0 = idxA1;
1002
0
      logtrace(LogMotion,"spatial merging candidate A0: redundant to A1\n");
1003
0
    }
1004
0
    else {
1005
0
      idxA0 = computed_candidates++;
1006
0
      out_cand[idxA0] = a0;
1007
0
      logtrace(LogMotion,"spatial merging candidate A0:\n");
1008
0
      logmvcand(out_cand[idxA0]);
1009
0
    }
1010
0
  }
1011
1012
0
  if (computed_candidates>=maxCandidates) return computed_candidates;
1013
1014
1015
  // --- B2 ---
1016
1017
0
  int xB2 = xP-1;
1018
0
  int yB2 = yP-1;
1019
1020
0
  bool availableB2;
1021
0
  int idxB2;
1022
1023
  // if we already have four candidates, do not consider B2 anymore
1024
0
  if (computed_candidates==4) {
1025
0
    availableB2 = false;
1026
0
    logtrace(LogMotion,"spatial merging candidate B2: ignore\n");
1027
0
  }
1028
0
  else if ((xP>>log2_parallel_merge_level) == (xB2>>log2_parallel_merge_level) &&
1029
0
           (yP>>log2_parallel_merge_level) == (yB2>>log2_parallel_merge_level)) {
1030
0
    availableB2 = false;
1031
0
    logtrace(LogMotion,"spatial merging candidate B2: below parallel merge level\n");
1032
0
  }
1033
0
  else {
1034
0
    availableB2 = img->available_pred_blk(xC,yC, nCS, xP,yP, nPbW,nPbH,partIdx, xB2,yB2);
1035
0
    if (!availableB2) logtrace(LogMotion,"spatial merging candidate B2: unavailable\n");
1036
0
  }
1037
1038
0
  if (availableB2) {
1039
0
    const PBMotion& b2 = img->get_mv_info(xB2,yB2);
1040
1041
    // B2 == B1 -> discard B2
1042
0
    if (availableB1 && out_cand[idxB1]==b2) {
1043
0
      idxB2 = idxB1;
1044
0
      logtrace(LogMotion,"spatial merging candidate B2: redundant to B1\n");
1045
0
    }
1046
    // B2 == A1 -> discard B2
1047
0
    else if (availableA1 && out_cand[idxA1]==b2) {
1048
0
      idxB2 = idxA1;
1049
0
      logtrace(LogMotion,"spatial merging candidate B2: redundant to A1\n");
1050
0
    }
1051
0
    else {
1052
0
      idxB2 = computed_candidates++;
1053
0
      out_cand[idxB2] = b2;
1054
0
      logtrace(LogMotion,"spatial merging candidate B2:\n");
1055
0
      logmvcand(out_cand[idxB2]);
1056
0
    }
1057
0
  }
1058
1059
0
  return computed_candidates;
1060
0
}
1061
1062
1063
// 8.5.3.1.4
1064
void derive_zero_motion_vector_candidates(const slice_segment_header* shdr,
1065
                                          PBMotion* out_mergeCandList,
1066
                                          int* inout_numCurrMergeCand,
1067
                                          int maxCandidates)
1068
0
{
1069
0
  logtrace(LogMotion,"derive_zero_motion_vector_candidates\n");
1070
1071
0
  int numRefIdx;
1072
1073
0
  if (shdr->slice_type==SLICE_TYPE_P) {
1074
0
    numRefIdx = shdr->num_ref_idx_l0_active;
1075
0
  }
1076
0
  else {
1077
0
    numRefIdx = std::min(shdr->num_ref_idx_l0_active,
1078
0
                             shdr->num_ref_idx_l1_active);
1079
0
  }
1080
1081
1082
  //int numInputMergeCand = *inout_numMergeCand;
1083
0
  int zeroIdx = 0;
1084
1085
0
  while (*inout_numCurrMergeCand < maxCandidates) {
1086
    // 1.
1087
1088
0
    logtrace(LogMotion,"zeroIdx:%d numRefIdx:%d\n", zeroIdx, numRefIdx);
1089
1090
0
    PBMotion* newCand = &out_mergeCandList[*inout_numCurrMergeCand];
1091
1092
0
    const int refIdx = (zeroIdx < numRefIdx) ? zeroIdx : 0;
1093
1094
0
    if (shdr->slice_type==SLICE_TYPE_P) {
1095
0
      newCand->refIdx[0] = refIdx;
1096
0
      newCand->refIdx[1] = 0;
1097
0
      newCand->predFlag[0] = 1;
1098
0
      newCand->predFlag[1] = 0;
1099
0
    }
1100
0
    else {
1101
0
      newCand->refIdx[0] = refIdx;
1102
0
      newCand->refIdx[1] = refIdx;
1103
0
      newCand->predFlag[0] = 1;
1104
0
      newCand->predFlag[1] = 1;
1105
0
    }
1106
1107
0
    newCand->mv[0].x = 0;
1108
0
    newCand->mv[0].y = 0;
1109
0
    newCand->mv[1].x = 0;
1110
0
    newCand->mv[1].y = 0;
1111
1112
0
    (*inout_numCurrMergeCand)++;
1113
1114
    // 2.
1115
1116
0
    zeroIdx++;
1117
0
  }
1118
0
}
1119
1120
1121
bool scale_mv(MotionVector* out_mv, MotionVector mv, int colDist, int currDist)
1122
0
{
1123
0
  int td = Clip3(-128,127, colDist);
1124
0
  int tb = Clip3(-128,127, currDist);
1125
1126
0
  if (td==0) {
1127
0
    *out_mv = mv;
1128
0
    return false;
1129
0
  }
1130
0
  else {
1131
0
    int tx = (16384 + (std::abs(td)>>1)) / td;
1132
0
    int distScaleFactor = Clip3(-4096,4095, (tb*tx+32)>>6);
1133
0
    out_mv->x = Clip3(-32768,32767,
1134
0
                      Sign(distScaleFactor*mv.x)*((std::abs(distScaleFactor*mv.x)+127)>>8));
1135
0
    out_mv->y = Clip3(-32768,32767,
1136
0
                      Sign(distScaleFactor*mv.y)*((std::abs(distScaleFactor*mv.y)+127)>>8));
1137
0
    return true;
1138
0
  }
1139
0
}
1140
1141
1142
// (L1003) 8.5.3.2.8
1143
1144
void derive_collocated_motion_vectors(base_context* ctx,
1145
                                      de265_image* img,
1146
                                      const slice_segment_header* shdr,
1147
                                      int xP,int yP,
1148
                                      int colPic,
1149
                                      int xColPb,int yColPb,
1150
                                      int refIdxLX,  // (always 0 for merge mode)
1151
                                      int X,
1152
                                      MotionVector* out_mvLXCol,
1153
                                      uint8_t* out_availableFlagLXCol)
1154
0
{
1155
0
  logtrace(LogMotion,"derive_collocated_motion_vectors %d;%d\n",xP,yP);
1156
1157
1158
  // get collocated image and the prediction mode at the collocated position
1159
1160
0
  assert(ctx->has_image(colPic));
1161
0
  const de265_image* colImg = ctx->get_image(colPic);
1162
1163
  // check for access outside image area
1164
1165
0
  if (xColPb >= colImg->get_width() ||
1166
0
      yColPb >= colImg->get_height()) {
1167
0
    ctx->add_warning(DE265_WARNING_COLLOCATED_MOTION_VECTOR_OUTSIDE_IMAGE_AREA, false);
1168
0
    *out_availableFlagLXCol = 0;
1169
0
    return;
1170
0
  }
1171
1172
0
  enum PredMode predMode = colImg->get_pred_mode(xColPb,yColPb);
1173
1174
1175
  // collocated block is Intra -> no collocated MV
1176
1177
0
  if (predMode == MODE_INTRA) {
1178
0
    out_mvLXCol->x = 0;
1179
0
    out_mvLXCol->y = 0;
1180
0
    *out_availableFlagLXCol = 0;
1181
0
    return;
1182
0
  }
1183
1184
1185
0
  logtrace(LogMotion,"colPic:%d (POC=%d) X:%d refIdxLX:%d refpiclist:%d\n",
1186
0
           colPic,
1187
0
           colImg->PicOrderCntVal,
1188
0
           X,refIdxLX,shdr->RefPicList[X][refIdxLX]);
1189
1190
1191
  // collocated reference image is unavailable -> no collocated MV
1192
1193
0
  if (colImg->integrity == INTEGRITY_UNAVAILABLE_REFERENCE) {
1194
0
    out_mvLXCol->x = 0;
1195
0
    out_mvLXCol->y = 0;
1196
0
    *out_availableFlagLXCol = 0;
1197
0
    return;
1198
0
  }
1199
1200
1201
  // get the collocated MV
1202
1203
0
  const PBMotion& mvi = colImg->get_mv_info(xColPb,yColPb);
1204
0
  int listCol;
1205
0
  int refIdxCol;
1206
0
  MotionVector mvCol;
1207
1208
0
  logtrace(LogMotion,"read MVI %d;%d:\n",xColPb,yColPb);
1209
0
  logmvcand(mvi);
1210
1211
1212
  // collocated MV uses only L1 -> use L1
1213
0
  if (mvi.predFlag[0]==0) {
1214
0
    mvCol = mvi.mv[1];
1215
0
    refIdxCol = mvi.refIdx[1];
1216
0
    listCol = 1;
1217
0
  }
1218
  // collocated MV uses only L0 -> use L0
1219
0
  else if (mvi.predFlag[1]==0) {
1220
0
    mvCol = mvi.mv[0];
1221
0
    refIdxCol = mvi.refIdx[0];
1222
0
    listCol = 0;
1223
0
  }
1224
  // collocated MV uses L0 and L1
1225
0
  else {
1226
0
    bool allRefFramesBeforeCurrentFrame = true;
1227
1228
0
    const int currentPOC = img->PicOrderCntVal;
1229
1230
    // all reference POCs earlier than current POC (list 1)
1231
    // Test L1 first, because there is a higher change to find a future reference frame.
1232
1233
0
    for (int rIdx=0; rIdx<shdr->num_ref_idx_l1_active && allRefFramesBeforeCurrentFrame; rIdx++)
1234
0
      {
1235
0
        const de265_image* refimg = ctx->get_image(shdr->RefPicList[1][rIdx]);
1236
0
        int refPOC = refimg->PicOrderCntVal;
1237
1238
0
        if (refPOC > currentPOC) {
1239
0
          allRefFramesBeforeCurrentFrame = false;
1240
0
        }
1241
0
      }
1242
1243
    // all reference POCs earlier than current POC (list 0)
1244
1245
0
    for (int rIdx=0; rIdx<shdr->num_ref_idx_l0_active && allRefFramesBeforeCurrentFrame; rIdx++)
1246
0
      {
1247
0
        const de265_image* refimg = ctx->get_image(shdr->RefPicList[0][rIdx]);
1248
0
        int refPOC = refimg->PicOrderCntVal;
1249
1250
0
        if (refPOC > currentPOC) {
1251
0
          allRefFramesBeforeCurrentFrame = false;
1252
0
        }
1253
0
      }
1254
1255
1256
    /* TODO: What is the rationale behind this ???
1257
1258
       My guess:
1259
       when there are images before the current frame (most probably in L0) and images after
1260
       the current frame (most probably in L1), we take the reference in the opposite
1261
       direction than where the collocated frame is positioned in the hope that the distance
1262
       to the current frame will be smaller and thus give a better prediction.
1263
1264
       If all references point into the past, we cannot say much about the temporal order or
1265
       L0,L1 and thus take over both parts.
1266
     */
1267
1268
0
    if (allRefFramesBeforeCurrentFrame) {
1269
0
      mvCol = mvi.mv[X];
1270
0
      refIdxCol = mvi.refIdx[X];
1271
0
      listCol = X;
1272
0
    }
1273
0
    else {
1274
0
      int N = shdr->collocated_from_l0_flag;
1275
0
      mvCol = mvi.mv[N];
1276
0
      refIdxCol = mvi.refIdx[N];
1277
0
      listCol = N;
1278
0
    }
1279
0
  }
1280
1281
1282
1283
0
  uint16_t slice_hdr_idx = colImg->get_SliceHeaderIndex(xColPb,yColPb);
1284
0
  if (slice_hdr_idx >= colImg->slices.size()) {
1285
0
    ctx->add_warning(DE265_WARNING_INVALID_SLICE_HEADER_INDEX_ACCESS, false);
1286
1287
0
    *out_availableFlagLXCol = 0;
1288
0
    out_mvLXCol->x = 0;
1289
0
    out_mvLXCol->y = 0;
1290
0
    return;
1291
0
  }
1292
1293
0
  const slice_segment_header* colShdr = colImg->slices[ colImg->get_SliceHeaderIndex(xColPb,yColPb) ];
1294
1295
0
  if (shdr->LongTermRefPic[X][refIdxLX] !=
1296
0
      colShdr->LongTermRefPic[listCol][refIdxCol]) {
1297
0
    *out_availableFlagLXCol = 0;
1298
0
    out_mvLXCol->x = 0;
1299
0
    out_mvLXCol->y = 0;
1300
0
  }
1301
0
  else {
1302
0
    *out_availableFlagLXCol = 1;
1303
1304
0
    const bool isLongTerm = shdr->LongTermRefPic[X][refIdxLX];
1305
1306
0
    int colDist  = colImg->PicOrderCntVal - colShdr->RefPicList_POC[listCol][refIdxCol];
1307
0
    int currDist = img->PicOrderCntVal - shdr->RefPicList_POC[X][refIdxLX];
1308
1309
0
    logtrace(LogMotion,"COLPOCDIFF %d %d [%d %d / %d %d]\n",colDist, currDist,
1310
0
             colImg->PicOrderCntVal, colShdr->RefPicList_POC[listCol][refIdxCol],
1311
0
             img->PicOrderCntVal, shdr->RefPicList_POC[X][refIdxLX]
1312
0
             );
1313
1314
0
    if (isLongTerm || colDist == currDist) {
1315
0
      *out_mvLXCol = mvCol;
1316
0
    }
1317
0
    else {
1318
0
      if (!scale_mv(out_mvLXCol, mvCol, colDist, currDist)) {
1319
0
        ctx->add_warning(DE265_WARNING_INCORRECT_MOTION_VECTOR_SCALING, false);
1320
0
        img->integrity = INTEGRITY_DECODING_ERRORS;
1321
0
      }
1322
1323
0
      logtrace(LogMotion,"scale: %d;%d to %d;%d\n",
1324
0
               mvCol.x,mvCol.y, out_mvLXCol->x,out_mvLXCol->y);
1325
0
    }
1326
0
  }
1327
0
}
1328
1329
1330
// 8.5.3.1.7
1331
void derive_temporal_luma_vector_prediction(base_context* ctx,
1332
                                            de265_image* img,
1333
                                            const slice_segment_header* shdr,
1334
                                            int xP,int yP,
1335
                                            int nPbW,int nPbH,
1336
                                            int refIdxL,
1337
                                            int X, // which MV (L0/L1) to get
1338
                                            MotionVector* out_mvLXCol,
1339
                                            uint8_t*      out_availableFlagLXCol)
1340
0
{
1341
  // --- no temporal MVP -> exit ---
1342
1343
0
  if (shdr->slice_temporal_mvp_enabled_flag == 0) {
1344
0
    out_mvLXCol->x = 0;
1345
0
    out_mvLXCol->y = 0;
1346
0
    *out_availableFlagLXCol = 0;
1347
0
    return;
1348
0
  }
1349
1350
1351
  // --- find collocated reference image ---
1352
1353
0
  int Log2CtbSizeY = img->get_sps().Log2CtbSizeY;
1354
1355
0
  int colPic; // TODO: this is the same for the whole slice. We can precompute it.
1356
1357
0
  if (shdr->slice_type == SLICE_TYPE_B &&
1358
0
      shdr->collocated_from_l0_flag == 0)
1359
0
    {
1360
0
      logtrace(LogMotion,"collocated L1 ref_idx=%d\n",shdr->collocated_ref_idx);
1361
1362
0
      colPic = shdr->RefPicList[1][ shdr->collocated_ref_idx ];
1363
0
    }
1364
0
  else
1365
0
    {
1366
0
      logtrace(LogMotion,"collocated L0 ref_idx=%d\n",shdr->collocated_ref_idx);
1367
1368
0
      colPic = shdr->RefPicList[0][ shdr->collocated_ref_idx ];
1369
0
    }
1370
1371
1372
  // check whether collocated reference picture exists
1373
1374
0
  if (!ctx->has_image(colPic)) {
1375
0
    out_mvLXCol->x = 0;
1376
0
    out_mvLXCol->y = 0;
1377
0
    *out_availableFlagLXCol = 0;
1378
1379
0
    ctx->add_warning(DE265_WARNING_NONEXISTING_REFERENCE_PICTURE_ACCESSED, false);
1380
0
    return;
1381
0
  }
1382
1383
1384
  // --- get collocated MV either at bottom-right corner or from center of PB ---
1385
1386
0
  int xColPb,yColPb;
1387
0
  int yColBr = yP + nPbH; // bottom right collocated motion vector position
1388
0
  int xColBr = xP + nPbW;
1389
1390
  /* If neighboring pixel at bottom-right corner is in the same CTB-row and inside the image,
1391
     use this (reduced down to 16 pixels resolution) as collocated MV position.
1392
1393
     Note: see 2014, Sze, Sect. 5.2.1.2 why candidate C0 is excluded when on another CTB-row.
1394
     This is to reduce the memory bandwidth requirements.
1395
   */
1396
0
  if ((yP>>Log2CtbSizeY) == (yColBr>>Log2CtbSizeY) &&
1397
0
      xColBr < img->get_sps().pic_width_in_luma_samples &&
1398
0
      yColBr < img->get_sps().pic_height_in_luma_samples)
1399
0
    {
1400
0
      xColPb = xColBr & ~0x0F; // reduce resolution of collocated motion-vectors to 16 pixels grid
1401
0
      yColPb = yColBr & ~0x0F;
1402
1403
0
      derive_collocated_motion_vectors(ctx,img,shdr, xP,yP, colPic, xColPb,yColPb, refIdxL, X,
1404
0
                                       out_mvLXCol, out_availableFlagLXCol);
1405
0
    }
1406
0
  else
1407
0
    {
1408
0
      out_mvLXCol->x = 0;
1409
0
      out_mvLXCol->y = 0;
1410
0
      *out_availableFlagLXCol = 0;
1411
0
    }
1412
1413
1414
0
  if (*out_availableFlagLXCol==0) {
1415
1416
0
    int xColCtr = xP+(nPbW>>1);
1417
0
    int yColCtr = yP+(nPbH>>1);
1418
1419
0
    xColPb = xColCtr & ~0x0F; // reduce resolution of collocated motion-vectors to 16 pixels grid
1420
0
    yColPb = yColCtr & ~0x0F;
1421
1422
0
    derive_collocated_motion_vectors(ctx,img,shdr, xP,yP, colPic, xColPb,yColPb, refIdxL, X,
1423
0
                                     out_mvLXCol, out_availableFlagLXCol);
1424
0
  }
1425
0
}
1426
1427
1428
static int table_8_19[2][12] = {
1429
  { 0,1,0,2,1,2,0,3,1,3,2,3 },
1430
  { 1,0,2,0,2,1,3,0,3,1,3,2 }
1431
  };
1432
1433
// 8.5.3.1.3
1434
/* Note (TODO): during decoding, we know which of the candidates we will select.
1435
+   Hence, we do not really have to generate the other ones...
1436
+ */
1437
void derive_combined_bipredictive_merging_candidates(const base_context* ctx,
1438
                                                     const slice_segment_header* shdr,
1439
                                                     PBMotion* inout_mergeCandList,
1440
                                                     int* inout_numMergeCand,
1441
                                                     int maxCandidates)
1442
0
{
1443
0
  if (*inout_numMergeCand>1 && *inout_numMergeCand < maxCandidates) {
1444
0
    int numOrigMergeCand = *inout_numMergeCand;
1445
1446
0
    int numInputMergeCand = *inout_numMergeCand;
1447
0
    int combIdx = 0;
1448
0
    uint8_t combStop = false;
1449
1450
0
    while (!combStop) {
1451
0
      int l0CandIdx = table_8_19[0][combIdx];
1452
0
      int l1CandIdx = table_8_19[1][combIdx];
1453
1454
0
      if (l0CandIdx >= numInputMergeCand ||
1455
0
          l1CandIdx >= numInputMergeCand) {
1456
0
        assert(false); // bitstream error -> TODO: conceal error
1457
0
      }
1458
1459
0
      PBMotion& l0Cand = inout_mergeCandList[l0CandIdx];
1460
0
      PBMotion& l1Cand = inout_mergeCandList[l1CandIdx];
1461
1462
0
      logtrace(LogMotion,"add bipredictive merging candidate (combIdx:%d)\n",combIdx);
1463
0
      logtrace(LogMotion,"l0Cand:\n"); logmvcand(l0Cand);
1464
0
      logtrace(LogMotion,"l1Cand:\n"); logmvcand(l1Cand);
1465
1466
0
      const de265_image* img0 = l0Cand.predFlag[0] ? ctx->get_image(shdr->RefPicList[0][l0Cand.refIdx[0]]) : nullptr;
1467
0
      const de265_image* img1 = l1Cand.predFlag[1] ? ctx->get_image(shdr->RefPicList[1][l1Cand.refIdx[1]]) : nullptr;
1468
1469
0
      if (l0Cand.predFlag[0] && !img0) {
1470
0
        return; // TODO error
1471
0
      }
1472
1473
0
      if (l1Cand.predFlag[1] && !img1) {
1474
0
        return; // TODO error
1475
0
      }
1476
1477
0
      if (l0Cand.predFlag[0] && l1Cand.predFlag[1] &&
1478
0
          (img0->PicOrderCntVal != img1->PicOrderCntVal     ||
1479
0
           l0Cand.mv[0].x != l1Cand.mv[1].x ||
1480
0
           l0Cand.mv[0].y != l1Cand.mv[1].y)) {
1481
0
        PBMotion& p = inout_mergeCandList[ *inout_numMergeCand ];
1482
0
        p.refIdx[0] = l0Cand.refIdx[0];
1483
0
        p.refIdx[1] = l1Cand.refIdx[1];
1484
0
        p.predFlag[0] = l0Cand.predFlag[0];
1485
0
        p.predFlag[1] = l1Cand.predFlag[1];
1486
0
        p.mv[0] = l0Cand.mv[0];
1487
0
        p.mv[1] = l1Cand.mv[1];
1488
0
        (*inout_numMergeCand)++;
1489
1490
0
        logtrace(LogMotion,"result:\n");
1491
0
        logmvcand(p);
1492
0
      }
1493
1494
0
      combIdx++;
1495
0
      if (combIdx == numOrigMergeCand*(numOrigMergeCand-1) ||
1496
0
          *inout_numMergeCand == maxCandidates) {
1497
0
        combStop = true;
1498
0
      }
1499
0
    }
1500
0
  }
1501
0
}
1502
1503
1504
// 8.5.3.1.1
1505
1506
void get_merge_candidate_list_without_step_9(base_context* ctx,
1507
                                             const slice_segment_header* shdr,
1508
                                             const MotionVectorAccess& mvaccess,
1509
                                             de265_image* img,
1510
                                             int xC,int yC, int xP,int yP,
1511
                                             int nCS, int nPbW,int nPbH, int partIdx,
1512
                                             int max_merge_idx,
1513
                                             PBMotion* mergeCandList)
1514
0
{
1515
1516
  //int xOrigP = xP;
1517
  //int yOrigP = yP;
1518
  //int nOrigPbW = nPbW;
1519
  //int nOrigPbH = nPbH;
1520
1521
0
  int singleMCLFlag; // single merge-candidate-list (MCL) flag
1522
1523
  /* Use single MCL for CBs of size 8x8, except when parallel-merge-level is at 4x4.
1524
     Without this flag, PBs smaller than 8x8 would not receive as much merging candidates.
1525
     Having additional candidates might have these advantages:
1526
     - coding MVs for these small PBs is expensive, and
1527
     - since the PBs are not far away from a proper (neighboring) merging candidate,
1528
     the quality of the candidates will still be good.
1529
  */
1530
0
  singleMCLFlag = (img->get_pps().log2_parallel_merge_level > 2 && nCS==8);
1531
1532
0
  if (singleMCLFlag) {
1533
0
    xP=xC;
1534
0
    yP=yC;
1535
0
    nPbW=nCS;
1536
0
    nPbH=nCS;
1537
0
    partIdx=0;
1538
0
  }
1539
1540
0
  int maxCandidates = max_merge_idx+1;
1541
  //MotionVectorSpec mergeCandList[5];
1542
0
  int numMergeCand=0;
1543
1544
  // --- spatial merge candidates
1545
1546
0
  numMergeCand = derive_spatial_merging_candidates(mvaccess,
1547
0
                                                   img, xC,yC, nCS, xP,yP, singleMCLFlag,
1548
0
                                                   nPbW,nPbH,partIdx, mergeCandList,
1549
0
                                                   maxCandidates);
1550
1551
  // --- collocated merge candidate
1552
0
  if (numMergeCand < maxCandidates) {
1553
0
    int refIdxCol[2] = { 0,0 };
1554
1555
0
    MotionVector mvCol[2];
1556
0
    uint8_t predFlagLCol[2];
1557
0
    derive_temporal_luma_vector_prediction(ctx,img,shdr, xP,yP,nPbW,nPbH,
1558
0
                                           refIdxCol[0],0, &mvCol[0],
1559
0
                                           &predFlagLCol[0]);
1560
1561
0
    uint8_t availableFlagCol = predFlagLCol[0];
1562
0
    predFlagLCol[1] = 0;
1563
1564
0
    if (shdr->slice_type == SLICE_TYPE_B) {
1565
0
      derive_temporal_luma_vector_prediction(ctx,img,shdr,
1566
0
                                             xP,yP,nPbW,nPbH, refIdxCol[1],1, &mvCol[1],
1567
0
                                             &predFlagLCol[1]);
1568
0
      availableFlagCol |= predFlagLCol[1];
1569
0
    }
1570
1571
1572
0
    if (availableFlagCol) {
1573
0
      PBMotion* colVec = &mergeCandList[numMergeCand++];
1574
1575
0
      colVec->mv[0] = mvCol[0];
1576
0
      colVec->mv[1] = mvCol[1];
1577
0
      colVec->predFlag[0] = predFlagLCol[0];
1578
0
      colVec->predFlag[1] = predFlagLCol[1];
1579
0
      colVec->refIdx[0] = refIdxCol[0];
1580
0
      colVec->refIdx[1] = refIdxCol[1];
1581
0
    }
1582
0
  }
1583
1584
1585
  // --- bipredictive merge candidates ---
1586
1587
0
  if (shdr->slice_type == SLICE_TYPE_B) {
1588
0
    derive_combined_bipredictive_merging_candidates(ctx, shdr,
1589
0
                                                    mergeCandList, &numMergeCand, maxCandidates);
1590
0
  }
1591
1592
1593
  // --- zero-vector merge candidates ---
1594
1595
0
  derive_zero_motion_vector_candidates(shdr, mergeCandList, &numMergeCand, maxCandidates);
1596
1597
1598
0
  logtrace(LogMotion,"mergeCandList:\n");
1599
0
  for (int i=0;i<shdr->MaxNumMergeCand;i++)
1600
0
    {
1601
      //logtrace(LogMotion, " %d:%s\n", i, i==merge_idx ? " SELECTED":"");
1602
0
      logmvcand(mergeCandList[i]);
1603
0
    }
1604
0
}
1605
1606
1607
1608
void get_merge_candidate_list(base_context* ctx,
1609
                              const slice_segment_header* shdr,
1610
                              de265_image* img,
1611
                              int xC,int yC, int xP,int yP,
1612
                              int nCS, int nPbW,int nPbH, int partIdx,
1613
                              PBMotion* mergeCandList)
1614
0
{
1615
0
  int max_merge_idx = 5-shdr->five_minus_max_num_merge_cand -1;
1616
1617
0
  get_merge_candidate_list_without_step_9(ctx, shdr,
1618
0
                                          MotionVectorAccess_de265_image(img), img,
1619
0
                                          xC,yC,xP,yP,nCS,nPbW,nPbH, partIdx,
1620
0
                                          max_merge_idx, mergeCandList);
1621
1622
  // 9. for encoder: modify all merge candidates
1623
1624
0
  for (int i=0;i<=max_merge_idx;i++) {
1625
0
    if (mergeCandList[i].predFlag[0] &&
1626
0
        mergeCandList[i].predFlag[1] &&
1627
0
        nPbW+nPbH==12)
1628
0
      {
1629
0
        mergeCandList[i].refIdx[1]   = 0;
1630
0
        mergeCandList[i].predFlag[1] = 0;
1631
0
      }
1632
0
  }
1633
0
}
1634
1635
1636
void derive_luma_motion_merge_mode(base_context* ctx,
1637
                                   const slice_segment_header* shdr,
1638
                                   de265_image* img,
1639
                                   int xC,int yC, int xP,int yP,
1640
                                   int nCS, int nPbW,int nPbH, int partIdx,
1641
                                   int merge_idx,
1642
                                   PBMotion* out_vi)
1643
0
{
1644
0
  PBMotion mergeCandList[5];
1645
1646
0
  get_merge_candidate_list_without_step_9(ctx, shdr,
1647
0
                                          MotionVectorAccess_de265_image(img), img,
1648
0
                                          xC,yC,xP,yP,nCS,nPbW,nPbH, partIdx,
1649
0
                                          merge_idx, mergeCandList);
1650
1651
1652
0
  *out_vi = mergeCandList[merge_idx];
1653
1654
  // 8.5.3.1.1 / 9.
1655
1656
0
  if (out_vi->predFlag[0] && out_vi->predFlag[1] && nPbW+nPbH==12) {
1657
0
    out_vi->refIdx[1] = 0;
1658
0
    out_vi->predFlag[1] = 0;
1659
0
  }
1660
0
}
1661
1662
1663
// 8.5.3.1.6
1664
void derive_spatial_luma_vector_prediction(base_context* ctx,
1665
                                           de265_image* img,
1666
                                           const slice_segment_header* shdr,
1667
                                           int xC,int yC,int nCS,int xP,int yP,
1668
                                           int nPbW,int nPbH, int X,
1669
                                           int refIdxLX, int partIdx,
1670
                                           uint8_t out_availableFlagLXN[2],
1671
                                           MotionVector out_mvLXN[2])
1672
0
{
1673
0
  if (refIdxLX >= MAX_NUM_REF_PICS) {
1674
0
    ctx->add_warning(DE265_WARNING_INCORRECT_MOTION_VECTOR_SCALING, false);
1675
0
    img->integrity = INTEGRITY_DECODING_ERRORS;
1676
1677
0
    out_availableFlagLXN[0] = false;
1678
0
    out_availableFlagLXN[1] = false;
1679
0
    out_mvLXN[0] = MotionVector();
1680
0
    out_mvLXN[1] = MotionVector();
1681
0
    return;
1682
0
  }
1683
1684
0
  int isScaledFlagLX = 0;
1685
1686
0
  const int A=0;
1687
0
  const int B=1;
1688
1689
0
  out_availableFlagLXN[A] = 0;
1690
0
  out_availableFlagLXN[B] = 0;
1691
1692
1693
  // --- A ---
1694
1695
  // 1.
1696
1697
0
  int xA[2], yA[2];
1698
0
  xA[0] = xP-1;
1699
0
  yA[0] = yP + nPbH;
1700
0
  xA[1] = xA[0];
1701
0
  yA[1] = yA[0]-1;
1702
1703
  // 2.
1704
1705
0
  out_availableFlagLXN[A] = 0;
1706
0
  out_mvLXN[A].x = 0;
1707
0
  out_mvLXN[A].y = 0;
1708
1709
  // 3. / 4.
1710
1711
0
  bool availableA[2];
1712
0
  availableA[0] = img->available_pred_blk(xC,yC, nCS, xP,yP, nPbW,nPbH,partIdx, xA[0],yA[0]);
1713
0
  availableA[1] = img->available_pred_blk(xC,yC, nCS, xP,yP, nPbW,nPbH,partIdx, xA[1],yA[1]);
1714
1715
  // 5.
1716
1717
0
  if (availableA[0] || availableA[1]) {
1718
0
    isScaledFlagLX = 1;
1719
0
  }
1720
1721
  // 6.  test A0 and A1  (Ak)
1722
1723
0
  int refIdxA=-1;
1724
1725
  // the POC we want to reference in this PB
1726
0
  const de265_image* tmpimg = ctx->get_image(shdr->RefPicList[X][ refIdxLX ]);
1727
0
  if (tmpimg==nullptr) { return; }
1728
0
  const int referenced_POC = tmpimg->PicOrderCntVal;
1729
1730
0
  for (int k=0;k<=1;k++) {
1731
1732
0
    if (availableA[k] &&
1733
0
        out_availableFlagLXN[A]==0 && // no A?-predictor so far
1734
0
        img->get_pred_mode(xA[k],yA[k]) != MODE_INTRA) {
1735
1736
0
      int Y=1-X;
1737
1738
0
      const PBMotion& vi = img->get_mv_info(xA[k],yA[k]);
1739
0
      logtrace(LogMotion,"MVP A%d=\n",k);
1740
0
      logmvcand(vi);
1741
1742
0
      const de265_image* imgX = nullptr;
1743
0
      if (vi.predFlag[X]) {
1744
0
        imgX = ctx->get_image(shdr->RefPicList[X][ vi.refIdx[X] ]);
1745
0
      }
1746
1747
0
      const de265_image* imgY = nullptr;
1748
0
      if (vi.predFlag[Y]) {
1749
0
        imgY = ctx->get_image(shdr->RefPicList[Y][ vi.refIdx[Y] ]);
1750
0
      }
1751
1752
      // check whether the predictor X is available and references the same POC
1753
0
      if (vi.predFlag[X] && imgX && imgX->PicOrderCntVal == referenced_POC) {
1754
1755
0
        logtrace(LogMotion,"take A%d/L%d as A candidate with same POC\n",k,X);
1756
1757
0
        out_availableFlagLXN[A]=1;
1758
0
        out_mvLXN[A] = vi.mv[X];
1759
0
        refIdxA = vi.refIdx[X];
1760
0
      }
1761
      // check whether the other predictor (Y) is available and references the same POC
1762
0
      else if (vi.predFlag[Y] && imgY && imgY->PicOrderCntVal == referenced_POC) {
1763
1764
0
        logtrace(LogMotion,"take A%d/L%d as A candidate with same POC\n",k,Y);
1765
1766
0
        out_availableFlagLXN[A]=1;
1767
0
        out_mvLXN[A] = vi.mv[Y];
1768
0
        refIdxA = vi.refIdx[Y];
1769
0
      }
1770
0
    }
1771
0
  }
1772
1773
  // 7. If there is no predictor referencing the same POC, we take any other reference as
1774
  //    long as it is the same type of reference (long-term / short-term)
1775
1776
0
  for (int k=0 ; k<=1 && out_availableFlagLXN[A]==0 ; k++) {
1777
0
    int refPicList=-1;
1778
1779
0
    if (availableA[k] &&
1780
        // TODO: we could remove this call by storing the result of the similar computation above
1781
0
        img->get_pred_mode(xA[k],yA[k]) != MODE_INTRA) {
1782
1783
0
      int Y=1-X;
1784
1785
0
      const PBMotion& vi = img->get_mv_info(xA[k],yA[k]);
1786
0
      if (vi.predFlag[X]==1 &&
1787
0
          shdr->LongTermRefPic[X][refIdxLX] == shdr->LongTermRefPic[X][ vi.refIdx[X] ]) {
1788
1789
0
        logtrace(LogMotion,"take A%D/L%d as A candidate with different POCs\n",k,X);
1790
1791
0
        out_availableFlagLXN[A]=1;
1792
0
        out_mvLXN[A] = vi.mv[X];
1793
0
        refIdxA = vi.refIdx[X];
1794
0
        refPicList = X;
1795
0
      }
1796
0
      else if (vi.predFlag[Y]==1 &&
1797
0
               shdr->LongTermRefPic[X][refIdxLX] == shdr->LongTermRefPic[Y][ vi.refIdx[Y] ]) {
1798
1799
0
        logtrace(LogMotion,"take A%d/L%d as A candidate with different POCs\n",k,Y);
1800
1801
0
        out_availableFlagLXN[A]=1;
1802
0
        out_mvLXN[A] = vi.mv[Y];
1803
0
        refIdxA = vi.refIdx[Y];
1804
0
        refPicList = Y;
1805
0
      }
1806
0
    }
1807
1808
0
    if (out_availableFlagLXN[A]==1) {
1809
0
      if (refIdxA<0) {
1810
0
        out_availableFlagLXN[0] = out_availableFlagLXN[1] = false;
1811
0
        return; // error
1812
0
      }
1813
1814
0
      assert(refIdxA>=0);
1815
0
      assert(refPicList>=0);
1816
1817
0
      const de265_image* refPicA = ctx->get_image(shdr->RefPicList[refPicList][refIdxA ]);
1818
1819
#ifdef DE265_LOG_TRACE
1820
      const de265_image* refPicX = ctx->get_image(shdr->RefPicList[X][refIdxLX]);
1821
#endif
1822
1823
      //int picStateA = shdr->RefPicList_PicState[refPicList][refIdxA ];
1824
      //int picStateX = shdr->RefPicList_PicState[X         ][refIdxLX];
1825
1826
0
      int isLongTermA = shdr->LongTermRefPic[refPicList][refIdxA ];
1827
0
      int isLongTermX = shdr->LongTermRefPic[X         ][refIdxLX];
1828
1829
0
      logtrace(LogMotion,"scale MVP A: A-POC:%d X-POC:%d\n",
1830
0
               refPicA->PicOrderCntVal,refPicX->PicOrderCntVal);
1831
1832
0
      if (!isLongTermA && !isLongTermX)
1833
      /*
1834
      if (picStateA == UsedForShortTermReference &&
1835
          picStateX == UsedForShortTermReference)
1836
      */
1837
0
        {
1838
0
          int distA = img->PicOrderCntVal - refPicA->PicOrderCntVal;
1839
0
          int distX = img->PicOrderCntVal - referenced_POC;
1840
1841
0
          if (!scale_mv(&out_mvLXN[A], out_mvLXN[A], distA, distX)) {
1842
0
            ctx->add_warning(DE265_WARNING_INCORRECT_MOTION_VECTOR_SCALING, false);
1843
0
            img->integrity = INTEGRITY_DECODING_ERRORS;
1844
0
          }
1845
0
        }
1846
0
    }
1847
0
  }
1848
1849
  // --- B ---
1850
1851
  // 1.
1852
1853
0
  int xB[3], yB[3];
1854
0
  xB[0] = xP+nPbW;
1855
0
  yB[0] = yP-1;
1856
0
  xB[1] = xB[0]-1;
1857
0
  yB[1] = yP-1;
1858
0
  xB[2] = xP-1;
1859
0
  yB[2] = yP-1;
1860
1861
  // 2.
1862
1863
0
  out_availableFlagLXN[B] = 0;
1864
0
  out_mvLXN[B].x = 0;
1865
0
  out_mvLXN[B].y = 0;
1866
1867
  // 3. test B0,B1,B2 (Bk)
1868
1869
0
  int refIdxB=-1;
1870
1871
0
  bool availableB[3];
1872
0
  for (int k=0;k<3;k++) {
1873
0
    availableB[k] = img->available_pred_blk(xC,yC, nCS, xP,yP, nPbW,nPbH,partIdx, xB[k],yB[k]);
1874
1875
0
    if (availableB[k] && out_availableFlagLXN[B]==0) {
1876
1877
0
      int Y=1-X;
1878
1879
0
      const PBMotion& vi = img->get_mv_info(xB[k],yB[k]);
1880
0
      logtrace(LogMotion,"MVP B%d=\n",k);
1881
0
      logmvcand(vi);
1882
1883
0
      const de265_image* imgX = nullptr;
1884
0
      if (vi.predFlag[X]) {
1885
0
        imgX = ctx->get_image(shdr->RefPicList[X][ vi.refIdx[X] ]);
1886
0
      }
1887
1888
0
      const de265_image* imgY = nullptr;
1889
0
      if (vi.predFlag[Y]) {
1890
0
        imgY = ctx->get_image(shdr->RefPicList[Y][ vi.refIdx[Y] ]);
1891
0
      }
1892
1893
0
      if (vi.predFlag[X] && imgX && imgX->PicOrderCntVal == referenced_POC) {
1894
0
        logtrace(LogMotion,"a) take B%d/L%d as B candidate with same POC\n",k,X);
1895
1896
0
        out_availableFlagLXN[B]=1;
1897
0
        out_mvLXN[B] = vi.mv[X];
1898
0
        refIdxB = vi.refIdx[X];
1899
0
      }
1900
0
      else if (vi.predFlag[Y] && imgY && imgY->PicOrderCntVal == referenced_POC) {
1901
0
        logtrace(LogMotion,"b) take B%d/L%d as B candidate with same POC\n",k,Y);
1902
1903
0
        out_availableFlagLXN[B]=1;
1904
0
        out_mvLXN[B] = vi.mv[Y];
1905
0
        refIdxB = vi.refIdx[Y];
1906
0
      }
1907
0
    }
1908
0
  }
1909
1910
  // 4.
1911
1912
0
  if (isScaledFlagLX==0 &&      // no A predictor,
1913
0
      out_availableFlagLXN[B])  // but an unscaled B predictor
1914
0
    {
1915
      // use unscaled B predictor as A predictor
1916
1917
0
      logtrace(LogMotion,"copy the same-POC B candidate as additional A candidate\n");
1918
1919
0
      out_availableFlagLXN[A]=1;
1920
0
      out_mvLXN[A] = out_mvLXN[B];
1921
0
      refIdxA = refIdxB;
1922
0
    }
1923
1924
  // 5.
1925
1926
  // If no A predictor, we output the unscaled B as the A predictor (above)
1927
  // and also add a scaled B predictor here.
1928
  // If there is (probably) an A predictor, no differing-POC B predictor is generated.
1929
0
  if (isScaledFlagLX==0) {
1930
0
    out_availableFlagLXN[B]=0;
1931
1932
0
    for (int k=0 ; k<=2 && out_availableFlagLXN[B]==0 ; k++) {
1933
0
      int refPicList=-1;
1934
1935
0
      if (availableB[k]) {
1936
0
        int Y=1-X;
1937
1938
0
        const PBMotion& vi = img->get_mv_info(xB[k],yB[k]);
1939
1940
0
        if (vi.predFlag[X]==1 &&
1941
0
            shdr->LongTermRefPic[X][refIdxLX] == shdr->LongTermRefPic[X][ vi.refIdx[X] ]) {
1942
0
          out_availableFlagLXN[B]=1;
1943
0
          out_mvLXN[B] = vi.mv[X];
1944
0
          refIdxB = vi.refIdx[X];
1945
0
          refPicList = X;
1946
0
        }
1947
0
        else if (vi.predFlag[Y]==1 &&
1948
0
                 shdr->LongTermRefPic[X][refIdxLX] == shdr->LongTermRefPic[Y][ vi.refIdx[Y] ]) {
1949
0
          out_availableFlagLXN[B]=1;
1950
0
          out_mvLXN[B] = vi.mv[Y];
1951
0
          refIdxB = vi.refIdx[Y];
1952
0
          refPicList = Y;
1953
0
        }
1954
0
      }
1955
1956
0
      if (out_availableFlagLXN[B]==1) {
1957
0
        if (refIdxB<0) {
1958
0
          out_availableFlagLXN[0] = out_availableFlagLXN[1] = false;
1959
0
          return; // error
1960
0
        }
1961
1962
0
        assert(refPicList>=0);
1963
0
        assert(refIdxB>=0);
1964
1965
0
        const de265_image* refPicB=ctx->get_image(shdr->RefPicList[refPicList][refIdxB ]);
1966
0
        const de265_image* refPicX=ctx->get_image(shdr->RefPicList[X         ][refIdxLX]);
1967
1968
0
        int isLongTermB = shdr->LongTermRefPic[refPicList][refIdxB ];
1969
0
        int isLongTermX = shdr->LongTermRefPic[X         ][refIdxLX];
1970
1971
0
        if (refPicB==nullptr || refPicX==nullptr) {
1972
0
          img->decctx->add_warning(DE265_WARNING_NONEXISTING_REFERENCE_PICTURE_ACCESSED,false);
1973
0
          img->integrity = INTEGRITY_DECODING_ERRORS;
1974
0
        }
1975
0
        else if (refPicB->PicOrderCntVal != refPicX->PicOrderCntVal &&
1976
0
                 !isLongTermB && !isLongTermX) {
1977
0
          int distB = img->PicOrderCntVal - refPicB->PicOrderCntVal;
1978
0
          int distX = img->PicOrderCntVal - referenced_POC;
1979
1980
0
          logtrace(LogMotion,"scale MVP B: B-POC:%d X-POC:%d\n",refPicB->PicOrderCntVal,refPicX->PicOrderCntVal);
1981
1982
0
          if (!scale_mv(&out_mvLXN[B], out_mvLXN[B], distB, distX)) {
1983
0
            ctx->add_warning(DE265_WARNING_INCORRECT_MOTION_VECTOR_SCALING, false);
1984
0
            img->integrity = INTEGRITY_DECODING_ERRORS;
1985
0
          }
1986
0
        }
1987
0
      }
1988
0
    }
1989
0
  }
1990
0
}
1991
1992
1993
// 8.5.3.1.5
1994
void fill_luma_motion_vector_predictors(base_context* ctx,
1995
                                        const slice_segment_header* shdr,
1996
                                        de265_image* img,
1997
                                        int xC,int yC,int nCS,int xP,int yP,
1998
                                        int nPbW,int nPbH, int l,
1999
                                        int refIdx, int partIdx,
2000
                                        MotionVector out_mvpList[2])
2001
0
{
2002
  // 8.5.3.1.6: derive two spatial vector predictors A (0) and B (1)
2003
2004
0
  uint8_t availableFlagLXN[2];
2005
0
  MotionVector mvLXN[2];
2006
2007
0
  derive_spatial_luma_vector_prediction(ctx, img, shdr, xC,yC, nCS, xP,yP,
2008
0
                                        nPbW,nPbH, l, refIdx, partIdx,
2009
0
                                        availableFlagLXN, mvLXN);
2010
2011
  // 8.5.3.1.7: if we only have one spatial vector or both spatial vectors are the same,
2012
  // derive a temporal predictor
2013
2014
0
  uint8_t availableFlagLXCol;
2015
0
  MotionVector mvLXCol;
2016
2017
2018
0
  if (availableFlagLXN[0] &&
2019
0
      availableFlagLXN[1] &&
2020
0
      (mvLXN[0].x != mvLXN[1].x || mvLXN[0].y != mvLXN[1].y)) {
2021
0
    availableFlagLXCol = 0;
2022
0
  }
2023
0
  else {
2024
0
    derive_temporal_luma_vector_prediction(ctx, img, shdr,
2025
0
                                           xP,yP, nPbW,nPbH, refIdx,l,
2026
0
                                           &mvLXCol, &availableFlagLXCol);
2027
0
  }
2028
2029
2030
  // --- build candidate vector list with exactly two entries ---
2031
2032
0
  int numMVPCandLX=0;
2033
2034
  // spatial predictor A
2035
2036
0
  if (availableFlagLXN[0])
2037
0
    {
2038
0
      out_mvpList[numMVPCandLX++] = mvLXN[0];
2039
0
    }
2040
2041
  // spatial predictor B (if not same as A)
2042
2043
0
  if (availableFlagLXN[1] &&
2044
0
      (!availableFlagLXN[0] || // in case A in not available, but mvLXA initialized to same as mvLXB
2045
0
       (mvLXN[0].x != mvLXN[1].x || mvLXN[0].y != mvLXN[1].y)))
2046
0
    {
2047
0
      out_mvpList[numMVPCandLX++] = mvLXN[1];
2048
0
    }
2049
2050
  // temporal predictor
2051
2052
0
  if (availableFlagLXCol)
2053
0
    {
2054
0
      out_mvpList[numMVPCandLX++] = mvLXCol;
2055
0
    }
2056
2057
  // fill with zero predictors
2058
2059
0
  while (numMVPCandLX<2) {
2060
0
    out_mvpList[numMVPCandLX].x = 0;
2061
0
    out_mvpList[numMVPCandLX].y = 0;
2062
0
    numMVPCandLX++;
2063
0
  }
2064
2065
2066
0
  assert(numMVPCandLX==2);
2067
0
}
2068
2069
2070
MotionVector luma_motion_vector_prediction(base_context* ctx,
2071
                                           const slice_segment_header* shdr,
2072
                                           de265_image* img,
2073
                                           const PBMotionCoding& motion,
2074
                                           int xC,int yC,int nCS,int xP,int yP,
2075
                                           int nPbW,int nPbH, int l,
2076
                                           int refIdx, int partIdx)
2077
0
{
2078
0
  MotionVector mvpList[2];
2079
2080
0
  fill_luma_motion_vector_predictors(ctx, shdr, img,
2081
0
                                     xC,yC,nCS,xP,yP,
2082
0
                                     nPbW, nPbH, l, refIdx, partIdx,
2083
0
                                     mvpList);
2084
2085
  // select predictor according to mvp_lX_flag
2086
2087
0
  return mvpList[ l ? motion.mvp_l1_flag : motion.mvp_l0_flag ];
2088
0
}
2089
2090
2091
#if DE265_LOG_TRACE
2092
void logMV(int x0,int y0,int nPbW,int nPbH, const char* mode,const PBMotion* mv)
2093
{
2094
  int pred0 = mv->predFlag[0];
2095
  int pred1 = mv->predFlag[1];
2096
2097
  logtrace(LogMotion,
2098
           "*MV %d;%d [%d;%d] %s: (%d) %d;%d @%d   (%d) %d;%d @%d\n", x0,y0,nPbW,nPbH,mode,
2099
           pred0,
2100
           pred0 ? mv->mv[0].x : 0,pred0 ? mv->mv[0].y : 0, pred0 ? mv->refIdx[0] : 0,
2101
           pred1,
2102
           pred1 ? mv->mv[1].x : 0,pred1 ? mv->mv[1].y : 0, pred1 ? mv->refIdx[1] : 0);
2103
}
2104
#else
2105
#define logMV(x0,y0,nPbW,nPbH,mode,mv)
2106
#endif
2107
2108
2109
2110
// 8.5.3.1
2111
void motion_vectors_and_ref_indices(base_context* ctx,
2112
                                    const slice_segment_header* shdr,
2113
                                    de265_image* img,
2114
                                    const PBMotionCoding& motion,
2115
                                    int xC,int yC, int xB,int yB, int nCS, int nPbW,int nPbH,
2116
                                    int partIdx,
2117
                                    PBMotion* out_vi)
2118
0
{
2119
  //slice_segment_header* shdr = tctx->shdr;
2120
2121
0
  int xP = xC+xB;
2122
0
  int yP = yC+yB;
2123
2124
0
  enum PredMode predMode = img->get_pred_mode(xC,yC);
2125
2126
0
  if (predMode == MODE_SKIP ||
2127
0
      (predMode == MODE_INTER && motion.merge_flag))
2128
0
    {
2129
0
      derive_luma_motion_merge_mode(ctx,shdr,img,
2130
0
                                    xC,yC, xP,yP, nCS,nPbW,nPbH, partIdx,
2131
0
                                    motion.merge_idx, out_vi);
2132
2133
0
      logMV(xP,yP,nPbW,nPbH, "merge_mode", out_vi);
2134
0
    }
2135
0
  else {
2136
0
    int mvdL[2][2];
2137
0
    MotionVector mvpL[2];
2138
2139
0
    for (int l=0;l<2;l++) {
2140
      // 1.
2141
2142
0
      enum InterPredIdc inter_pred_idc = (enum InterPredIdc)motion.inter_pred_idc;
2143
2144
0
      if (inter_pred_idc == PRED_BI ||
2145
0
          (inter_pred_idc == PRED_L0 && l==0) ||
2146
0
          (inter_pred_idc == PRED_L1 && l==1)) {
2147
0
        out_vi->refIdx[l] = motion.refIdx[l];
2148
0
        out_vi->predFlag[l] = 1;
2149
0
      }
2150
0
      else {
2151
0
        out_vi->refIdx[l] = 0;
2152
0
        out_vi->predFlag[l] = 0;
2153
0
      }
2154
2155
      // 2.
2156
2157
0
      mvdL[l][0] = motion.mvd[l][0];
2158
0
      mvdL[l][1] = motion.mvd[l][1];
2159
2160
2161
0
      if (out_vi->predFlag[l]) {
2162
        // 3.
2163
2164
0
        mvpL[l] = luma_motion_vector_prediction(ctx,shdr,img,motion,
2165
0
                                                xC,yC,nCS,xP,yP, nPbW,nPbH, l,
2166
0
                                                out_vi->refIdx[l], partIdx);
2167
2168
        // 4.
2169
2170
0
        int32_t x = (mvpL[l].x + mvdL[l][0] + 0x10000) & 0xFFFF;
2171
0
        int32_t y = (mvpL[l].y + mvdL[l][1] + 0x10000) & 0xFFFF;
2172
2173
0
        out_vi->mv[l].x = (x>=0x8000) ? x-0x10000 : x;
2174
0
        out_vi->mv[l].y = (y>=0x8000) ? y-0x10000 : y;
2175
0
      }
2176
0
    }
2177
2178
0
    logMV(xP,yP,nPbW,nPbH, "mvp", out_vi);
2179
0
  }
2180
0
}
2181
2182
2183
// 8.5.3
2184
2185
/* xC/yC : CB position
2186
   xB/yB : position offset of the PB
2187
   nPbW/nPbH : size of PB
2188
   nCS   : CB size
2189
 */
2190
void decode_prediction_unit(base_context* ctx,
2191
                            const slice_segment_header* shdr,
2192
                            de265_image* img,
2193
                            const PBMotionCoding& motion,
2194
                            int xC,int yC, int xB,int yB, int nCS, int nPbW,int nPbH, int partIdx)
2195
0
{
2196
0
  logtrace(LogMotion,"decode_prediction_unit POC=%d %d;%d %dx%d\n",
2197
0
           img->PicOrderCntVal, xC+xB,yC+yB, nPbW,nPbH);
2198
2199
  //slice_segment_header* shdr = tctx->shdr;
2200
2201
  // 1.
2202
2203
0
  PBMotion vi;
2204
0
  motion_vectors_and_ref_indices(ctx, shdr, img, motion,
2205
0
                                 xC,yC, xB,yB, nCS, nPbW,nPbH, partIdx, &vi);
2206
2207
  // 2.
2208
2209
0
  generate_inter_prediction_samples(ctx,shdr, img, xC,yC, xB,yB, nCS, nPbW,nPbH, &vi);
2210
2211
2212
0
  img->set_mv_info(xC+xB,yC+yB,nPbW,nPbH, vi);
2213
0
}