Exemplo n.º 1
0
        private void ReadHeader(EBMLreader element)
        {
            string doctype = null;
            ulong  i       = 0;

            while (i < element.DataSize)
            {
                var child = new EBMLreader(element, element.DataOffset + i);

                switch ((EBMLID)child.ID)
                {
                case EBMLID.EBMLDocType:
                    doctype = child.ReadString();
                    break;
                }

                i += child.Size;
            }

            // Check DocType
            if (string.IsNullOrEmpty(doctype) || doctype != "matroska" && doctype != "webm")
            {
                throw new UnsupportedFormatException("DocType is not matroska or webm");
            }
        }
Exemplo n.º 2
0
        private void ReadCreateSegmentInfo(EBMLreader element, EBMLelement ebml_sinfo)
        {
            ulong i = 0;

            while (i < element.DataSize)
            {
                var child = new EBMLreader(element, element.DataOffset + i);
                switch (child.ID)
                {
                case MatroskaID.Duration:
                    duration_unscaled = child.ReadDouble();
                    if (time_scale > 0)
                    {
                        duration = TimeSpan.FromMilliseconds(duration_unscaled * time_scale / 1000000);
                    }

                    break;

                case MatroskaID.TimeCodeScale:
                    time_scale = child.ReadULong();
                    if (duration_unscaled > 0)
                    {
                        duration = TimeSpan.FromMilliseconds(duration_unscaled * time_scale / 1000000);
                    }

                    break;

                case MatroskaID.Title:
                    break;
                }

                i += child.Size;
            }
        }
Exemplo n.º 3
0
        /// <summary>
        ///     Constructs a <see cref="Track" /> parsing from provided
        ///     file data.
        ///     Parsing will be done reading from _file at position references by
        ///     parent element's data section.
        /// </summary>
        /// <param name="_file"><see cref="File" /> instance to read from.</param>
        /// <param name="element">Parent <see cref="EBMLreader" />.</param>
        public Track(File _file, EBMLreader element)
        {
            ulong i = 0;

            while (i < element.DataSize)
            {
                var child = new EBMLreader(_file, element.DataOffset + i);

                switch (child.ID)
                {
                case MatroskaID.TrackNumber:
                    track_number = child.ReadULong();
                    break;

                case MatroskaID.TrackUID:
                    _UID = child.ReadULong();
                    break;

                case MatroskaID.CodecID:
                    track_codec_id = child.ReadString();
                    break;

                case MatroskaID.CodecName:
                    track_codec_name = child.ReadString();
                    break;

                case MatroskaID.TrackName:
                    track_name = child.ReadString();
                    break;

                case MatroskaID.TrackLanguage:
                    track_language = child.ReadString();
                    break;

                case MatroskaID.TrackFlagEnabled:
                    track_enabled = child.ReadBool();
                    break;

                case MatroskaID.TrackFlagDefault:
                    track_default = child.ReadBool();
                    break;

                case MatroskaID.CodecPrivate:
                    codec_data = child.ReadBytes();
                    break;

                default:
                    UnknownElements.Add(child);
                    break;
                }

                i += child.Size;
            }
        }
Exemplo n.º 4
0
        /// <summary>
        ///     Construct a <see cref="AudioTrack" /> reading information from
        ///     provided file data.
        ///     Parsing will be done reading from _file at position references by
        ///     parent element's data section.
        /// </summary>
        /// <param name="_file"><see cref="File" /> instance to read from.</param>
        /// <param name="element">Parent <see cref="EBMLreader" />.</param>
        public AudioTrack(File _file, EBMLreader element)
            : base(_file, element)
        {
            MatroskaID matroska_id;

            // Here we handle the unknown elements we know, and store the rest
            foreach (var elem in base.UnknownElements)
            {
                matroska_id = elem.ID;

                switch (matroska_id)
                {
                case MatroskaID.TrackAudio:
                {
                    ulong i = 0;

                    while (i < elem.DataSize)
                    {
                        var child = new EBMLreader(_file, elem.DataOffset + i);

                        matroska_id = child.ID;

                        switch (matroska_id)
                        {
                        case MatroskaID.AudioChannels:
                            channels = child.ReadULong();
                            break;

                        case MatroskaID.AudioBitDepth:
                            depth = child.ReadULong();
                            break;

                        case MatroskaID.AudioSamplingFreq:
                            rate = child.ReadDouble();
                            break;

                        default:
                            UnknownElements.Add(child);
                            break;
                        }

                        i += child.Size;
                    }

                    break;
                }

                default:
                    UnknownElements.Add(elem);
                    break;
                }
            }
        }
Exemplo n.º 5
0
        /// <summary>
        ///     Create a new abstract <see cref="EBMLreader" /> with arbitrary attributes,
        ///     without reading its information on the file.
        /// </summary>
        /// <param name="parent">The <see cref="EBMLreader" /> that contains the instance to be described.</param>
        /// <param name="position">Position in the file.</param>
        /// <param name="ebmlid">EBML ID of the element</param>
        /// <param name="size">Total size of the EBML, in bytes</param>
        public EBMLreader(EBMLreader parent, ulong position, MatroskaID ebmlid, ulong size = 0)
        {
            // Keep a reference to the file
            if (parent != null)
            {
                file = parent.file;
            }

            Parent = parent;

            // Initialize attributes
            offset     = position;
            DataOffset = offset;
            ebml_id    = (uint)ebmlid;
            DataSize   = size;
        }
Exemplo n.º 6
0
        /// <summary>
        ///     Reads (and Write, if file Mode is Write) the file with a specified read style.
        /// </summary>
        /// <param name="propertiesStyle">
        ///     A <see cref="ReadStyle" /> value specifying at what level
        ///     of accuracy to read the media properties, or
        ///     <see
        ///         cref="ReadStyle.None" />
        ///     to ignore the properties.
        /// </param>
        private void ReadWrite(ReadStyle propertiesStyle)
        {
            var offset = ReadLeadText();

            var hasSegment = false;

            while (offset < (ulong)Length)
            {
                EBMLreader element;
                try
                {
                    element = new EBMLreader(this, offset);
                }
                catch (Exception)
                {
                    // Sometimes, the file has zero padding at the end
                    if (hasSegment)
                    {
                        break;                         // Avoid crash
                    }

                    throw;
                }

                var ebml_id     = (EBMLID)element.ID;
                var matroska_id = element.ID;

                switch (ebml_id)
                {
                case EBMLID.EBMLHeader:
                    ReadHeader(element);
                    break;
                }

                switch (matroska_id)
                {
                case MatroskaID.Segment:
                    ReadWriteSegment(element, propertiesStyle);
                    hasSegment = true;
                    break;
                }

                offset += element.Size;
            }
        }
Exemplo n.º 7
0
        private void ReadTracks(EBMLreader element)
        {
            ulong i = 0;

            while (i < element.DataSize)
            {
                var child = new EBMLreader(element, element.DataOffset + i);

                switch (child.ID)
                {
                case MatroskaID.TrackEntry:
                    ReadTrackEntry(child);
                    break;
                }

                i += child.Size;
            }
        }
Exemplo n.º 8
0
        private void ReadAttachments(EBMLreader element, ReadStyle propertiesStyle)
        {
            ulong i = 0;

            while (i < (ulong)(long)element.DataSize)
            {
                var child = new EBMLreader(element, element.DataOffset + i);

                switch (child.ID)
                {
                case MatroskaID.AttachedFile:
                    ReadAttachedFile(child, propertiesStyle);
                    break;
                }

                i += child.Size;
            }
        }
Exemplo n.º 9
0
        /// <summary>
        ///     Constructs a child <see cref="EBMLreader" /> reading the data from the
        ///     EBML parent at the provided file position.
        /// </summary>
        /// <param name="parent">The <see cref="EBMLreader" /> that contains the instance to be created.</param>
        /// <param name="position">Position in the file to start reading from.</param>
        public EBMLreader(EBMLreader parent, ulong position)
        {
            if (parent == null)
            {
                throw new ArgumentNullException("file");
            }

            // Keep a reference to the file
            file   = parent.file;
            Parent = parent;

            // Initialize attributes
            offset     = position;
            DataOffset = position;
            ebml_id    = 0;
            DataSize   = 0;

            // Actually read the EBML on the file
            Read(true);
        }
Exemplo n.º 10
0
        private void ReadTrackEntry(EBMLreader element)
        {
            ulong i = 0;

            while (i < element.DataSize)
            {
                var child = new EBMLreader(element, element.DataOffset + i);

                switch (child.ID)
                {
                case MatroskaID.TrackType:
                {
                    switch ((TrackType)child.ReadULong())
                    {
                    case TrackType.Video:
                    {
                        var track = new VideoTrack(this, element);

                        tracks.Add(track);
                        break;
                    }

                    case TrackType.Audio:
                    {
                        var track = new AudioTrack(this, element);

                        tracks.Add(track);
                        break;
                    }
                    }

                    break;
                }
                }

                i += child.Size;
            }
        }
Exemplo n.º 11
0
        private void ReadAttachedFile(EBMLreader element, ReadStyle propertiesStyle)
        {
            ulong i = 0;

#pragma warning restore 219

            while (i < element.DataSize)
            {
                var child = new EBMLreader(element, element.DataOffset + i);

                switch (child.ID)
                {
                case MatroskaID.FileName:
#pragma warning disable 219 // Assigned, never read
                    _ = child.ReadString();
                    break;

                case MatroskaID.FileMimeType:
                    _ = child.ReadString();
                    break;

                case MatroskaID.FileDescription:
                    _ = child.ReadString();
                    break;

                case MatroskaID.FileData:
                    break;

                case MatroskaID.FileUID:
                    _ = child.ReadULong();
                    break;
                }

                i += child.Size;
            }
        }
Exemplo n.º 12
0
        /// <summary>
        ///     Constructs a <see cref="VideoTrack" /> parsing from provided
        ///     file data.
        ///     Parsing will be done reading from _file at position references by
        ///     parent element's data section.
        /// </summary>
        /// <param name="_file"><see cref="File" /> instance to read from.</param>
        /// <param name="element">Parent <see cref="EBMLreader" />.</param>
        public VideoTrack(File _file, EBMLreader element)
            : base(_file, element)
        {
            MatroskaID matroska_id;

            // Here we handle the unknown elements we know, and store the rest
            foreach (var elem in base.UnknownElements)
            {
                matroska_id = elem.ID;

                switch (matroska_id)
                {
                case MatroskaID.TrackVideo:
                {
                    ulong i = 0;

                    while (i < elem.DataSize)
                    {
                        var child = new EBMLreader(_file, elem.DataOffset + i);

                        matroska_id = child.ID;

                        switch (matroska_id)
                        {
                        case MatroskaID.VideoDisplayWidth:
                            disp_width = child.ReadULong();
                            break;

                        case MatroskaID.VideoDisplayHeight:
                            disp_height = child.ReadULong();
                            break;

                        case MatroskaID.VideoPixelWidth:
                            width = child.ReadULong();
                            break;

                        case MatroskaID.VideoPixelHeight:
                            height = child.ReadULong();
                            break;

                        case MatroskaID.VideoFrameRate:
                            framerate = child.ReadDouble();
                            break;

                        case MatroskaID.VideoFlagInterlaced:
                            interlaced = child.ReadBool();
                            break;

                        case MatroskaID.VideoAspectRatioType:
                            ratio_type = (VideoAspectRatioType)child.ReadULong();
                            break;

                        case MatroskaID.VideoColourSpace:
                            fourcc = child.ReadBytes();
                            break;

                        default:
                            UnknownElements.Add(child);
                            break;
                        }

                        i += child.Size;
                    }

                    break;
                }

                case MatroskaID.TrackDefaultDuration:
                    var tmp = elem.ReadULong();
                    framerate = 1000000000.0 / tmp;
                    break;

                default:
                    UnknownElements.Add(elem);
                    break;
                }
            }
        }
Exemplo n.º 13
0
        private bool ReadSeekHead(EBMLreader element, List <EBMLreader> segm_list)
        {
            MatroskaID ebml_id       = 0;
            ulong      ebml_position = 0;

            ulong i = 0;

            while (i < element.DataSize)
            {
                var ebml_seek   = new EBMLreader(element, element.DataOffset + i);
                var matroska_id = ebml_seek.ID;

                if (matroska_id != MatroskaID.Seek)
                {
                    return(false);                    // corrupted SeekHead
                }

                ulong j = 0;
                while (j < ebml_seek.DataSize)
                {
                    var child = new EBMLreader(ebml_seek, ebml_seek.DataOffset + j);
                    matroska_id = child.ID;

                    switch (matroska_id)
                    {
                    case MatroskaID.SeekID:
                        ebml_id = (MatroskaID)child.ReadULong();
                        break;

                    case MatroskaID.SeekPosition:
                        ebml_position = child.ReadULong() + element.Offset;
                        break;
                    }

                    j += child.Size;
                }

                if (ebml_id > 0 && ebml_position > 0)
                {
                    // Create abstract EBML representation of the segment EBML
                    var ebml = new EBMLreader(element.Parent, ebml_position, ebml_id);

                    // Sort the seek-entries by increasing position order
                    int k;
                    for (k = segm_list.Count - 1; k >= 0; k--)
                    {
                        if (ebml_position > segm_list[k]
                            .Offset)
                        {
                            break;
                        }
                    }

                    segm_list.Insert(k + 1, ebml);

                    // Chained SeekHead recursive read
                    if (ebml_id == MatroskaID.SeekHead)
                    {
                        if (!ebml.Read())
                        {
                            return(false);                            // Corrupted
                        }

                        ReadSeekHead(ebml, segm_list);
                    }
                }

                i += ebml_seek.Size;
            }

            return(true);
        }
Exemplo n.º 14
0
        private List <EBMLreader> ReadSegments(EBMLreader element, bool allowSeekHead)
        {
            var segm_list = new List <EBMLreader>(10);

            var foundCluster = false;             // find first Cluster

            ulong i = 0;

            while (i < element.DataSize)
            {
                EBMLreader child;

                try
                {
                    child = new EBMLreader(element, element.DataOffset + i);
                }
                catch
                {
                    MarkAsCorrupt("Truncated file or invalid EBML entry");
                    break;                     // Corrupted file: quit here and good luck for the rest
                }

                var matroska_id   = child.ID;
                var refInSeekHead = false;

                switch (matroska_id)
                {
                case MatroskaID.SeekHead:
                    if (allowSeekHead)
                    {
                        // Take only the first SeekHead into account
                        var ebml_seek = new List <EBMLreader>(10)
                        {
                            child
                        };
                        if (ReadSeekHead(child, ebml_seek))
                        {
                            // Always reference the first element
                            if (ebml_seek[0]
                                .Offset > element.DataOffset)
                            {
                                ebml_seek.Insert(0, segm_list[0]);
                            }

                            segm_list = ebml_seek;
                            i         = element.DataSize;                             // Exit the loop: we got what we need
                        }
                        else
                        {
                            MarkAsCorrupt("Invalid Meta Seek");
                            refInSeekHead = true;
                        }
                    }
                    else
                    {
                        refInSeekHead = true;
                    }

                    break;

                case MatroskaID.Void:                         // extend SeekHead space to following void
                    break;

                case MatroskaID.Cluster:                         // reference first Cluster only (too many)
                    refInSeekHead = !foundCluster;
                    foundCluster  = true;
                    break;

                // Reference the following elements
                case MatroskaID.Cues:
                case MatroskaID.Tracks:
                case MatroskaID.SegmentInfo:
                case MatroskaID.Tags:
                case MatroskaID.Attachments:
                default:
                    refInSeekHead = true;
                    break;
                }

                i += child.Size;

                if (refInSeekHead || i == 0)
                {
                    segm_list.Add(child);
                }
            }

            return(segm_list);
        }
Exemplo n.º 15
0
        private void ReadWriteSegment(EBMLreader element, ReadStyle propertiesStyle, bool retry = true)
        {
            // First make reference of all EBML elements at level 1 (top) in the Segment

            var segm_list = ReadSegments(element, retry);             // Try to get it from SeekHead the first time (way faster)

            // Now process (read and prepare to write) the referenced elements we care about

            EBMLelement ebml_sinfo = null;


            var valid = true;

            foreach (var child in segm_list)
            {
                // the child here may be Abstract if it has been retrieved in the SeekHead,
                // so child.Read() must be used to retrieve the full EBML header

                switch (child.ID)
                {
                case MatroskaID.SeekHead:
                    valid = child.Read();
                    break;

                case MatroskaID.SegmentInfo:
                    if (valid = child.Read())
                    {
                        ReadCreateSegmentInfo(child, ebml_sinfo);
                    }

                    break;

                case MatroskaID.Tracks:
                    if ((propertiesStyle & ReadStyle.Average) != 0)
                    {
                        if (valid = child.Read())
                        {
                            ReadTracks(child);
                        }
                    }

                    break;

                case MatroskaID.Tags:
                    valid = child.Read();
                    break;

                case MatroskaID.Attachments:
                    valid = child.Read();
                    if (valid)
                    {
                        ReadAttachments(child, propertiesStyle);
                    }

                    break;

                case MatroskaID.CRC32:                         // We don't support it
                    valid = child.Read();
                    break;
                }

                if (!valid)
                {
                    break;
                }
            }

            // Detect invalid SeekHead
            if (!valid)
            {
                if (retry)
                {
                    MarkAsCorrupt("Invalid Meta Seek");

                    // Retry it one last time
                    ReadWriteSegment(element, propertiesStyle, false);
                }
                else
                {
                    MarkAsCorrupt("Invalid EBML element Read");
                }
            }
        }