├── .gitignore ├── CODE_OF_CONDUCT.md ├── Cinegy.TsDecoder.Tests ├── Buffers │ └── RingBufferTests.cs ├── Cinegy.TsDecoder.Tests.csproj ├── DescriptorTests │ └── DescriptorDeserializerTests.cs ├── TestStreams │ ├── 11720-2017-07-09-16-01-43.ts │ ├── 11954-2017-07-09-16-05-06.ts │ ├── D2-TS-HD-AC3-Blue-45mbps.ts │ ├── SD-H264-1mbps-Bars.ts │ ├── cut-2ts.ts │ └── cut-bbchd-dvbs2mux.ts └── TransportStream │ ├── DescriptorTests.cs │ └── TsPacketFactoryTests.cs ├── Cinegy.TsDecoder.sln ├── Cinegy.TsDecoder ├── Buffers │ └── RingBuffer.cs ├── Cinegy.TsDecoder.csproj ├── DataAccess │ ├── BitReader.cs │ └── BitWriter.cs ├── Descriptors │ ├── AacDescriptor.cs │ ├── Ac3Descriptor.cs │ ├── AvcVideoDescriptor.cs │ ├── BouquetNameDescriptor.cs │ ├── CaDescriptor.cs │ ├── CaIdentifierDescriptor.cs │ ├── CinegyDaniel2Descriptor.cs │ ├── CinegyTechMetadataDescriptor.cs │ ├── ComponentDescriptor.cs │ ├── ContentDescriptor.cs │ ├── CountryAvailabilityDescriptor.cs │ ├── CueIdentifierDescriptor.cs │ ├── DataBroadcastDescriptor.cs │ ├── DataBroadcastIdDescriptor.cs │ ├── Descriptor.cs │ ├── DescriptorDictionaries.cs │ ├── DescriptorFactory.cs │ ├── DtsDescriptor.cs │ ├── Eac3Descriptor.cs │ ├── ExtendedEventDescriptor.cs │ ├── ExtensionDescriptor.cs │ ├── HevcDescriptor.cs │ ├── Iso639LanguageDescriptor.cs │ ├── LcnDescriptor.cs │ ├── LinkageDescriptor.cs │ ├── MetadataDescriptor.cs │ ├── MetadataStdDescriptor.cs │ ├── NetworkNameDescriptor.cs │ ├── ParentalRatingDescriptor.cs │ ├── PrivateDataSpecifierDescriptor.cs │ ├── RegistrationDescriptor.cs │ ├── SatelliteDeliverySystemDescriptor.cs │ ├── ScramblingDescriptor.cs │ ├── ServiceDescriptor.cs │ ├── ServiceListDescriptor.cs │ ├── ShortEventDescriptor.cs │ ├── StreamIdentifierDescriptor.cs │ ├── SubtitlingDescriptor.cs │ ├── TeletextDescriptor.cs │ └── TerrestrialDeliverySystemDescriptor.cs ├── Tables │ ├── EventInformationItem.cs │ ├── EventInformationTable.cs │ ├── EventInformationTableFactory.cs │ ├── ITable.cs │ ├── NetworkInformationTable.cs │ ├── NetworkInformationTableFactory.cs │ ├── ProgramAssociationTable.cs │ ├── ProgramAssociationTableFactory.cs │ ├── ProgramMapTable.cs │ ├── ProgramMapTableFactory.cs │ ├── ServiceDescriptionTable.cs │ ├── ServiceDescriptionTableFactory.cs │ ├── SpliceInfoTable.cs │ ├── SpliceInfoTableFactory.cs │ ├── Table.cs │ └── TableFactory.cs ├── TransportStream │ ├── AdaptationField.cs │ ├── EsInfo.cs │ ├── OptionalPes.cs │ ├── PES.cs │ ├── PesHdr.cs │ ├── PesStreamTypes.cs │ ├── PidType.cs │ ├── TableChangedEventArgs.cs │ ├── Text.cs │ ├── TransportStreamEventArgs.cs │ ├── TsDecoder.cs │ ├── TsPacket.cs │ ├── TsPacketFactory.cs │ └── Utils.cs └── Video │ ├── H264BitReader.cs │ ├── H264BitWriter.cs │ ├── H264HrdParams.cs │ ├── H264NalUnit.cs │ ├── H264NalUnitFactory.cs │ ├── H264NalUnitType.cs │ ├── H264SeqParamSet.cs │ ├── H265NalUnit.cs │ ├── H265NalUnitType.cs │ ├── INalUnit.cs │ ├── NalUnit.cs │ ├── NalUnitFactory.cs │ ├── NalUnitReadyEventArgs.cs │ ├── RbspBitReader.cs │ ├── SeiMessage.cs │ ├── VideoTsDecoder.cs │ └── VideoTsService.cs ├── LICENSE ├── Readme.md └── appveyor.yml /.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | obj 3 | .vs 4 | *.nupkg 5 | TestResults 6 | *.user 7 | /Cinegy.TsDecoder/project.lock.json 8 | /packages 9 | /Cinegy.TsDecoder/Properties/PublishProfiles/FolderProfile.pubxml 10 | .idea/ 11 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at lewis.kirkaldie@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder.Tests/Cinegy.TsDecoder.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net6.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | PreserveNewest 22 | 23 | 24 | PreserveNewest 25 | 26 | 27 | PreserveNewest 28 | 29 | 30 | PreserveNewest 31 | 32 | 33 | PreserveNewest 34 | 35 | 36 | PreserveNewest 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder.Tests/DescriptorTests/DescriptorDeserializerTests.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2016-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | using Cinegy.TsDecoder.TransportStream; 17 | using NUnit.Framework; 18 | using System; 19 | using System.Collections.Generic; 20 | using System.Linq; 21 | using System.Text; 22 | using System.Threading.Tasks; 23 | using Cinegy.TsDecoder.Descriptors; 24 | 25 | namespace Cinegy.TsDecoder.Tests.DescriptorTests 26 | { 27 | [TestFixture] 28 | public class DescriptorDeserializerTests 29 | { 30 | [TestCase(new byte[] { 0x4A, 0x14, 0x00, 0x12, 0x06, 0x00, 0x45, 0x44, 0x05, 0x44, 0x56, 0x52, 0x31, 0x04, 0xB0, 0x01, 0x10, 0x35, 0x00, 0x00, 0x09, 0xB7 })] 31 | public void LinkageDescriptorTest(byte[] hexBytes) 32 | { 33 | var descriptor = DescriptorFactory.DescriptorFromData(hexBytes, 0) as LinkageDescriptor; 34 | 35 | Assert.IsNotNull(descriptor); 36 | Assert.AreEqual(descriptor.TransportStreamId,0x12); 37 | Assert.AreEqual(descriptor.OriginalNetworkId, 0x600); 38 | Assert.AreEqual(descriptor.ServiceId, 0x4544); 39 | Assert.AreEqual(descriptor.LinkageType, 0x5); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder.Tests/TestStreams/11720-2017-07-09-16-01-43.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cinegy/TsDecoder/d64100baab9aa225f06ff1ed4a70a5eb793786cc/Cinegy.TsDecoder.Tests/TestStreams/11720-2017-07-09-16-01-43.ts -------------------------------------------------------------------------------- /Cinegy.TsDecoder.Tests/TestStreams/11954-2017-07-09-16-05-06.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cinegy/TsDecoder/d64100baab9aa225f06ff1ed4a70a5eb793786cc/Cinegy.TsDecoder.Tests/TestStreams/11954-2017-07-09-16-05-06.ts -------------------------------------------------------------------------------- /Cinegy.TsDecoder.Tests/TestStreams/D2-TS-HD-AC3-Blue-45mbps.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cinegy/TsDecoder/d64100baab9aa225f06ff1ed4a70a5eb793786cc/Cinegy.TsDecoder.Tests/TestStreams/D2-TS-HD-AC3-Blue-45mbps.ts -------------------------------------------------------------------------------- /Cinegy.TsDecoder.Tests/TestStreams/SD-H264-1mbps-Bars.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cinegy/TsDecoder/d64100baab9aa225f06ff1ed4a70a5eb793786cc/Cinegy.TsDecoder.Tests/TestStreams/SD-H264-1mbps-Bars.ts -------------------------------------------------------------------------------- /Cinegy.TsDecoder.Tests/TestStreams/cut-2ts.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cinegy/TsDecoder/d64100baab9aa225f06ff1ed4a70a5eb793786cc/Cinegy.TsDecoder.Tests/TestStreams/cut-2ts.ts -------------------------------------------------------------------------------- /Cinegy.TsDecoder.Tests/TestStreams/cut-bbchd-dvbs2mux.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cinegy/TsDecoder/d64100baab9aa225f06ff1ed4a70a5eb793786cc/Cinegy.TsDecoder.Tests/TestStreams/cut-bbchd-dvbs2mux.ts -------------------------------------------------------------------------------- /Cinegy.TsDecoder.Tests/TransportStream/DescriptorTests.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2016-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | using System; 17 | using System.Collections.Generic; 18 | using System.Diagnostics; 19 | using System.Linq; 20 | using System.Text; 21 | using System.Threading.Tasks; 22 | using System.IO; 23 | using Cinegy.TsDecoder.Descriptors; 24 | using Cinegy.TsDecoder.Tables; 25 | using Cinegy.TsDecoder.TransportStream; 26 | using NUnit.Framework; 27 | 28 | namespace Cinegy.TsDecoder.Tests.TransportStream 29 | { 30 | [TestFixture] 31 | public class DescriptorTests 32 | { 33 | 34 | [TestCase(@"TestStreams/11954-2017-07-09-16-05-06.ts")] 35 | [TestCase(@"TestStreams/11720-2017-07-09-16-01-43.ts")] 36 | //[TestCase(@"C:\Users\lewis\OneDrive\Temp\BBCHD-DVBS2Mux-19thSept2016-20160919-105050.ts")] 37 | public void ReadDescriptorsFromTestStreams(string file) 38 | { 39 | var testFile = Path.Combine(TestContext.CurrentContext.TestDirectory, file); 40 | ProcessFileForDescriptors(testFile); 41 | } 42 | 43 | private static void ProcessFileForDescriptors(string sourceFileName) 44 | { 45 | const int readFragmentSize = 1316; 46 | 47 | var stream = File.Open(sourceFileName, FileMode.Open); 48 | 49 | if (stream == null) Assert.Fail("Unable to read test file: " + sourceFileName); 50 | 51 | var data = new byte[readFragmentSize]; 52 | 53 | var readCount = stream.Read(data, 0, readFragmentSize); 54 | 55 | var decoder = new TsDecoder.TransportStream.TsDecoder(); 56 | decoder.TableChangeDetected += Decoder_TableChangeDetected; 57 | 58 | while (readCount > 0) 59 | { 60 | try 61 | { 62 | if (readCount < readFragmentSize) 63 | { 64 | var tmpArr = new byte[readCount]; 65 | Buffer.BlockCopy(data, 0, tmpArr, 0, readCount); 66 | data = new byte[readCount]; 67 | Buffer.BlockCopy(tmpArr, 0, data, 0, readCount); 68 | } 69 | 70 | decoder.AddData(data); 71 | 72 | if (decoder.ServiceDescriptionTable != null && decoder.ServiceDescriptionTable.ItemsIncomplete != true) 73 | { 74 | foreach (var program in decoder.ProgramMapTables) 75 | { 76 | Console.WriteLine(decoder.GetServiceDescriptorForProgramNumber(program.ProgramNumber).ServiceName); 77 | foreach (var esStream in program.EsStreams) 78 | { 79 | Console.WriteLine($"\t0x{esStream.ElementaryPid:X4} - {DescriptorDictionaries.ShortElementaryStreamTypeDescriptions[esStream.StreamType]}"); 80 | 81 | //only check type 6 privately defined streams 82 | if (esStream.StreamType != 6) continue; 83 | 84 | foreach (var desc in esStream.Descriptors) 85 | { 86 | if (desc is ExtendedEventDescriptor extDesc) 87 | { 88 | Console.WriteLine($"{extDesc.TextChar.Value}"); 89 | } 90 | else 91 | { 92 | Console.WriteLine($"\t {desc}"); 93 | } 94 | } 95 | } 96 | } 97 | return; 98 | } 99 | 100 | 101 | if (stream.Position < stream.Length) 102 | { 103 | readCount = stream.Read(data, 0, readFragmentSize); 104 | } 105 | else 106 | { 107 | Assert.Fail("Reached end of file without completing descriptor scan"); 108 | } 109 | } 110 | catch (Exception ex) 111 | { 112 | Assert.Fail($"Problem reading file: {ex.Message}"); 113 | } 114 | } 115 | } 116 | 117 | private static void Decoder_TableChangeDetected(object sender, TableChangedEventArgs args) 118 | { 119 | var fact = sender as TableFactory; 120 | 121 | if (fact is ServiceDescriptionTableFactory sdtFact) 122 | { 123 | Console.WriteLine($"{args.Message} - {sdtFact.ServiceDescriptionItems.Count}"); 124 | } 125 | } 126 | } 127 | 128 | } 129 | 130 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.1.32421.90 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cinegy.TsDecoder", "Cinegy.TsDecoder\Cinegy.TsDecoder.csproj", "{6D63F8EF-963F-4998-93AD-BF6DBCCF3D97}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cinegy.TsDecoder.Tests", "Cinegy.TsDecoder.Tests\Cinegy.TsDecoder.Tests.csproj", "{C180CE0E-FCBD-4E58-B9A3-C798D00B7D18}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionItems", "{782C9245-661F-4DA2-98D5-DA836FD6A08F}" 11 | ProjectSection(SolutionItems) = preProject 12 | appveyor.yml = appveyor.yml 13 | Readme.md = Readme.md 14 | EndProjectSection 15 | EndProject 16 | Global 17 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 18 | Debug|Any CPU = Debug|Any CPU 19 | Release|Any CPU = Release|Any CPU 20 | EndGlobalSection 21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 22 | {6D63F8EF-963F-4998-93AD-BF6DBCCF3D97}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {6D63F8EF-963F-4998-93AD-BF6DBCCF3D97}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {6D63F8EF-963F-4998-93AD-BF6DBCCF3D97}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {6D63F8EF-963F-4998-93AD-BF6DBCCF3D97}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {C180CE0E-FCBD-4E58-B9A3-C798D00B7D18}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {C180CE0E-FCBD-4E58-B9A3-C798D00B7D18}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {C180CE0E-FCBD-4E58-B9A3-C798D00B7D18}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {C180CE0E-FCBD-4E58-B9A3-C798D00B7D18}.Release|Any CPU.Build.0 = Release|Any CPU 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | GlobalSection(ExtensibilityGlobals) = postSolution 35 | SolutionGuid = {7645DE27-F6F1-469E-B175-3E9E7AE03FC7} 36 | EndGlobalSection 37 | EndGlobal 38 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Cinegy.TsDecoder.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net6.0 5 | 4.0.0-alpha 6 | Lewis Kirkaldie 7 | Cinegy GmbH 8 | An MPEG2 Transport Stream decoder, in C# using NET 6.0 9 | Cinegy GmbH 10 | Transport Stream MPEGTS 11 | https://github.com/Cinegy/TsDecoder 12 | 13 | true 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/DataAccess/BitReader.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | using System; 17 | 18 | namespace Cinegy.TsDecoder.DataAccess 19 | { 20 | public class BitReader 21 | { 22 | private readonly byte[] _buffer; 23 | private int _pos; 24 | 25 | public BitReader(byte[] buf) 26 | { 27 | _buffer = buf; 28 | } 29 | 30 | private int get_03_code_bits(int n) 31 | { 32 | var currentOffs = _pos >> 3; 33 | var nextOffs = _pos + n >> 3; 34 | 35 | if (nextOffs >= _buffer.Length) 36 | { 37 | throw new IndexOutOfRangeException("Reading the bits beyond the buffer"); 38 | } 39 | 40 | if (currentOffs < 2) 41 | return 0; 42 | 43 | var cnt = 0; 44 | 45 | for (var i = currentOffs; i <= nextOffs; i++) 46 | if (_buffer[i] == 0x03 && _buffer[i - 1] == 0 && _buffer[i - 2] == 0) 47 | cnt++; 48 | 49 | return cnt * 8; 50 | } 51 | 52 | public uint Show_Bits(int n) 53 | { 54 | switch (n) 55 | { 56 | case < 0: 57 | throw new Exception("ShowBits(): The value on N is negative"); 58 | case 0: 59 | return 0; 60 | case > 32: 61 | throw new Exception("ShowBits(): The value on N is too big"); 62 | } 63 | 64 | if (_pos + n > _buffer.Length * 8) 65 | { 66 | if (_pos >= _buffer.Length * 8) 67 | throw new Exception("ShowBits(): Reading the bits beyond the buffer"); 68 | 69 | var safeBits = _buffer.Length * 8 - _pos; 70 | 71 | if (safeBits <= 0) 72 | { 73 | throw new IndexOutOfRangeException("Reading the bits beyond the buffer"); 74 | } 75 | 76 | return Show_Bits(safeBits) << n - safeBits; 77 | } 78 | 79 | var offs = _pos >> 3; 80 | var pPos = _pos & 7; 81 | 82 | long val = 0; 83 | var bitsRead = 0; 84 | 85 | for (; ; ) 86 | { 87 | var x = _buffer[offs++]; 88 | 89 | if (x == 0x03 && offs >= 3 && _buffer[offs - 2] == 0 && _buffer[offs - 3] == 0) 90 | continue; 91 | 92 | val = val << 8 | x; 93 | 94 | if ((bitsRead += 8) >= n + pPos) 95 | break; 96 | } 97 | 98 | val >>= bitsRead - (n + pPos); 99 | 100 | return (uint)(val & ~0U >> 32 - n); 101 | } 102 | 103 | public void Flush_Bits(int n) 104 | { 105 | _pos += n + get_03_code_bits(n); 106 | } 107 | 108 | public uint Get_Bits(int n) 109 | { 110 | var val = Show_Bits(n); 111 | Flush_Bits(n); 112 | return val; 113 | } 114 | 115 | public uint Show_Bits32_Aligned() 116 | { 117 | var offs = _pos + 7 >> 3; 118 | 119 | if (offs + 4 > _buffer.Length) 120 | throw new Exception("ShowBits32(): Reading the bits beyond the buffer"); 121 | 122 | return (uint)(_buffer[offs + 0] << 24 | 123 | _buffer[offs + 1] << 16 | 124 | _buffer[offs + 2] << 8 | 125 | _buffer[offs + 3] << 0); 126 | } 127 | 128 | public bool Get_Bool() 129 | { 130 | return Get_Bits(1) != 0; 131 | } 132 | 133 | public void Unget_Bits(int n) 134 | { 135 | if (_pos < n) 136 | throw new Exception("Too many bits to rewind"); 137 | 138 | _pos -= n; 139 | } 140 | 141 | private int BitsToAlign() 142 | { 143 | return _pos - 1 & 7 ^ 7; 144 | } 145 | 146 | public bool IsAligned() 147 | { 148 | return (_pos & 7) == 0; 149 | } 150 | 151 | public void Align() 152 | { 153 | //if(_pos&7) _pos = (_pos+7)&~7; 154 | _pos += BitsToAlign(); 155 | } 156 | 157 | public int BitPos 158 | { 159 | get => _pos; 160 | set 161 | { 162 | if (value > _buffer.Length * 8) 163 | throw new Exception("BitPos is outside the bounds"); 164 | 165 | _pos = value; 166 | } 167 | } 168 | 169 | public int BitsLeft => _buffer.Length * 8 - _pos; 170 | } 171 | 172 | } 173 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/DataAccess/BitWriter.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016-2023 Cinegy GmbH 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | */ 17 | 18 | using System; 19 | 20 | namespace Cinegy.TsDecoder.DataAccess 21 | { 22 | public class BitWriter 23 | { 24 | internal byte[] Buffer; 25 | private int _bitPos; 26 | 27 | public BitWriter(byte[] buf) 28 | { 29 | Buffer = buf; 30 | } 31 | 32 | public void Put_Bits(uint val, int n) 33 | { 34 | if (n == 0) 35 | return; 36 | 37 | var bitsLeft = 8 - _bitPos; 38 | 39 | if (n < bitsLeft) 40 | { 41 | val <<= bitsLeft - n; 42 | Buffer[BytePos] |= (byte)val; 43 | _bitPos += n; 44 | return; 45 | } 46 | 47 | var bigVal = (long)Buffer[BytePos] << n - bitsLeft | val; 48 | 49 | var nn = n + _bitPos; 50 | 51 | while (nn >= 8) 52 | { 53 | Write_Byte((byte)(bigVal >> nn - 8)); 54 | nn -= 8; 55 | } 56 | 57 | _bitPos += n; 58 | _bitPos &= 7; 59 | 60 | if (nn != 0) 61 | { 62 | Buffer[BytePos] = (byte)(bigVal << 8 - _bitPos); 63 | } 64 | } 65 | 66 | protected virtual void Write_Byte(byte val) 67 | { 68 | Buffer[BytePos++] = val; 69 | } 70 | 71 | public void Put_Bits32_Aligned(uint val) 72 | { 73 | Align(); 74 | Write_Byte((byte)(val >> 24)); 75 | Write_Byte((byte)(val >> 16)); 76 | Write_Byte((byte)(val >> 8)); 77 | Write_Byte((byte)(val >> 0)); 78 | } 79 | 80 | public bool Put_Bool(bool val) 81 | { 82 | Put_Bits(val ? 1u : 0u, 1); 83 | return val; 84 | } 85 | 86 | private int BitsToAlign() 87 | { 88 | return _bitPos - 1 & 7 ^ 7; 89 | } 90 | 91 | public bool IsAligned() 92 | { 93 | return (_bitPos & 7) == 0; 94 | } 95 | 96 | public void Align() 97 | { 98 | //if(m_pos&7) m_pos = (m_pos+7)&~7; 99 | //m_pos += BitsToAlign(); 100 | Put_Bits(0, BitsToAlign()); 101 | } 102 | 103 | public int BytePos { get; set; } 104 | 105 | public int BitPos 106 | { 107 | get => (BytePos << 3) + _bitPos; 108 | set 109 | { 110 | if (value > Buffer.Length * 8) 111 | throw new IndexOutOfRangeException("BitPos is outside the bounds"); 112 | 113 | BytePos = value >> 3; 114 | _bitPos = value & 7; 115 | } 116 | } 117 | 118 | public int BytesInBuffer => BitPos + 7 >> 3; 119 | } 120 | 121 | } 122 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Descriptors/AacDescriptor.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | using System; 17 | 18 | namespace Cinegy.TsDecoder.Descriptors 19 | { 20 | /// 21 | /// A AAC Descriptor . 22 | /// 23 | /// 24 | /// For details please refer to the original documentation, 25 | /// e.g. ETSI EN 300 468 V1.15.1 (2016-03) Table H.1 or alternate versions. 26 | /// 27 | public class AacDescriptor : Descriptor 28 | { 29 | /*DTSAudioStreamDescriptor(){ 30 | * descriptor_tag 8 uimsbf 31 | * descriptor_lengh 8 uimsbf 32 | * profile_and_level 8 uimsbf 33 | * aac_type_flag 1 bslbf 34 | * saoc_de_flag 1 bslbf 35 | * reserve_for future_use 6 bslbf 36 | * if(aac_type_flag==1){ 37 | * aac_type 8 uimsbf 38 | * } 39 | * for(i=0;i> 7 & 0x01; 52 | 53 | var i = 4; 54 | if (AacTypeFlag == 0x01) 55 | { 56 | headerLength++; 57 | AacType = stream[i++]; 58 | } 59 | 60 | AdditionalInfoBytes = new byte[DescriptorLength - headerLength]; 61 | Buffer.BlockCopy(stream, stream[i], AdditionalInfoBytes, 0, DescriptorLength - headerLength); 62 | 63 | } 64 | catch (IndexOutOfRangeException) 65 | { 66 | throw new ArgumentOutOfRangeException("The AAC Descriptor Message is short!"); 67 | } 68 | } 69 | public byte ProfileAndLevel { get; } 70 | public int AacTypeFlag { get; } 71 | public bool SaocDeTypeFlag { get; } 72 | public byte AacType { get; } 73 | public byte[] AdditionalInfoBytes { get; } 74 | 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Descriptors/Ac3Descriptor.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | namespace Cinegy.TsDecoder.Descriptors 17 | { 18 | /// 19 | /// A AC3 Descriptor . 20 | /// 21 | /// 22 | /// For details please refer to the original documentation, 23 | /// e.g. ETSI EN 300 468 V1.15.1 (2016-03) or alternate versions. 24 | /// 25 | public class Ac3Descriptor : Descriptor 26 | { 27 | /* 28 | * AC-3_descriptor() 29 | * { 30 | * descriptor_tag 8 uimsbf 31 | * descriptor_length 8 uimsbf 32 | * component_type_flag 1 bslbf 33 | * bsid_flag 1 bslbf 34 | * mainid_flag 1 bslbf 35 | * asvc_flag 1 bslbf 36 | * reserved_flags 4 bslbf 37 | * if (component_type_flag == 1) 38 | * * { 8 uimsbf component_type } 39 | * if (bsid_flag == 1) 40 | * { 8 uimsbf bsid } 41 | * if (mainid_flag == 1) 42 | * { 8 uimsbf mainid } 43 | * if (asvc_flag == 1) 44 | * { 8 uimsbf asvc } 45 | * for(i=0;i 21 | /// A Bouquetname Descriptor . 22 | /// 23 | /// 24 | /// For details please refer to the original documentation, 25 | /// e.g. ETSI EN 300 468 V1.15.1 (2016-03) or alternate versions. 26 | /// 27 | public class BouquetNameDescriptor : Descriptor 28 | { 29 | public BouquetNameDescriptor(byte[] stream, int start) : base(stream, start) 30 | { 31 | var lastIndex = start + 2; 32 | if (DescriptorLength != 0) 33 | { 34 | BouquetName = Encoding.UTF8.GetString(stream, lastIndex, DescriptorLength); 35 | } 36 | } 37 | 38 | public string BouquetName { get; private set; } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Descriptors/CaDescriptor.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | namespace Cinegy.TsDecoder.Descriptors 17 | { 18 | /// 19 | /// A CA Descriptor . 20 | /// 21 | /// 22 | /// For details please refer to the original documentation, 23 | /// e.g. ETSI EN 300 468 V1.15.1 (2016-03) or alternate versions. 24 | /// 25 | public class CaDescriptor : Descriptor 26 | { 27 | public CaDescriptor(byte[] stream, int start) : base(stream, start) 28 | { 29 | SystemIdentifier = stream[start + 2] << 8 + stream[start + 3]; 30 | CaPid = (stream[start + 4] & 0x1f) << 8 + stream[start + 4]; 31 | } 32 | 33 | public int CaPid { get; } 34 | public int SystemIdentifier { get; } 35 | 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Descriptors/CaIdentifierDescriptor.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | using System; 17 | using System.Collections.Generic; 18 | 19 | namespace Cinegy.TsDecoder.Descriptors 20 | { 21 | /// 22 | /// A Ca Identifier Descriptor . 23 | /// 24 | /// 25 | /// For details please refer to the original documentation, 26 | /// e.g. ETSI EN 300 468 V1.15.1 (2016-03) or alternate versions. 27 | /// 28 | public class CaIdentifierDescriptor : Descriptor 29 | { 30 | public CaIdentifierDescriptor(byte[] stream, int start) : base(stream, start) 31 | { 32 | var lastindex = start + 2; 33 | try 34 | { 35 | var al = new List(); 36 | for (int offset2 = lastindex; offset2 < lastindex + DescriptorLength - 1; offset2 += 2) 37 | al.Add((ushort)(stream[offset2] << 8 | stream[offset2 + 1])); 38 | CaSystemIds = al.ToArray(); 39 | 40 | } 41 | catch (IndexOutOfRangeException) 42 | { 43 | throw new ArgumentOutOfRangeException("The CA Identifier Descriptor Message is short!"); 44 | } 45 | } 46 | public ushort[] CaSystemIds { get; set; } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Descriptors/CinegyDaniel2Descriptor.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | using System.Text; 17 | using Cinegy.TsDecoder.TransportStream; 18 | 19 | namespace Cinegy.TsDecoder.Descriptors 20 | { 21 | public class CinegyDaniel2Descriptor : RegistrationDescriptor //if format-identifier / organization tag == 2LND 22 | { 23 | public CinegyDaniel2Descriptor(byte[] stream, int start) : base(stream, start) 24 | { 25 | //TODO:Set correct length check 26 | if (!(AdditionalIdentificationInfo?.Length < 30)) return; 27 | 28 | FourCc = Encoding.ASCII.GetString(stream, start + 2, 4); 29 | Version = stream[start + 6]; 30 | HdrSize = stream[start + 7]; 31 | Flags = Utils.Convert2BytesToUshort(stream, start + 8); 32 | Width = Utils.Convert4BytesToUint(stream, start + 10); 33 | Height = Utils.Convert4BytesToUint(stream, start + 14); 34 | FrameRate = Utils.Convert4BytesToUint(stream, start + 18); 35 | AspectRatio = Utils.Convert4BytesToUint(stream, start + 22); 36 | MainQuantizer = Utils.Convert4BytesToUint(stream, start + 26); //this is very wrong, i cannot just jam a float in here like this :-) 37 | 38 | //todo: fill in the rest of all this 39 | ChromaQuantizerAdd = 0;// 1 percents. ChromaQuantizer = MainQuantizer * (100 + ChromaQuantizerAdd) / 100 40 | AlphaQuantizerAdd = 0;// 1 percents. AlphaQuantizer = MainQuantizer * (100 + AlphaQuantizerAdd ) / 100 41 | Orientation = 0; // 1 see ORIENTATION 42 | InterlaceType = 0; // 1 see INTERLACE_TYPE 43 | ChromaFormat = 0; // 1 see CHROMA_FORMAT 44 | BitDepth = 0; // 1 Main Bitdepth 45 | VideoFormat = 0; // 1 46 | ColorPrimaries = 0; // 1 47 | TransferCharacteristics = 0;// 1 48 | MatrixCoefficients = 0; // 1 49 | MaxFrameSize = 0; // 4 if 0 - unspecified (VBR), if != 0 - specifies max public byte rate and CBR 50 | EncodeMethod = 0; // 1 51 | FrameType = 0; // 1 0 - total Intra, 1 - can have Delta-blocks, 2 - total Delta 52 | TempRef = 0; // 1 53 | TimeCode = 0; // 4 54 | FrameSize = 0; // 4 12 Coded frame size (in bytes), including header 55 | NumExtraRecords = 0;// 1 56 | ExtraRecordsSize = 0;// 2 57 | } 58 | 59 | public override string LongName => "Cinegy Daniel2 Coded Video"; 60 | 61 | public override string Name => "Daniel2 Video"; 62 | 63 | public string FourCc { get; } // 4 'D''N''L''2' 64 | 65 | public byte Version { get; } // 1 Coded codec version 66 | public byte HdrSize { get; } // 1 size of header, not including extra records 67 | public ushort Flags { get; } // 2 see D2_FLAGS 68 | 69 | public uint Width { get; } // 4 Frame width 70 | public uint Height { get; } // 4 Frame height 71 | 72 | public uint FrameRate { get; } // 4 bits 0..19 are numerator, bits 20..31 are denominator (assuming 0 == 1 for denom). 73 | public uint AspectRatio { get; } // 4 bits 0..15 are numerator, bits 16..31 are denominator 74 | 75 | public float MainQuantizer { get; } // 4 Main Quantizer 76 | public byte ChromaQuantizerAdd { get; } // 1 percents. ChromaQuantizer = MainQuantizer * (100 + ChromaQuantizerAdd) / 100 77 | public byte AlphaQuantizerAdd { get; } // 1 percents. AlphaQuantizer = MainQuantizer * (100 + AlphaQuantizerAdd ) / 100 78 | 79 | public byte Orientation { get; } // 1 see ORIENTATION 80 | public byte InterlaceType { get; } // 1 see INTERLACE_TYPE 81 | 82 | public byte ChromaFormat { get; } // 1 see CHROMA_FORMAT 83 | public byte BitDepth { get; } // 1 Main Bitdepth 84 | 85 | public byte VideoFormat { get; } 86 | public byte ColorPrimaries { get; } 87 | public byte TransferCharacteristics { get; } 88 | public byte MatrixCoefficients { get; } 89 | 90 | public uint MaxFrameSize { get; } // 4 if 0 - unspecified (VBR), if != 0 - specifies max public byte rate and CBR 91 | 92 | // frame parameters 93 | public byte EncodeMethod { get; } // 1 94 | public byte FrameType { get; } // 1 0 - total Intra, 1 - can have Delta-blocks, 2 - total Delta 95 | public byte TempRef { get; } // 1 96 | 97 | public uint TimeCode { get; } // 4 98 | public uint FrameSize { get; } // 4 12 Coded frame size (in bytes), including header 99 | 100 | public byte NumExtraRecords { get; } // 1 101 | public ushort ExtraRecordsSize { get; } // 2 102 | 103 | //TODO: work out what to do with this - probably just delete... 104 | // public byte __dummy[8]{ get; }; // 105 | 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Descriptors/CinegyTechMetadataDescriptor.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | namespace Cinegy.TsDecoder.Descriptors 17 | { 18 | 19 | public class CinegyTechMetadataDescriptor : RegistrationDescriptor //if format-identifier / organization tag == CNGY 20 | { 21 | public CinegyTechMetadataDescriptor(byte[] stream, int start) : base(stream, start) 22 | { 23 | if (!(AdditionalIdentificationInfo?.Length >= 2)) return; 24 | 25 | //todo: set to extracted values 26 | CinecoderVersion = "3.28.22"; 27 | MLVersion = "6.7.1"; 28 | AppVersion = "12.0.3.2112"; 29 | AppName = "PlayoutExApp"; 30 | } 31 | 32 | public string CinecoderVersion { get; } 33 | public string MLVersion { get; } 34 | public string AppVersion { get; } 35 | public string AppName { get; } 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Descriptors/CountryAvailabilityDescriptor.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | using System; 17 | using System.Collections.ObjectModel; 18 | using System.Text; 19 | 20 | namespace Cinegy.TsDecoder.Descriptors 21 | { 22 | /// 23 | /// A Country Availability Descriptor . 24 | /// 25 | /// 26 | /// For details please refer to the original documentation, 27 | /// e.g. ETSI EN 300 468 V1.15.1 (2016-03) or alternate versions. 28 | /// 29 | public class CountryAvailabilityDescriptor : Descriptor 30 | { 31 | public CountryAvailabilityDescriptor(byte[] stream, int start) : base(stream, start) 32 | { 33 | var lastIndex = start + 2; 34 | 35 | try 36 | { 37 | if (DescriptorLength != 0) 38 | { 39 | AvailabilityFlag = (stream[lastIndex] & 0x80) != 0; 40 | lastIndex++; 41 | 42 | int countryCount = (DescriptorLength - 1) / 3; 43 | 44 | if (countryCount != 0) 45 | { 46 | CountryCodes = new Collection(); 47 | 48 | while (CountryCodes.Count != countryCount) 49 | { 50 | var countryCode = Encoding.UTF8.GetString(stream, lastIndex, 3); 51 | CountryCodes.Add(countryCode); 52 | lastIndex += 3; 53 | } 54 | } 55 | } 56 | } 57 | catch (IndexOutOfRangeException) 58 | { 59 | throw new ArgumentOutOfRangeException("The Country Availability Descriptor message is short"); 60 | } 61 | } 62 | 63 | public bool AvailabilityFlag { get; private set; } 64 | 65 | public Collection CountryCodes { get; private set; } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Descriptors/CueIdentifierDescriptor.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | namespace Cinegy.TsDecoder.Descriptors 17 | { 18 | /// 19 | /// A Cue Identifier Descriptor . 20 | /// 21 | /// 22 | /// For details please refer to the original documentation, 23 | /// e.g. ETSI EN 300 468 V1.15.1 (2016-03) or alternate versions. 24 | /// 25 | public class CueIdentifierDescriptor : Descriptor 26 | { 27 | public string CueStreamTypeDescription(byte cueType) 28 | { 29 | switch (cueType) 30 | { 31 | case 0x00: 32 | return "splice_insert, splice_null, splice_schedule"; 33 | case 0x01: 34 | return "All Commands"; 35 | case 0x02: 36 | return "Segmentation"; 37 | case 0x03: 38 | return "Tiered Splicing"; 39 | case 0x04: 40 | return "Tiered Segmentation"; 41 | default: 42 | if (cueType >= 0x05 && cueType <= 0x7f) return "Reserved"; 43 | break; 44 | } 45 | return "User Defined"; 46 | } 47 | 48 | 49 | public CueIdentifierDescriptor(byte[] stream, int start) 50 | : base(stream, start) 51 | { 52 | CueStreamType = stream[start + 2]; 53 | } 54 | 55 | public byte CueStreamType { get; } 56 | public string CueStreamTypeString => CueStreamTypeDescription(CueStreamType); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Descriptors/DataBroadcastDescriptor.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | using System; 17 | using System.Text; 18 | 19 | namespace Cinegy.TsDecoder.Descriptors 20 | { 21 | /// 22 | /// A Data Broadcast Descriptor . 23 | /// 24 | /// 25 | /// For details please refer to the original documentation, 26 | /// e.g. ETSI EN 300 468 V1.15.1 (2016-03) or alternate versions. 27 | /// 28 | public class DataBroadcastDescriptor : Descriptor 29 | { 30 | public DataBroadcastDescriptor(byte[] stream, int start) : base(stream, start) 31 | { 32 | var lastIndex = start + 2; 33 | 34 | try 35 | { 36 | if (DescriptorLength != 0) 37 | { 38 | DataBroadcastId = (stream[lastIndex] << 8) + stream[lastIndex + 1]; 39 | lastIndex += 2; 40 | 41 | ComponentTag = stream[lastIndex]; 42 | lastIndex++; 43 | 44 | int selectorLength = stream[lastIndex]; 45 | lastIndex++; 46 | 47 | if (selectorLength != 0) 48 | { 49 | Buffer.BlockCopy(stream, lastIndex, SelectorBytes, 0, selectorLength); 50 | lastIndex += selectorLength; 51 | } 52 | 53 | LanguageCode = Encoding.UTF8.GetString(stream, lastIndex, 3); 54 | lastIndex += 3; 55 | } 56 | 57 | int textLength = stream[lastIndex]; 58 | lastIndex++; 59 | 60 | if (textLength != 0) 61 | { 62 | TextDescription = Encoding.UTF8.GetString(stream, lastIndex, textLength); 63 | lastIndex += textLength; 64 | } 65 | } 66 | catch (IndexOutOfRangeException) 67 | { 68 | throw new ArgumentOutOfRangeException("The Data Broadcast Descriptor message is short"); 69 | } 70 | } 71 | 72 | public int DataBroadcastId { get; private set; } 73 | public int ComponentTag { get; private set; } 74 | public string LanguageCode { get; private set; } 75 | public string TextDescription { get; private set; } 76 | public byte[] SelectorBytes { get; private set; } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Descriptors/DataBroadcastIdDescriptor.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | namespace Cinegy.TsDecoder.Descriptors 17 | { 18 | /// 19 | /// A Data Broadcast Identity Descriptor . 20 | /// 21 | /// 22 | /// For details please refer to the original documentation, 23 | /// e.g. ETSI EN 300 468 V1.15.1 (2016-03) or alternate versions. 24 | /// 25 | public class DataBroadcastIdDescriptor : Descriptor 26 | { 27 | public DataBroadcastIdDescriptor(byte[] stream, int start) : base(stream, start) 28 | { 29 | DataBroadcastId = (ushort)((stream[start + 2] << 8) + stream[start + 3]); 30 | } 31 | 32 | public ushort DataBroadcastId { get; } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Descriptors/Descriptor.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | using System; 17 | 18 | namespace Cinegy.TsDecoder.Descriptors 19 | { 20 | public class Descriptor 21 | { 22 | public Descriptor() { } 23 | 24 | public Descriptor(byte[] stream, int start) 25 | { 26 | if (start + 1 > stream.Length) 27 | { 28 | //corrupt packet 29 | return; 30 | } 31 | 32 | DescriptorTag = stream[start]; 33 | DescriptorLength = stream[start + 1]; 34 | 35 | if (stream.Length - start - 2 >= DescriptorLength) 36 | { 37 | Data = new byte[DescriptorLength]; 38 | Buffer.BlockCopy(stream, start + 2, Data, 0, DescriptorLength); 39 | } 40 | else 41 | { 42 | //corrupt packet 43 | //Debug.WriteLine($"Descriptor has length beyond packet {Name} - {DescriptorTag}."); 44 | } 45 | } 46 | 47 | public byte DescriptorTag { get; internal set; } 48 | 49 | public byte DescriptorLength { get; internal set; } 50 | 51 | public byte[] Data { get; } 52 | 53 | public virtual string LongName => DescriptorDictionaries.DescriptorTypeDescriptions[DescriptorTag]; 54 | 55 | public virtual string Name => DescriptorDictionaries.DescriptorTypeShortDescriptions[DescriptorTag]; 56 | 57 | public override string ToString() 58 | { 59 | return $"(0x{DescriptorTag:x2}): {Name}, Length: {DescriptorLength}"; 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Descriptors/DescriptorFactory.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | namespace Cinegy.TsDecoder.Descriptors 17 | { 18 | public static class DescriptorFactory 19 | { 20 | public static Descriptor DescriptorFromData(byte[] stream, int start) 21 | { 22 | switch (stream[start]) 23 | { 24 | case 0x05: 25 | var regDesc = new RegistrationDescriptor(stream, start); 26 | switch (regDesc.Organization) 27 | { 28 | case "2LND": 29 | return new CinegyDaniel2Descriptor(stream, start); 30 | case "CNGY": 31 | return new CinegyTechMetadataDescriptor(stream, start); 32 | default: 33 | return regDesc; 34 | } 35 | case 0x09: return new CaDescriptor(stream, start); 36 | case 0x0a: return new Iso639LanguageDescriptor(stream, start); 37 | case 0x26: return new MetadataDescriptor(stream, start); 38 | case 0x27: return new MetadataStdDescriptor(stream, start); 39 | case 0x28: return new AvcVideoDescriptor(stream, start); 40 | case 0x38: return new HevcDescriptor(stream, start); 41 | case 0x3F: return new ExtensionDescriptor(stream, start); 42 | case 0x40: return new NetworkNameDescriptor(stream, start); 43 | case 0x41: return new ServiceListDescriptor(stream, start); 44 | case 0x43: return new SatelliteDeliverySystemDescriptor(stream, start); 45 | case 0x47: return new BouquetNameDescriptor(stream, start); 46 | case 0x48: return new ServiceDescriptor(stream, start); 47 | case 0x49: return new CountryAvailabilityDescriptor(stream, start); 48 | case 0x4A: return new LinkageDescriptor(stream, start); 49 | case 0x4D: return new ShortEventDescriptor(stream, start); 50 | case 0x4E: return new ExtendedEventDescriptor(stream, start); 51 | case 0x50: return new ComponentDescriptor(stream, start); 52 | case 0x52: return new StreamIdentifierDescriptor(stream, start); 53 | case 0x53: return new CaIdentifierDescriptor(stream, start); 54 | case 0x54: return new ContentDescriptor(stream, start); 55 | case 0x55: return new ParentalRatingDescriptor(stream, start); 56 | case 0x56: return new TeletextDescriptor(stream, start); 57 | case 0x59: return new SubtitlingDescriptor(stream, start); 58 | case 0x5a: return new TerrestrialDeliverySystemDescriptor(stream, start); 59 | case 0x5F: return new PrivateDataSpecifierDescriptor(stream, start); 60 | case 0x64: return new DataBroadcastDescriptor(stream, start); 61 | case 0x65: return new ScramblingDescriptor(stream, start); 62 | case 0x66: return new DataBroadcastIdDescriptor(stream, start); 63 | case 0x6a: return new Ac3Descriptor(stream, start); 64 | case 0x7a: return new Eac3Descriptor(stream, start); 65 | case 0x7b: return new DtsDescriptor(stream, start); 66 | case 0x7c: return new AacDescriptor(stream, start); 67 | case 0x83: return new LcnDescriptor(stream, start); 68 | case 0x8A: return new CueIdentifierDescriptor(stream, start); 69 | default: return new Descriptor(stream, start); 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Descriptors/DtsDescriptor.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | using System; 17 | 18 | namespace Cinegy.TsDecoder.Descriptors 19 | { 20 | /// 21 | /// A DTS Descriptor . 22 | /// 23 | /// 24 | /// For details please refer to the original documentation, 25 | /// e.g. ETSI EN 300 468 V1.15.1 (2016-03) table G.1: DTS Audio Descriptor or alternate versions. 26 | /// 27 | public class DtsDescriptor : Descriptor 28 | { 29 | /*DTSAudioStreamDescriptor(){ 30 | * descriptor_tag 8 uimsbf 31 | * descriptor_lengh 8 uimsbf 32 | * sample_rate_code 4 bslbf 33 | * bit_rate_code 6 bslbf 34 | * nblks 7 bslbf 35 | * fsize 14 uimsbf 36 | * surround_mode 6 bslbf 37 | * lfeflag 1 uimsbf 38 | * extended_surround_flag 2 uimsbf 39 | * for(i=0;i> 4 & 0x0f; 50 | Bitrate = (stream[2] & 0x0f) << 2 | stream[3] >> 6 & 0x02; 51 | NumberOfBlocks = (stream[3] & 0x3f) << 2 | stream[4] >> 7 & 0x01; 52 | FrameSize = (stream[4] & 0x7f) << 7 | stream[5] >> 1; 53 | SuroundMode = (stream[5] & 0x01) << 6 | stream[6] >> 3 & 0x1f; 54 | LfeFlag = stream[6] >> 2 & 0x01; 55 | ExtendedSurroundFlag = stream[6] & 0x03; 56 | AdditionalInfoBytes = new byte[DescriptorLength - 5]; 57 | Buffer.BlockCopy(stream, stream[7], AdditionalInfoBytes, 0, DescriptorLength - 5); 58 | } 59 | catch (IndexOutOfRangeException) 60 | { 61 | throw new ArgumentOutOfRangeException("The DTS Descriptor Message is short!"); 62 | } 63 | } 64 | 65 | public int SamplerateCode { get; } 66 | public int Bitrate { get; } 67 | public int NumberOfBlocks { get; } 68 | public int FrameSize { get; } 69 | public int SuroundMode { get; } 70 | public int LfeFlag { get; } 71 | public int ExtendedSurroundFlag { get; } 72 | public byte[] AdditionalInfoBytes { get; } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Descriptors/Eac3Descriptor.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | namespace Cinegy.TsDecoder.Descriptors 17 | { 18 | /// 19 | /// A Enhanced AC3 Descriptor . 20 | /// 21 | /// 22 | /// For details please refer to the original documentation, 23 | /// e.g. ETSI EN 300 468 V1.15.1 (2016-03) or alternate versions. 24 | /// 25 | public class Eac3Descriptor : Descriptor 26 | { 27 | /* 28 | * EAC-3_descriptor() 29 | * { 30 | * descriptor_tag 8 uimsbf 31 | * descriptor_length 8 uimsbf 32 | * component_type_flag 1 bslbf 33 | * bsid_flag 1 bslbf 34 | * mainid_flag 1 bslbf 35 | * asvc_flag 1 bslbf 36 | * mixinfoexists 1 bslbf 37 | * substream1_flag 1 bslbf 38 | * substream2_flag 1 bslbf 39 | * substream3_flag 1 bslbf 40 | * if (component_type_flag == 1) 41 | * { 8 uimsbf component_type } 42 | * if (bsid_flag == 1) 43 | * { 8 uimsbf bsid } 44 | * if (mainid_flag == 1) 45 | * { 8 uimsbf mainid } 46 | * if (asvc_flag == 1) 47 | * { 8 uimsbf asvc } 48 | * if (substream1_flag == 1) 49 | * { 8 uimsbf substream1 } 50 | * if (substream2_flag == 1) 51 | * { 8 uimsbf substream2 } 52 | * if (substream3_flag == 1) 53 | * { 8 uimsbf substream3 } 54 | * for(i=0;i 24 | /// A Extended Event Descriptor . 25 | /// 26 | /// 27 | /// For details please refer to the original documentation, 28 | /// e.g. ETSI EN 300 468 V1.15.1 (2016-03) or alternate versions. 29 | /// 30 | public class ExtendedEventDescriptor : Descriptor 31 | { 32 | public class Item 33 | { 34 | public Item() 35 | { 36 | } 37 | 38 | public Item(Item item) 39 | { 40 | ItemDescriptionLength = item.ItemDescriptionLength; 41 | ItemDescriptionChar = new Text(item.ItemDescriptionChar); 42 | ItemLength = item.ItemLength; 43 | ItemChar = new Text(item.ItemChar); 44 | } 45 | 46 | public byte ItemDescriptionLength { get; internal set; } 47 | public Text ItemDescriptionChar { get; internal set; } 48 | public byte ItemLength { get; internal set; } 49 | public Text ItemChar { get; internal set; } 50 | } 51 | 52 | public ExtendedEventDescriptor(byte[] stream, int start) : base(stream, start) 53 | { 54 | int lastindex = start + 2; 55 | try 56 | { 57 | DescriptorNumber = (byte)(stream[lastindex] >> 4 & 0x0F); 58 | LastDescriptorNumber = (byte)(stream[lastindex] & 0x0F); 59 | lastindex++; 60 | Iso639LanguageCode = Encoding.UTF8.GetString(stream, lastindex, 3); 61 | lastindex += Iso639LanguageCode.Length; 62 | LengthOfItems = stream[lastindex]; 63 | lastindex++; 64 | if (LengthOfItems != 0) 65 | { 66 | var items = new List(); 67 | while (LengthOfItems != 0) 68 | { 69 | var item = new Item { ItemDescriptionLength = stream[lastindex] }; 70 | lastindex++; 71 | if (item.ItemDescriptionLength != 0) 72 | { 73 | item.ItemDescriptionChar = new Text(stream, lastindex, item.ItemDescriptionLength); 74 | lastindex += item.ItemDescriptionLength; 75 | } 76 | 77 | item.ItemLength = stream[lastindex]; 78 | lastindex++; 79 | if (item.ItemLength != 0) 80 | { 81 | item.ItemChar = new Text(stream, lastindex, item.ItemLength); 82 | lastindex += item.ItemLength; 83 | } 84 | 85 | items.Add(item); 86 | LengthOfItems -= item.ItemDescriptionLength + item.ItemLength + 2; 87 | } 88 | 89 | Items = items; 90 | } 91 | 92 | TextLength = stream[lastindex]; 93 | lastindex++; 94 | if (TextLength != 0) 95 | { 96 | TextChar = new Text(stream, lastindex, TextLength); 97 | lastindex = +TextLength; 98 | } 99 | } 100 | catch (Exception) 101 | { 102 | throw new ArgumentOutOfRangeException("Index was outside the bounds of the array for ExtendedEventDescriptor"); 103 | } 104 | } 105 | 106 | public byte DescriptorNumber { get; } 107 | public byte LastDescriptorNumber { get; } 108 | public string Iso639LanguageCode { get; } 109 | public int LengthOfItems { get; } 110 | public IEnumerable Items { get; } 111 | public byte TextLength { get; } 112 | public Text TextChar { get; } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Descriptors/ExtensionDescriptor.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | namespace Cinegy.TsDecoder.Descriptors; 17 | 18 | public class ExtensionDescriptor : Descriptor 19 | { 20 | public ExtensionDescriptor(byte[] stream, int start) : base(stream, start) 21 | { 22 | 23 | } 24 | } -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Descriptors/HevcDescriptor.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | namespace Cinegy.TsDecoder.Descriptors; 17 | 18 | public class HevcDescriptor : Descriptor 19 | { 20 | public byte ProfileSpace { get; set; } 21 | 22 | public bool TierFlag { get; set; } 23 | 24 | public byte ProfileIdc { get; set; } 25 | 26 | public HevcDescriptor(byte[] stream, int start) : base(stream, start) 27 | { 28 | var idx = start + 2; 29 | 30 | ProfileSpace = (byte)((stream[idx] & 0b11000000) >> 6); 31 | TierFlag = (stream[idx] & 0b00100000) == 0b00100000; 32 | ProfileIdc = (byte)(stream[idx] & 0b00011111); 33 | //TODO: unpack the reset of the descriptor 34 | } 35 | } -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Descriptors/Iso639LanguageDescriptor.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | using System.Text; 17 | 18 | namespace Cinegy.TsDecoder.Descriptors 19 | { 20 | /// 21 | /// A Iso 639 Language Descriptor . 22 | /// 23 | /// 24 | /// For details please refer to the original documentation, 25 | /// e.g. ETSI EN 300 468 V1.15.1 (2016-03) or alternate versions. 26 | /// 27 | public class Iso639LanguageDescriptor : Descriptor 28 | { 29 | public Iso639LanguageDescriptor(byte[] stream, int start) : base(stream, start) 30 | { 31 | Language = Encoding.UTF8.GetString(stream, start + 2, 3); 32 | AudioType = stream[start + 5]; 33 | } 34 | 35 | public string Language { get; } 36 | public byte AudioType { get; } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Descriptors/LcnDescriptor.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | using System.Collections.Generic; 17 | 18 | namespace Cinegy.TsDecoder.Descriptors 19 | { 20 | /// 21 | /// A Logical Channel Number Descriptor 0x83 . 22 | /// 23 | /// 24 | /// For details please refer to the original documentation, 25 | /// e.g. ETSI EN 300 468 V1.15.1 (2016-03) or alternate versions. 26 | /// 27 | public class LcnDescriptor : Descriptor 28 | { 29 | public class LogicalchannelnumberItem 30 | { 31 | private ushort serviceID; 32 | private bool visibleServiceFlag; 33 | private byte reserved; 34 | private ushort logicalChannelNumber; 35 | 36 | public ushort ServiceID { get { return serviceID; } set { serviceID = value; } } 37 | public bool VisibleServiceFlag { get { return visibleServiceFlag; } set { visibleServiceFlag = value; } } 38 | public byte Reserved { get { return reserved; } set { reserved = value; } } 39 | public ushort LogicalChannelNumber { get { return logicalChannelNumber; } set { logicalChannelNumber = value; } } 40 | } 41 | 42 | private List logicalChannelNumbers = new List(); 43 | 44 | public LcnDescriptor(byte[] stream, int start) 45 | : base(stream, start) 46 | { 47 | 48 | for (int idx = start + 2; idx < start + DescriptorLength - 1; idx += 4) 49 | { 50 | LogicalchannelnumberItem lcnItem = new LogicalchannelnumberItem(); 51 | lcnItem.ServiceID = (ushort)(stream[idx] << 8 | stream[idx + 1]); 52 | lcnItem.VisibleServiceFlag = (stream[idx + 2] >> 7 & 0x01) != 0; ; 53 | lcnItem.Reserved = (byte)(stream[idx + 2] >> 2 & 0x1F); 54 | lcnItem.LogicalChannelNumber = (ushort)((stream[idx + 2] & 0x02) << 8 | stream[idx + 3]); 55 | logicalChannelNumbers.Add(lcnItem); 56 | } 57 | LogicalChannelNumbers = logicalChannelNumbers; 58 | } 59 | 60 | public IEnumerable LogicalChannelNumbers { get; } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Descriptors/LinkageDescriptor.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | using System; 17 | 18 | namespace Cinegy.TsDecoder.Descriptors 19 | { 20 | /// 21 | /// A Linkage Descriptor . 22 | /// 23 | /// 24 | /// For details please refer to the original documentation, 25 | /// e.g. ETSI EN 300 468 V1.15.1 (2016-03) Table 57 or alternate versions. 26 | /// 27 | public class LinkageDescriptor : Descriptor 28 | { 29 | public LinkageDescriptor(byte[] stream, int start) : base(stream, start) 30 | { 31 | try 32 | { 33 | TransportStreamId = (ushort)((Data[0] << 8) + Data[1]); 34 | 35 | OriginalNetworkId = (ushort)((Data[2] << 8) + Data[3]); 36 | 37 | ServiceId = (ushort)((Data[4] << 8) + Data[5]); 38 | 39 | LinkageType = Data[6]; 40 | 41 | //TODO: rest of message 42 | } 43 | catch (IndexOutOfRangeException) 44 | { 45 | throw new ArgumentOutOfRangeException("The Linkage Descriptor Message is short!"); 46 | } 47 | 48 | } 49 | 50 | public ushort TransportStreamId { get; } 51 | public ushort OriginalNetworkId { get; } 52 | public ushort ServiceId { get; } 53 | public byte LinkageType { get; } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Descriptors/MetadataDescriptor.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | namespace Cinegy.TsDecoder.Descriptors 17 | { 18 | public class MetadataDescriptor : Descriptor 19 | { 20 | public ushort ApplicationFormat { get; set; } 21 | 22 | public uint ApplicationFormatId { get; set; } 23 | 24 | public byte MetadataFormat { get; set; } 25 | 26 | public uint MetadataFormatId { get; set; } 27 | 28 | public byte MetadataServiceId { get; set; } 29 | 30 | public byte DecoderConfigFlag { get; set; } 31 | 32 | public bool DsmCcFlag { get; set; } 33 | 34 | public byte[] ServiceIdRecord { get; set; } 35 | 36 | public MetadataDescriptor(byte[] stream, int start) : base(stream, start) 37 | { 38 | var idx = start + 2; 39 | ApplicationFormat = (ushort)(stream[idx++] << 8); 40 | ApplicationFormat += (ushort)(stream[idx++] & 0xFF); 41 | 42 | if (ApplicationFormat == 0xFFFF) 43 | { 44 | ApplicationFormatId = (uint)(stream[idx++] << 24); 45 | ApplicationFormatId += (uint)(stream[idx++] << 16); 46 | ApplicationFormatId += (uint)(stream[idx++] << 8); 47 | ApplicationFormatId += (uint)(stream[idx++] & 0xFF); 48 | } 49 | 50 | MetadataFormat = stream[idx++]; 51 | 52 | if (MetadataFormat == 0xFF) 53 | { 54 | MetadataFormatId = (uint)(stream[idx++] << 24); 55 | MetadataFormatId += (uint)(stream[idx++] << 16); 56 | MetadataFormatId += (uint)(stream[idx++] << 8); 57 | MetadataFormatId += (uint)(stream[idx++] & 0xFF); 58 | } 59 | 60 | MetadataServiceId = stream[idx++]; 61 | 62 | DecoderConfigFlag = (byte)((stream[idx] & 0b11100000) >> 5); 63 | DsmCcFlag = (stream[idx++] & 0b00010000) > 0; 64 | 65 | if (DsmCcFlag) 66 | { 67 | var serviceIdLen = stream[idx++]; 68 | ServiceIdRecord = new byte[serviceIdLen]; 69 | for (int i = 0; i < serviceIdLen; i++) 70 | { 71 | ServiceIdRecord[i] = stream[idx++]; 72 | } 73 | } 74 | } 75 | 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Descriptors/MetadataStdDescriptor.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | namespace Cinegy.TsDecoder.Descriptors 17 | { 18 | public class MetadataStdDescriptor : Descriptor 19 | { 20 | //STD model input leak rate in bits per second 21 | public uint InputLeakRateBits { get; set; } 22 | 23 | public uint BufferSizeKB { get; set; } 24 | 25 | //STD model output leak rate in bits per second 26 | public uint OutputLeakRateBits { get; set; } 27 | 28 | public MetadataStdDescriptor(byte[] stream, int start) : base(stream, start) 29 | { 30 | var idx = start + 2; 31 | 32 | InputLeakRateBits = (uint)((stream[idx++] << 16) & 0b00111111); 33 | InputLeakRateBits += (uint)(stream[idx++] << 8); 34 | InputLeakRateBits += (uint)(stream[idx++] & 0xFF); 35 | InputLeakRateBits *= 400; 36 | 37 | BufferSizeKB = (uint)((stream[idx++] << 16) & 0b00111111); 38 | BufferSizeKB += (uint)(stream[idx++] << 8); 39 | BufferSizeKB += (uint)(stream[idx++] & 0xFF); 40 | 41 | OutputLeakRateBits = (uint)((stream[idx++] << 16) & 0b00111111); 42 | OutputLeakRateBits += (uint)(stream[idx++] << 8); 43 | OutputLeakRateBits += (uint)(stream[idx++] & 0xFF); 44 | OutputLeakRateBits *= 400; 45 | 46 | } 47 | 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Descriptors/NetworkNameDescriptor.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | using System.Text; 17 | 18 | namespace Cinegy.TsDecoder.Descriptors 19 | { 20 | /// 21 | /// A Networkname Descriptor . 22 | /// 23 | /// 24 | /// For details please refer to the original documentation, 25 | /// e.g. ETSI EN 300 468 V1.15.1 (2016-03) or alternate versions. 26 | /// 27 | public class NetworkNameDescriptor : Descriptor 28 | { 29 | public NetworkNameDescriptor(byte[] stream, int start) : base(stream, start) 30 | { 31 | var startOfName = (byte)(start + 2); 32 | switch (stream[start + 2]) 33 | { 34 | case 0x1F: 35 | startOfName += 2; 36 | break; 37 | case 0x10: 38 | startOfName += 3; 39 | break; 40 | } 41 | NetworkName = Encoding.UTF8.GetString(stream, startOfName, DescriptorLength - (startOfName - start) + 2); 42 | } 43 | 44 | public string NetworkName { get; } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Descriptors/ParentalRatingDescriptor.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | using System; 17 | using System.Collections.Generic; 18 | using System.Text; 19 | 20 | namespace Cinegy.TsDecoder.Descriptors 21 | { 22 | /// 23 | /// A Parental Rating Descriptor . 24 | /// 25 | /// 26 | /// For details please refer to the original documentation, 27 | /// e.g. ETSI EN 300 468 V1.15.1 (2016-03) or alternate versions. 28 | /// 29 | public class ParentalRatingDescriptor : Descriptor 30 | { 31 | public ParentalRatingDescriptor(byte[] stream, int start) : base(stream, start) 32 | { 33 | if (ParentalRatings == null) ParentalRatings = new List(); 34 | 35 | var lastindex = start + 2; 36 | try 37 | { 38 | if (DescriptorLength == 0) return; 39 | var length = DescriptorLength; 40 | 41 | while (length != 0) 42 | { 43 | CountryCode = Encoding.UTF8.GetString(stream, lastindex, 3); 44 | lastindex += 3; 45 | var parentalRating = (int)stream[lastindex]; 46 | lastindex++; 47 | ParentalRatings.Add(parentalRating); 48 | length -= 4; 49 | } 50 | } 51 | catch(Exception) 52 | { 53 | //corrupt packet; 54 | return; 55 | } 56 | } 57 | public string CountryCode { get; set; } 58 | public ICollection ParentalRatings { get; } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Descriptors/PrivateDataSpecifierDescriptor.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | using System; 17 | 18 | namespace Cinegy.TsDecoder.Descriptors 19 | { 20 | /// 21 | /// A Private Data Specifier Descriptor . 22 | /// 23 | /// 24 | /// For details please refer to the original documentation, 25 | /// e.g. ETSI EN 300 468 V1.15.1 (2016-03) or alternate versions. 26 | /// 27 | public class PrivateDataSpecifierDescriptor : Descriptor 28 | { 29 | public PrivateDataSpecifierDescriptor(byte[] stream, int start) : base(stream, start) 30 | { 31 | var lastIndex = start + 2; 32 | 33 | try 34 | { 35 | if (DescriptorLength != 0) 36 | { 37 | DataSpecifier = (stream[lastIndex] << 24) + (stream[lastIndex + 1] << 16) + (stream[lastIndex + 2] << 8) + stream[lastIndex + 3]; 38 | lastIndex += 4; 39 | } 40 | } 41 | catch (IndexOutOfRangeException) 42 | { 43 | throw new ArgumentOutOfRangeException("The Private Data Specifier Descriptor message is short"); 44 | } 45 | } 46 | 47 | public int DataSpecifier { get; private set; } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Descriptors/RegistrationDescriptor.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | using System; 17 | using System.Text; 18 | 19 | namespace Cinegy.TsDecoder.Descriptors 20 | { 21 | /// 22 | /// A Registration Descriptor . 23 | /// 24 | /// 25 | /// For details please refer to the original documentation, 26 | /// e.g. ETSI EN 300 468 V1.15.1 (2016-03) or alternate versions. 27 | /// 28 | public class RegistrationDescriptor : Descriptor 29 | { 30 | //ISO/IEC 13818-1:2007 Table 2-51 31 | public RegistrationDescriptor() { 32 | DescriptorTag = 0x5; 33 | DescriptorLength = 0x4; 34 | } 35 | 36 | public RegistrationDescriptor(byte[] stream, int start) : base(stream, start) 37 | { 38 | var idx = start + 2; //start + desc tag byte + desc len byte 39 | 40 | Buffer.BlockCopy(stream, idx, FormatIdentifier, 0, 4); 41 | idx += 4; 42 | 43 | if (DescriptorLength <= 4) return; 44 | AdditionalIdentificationInfo = new byte[DescriptorLength - 4]; 45 | Buffer.BlockCopy(stream, idx, AdditionalIdentificationInfo, 0, AdditionalIdentificationInfo.Length); 46 | } 47 | 48 | public byte[] FormatIdentifier { get; set; } = new byte[4]; 49 | 50 | public string Organization { 51 | get 52 | { 53 | var termination = 4; 54 | for (var i = 0; i < 4; i++) 55 | { 56 | if (FormatIdentifier[i] == 0) 57 | { 58 | termination = i; 59 | break; 60 | } 61 | else if (FormatIdentifier[i] < 32 || FormatIdentifier[i] > 126 ) 62 | { 63 | return string.Empty; 64 | } 65 | } 66 | 67 | return Encoding.ASCII.GetString(FormatIdentifier, 0, termination); 68 | } 69 | } 70 | 71 | public byte[] AdditionalIdentificationInfo { get; } 72 | 73 | public byte[] GetData() 74 | { 75 | if(DescriptorLength > 6) 76 | { 77 | throw new NotImplementedException("Registration Descriptors with Addition ID Info set are not yet supported for serialization"); 78 | } 79 | 80 | var data = new byte[2 + DescriptorLength]; 81 | data[0] = DescriptorTag; 82 | data[1] = DescriptorLength; 83 | Buffer.BlockCopy(FormatIdentifier, 0, data, 2, 4); 84 | return data; 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Descriptors/SatelliteDeliverySystemDescriptor.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | namespace Cinegy.TsDecoder.Descriptors 17 | { 18 | /// 19 | /// A Satelite Delivery Descriptor . 20 | /// 21 | /// 22 | /// For details please refer to the original documentation, 23 | /// e.g. ETSI EN 300 468 V1.15.1 (2016-03) or alternate versions. 24 | /// 25 | public class SatelliteDeliverySystemDescriptor : Descriptor 26 | { 27 | public static string[] PolarizationDescription = new string[] 28 | {"Linear-horizontal", "linear-vertical", "circular-left", "circular-right"}; 29 | 30 | public static string[] RoleOffDescription = new string[] { "α = 0,35", "α = 0,25", "α = 0,20", "reserved" }; 31 | 32 | public static string ModulationDescription(byte modulation) 33 | { 34 | switch (modulation) 35 | { 36 | case 0x0: 37 | return "Auto"; 38 | case 0x01: 39 | return "QPSK"; 40 | case 0x02: 41 | return "8PSK"; 42 | case 0x03: 43 | return "16-QAM (n/a for DVB-S2)"; 44 | default: 45 | return "Impossible in a 2 bit number"; 46 | } 47 | } 48 | 49 | public static string FECInnerDescription(byte fecInner) 50 | { 51 | switch (fecInner) 52 | { 53 | case 0x0: 54 | return "not defined"; 55 | case 0x1: 56 | return "1/2 conv. code rate"; 57 | case 0x2: 58 | return "2/3 conv. code rate"; 59 | case 0x3: 60 | return "3/4 conv. code rate"; 61 | case 0x4: 62 | return "5/6 conv. code rate"; 63 | case 0x5: 64 | return "7/8 conv. code rate"; 65 | case 0x6: 66 | return "8/9 conv. code rate"; 67 | case 0x7: 68 | return "3/5 conv. code rate "; 69 | case 0x8: 70 | return "4/5 conv. code rate"; 71 | case 0x9: 72 | return "9/10 conv. code rate"; 73 | case 0xf: 74 | return "no conv. coding"; 75 | default: 76 | return "reserved"; 77 | } 78 | } 79 | 80 | public SatelliteDeliverySystemDescriptor(byte[] stream, int start) : base(stream, start) 81 | { 82 | Frequency = 83 | $"{stream[start + 2] >> 4 & 0x0F}{stream[start + 2] & 0x0F}{stream[start + 3] >> 4 & 0x0F}{stream[start + 3] & 0x0F}{stream[start + 4] >> 4 & 0x0F}{stream[start + 4] & 0x0F}{stream[start + 5] >> 4 & 0x0F}{stream[start + 5] & 0x0F}"; 84 | OrbitalPosition = 85 | $"{stream[start + 6] >> 4 & 0x0F}{stream[start + 6] & 0x0F}{stream[start + 7] >> 4 & 0x0F}{stream[start + 7] & 0x0F}"; 86 | WestEastFlag = (stream[start + 8] >> 7 & 0x01) == 0x01; 87 | Polarization = (byte)(stream[start + 8] >> 5 & 0x03); 88 | RollOff = (byte)(stream[start + 8] >> 3 & 0x03); 89 | ModulationSystem = (stream[start + 8] >> 2 & 0x01) == 0x01; 90 | Modulation = (byte)(stream[start + 8] & 0x03); 91 | SymbolRate = 92 | $"{stream[start + 9] >> 4 & 0x0F}{stream[start + 9] & 0x0F}{stream[start + 10] >> 4 & 0x0F}{stream[start + 10] & 0x0F}{stream[start + 11] >> 4 & 0x0F}{stream[start + 11] & 0x0F}{stream[start + 12] >> 4 & 0x0F}"; 93 | FECInner = (byte)(stream[start + 12] & 0x0F); 94 | } 95 | 96 | public string Frequency { get; } 97 | public string FrequencyString => string.Format("{0} GHz", Frequency.Insert(3, ",")); 98 | public string OrbitalPosition { get; } 99 | public string OrbitalPositionString => string.Format("{0} deg", OrbitalPosition.Insert(3, ",")); 100 | public bool WestEastFlag { get; } 101 | public byte Polarization { get; } 102 | public byte RollOff { get; } 103 | public string RollOffString => RoleOffDescription[RollOff]; 104 | public string PolarizationString => PolarizationDescription[Polarization]; 105 | public bool ModulationSystem { get; } 106 | public string ModulationSystemString => ModulationSystem ? "S2" : "S"; 107 | public byte Modulation { get; } 108 | public string ModulationString => ModulationDescription(Modulation); 109 | public string SymbolRate { get; } 110 | public byte FECInner { get; } 111 | public string FECInnerString => FECInnerDescription(FECInner); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Descriptors/ScramblingDescriptor.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | using System; 17 | 18 | namespace Cinegy.TsDecoder.Descriptors 19 | { 20 | /// 21 | /// A Scrambling Descriptor . 22 | /// 23 | /// 24 | /// For details please refer to the original documentation, 25 | /// e.g. ETSI EN 300 468 V1.15.1 (2016-03) Table 84 or alternate versions. 26 | /// 27 | public class ScramblingDescriptor : Descriptor 28 | { 29 | public ScramblingDescriptor(byte[] stream, int start) : base(stream, start) 30 | { 31 | 32 | var lastIndex = start + 2; 33 | 34 | try 35 | { 36 | if (DescriptorLength != 0) 37 | { 38 | ScramblingMode = (stream[lastIndex + 0] << 8) + stream[lastIndex + 1]; 39 | lastIndex += 4; 40 | } 41 | } 42 | catch (IndexOutOfRangeException) 43 | { 44 | throw new ArgumentOutOfRangeException("The Scrambling Descriptor message is short"); 45 | } 46 | } 47 | 48 | public int ScramblingMode { get; private set; } 49 | 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Descriptors/ServiceDescriptor.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | using Cinegy.TsDecoder.TransportStream; 17 | 18 | namespace Cinegy.TsDecoder.Descriptors 19 | { 20 | /// 21 | /// A Service Descriptor . 22 | /// 23 | /// 24 | /// For details please refer to the original documentation, 25 | /// e.g. ETSI EN 300 468 V1.15.1 (2016-03) or alternate versions. 26 | /// 27 | public class ServiceDescriptor : Descriptor 28 | { 29 | public static string GetServiceTypeDescription(byte serviceType) 30 | { 31 | switch (serviceType) 32 | { 33 | case 0x00: 34 | return "reserved for future use"; 35 | case 0x01: 36 | return "digital television service (see note 1)"; 37 | case 0x02: 38 | return "digital radio sound service (see note 2)"; 39 | case 0x03: 40 | return "Teletext service"; 41 | case 0x04: 42 | return "NVOD reference service (see note 1)"; 43 | case 0x05: 44 | return "NVOD time-shifted service (see note 1)"; 45 | case 0x06: 46 | return "mosaic service"; 47 | case 0x07: 48 | return "FM radio service"; 49 | case 0x08: 50 | return "DVB SRM service [49]"; 51 | case 0x09: 52 | return "reserved for future use"; 53 | case 0x0A: 54 | return "advanced codec digital radio sound service"; 55 | case 0x0B: 56 | return "H.264/AVC mosaic service"; 57 | case 0x0C: 58 | return "data broadcast service"; 59 | case 0x0D: 60 | return "reserved for Common Interface Usage (EN 50221[37])"; 61 | case 0x0E: 62 | return "RCS Map (see EN301790[7])"; 63 | case 0x0F: 64 | return "RCS FLS (see EN301790[7])"; 65 | case 0x10: 66 | return "DVB MHP service 0x11 MPEG-2 HD digital television service"; 67 | case 0x16: 68 | return "H.264/AVC SD digital television service"; 69 | case 0x17: 70 | return "H.264/AVC SD NVOD time-shifted service"; 71 | case 0x18: 72 | return "H.264/AVC SD NVOD reference service"; 73 | case 0x19: 74 | return "H.264/AVC HD digital television service"; 75 | case 0x1A: 76 | return "H.264/AVC HD NVOD time-shifted service"; 77 | case 0x1B: 78 | return "H.264/AVC HD NVOD reference service"; 79 | case 0x1C: 80 | return "H.264/AVC frame compatible plano-stereoscopic HD digital television service (see note 3)"; 81 | case 0x1D: 82 | return "H.264/AVC frame compatible plano-stereoscopic HD NVOD time-shifted service (see note 3)"; 83 | case 0x1E: 84 | return "H.264/AVC frame compatible plano-stereoscopic HD NVOD reference service (see note 3)"; 85 | case 0x1F: 86 | return "HEVC digital television service"; 87 | case 0xFF: 88 | return "reserved for future use"; 89 | } 90 | if (serviceType >= 0x20 || serviceType <= 0x7F) 91 | { 92 | return "reserved for future use"; 93 | } 94 | if (serviceType >= 0x80 || serviceType <= 0xFE) 95 | { 96 | return "user defined"; 97 | } 98 | if (serviceType >= 0x12 || serviceType <= 0x15) 99 | { 100 | return "reserved for future use"; 101 | } 102 | return "unknown"; 103 | } 104 | 105 | public ServiceDescriptor(byte[] stream, int start) : base(stream, start) 106 | { 107 | ServiceType = stream[start + 2]; 108 | ServiceProviderNameLength = stream[start + 3]; 109 | ServiceProviderName = new Text(stream, start + 4, ServiceProviderNameLength); 110 | ServiceNameLength = stream[start + 4 + ServiceProviderNameLength]; 111 | ServiceName = new Text(stream, start + 4 + ServiceProviderNameLength + 1, ServiceNameLength); 112 | } 113 | 114 | public byte ServiceType { get; } //8 uimsbf 115 | public string ServiceTypeDescription => GetServiceTypeDescription(ServiceType); 116 | public byte ServiceProviderNameLength { get; } // 8 uimsbf 117 | public Text ServiceProviderName { get; } // 118 | public byte ServiceNameLength { get; } // 8 uimsbf 119 | public Text ServiceName { get; } 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Descriptors/ServiceListDescriptor.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | using System.Collections.Generic; 17 | 18 | namespace Cinegy.TsDecoder.Descriptors 19 | { 20 | /// 21 | /// A Service List Descriptor . 22 | /// 23 | /// 24 | /// For details please refer to the original documentation, 25 | /// e.g. ETSI EN 300 468 V1.15.1 (2016-03) or alternate versions. 26 | /// 27 | public class ServiceListDescriptor : Descriptor 28 | { 29 | public static string ServiceTypeDescription(byte serviceType) 30 | { 31 | if (serviceType <= 0x0C) 32 | { 33 | switch (serviceType) 34 | { 35 | case 0x00: 36 | return "reserved for future use"; 37 | case 0x01: 38 | return "digital television service"; 39 | case 0x02: 40 | return "digital radio sound service"; 41 | case 0x03: 42 | return "teletext service"; 43 | case 0x04: 44 | return "NVOD reference service"; 45 | case 0x05: 46 | return "NVOD time-shifted service"; 47 | case 0x06: 48 | return "mosaic service"; 49 | case 0x07: 50 | return "PAL coded signal"; 51 | case 0x08: 52 | return "SECAM coded signal"; 53 | case 0x09: 54 | return "D/D2-MAC"; 55 | case 0x0A: 56 | return "FM Radio"; 57 | case 0x0B: 58 | return "NTSC coded signal"; 59 | case 0x0C: 60 | return "data broadcast service"; 61 | } 62 | } 63 | else if (serviceType >= 0x0D && serviceType <= 0x7F) 64 | { 65 | return "reserved for future use"; 66 | } 67 | else if (serviceType >= 0x80 && serviceType <= 0xFE) 68 | { 69 | return "user defined"; 70 | } 71 | 72 | return "Forbidden"; 73 | } 74 | 75 | public class Service 76 | { 77 | public Service() 78 | { 79 | } 80 | 81 | public Service(Service service) 82 | { 83 | ServiceId = service.ServiceId; 84 | ServiceType = service.ServiceType; 85 | } 86 | 87 | public ushort ServiceId { get; internal set; } 88 | public byte ServiceType { get; internal set; } 89 | public string ServiceTypeString => ServiceTypeDescription(ServiceType); 90 | } 91 | 92 | public ServiceListDescriptor(byte[] stream, int start) : base(stream, start) 93 | { 94 | var services = new List(); 95 | var startOfNextBlock = (ushort)(start + 2); 96 | while (startOfNextBlock < start + DescriptorLength + 2) 97 | { 98 | var service = new Service 99 | { 100 | ServiceId = (ushort)((stream[startOfNextBlock] << 8) + stream[startOfNextBlock + 1]), 101 | ServiceType = stream[startOfNextBlock + 2] 102 | }; 103 | 104 | startOfNextBlock += 3; 105 | 106 | services.Add(service); 107 | } 108 | Services = services; 109 | } 110 | 111 | public IEnumerable Services { get; } 112 | 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Descriptors/ShortEventDescriptor.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | using System; 17 | using System.Text; 18 | using Cinegy.TsDecoder.TransportStream; 19 | 20 | namespace Cinegy.TsDecoder.Descriptors 21 | { 22 | /// 23 | /// A Short Event Descriptor . 24 | /// 25 | /// 26 | /// For details please refer to the original documentation, 27 | /// e.g. ETSI EN 300 468 V1.15.1 (2016-03) or alternate versions. 28 | /// 29 | public class ShortEventDescriptor : Descriptor 30 | { 31 | public ShortEventDescriptor(byte[] stream, int start) : base(stream, start) 32 | { 33 | int lastindex = start + 2; 34 | try 35 | { 36 | 37 | Iso639LanguageCode = Encoding.UTF8.GetString(stream, lastindex, 3); 38 | lastindex += Iso639LanguageCode.Length; 39 | 40 | EventNameLength = stream[lastindex]; 41 | lastindex++; 42 | 43 | if (EventNameLength != 0) 44 | { 45 | EventNameChar = new Text(stream, lastindex, EventNameLength); 46 | lastindex += EventNameLength; 47 | //Debug.WriteLine(EventNameChar); 48 | } 49 | 50 | TextLength = stream[lastindex]; 51 | lastindex++; 52 | if (TextLength != 0) 53 | { 54 | TextChar = new Text(stream, lastindex, TextLength); 55 | lastindex += TextLength; 56 | //Debug.WriteLine(TextChar); 57 | } 58 | } 59 | catch (IndexOutOfRangeException) 60 | { 61 | throw new ArgumentOutOfRangeException("Index was outside the bounds of the array."); 62 | } 63 | } 64 | 65 | public string Iso639LanguageCode { get; } 66 | public byte EventNameLength { get; } 67 | public Text EventNameChar { get; } 68 | public byte TextLength { get; } 69 | public Text TextChar { get; } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Descriptors/StreamIdentifierDescriptor.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | namespace Cinegy.TsDecoder.Descriptors 17 | { 18 | /// 19 | /// A Stream Identifier Descriptor . 20 | /// 21 | /// 22 | /// For details please refer to the original documentation, 23 | /// e.g. ETSI EN 300 468 V1.15.1 (2016-03) or alternate versions. 24 | /// 25 | public class StreamIdentifierDescriptor : Descriptor 26 | { 27 | public StreamIdentifierDescriptor(byte[] stream, int start) : base(stream, start) 28 | { 29 | ComponentTag = stream[start + 2]; 30 | } 31 | 32 | public byte ComponentTag { get; } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Descriptors/SubtitlingDescriptor.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | using System.Collections.Generic; 17 | using System.Text; 18 | 19 | namespace Cinegy.TsDecoder.Descriptors 20 | { 21 | /// 22 | /// A Subtitling Descriptor . 23 | /// 24 | /// 25 | /// For details please refer to the original documentation, 26 | /// e.g. ETSI EN 300 468 V1.15.1 (2016-03) or alternate versions. 27 | /// 28 | public class SubtitlingDescriptor : Descriptor 29 | { 30 | 31 | public SubtitlingDescriptor(byte[] stream, int start) : base(stream, start) 32 | { 33 | var languages = new List(); 34 | var currentPos = start + 2; 35 | do 36 | { 37 | var lang = new Language 38 | { 39 | Iso639LanguageCode = Encoding.UTF8.GetString(stream, currentPos, 3), 40 | SubtitlingType = stream[currentPos + 3], 41 | CompositionPageId = (ushort)((stream[currentPos + 4] << 8) + stream[currentPos + 5]), 42 | AncillaryPageId = (ushort)((stream[currentPos + 6] << 8) + stream[currentPos + 7]) 43 | }; 44 | 45 | languages.Add(lang); 46 | 47 | currentPos += 8; 48 | 49 | } while (currentPos < start + 2 + DescriptorLength); 50 | Languages = languages; 51 | } 52 | 53 | public class Language 54 | { 55 | public string Iso639LanguageCode { get; internal set; } 56 | public byte SubtitlingType { get; internal set; } 57 | public ushort CompositionPageId { get; internal set; } 58 | public ushort AncillaryPageId { get; internal set; } 59 | } 60 | 61 | public IEnumerable Languages { get; } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Descriptors/TeletextDescriptor.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | using System.Collections.Generic; 17 | using System.Text; 18 | 19 | namespace Cinegy.TsDecoder.Descriptors 20 | { 21 | /// 22 | /// A TeleText Descriptor . 23 | /// 24 | /// 25 | /// For details please refer to the original documentation, 26 | /// e.g. ETSI EN 300 468 V1.15.1 (2016-03) or alternate versions. 27 | /// 28 | public class TeletextDescriptor : Descriptor 29 | { 30 | public static Dictionary TeletextTypes = new Dictionary() 31 | { 32 | {0x00, "reserved for future use"}, 33 | {0x01, "initial Teletext page"}, 34 | {0x02, "Teletext subtitle page"}, 35 | {0x03, "additional information page"}, 36 | {0x04, "programme schedule page"}, 37 | {0x05, "Teletext subtitle page for hearing impaired people"}, 38 | {0x07, "reserved for future use"}, 39 | {0x08, "reserved for future use"}, 40 | {0x09, "reserved for future use"}, 41 | {0x0A, "reserved for future use"}, 42 | {0x0B, "reserved for future use"}, 43 | {0x0C, "reserved for future use"}, 44 | {0x0D, "reserved for future use"}, 45 | {0x0E, "reserved for future use"}, 46 | {0x0F, "reserved for future use"}, 47 | {0x10, "reserved for future use"}, 48 | {0x11, "reserved for future use"}, 49 | {0x12, "reserved for future use"}, 50 | {0x13, "reserved for future use"}, 51 | {0x14, "reserved for future use"}, 52 | {0x15, "reserved for future use"}, 53 | {0x16, "reserved for future use"}, 54 | {0x17, "reserved for future use"}, 55 | {0x18, "reserved for future use"}, 56 | {0x19, "reserved for future use"}, 57 | {0x1A, "reserved for future use"}, 58 | {0x1B, "reserved for future use"}, 59 | {0x1C, "reserved for future use"}, 60 | {0x1D, "reserved for future use"}, 61 | {0x1E, "reserved for future use"}, 62 | {0x1F, "reserved for future use"} 63 | }; 64 | 65 | 66 | public TeletextDescriptor(byte[] stream, int start) 67 | : base(stream, start) 68 | { 69 | var languages = new List(); 70 | var currentPos = start + 2; 71 | do 72 | { 73 | var lang = new Language 74 | { 75 | Iso639LanguageCode = Encoding.UTF8.GetString(stream, currentPos, 3), 76 | TeletextType = (byte)(stream[currentPos + 3] >> 3 & 0x01f), 77 | TeletextMagazineNumber = (byte)(stream[currentPos + 3] & 0x7), 78 | TeletextPageNumber = stream[currentPos + 4] 79 | }; 80 | 81 | languages.Add(lang); 82 | 83 | currentPos += 5; 84 | 85 | } while (currentPos < start + 2 + DescriptorLength); 86 | Languages = languages; 87 | } 88 | 89 | public class Language 90 | { 91 | public Language() 92 | { 93 | } 94 | 95 | public Language(Language lang) 96 | { 97 | Iso639LanguageCode = lang.Iso639LanguageCode; 98 | TeletextType = lang.TeletextType; 99 | TeletextMagazineNumber = lang.TeletextMagazineNumber; 100 | TeletextPageNumber = lang.TeletextPageNumber; 101 | } 102 | 103 | public string Iso639LanguageCode { get; internal set; } 104 | public byte TeletextType { get; internal set; } 105 | public byte TeletextMagazineNumber { get; internal set; } 106 | public byte TeletextPageNumber { get; internal set; } 107 | } 108 | 109 | public IEnumerable Languages { get; } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Descriptors/TerrestrialDeliverySystemDescriptor.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | namespace Cinegy.TsDecoder.Descriptors 17 | { 18 | /// 19 | /// A Terrestrial Delivery System Descriptor . 20 | /// 21 | /// 22 | /// For details please refer to the original documentation, 23 | /// e.g. ETSI EN 300 468 V1.15.1 (2016-03) or alternate versions. 24 | /// 25 | public class TerrestrialDeliverySystemDescriptor : Descriptor 26 | { 27 | public static string[] BandwidthDescription = new string[] 28 | { 29 | "8 MHz", "7 MHz", "reserved for future us", "reserved for future us", "reserved for future us", 30 | "reserved for future us", "reserved for future us", "reserved for future us" 31 | }; 32 | 33 | public static string[] ConstellationDescription = new string[] 34 | { 35 | "QPSK", "16-QAM", "64-QAM", "reserved for future use" 36 | }; 37 | 38 | public static string[] HierarchyInformationDescription = new string[] 39 | { 40 | "non-hierarchical", "α = 1", "α = 2", "α = 4", "reserved for future us", "reserved for future us", 41 | "reserved for future us", "reserved for future us" 42 | }; 43 | 44 | public static string[] CodeRateDescription = new string[] 45 | { 46 | "1/2", "2/3", "3/4", "5/6", "7/8", "reserved for future us", "reserved for future us", "reserved for future us" 47 | }; 48 | 49 | public static string[] GuardIntervalDescription = new string[] { "1/32", "1/16", "1/8", "1/4" }; 50 | 51 | public static string[] TransmissionModeDescription = new string[] 52 | { 53 | "2k mode", "8k mode", "reserved for future us", "reserved for future us4" 54 | }; 55 | 56 | public TerrestrialDeliverySystemDescriptor(byte[] stream, int start) : base(stream, start) 57 | { 58 | CentreFrequency = 59 | (uint) 60 | ((stream[start + 2] << 24) + (stream[start + 3] << 16) + (stream[start + 4] << 8) + 61 | stream[start + 5]); 62 | Bandwidth = (byte)(stream[start + 6] >> 5 & 0x07); 63 | ReservedFutureUse = (byte)(stream[start + 6] & 0x1F); 64 | Constellation = (byte)(stream[start + 7] >> 6 & 0x03); 65 | HierarchyInformation = (byte)(stream[start + 7] >> 3 & 0x07); 66 | CodeRateHPStream = (byte)(stream[start + 7] & 0x07); 67 | CodeRateLPStream = (byte)(stream[start + 8] >> 5 & 0x07); 68 | GuardInterval = (byte)(stream[start + 8] >> 3 & 0x03); 69 | TransmissionMode = (byte)(stream[start + 8] >> 1 & 0x03); 70 | OtherFrequencyFlag = (stream[start + 8] & 0x01) == 0x01; 71 | ReservedFutureUse2 = 72 | (uint) 73 | ((stream[start + 9] << 24) + (stream[start + 10] << 16) + (stream[start + 11] << 8) + 74 | stream[start + 12]); 75 | } 76 | 77 | public uint CentreFrequency { get; } 78 | public byte Bandwidth { get; } 79 | public string BandwidthString => BandwidthDescription[Bandwidth]; 80 | public byte ReservedFutureUse { get; } 81 | public byte Constellation { get; } 82 | public string ConstellationString => ConstellationDescription[Constellation]; 83 | public byte HierarchyInformation { get; } 84 | public string HierarchyInformationString => HierarchyInformationDescription[HierarchyInformation]; 85 | public byte CodeRateHPStream { get; } 86 | public string CodeRateHPStreamString => CodeRateDescription[CodeRateHPStream]; 87 | public byte CodeRateLPStream { get; } 88 | public string CodeRateLPStreamString => CodeRateDescription[CodeRateLPStream]; 89 | public byte GuardInterval { get; } 90 | public string GuardIntervalString => GuardIntervalDescription[GuardInterval]; 91 | public byte TransmissionMode { get; } 92 | public bool OtherFrequencyFlag { get; } 93 | public uint ReservedFutureUse2 { get; } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Tables/EventInformationItem.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | using System.Collections.Generic; 17 | using Cinegy.TsDecoder.Descriptors; 18 | 19 | // ReSharper disable UnusedAutoPropertyAccessor.Global 20 | 21 | namespace Cinegy.TsDecoder.Tables 22 | { 23 | public class EventInformationItem 24 | { 25 | public static string[] RunningStatusDescription = new string[] { "undefined", "not running", "Starts in a few seconds", "pausing", "running", "reserved for future use", "reserved for future use" }; 26 | public ushort EventId { get; set; }// 16 uimsbf 27 | public ulong StartTime { get; set; }// 40 bslbf 28 | public string StartTimeString 29 | { 30 | get 31 | { 32 | var mjd = StartTime >> 24; 33 | long y, m, d, k; 34 | 35 | y = (long)((mjd - 15078.2) / 365.25); 36 | m = (long)((mjd - 14956.1 - (long)(y * 365.25)) / 30.6001); 37 | d = (long)(mjd - 14956 - (ulong)(y * 365.25) - (ulong)(m * 30.6001)); 38 | k = m == 14 || m == 15 ? 1 : 0; 39 | y = y + k + 1900; 40 | m = m - 1 - k * 12; 41 | 42 | return string.Format("{3,00}-{4,00}-{5,00} {0:x}:{1:x}:{2:x}", (StartTime >> 16) & 0xFF, (StartTime >> 8) & 0xFF, StartTime & 0xFF, y, m, d); 43 | } 44 | } 45 | public uint Duration { get; set; }// 24 uimsbf 46 | public string DurationString => string.Format("{0:x}:{1:x}:{2:x}", (Duration >> 16) & 0xFF, (Duration >> 8) & 0xFF, Duration & 0xFF); 47 | public byte RunningStatus { get; set; }// 3 uimsbf 48 | public string RunningStatusString => RunningStatusDescription[RunningStatus]; 49 | public bool FreeCAMode { get; set; }// 1 bslbf 50 | public ushort DescriptorsLoopLength { get; set; }// 12 uimsbf 51 | public IEnumerable Descriptors { get; set; } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Tables/EventInformationTable.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | using System.Collections.Generic; 17 | 18 | // ReSharper disable UnusedAutoPropertyAccessor.Global 19 | 20 | namespace Cinegy.TsDecoder.Tables 21 | { 22 | public class EventInformationTable : Table 23 | { 24 | public ushort ServiceId { get; set; } 25 | public byte VersionNumber { get; set; } 26 | public bool CurrentNextIndicator { get; set; } 27 | public byte SectionNumber { get; set; } 28 | public byte LastSectionNumber { get; set; } 29 | public ushort TransportStreamId { get; set; } 30 | public ushort OriginalNetworkId { get; set; } 31 | public byte SegmentLastSectionNumber { get; set; } 32 | public byte LastTableId { get; set; } 33 | public List Items { get; set; } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Tables/ITable.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | using System.Collections.Generic; 17 | using Cinegy.TsDecoder.Descriptors; 18 | 19 | namespace Cinegy.TsDecoder.Tables 20 | { 21 | public interface ITable 22 | { 23 | List Descriptors { get; set; } 24 | ushort Pid { get; set; } 25 | byte PointerField { get; set; } 26 | ushort SectionLength { get; set; } 27 | byte TableId { get; set; } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Tables/ProgramAssociationTable.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | // ReSharper disable UnusedAutoPropertyAccessor.Global 17 | namespace Cinegy.TsDecoder.Tables 18 | { 19 | public class ProgramAssociationTable : Table 20 | { 21 | public ushort TransportStreamId { get; set; } 22 | public byte VersionNumber { get; set; } 23 | public bool CurrentNextIndicator { get; set; } 24 | public byte SectionNumber { get; set; } 25 | public byte LastSectionNumber { get; set; } 26 | public ushort[] ProgramNumbers { get; set; } 27 | public ushort[] Pids { get; set; } 28 | public uint Crc { get; set; } 29 | 30 | public byte[] GetData() 31 | { 32 | if(SectionLength == 0) 33 | { 34 | SectionLength = (ushort)(9 + ProgramNumbers.Length * 4); 35 | } 36 | 37 | var data = new byte[3 + SectionLength]; 38 | data[0] = TableId; 39 | data[1] = 0b10000000; //section_syntax_indicator shall be '1', followed by '0', followed by 2 reserved bytes, and a leading 2 '0's from section length 40 | data[1] = (byte)((SectionLength >> 8) & 0b00000011); 41 | data[2] = (byte)(SectionLength & 0xFF); 42 | data[3] = (byte)(TransportStreamId >> 8); 43 | data[4] = (byte)(TransportStreamId & 0xFF); 44 | data[5] = (byte)(VersionNumber & 0b00111110); 45 | if (CurrentNextIndicator) data[5] += 0b00000001; 46 | data[6] = SectionNumber; 47 | data[7] = LastSectionNumber; 48 | 49 | var idx = 8; 50 | for (var i = 0; i < ProgramNumbers.Length; i++) 51 | { 52 | data[idx] = (byte)(ProgramNumbers[i] >> 8); 53 | data[idx + 1] = (byte)(ProgramNumbers[i] & 0xFF); 54 | data[idx + 2] = (byte)((Pids[i] >> 8) & 0b000111111); 55 | data[idx + 3] = (byte)(Pids[i] & 0xFF); 56 | i++; 57 | idx += 4; 58 | } 59 | 60 | //TODO: CRC needs calc'ing here 61 | 62 | return data; 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Tables/ProgramAssociationTableFactory.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | using System.Diagnostics; 17 | using Cinegy.TsDecoder.TransportStream; 18 | 19 | namespace Cinegy.TsDecoder.Tables 20 | { 21 | public class ProgramAssociationTableFactory : TableFactory 22 | { 23 | public ProgramAssociationTable ProgramAssociationTable { get; private set; } 24 | 25 | private new ProgramAssociationTable InProgressTable 26 | { 27 | get { return base.InProgressTable as ProgramAssociationTable; } 28 | set { base.InProgressTable = value; } 29 | } 30 | 31 | public void AddPacket(TsPacket packet) 32 | { 33 | CheckPid(packet.Pid); 34 | 35 | if (!packet.PayloadUnitStartIndicator) return; 36 | 37 | InProgressTable = new ProgramAssociationTable { PointerField = packet.Payload[0] }; 38 | 39 | if (InProgressTable.PointerField > packet.PayloadLen) 40 | { 41 | Debug.Assert(true, "Program Association Table has packet pointer outside the packet."); 42 | } 43 | 44 | var pos = 1 + InProgressTable.PointerField; 45 | 46 | if (pos > 184) 47 | { 48 | CorruptedPackets++; 49 | InProgressTable = null; 50 | return; 51 | } 52 | InProgressTable.VersionNumber = (byte)((packet.Payload[pos + 5] & 0x3E) >> 1); 53 | 54 | //if (ProgramAssociationTable != null && ProgramAssociationTable.VersionNumber == InProgressTable.VersionNumber) 55 | //{ 56 | // InProgressTable = null; 57 | // return; 58 | //} 59 | 60 | InProgressTable.TransportStreamId = (ushort)((packet.Payload[pos + 3] << 8) + packet.Payload[pos + 4]); 61 | 62 | InProgressTable.TableId = packet.Payload[pos]; 63 | InProgressTable.SectionLength = (ushort)(((packet.Payload[pos + 1] & 0x3) << 8) + packet.Payload[pos + 2]); 64 | 65 | InProgressTable.CurrentNextIndicator = (packet.Payload[pos + 5] & 0x1) != 0; 66 | InProgressTable.SectionNumber = packet.Payload[pos + 6]; 67 | InProgressTable.LastSectionNumber = packet.Payload[pos + 7]; 68 | 69 | if (InProgressTable.SectionLength - 9 < 1) 70 | { 71 | CorruptedPackets++; 72 | InProgressTable = null; 73 | return; 74 | } 75 | InProgressTable.ProgramNumbers = new ushort[(InProgressTable.SectionLength - 9) / 4]; 76 | InProgressTable.Pids = new ushort[(InProgressTable.SectionLength - 9) / 4]; 77 | 78 | var programStart = pos + 8; 79 | pos = programStart; 80 | 81 | for (var i = 0; i < (InProgressTable.SectionLength - 9) / 4; i++) 82 | { 83 | if (programStart + (i * 4) + 3 > 184) 84 | { 85 | InProgressTable = null; 86 | return; 87 | } 88 | 89 | InProgressTable.ProgramNumbers[i] = 90 | (ushort) 91 | ((packet.Payload[programStart + (i * 4)] << 8) + packet.Payload[programStart + 1 + (i * 4)]); 92 | InProgressTable.Pids[i] = 93 | (ushort) 94 | (((packet.Payload[programStart + 2 + (i * 4)] & 0x1F) << 8) + 95 | packet.Payload[programStart + 3 + (i * 4)]); 96 | 97 | pos += 4; 98 | } 99 | 100 | InProgressTable.Crc = (uint)(((packet.Payload[pos]) << 24) + (packet.Payload[pos + 1] << 16) + 101 | (packet.Payload[pos + 2] << 8) + (packet.Payload[pos + 3])); 102 | 103 | if (InProgressTable.Crc == ProgramAssociationTable?.Crc) return; 104 | 105 | ProgramAssociationTable = InProgressTable; 106 | 107 | OnTableChangeDetected(); 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Tables/ProgramMapTable.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | using System.Collections.Generic; 17 | using Cinegy.TsDecoder.TransportStream; 18 | using System; 19 | 20 | // ReSharper disable UnusedAutoPropertyAccessor.Global 21 | 22 | namespace Cinegy.TsDecoder.Tables 23 | { 24 | public class ProgramMapTable : Table 25 | { 26 | public ushort ProgramNumber { get; set; } 27 | public byte VersionNumber { get; set; } 28 | public bool CurrentNextIndicator { get; set; } 29 | public byte SectionNumber { get; set; } 30 | public byte LastSectionNumber { get; set; } 31 | public ushort PcrPid { get; set; } 32 | public byte ProgramInfoLength { get; set; } 33 | public List EsStreams { get; set; } 34 | public uint Crc { get; set; } 35 | 36 | public byte[] GetData() 37 | { 38 | if(ProgramInfoLength == 0) 39 | { 40 | if (Descriptors != null) 41 | { 42 | foreach(var desc in Descriptors) 43 | { 44 | ProgramInfoLength += (byte)(2 + desc.DescriptorLength); 45 | } 46 | } 47 | } 48 | 49 | if (SectionLength == 0) 50 | { 51 | SectionLength = (ushort)(9 + ProgramInfoLength + 4); 52 | if (EsStreams != null) 53 | { 54 | foreach (var esInfo in EsStreams) 55 | { 56 | SectionLength += 5; 57 | SectionLength += esInfo.DescriptorsLength; 58 | } 59 | } 60 | } 61 | 62 | var data = new byte[3 + SectionLength]; 63 | data[0] = TableId; 64 | data[1] = 0b10000000; //section_syntax_indicator shall be '1', followed by '0', followed by 2 reserved bytes, and a leading 2 '0's from section length 65 | data[1] = (byte)((SectionLength >> 8) & 0b00000011); 66 | data[2] = (byte)(SectionLength & 0xFF); 67 | data[3] = (byte)(ProgramNumber >> 8); 68 | data[4] = (byte)(ProgramNumber & 0xFF); 69 | data[5] = (byte)(VersionNumber & 0b00111110); 70 | if (CurrentNextIndicator) data[5] += 0b00000001; 71 | data[6] = SectionNumber; 72 | data[7] = LastSectionNumber; 73 | data[8] = (byte)((PcrPid >> 8) & 0b00011111); 74 | data[9] = (byte)(PcrPid & 0xFF); 75 | data[10] = (byte)((ProgramInfoLength >> 8) & 0b00000011); 76 | data[11] = (byte)(ProgramInfoLength & 0xFF); 77 | 78 | //TODO: This is a crude 'hop' over space for program descriptors - chaos will ensue if there is actually supposed to be any 79 | var idx = 12 + data[11]; 80 | 81 | //if we have Elementary Streams, add them to this table 82 | if (EsStreams != null) 83 | { 84 | foreach (var esInfo in EsStreams) 85 | { 86 | var esData = esInfo.GetData(); 87 | Buffer.BlockCopy(esData, 0, data, idx, esData.Length); 88 | idx += esData.Length; 89 | } 90 | } 91 | //var idx = 8; 92 | //for (var i = 0; i < ProgramNumbers.Length; i++) 93 | //{ 94 | // data[idx] = (byte)(ProgramNumbers[i] >> 8); 95 | // data[idx + 1] = (byte)(ProgramNumbers[i] & 0xFF); 96 | // data[idx + 2] = (byte)((Pids[i] >> 8) & 0b000111111); 97 | // data[idx + 3] = (byte)(Pids[i] & 0xFF); 98 | // i++; 99 | // idx += 4; 100 | //} 101 | 102 | //TODO: CRC needs calc'ing here 103 | 104 | return data; 105 | } 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Tables/ServiceDescriptionTable.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | using System.Collections.Generic; 17 | using Cinegy.TsDecoder.Descriptors; 18 | 19 | // ReSharper disable UnusedAutoPropertyAccessor.Global 20 | 21 | namespace Cinegy.TsDecoder.Tables 22 | { 23 | 24 | public class ServiceDescriptionTable : Table 25 | { 26 | public ushort TransportStreamId { get; set; } 27 | public byte VersionNumber { get; set; } 28 | public bool CurrentNextIndicator { get; set; } 29 | public byte SectionNumber { get; set; } 30 | public byte LastSectionNumber { get; set; } 31 | public bool ItemsIncomplete { get; set; } = true; 32 | public ushort OriginalNetworkId { get; set; } 33 | public List Items { get; set; } 34 | } 35 | 36 | public class ServiceDescriptionItem 37 | { 38 | public ushort ServiceId; 39 | public bool EitScheduleFlag; 40 | public bool EitPresentFollowingFlag; 41 | public byte RunningStatus; 42 | public bool FreeCaMode; 43 | public ushort DescriptorsLoopLength; 44 | public List Descriptors { get; set; } 45 | public byte DvbDescriptorTag; 46 | public byte DescriptorLength; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Tables/SpliceInfoTable.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | namespace Cinegy.TsDecoder.Tables 17 | { 18 | public class SpliceTime 19 | { 20 | public bool TimeSpecifiedFlag { get; set; } 21 | public ulong PTSTime { get; set; } 22 | public string SpliceTimeString { 23 | get { 24 | var t_stamp = (long)PTSTime; 25 | var hour = (int)(t_stamp / 324000000); 26 | var r = t_stamp % 324000000; 27 | var minute = (int)(r / 5400000); 28 | r = r % 5400000; 29 | var second = (int)(r / 90000); 30 | r = r % 90000; 31 | var millis = (int)(r / 90); 32 | 33 | return $"{hour:D2}:{minute:D2}:{second:D2}.{millis:D2}"; 34 | } 35 | } 36 | } 37 | 38 | public class BreakDuration 39 | { 40 | public bool AutoReturn { get; set; } 41 | public ulong Duration { get; set; } 42 | } 43 | 44 | public interface ISplice 45 | { 46 | 47 | } 48 | 49 | public class SpliceInsert : ISplice 50 | { 51 | public class Component 52 | { 53 | public byte ComponentTag { get; set; } 54 | public SpliceTime SpliceTime { get; set; } 55 | } 56 | 57 | public ulong SpliceEventId { get; set; } 58 | public bool SpliceEventCancelIndicator { get; set; } 59 | public bool OutOfNetworkIndicator { get; set; } 60 | public bool ProgramSpliceFlag { get; set; } 61 | public bool DurationFlag { get; set; } 62 | public bool SpliceImmediateFlag { get; set; } 63 | public SpliceTime SpliceTime { get; set; } 64 | public byte ComponentCount { get; set; } 65 | public System.Collections.Generic.IEnumerable Components { get; set; } 66 | public BreakDuration BreakDuration { get; set; } 67 | public ushort UniqueProgramId { get; set; } 68 | public byte AvailNum { get; set; } 69 | public byte AvailsExpected { get; set; } 70 | } 71 | 72 | public class SpliceInfoTable : Table 73 | { 74 | public byte ProtocolVersion { get; set; } 75 | public bool EncryptedPacket { get; set; } 76 | public byte EncryptionAlgorithm { get; set; } 77 | public ulong PTSAdjustment { get; set; } 78 | public byte CWIndex { get; set; } 79 | public ushort Tier { get; set; } 80 | public ushort SpliceCommandLength { get; set; } 81 | public ushort SpliceCommandType { get; set; } 82 | public ISplice Splice { get; set; } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Tables/Table.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | using System.Collections.Generic; 17 | using Cinegy.TsDecoder.Descriptors; 18 | 19 | namespace Cinegy.TsDecoder.Tables 20 | { 21 | public class Table : ITable 22 | { 23 | public ushort Pid { get; set; } 24 | public byte PointerField { get; set; } 25 | public byte TableId { get; set; } 26 | public ushort SectionLength { get; set; } 27 | public List Descriptors { get; set; } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Tables/TableFactory.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | using System; 17 | using System.Collections.Generic; 18 | using Cinegy.TsDecoder.Descriptors; 19 | using Cinegy.TsDecoder.TransportStream; 20 | 21 | namespace Cinegy.TsDecoder.Tables 22 | { 23 | public class TableFactory 24 | { 25 | private ushort _tableBytes; 26 | internal byte[] Data; 27 | 28 | public int CorruptedPackets { get; internal set; } = 0; 29 | 30 | public int TablePid { get; private set; } = -1; 31 | 32 | protected ITable InProgressTable { get; set; } 33 | 34 | public delegate void TableChangeEventHandler(object sender, TransportStreamEventArgs args); 35 | 36 | public void ResetCounters() 37 | { 38 | CorruptedPackets = 0; 39 | } 40 | 41 | protected int GetDescriptors(byte descriptorsLength, int startOfNextField) 42 | { 43 | var descriptors = new List(); 44 | var startPos = startOfNextField; 45 | while (startOfNextField < startPos + descriptorsLength) 46 | { 47 | if (startOfNextField > Data.Length) 48 | { 49 | return -1; 50 | } 51 | var des = DescriptorFactory.DescriptorFromData(Data, startOfNextField); 52 | descriptors.Add(des); 53 | 54 | startOfNextField += des.DescriptorLength + 2; 55 | } 56 | 57 | InProgressTable.Descriptors = descriptors; 58 | 59 | return startOfNextField; 60 | } 61 | 62 | internal bool HasAllBytes() 63 | { 64 | return _tableBytes >= InProgressTable.SectionLength + 3 && InProgressTable.SectionLength > 0; 65 | } 66 | 67 | internal void CheckPid(int newPid) 68 | { 69 | if (TablePid == newPid) return; 70 | 71 | if (TablePid == -1) 72 | { 73 | TablePid = newPid; 74 | } 75 | else 76 | { 77 | CorruptedPackets++; 78 | #if DEBUG 79 | Console.WriteLine("TableFactory cannot have mixed PIDs added after startup"); 80 | #endif 81 | } 82 | } 83 | 84 | protected void AddData(TsPacket packet) 85 | { 86 | CheckPid(packet.Pid); 87 | 88 | if (packet.PayloadUnitStartIndicator) 89 | { 90 | Data = new byte[InProgressTable.SectionLength + 3]; 91 | _tableBytes = 0; 92 | } 93 | 94 | if (packet.PayloadLen == 0) 95 | { 96 | CorruptedPackets++; 97 | return; 98 | } 99 | 100 | if ((InProgressTable.SectionLength + 3 - _tableBytes) > packet.PayloadLen) 101 | { 102 | Buffer.BlockCopy(packet.Payload, 0, Data, _tableBytes, packet.PayloadLen); 103 | _tableBytes += (ushort)(packet.PayloadLen); 104 | } 105 | else 106 | { 107 | Buffer.BlockCopy(packet.Payload, 0, Data, _tableBytes, (InProgressTable.SectionLength + 3 - _tableBytes)); 108 | _tableBytes += (ushort)(InProgressTable.SectionLength + 3 - _tableBytes); 109 | } 110 | } 111 | 112 | // The associated table has changed / been updated 113 | public event TableChangeEventHandler TableChangeDetected; 114 | 115 | 116 | protected void OnTableChangeDetected() 117 | { 118 | var handler = TableChangeDetected; 119 | if (handler == null) return; 120 | 121 | var generatingPid = -1; 122 | 123 | if (InProgressTable != null) 124 | { 125 | generatingPid = InProgressTable.Pid; 126 | } 127 | 128 | var args = new TransportStreamEventArgs { TsPid = generatingPid }; 129 | handler(this, args); 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/TransportStream/AdaptationField.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | namespace Cinegy.TsDecoder.TransportStream 17 | { 18 | public struct AdaptationField 19 | { 20 | public byte FieldSize; 21 | public bool DiscontinuityIndicator; 22 | public bool RandomAccessIndicator; 23 | public bool ElementaryStreamPriorityIndicator; 24 | public bool PcrFlag; 25 | public bool OpcrFlag; 26 | public bool SplicingPointFlag; 27 | public bool TransportPrivateDataFlag; 28 | public bool AdaptationFieldExtensionFlag; 29 | public ulong Pcr; 30 | public ulong Opcr; 31 | } 32 | 33 | 34 | } 35 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/TransportStream/EsInfo.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | using System; 17 | using System.Collections.Generic; 18 | using System.Linq; 19 | using Cinegy.TsDecoder.Descriptors; 20 | 21 | // ReSharper disable UnusedAutoPropertyAccessor.Global 22 | 23 | namespace Cinegy.TsDecoder.TransportStream 24 | { 25 | public class EsInfo 26 | { 27 | public byte StreamType { get; set; } 28 | 29 | public ushort ElementaryPid { get; set; } 30 | 31 | public ushort EsInfoLength { get; set; } 32 | 33 | public ushort DescriptorsLength { 34 | get 35 | { 36 | var descsLength = 0; 37 | //only serialize RegistrationDescriptors for now 38 | var regDescs = Descriptors.Where(i => i.GetType() == typeof(RegistrationDescriptor)); 39 | 40 | foreach (var esDesc in regDescs) 41 | { 42 | descsLength += (ushort)(2 + esDesc.DescriptorLength); 43 | } 44 | return (ushort)descsLength; 45 | } 46 | } 47 | 48 | public ICollection Descriptors { get; set; } 49 | 50 | public byte[] SourceData { get; set; } 51 | 52 | public byte[] GetData() 53 | { 54 | var dataLength = 5; 55 | var descsLength = DescriptorsLength; 56 | dataLength += descsLength; 57 | 58 | var data = new byte[dataLength]; 59 | var idx = 0; 60 | 61 | data [idx++] = StreamType; 62 | data [idx++] = (byte) ((ElementaryPid >> 8) & 0b00011111); 63 | data[idx++] = (byte) (ElementaryPid & 0xFF); 64 | data[idx++] = (byte)((descsLength >> 8) & 0b00000011); 65 | data[idx++] = (byte)(descsLength & 0xFF); 66 | 67 | var regDescs = Descriptors.Where(i => i.GetType() == typeof(RegistrationDescriptor)); 68 | foreach (var esDesc in regDescs) 69 | { 70 | var registrationDesc = (RegistrationDescriptor)esDesc; 71 | if (registrationDesc != null) 72 | { 73 | var descLength = (ushort)(2 + esDesc.DescriptorLength); 74 | descsLength += descLength; 75 | var descData = registrationDesc.GetData(); 76 | Buffer.BlockCopy(descData, 0, data, idx, descLength); 77 | idx += descLength; 78 | } 79 | } 80 | 81 | return data; 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/TransportStream/OptionalPes.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | // ReSharper disable UnusedAutoPropertyAccessor.Global 17 | 18 | using System; 19 | 20 | namespace Cinegy.TsDecoder.TransportStream 21 | { 22 | public class OptionalPes 23 | { 24 | private int _length = -1; 25 | 26 | public byte MarkerBits { get; set; } // 2 10 binary or 0x2 hex 27 | public byte ScramblingControl { get; set; } // 2 00 implies not scrambled 28 | public bool Priority { get; set; } // 1 29 | public bool DataAlignmentIndicator { get; set; } // 1 1 indicates that the PES packet header is immediately followed by the video start code or audio syncword 30 | public bool Copyright { get; set; } // 1 1 implies copyrighted 31 | public bool OriginalOrCopy { get; set; } // 1 1 implies original 32 | public byte PtsdtsIndicator { get; set; } // 2 11 = both present, 01 is forbidden, 10 = only PTS, 00 = no PTS or DTS 33 | public bool EscrFlag { get; set; } // 1 34 | public bool EsRateFlag { get; set; } // 1 35 | public bool DsmTrickModeFlag { get; set; } // 1 36 | public bool AdditionalCopyInfoFlag { get; set; } // 1 37 | public bool CrcFlag { get; set; } // 1 38 | public bool ExtensionFlag { get; set; } // 1 39 | 40 | public byte PesHeaderLength 41 | { 42 | get 43 | { 44 | //check if this field has been set, and return if it has 45 | if (_length != -1) 46 | { 47 | return (byte)_length; 48 | } 49 | 50 | //the value is unset, so we shall attempt to calculate it from flag presence 51 | var length = 0; 52 | 53 | switch (PtsdtsIndicator) 54 | { 55 | case 0b10: 56 | //5 bytes for just a PTS value 57 | length += 5; 58 | break; 59 | case 0b11: 60 | //10 bytes for both a PTS and DTS 61 | length += 10; 62 | break; 63 | } 64 | 65 | //ESCR is described in 6 bytes 66 | if (EscrFlag) length += 6; 67 | 68 | //ES rate is described in 3 bytes 69 | if (EsRateFlag) length += 3; 70 | 71 | //Dsm trick mode is described in a bye 72 | if(DsmTrickModeFlag) 73 | { 74 | length += 8; 75 | } 76 | 77 | //additional copy info is just a byte 78 | if (AdditionalCopyInfoFlag) length += 1; 79 | 80 | //crc flag as 2 byte description 81 | if (CrcFlag) length += 2; 82 | 83 | //extension flag is not supported - throw an exception if detected 84 | if (ExtensionFlag) 85 | { 86 | throw new NotSupportedException( 87 | "PES Extension Flag set in optional PES header, and this is unsupported for decoding implicit PES lengths"); 88 | } 89 | 90 | if(OptionalFields!=null) length += OptionalFields.Length; 91 | 92 | return (byte)length; 93 | } 94 | set => _length = value; 95 | } 96 | 97 | 98 | public byte[] OptionalFields { get; set; } // variable length presence is determined by flag bits above 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/TransportStream/PesHdr.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | namespace Cinegy.TsDecoder.TransportStream 17 | { 18 | public struct PesHdr 19 | { 20 | public uint StartCode; 21 | public byte StreamId; 22 | public ushort PacketLength; 23 | public long Pts; 24 | public long Dts; 25 | public byte HeaderLength; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/TransportStream/PesStreamTypes.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | namespace Cinegy.TsDecoder.TransportStream 17 | { 18 | public enum PesStreamTypes 19 | { 20 | ProgramStreamMap = 0xBC, 21 | PrivateStream1 = 0xBD, 22 | PaddingStream = 0xBE, 23 | PrivateStream2 = 0xBF, 24 | ECMStream = 0xF0, 25 | EMMStream = 0xF1, 26 | DSMCCStream = 0xF2, 27 | IEC13522Stream = 0xF3, 28 | H2221TypeAStream = 0xF4, 29 | H2221TypeBStream = 0xF5, 30 | H2221TypeCStream = 0xF6, 31 | H2221TypeDStream = 0xF7, 32 | H2221TypeEStream = 0xF8, 33 | AncillaryStream = 0xF9, 34 | IEC144961SLPacketizedStream = 0xFA, 35 | IEC144961FlexMuxStream = 0xFB, 36 | ProgramStreamDirectory = 0xFF 37 | } 38 | 39 | 40 | } 41 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/TransportStream/PidType.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | namespace Cinegy.TsDecoder.TransportStream 17 | { 18 | public enum PidType 19 | { 20 | PatPid = 0x0, 21 | CatPid = 0x1, 22 | TsDescPid = 0x2, 23 | NitPid = 0x10, 24 | SdtBatPid = 0x11, 25 | EitPid = 0x12, 26 | NullPid = 0x1FFF 27 | } 28 | 29 | 30 | } 31 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/TransportStream/TableChangedEventArgs.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | namespace Cinegy.TsDecoder.TransportStream 17 | { 18 | public class TableChangedEventArgs : System.EventArgs 19 | { 20 | public int TablePid { get; set; } 21 | public string Message { get; set; } 22 | public TableType TableType { get; set; } 23 | } 24 | 25 | public enum TableType 26 | { 27 | Undefined, 28 | Pat, 29 | Pmt, 30 | Sdt, 31 | Eit, 32 | Nit, 33 | SdtOther, 34 | Bat 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/TransportStream/Text.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2022 Cinegy GmbH. */ 2 | using System; 3 | using System.Text; 4 | 5 | namespace Cinegy.TsDecoder.TransportStream 6 | { 7 | public class Text 8 | { 9 | private readonly byte[] _characters; 10 | 11 | public string Value => ToString(); 12 | 13 | public Text(Text text) 14 | { 15 | if (text == null) return; 16 | 17 | _characters = new byte[text._characters.Length]; 18 | Buffer.BlockCopy(text._characters, 0, _characters, 0, text._characters.Length); 19 | } 20 | 21 | public Text(byte[] inputChars, int start, int length) 22 | { 23 | if (null == inputChars || inputChars.Length <= start) return; 24 | 25 | if (inputChars.Length <= length + start) 26 | { 27 | length = inputChars.Length - start; 28 | } 29 | 30 | try 31 | { 32 | _characters = new byte[length]; 33 | Buffer.BlockCopy(inputChars, start, _characters, 0, length); 34 | } 35 | catch (Exception ex) 36 | { 37 | System.Diagnostics.Debug.WriteLine("Overflow copying text chars from input - improve bounds checking! Exception: ", ex.Message); 38 | } 39 | } 40 | 41 | public override string ToString() 42 | { 43 | if (_characters.Length == 0) 44 | { 45 | return ""; 46 | } 47 | var ret = new byte[_characters.Length * 2]; //set to twice possible size to prevent repeat CRLF char doubles overflowing 48 | var char0 = _characters[0]; 49 | ushort start; 50 | var characterTable = "ISO-8859-1"; 51 | var ii = 0; 52 | if (_characters[0] >= 0x20 && _characters[0] <= 0xFF) 53 | { 54 | start = 0; 55 | } 56 | else 57 | { 58 | start = 1; 59 | 60 | switch (char0) 61 | { 62 | case 0x01: characterTable = "ISO-8859-5"; break; 63 | case 0x02: characterTable = "ISO-8859-6"; break; 64 | case 0x03: characterTable = "ISO-8859-7"; break; 65 | case 0x04: characterTable = "ISO-8859-8"; break; 66 | case 0x05: characterTable = "ISO-8859-9"; break; 67 | case 0x06: characterTable = "ISO-8859-10"; break; 68 | case 0x07: characterTable = "ISO-8859-11"; break; 69 | case 0x09: characterTable = "ISO-8859-13"; break; 70 | case 0x0A: characterTable = "ISO-8859-14"; break; 71 | case 0x0B: characterTable = "ISO-8859-15"; break; 72 | case 0x10: characterTable = "ISO-8859"; break; 73 | case 0x11: characterTable = "ISO-10646"; break; 74 | case 0x12: characterTable = "KSX1001-2004"; break; 75 | case 0x13: characterTable = "GB-2312-1980"; break; 76 | case 0x14: characterTable = "Big5"; break; 77 | case 0x15: characterTable = "UTF-8 "; break; 78 | } 79 | } 80 | 81 | for (int i = start; i < _characters.Length; i++) 82 | { 83 | var character = _characters[i]; 84 | if (character >= 0x80 && character <= 0x9F) 85 | { 86 | switch (character) 87 | { 88 | case 0x80: break; 89 | case 0x81: break; 90 | case 0x82: break; 91 | case 0x83: break; 92 | case 0x84: break; 93 | case 0x85: break; 94 | case 0x86: break; 95 | case 0x87: break; 96 | case 0x88: break; 97 | case 0x8A: ret[ii++] = 10; ret[ii++] = 13; break; 98 | case 0x8B: break; 99 | case 0x8C: break; 100 | case 0x8D: break; 101 | case 0x8E: break; 102 | case 0x8F: break; 103 | // ReSharper disable once RedundantEmptyDefaultSwitchBranch 104 | default: break; 105 | } 106 | } 107 | else if (character != 0) 108 | { 109 | ret[ii++] = character; 110 | } 111 | } 112 | 113 | var result = Encoding.GetEncoding(characterTable).GetString(Encoding.Convert(Encoding.GetEncoding(characterTable), Encoding.GetEncoding(characterTable), ret)).Substring(0, ii); 114 | return result; 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/TransportStream/TransportStreamEventArgs.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | namespace Cinegy.TsDecoder.TransportStream 17 | { 18 | public class TransportStreamEventArgs : System.EventArgs 19 | { 20 | public int TsPid { get; set; } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/TransportStream/TsPacket.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | namespace Cinegy.TsDecoder.TransportStream 17 | { 18 | 19 | public struct TsPacket 20 | { 21 | public byte SyncByte; //should always be 0x47 - indicates start of a TS packet 22 | public bool TransportErrorIndicator; //Set when a demodulator can't correct errors from FEC data - this would inform a stream processor to ignore the packet 23 | public bool PayloadUnitStartIndicator; //true = the start of PES data or PSI otherwise zero only. 24 | public bool TransportPriority; //true = the current packet has a higher priority than other packets with the same PID. 25 | public ushort Pid; //Packet identifier flag, used to associate one packet with a set 26 | public byte ScramblingControl; // '00' = Not scrambled, For DVB-CSA only:'01' = Reserved for future use, '10' = Scrambled with even key, '11' = Scrambled with odd key 27 | public bool AdaptationFieldExists; // Combined with Contains Payload flag - '00' = Reserved, '01' = Payload only, '10' = Adaptation field only, '11' = Adaptation field and payload 28 | public bool ContainsPayload; 29 | public byte ContinuityCounter; 30 | public PesHdr PesHeader; 31 | public byte[] Payload; 32 | public int PayloadLen; //length of valid data within Payload field (source data array may be oversized if rented) 33 | public AdaptationField AdaptationField; 34 | public byte[] SourceData; //original data used to construct packet (if chosen to retain) 35 | public int SourceDataLen; //length of valid data within SourceData field (source data array may be oversized if rented) 36 | public int SourceBufferIndex; //index into original data buffer used to construct packet 37 | } 38 | 39 | 40 | } 41 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/TransportStream/Utils.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | using System.Text; 17 | 18 | namespace Cinegy.TsDecoder.TransportStream 19 | { 20 | internal static class Utils 21 | { 22 | public static int ConvertBCDToInt(byte[] byteData, int index, int count) 23 | { 24 | var result = 0; 25 | var shift = 4; 26 | 27 | for (var nibbleIndex = 0; nibbleIndex < count; nibbleIndex++) 28 | { 29 | result = (result * 10) + ((byteData[index] >> shift) & 0x0f); 30 | 31 | if (shift == 4) 32 | shift = 0; 33 | else 34 | { 35 | shift = 4; 36 | index++; 37 | } 38 | } 39 | 40 | return result; 41 | } 42 | 43 | public static string ToHexString(this byte[] hex) 44 | { 45 | if (hex == null) return null; 46 | if (hex.Length == 0) return string.Empty; 47 | 48 | var s = new StringBuilder(); 49 | foreach (var b in hex) 50 | { 51 | s.Append(b.ToString("x2")); 52 | } 53 | return s.ToString(); 54 | } 55 | 56 | public static ushort Convert2BytesToUshort(byte[] buffer, int offset) 57 | { 58 | return (ushort)((buffer[offset] << 8) + buffer[offset + 1]); 59 | } 60 | 61 | public static uint Convert3BytesToUint(byte[] buffer, int offset) 62 | { 63 | return (uint)((buffer[offset] << 16) + (buffer[offset + 1] << 8) + buffer[offset + 2]); 64 | } 65 | 66 | public static uint Convert4BytesToUint(byte[] buffer, int offset) 67 | { 68 | return (uint)((buffer[offset] << 24) + (buffer[offset+1] << 16) + (buffer[offset + 2] << 8) + buffer[offset + 3]); 69 | } 70 | 71 | public static long Convert8BytesToLong(byte[] buffer, int offset) 72 | { 73 | long temp = 0; 74 | 75 | for (var index = 0; index < 8; index++) 76 | temp = (temp << 8) + buffer[offset + index]; 77 | 78 | return temp; 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Video/H264BitReader.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2016-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | using System; 17 | using Cinegy.TsDecoder.DataAccess; 18 | 19 | namespace Cinegy.TsDecoder.Video; 20 | 21 | public class H264BitReader : BitReader 22 | { 23 | public H264BitReader(byte[] buf) : base(buf) 24 | { 25 | } 26 | 27 | public uint Get_UE() 28 | { 29 | var leadingZeroBits = 0; 30 | 31 | while (Get_Bits(1) == 0) 32 | leadingZeroBits++; 33 | 34 | return leadingZeroBits == 0 ? 0 : (1u << leadingZeroBits) - 1 + Get_Bits(leadingZeroBits); 35 | } 36 | 37 | public int Get_SE() 38 | { 39 | var val = Get_UE(); 40 | //return val == 0 ? 0 : (int)((val + 1) >> 1) * ((val & 1) != 0 ? 1 : -1); 41 | var sign = (val & 1) - 1; 42 | return val == 0 ? 0 : (int)((((val + 1) >> 1) ^ sign) - sign); 43 | } 44 | 45 | public uint FindStartCode() 46 | { 47 | Align(); 48 | 49 | for (;;) 50 | { 51 | if (BitsLeft < 32) 52 | return 0; 53 | 54 | var code = Show_Bits32_Aligned(); 55 | 56 | if (((code ^ ~(code + 0x7efefeff)) & 0x81010100) != 0) 57 | { 58 | if ((code & 0xFFFFFF00) == 0x00000100) 59 | return code; 60 | 61 | if (code == 0x00000001) 62 | { 63 | Flush_Bits(8); 64 | code = Show_Bits32_Aligned(); 65 | Unget_Bits(8); 66 | return code; 67 | } 68 | 69 | Flush_Bits(8); // going slow 70 | continue; 71 | } 72 | 73 | Flush_Bits(32); 74 | } 75 | } 76 | 77 | public int SkipStartCode() 78 | { 79 | if (!IsAligned()) 80 | return 0; 81 | 82 | var code = Show_Bits32_Aligned(); 83 | 84 | if ((code & 0xFFFFFF00) == 0x00000100) 85 | { 86 | Flush_Bits(32); 87 | return 32; 88 | } 89 | 90 | if (code == 0x00000001) 91 | { 92 | Flush_Bits(40); 93 | return 40; 94 | } 95 | 96 | return 0; 97 | } 98 | 99 | public bool RBSP_Trailing_Bits() 100 | { 101 | if (BitsLeft <= 0) 102 | return false; 103 | 104 | var rbsp_stop_bit = Get_Bits(1); 105 | //int rbsp_alignment_zero_bits = Show_Bits(BitsToAlign()); 106 | var rbsp_zero_bits = Show_Bits(Math.Min(23, BitsLeft)); // aligning_bits + next_start_code_bits 107 | 108 | Unget_Bits(1); 109 | 110 | return rbsp_stop_bit == 1 && rbsp_zero_bits == 0; 111 | } 112 | 113 | public bool More_RBSP_Data() 114 | { 115 | if (BitsLeft <= 0) 116 | return false; 117 | 118 | return !RBSP_Trailing_Bits(); 119 | } 120 | } -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Video/H264BitWriter.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2016-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | using Cinegy.TsDecoder.DataAccess; 17 | 18 | namespace Cinegy.TsDecoder.Video; 19 | 20 | public class H264BitWriter : BitWriter 21 | { 22 | public H264BitWriter(byte[] buf) : base(buf) 23 | { 24 | } 25 | 26 | protected override void Write_Byte(byte val) 27 | { 28 | if (val <= 1 && BytePos >= 2 && Buffer[BytePos - 1] == 0 && Buffer[BytePos - 2] == 0) 29 | Buffer[BytePos++] = 03; 30 | 31 | Buffer[BytePos++] = val; 32 | } 33 | 34 | public void Put_StartCode(int len) 35 | { 36 | Align(); 37 | 38 | for (var i = 0; i < len - 1; i++) 39 | base.Write_Byte(0); 40 | 41 | base.Write_Byte(1); 42 | } 43 | 44 | public void Put_UE(uint val) 45 | { 46 | if (val == 0) 47 | { 48 | Put_Bits(1, 1); 49 | return; 50 | } 51 | 52 | val += 1; 53 | var lsbPos = __bsr(val); 54 | 55 | Put_Bits(val, lsbPos * 2 + 1); 56 | } 57 | 58 | public void Put_SE(int val) 59 | { 60 | if (val > 0) 61 | Put_UE((uint)(val * 2 - 1)); 62 | else 63 | Put_UE((uint)(-val * 2)); 64 | } 65 | 66 | #if true 67 | private static int __bsr(uint v) 68 | { 69 | var r = 0; 70 | while ((v >>= 1) != 0) 71 | { 72 | r++; 73 | } 74 | return r; 75 | } 76 | #else 77 | private uint LeadingZeros(uint x) 78 | { 79 | x |= (x >> 1); 80 | x |= (x >> 2); 81 | x |= (x >> 4); 82 | x |= (x >> 8); 83 | x |= (x >> 16); 84 | return (sizeof(int) * 8 - Ones(x)); 85 | } 86 | private uint Ones(uint x) 87 | { 88 | x -= ((x >> 1) & 0x55555555); 89 | x = (((x >> 2) & 0x33333333) + (x & 0x33333333)); 90 | x = (((x >> 4) + x) & 0x0f0f0f0f); 91 | x += (x >> 8); 92 | x += (x >> 16); 93 | return (x & 0x0000003f); 94 | } 95 | #endif 96 | } -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Video/H264HrdParams.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2017-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | using System.Runtime.InteropServices; 17 | 18 | namespace Cinegy.TsDecoder.Video 19 | { 20 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 21 | public unsafe struct H264HrdParams 22 | { 23 | public bool present_flag; 24 | public byte cpb_cnt; 25 | public byte bit_rate_scale; 26 | public byte cpb_size_scale; 27 | public fixed uint bit_rate_value[32]; 28 | public fixed uint cpb_size_value[32]; 29 | public fixed bool cbr_flag[32]; 30 | public byte initial_cpb_removal_delay_length; 31 | public byte cpb_removal_delay_length; 32 | public byte dpb_output_delay_length; 33 | public byte time_offset_length; 34 | 35 | public void Read(ref H264BitReader br) 36 | { 37 | present_flag = br.Get_Bool(); 38 | 39 | if (!present_flag) 40 | return; 41 | 42 | cpb_cnt = (byte)(br.Get_UE() + 1); 43 | bit_rate_scale = (byte)br.Get_Bits(4); 44 | cpb_size_scale = (byte)br.Get_Bits(4); 45 | 46 | for (var idx = 0; idx < cpb_cnt; idx++) 47 | { 48 | bit_rate_value[idx] = br.Get_UE() + 1; 49 | cpb_size_value[idx] = br.Get_UE() + 1; 50 | cbr_flag[idx] = br.Get_Bool(); 51 | } 52 | 53 | initial_cpb_removal_delay_length = (byte)(br.Get_Bits(5) + 1); 54 | cpb_removal_delay_length = (byte)(br.Get_Bits(5) + 1); 55 | dpb_output_delay_length = (byte)(br.Get_Bits(5) + 1); 56 | time_offset_length = (byte)br.Get_Bits(5); 57 | } 58 | 59 | public void Write(ref H264BitWriter bw) 60 | { 61 | bw.Put_Bool(present_flag); 62 | 63 | if (!present_flag) 64 | return; 65 | 66 | bw.Put_UE(cpb_cnt - 1u); 67 | bw.Put_Bits(bit_rate_scale, 4); 68 | bw.Put_Bits(cpb_size_scale, 4); 69 | 70 | for (var idx = 0; idx < cpb_cnt; idx++) 71 | { 72 | bw.Put_UE(bit_rate_value[idx] - 1); 73 | bw.Put_UE(cpb_size_value[idx] - 1); 74 | bw.Put_Bool(cbr_flag[idx]); 75 | } 76 | 77 | bw.Put_Bits(initial_cpb_removal_delay_length - 1u, 5); 78 | bw.Put_Bits(cpb_removal_delay_length - 1u, 5); 79 | bw.Put_Bits(dpb_output_delay_length - 1u, 5); 80 | bw.Put_Bits(time_offset_length, 5); 81 | } 82 | } 83 | } 84 | 85 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Video/H264NalUnitFactory.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2016-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | using System.Collections.Generic; 17 | using Cinegy.TsDecoder.TransportStream; 18 | 19 | namespace Cinegy.TsDecoder.Video 20 | { 21 | //public class H264NalUnitFactory 22 | //{ 23 | // public void AddPes(Pes pes, PesHdr tsPacketPesHeader) 24 | // { 25 | // if (pes.PacketStartCodePrefix != Pes.DefaultPacketStartCodePrefix) return; 26 | 27 | // var startOfData = 6; 28 | 29 | // if (pes.OptionalPesHeader?.MarkerBits == 2) //optional PES header exists - minimum length is 3 30 | // { 31 | // startOfData += (ushort)(3 + pes.OptionalPesHeader.PesHeaderLength); 32 | // } 33 | 34 | // var dataBufSize = pes.Data.Length - startOfData; 35 | 36 | // var entities = GetEntitiesFromData(pes.Data[startOfData..], dataBufSize); 37 | 38 | // OnVideoReady(entities); 39 | // } 40 | 41 | // public static List GetEntitiesFromData(byte[] sourceData, int dataLen) 42 | // { 43 | // var videoEntities = new List(); 44 | // var sourceDataPos = 0; 45 | // while (sourceDataPos < dataLen) 46 | // { 47 | // var nalUnit = new H264NalUnit(sourceData, sourceDataPos, dataLen); 48 | // sourceDataPos += nalUnit.ReadBytes; 49 | // videoEntities.Add(nalUnit); 50 | // } 51 | 52 | // return videoEntities; 53 | // } 54 | 55 | // public event NalUnitsReadyEventHandler NalUnitsReady; 56 | 57 | // private void OnVideoReady(List nalUnits) 58 | // { 59 | // NalUnitsReady?.Invoke(this, new NalUnitReadyEventArgs(nalUnits)); 60 | // } 61 | //} 62 | } 63 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Video/H264NalUnitType.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2016-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | namespace Cinegy.TsDecoder.Video; 17 | 18 | public enum H264NalUnitType 19 | { 20 | Unspecified = 0, 21 | CodedSliceNonIdrPicture = 1, 22 | CodedSliceDataPartitionA = 2, 23 | CodedSliceDataPartitionB= 3, 24 | CodedSliceDataPartitionC = 4, 25 | CodedSliceIdrPictureSlice = 5, 26 | SupplementalEnhancementInfo = 6, 27 | SequenceParameterSet = 7, 28 | PictureParameterSet = 8, 29 | AccessUnit = 9, 30 | EndOfSequence = 10, 31 | EndOfStream = 11, 32 | Filler = 12, 33 | SpsExtension = 13, 34 | PrefixNalUnit = 14, 35 | SubsetSps = 15, 36 | DepthParameterSet = 16, 37 | Reserved17 = 17, 38 | Reserved18 = 18, 39 | CodedSliceAuxCodedPicture = 19, 40 | CodedSliceExtension = 20, 41 | CodedSliceExtensionDepthViewComponent = 21, 42 | Reserved22 = 22, 43 | Reserved23 = 23, 44 | Reserved24 = 24, 45 | Unspecified25 = 25, 46 | Unspecified26 = 26, 47 | Unspecified27 = 27, 48 | Unspecified28 = 28, 49 | Unspecified29 = 29, 50 | Unspecified30 = 30, 51 | Unspecified31 = 31 52 | } -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Video/H265NalUnit.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2016-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | using System.IO; 17 | 18 | namespace Cinegy.TsDecoder.Video 19 | { 20 | public class H265NalUnit : NalUnit 21 | { 22 | public uint RefIdc; 23 | public bool SvcExtensionFlag; 24 | public bool AvcVideoDescriptor3dExtensionFlag; 25 | public int UnitType; 26 | public byte[] RbspData; 27 | 28 | public H265NalUnit() 29 | { 30 | } 31 | 32 | public H265NalUnit(byte[] data, int offset, int length) 33 | { 34 | Init(data, offset, length); 35 | } 36 | 37 | public sealed override void Init(byte[] data, int offset, int length) 38 | { 39 | var nalUnitStart = FindNalUnit(data[..length], offset, out var nalUnitLength); 40 | var dataPos = nalUnitStart; 41 | UnitType = (int)(data[dataPos] & 0b01111110)>>1; 42 | dataPos+=2; 43 | var numBytesInRbsp = 0; 44 | 45 | RbspData = new byte[nalUnitLength - 2]; 46 | for (var i = 2; i < nalUnitLength; i++) 47 | { 48 | if (i + 2 < nalUnitLength && data[dataPos] == 0 && data[dataPos + 1] == 0 && data[dataPos + 2] == 0x3) 49 | { 50 | RbspData[numBytesInRbsp++] = data[dataPos++]; 51 | RbspData[numBytesInRbsp++] = data[dataPos++]; 52 | dataPos++; 53 | i += 2; 54 | } 55 | else 56 | { 57 | RbspData[numBytesInRbsp++] = data[dataPos++]; 58 | } 59 | } 60 | 61 | NalUnitSize = nalUnitLength; 62 | ReadBytes = dataPos - offset; 63 | } 64 | 65 | private int FindNalUnit(byte[] data, int offset, out int length) 66 | { 67 | var dataPos = offset; 68 | length = 0; 69 | 70 | //check we have entered the function at a NAL unit start 71 | if (data[dataPos] == 0 && data[dataPos+1] == 0 && data[dataPos+2] == 1) 72 | { 73 | dataPos += 3; 74 | //start code is 001 75 | } 76 | else if (data[dataPos] == 0 && data[dataPos+1] == 0 && data[dataPos+2] == 0 && data[dataPos+3] == 1) 77 | { 78 | dataPos += 4; 79 | //start code is 0001 80 | } 81 | else 82 | { 83 | //corrupt data 84 | //TODO: Don't except here, since corruption in stream will trigger exception storm and kill things... 85 | throw new InvalidDataException("Could not find start code in NAL unit data"); 86 | } 87 | 88 | if ((data[dataPos] & 0b10000000) != 0) 89 | { 90 | //TODO: Don't except here, since corruption in stream will trigger exception storm and kill things... 91 | throw new InvalidDataException("NAL unit forbidden zero bit is not zero"); 92 | } 93 | 94 | //set the start position to after the 3-byte start code (Table 7.3.1 shows the NAL unit defined exclusive of a start code) 95 | var startPosition = dataPos; 96 | 97 | while (dataPos + 3 < data.Length) 98 | { 99 | if (data[dataPos] == 0 && data[dataPos + 1] == 0 && data[dataPos + 2] == 1) 100 | { 101 | break; 102 | //encountered next start code - trailing start codes are always only 001 as prior zeros are considered 'trailing zero 8 bits' at end of last NAL 103 | } 104 | else 105 | { 106 | dataPos++; 107 | } 108 | } 109 | 110 | if (dataPos + 3 == data.Length) 111 | { 112 | dataPos += 3; 113 | } 114 | 115 | length = dataPos - startPosition; 116 | return startPosition; 117 | } 118 | } 119 | } -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Video/H265NalUnitType.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2016-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | namespace Cinegy.TsDecoder.Video; 17 | 18 | public enum H265NalUnitType 19 | { 20 | Unspecified = 0, 21 | CodedSliceNonIdrPicture = 1, 22 | CodedSliceDataPartitionA = 2, 23 | CodedSliceDataPartitionB= 3, 24 | CodedSliceDataPartitionC = 4, 25 | CodedSliceIdrPictureSlice = 5, 26 | SupplementalEnhancementInfo = 6, 27 | SequenceParameterSet = 7, 28 | PictureParameterSet = 8, 29 | AccessUnit = 9, 30 | EndOfSequence = 10, 31 | EndOfStream = 11, 32 | Filler = 12, 33 | SpsExtension = 13, 34 | PrefixNalUnit = 14, 35 | SubsetSps = 15, 36 | DepthParameterSet = 16, 37 | Reserved17 = 17, 38 | Reserved18 = 18, 39 | CodedSliceAuxCodedPicture = 19, 40 | CodedSliceExtension = 20, 41 | CodedSliceExtensionDepthViewComponent = 21, 42 | Reserved22 = 22, 43 | Reserved23 = 23, 44 | Reserved24 = 24, 45 | Unspecified25 = 25, 46 | Unspecified26 = 26, 47 | Unspecified27 = 27, 48 | Unspecified28 = 28, 49 | Unspecified29 = 29, 50 | Unspecified30 = 30, 51 | Unspecified31 = 31 52 | } -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Video/INalUnit.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2016-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | namespace Cinegy.TsDecoder.Video 17 | { 18 | public interface INalUnit 19 | { 20 | void Init(byte[] sourceData, int offset, int length); 21 | int NalUnitSize { get; } 22 | int ReadBytes { get; } 23 | } 24 | } -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Video/NalUnit.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2016-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | using System.Text.Json.Serialization; 17 | 18 | namespace Cinegy.TsDecoder.Video; 19 | 20 | public abstract class NalUnit : INalUnit 21 | { 22 | public abstract void Init(byte[] sourceData, int offset, int length); 23 | 24 | public int NalUnitSize { get; internal set; } 25 | 26 | [JsonIgnore] 27 | public int ReadBytes { get; internal set; } 28 | 29 | } -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Video/NalUnitFactory.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2016-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | using System; 17 | using System.Collections.Generic; 18 | using Cinegy.TsDecoder.TransportStream; 19 | 20 | namespace Cinegy.TsDecoder.Video 21 | { 22 | public class NalUnitFactory 23 | { 24 | 25 | public void AddPes(Pes pes, PesHdr tsPacketPesHeader, ushort streamType) 26 | { 27 | if (pes.PacketStartCodePrefix != Pes.DefaultPacketStartCodePrefix) return; 28 | 29 | var startOfData = 6; 30 | 31 | if (pes.OptionalPesHeader?.MarkerBits == 2) //optional PES header exists - minimum length is 3 32 | { 33 | startOfData += (ushort)(3 + pes.OptionalPesHeader.PesHeaderLength); 34 | } 35 | 36 | var dataBufSize = pes.Data.Length - startOfData; 37 | 38 | List entities = null; 39 | if (streamType == 0x1b) 40 | { 41 | entities = GetEntitiesFromData(pes.Data[startOfData..], dataBufSize); 42 | } 43 | else if (streamType == 0x24) 44 | { 45 | entities = GetEntitiesFromData(pes.Data[startOfData..], dataBufSize); 46 | } 47 | 48 | OnVideoReady(entities); 49 | } 50 | 51 | public static List GetEntitiesFromData(byte[] sourceData, int dataLen) where T : INalUnit, new() 52 | { 53 | var videoEntities = new List(); 54 | var sourceDataPos = 0; 55 | 56 | while (sourceDataPos < dataLen) 57 | { 58 | var nalUnit = new T(); 59 | nalUnit.Init(sourceData, sourceDataPos, dataLen); 60 | sourceDataPos += nalUnit.ReadBytes; 61 | videoEntities.Add(nalUnit); 62 | } 63 | 64 | return videoEntities; 65 | } 66 | 67 | public event NalUnitsReadyEventHandler NalUnitsReady; 68 | 69 | private void OnVideoReady(List nalUnits) 70 | { 71 | NalUnitsReady?.Invoke(this, new NalUnitReadyEventArgs(nalUnits)); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Video/NalUnitReadyEventArgs.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2016-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | using System; 17 | using System.Collections.Generic; 18 | 19 | namespace Cinegy.TsDecoder.Video; 20 | 21 | public delegate void NalUnitsReadyEventHandler(object sender, NalUnitReadyEventArgs args); 22 | 23 | public class NalUnitReadyEventArgs : EventArgs 24 | { 25 | public List NalUnits { get; set; } 26 | 27 | public NalUnitReadyEventArgs(List units) 28 | { 29 | NalUnits = units; 30 | } 31 | } -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Video/RbspBitReader.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2016-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | using System; 17 | using Cinegy.TsDecoder.DataAccess; 18 | 19 | namespace Cinegy.TsDecoder.Video; 20 | 21 | public class RbspBitReader : BitReader 22 | { 23 | //public byte[] RbspData { get; private set; } 24 | 25 | public RbspBitReader(byte[] buf) : base(buf) 26 | { 27 | //RbspData = new byte[buf.Length]; 28 | //var bw = new BitWriter(RbspData); 29 | //while (More_RBSP_Data()) 30 | //{ 31 | // bw.Put_Bool(Get_Bool()); 32 | //} 33 | } 34 | 35 | public bool RBSP_Trailing_Bits() 36 | { 37 | if (BitsLeft <= 0) 38 | return false; 39 | 40 | var rbsp_stop_bit = Get_Bits(1); 41 | //int rbsp_alignment_zero_bits = Show_Bits(BitsToAlign()); 42 | var rbsp_zero_bits = Show_Bits(Math.Min(23, BitsLeft)); // aligning_bits + next_start_code_bits 43 | 44 | Unget_Bits(1); 45 | 46 | return rbsp_stop_bit == 1 && rbsp_zero_bits == 0; 47 | } 48 | 49 | public bool More_RBSP_Data() 50 | { 51 | if (BitsLeft <= 0) 52 | return false; 53 | 54 | return !RBSP_Trailing_Bits(); 55 | } 56 | } -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Video/SeiMessage.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2016-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | using System; 17 | using System.Data; 18 | using System.IO; 19 | using Cinegy.TsDecoder.DataAccess; 20 | 21 | namespace Cinegy.TsDecoder.Video; 22 | 23 | public struct SeiMessage 24 | { 25 | public uint Type { get; set; } 26 | 27 | public uint PayloadSize { get; set; } 28 | 29 | public byte[] Payload { get; set; } 30 | 31 | public void Init(RbspBitReader bitReader) 32 | { 33 | byte currentByte = 0xFF; 34 | while (currentByte == 0xFF) 35 | { 36 | currentByte = (byte)bitReader.Get_Bits(8); 37 | Type += currentByte; 38 | } 39 | 40 | currentByte = 0xFF; 41 | while (currentByte == 0xFF) 42 | { 43 | currentByte = (byte)bitReader.Get_Bits(8); 44 | PayloadSize += currentByte; 45 | } 46 | 47 | Payload = new byte[PayloadSize]; 48 | 49 | for(var i = 0; i < PayloadSize; i++){ 50 | Payload[i] = (byte)bitReader.Get_Bits(8); 51 | } 52 | } 53 | 54 | public void Init(byte[] data, int offset, int length) 55 | { 56 | var dataPos = offset; 57 | var dataEndPos = offset + length; 58 | 59 | byte currentByte = 0xFF; 60 | while (currentByte == 0xFF) 61 | { 62 | if (dataPos >= dataEndPos) 63 | { 64 | throw new InvalidDataException( 65 | "Corrupted SEI message buffer - attempted to read SEI type past end of buffer"); 66 | } 67 | 68 | currentByte = data[dataPos++]; 69 | Type += currentByte; 70 | } 71 | 72 | currentByte = 0xFF; 73 | while (currentByte == 0xFF) 74 | { 75 | if (dataPos >= dataEndPos) 76 | { 77 | throw new InvalidDataException( 78 | "Corrupted SEI message buffer - attempted to read SEI payload size past end of buffer"); 79 | } 80 | currentByte = data[dataPos++]; 81 | PayloadSize += currentByte; 82 | } 83 | 84 | if (dataPos + PayloadSize != dataEndPos) 85 | { 86 | throw new InvalidDataException( 87 | "Corrupted SEI message buffer - payload size indicated does not fit final extent of data buffer provided"); 88 | } 89 | 90 | Buffer.BlockCopy(data[dataPos..dataEndPos],0,Payload,0,(int)PayloadSize); 91 | } 92 | 93 | } -------------------------------------------------------------------------------- /Cinegy.TsDecoder/Video/VideoTsService.cs: -------------------------------------------------------------------------------- 1 | /* Copyright 2016-2023 Cinegy GmbH. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | using System.Collections.Generic; 17 | using Cinegy.TsDecoder.Descriptors; 18 | using Cinegy.TsDecoder.TransportStream; 19 | 20 | namespace Cinegy.TsDecoder.Video 21 | { 22 | public class VideoTsService 23 | { 24 | private readonly NalUnitFactory _nalUnitFactory; 25 | 26 | public VideoTsService() 27 | { 28 | _nalUnitFactory = new NalUnitFactory(); 29 | _nalUnitFactory.NalUnitsReady += NalUnitFactoryOnNalUnitsReady; 30 | } 31 | 32 | private void NalUnitFactoryOnNalUnitsReady(object sender, NalUnitReadyEventArgs args) 33 | { 34 | OnVideoNalUnitsReady?.Invoke(this, args); 35 | } 36 | 37 | /// 38 | /// Reference PTS, used to calculate and display relative time offsets for data within stream 39 | /// 40 | public long ReferencePts { get; set; } 41 | 42 | /// 43 | /// The TS Packet ID that has been selected as the elementary stream containing KLV data 44 | /// 45 | public ushort? VideoPid { get; set; } = null; 46 | 47 | /// 48 | /// The Program Number ID to which the selected KLV PID belongs, if any 49 | /// 50 | public ushort ProgramNumber { get; set; } = 0; 51 | 52 | /// 53 | /// The associated Descriptor for the service, if any 54 | /// 55 | public Descriptor AssociatedDescriptor { get; set; } 56 | 57 | public void AddData(Pes pes, PesHdr tsPacketPesHeader, ushort streamType) 58 | { 59 | //update / store any reference PTS for displaying easy relative values 60 | if (ReferencePts == 0) ReferencePts = tsPacketPesHeader.Pts; 61 | if (ReferencePts > 0 && tsPacketPesHeader.Pts < ReferencePts) ReferencePts = tsPacketPesHeader.Pts; 62 | _nalUnitFactory.AddPes(pes, tsPacketPesHeader, streamType); 63 | } 64 | 65 | public event NalUnitsReadyEventHandler OnVideoNalUnitsReady; 66 | 67 | internal virtual void OnVideoEntitiesReady(List nalUnits) 68 | { 69 | OnVideoNalUnitsReady?.Invoke(this, new NalUnitReadyEventArgs(nalUnits)); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # Cinegy Transport Stream Decoder Library 2 | 3 | Use this library to decode MPEGTS (including DVB) transport streams - tested with various streams, from Multicast and File sources, with single- and multi-program streams. 4 | 5 | ## How easy is it? 6 | 7 | Assuming you have some data from a source as a byte array (e.g. from a UDP packet or from a file), just add them to the decoder! 8 | 9 | ``` 10 | _tsDecoder.AddData(byteArrayData); 11 | 12 | ``` 13 | 14 | Once you start feeding in packets, the class will start to populate with data - allowing you to explore the Program Allocation Table, Service Descriptors, or even start grabbing the data from an individual elementary stream. 15 | 16 | See all of this in action inside the Cinegy TS Analyser tool here: [GitHub] [https://github.com/cinegy/tsanalyser] 17 | 18 | ## Getting the library 19 | 20 | Just to make your life easier, we auto-build this using AppVeyor and push to NuGet - here is how we are doing right now: 21 | 22 | [![Build status](https://ci.appveyor.com/api/projects/status/mmqiy7vr5f01lhcx?svg=true)](https://ci.appveyor.com/project/cinegy/tsdecoder) 23 | 24 | You can check out the latest compiled binary from the master or pre-master code here: 25 | 26 | [AppVeyor TsDecoder Project Builder](https://ci.appveyor.com/project/cinegy/tsdecoder/build/artifacts) 27 | 28 | Available on NuGet here: 29 | 30 | [NuGet](https://www.nuget.org/packages/Cinegy.TsDecoder/) 31 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 4.0.{build}-alpha 2 | branches: 3 | only: 4 | - master 5 | image: Visual Studio 2022 6 | configuration: Release 7 | dotnet_csproj: 8 | patch: true 9 | file: '**\*.csproj' 10 | version: '{version}' 11 | package_version: '{version}' 12 | assembly_version: '{version}' 13 | file_version: '{version}' 14 | informational_version: '{version}' 15 | build: 16 | project: Cinegy.TsDecoder.sln 17 | publish_nuget: true 18 | verbosity: minimal 19 | before_build: 20 | - cmd: nuget restore 21 | after_build: 22 | - cmd: >- 23 | 7z a Cinegy.TsDecoder-%APPVEYOR_REPO_BRANCH%-%APPVEYOR_BUILD_VERSION%-PDB.zip %APPVEYOR_BUILD_FOLDER%\Cinegy.TsDecoder\bin 24 | 25 | appveyor PushArtifact Cinegy.TsDecoder-%APPVEYOR_REPO_BRANCH%-%APPVEYOR_BUILD_VERSION%-PDB.zip 26 | # deploy: 27 | # - provider: NuGet 28 | # api_key: 29 | # secure: H2zueAN/L9RNQugcZ31Qbc0e9T62ipvbiH61y2IXCjYOL3lebABxDpl8kh9dosN1 30 | # skip_symbols: true 31 | --------------------------------------------------------------------------------