using System;
using System.Buffers.Binary;
using System.Collections.Generic;
using System.Text;
namespace JT1078.Flv.MessagePack
{
///
/// Exp-Golomb指数哥伦布编码
///
public ref struct ExpGolombReader
{
public ReadOnlySpan SrcBuffer { get; }
public int BytesAvailable { get; private set; }
public int Word { get; private set; }
public int BitsAvailable { get; private set; }
public ExpGolombReader(ReadOnlySpan srcBuffer)
{
SrcBuffer = srcBuffer;
BytesAvailable = srcBuffer.Length;
Word = 0;
BitsAvailable = 0;
}
public (byte profileIdc,byte levelIdc,uint profileCompat,int width, int height) ReadSPS()
{
int sarScale = 1;
uint frameCropLeftOffset=0;
uint frameCropRightOffset = 0;
uint frameCropTopOffset = 0;
uint frameCropBottomOffset = 0;
ReadByte();
//profile_idc
byte profileIdc = ReadByte();
//constraint_set[0-4]_flag, u(5)
uint profileCompat = ReadBits(5);
//reserved_zero_3bits
SkipBits(3);
//level_idc u(8)
byte levelIdc = ReadByte();
//seq_parameter_set_id
SkipUEG();
if (profileIdc == 100 ||
profileIdc == 110 ||
profileIdc == 122 ||
profileIdc == 244 ||
profileIdc == 44 ||
profileIdc == 83 ||
profileIdc == 86 ||
profileIdc == 118 ||
profileIdc == 128)
{
uint chromaFormatIdc = ReadUEG();
if (chromaFormatIdc == 3)
{
SkipBits(1); // separate_colour_plane_flag
}
SkipUEG(); // bit_depth_luma_minus8
SkipUEG(); // bit_depth_chroma_minus8
SkipBits(1); // qpprime_y_zero_transform_bypass_flag
if (ReadBoolean())
{ // seq_scaling_matrix_present_flag
int scalingListCount = (chromaFormatIdc != 3) ? 8 : 12;
for (int i = 0; i < scalingListCount; i++)
{
if (ReadBoolean())
{ // seq_scaling_list_present_flag[ i ]
if (i < 6)
{
SkipScalingList(16);
}
else
{
SkipScalingList(64);
}
}
}
}
}
// log2_max_frame_num_minus4
SkipUEG();
var picOrderCntType = ReadUEG();
if (picOrderCntType == 0)
{
ReadUEG(); //log2_max_pic_order_cnt_lsb_minus4
}
else if (picOrderCntType == 1)
{
SkipBits(1); // delta_pic_order_always_zero_flag
SkipEG(); // offset_for_non_ref_pic
SkipEG(); // offset_for_top_to_bottom_field
uint numRefFramesInPicOrderCntCycle = ReadUEG();
for (int i = 0; i < numRefFramesInPicOrderCntCycle; i++)
{
SkipEG(); // offset_for_ref_frame[ i ]
}
}
SkipUEG(); // max_num_ref_frames
SkipBits(1); // gaps_in_frame_num_value_allowed_flag
uint picWidthInMbsMinus1 = ReadUEG();
uint picHeightInMapUnitsMinus1 = ReadUEG();
uint frameMbsOnlyFlag = ReadBits(1);
if (frameMbsOnlyFlag == 0)
{
SkipBits(1); // mb_adaptive_frame_field_flag
}
this.SkipBits(1); // direct_8x8_inference_flag
if (ReadBoolean())
{
// frame_cropping_flag
frameCropLeftOffset = ReadUEG();
frameCropRightOffset = ReadUEG();
frameCropTopOffset = ReadUEG();
frameCropBottomOffset = ReadUEG();
}
if (ReadBoolean())
{
// vui_parameters_present_flag
if (ReadBoolean())
{
// aspect_ratio_info_present_flag
byte[] sarRatio=null;
byte aspectRatioIdc = ReadByte();
switch (aspectRatioIdc)
{
case 1: sarRatio =new byte[2] { 1, 1 }; break;
case 2: sarRatio =new byte[2] { 12, 11}; break;
case 3: sarRatio =new byte[2] { 10, 11}; break;
case 4: sarRatio =new byte[2] { 16, 11}; break;
case 5: sarRatio =new byte[2] { 40, 33}; break;
case 6: sarRatio =new byte[2] { 24, 11}; break;
case 7: sarRatio =new byte[2] { 20, 11}; break;
case 8: sarRatio =new byte[2] { 32, 11 }; break;
case 9: sarRatio = new byte[2] {80, 33 }; break;
case 10: sarRatio = new byte[2]{18, 11 }; break;
case 11: sarRatio = new byte[2]{15, 11 }; break;
case 12: sarRatio = new byte[2]{64, 33 }; break;
case 13: sarRatio = new byte[2]{160, 99 }; break;
case 14: sarRatio = new byte[2]{4, 3 }; break;
case 15: sarRatio = new byte[2]{3, 2 }; break;
case 16: sarRatio = new byte[2]{ 2, 1 }; break;
case 255:
{
sarRatio = new byte[2] { (byte)(ReadByte() << 8 | ReadByte()), (byte)(ReadByte() << 8 | ReadByte()) };
break;
}
}
if (sarRatio != null)
{
sarScale = sarRatio[0] / sarRatio[1];
}
}
}
int width= (int)((((picWidthInMbsMinus1 + 1) * 16) - frameCropLeftOffset * 2 - frameCropRightOffset * 2) * sarScale);
int height = (int)(((2 - frameMbsOnlyFlag) * (picHeightInMapUnitsMinus1 + 1) * 16) - ((frameMbsOnlyFlag == 1U ? 2 : 4) * (frameCropTopOffset + frameCropBottomOffset)));
return (profileIdc, levelIdc, profileCompat,width, height);
}
public void LoadWord()
{
var position = SrcBuffer.Length - BytesAvailable;
int tmpAvailableBytes = BytesAvailable - 4;
int availableBytes = Math.Min(4, BytesAvailable);
//if (availableBytes == 0)
//{
// throw new OverflowException("no bytes available");
//}
ReadOnlySpan workingBytes=ReadOnlySpan.Empty;
if (tmpAvailableBytes < 0)
{
var buffer = new byte[4];
Array.Copy(SrcBuffer.Slice(position, BytesAvailable).ToArray(), buffer, BytesAvailable);
workingBytes = buffer;
}
else
{
workingBytes = SrcBuffer.Slice(position, 4);
}
Word = BinaryPrimitives.ReadInt32BigEndian(workingBytes);
// track the amount of this.data that has been processed
BitsAvailable = availableBytes * 8;
BytesAvailable -= availableBytes;
}
public void SkipBits(int count)
{
if (BitsAvailable > count)
{
Word <<= count;
BitsAvailable -= count;
}
else
{
count -= BitsAvailable;
int skipBytes = count >> 3;
count -= (skipBytes >> 3);
LoadWord();
Word <<= count;
BitsAvailable -= count;
}
}
public uint ReadBits(int size)
{
var bits = Math.Min(BitsAvailable, size); // :uint
var valu = (uint)Word >> (32 - bits); // :uint
if (size > 32)
{
throw new OverflowException("Cannot read more than 32 bits at a time");
}
BitsAvailable -= bits;
if (BitsAvailable > 0)
{
Word <<= bits;
}
else if (BytesAvailable > 0)
{
LoadWord();
}
bits = size - bits;
if (bits > 0)
{
return ((valu << bits) | ReadBits(bits));
}
else
{
return valu;
}
}
public int SkipLZ()
{
int leadingZeroCount; // :uint
for (leadingZeroCount = 0; leadingZeroCount < this.BitsAvailable; ++leadingZeroCount)
{
if (0 != (Word & (0x80000000 >> leadingZeroCount)))
{
// the first bit of working word is 1
Word <<= leadingZeroCount;
BitsAvailable -= leadingZeroCount;
return leadingZeroCount;
}
}
// we exhausted word and still have not found a 1
LoadWord();
return (leadingZeroCount + SkipLZ());
}
public void SkipUEG()
{
SkipBits(1 + SkipLZ());
}
public void SkipEG()
{
SkipBits(1 + SkipLZ());
}
public uint ReadUEG()
{
var clz =SkipLZ();
return ReadBits(clz + 1) - 1;
}
public int ReadEG()
{
var valu = (int)ReadUEG(); // :int
if ((0x01 & valu)==1)
{
// the number is odd if the low order bit is set
return (1 + valu) >> 1; // add 1 to make it even, and divide by 2
}
else
{
return -1 * (valu >> 1); // divide by two then make it negative
}
}
public bool ReadBoolean()
{
return 1 == ReadBits(1);
}
public byte ReadByte()
{
return (byte)ReadBits(8);
}
public ushort ReadUShort()
{
return (ushort)ReadBits(16);
}
public uint ReadUInt()
{
return ReadBits(32);
}
///
///Advance the ExpGolomb decoder past a scaling list.The scaling
///list is optionally transmitted as part of a sequence parameter
///set and is not relevant to transmuxing.
///@param count { number}
///the number of entries in this scaling list
///@see Recommendation ITU-T H.264, Section 7.3.2.1.1.1
///
///
public void SkipScalingList(int count)
{
int lastScale = 8,
nextScale = 8,
j,
deltaScale;
for (j = 0; j < count; j++)
{
if (nextScale != 0)
{
deltaScale = ReadEG();
nextScale = (lastScale + deltaScale + 256) % 256;
}
lastScale = (nextScale == 0) ? lastScale : nextScale;
}
}
}
}