Ejemplo n.º 1
0
        public void Decode(
            Vp9FrameKeys keys,
            Vp9FrameHeader header,
            Vp9ProbabilityTables probs,
            byte[]               frameData)
        {
            bool isKeyFrame         = ((header.Flags >> 0) & 1) != 0;
            bool lastIsKeyFrame     = ((header.Flags >> 1) & 1) != 0;
            bool frameSizeChanged   = ((header.Flags >> 2) & 1) != 0;
            bool errorResilientMode = ((header.Flags >> 3) & 1) != 0;
            bool lastShowFrame      = ((header.Flags >> 4) & 1) != 0;
            bool isFrameIntra       = ((header.Flags >> 5) & 1) != 0;

            bool showFrame = !isFrameIntra;

            //Write compressed header.
            byte[] compressedHeaderData;

            using (MemoryStream compressedHeader = new MemoryStream())
            {
                VpxRangeEncoder writer = new VpxRangeEncoder(compressedHeader);

                if (!header.Lossless)
                {
                    if ((uint)header.TxMode >= 3)
                    {
                        writer.Write(3, 2);
                        writer.Write(header.TxMode == 4);
                    }
                    else
                    {
                        writer.Write(header.TxMode, 2);
                    }
                }

                if (header.TxMode == 4)
                {
                    WriteProbabilityUpdate(writer, probs.Tx8x8Probs, DefaultTx8x8Probs);
                    WriteProbabilityUpdate(writer, probs.Tx16x16Probs, DefaultTx16x16Probs);
                    WriteProbabilityUpdate(writer, probs.Tx32x32Probs, DefaultTx32x32Probs);
                }

                WriteCoefProbabilityUpdate(writer, header.TxMode, probs.CoefProbs, _defaultCoefProbs);

                WriteProbabilityUpdate(writer, probs.SkipProbs, _defaultSkipProbs);

                if (!isFrameIntra)
                {
                    WriteProbabilityUpdateAligned4(writer, probs.InterModeProbs, _defaultInterModeProbs);

                    if (header.RawInterpolationFilter == 4)
                    {
                        WriteProbabilityUpdate(writer, probs.InterpFilterProbs, _defaultInterpFilterProbs);
                    }

                    WriteProbabilityUpdate(writer, probs.IsInterProbs, _defaultIsInterProbs);

                    if ((header.RefFrameSignBias[1] & 1) != (header.RefFrameSignBias[2] & 1) ||
                        (header.RefFrameSignBias[1] & 1) != (header.RefFrameSignBias[3] & 1))
                    {
                        if ((uint)header.CompPredMode >= 1)
                        {
                            writer.Write(1, 1);
                            writer.Write(header.CompPredMode == 2);
                        }
                        else
                        {
                            writer.Write(0, 1);
                        }
                    }

                    if (header.CompPredMode == 2)
                    {
                        WriteProbabilityUpdate(writer, probs.CompModeProbs, _defaultCompModeProbs);
                    }

                    if (header.CompPredMode != 1)
                    {
                        WriteProbabilityUpdate(writer, probs.SingleRefProbs, _defaultSingleRefProbs);
                    }

                    if (header.CompPredMode != 0)
                    {
                        WriteProbabilityUpdate(writer, probs.CompRefProbs, _defaultCompRefProbs);
                    }

                    for (int index = 0; index < 4; index++)
                    {
                        int i = index * 8;
                        int j = index;

                        WriteProbabilityUpdate(writer, probs.YModeProbs0[i + 0], _defaultYModeProbs0[i + 0]);
                        WriteProbabilityUpdate(writer, probs.YModeProbs0[i + 1], _defaultYModeProbs0[i + 1]);
                        WriteProbabilityUpdate(writer, probs.YModeProbs0[i + 2], _defaultYModeProbs0[i + 2]);
                        WriteProbabilityUpdate(writer, probs.YModeProbs0[i + 3], _defaultYModeProbs0[i + 3]);
                        WriteProbabilityUpdate(writer, probs.YModeProbs0[i + 4], _defaultYModeProbs0[i + 4]);
                        WriteProbabilityUpdate(writer, probs.YModeProbs0[i + 5], _defaultYModeProbs0[i + 5]);
                        WriteProbabilityUpdate(writer, probs.YModeProbs0[i + 6], _defaultYModeProbs0[i + 6]);
                        WriteProbabilityUpdate(writer, probs.YModeProbs0[i + 7], _defaultYModeProbs0[i + 7]);
                        WriteProbabilityUpdate(writer, probs.YModeProbs1[j + 0], _defaultYModeProbs1[j + 0]);
                    }

                    WriteProbabilityUpdateAligned4(writer, probs.PartitionProbs, _defaultPartitionProbs);

                    for (int i = 0; i < 3; i++)
                    {
                        WriteMvProbabilityUpdate(writer, probs.MvJointProbs[i], _defaultMvJointProbs[i]);
                    }

                    for (int i = 0; i < 2; i++)
                    {
                        WriteMvProbabilityUpdate(writer, probs.MvSignProbs[i], _defaultMvSignProbs[i]);

                        for (int j = 0; j < 10; j++)
                        {
                            int index = i * 10 + j;

                            WriteMvProbabilityUpdate(writer, probs.MvClassProbs[index], _defaultMvClassProbs[index]);
                        }

                        WriteMvProbabilityUpdate(writer, probs.MvClass0BitProbs[i], _defaultMvClass0BitProbs[i]);

                        for (int j = 0; j < 10; j++)
                        {
                            int index = i * 10 + j;

                            WriteMvProbabilityUpdate(writer, probs.MvBitsProbs[index], _defaultMvBitsProbs[index]);
                        }
                    }

                    for (int i = 0; i < 2; i++)
                    {
                        for (int j = 0; j < 2; j++)
                        {
                            for (int k = 0; k < 3; k++)
                            {
                                int index = i * 2 * 3 + j * 3 + k;

                                WriteMvProbabilityUpdate(writer, probs.MvClass0FrProbs[index], _defaultMvClass0FrProbs[index]);
                            }
                        }

                        for (int j = 0; j < 3; j++)
                        {
                            int index = i * 3 + j;

                            WriteMvProbabilityUpdate(writer, probs.MvFrProbs[index], _defaultMvFrProbs[index]);
                        }
                    }

                    if (header.AllowHighPrecisionMv)
                    {
                        for (int index = 0; index < 2; index++)
                        {
                            WriteMvProbabilityUpdate(writer, probs.MvClass0HpProbs[index], _defaultMvClass0HpProbs[index]);
                            WriteMvProbabilityUpdate(writer, probs.MvHpProbs[index], _defaultMvHpProbs[index]);
                        }
                    }
                }

                writer.End();

                compressedHeaderData = compressedHeader.ToArray();
            }

            //Write uncompressed header.
            using (MemoryStream encodedHeader = new MemoryStream())
            {
                VpxBitStreamWriter writer = new VpxBitStreamWriter(encodedHeader);

                writer.WriteU(2, 2);    //Frame marker.
                writer.WriteU(0, 2);    //Profile.
                writer.WriteBit(false); //Show existing frame.
                writer.WriteBit(!isKeyFrame);
                writer.WriteBit(showFrame);
                writer.WriteBit(errorResilientMode);

                if (isKeyFrame)
                {
                    writer.WriteU(FrameSyncCode, 24);
                    writer.WriteU(0, 3); //Color space.
                    writer.WriteU(0, 1); //Color range.
                    writer.WriteU(header.CurrentFrame.Width - 1, 16);
                    writer.WriteU(header.CurrentFrame.Height - 1, 16);
                    writer.WriteBit(false); //Render and frame size different.

                    _cachedRefFrames.Clear();

                    //On key frames, all frame slots are set to the current frame,
                    //so the value of the selected slot doesn't really matter.
                    GetNewFrameSlot(keys.CurrKey);
                }
                else
                {
                    if (!showFrame)
                    {
                        writer.WriteBit(isFrameIntra);
                    }

                    if (!errorResilientMode)
                    {
                        writer.WriteU(0, 2); //Reset frame context.
                    }

                    int refreshFrameFlags = 1 << GetNewFrameSlot(keys.CurrKey);

                    if (isFrameIntra)
                    {
                        writer.WriteU(FrameSyncCode, 24);
                        writer.WriteU(refreshFrameFlags, 8);
                        writer.WriteU(header.CurrentFrame.Width - 1, 16);
                        writer.WriteU(header.CurrentFrame.Height - 1, 16);
                        writer.WriteBit(false); //Render and frame size different.
                    }
                    else
                    {
                        writer.WriteU(refreshFrameFlags, 8);

                        int[] refFrameIndex = new int[]
                        {
                            GetFrameSlot(keys.Ref0Key),
                            GetFrameSlot(keys.Ref1Key),
                            GetFrameSlot(keys.Ref2Key)
                        };

                        byte[] refFrameSignBias = header.RefFrameSignBias;

                        for (int index = 1; index < 4; index++)
                        {
                            writer.WriteU(refFrameIndex[index - 1], 3);
                            writer.WriteU(refFrameSignBias[index], 1);
                        }

                        writer.WriteBit(true);  //Frame size with refs.
                        writer.WriteBit(false); //Render and frame size different.
                        writer.WriteBit(header.AllowHighPrecisionMv);
                        writer.WriteBit(header.RawInterpolationFilter == 4);

                        if (header.RawInterpolationFilter != 4)
                        {
                            writer.WriteU(header.RawInterpolationFilter, 2);
                        }
                    }
                }

                if (!errorResilientMode)
                {
                    writer.WriteBit(false); //Refresh frame context.
                    writer.WriteBit(true);  //Frame parallel decoding mode.
                }

                writer.WriteU(0, 2); //Frame context index.

                writer.WriteU(header.LoopFilterLevel, 6);
                writer.WriteU(header.LoopFilterSharpness, 3);
                writer.WriteBit(header.LoopFilterDeltaEnabled);

                if (header.LoopFilterDeltaEnabled)
                {
                    bool[] updateLoopFilterRefDeltas  = new bool[4];
                    bool[] updateLoopFilterModeDeltas = new bool[2];

                    bool loopFilterDeltaUpdate = false;

                    for (int index = 0; index < header.LoopFilterRefDeltas.Length; index++)
                    {
                        sbyte old = _loopFilterRefDeltas[index];
                        sbyte New = header.LoopFilterRefDeltas[index];

                        loopFilterDeltaUpdate |= (updateLoopFilterRefDeltas[index] = old != New);
                    }

                    for (int index = 0; index < header.LoopFilterModeDeltas.Length; index++)
                    {
                        sbyte old = _loopFilterModeDeltas[index];
                        sbyte New = header.LoopFilterModeDeltas[index];

                        loopFilterDeltaUpdate |= (updateLoopFilterModeDeltas[index] = old != New);
                    }

                    writer.WriteBit(loopFilterDeltaUpdate);

                    if (loopFilterDeltaUpdate)
                    {
                        for (int index = 0; index < header.LoopFilterRefDeltas.Length; index++)
                        {
                            writer.WriteBit(updateLoopFilterRefDeltas[index]);

                            if (updateLoopFilterRefDeltas[index])
                            {
                                writer.WriteS(header.LoopFilterRefDeltas[index], 6);
                            }
                        }

                        for (int index = 0; index < header.LoopFilterModeDeltas.Length; index++)
                        {
                            writer.WriteBit(updateLoopFilterModeDeltas[index]);

                            if (updateLoopFilterModeDeltas[index])
                            {
                                writer.WriteS(header.LoopFilterModeDeltas[index], 6);
                            }
                        }
                    }
                }

                writer.WriteU(header.BaseQIndex, 8);

                writer.WriteDeltaQ(header.DeltaQYDc);
                writer.WriteDeltaQ(header.DeltaQUvDc);
                writer.WriteDeltaQ(header.DeltaQUvAc);

                writer.WriteBit(false); //Segmentation enabled (TODO).

                int minTileColsLog2 = CalcMinLog2TileCols(header.CurrentFrame.Width);
                int maxTileColsLog2 = CalcMaxLog2TileCols(header.CurrentFrame.Width);

                int tileColsLog2Diff = header.TileColsLog2 - minTileColsLog2;

                int tileColsLog2IncMask = (1 << tileColsLog2Diff) - 1;

                //If it's less than the maximum, we need to add an extra 0 on the bitstream
                //to indicate that it should stop reading.
                if (header.TileColsLog2 < maxTileColsLog2)
                {
                    writer.WriteU(tileColsLog2IncMask << 1, tileColsLog2Diff + 1);
                }
                else
                {
                    writer.WriteU(tileColsLog2IncMask, tileColsLog2Diff);
                }

                bool tileRowsLog2IsNonZero = header.TileRowsLog2 != 0;

                writer.WriteBit(tileRowsLog2IsNonZero);

                if (tileRowsLog2IsNonZero)
                {
                    writer.WriteBit(header.TileRowsLog2 > 1);
                }

                writer.WriteU(compressedHeaderData.Length, 16);

                writer.Flush();

                encodedHeader.Write(compressedHeaderData, 0, compressedHeaderData.Length);

                if (!FFmpegWrapper.IsInitialized)
                {
                    FFmpegWrapper.Vp9Initialize();
                }

                FFmpegWrapper.DecodeFrame(DecoderHelper.Combine(encodedHeader.ToArray(), frameData));
            }

            _loopFilterRefDeltas  = header.LoopFilterRefDeltas;
            _loopFilterModeDeltas = header.LoopFilterModeDeltas;
        }
Ejemplo n.º 2
0
        private void Execute(NvGpuVmm vmm, int[] arguments)
        {
            if (_currentVideoCodec == VideoCodec.H264)
            {
                int frameDataSize = vmm.ReadInt32(_decoderContextAddress + 0x48);

                H264ParameterSets Params = MemoryHelper.Read <H264ParameterSets>(vmm.Memory, vmm.GetPhysicalAddress(_decoderContextAddress + 0x58));

                H264Matrices matrices = new H264Matrices()
                {
                    ScalingMatrix4 = vmm.ReadBytes(_decoderContextAddress + 0x1c0, 6 * 16),
                    ScalingMatrix8 = vmm.ReadBytes(_decoderContextAddress + 0x220, 2 * 64)
                };

                byte[] frameData = vmm.ReadBytes(_frameDataAddress, frameDataSize);

                _h264Decoder.Decode(Params, matrices, frameData);
            }
            else if (_currentVideoCodec == VideoCodec.Vp9)
            {
                int frameDataSize = vmm.ReadInt32(_decoderContextAddress + 0x30);

                Vp9FrameKeys keys = new Vp9FrameKeys()
                {
                    CurrKey = vmm.GetPhysicalAddress(_vpxCurrLumaAddress),
                    Ref0Key = vmm.GetPhysicalAddress(_vpxRef0LumaAddress),
                    Ref1Key = vmm.GetPhysicalAddress(_vpxRef1LumaAddress),
                    Ref2Key = vmm.GetPhysicalAddress(_vpxRef2LumaAddress)
                };

                Vp9FrameHeader header = MemoryHelper.Read <Vp9FrameHeader>(vmm.Memory, vmm.GetPhysicalAddress(_decoderContextAddress + 0x48));

                Vp9ProbabilityTables probs = new Vp9ProbabilityTables()
                {
                    SegmentationTreeProbs = vmm.ReadBytes(_vpxProbTablesAddress + 0x387, 0x7),
                    SegmentationPredProbs = vmm.ReadBytes(_vpxProbTablesAddress + 0x38e, 0x3),
                    Tx8x8Probs            = vmm.ReadBytes(_vpxProbTablesAddress + 0x470, 0x2),
                    Tx16x16Probs          = vmm.ReadBytes(_vpxProbTablesAddress + 0x472, 0x4),
                    Tx32x32Probs          = vmm.ReadBytes(_vpxProbTablesAddress + 0x476, 0x6),
                    CoefProbs             = vmm.ReadBytes(_vpxProbTablesAddress + 0x5a0, 0x900),
                    SkipProbs             = vmm.ReadBytes(_vpxProbTablesAddress + 0x537, 0x3),
                    InterModeProbs        = vmm.ReadBytes(_vpxProbTablesAddress + 0x400, 0x1c),
                    InterpFilterProbs     = vmm.ReadBytes(_vpxProbTablesAddress + 0x52a, 0x8),
                    IsInterProbs          = vmm.ReadBytes(_vpxProbTablesAddress + 0x41c, 0x4),
                    CompModeProbs         = vmm.ReadBytes(_vpxProbTablesAddress + 0x532, 0x5),
                    SingleRefProbs        = vmm.ReadBytes(_vpxProbTablesAddress + 0x580, 0xa),
                    CompRefProbs          = vmm.ReadBytes(_vpxProbTablesAddress + 0x58a, 0x5),
                    YModeProbs0           = vmm.ReadBytes(_vpxProbTablesAddress + 0x480, 0x20),
                    YModeProbs1           = vmm.ReadBytes(_vpxProbTablesAddress + 0x47c, 0x4),
                    PartitionProbs        = vmm.ReadBytes(_vpxProbTablesAddress + 0x4e0, 0x40),
                    MvJointProbs          = vmm.ReadBytes(_vpxProbTablesAddress + 0x53b, 0x3),
                    MvSignProbs           = vmm.ReadBytes(_vpxProbTablesAddress + 0x53e, 0x3),
                    MvClassProbs          = vmm.ReadBytes(_vpxProbTablesAddress + 0x54c, 0x14),
                    MvClass0BitProbs      = vmm.ReadBytes(_vpxProbTablesAddress + 0x540, 0x3),
                    MvBitsProbs           = vmm.ReadBytes(_vpxProbTablesAddress + 0x56c, 0x14),
                    MvClass0FrProbs       = vmm.ReadBytes(_vpxProbTablesAddress + 0x560, 0xc),
                    MvFrProbs             = vmm.ReadBytes(_vpxProbTablesAddress + 0x542, 0x6),
                    MvClass0HpProbs       = vmm.ReadBytes(_vpxProbTablesAddress + 0x548, 0x2),
                    MvHpProbs             = vmm.ReadBytes(_vpxProbTablesAddress + 0x54a, 0x2)
                };

                byte[] frameData = vmm.ReadBytes(_frameDataAddress, frameDataSize);

                _vp9Decoder.Decode(keys, header, probs, frameData);
            }
            else
            {
                ThrowUnimplementedCodec();
            }
        }