void ObjectElement(BitExtractor extractor, int objectCount, int bedOrISFObjects) { MDUpdateInfo(extractor); if (!extractor.ReadBit()) // Reserved { extractor.Skip(5); } if (blockUsed.Length != rampDuration.Length || infoBlocks.Length != objectCount) { blockUsed = new bool[rampDuration.Length]; infoBlocks = new ObjectInfoBlock[objectCount][]; for (int obj = 0; obj < objectCount; ++obj) { infoBlocks[obj] = new ObjectInfoBlock[rampDuration.Length]; for (int blk = 0; blk < infoBlocks[obj].Length; ++blk) { infoBlocks[obj][blk] = new ObjectInfoBlock(); } } future = new Vector3[objectCount]; } Array.Clear(blockUsed, 0, blockUsed.Length); for (int obj = 0; obj < objectCount; ++obj) { for (int blk = 0; blk < infoBlocks[obj].Length; ++blk) { infoBlocks[obj][blk].Update(extractor, blk, obj < bedOrISFObjects); } } }
/// <summary> /// Read new information for this block. /// </summary> public void Update(BitExtractor extractor, int blk, bool bedOrISFObject) { bool inactive = extractor.ReadBit(); int basicInfoStatus = inactive ? 0 : (blk == 0 ? 1 : extractor.Read(2)); if ((basicInfoStatus & 1) == 1) { ObjectBasicInfo(extractor, basicInfoStatus == 1); } int renderInfoStatus = 0; if (!inactive && !bedOrISFObject) { renderInfoStatus = blk == 0 ? 1 : extractor.Read(2); } if ((renderInfoStatus & 1) == 1) { ObjectRenderInfo(extractor, blk, renderInfoStatus == 1); } if (extractor.ReadBit()) // Additional table data { extractor.Skip((extractor.Read(4) + 1) * 8); } if (bedOrISFObject) { anchor = ObjectAnchor.Speaker; } }
/// <summary> /// Decodes the E-AC-3 header after the ID of the decoder. /// </summary> void BitStreamInformationEAC3(BitExtractor extractor) { dialnorm = extractor.Read(5); compr = extractor.ReadConditional(8); if (ChannelMode == 0) { dialnorm2 = extractor.Read(5); compr2 = extractor.ReadConditional(8); } if (StreamType == StreamTypes.Dependent) { channelMapping = extractor.ReadConditional(channelMappingBits); } ReadMixingMetadata(extractor); ReadInfoMetadata(extractor); if (StreamType == StreamTypes.Independent && Blocks != 6) { convsync = extractor.ReadBit(); } if (StreamType == StreamTypes.Repackaged && (blkid = Blocks == 6 || extractor.ReadBit())) { frmsizecod = extractor.Read(6); } if (addbsie = extractor.ReadBit()) { addbsi = extractor.ReadBytes(extractor.Read(6) + 1); } }
void DecodeInfo(BitExtractor extractor) { int gainPower = extractor.Read(3); Gain = 1 + (extractor.Read(5) / 32f) * MathF.Pow(2, gainPower - 4); extractor.Skip(10); // Sequence counter for (int obj = 0; obj < ObjectCount; ++obj) { if (ObjectActive[obj] = extractor.ReadBit()) { bandsIndex[obj] = (byte)extractor.Read(3); bands[obj] = JointObjectCodingTables.joc_num_bands[bandsIndex[obj]]; sparseCoded[obj] = extractor.ReadBit(); quantizationTable[obj] = (byte)extractor.ReadBitInt(); // joc_data_point_info steepSlope[obj] = extractor.ReadBit(); dataPoints[obj] = extractor.Read(1) + 1; if (steepSlope[obj]) { for (int dp = 0; dp < dataPoints[obj]; ++dp) { timeslotOffsets[obj][dp] = extractor.Read(5) + 1; } } } } }
public void BitExtractor_GetBits_FourBit_Success() { byte[] data = new byte[] { 0x48, 0x45, 0x4C, 0x4C, 0x4F }; BitExtractor fourBit = new BitExtractor(data, BitsToEncode.Four); Assert.AreEqual(0xF4, fourBit.GetBits(0)); Assert.AreEqual(0xF8, fourBit.GetBits(1)); }
public void BitExtractor_GetBits_EightBit_Success() { byte[] data = new byte[] { 0x48, 0x45, 0x4C, 0x4C, 0x4F }; BitExtractor eightBit = new BitExtractor(data, BitsToEncode.Eight); Assert.AreEqual(0x48, eightBit.GetBits(0)); Assert.AreEqual(0x45, eightBit.GetBits(1)); }
public void BitExtractor_GetBits_NegativeIndex_Throws() { byte[] data = new byte[] { 0x48, 0x45, 0x4C, 0x4C, 0x4F }; BitExtractor oneBit = new BitExtractor(data, BitsToEncode.One); oneBit.GetBits(-1); }
public void BitExtractor_GetBits_IndexTooLarge_Throws() { byte[] data = new byte[] { 0x48, 0x45, 0x4C, 0x4C, 0x4F }; BitExtractor oneBit = new BitExtractor(data, BitsToEncode.One); oneBit.GetBits(40); }
public void BitExtractor_GetBits_InvalidBitsEnum_Throws() { byte[] data = new byte[] { 0x48, 0x45, 0x4C, 0x4C, 0x4F }; BitExtractor oneBit = new BitExtractor(data, (BitsToEncode)3); oneBit.GetBits(5); }
int HuffmanDecode(int[][] joc_huff_code, BitExtractor extractor) { int node = 0; do { node = joc_huff_code[node][extractor.ReadBit() ? 1 : 0]; } while (node > 0); return(-1 - node); }
public void BitExtractor_GetBits_TwoBit_Success() { byte[] data = new byte[] { 0x48, 0x45, 0x4C, 0x4C, 0x4F }; BitExtractor twoBit = new BitExtractor(data, BitsToEncode.Two); Assert.AreEqual(0xFD, twoBit.GetBits(0)); Assert.AreEqual(0xFC, twoBit.GetBits(1)); Assert.AreEqual(0xFE, twoBit.GetBits(2)); Assert.AreEqual(0xFC, twoBit.GetBits(3)); }
void DecodeHeader(BitExtractor extractor) { joc_dmx_config_idx = extractor.Read(3); if (joc_dmx_config_idx > 2) { throw new UnsupportedFeatureException("DMXconfig"); } ChannelCount = (joc_dmx_config_idx == 0 || joc_dmx_config_idx == 3) ? 5 : 7; ObjectCount = extractor.Read(6) + 1; UpdateCache(); joc_ext_config_idx = extractor.Read(3); }
/// <summary> /// Decode the next EMDF frame from a bitstream. /// </summary> public void Decode(BitExtractor extractor) { HasObjects = false; int syncword = 0; while (extractor.Position < extractor.BackPosition - 32) { syncword = ((syncword << 8) & 0xFFFF) + extractor.Read(8); // Syncwords are byte-padded if (syncword == syncWord && DecodeBlock(extractor)) { break; } } }
public void BitExtractor_Constructor_EmptyData_Success() { byte[] data = new byte[0]; BitExtractor oneBit = new BitExtractor(data, BitsToEncode.One); BitExtractor twoBit = new BitExtractor(data, BitsToEncode.Two); BitExtractor fourBit = new BitExtractor(data, BitsToEncode.Four); BitExtractor eightBit = new BitExtractor(data, BitsToEncode.Eight); Assert.AreEqual(0, oneBit.EncodedByteLength); Assert.AreEqual(0, twoBit.EncodedByteLength); Assert.AreEqual(0, fourBit.EncodedByteLength); Assert.AreEqual(0, eightBit.EncodedByteLength); }
public void BitExtractor_Constructor_Data_Success() { byte[] data = new byte[] { 0x48, 0x45, 0x4C, 0x4C, 0x4F }; BitExtractor oneBit = new BitExtractor(data, BitsToEncode.One); BitExtractor twoBit = new BitExtractor(data, BitsToEncode.Two); BitExtractor fourBit = new BitExtractor(data, BitsToEncode.Four); BitExtractor eightBit = new BitExtractor(data, BitsToEncode.Eight); Assert.AreEqual(40, oneBit.EncodedByteLength); Assert.AreEqual(20, twoBit.EncodedByteLength); Assert.AreEqual(10, fourBit.EncodedByteLength); Assert.AreEqual(5, eightBit.EncodedByteLength); }
void MDUpdateInfo(BitExtractor extractor) { sampleOffset = extractor.Read(2) switch { 0 => 0, 1 => sampleOffsetIndex[extractor.Read(2)], 2 => (byte)extractor.Read(5), _ => throw new UnsupportedFeatureException("mdOffset"), }; blockOffsetFactor = new short[extractor.Read(3) + 1]; rampDuration = new short[blockOffsetFactor.Length]; for (int blk = 0; blk < rampDuration.Length; ++blk) { BlockUpdateInfo(extractor, blk); } }
/// <summary> /// Read variable-length values from an EMDF stream with a limit on length. /// The <paramref name="limit"/> parameter takes 1 less than the actual length because reasons. /// </summary> public static int VariableBits(this BitExtractor extractor, byte bits, int limit) { int value = 0; bool readMore; do { value += extractor.Read(bits); if (readMore = extractor.ReadBit()) { value = (value + 1) << bits; } } while (readMore && limit-- != 0); return(value); }
public void BitExtractor_GetBits_OneBit_Success() { byte[] data = new byte[] { 0x48, 0x45, 0x4C, 0x4C, 0x4F }; BitExtractor oneBit = new BitExtractor(data, BitsToEncode.One); Assert.AreEqual(0xFE, oneBit.GetBits(0)); Assert.AreEqual(0xFF, oneBit.GetBits(1)); Assert.AreEqual(0xFE, oneBit.GetBits(2)); Assert.AreEqual(0xFE, oneBit.GetBits(3)); Assert.AreEqual(0xFF, oneBit.GetBits(4)); Assert.AreEqual(0xFE, oneBit.GetBits(5)); Assert.AreEqual(0xFE, oneBit.GetBits(6)); Assert.AreEqual(0xFE, oneBit.GetBits(7)); }
public void ReadMantissa(BitExtractor extractor, int[] target, int start, int end) { for (int bin = start; bin < end; ++bin) { switch (bap[bin]) { case 1: if (bap1Bits == 0) { bap1Bits = 2; extractor.Skip(bitsToRead[1]); // TODO: temp } else { --bap1Bits; } break; case 2: if (bap2Bits == 0) { bap2Bits = 2; extractor.Skip(bitsToRead[2]); // TODO: temp } else { --bap2Bits; } break; case 4: if (bap4Bits == 0) { bap4Bits = 1; extractor.Skip(bitsToRead[4]); // TODO: temp } else { --bap4Bits; } break; default: target[bin] = extractor.Read(bitsToRead[bap[bin]]); break; } } }
/// <summary> /// Decodes a OAMD frame from an EMDF payload. /// </summary> public void Decode(BitExtractor extractor, int offset) { this.offset = offset; int versionNumber = extractor.Read(2); if (versionNumber == 3) { versionNumber += extractor.Read(3); } if (versionNumber != 0) { throw new UnsupportedFeatureException("OAver"); } ObjectCount = extractor.Read(5) + 1; if (ObjectCount == 32) { ObjectCount += extractor.Read(7); } ProgramAssignment(extractor); bool alternateObjectPresent = extractor.ReadBit(); int elementCount = extractor.Read(4); if (elementCount == 15) { elementCount += extractor.Read(5); } int bedOrISFObjects = beds; if (isfInUse) { bedOrISFObjects += isfObjectCount[isfIndex]; } if (elements.Length != elementCount) { elements = new OAElementMD[elementCount]; for (int i = 0; i < elementCount; ++i) { elements[i] = new OAElementMD(); } } for (int i = 0; i < elementCount; ++i) { elements[i].Read(extractor, alternateObjectPresent, ObjectCount, bedOrISFObjects); } }
/// <summary> /// Decodes the legacy or alternative AC-3 header after the ID of the decoder. /// </summary> void BitStreamInformation(BitExtractor extractor) { if ((ChannelMode & 0x1) != 0 && (ChannelMode != 0x1)) // 3 fronts exist { centerDownmix = extractor.Read(2); } if ((ChannelMode & 0x4) != 0) // Surrounds exist { surroundDownmix = extractor.Read(2); } if (ChannelMode == 0x2) // Stereo { dsurmod = extractor.Read(2); } LFE = extractor.ReadBit(); dialnorm = extractor.Read(5); compr = extractor.ReadConditional(8); langcod = extractor.ReadConditional(8); if (audprodie = extractor.ReadBit()) { mixlevel = extractor.Read(5); roomtyp = extractor.Read(2); } if (ChannelMode == 0) { dialnorm2 = extractor.Read(5); compr2 = extractor.ReadConditional(8); langcod2 = extractor.ReadConditional(8); if (audprodi2e = extractor.ReadBit()) { mixlevel2 = extractor.Read(5); roomtyp2 = extractor.Read(2); } } copyrightb = extractor.ReadBit(); origbs = extractor.ReadBit(); additionalDownmixInfo = extractor.ReadConditional(14); additionalMixInfo = extractor.ReadConditional(14); if (addbsie = extractor.ReadBit()) { addbsi = extractor.ReadBytes(extractor.Read(6) + 1); } }
/// <summary> /// Read the delta bit allocation from the bitstream. /// </summary> public void Read(BitExtractor extractor) { int segments = extractor.Read(3) + 1; if (Offset.Length != segments) { Offset = new int[segments]; Length = new int[segments]; BitAllocation = new int[segments]; } for (int segment = 0; segment < segments; ++segment) { Offset[segment] = extractor.Read(5); Length[segment] = extractor.Read(4); BitAllocation[segment] = extractor.Read(3); } }
/// <summary> /// Decodes an object audio element metadata block. /// </summary> public void Read(BitExtractor extractor, bool alternateObjectPresent, int objectCount, int bedOrISFObjects) { int elementIndex = extractor.Read(4); int endPos = extractor.Position + ExtensibleMetadataExtensions.VariableBits(extractor, 4, 4) + 1; extractor.Skip(alternateObjectPresent ? 5 : 1); switch (elementIndex) { case objectElementIndex: ObjectElement(extractor, objectCount, bedOrISFObjects); break; case extendedObjectElementIndex: // TODO: support other element types default: blockOffsetFactor = new short[] { -1 }; break; } extractor.Position = endPos; // Padding }
void BlockUpdateInfo(BitExtractor extractor, int blk) { blockOffsetFactor[blk] = (short)(extractor.Read(6) + sampleOffset); int rampDurationCode = extractor.Read(2); if (rampDurationCode == 3) { if (extractor.ReadBit()) { rampDuration[blk] = rampDurationIndex[extractor.Read(4)]; } else { rampDuration[blk] = (short)extractor.Read(11); } } else { rampDuration[blk] = rampDurations[rampDurationCode]; } }
void DecodeData(BitExtractor extractor) { for (int obj = 0; obj < ObjectCount; ++obj) { if (ObjectActive[obj]) { for (int dp = 0; dp < dataPoints[obj]; ++dp) { int[][] codeTable; if (sparseCoded[obj]) { jocChannel[obj][dp][0] = extractor.Read(3); codeTable = JointObjectCodingTables.GetHuffCodeTable(ChannelCount, HuffmanType.IDX); for (int pb = 1; pb < bands[obj]; ++pb) { jocChannel[obj][dp][pb] = HuffmanDecode(codeTable, extractor); } codeTable = JointObjectCodingTables.GetHuffCodeTable(quantizationTable[obj], HuffmanType.VEC); for (int pb = 0; pb < bands[obj]; ++pb) { jocVector[obj][dp][pb] = HuffmanDecode(codeTable, extractor); } } else { codeTable = JointObjectCodingTables.GetHuffCodeTable(quantizationTable[obj], HuffmanType.MTX); for (int ch = 0; ch < ChannelCount; ++ch) { for (int pb = 0; pb < bands[obj]; ++pb) { jocMatrix[obj][dp][ch][pb] = HuffmanDecode(codeTable, extractor); } } } } } } }
/// <summary> /// Parse informational metadata. /// </summary> void ReadInfoMetadata(BitExtractor extractor) { if (!(infomdate = extractor.ReadBit())) { return; } bsmod = extractor.Read(3); copyrightb = extractor.ReadBit(); origbs = extractor.ReadBit(); if (ChannelMode == 2) { dsurmod = extractor.Read(2); dheadphonmod = extractor.Read(2); } if (ChannelMode >= 6) { dsurexmod = extractor.Read(2); } if (audprodie = extractor.ReadBit()) { mixlevel = extractor.Read(5); roomtyp = extractor.Read(2); adconvtyp = extractor.ReadBit(); } if (ChannelMode == 0) { if (audprodi2e = extractor.ReadBit()) { mixlevel2 = extractor.Read(5); roomtyp2 = extractor.Read(2); adconvtyp2 = extractor.ReadBit(); } } if (SampleRateCode < 3) { sourcefscod = extractor.ReadBit(); } }
void ObjectBasicInfo(BitExtractor extractor, bool readAllBlocks) { int blocks = readAllBlocks ? 3 : extractor.Read(2); // Gain if ((blocks & 2) != 0) { int gainHelper = extractor.Read(2); gain = gainHelper switch { 0 => 1, 1 => 0, 2 => (gainHelper = extractor.Read(6)) < 15 ? QMath.DbToGain(15 - gainHelper) : QMath.DbToGain(14 - gainHelper), _ => - 1, }; } // Priority - unneccessary, everything's rendered if ((blocks & 1) != 0 && !extractor.ReadBit()) { extractor.Skip(5); } }
/// <summary> /// Decodes a JOC frame from an EMDF payload. /// </summary> public void Decode(BitExtractor extractor) { DecodeHeader(extractor); DecodeInfo(extractor); DecodeData(extractor); }
void ProgramAssignment(BitExtractor extractor) { if (extractor.ReadBit()) // Dynamic object-only program { if (extractor.ReadBit()) // LFE present { bedAssignment = new bool[1][]; bedAssignment[0] = new bool[(int)NonStandardBedChannel.Max]; bedAssignment[0][(int)NonStandardBedChannel.LowFrequencyEffects] = true; } } else { int contentDescription = extractor.Read(4); // Object(s) with speaker-anchored coordinate(s) (bed objects) if ((contentDescription & 8) != 0) { extractor.Skip(1); // The object is distributable - Cavern will do it anyway bedAssignment = new bool[extractor.ReadBit() ? extractor.Read(3) + 2 : 1][]; for (int bed = 0; bed < bedAssignment.Length; ++bed) { if (extractor.ReadBit()) // LFE only { bedAssignment[bed] = new bool[(int)NonStandardBedChannel.Max]; bedAssignment[bed][(int)NonStandardBedChannel.LowFrequencyEffects] = true; } else { if (extractor.ReadBit()) // Standard bed assignment { bool[] standardAssignment = extractor.ReadBits(10); for (int i = 0; i < standardAssignment.Length; ++i) { for (int j = 0; j < standardBedChannels[i].Length; ++j) { bedAssignment[bed][standardBedChannels[i][j]] = standardAssignment[i]; } } } else { bedAssignment[bed] = extractor.ReadBits((int)NonStandardBedChannel.Max); } } } } // Intermediate spatial format (ISF) if (isfInUse = (contentDescription & 4) != 0) { isfIndex = (byte)extractor.Read(3); if (isfIndex >= isfObjectCount.Length) { throw new UnsupportedFeatureException("ISF"); } } // Object(s) with room-anchored or screen-anchored coordinates if ((contentDescription & 2) != 0) // This is useless, same as ObjectCount - bedOrISFObjects, also found in JOC { if (extractor.Read(5) == 31) { extractor.Skip(7); } } // Reserved if ((contentDescription & 1) != 0) { extractor.Skip((extractor.Read(4) + 1) * 8); } } beds = 0; for (int bed = 0; bed < bedAssignment.Length; ++bed) { for (int i = 0; i < (int)NonStandardBedChannel.Max; ++i) { if (bedAssignment[bed][i]) { ++beds; } } } }
public void BitExtractor_Constructor_NullData_Throws() { BitExtractor extractor = new BitExtractor(null, BitsToEncode.One); }