コード例 #1
0
        private void EncodeTermSubExp(VpxRangeEncoder writer, int value)
        {
            if (WriteLessThan(writer, value, 16))
            {
                writer.Write(value, 4);
            }
            else if (WriteLessThan(writer, value, 32))
            {
                writer.Write(value - 16, 4);
            }
            else if (WriteLessThan(writer, value, 64))
            {
                writer.Write(value - 32, 5);
            }
            else
            {
                value -= 64;

                const int size = 8;

                int mask = (1 << size) - 191;

                int delta = value - mask;

                if (delta < 0)
                {
                    writer.Write(value, size - 1);
                }
                else
                {
                    writer.Write(delta / 2 + mask, size - 1);
                    writer.Write(delta & 1, 1);
                }
            }
        }
コード例 #2
0
        private void EncodeTermSubExp(VpxRangeEncoder Writer, int Value)
        {
            if (WriteLessThan(Writer, Value, 16))
            {
                Writer.Write(Value, 4);
            }
            else if (WriteLessThan(Writer, Value, 32))
            {
                Writer.Write(Value - 16, 4);
            }
            else if (WriteLessThan(Writer, Value, 64))
            {
                Writer.Write(Value - 32, 5);
            }
            else
            {
                Value -= 64;

                const int Size = 8;

                int Mask = (1 << Size) - 191;

                int Delta = Value - Mask;

                if (Delta < 0)
                {
                    Writer.Write(Value, Size - 1);
                }
                else
                {
                    Writer.Write(Delta / 2 + Mask, Size - 1);
                    Writer.Write(Delta & 1, 1);
                }
            }
        }
コード例 #3
0
 private void WriteProbabilityUpdate(VpxRangeEncoder writer, byte[] New, byte[] old)
 {
     for (int offset = 0; offset < New.Length; offset++)
     {
         WriteProbabilityUpdate(writer, New[offset], old[offset]);
     }
 }
コード例 #4
0
 private void WriteProbabilityUpdate(VpxRangeEncoder Writer, byte[] New, byte[] Old)
 {
     for (int Offset = 0; Offset < New.Length; Offset++)
     {
         WriteProbabilityUpdate(Writer, New[Offset], Old[Offset]);
     }
 }
コード例 #5
0
        private bool WriteLessThan(VpxRangeEncoder writer, int value, int test)
        {
            bool isLessThan = value < test;

            writer.Write(!isLessThan);

            return(isLessThan);
        }
コード例 #6
0
        private bool WriteLessThan(VpxRangeEncoder Writer, int Value, int Test)
        {
            bool IsLessThan = Value < Test;

            Writer.Write(!IsLessThan);

            return(IsLessThan);
        }
コード例 #7
0
 private void WriteProbabilityUpdateAligned4(VpxRangeEncoder writer, byte[] New, byte[] old)
 {
     for (int offset = 0; offset < New.Length; offset += 4)
     {
         WriteProbabilityUpdate(writer, New[offset + 0], old[offset + 0]);
         WriteProbabilityUpdate(writer, New[offset + 1], old[offset + 1]);
         WriteProbabilityUpdate(writer, New[offset + 2], old[offset + 2]);
     }
 }
コード例 #8
0
 private void WriteProbabilityUpdateAligned4(VpxRangeEncoder Writer, byte[] New, byte[] Old)
 {
     for (int Offset = 0; Offset < New.Length; Offset += 4)
     {
         WriteProbabilityUpdate(Writer, New[Offset + 0], Old[Offset + 0]);
         WriteProbabilityUpdate(Writer, New[Offset + 1], Old[Offset + 1]);
         WriteProbabilityUpdate(Writer, New[Offset + 2], Old[Offset + 2]);
     }
 }
コード例 #9
0
        private void WriteMvProbabilityUpdate(VpxRangeEncoder writer, byte New, byte old)
        {
            bool update = New != old;

            writer.Write(update, DiffUpdateProbability);

            if (update)
            {
                writer.Write(New >> 1, 7);
            }
        }
コード例 #10
0
        private void WriteProbabilityUpdate(VpxRangeEncoder writer, byte New, byte old)
        {
            bool update = New != old;

            writer.Write(update, DiffUpdateProbability);

            if (update)
            {
                WriteProbabilityDelta(writer, New, old);
            }
        }
コード例 #11
0
        private void WriteMvProbabilityUpdate(VpxRangeEncoder Writer, byte New, byte Old)
        {
            bool Update = New != Old;

            Writer.Write(Update, DiffUpdateProbability);

            if (Update)
            {
                Writer.Write(New >> 1, 7);
            }
        }
コード例 #12
0
        private void WriteProbabilityDelta(VpxRangeEncoder writer, int New, int old)
        {
            int delta = RemapProbability(New, old);

            EncodeTermSubExp(writer, delta);
        }
コード例 #13
0
        private void WriteCoefProbabilityUpdate(VpxRangeEncoder writer, int txMode, byte[] New, byte[] old)
        {
            //Note: There's 1 byte added on each packet for alignment,
            //this byte is ignored when doing updates.
            const int blockBytes = 2 * 2 * 6 * 6 * 4;

            bool NeedsUpdate(int baseIndex)
            {
                int index = baseIndex;

                for (int i = 0; i < 2; i++)
                {
                    for (int j = 0; j < 2; j++)
                    {
                        for (int k = 0; k < 6; k++)
                        {
                            for (int l = 0; l < 6; l++)
                            {
                                if (New[index + 0] != old[index + 0] ||
                                    New[index + 1] != old[index + 1] ||
                                    New[index + 2] != old[index + 2])
                                {
                                    return(true);
                                }

                                index += 4;
                            }
                        }
                    }
                }

                return(false);
            }

            for (int blockIndex = 0; blockIndex < 4; blockIndex++)
            {
                int baseIndex = blockIndex * blockBytes;

                bool update = NeedsUpdate(baseIndex);

                writer.Write(update);

                if (update)
                {
                    int index = baseIndex;

                    for (int i = 0; i < 2; i++)
                    {
                        for (int j = 0; j < 2; j++)
                        {
                            for (int k = 0; k < 6; k++)
                            {
                                for (int l = 0; l < 6; l++)
                                {
                                    if (k != 0 || l < 3)
                                    {
                                        WriteProbabilityUpdate(writer, New[index + 0], old[index + 0]);
                                        WriteProbabilityUpdate(writer, New[index + 1], old[index + 1]);
                                        WriteProbabilityUpdate(writer, New[index + 2], old[index + 2]);
                                    }

                                    index += 4;
                                }
                            }
                        }
                    }
                }

                if (blockIndex == txMode)
                {
                    break;
                }
            }
        }
コード例 #14
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;
        }
コード例 #15
0
        private void WriteProbabilityDelta(VpxRangeEncoder Writer, int New, int Old)
        {
            int Delta = RemapProbability(New, Old);

            EncodeTermSubExp(Writer, Delta);
        }
コード例 #16
0
        private void WriteCoefProbabilityUpdate(VpxRangeEncoder Writer, int TxMode, byte[] New, byte[] Old)
        {
            //Note: There's 1 byte added on each packet for alignment,
            //this byte is ignored when doing updates.
            const int BlockBytes = 2 * 2 * 6 * 6 * 4;

            bool NeedsUpdate(int BaseIndex)
            {
                int Index = BaseIndex;

                for (int i = 0; i < 2; i++)
                {
                    for (int j = 0; j < 2; j++)
                    {
                        for (int k = 0; k < 6; k++)
                        {
                            for (int l = 0; l < 6; l++)
                            {
                                if (New[Index + 0] != Old[Index + 0] ||
                                    New[Index + 1] != Old[Index + 1] ||
                                    New[Index + 2] != Old[Index + 2])
                                {
                                    return(true);
                                }

                                Index += 4;
                            }
                        }
                    }
                }

                return(false);
            }

            for (int BlockIndex = 0; BlockIndex < 4; BlockIndex++)
            {
                int BaseIndex = BlockIndex * BlockBytes;

                bool Update = NeedsUpdate(BaseIndex);

                Writer.Write(Update);

                if (Update)
                {
                    int Index = BaseIndex;

                    for (int i = 0; i < 2; i++)
                    {
                        for (int j = 0; j < 2; j++)
                        {
                            for (int k = 0; k < 6; k++)
                            {
                                for (int l = 0; l < 6; l++)
                                {
                                    if (k != 0 || l < 3)
                                    {
                                        WriteProbabilityUpdate(Writer, New[Index + 0], Old[Index + 0]);
                                        WriteProbabilityUpdate(Writer, New[Index + 1], Old[Index + 1]);
                                        WriteProbabilityUpdate(Writer, New[Index + 2], Old[Index + 2]);
                                    }

                                    Index += 4;
                                }
                            }
                        }
                    }
                }

                if (BlockIndex == TxMode)
                {
                    break;
                }
            }
        }