DecodeMv.cs
1 using Ryujinx.Common.Memory; 2 using Ryujinx.Graphics.Nvdec.Vp9.Dsp; 3 using Ryujinx.Graphics.Nvdec.Vp9.Types; 4 using Ryujinx.Graphics.Video; 5 using System; 6 using System.Diagnostics; 7 using System.Runtime.CompilerServices; 8 9 namespace Ryujinx.Graphics.Nvdec.Vp9 10 { 11 internal static class DecodeMv 12 { 13 private const int MvrefNeighbours = 8; 14 15 private static PredictionMode ReadIntraMode(ref Reader r, ReadOnlySpan<byte> p) 16 { 17 return (PredictionMode)r.ReadTree(Luts.Vp9IntraModeTree, p); 18 } 19 20 private static PredictionMode ReadIntraModeY(ref Vp9Common cm, ref MacroBlockD xd, ref Reader r, int sizeGroup) 21 { 22 PredictionMode yMode = ReadIntraMode(ref r, cm.Fc.Value.YModeProb[sizeGroup].AsSpan()); 23 if (!xd.Counts.IsNull) 24 { 25 ++xd.Counts.Value.YMode[sizeGroup][(int)yMode]; 26 } 27 28 return yMode; 29 } 30 31 private static PredictionMode ReadIntraModeUv(ref Vp9Common cm, ref MacroBlockD xd, ref Reader r, byte yMode) 32 { 33 PredictionMode uvMode = ReadIntraMode(ref r, cm.Fc.Value.UvModeProb[yMode].AsSpan()); 34 if (!xd.Counts.IsNull) 35 { 36 ++xd.Counts.Value.UvMode[yMode][(int)uvMode]; 37 } 38 39 return uvMode; 40 } 41 42 private static PredictionMode ReadInterMode(ref Vp9Common cm, ref MacroBlockD xd, ref Reader r, int ctx) 43 { 44 int mode = r.ReadTree(Luts.Vp9InterModeTree, cm.Fc.Value.InterModeProb[ctx].AsSpan()); 45 if (!xd.Counts.IsNull) 46 { 47 ++xd.Counts.Value.InterMode[ctx][mode]; 48 } 49 50 return PredictionMode.NearestMv + mode; 51 } 52 53 private static int ReadSegmentId(ref Reader r, ref Array7<byte> segTreeProbs) 54 { 55 return r.ReadTree(Luts.Vp9SegmentTree, segTreeProbs.AsSpan()); 56 } 57 58 private static ReadOnlySpan<byte> GetTxProbs(ref Vp9EntropyProbs fc, TxSize maxTxSize, int ctx) 59 { 60 switch (maxTxSize) 61 { 62 case TxSize.Tx8x8: 63 return fc.Tx8x8Prob[ctx].AsSpan(); 64 case TxSize.Tx16x16: 65 return fc.Tx16x16Prob[ctx].AsSpan(); 66 case TxSize.Tx32x32: 67 return fc.Tx32x32Prob[ctx].AsSpan(); 68 default: 69 Debug.Assert(false, "Invalid maxTxSize."); 70 71 return ReadOnlySpan<byte>.Empty; 72 } 73 } 74 75 private static Span<uint> GetTxCounts(ref Vp9BackwardUpdates counts, TxSize maxTxSize, int ctx) 76 { 77 switch (maxTxSize) 78 { 79 case TxSize.Tx8x8: 80 return counts.Tx8x8[ctx].AsSpan(); 81 case TxSize.Tx16x16: 82 return counts.Tx16x16[ctx].AsSpan(); 83 case TxSize.Tx32x32: 84 return counts.Tx32x32[ctx].AsSpan(); 85 default: 86 Debug.Assert(false, "Invalid maxTxSize."); 87 88 return Span<uint>.Empty; 89 } 90 } 91 92 private static TxSize ReadSelectedTxSize(ref Vp9Common cm, ref MacroBlockD xd, TxSize maxTxSize, ref Reader r) 93 { 94 int ctx = xd.GetTxSizeContext(); 95 ReadOnlySpan<byte> txProbs = GetTxProbs(ref cm.Fc.Value, maxTxSize, ctx); 96 TxSize txSize = (TxSize)r.Read(txProbs[0]); 97 if (txSize != TxSize.Tx4x4 && maxTxSize >= TxSize.Tx16x16) 98 { 99 txSize += r.Read(txProbs[1]); 100 if (txSize != TxSize.Tx8x8 && maxTxSize >= TxSize.Tx32x32) 101 { 102 txSize += r.Read(txProbs[2]); 103 } 104 } 105 106 if (!xd.Counts.IsNull) 107 { 108 ++GetTxCounts(ref xd.Counts.Value, maxTxSize, ctx)[(int)txSize]; 109 } 110 111 return txSize; 112 } 113 114 private static TxSize ReadTxSize(ref Vp9Common cm, ref MacroBlockD xd, bool allowSelect, ref Reader r) 115 { 116 TxMode txMode = cm.TxMode; 117 BlockSize bsize = xd.Mi[0].Value.SbType; 118 TxSize maxTxSize = Luts.MaxTxSizeLookup[(int)bsize]; 119 if (allowSelect && txMode == TxMode.TxModeSelect && bsize >= BlockSize.Block8x8) 120 { 121 return ReadSelectedTxSize(ref cm, ref xd, maxTxSize, ref r); 122 } 123 124 return (TxSize)Math.Min((int)maxTxSize, (int)Luts.TxModeToBiggestTxSize[(int)txMode]); 125 } 126 127 private static int DecGetSegmentId(ref Vp9Common cm, ArrayPtr<byte> segmentIds, int miOffset, int xMis, int yMis) 128 { 129 int x, y, segmentId = int.MaxValue; 130 131 for (y = 0; y < yMis; y++) 132 { 133 for (x = 0; x < xMis; x++) 134 { 135 segmentId = Math.Min(segmentId, segmentIds[miOffset + y * cm.MiCols + x]); 136 } 137 } 138 139 Debug.Assert(segmentId >= 0 && segmentId < Constants.MaxSegments); 140 141 return segmentId; 142 } 143 144 private static void SetSegmentId(ref Vp9Common cm, int miOffset, int xMis, int yMis, int segmentId) 145 { 146 int x, y; 147 148 Debug.Assert(segmentId >= 0 && segmentId < Constants.MaxSegments); 149 150 for (y = 0; y < yMis; y++) 151 { 152 for (x = 0; x < xMis; x++) 153 { 154 cm.CurrentFrameSegMap[miOffset + y * cm.MiCols + x] = (byte)segmentId; 155 } 156 } 157 } 158 159 private static void CopySegmentId( 160 ref Vp9Common cm, 161 ArrayPtr<byte> lastSegmentIds, 162 ArrayPtr<byte> currentSegmentIds, 163 int miOffset, 164 int xMis, 165 int yMis) 166 { 167 int x, y; 168 169 for (y = 0; y < yMis; y++) 170 { 171 for (x = 0; x < xMis; x++) 172 { 173 currentSegmentIds[miOffset + y * cm.MiCols + x] = (byte)(!lastSegmentIds.IsNull ? lastSegmentIds[miOffset + y * cm.MiCols + x] : 0); 174 } 175 } 176 } 177 178 private static int ReadIntraSegmentId(ref Vp9Common cm, int miOffset, int xMis, int yMis, ref Reader r) 179 { 180 ref Segmentation seg = ref cm.Seg; 181 int segmentId; 182 183 if (!seg.Enabled) 184 { 185 return 0; // Default for disabled segmentation 186 } 187 188 if (!seg.UpdateMap) 189 { 190 CopySegmentId(ref cm, cm.LastFrameSegMap, cm.CurrentFrameSegMap, miOffset, xMis, yMis); 191 192 return 0; 193 } 194 195 segmentId = ReadSegmentId(ref r, ref cm.Fc.Value.SegTreeProb); 196 SetSegmentId(ref cm, miOffset, xMis, yMis, segmentId); 197 198 return segmentId; 199 } 200 201 private static int ReadInterSegmentId( 202 ref Vp9Common cm, 203 ref MacroBlockD xd, 204 int miRow, 205 int miCol, 206 ref Reader r, 207 int xMis, 208 int yMis) 209 { 210 ref Segmentation seg = ref cm.Seg; 211 ref ModeInfo mi = ref xd.Mi[0].Value; 212 int predictedSegmentId, segmentId; 213 int miOffset = miRow * cm.MiCols + miCol; 214 215 if (!seg.Enabled) 216 { 217 return 0; // Default for disabled segmentation 218 } 219 220 predictedSegmentId = !cm.LastFrameSegMap.IsNull 221 ? DecGetSegmentId(ref cm, cm.LastFrameSegMap, miOffset, xMis, yMis) 222 : 0; 223 224 if (!seg.UpdateMap) 225 { 226 CopySegmentId(ref cm, cm.LastFrameSegMap, cm.CurrentFrameSegMap, miOffset, xMis, yMis); 227 228 return predictedSegmentId; 229 } 230 231 if (seg.TemporalUpdate) 232 { 233 byte predProb = Segmentation.GetPredProbSegId(ref cm.Fc.Value.SegPredProb, ref xd); 234 mi.SegIdPredicted = (sbyte)r.Read(predProb); 235 segmentId = mi.SegIdPredicted != 0 ? predictedSegmentId : ReadSegmentId(ref r, ref cm.Fc.Value.SegTreeProb); 236 } 237 else 238 { 239 segmentId = ReadSegmentId(ref r, ref cm.Fc.Value.SegTreeProb); 240 } 241 SetSegmentId(ref cm, miOffset, xMis, yMis, segmentId); 242 243 return segmentId; 244 } 245 246 private static int ReadSkip(ref Vp9Common cm, ref MacroBlockD xd, int segmentId, ref Reader r) 247 { 248 if (cm.Seg.IsSegFeatureActive(segmentId, SegLvlFeatures.SegLvlSkip) != 0) 249 { 250 return 1; 251 } 252 253 int ctx = xd.GetSkipContext(); 254 int skip = r.Read(cm.Fc.Value.SkipProb[ctx]); 255 if (!xd.Counts.IsNull) 256 { 257 ++xd.Counts.Value.Skip[ctx][skip]; 258 } 259 260 return skip; 261 } 262 263 private static int ReadMvComponent(ref Reader r, ref Vp9EntropyProbs fc, int mvcomp, bool usehp) 264 { 265 int mag, d, fr, hp; 266 bool sign = r.Read(fc.Sign[mvcomp]) != 0; 267 MvClassType mvClass = (MvClassType)r.ReadTree(Luts.Vp9MvClassTree, fc.Classes[mvcomp].AsSpan()); 268 bool class0 = mvClass == MvClassType.MvClass0; 269 270 // Integer part 271 if (class0) 272 { 273 d = r.Read(fc.Class0[mvcomp][0]); 274 mag = 0; 275 } 276 else 277 { 278 int i; 279 int n = (int)mvClass + Constants.Class0Bits - 1; // Number of bits 280 281 d = 0; 282 for (i = 0; i < n; ++i) 283 { 284 d |= r.Read(fc.Bits[mvcomp][i]) << i; 285 } 286 287 mag = Constants.Class0Size << ((int)mvClass + 2); 288 } 289 290 // Fractional part 291 fr = r.ReadTree(Luts.Vp9MvFPTree, class0 ? fc.Class0Fp[mvcomp][d].AsSpan() : fc.Fp[mvcomp].AsSpan()); 292 293 // High precision part (if hp is not used, the default value of the hp is 1) 294 hp = usehp ? r.Read(class0 ? fc.Class0Hp[mvcomp] : fc.Hp[mvcomp]) : 1; 295 296 // Result 297 mag += ((d << 3) | (fr << 1) | hp) + 1; 298 299 return sign ? -mag : mag; 300 } 301 302 private static void ReadMv( 303 ref Reader r, 304 ref Mv mv, 305 ref Mv refr, 306 ref Vp9EntropyProbs fc, 307 Ptr<Vp9BackwardUpdates> counts, 308 bool allowHP) 309 { 310 MvJointType jointType = (MvJointType)r.ReadTree(Luts.Vp9MvJointTree, fc.Joints.AsSpan()); 311 bool useHP = allowHP && refr.UseMvHp(); 312 Mv diff = new(); 313 314 if (Mv.MvJointVertical(jointType)) 315 { 316 diff.Row = (short)ReadMvComponent(ref r, ref fc, 0, useHP); 317 } 318 319 if (Mv.MvJointHorizontal(jointType)) 320 { 321 diff.Col = (short)ReadMvComponent(ref r, ref fc, 1, useHP); 322 } 323 324 diff.IncMv(counts); 325 326 mv.Row = (short)(refr.Row + diff.Row); 327 mv.Col = (short)(refr.Col + diff.Col); 328 } 329 330 private static ReferenceMode ReadBlockReferenceMode(ref Vp9Common cm, ref MacroBlockD xd, ref Reader r) 331 { 332 if (cm.ReferenceMode == ReferenceMode.ReferenceModeSelect) 333 { 334 int ctx = PredCommon.GetReferenceModeContext(ref cm, ref xd); 335 ReferenceMode mode = (ReferenceMode)r.Read(cm.Fc.Value.CompInterProb[ctx]); 336 if (!xd.Counts.IsNull) 337 { 338 ++xd.Counts.Value.CompInter[ctx][(int)mode]; 339 } 340 341 return mode; // SingleReference or CompoundReference 342 } 343 344 return cm.ReferenceMode; 345 } 346 347 // Read the referncence frame 348 private static void ReadRefFrames( 349 ref Vp9Common cm, 350 ref MacroBlockD xd, 351 ref Reader r, 352 int segmentId, 353 ref Array2<sbyte> refFrame) 354 { 355 ref Vp9EntropyProbs fc = ref cm.Fc.Value; 356 357 if (cm.Seg.IsSegFeatureActive(segmentId, SegLvlFeatures.SegLvlRefFrame) != 0) 358 { 359 refFrame[0] = (sbyte)cm.Seg.GetSegData(segmentId, SegLvlFeatures.SegLvlRefFrame); 360 refFrame[1] = Constants.None; 361 } 362 else 363 { 364 ReferenceMode mode = ReadBlockReferenceMode(ref cm, ref xd, ref r); 365 if (mode == ReferenceMode.CompoundReference) 366 { 367 int idx = cm.RefFrameSignBias[cm.CompFixedRef]; 368 int ctx = PredCommon.GetPredContextCompRefP(ref cm, ref xd); 369 int bit = r.Read(fc.CompRefProb[ctx]); 370 if (!xd.Counts.IsNull) 371 { 372 ++xd.Counts.Value.CompRef[ctx][bit]; 373 } 374 375 refFrame[idx] = cm.CompFixedRef; 376 refFrame[idx == 0 ? 1 : 0] = cm.CompVarRef[bit]; 377 } 378 else if (mode == ReferenceMode.SingleReference) 379 { 380 int ctx0 = PredCommon.GetPredContextSingleRefP1(ref xd); 381 int bit0 = r.Read(fc.SingleRefProb[ctx0][0]); 382 if (!xd.Counts.IsNull) 383 { 384 ++xd.Counts.Value.SingleRef[ctx0][0][bit0]; 385 } 386 387 if (bit0 != 0) 388 { 389 int ctx1 = PredCommon.GetPredContextSingleRefP2(ref xd); 390 int bit1 = r.Read(fc.SingleRefProb[ctx1][1]); 391 if (!xd.Counts.IsNull) 392 { 393 ++xd.Counts.Value.SingleRef[ctx1][1][bit1]; 394 } 395 396 refFrame[0] = (sbyte)(bit1 != 0 ? Constants.AltRefFrame : Constants.GoldenFrame); 397 } 398 else 399 { 400 refFrame[0] = Constants.LastFrame; 401 } 402 403 refFrame[1] = Constants.None; 404 } 405 else 406 { 407 Debug.Assert(false, "Invalid prediction mode."); 408 } 409 } 410 } 411 412 private static byte ReadSwitchableInterpFilter(ref Vp9Common cm, ref MacroBlockD xd, ref Reader r) 413 { 414 int ctx = xd.GetPredContextSwitchableInterp(); 415 byte type = (byte)r.ReadTree(Luts.Vp9SwitchableInterpTree, cm.Fc.Value.SwitchableInterpProb[ctx].AsSpan()); 416 if (!xd.Counts.IsNull) 417 { 418 ++xd.Counts.Value.SwitchableInterp[ctx][type]; 419 } 420 421 return type; 422 } 423 424 private static void ReadIntraBlockModeInfo(ref Vp9Common cm, ref MacroBlockD xd, ref ModeInfo mi, ref Reader r) 425 { 426 BlockSize bsize = mi.SbType; 427 int i; 428 429 switch (bsize) 430 { 431 case BlockSize.Block4x4: 432 for (i = 0; i < 4; ++i) 433 { 434 mi.Bmi[i].Mode = ReadIntraModeY(ref cm, ref xd, ref r, 0); 435 } 436 437 mi.Mode = mi.Bmi[3].Mode; 438 break; 439 case BlockSize.Block4x8: 440 mi.Bmi[0].Mode = mi.Bmi[2].Mode = ReadIntraModeY(ref cm, ref xd, ref r, 0); 441 mi.Bmi[1].Mode = mi.Bmi[3].Mode = mi.Mode = ReadIntraModeY(ref cm, ref xd, ref r, 0); 442 break; 443 case BlockSize.Block8x4: 444 mi.Bmi[0].Mode = mi.Bmi[1].Mode = ReadIntraModeY(ref cm, ref xd, ref r, 0); 445 mi.Bmi[2].Mode = mi.Bmi[3].Mode = mi.Mode = ReadIntraModeY(ref cm, ref xd, ref r, 0); 446 break; 447 default: 448 mi.Mode = ReadIntraModeY(ref cm, ref xd, ref r, Luts.SizeGroupLookup[(int)bsize]); 449 break; 450 } 451 452 mi.UvMode = ReadIntraModeUv(ref cm, ref xd, ref r, (byte)mi.Mode); 453 454 // Initialize interp_filter here so we do not have to check for inter block 455 // modes in GetPredContextSwitchableInterp() 456 mi.InterpFilter = Constants.SwitchableFilters; 457 458 mi.RefFrame[0] = Constants.IntraFrame; 459 mi.RefFrame[1] = Constants.None; 460 } 461 462 private static bool IsMvValid(ref Mv mv) 463 { 464 return mv.Row > Constants.MvLow && 465 mv.Row < Constants.MvUpp && 466 mv.Col > Constants.MvLow && 467 mv.Col < Constants.MvUpp; 468 } 469 470 private static void CopyMvPair(ref Array2<Mv> dst, ref Array2<Mv> src) 471 { 472 dst[0] = src[0]; 473 dst[1] = src[1]; 474 } 475 476 private static void ZeroMvPair(ref Array2<Mv> dst) 477 { 478 dst[0] = new Mv(); 479 dst[1] = new Mv(); 480 } 481 482 private static bool AssignMv( 483 ref Vp9Common cm, 484 ref MacroBlockD xd, 485 PredictionMode mode, 486 ref Array2<Mv> mv, 487 ref Array2<Mv> refMv, 488 ref Array2<Mv> nearNearestMv, 489 int isCompound, 490 bool allowHP, 491 ref Reader r) 492 { 493 int i; 494 bool ret = true; 495 496 switch (mode) 497 { 498 case PredictionMode.NewMv: 499 { 500 for (i = 0; i < 1 + isCompound; ++i) 501 { 502 ReadMv(ref r, ref mv[i], ref refMv[i], ref cm.Fc.Value, xd.Counts, allowHP); 503 ret = ret && IsMvValid(ref mv[i]); 504 } 505 break; 506 } 507 case PredictionMode.NearMv: 508 case PredictionMode.NearestMv: 509 { 510 CopyMvPair(ref mv, ref nearNearestMv); 511 break; 512 } 513 case PredictionMode.ZeroMv: 514 { 515 ZeroMvPair(ref mv); 516 break; 517 } 518 default: 519 return false; 520 } 521 return ret; 522 } 523 524 private static bool ReadIsInterBlock(ref Vp9Common cm, ref MacroBlockD xd, int segmentId, ref Reader r) 525 { 526 if (cm.Seg.IsSegFeatureActive(segmentId, SegLvlFeatures.SegLvlRefFrame) != 0) 527 { 528 return cm.Seg.GetSegData(segmentId, SegLvlFeatures.SegLvlRefFrame) != Constants.IntraFrame; 529 } 530 531 int ctx = xd.GetIntraInterContext(); 532 bool isInter = r.Read(cm.Fc.Value.IntraInterProb[ctx]) != 0; 533 if (!xd.Counts.IsNull) 534 { 535 ++xd.Counts.Value.IntraInter[ctx][isInter ? 1 : 0]; 536 } 537 538 return isInter; 539 } 540 541 private static void DecFindBestRefMvs(bool allowHP, Span<Mv> mvlist, ref Mv bestMv, int refmvCount) 542 { 543 int i; 544 545 // Make sure all the candidates are properly clamped etc 546 for (i = 0; i < refmvCount; ++i) 547 { 548 mvlist[i].LowerMvPrecision(allowHP); 549 bestMv = mvlist[i]; 550 } 551 } 552 553 private static bool AddMvRefListEb(Mv mv, ref int refMvCount, Span<Mv> mvRefList, bool earlyBreak) 554 { 555 if (refMvCount != 0) 556 { 557 if (Unsafe.As<Mv, int>(ref mv) != Unsafe.As<Mv, int>(ref mvRefList[0])) 558 { 559 mvRefList[refMvCount] = mv; 560 refMvCount++; 561 562 return true; 563 } 564 } 565 else 566 { 567 mvRefList[refMvCount++] = mv; 568 if (earlyBreak) 569 { 570 return true; 571 } 572 } 573 574 return false; 575 } 576 577 // Performs mv sign inversion if indicated by the reference frame combination. 578 private static Mv ScaleMv(ref ModeInfo mi, int refr, sbyte thisRefFrame, ref Array4<sbyte> refSignBias) 579 { 580 Mv mv = mi.Mv[refr]; 581 if (refSignBias[mi.RefFrame[refr]] != refSignBias[thisRefFrame]) 582 { 583 mv.Row *= -1; 584 mv.Col *= -1; 585 } 586 return mv; 587 } 588 589 private static bool IsDiffRefFrameAddMvEb( 590 ref ModeInfo mbmi, 591 sbyte refFrame, 592 ref Array4<sbyte> refSignBias, 593 ref int refmvCount, 594 Span<Mv> mvRefList, 595 bool earlyBreak) 596 { 597 if (mbmi.IsInterBlock()) 598 { 599 if (mbmi.RefFrame[0] != refFrame) 600 { 601 if (AddMvRefListEb(ScaleMv(ref mbmi, 0, refFrame, ref refSignBias), ref refmvCount, mvRefList, earlyBreak)) 602 { 603 return true; 604 } 605 } 606 if (mbmi.HasSecondRef() && mbmi.RefFrame[1] != refFrame && Unsafe.As<Mv, int>(ref mbmi.Mv[1]) != Unsafe.As<Mv, int>(ref mbmi.Mv[0])) 607 { 608 if (AddMvRefListEb(ScaleMv(ref mbmi, 1, refFrame, ref refSignBias), ref refmvCount, mvRefList, earlyBreak)) 609 { 610 return true; 611 } 612 } 613 614 } 615 return false; 616 } 617 618 // This function searches the neighborhood of a given MB/SB 619 // to try and find candidate reference vectors. 620 private static int DecFindMvRefs( 621 ref Vp9Common cm, 622 ref MacroBlockD xd, 623 PredictionMode mode, 624 sbyte refFrame, 625 Span<Position> mvRefSearch, 626 Span<Mv> mvRefList, 627 int miRow, 628 int miCol, 629 int block, 630 int isSub8X8) 631 { 632 ref Array4<sbyte> refSignBias = ref cm.RefFrameSignBias; 633 int i, refmvCount = 0; 634 bool differentRefFound = false; 635 Ptr<MvRef> prevFrameMvs = cm.UsePrevFrameMvs ? new Ptr<MvRef>(ref cm.PrevFrameMvs[miRow * cm.MiCols + miCol]) : Ptr<MvRef>.Null; 636 ref TileInfo tile = ref xd.Tile; 637 // If mode is nearestmv or newmv (uses nearestmv as a reference) then stop 638 // searching after the first mv is found. 639 bool earlyBreak = mode != PredictionMode.NearMv; 640 641 // Blank the reference vector list 642 mvRefList[..Constants.MaxMvRefCandidates].Clear(); 643 644 i = 0; 645 if (isSub8X8 != 0) 646 { 647 // If the size < 8x8 we get the mv from the bmi substructure for the 648 // nearest two blocks. 649 for (i = 0; i < 2; ++i) 650 { 651 ref Position mvRef = ref mvRefSearch[i]; 652 if (tile.IsInside(miCol, miRow, cm.MiRows, ref mvRef)) 653 { 654 ref ModeInfo candidateMi = ref xd.Mi[mvRef.Col + mvRef.Row * xd.MiStride].Value; 655 differentRefFound = true; 656 657 if (candidateMi.RefFrame[0] == refFrame) 658 { 659 if (AddMvRefListEb(candidateMi.GetSubBlockMv(0, mvRef.Col, block), ref refmvCount, mvRefList, earlyBreak)) 660 { 661 goto Done; 662 } 663 } 664 else if (candidateMi.RefFrame[1] == refFrame) 665 { 666 if (AddMvRefListEb(candidateMi.GetSubBlockMv(1, mvRef.Col, block), ref refmvCount, mvRefList, earlyBreak)) 667 { 668 goto Done; 669 } 670 } 671 } 672 } 673 } 674 675 // Check the rest of the neighbors in much the same way 676 // as before except we don't need to keep track of sub blocks or 677 // mode counts. 678 for (; i < MvrefNeighbours; ++i) 679 { 680 ref Position mvRef = ref mvRefSearch[i]; 681 if (tile.IsInside(miCol, miRow, cm.MiRows, ref mvRef)) 682 { 683 ref ModeInfo candidate = ref xd.Mi[mvRef.Col + mvRef.Row * xd.MiStride].Value; 684 differentRefFound = true; 685 686 if (candidate.RefFrame[0] == refFrame) 687 { 688 if (AddMvRefListEb(candidate.Mv[0], ref refmvCount, mvRefList, earlyBreak)) 689 { 690 goto Done; 691 } 692 } 693 else if (candidate.RefFrame[1] == refFrame) 694 { 695 if (AddMvRefListEb(candidate.Mv[1], ref refmvCount, mvRefList, earlyBreak)) 696 { 697 goto Done; 698 } 699 } 700 } 701 } 702 703 // Check the last frame's mode and mv info. 704 if (!prevFrameMvs.IsNull) 705 { 706 if (prevFrameMvs.Value.RefFrame[0] == refFrame) 707 { 708 if (AddMvRefListEb(prevFrameMvs.Value.Mv[0], ref refmvCount, mvRefList, earlyBreak)) 709 { 710 goto Done; 711 } 712 } 713 else if (prevFrameMvs.Value.RefFrame[1] == refFrame) 714 { 715 if (AddMvRefListEb(prevFrameMvs.Value.Mv[1], ref refmvCount, mvRefList, earlyBreak)) 716 { 717 goto Done; 718 } 719 } 720 } 721 722 // Since we couldn't find 2 mvs from the same reference frame 723 // go back through the neighbors and find motion vectors from 724 // different reference frames. 725 if (differentRefFound) 726 { 727 for (i = 0; i < MvrefNeighbours; ++i) 728 { 729 ref Position mvRef = ref mvRefSearch[i]; 730 if (tile.IsInside(miCol, miRow, cm.MiRows, ref mvRef)) 731 { 732 ref ModeInfo candidate = ref xd.Mi[mvRef.Col + mvRef.Row * xd.MiStride].Value; 733 734 // If the candidate is Intra we don't want to consider its mv. 735 if (IsDiffRefFrameAddMvEb(ref candidate, refFrame, ref refSignBias, ref refmvCount, mvRefList, earlyBreak)) 736 { 737 goto Done; 738 } 739 } 740 } 741 } 742 743 // Since we still don't have a candidate we'll try the last frame. 744 if (!prevFrameMvs.IsNull) 745 { 746 if (prevFrameMvs.Value.RefFrame[0] != refFrame && prevFrameMvs.Value.RefFrame[0] > Constants.IntraFrame) 747 { 748 Mv mv = prevFrameMvs.Value.Mv[0]; 749 if (refSignBias[prevFrameMvs.Value.RefFrame[0]] != refSignBias[refFrame]) 750 { 751 mv.Row *= -1; 752 mv.Col *= -1; 753 } 754 if (AddMvRefListEb(mv, ref refmvCount, mvRefList, earlyBreak)) 755 { 756 goto Done; 757 } 758 } 759 760 if (prevFrameMvs.Value.RefFrame[1] > Constants.IntraFrame && 761 prevFrameMvs.Value.RefFrame[1] != refFrame && 762 Unsafe.As<Mv, int>(ref prevFrameMvs.Value.Mv[1]) != Unsafe.As<Mv, int>(ref prevFrameMvs.Value.Mv[0])) 763 { 764 Mv mv = prevFrameMvs.Value.Mv[1]; 765 if (refSignBias[prevFrameMvs.Value.RefFrame[1]] != refSignBias[refFrame]) 766 { 767 mv.Row *= -1; 768 mv.Col *= -1; 769 } 770 if (AddMvRefListEb(mv, ref refmvCount, mvRefList, earlyBreak)) 771 { 772 goto Done; 773 } 774 } 775 } 776 777 if (mode == PredictionMode.NearMv) 778 { 779 refmvCount = Constants.MaxMvRefCandidates; 780 } 781 else 782 { 783 // We only care about the nearestmv for the remaining modes 784 refmvCount = 1; 785 } 786 787 Done: 788 // Clamp vectors 789 for (i = 0; i < refmvCount; ++i) 790 { 791 mvRefList[i].ClampMvRef(ref xd); 792 } 793 794 return refmvCount; 795 } 796 797 private static void AppendSub8x8MvsForIdx( 798 ref Vp9Common cm, 799 ref MacroBlockD xd, 800 Span<Position> mvRefSearch, 801 PredictionMode bMode, 802 int block, 803 int refr, 804 int miRow, 805 int miCol, 806 ref Mv bestSub8x8) 807 { 808 Span<Mv> mvList = stackalloc Mv[Constants.MaxMvRefCandidates]; 809 ref ModeInfo mi = ref xd.Mi[0].Value; 810 ref Array4<BModeInfo> bmi = ref mi.Bmi; 811 int n; 812 int refmvCount; 813 814 Debug.Assert(Constants.MaxMvRefCandidates == 2); 815 816 refmvCount = DecFindMvRefs(ref cm, ref xd, bMode, mi.RefFrame[refr], mvRefSearch, mvList, miRow, miCol, block, 1); 817 818 switch (block) 819 { 820 case 0: 821 bestSub8x8 = mvList[refmvCount - 1]; 822 break; 823 case 1: 824 case 2: 825 if (bMode == PredictionMode.NearestMv) 826 { 827 bestSub8x8 = bmi[0].Mv[refr]; 828 } 829 else 830 { 831 bestSub8x8 = new Mv(); 832 for (n = 0; n < refmvCount; ++n) 833 { 834 if (Unsafe.As<Mv, int>(ref bmi[0].Mv[refr]) != Unsafe.As<Mv, int>(ref mvList[n])) 835 { 836 bestSub8x8 = mvList[n]; 837 break; 838 } 839 } 840 } 841 break; 842 case 3: 843 if (bMode == PredictionMode.NearestMv) 844 { 845 bestSub8x8 = bmi[2].Mv[refr]; 846 } 847 else 848 { 849 Span<Mv> candidates = stackalloc Mv[2 + Constants.MaxMvRefCandidates]; 850 candidates[0] = bmi[1].Mv[refr]; 851 candidates[1] = bmi[0].Mv[refr]; 852 candidates[2] = mvList[0]; 853 candidates[3] = mvList[1]; 854 bestSub8x8 = new Mv(); 855 for (n = 0; n < 2 + Constants.MaxMvRefCandidates; ++n) 856 { 857 if (Unsafe.As<Mv, int>(ref bmi[2].Mv[refr]) != Unsafe.As<Mv, int>(ref candidates[n])) 858 { 859 bestSub8x8 = candidates[n]; 860 break; 861 } 862 } 863 } 864 break; 865 default: 866 Debug.Assert(false, "Invalid block index."); 867 break; 868 } 869 } 870 871 private static byte GetModeContext(ref Vp9Common cm, ref MacroBlockD xd, Span<Position> mvRefSearch, int miRow, int miCol) 872 { 873 int i; 874 int contextCounter = 0; 875 ref TileInfo tile = ref xd.Tile; 876 877 // Get mode count from nearest 2 blocks 878 for (i = 0; i < 2; ++i) 879 { 880 ref Position mvRef = ref mvRefSearch[i]; 881 if (tile.IsInside(miCol, miRow, cm.MiRows, ref mvRef)) 882 { 883 ref ModeInfo candidate = ref xd.Mi[mvRef.Col + mvRef.Row * xd.MiStride].Value; 884 // Keep counts for entropy encoding. 885 contextCounter += Luts.Mode2Counter[(int)candidate.Mode]; 886 } 887 } 888 889 return (byte)Luts.CounterToContext[contextCounter]; 890 } 891 892 private static void ReadInterBlockModeInfo( 893 ref Vp9Common cm, 894 ref MacroBlockD xd, 895 ref ModeInfo mi, 896 int miRow, 897 int miCol, 898 ref Reader r) 899 { 900 BlockSize bsize = mi.SbType; 901 bool allowHP = cm.AllowHighPrecisionMv; 902 Array2<Mv> bestRefMvs = new(); 903 int refr, isCompound; 904 byte interModeCtx; 905 Span<Position> mvRefSearch = Luts.MvRefBlocks[(int)bsize]; 906 907 ReadRefFrames(ref cm, ref xd, ref r, mi.SegmentId, ref mi.RefFrame); 908 isCompound = mi.HasSecondRef() ? 1 : 0; 909 interModeCtx = GetModeContext(ref cm, ref xd, mvRefSearch, miRow, miCol); 910 911 if (cm.Seg.IsSegFeatureActive(mi.SegmentId, SegLvlFeatures.SegLvlSkip) != 0) 912 { 913 mi.Mode = PredictionMode.ZeroMv; 914 if (bsize < BlockSize.Block8x8) 915 { 916 xd.ErrorInfo.Value.InternalError(CodecErr.CodecUnsupBitstream, "Invalid usage of segement feature on small blocks"); 917 918 return; 919 } 920 } 921 else 922 { 923 if (bsize >= BlockSize.Block8x8) 924 { 925 mi.Mode = ReadInterMode(ref cm, ref xd, ref r, interModeCtx); 926 } 927 else 928 { 929 // Sub 8x8 blocks use the nearestmv as a ref_mv if the bMode is NewMv. 930 // Setting mode to NearestMv forces the search to stop after the nearestmv 931 // has been found. After bModes have been read, mode will be overwritten 932 // by the last bMode. 933 mi.Mode = PredictionMode.NearestMv; 934 } 935 936 if (mi.Mode != PredictionMode.ZeroMv) 937 { 938 Span<Mv> tmpMvs = stackalloc Mv[Constants.MaxMvRefCandidates]; 939 940 for (refr = 0; refr < 1 + isCompound; ++refr) 941 { 942 sbyte frame = mi.RefFrame[refr]; 943 int refmvCount; 944 945 refmvCount = DecFindMvRefs(ref cm, ref xd, mi.Mode, frame, mvRefSearch, tmpMvs, miRow, miCol, -1, 0); 946 947 DecFindBestRefMvs(allowHP, tmpMvs, ref bestRefMvs[refr], refmvCount); 948 } 949 } 950 } 951 952 mi.InterpFilter = (cm.InterpFilter == Constants.Switchable) ? ReadSwitchableInterpFilter(ref cm, ref xd, ref r) : cm.InterpFilter; 953 954 if (bsize < BlockSize.Block8x8) 955 { 956 int num4X4W = 1 << xd.BmodeBlocksWl; 957 int num4X4H = 1 << xd.BmodeBlocksHl; 958 int idx, idy; 959 PredictionMode bMode = 0; 960 Array2<Mv> bestSub8x8 = new(); 961 const uint InvalidMv = 0x80008000; 962 // Initialize the 2nd element as even though it won't be used meaningfully 963 // if isCompound is false. 964 Unsafe.As<Mv, uint>(ref bestSub8x8[1]) = InvalidMv; 965 for (idy = 0; idy < 2; idy += num4X4H) 966 { 967 for (idx = 0; idx < 2; idx += num4X4W) 968 { 969 int j = idy * 2 + idx; 970 bMode = ReadInterMode(ref cm, ref xd, ref r, interModeCtx); 971 972 if (bMode == PredictionMode.NearestMv || bMode == PredictionMode.NearMv) 973 { 974 for (refr = 0; refr < 1 + isCompound; ++refr) 975 { 976 AppendSub8x8MvsForIdx(ref cm, ref xd, mvRefSearch, bMode, j, refr, miRow, miCol, ref bestSub8x8[refr]); 977 } 978 } 979 980 if (!AssignMv(ref cm, ref xd, bMode, ref mi.Bmi[j].Mv, ref bestRefMvs, ref bestSub8x8, isCompound, allowHP, ref r)) 981 { 982 xd.Corrupted |= true; 983 break; 984 } 985 986 if (num4X4H == 2) 987 { 988 mi.Bmi[j + 2] = mi.Bmi[j]; 989 } 990 991 if (num4X4W == 2) 992 { 993 mi.Bmi[j + 1] = mi.Bmi[j]; 994 } 995 } 996 } 997 998 mi.Mode = bMode; 999 1000 CopyMvPair(ref mi.Mv, ref mi.Bmi[3].Mv); 1001 } 1002 else 1003 { 1004 xd.Corrupted |= !AssignMv(ref cm, ref xd, mi.Mode, ref mi.Mv, ref bestRefMvs, ref bestRefMvs, isCompound, allowHP, ref r); 1005 } 1006 } 1007 1008 private static void ReadInterFrameModeInfo( 1009 ref Vp9Common cm, 1010 ref MacroBlockD xd, 1011 int miRow, 1012 int miCol, 1013 ref Reader r, 1014 int xMis, 1015 int yMis) 1016 { 1017 ref ModeInfo mi = ref xd.Mi[0].Value; 1018 bool interBlock; 1019 1020 mi.SegmentId = (sbyte)ReadInterSegmentId(ref cm, ref xd, miRow, miCol, ref r, xMis, yMis); 1021 mi.Skip = (sbyte)ReadSkip(ref cm, ref xd, mi.SegmentId, ref r); 1022 interBlock = ReadIsInterBlock(ref cm, ref xd, mi.SegmentId, ref r); 1023 mi.TxSize = ReadTxSize(ref cm, ref xd, mi.Skip == 0 || !interBlock, ref r); 1024 1025 if (interBlock) 1026 { 1027 ReadInterBlockModeInfo(ref cm, ref xd, ref mi, miRow, miCol, ref r); 1028 } 1029 else 1030 { 1031 ReadIntraBlockModeInfo(ref cm, ref xd, ref mi, ref r); 1032 } 1033 } 1034 1035 private static PredictionMode LeftBlockMode(Ptr<ModeInfo> curMi, Ptr<ModeInfo> leftMi, int b) 1036 { 1037 if (b == 0 || b == 2) 1038 { 1039 if (leftMi.IsNull || leftMi.Value.IsInterBlock()) 1040 { 1041 return PredictionMode.DcPred; 1042 } 1043 1044 return leftMi.Value.GetYMode(b + 1); 1045 } 1046 1047 Debug.Assert(b == 1 || b == 3); 1048 1049 return curMi.Value.Bmi[b - 1].Mode; 1050 } 1051 1052 private static PredictionMode AboveBlockMode(Ptr<ModeInfo> curMi, Ptr<ModeInfo> aboveMi, int b) 1053 { 1054 if (b == 0 || b == 1) 1055 { 1056 if (aboveMi.IsNull || aboveMi.Value.IsInterBlock()) 1057 { 1058 return PredictionMode.DcPred; 1059 } 1060 1061 return aboveMi.Value.GetYMode(b + 2); 1062 } 1063 1064 Debug.Assert(b == 2 || b == 3); 1065 1066 return curMi.Value.Bmi[b - 2].Mode; 1067 } 1068 1069 private static ReadOnlySpan<byte> GetYModeProbs( 1070 ref Vp9EntropyProbs fc, 1071 Ptr<ModeInfo> mi, 1072 Ptr<ModeInfo> aboveMi, 1073 Ptr<ModeInfo> leftMi, 1074 int block) 1075 { 1076 PredictionMode above = AboveBlockMode(mi, aboveMi, block); 1077 PredictionMode left = LeftBlockMode(mi, leftMi, block); 1078 1079 return fc.KfYModeProb[(int)above][(int)left].AsSpan(); 1080 } 1081 1082 private static void ReadIntraFrameModeInfo( 1083 ref Vp9Common cm, 1084 ref MacroBlockD xd, 1085 int miRow, 1086 int miCol, 1087 ref Reader r, 1088 int xMis, 1089 int yMis) 1090 { 1091 Ptr<ModeInfo> mi = xd.Mi[0]; 1092 Ptr<ModeInfo> aboveMi = xd.AboveMi; 1093 Ptr<ModeInfo> leftMi = xd.LeftMi; 1094 BlockSize bsize = mi.Value.SbType; 1095 int i; 1096 int miOffset = miRow * cm.MiCols + miCol; 1097 1098 mi.Value.SegmentId = (sbyte)ReadIntraSegmentId(ref cm, miOffset, xMis, yMis, ref r); 1099 mi.Value.Skip = (sbyte)ReadSkip(ref cm, ref xd, mi.Value.SegmentId, ref r); 1100 mi.Value.TxSize = ReadTxSize(ref cm, ref xd, true, ref r); 1101 mi.Value.RefFrame[0] = Constants.IntraFrame; 1102 mi.Value.RefFrame[1] = Constants.None; 1103 1104 switch (bsize) 1105 { 1106 case BlockSize.Block4x4: 1107 for (i = 0; i < 4; ++i) 1108 { 1109 mi.Value.Bmi[i].Mode = 1110 ReadIntraMode(ref r, GetYModeProbs(ref cm.Fc.Value, mi, aboveMi, leftMi, i)); 1111 } 1112 1113 mi.Value.Mode = mi.Value.Bmi[3].Mode; 1114 break; 1115 case BlockSize.Block4x8: 1116 mi.Value.Bmi[0].Mode = mi.Value.Bmi[2].Mode = 1117 ReadIntraMode(ref r, GetYModeProbs(ref cm.Fc.Value, mi, aboveMi, leftMi, 0)); 1118 mi.Value.Bmi[1].Mode = mi.Value.Bmi[3].Mode = mi.Value.Mode = 1119 ReadIntraMode(ref r, GetYModeProbs(ref cm.Fc.Value, mi, aboveMi, leftMi, 1)); 1120 break; 1121 case BlockSize.Block8x4: 1122 mi.Value.Bmi[0].Mode = mi.Value.Bmi[1].Mode = 1123 ReadIntraMode(ref r, GetYModeProbs(ref cm.Fc.Value, mi, aboveMi, leftMi, 0)); 1124 mi.Value.Bmi[2].Mode = mi.Value.Bmi[3].Mode = mi.Value.Mode = 1125 ReadIntraMode(ref r, GetYModeProbs(ref cm.Fc.Value, mi, aboveMi, leftMi, 2)); 1126 break; 1127 default: 1128 mi.Value.Mode = ReadIntraMode(ref r, GetYModeProbs(ref cm.Fc.Value, mi, aboveMi, leftMi, 0)); 1129 break; 1130 } 1131 1132 mi.Value.UvMode = ReadIntraMode(ref r, cm.Fc.Value.KfUvModeProb[(int)mi.Value.Mode].AsSpan()); 1133 } 1134 1135 private static void CopyRefFramePair(ref Array2<sbyte> dst, ref Array2<sbyte> src) 1136 { 1137 dst[0] = src[0]; 1138 dst[1] = src[1]; 1139 } 1140 1141 public static void ReadModeInfo( 1142 ref TileWorkerData twd, 1143 ref Vp9Common cm, 1144 int miRow, 1145 int miCol, 1146 int xMis, 1147 int yMis) 1148 { 1149 ref Reader r = ref twd.BitReader; 1150 ref MacroBlockD xd = ref twd.Xd; 1151 ref ModeInfo mi = ref xd.Mi[0].Value; 1152 ArrayPtr<MvRef> frameMvs = cm.CurFrameMvs.Slice(miRow * cm.MiCols + miCol); 1153 int w, h; 1154 1155 if (cm.FrameIsIntraOnly()) 1156 { 1157 ReadIntraFrameModeInfo(ref cm, ref xd, miRow, miCol, ref r, xMis, yMis); 1158 } 1159 else 1160 { 1161 ReadInterFrameModeInfo(ref cm, ref xd, miRow, miCol, ref r, xMis, yMis); 1162 1163 for (h = 0; h < yMis; ++h) 1164 { 1165 for (w = 0; w < xMis; ++w) 1166 { 1167 ref MvRef mv = ref frameMvs[w]; 1168 CopyRefFramePair(ref mv.RefFrame, ref mi.RefFrame); 1169 CopyMvPair(ref mv.Mv, ref mi.Mv); 1170 } 1171 frameMvs = frameMvs.Slice(cm.MiCols); 1172 } 1173 } 1174 } 1175 } 1176 }