Esempio n. 1
0
        /// <summary>
        /// Parses a <see cref="BlockType.StreamInfo"/> <see cref="Media.Container.Node"/>
        /// </summary>
        /// <param name=nameof(node)>The <see cref="Media.Container.Node"/> to parse</param>
        internal protected void ParseStreamInfo(Container.Node node = null)
        {
            node = node ?? Root;
            VerifyBlockType(node, BlockType.StreamInfo);
            //METADATA_BLOCK_STREAMINFO
            using (System.IO.BinaryReader bi = new System.IO.BinaryReader(node.DataStream))
            {
                using (BitReader br = new BitReader(bi.BaseStream, Binary.BitOrder.MostSignificant, IdentifierSize * 2, true))
                {
                    m_MinBlockSize = Common.Binary.ReadU16(node.Data, 0, BitConverter.IsLittleEndian); //br.Read16();

                    m_MaxBlockSize = Common.Binary.ReadU16(node.Data, 2, BitConverter.IsLittleEndian);

                    m_MinFrameSize = (int)Common.Binary.ReadU24(node.Data, 4, BitConverter.IsLittleEndian);

                    m_MaxFrameSize = (int)Common.Binary.ReadU24(node.Data, 7, BitConverter.IsLittleEndian);

                    m_SampleRate = (int)Common.Binary.ReadUInt64MSB(node.Data, 10, 20, 0);

                    m_Channels = 1 + (int)Common.Binary.ReadUInt64MSB(node.Data, 12, 3, 4);

                    m_BitsPerSample = 1 + (int)Common.Binary.ReadUInt64MSB(node.Data, 12, 5, 7);

                    m_TotalSamples = Common.Binary.ReadUInt64MSB(node.Data, 13, 36, 4);

                    m_Md5 = new string(Encoding.ASCII.GetChars(node.Data, 8, 16));
                }
            }
        }
Esempio n. 2
0
        public override IEnumerator <Container.Node> GetEnumerator()
        {
            while (Remaining >= MinimumSize)
            {
                Container.Node next = ReadNext();

                if (next == null)
                {
                    yield break;
                }

                yield return(next);

                //Determine if the node holds data required.
                switch (next.Identifier[3])
                {
                case Mpeg.StreamTypes.ProgramStreamMap:
                {
                    ParseProgramStreamMap(next);
                    break;
                }
                }

                Skip(next.DataSize);
            }
        }
Esempio n. 3
0
 public override string ToTextualConvention(Container.Node node)
 {
     if (node.Master.Equals(this))
     {
         return(ProgramStreamReader.ToTextualConvention(node.Identifier));
     }
     return(base.ToTextualConvention(node));
 }
Esempio n. 4
0
 public override string ToTextualConvention(Container.Node node)
 {
     if (node.Master.Equals(this))
     {
         return(RiffReader.ToFourCharacterCode(node.Identifier));
     }
     return(base.ToTextualConvention(node));
 }
Esempio n. 5
0
        /// <summary>
        /// <see cref="Mpeg.StartCodes"/> for names.
        /// </summary>
        /// <param name="name"></param>
        /// <param name="offset"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public Container.Node FindNode(byte name, long offset, long count)
        {
            long position = Position;

            Container.Node result = FindNodes(offset, count, name).FirstOrDefault();

            Position = position;

            return(result);
        }
Esempio n. 6
0
        protected virtual void ParseProgramStreamMap(Container.Node node)
        {
            if (node.Identifier[3] != Mpeg.StreamTypes.ProgramStreamMap)
            {
                return;
            }

            int dataLength = node.Data.Length;

            if (dataLength < 4)
            {
                return;
            }

            byte mapId = node.Data[0];

            byte reserved = node.Data[1];

            ushort infoLength = Common.Binary.ReadU16(node.Data, 2, Common.Binary.IsLittleEndian);

            ushort mapLength = Common.Binary.ReadU16(node.Data, 4 + infoLength, Common.Binary.IsLittleEndian);

            int offset = 4 + infoLength + 2;

            int crcOffset = dataLength - 4;

            //While data remains in the map
            while (offset < crcOffset)
            {
                //Find out the type of item it is
                byte esType = node.Data[offset++];

                //Find out the elementary stream id
                byte esId = node.Data[offset++];

                //find out how long the info is
                ushort esInfoLength = Common.Binary.ReadU16(node.Data, offset, Common.Binary.IsLittleEndian);

                //Get a array containing the info
                Common.MemorySegment esData = esInfoLength == 0 ? Media.Common.MemorySegment.Empty : new Common.MemorySegment(node.Data, offset, esInfoLength); //node.Data.Skip(offset).Take(esInfoLength).ToArray();

                //Create the entry
                var entry = new Tuple <byte, Common.MemorySegment>(esType, esData);

                //should keep entries until crc is updated if present and then insert.

                //Add it to the ProgramStreams
                m_ProgramStreams.AddOrUpdate(esId, entry, (id, old) => entry);

                //Move the offset
                offset += 2 + esInfoLength;
            }

            //Map crc
        }
Esempio n. 7
0
        public override IEnumerator <Container.Node> GetEnumerator()
        {
            while (Remaining >= PacketizedElementaryStreamReader.IdentifierSize)
            {
                Container.Node next = ReadNext();

                if (next == null)
                {
                    yield break;
                }

                yield return(next);

                //Determine if the node holds data required.
                switch (next.Identifier[3])
                {
                case Mpeg.StreamTypes.PackHeader:
                {
                    //Decoder the SCR
                    double scr;
                    ParsePackHeader(next, out scr);

                    //Set the SystemClockRate
                    m_SystemClockRate = scr;

                    break;
                }

                case Mpeg.StreamTypes.SystemHeader:
                {
                    //Parse the system Header
                    ParseSystemsHeader(next);
                    break;
                }

                case Mpeg.StreamTypes.ProgramStreamMap:
                {
                    ParseProgramStreamMap(next);
                    break;
                }
                }

                Skip(next.DataSize);
            }
        }
Esempio n. 8
0
        internal protected void ParseData(Container.Node node)
        {
            /*
             * The "data" subchunk contains the size of the data and the actual sound:
             *
             * 36        4   Subchunk2ID      Contains the letters "data"
             *                             (0x64617461 big-endian form).
             * 40        4   Subchunk2Size    == NumSamples * NumChannels * BitsPerSample/8
             *                             This is the number of bytes in the data.
             *                             You can also think of this as the size
             *                             of the read of the subchunk following this
             *                             number.
             * 44        *   Data             The actual sound data.
             */

            //using (var chunk = ReadChunk(FourCharacterCode.data, Root.Offset))
            //{
            //}
        }
Esempio n. 9
0
        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
        }
Esempio n. 10
0
        protected virtual void ParseSystemsHeader(Container.Node node)
        {
            if (node.Identifier[3] != Mpeg.StreamTypes.SystemHeader)
            {
                return;
            }

            //These values or the entire node should probably also be stored.

            //22-bit unsigned integer. Must be greater than or equal to (>=) the maximum value of the program_mux_rate coded in any pack of the program stream.
            //For DVD-Video this value should be 25200 decimal.
            uint rateBound = Common.Binary.ReadU24(node.Data, 0, Common.Binary.IsLittleEndian);

            rateBound &= 0x80000001; //2147483649

            //Make a 'checked' read
            byte temp = node.Data[3];

            //6-bit unsigned integer, ranging from 0 to 32 inclusive. Must be greater than or equal to (>=) the maximum number of audio streams in the program stream.
            //ISO 13818-1 states this should be the MPEG audio streams, but DVD-Video counts all audio streams.
            //For DVD-Video this should be the number of audio streams of any type, from 0 to 8 inclusive.
            byte audioBound = (byte)(temp & 0xFC); //252

            //1-bit boolean. If TRUE (1) the program stream is multiplexed at a fixed bitrate.
            //For DVD-Video this flag should be FALSE (0).
            bool fixedBitrate = (temp & 2) > 0;

            //1-bit boolean. If TRUE (1) the program stream meets the requirements of a "Constrained System parameter Program Stream".
            //For DVD-Video this flag must be FALSE (0).
            bool csps = (temp & 1) > 0;

            //1-bit boolean. TRUE (1) indicates that there is a specified constant rational relationship between the audio sampling rate and the system_clock_frequency (27MHz).
            //For DVD-Video this flag should be TRUE (1).

            //Make a 'checked' read
            temp = node.Data[4];

            bool system_audio_lock = (temp & 128) > 0;

            //1-bit boolean. TRUE (1) indicates that there is a specified constant rational relationship between the video picture rate and the system_clock_frequency (27MHz).
            //For DVD-Video this flag should be TRUE (1).
            //The PAL/SECAM ratio is 1080000 system clocks (3600 90KHz clocks) per displayed picture.
            //The NTSC ratio is 900900 system clocks (3003 90KHz clocks) per displayed picture. This rate differs slightly from the nominal rate for NTSC, but is fixed, and consistent with ITU-601.

            bool system_video_lock = (temp & 64) > 0;

            //5-bit unsigned integer, ranging from 0 to 16 inclusive. Must be greater than or equal to (>=) the maximum number of video streams in the program stream.
            //For DVD-Video this value will always be 1.

            byte video_boud = (byte)(temp & 0xE0);

            //1-bit boolean. If CSPS_flag is TRUE (1) this specifies which restraint is applicable to the packet rate, otherwise the flag has no meaning.
            //For DVD-Video this flag must be FALSE (0).

            //Make a 'checked' read
            temp = node.Data[5];

            bool packRateRestriction = (temp & 128) > 0;

            //7-bit reserved. Should always equal 111 1111.
            if ((temp & 0x7F) != 0x7F)
            {
                throw new InvalidOperationException("Systems Header Reserved Bits are not Reserved");
            }

            //Stream bound entries start at byte 6
            int offset = 6;

            //Note: While the System header is flexible, for DVD-Video the length and content are fixed. There must be 4 stream_bound entries:
            while (offset < node.DataSize)
            {
                /*
                 * 8-bit unsigned integer. Indicates to which stream the following buffer bound applies.
                 *  1011 1000 (0xB8) indicates all audio streams.
                 *  1011 1001 (0xB9) indicates all video streams.
                 *  Any other value must be greater than or equal to 1011 1100 (0xBC) and refers to the stream as defined for PES stream ID
                 */
                byte streamId = node.Data[offset++];

                //Use constants from StreamType and see if a switch could be better.
                if (streamId < 0xBC && streamId != 0xB8 && streamId != 0xB9)
                {
                    throw new InvalidOperationException("All Entries in the System Header must apply to a stream with an id >= 0xBC");
                }

                /*
                 * 1-bit boolean. False (0) indicates the multiplier is 128, TRUE (1) indicates the multiplier is 1024.
                 * Must be 0 for audio streams, 1 for video streams. May be 0 or 1 for other types.
                 */
                //2 reserved bits (32 = 00100000)
                bool bufferBoundScale = (node.Data[offset] & 32) > 0;

                /*
                 * 13-bit unsigned integer. When multiplied by either 128 or 1024, as indicated by P-STD_buffer_bound_scale,
                 * defines a value that is greater than or equal to the maximum P-STD buffer size for all packets of the designated stream in the entire program stream.
                 */
                //3 bits masked out (0x1FFF = 8191 = 0001111111111111)
                ushort stdBufferSizeBound = (ushort)(Common.Binary.ReadU16(node.Data, ref offset, Common.Binary.IsLittleEndian) & 0x1FFF);

                //Create the the StreamBound Entry
                var entry = new Tuple <bool, ushort, Container.Node>(bufferBoundScale, stdBufferSizeBound, node);

                //Add or Update given the streamId
                m_StreamBoundEntries.AddOrUpdate(streamId, entry, (a, old) => entry);
            }
        }
Esempio n. 11
0
        //probably not be needed..
        //int? m_PackHeaderVersion;

        ///// <summary>
        ///// Decodes the Mpeg Version from the Pack Header found in the Root node.
        ///// (Adds 1 to the value found because MPEG 1 used 0 and MPEG 2 used 1).
        ///// </summary>
        //public int PackHeaderVersion
        //{
        //    get
        //    {
        //        if (!m_PackHeaderVersion.HasValue)
        //        {
        //            using (var root = Root) m_PackHeaderVersion = 1 + root.Identifier[4] >> 6;
        //        }
        //        return m_PackHeaderVersion.Value;
        //    }
        //}

        protected virtual void ParsePackHeader(Container.Node node, out double scr)
        {
            //Indicate no value found
            scr = double.NaN;

            //If the identifier is not the PackHeader then do nothing
            if (node.Identifier[3] != Mpeg.StreamTypes.PackHeader)
            {
                return;
            }

            //Declare the high and low parts for decoding
            double high = 0;
            uint   low  = 0;

            //m_PackHeaderVersion could be ser here..

            //Determine which version of the Pack Header this is
            switch (node.Identifier[4] >> 6)
            {
            case 0:     //MPEG 1
            {
                //Decode the SCR

                //Todo, use ReadBigEndianInteger or BitStream
                high = (double)((node.Identifier[5] >> 3) & 0x01);

                low = ((uint)((node.Identifier[5] >> 1) & 0x03) << 30) |
                      (uint)(node.Identifier[6] << 22) |
                      (uint)((node.Identifier[7] >> 1) << 15) |
                      (uint)(node.Identifier[8] << 7) |
                      (uint)(node.Identifier[9] << 1);

                break;
            }

            default:     //MPEG 2
            {
                //Decode the SCR

                //Todo, use ReadBigEndianInteger or BitStream
                high = (double)((node.Identifier[5] & 0x20) >> 5);

                low = ((uint)((node.Identifier[5] & 0x18) >> 3) << 30) |
                      (uint)((node.Identifier[5] & 0x03) << 28) |
                      (uint)(node.Identifier[6] << 20) |
                      (uint)((node.Identifier[7] & 0xF8) << 12) |
                      (uint)((node.Identifier[7] & 0x03) << 13) |
                      (uint)(node.Identifier[8] << 5) |
                      (uint)(node.Identifier[9] >> 3);

                //Determine if this should be also decoded here.
                //Program Mux Rate - This is a 22 bit integer specifying the rate at which the program stream target decoder receives the Program Stream during the pack in which it is included. The value of program_mux_rate is measured in units of 50 bytes/second. The value 0 is forbidden.

                break;
            }
            }

            //SCR and SCR_ext together are the System Clock Reference, a counter driven at 27MHz, used as a reference to synchronize streams. The clock is divided by 300 (to match the 90KHz clocks such as PTS/DTS), the quotient is SCR (33 bits), the remainder is SCR_ext (9 bits)
            scr = (((high * 0x10000) * 0x10000) + low) / 90000.0;
        }
Esempio n. 12
0
 public static bool HasPayload(TransportStreamReader reader, Container.Node tsUnit)
 {
     return(GetAdaptationFieldControl(reader, tsUnit).HasFlag(TransportStreamUnit.AdaptationFieldControl.AdaptationFieldAndPayload));
 }
Esempio n. 13
0
 public static TransportStreamUnit.ScramblingControl GetScramblingControl(TransportStreamReader reader, Container.Node tsUnit)
 {
     return(TransportStreamUnit.GetScramblingControl(tsUnit.Identifier, reader.UnitOverhead));
 }
Esempio n. 14
0
 string Media.Container.IMediaContainer.ToTextualConvention(Container.Node n)
 {
     return("RtpDump-Node");
     //Create a packet from the node, 3 byte identifer is RTP
     //return RtpSend.ToTextualConvention(packet);
 }
Esempio n. 15
0
 public static bool HasAdaptationField(TransportStreamReader reader, Container.Node tsUnit)
 {
     return(TransportStreamUnit.GetAdaptationFieldControl(tsUnit.Identifier, reader.UnitOverhead) > TransportStreamUnit.AdaptationFieldControl.None);
 }
Esempio n. 16
0
        //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
        }
Esempio n. 17
0
        static internal int ReadPointerField(Container.Node node, int offset = 0)
        {
            int pointer = node.Data[offset++];

            return(pointer > 0 ? offset += pointer * Common.Binary.BitsPerByte : offset);
        }
Esempio n. 18
0
        /// <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);
            }
        }
Esempio n. 19
0
 public static byte[] GetAdaptationFieldData(TransportStreamReader reader, Container.Node tsUnit)
 {
     return(TransportStreamUnit.AdaptationField.GetAdaptationFieldData(tsUnit.Identifier, reader.UnitOverhead, tsUnit.Data, 0));
 }
Esempio n. 20
0
 public static int GetContinuityCounter(TransportStreamReader reader, Container.Node tsUnit)
 {
     return(TransportStreamUnit.GetContinuityCounter(tsUnit.Identifier, reader.UnitOverhead));
 }
Esempio n. 21
0
 public static bool HasPayloadUnitStartIndicator(TransportStreamReader reader, Container.Node tsUnit)
 {
     return(TransportStreamUnit.HasPayloadUnitStartIndicator(tsUnit.Identifier, reader.UnitOverhead));
 }
Esempio n. 22
0
 public static bool HasTransportPriority(TransportStreamReader reader, Container.Node tsUnit)
 {
     return(TransportStreamUnit.HasTransportPriority(tsUnit.Identifier, reader.UnitOverhead));
 }