public Media.Container.Node ReadUnit(TransportStreamUnit.PacketIdentifier name, long offset = 0) { long positionStart = Position; Media.Container.Node result = ReadUnits(offset, Length - offset, name).FirstOrDefault(); Position = positionStart; return(result); }
public static string ToTextualConvention(TransportStreamReader reader, byte[] identifier) { TransportStreamUnit.PacketIdentifier result = TransportStreamUnit.GetPacketIdentifier(identifier, reader.UnitOverhead); if (TransportStreamUnit.IsReserved(result)) { return("Reserved"); } if (TransportStreamUnit.IsDVBMetaData(result)) { return("DVBMetaData"); } if (TransportStreamUnit.IsUserDefined(result)) { return("UserDefined"); } return(result.ToString()); }
internal protected virtual void ParseDescriptionTable(Container.Node node) { int offset = ReadPointerField(node); //Get the table id TransportStreamUnit.TableIdentifier tableId = (TransportStreamUnit.TableIdentifier)node.Data[offset++]; if (tableId != TransportStreamUnit.TableIdentifier.ProgramAssociation) { return; } TransportStreamUnit.PacketIdentifier pcrPid = (TransportStreamUnit.PacketIdentifier)(Common.Binary.ReadU16(node.Data, offset, Common.Binary.IsLittleEndian) & TransportStreamUnit.PacketIdentifierMask); int infoLength = Common.Binary.ReadU16(node.Data, ref offset, Common.Binary.IsLittleEndian) & 0x0FFF; //Determine where to end (don't count the crc) int end = (infoLength + 3) - 4; while (offset < end) { byte esType = node.Data[offset++]; //Could store two bytes and have methods to extract with masks. TransportStreamUnit.PacketIdentifier esPid = (TransportStreamUnit.PacketIdentifier)(Common.Binary.ReadU16(node.Data, offset, Common.Binary.IsLittleEndian) & TransportStreamUnit.PacketIdentifierMask); ushort descLength = (ushort)(Common.Binary.ReadU16(node.Data, offset, Common.Binary.IsLittleEndian) & 0x0FFF); var entry = new Tuple <TransportStreamUnit.PacketIdentifier, ushort>(esPid, descLength); m_ProgramDescriptions.AddOrUpdate(esType, entry, (a, old) => entry); offset += 2; } //CRC }
//Static and take reader? //Maps from Program to PacketIdentifer? internal protected virtual void ParseProgramAssociationTable(Container.Node node) { int offset = ReadPointerField(node); //Get the table id TransportStreamUnit.TableIdentifier tableId = (TransportStreamUnit.TableIdentifier)node.Data[offset++]; if (tableId != TransportStreamUnit.TableIdentifier.ProgramAssociation) { return; } /* * Program Association Table (PAT) section syntax * syntax bit index # of bits mnemonic * table_id 0 8 uimsbf * section_syntax_indicator 8 1 bslbf * '0' 9 1 bslbf * reserved 10 2 bslbf * section_length 12 12 uimsbf * transport_stream_id 24 16 uimsbf * reserved 40 2 bslbf * version_number 42 5 uimsbf * current_next_indicator 47 1 bslbf * section_number 48 8 bslbf * last_section_number 56 8 bslbf * for i = 0 to N * program_number 56 + (i * 4) 16 uimsbf * reserved 72 + (i * 4) 3 bslbf * if program_number = 0 * network_PID 75 + (i * 4) 13 uimsbf * else * program_map_pid 75 + (i * 4) 13 uimsbf * end if * next * CRC_32 88 + (i * 4) 32 rpchof * Table section legend */ //section syntax indicator, 0 bit, and 2 reserved bits. //Section Length The number of bytes that follow for the syntax section (with CRC value) and/or table data. These bytes must not exceed a value of 1021. // section_length field is a 12-bit field that gives the length of the table section beyond this field //Since it is carried starting at bit index 12 in the section (the second and third bytes), the actual size of the table section is section_length + 3. ushort sectionLength = (ushort)(Common.Binary.ReadU16(node.Data, ref offset, Common.Binary.IsLittleEndian) & 0x0FFF); //transport_stream_id 24 16 uimsbf ushort transportStreamId = (ushort)(Common.Binary.ReadU16(node.Data, ref offset, Common.Binary.IsLittleEndian) & 0x0FFF); //Skip reserved, version number and current/next indicator. ++offset; //Skip section number ++offset; //Skip last section number ++offset; //Determine where to end (don't count the crc) int end = (sectionLength + 3) - 4; //4 bytes per ProgramInfo in node.Data while (offset < end) { //2 Bytes ProgramNumber ushort programNumber = Common.Binary.ReadU16(node.Data, offset, Common.Binary.IsLittleEndian); //3 bits reserved //2 Bytes ProgramID TransportStreamUnit.PacketIdentifier pid = TransportStreamUnit.GetPacketIdentifier(node.Data, offset + 2); //Add or update the entry m_ProgramAssociations.AddOrUpdate(programNumber, pid, (id, old) => pid); //Move the offset offset += 4; } //CRC }
/// <summary> /// Enumerates each unit found in the TransportStream. /// When a unit is found it is either added to the Streams or it is parsed to obtain information. /// </summary> /// <returns></returns> public override IEnumerator <Container.Node> GetEnumerator() { //Ensure a Unit remains while (Remaining >= TransportUnitSize) { //Read a unit Container.Node next = ReadNext(); //No more units stops the enumeration if (next == null) { yield break; } //Return the unit for external handling yield return(next); //Get the type of packet this is TransportStreamUnit.PacketIdentifier pid = GetPacketIdentifier(this, next.Identifier); //Need to parse the packet to ensure that GetTracks can always be updated. switch (pid) { case TransportStreamUnit.PacketIdentifier.ProgramAssociationTable: { /* * * The Program Association Table (PAT) is the entry point for the Program Specific Information (PSI) tables. * * It is always carried in packets with PID (packet ID) = 0. For each assigned program number, the PAT lists the PID for packets containing that program's PMT. * * The PMT lists all the PIDs for packets containing elements of a particular program (audio, video, aux data, and Program Clock Reference (PCR)). * * The PAT also contains the PIDs for the NIT(s). * * The NIT is an optional table that maps channel frequencies, transponder numbers, and other guide information for programs. * */ ParseProgramAssociationTable(next); goto default; } case TransportStreamUnit.PacketIdentifier.DescriptionTable: // TableIdentifier.ProgramMap { //Parse the table ParseDescriptionTable(next); goto default; } //case PacketIdentifier.Program case TransportStreamUnit.PacketIdentifier.ConditionalAccessTable: case TransportStreamUnit.PacketIdentifier.SelectionInformationTable: case TransportStreamUnit.PacketIdentifier.NetworkInformationTable: { //Todo goto default; } default: { //Include the PId with the StreamId m_ProgramIds.Add(pid); break; } } //Done with the unit Skip(next.DataSize); } }