public MatroskaFile(string path)
        {
            _path = path;
            _stream = new FastFileStream(path);

            // read header
            var headerElement = ReadElement();
            if (headerElement != null && headerElement.Id == ElementId.Ebml)
            {
                // read segment
                _stream.Seek(headerElement.DataSize, SeekOrigin.Current);
                _segmentElement = ReadElement();
                if (_segmentElement != null && _segmentElement.Id == ElementId.Segment)
                {
                    _valid = true; // matroska file must start with ebml header and segment
                }
            }
        }
 private void ReadVideoElement(Element videoElement)
 {
     Element element;
     while (_stream.Position < videoElement.EndPosition && (element = ReadElement()) != null)
     {
         switch (element.Id)
         {
             case ElementId.PixelWidth:
                 _pixelWidth = (int)ReadUInt((int)element.DataSize);
                 break;
             case ElementId.PixelHeight:
                 _pixelHeight = (int)ReadUInt((int)element.DataSize);
                 break;
             default:
                 _stream.Seek(element.DataSize, SeekOrigin.Current);
                 break;
         }
     }
 }
        private void ReadTracksElement(Element tracksElement)
        {
            _tracks = new List<MatroskaTrackInfo>();

            Element element;
            while (_stream.Position < tracksElement.EndPosition && (element = ReadElement()) != null)
            {
                if (element.Id == ElementId.TrackEntry)
                {
                    ReadTrackEntryElement(element);
                }
                else
                {
                    _stream.Seek(element.DataSize, SeekOrigin.Current);
                }
            }
        }
        private void ReadTrackEntryElement(Element trackEntryElement)
        {
            long defaultDuration = 0;
            bool isVideo = false;
            bool isAudio = false;
            bool isSubtitle = false;
            var trackNumber = 0;
            string name = string.Empty;
            string language = "eng"; // default value
            string codecId = string.Empty;
            string codecPrivate = string.Empty;
            //var biCompression = string.Empty;
            int contentCompressionAlgorithm = -1;
            int contentEncodingType = -1;

            Element element;
            while (_stream.Position < trackEntryElement.EndPosition && (element = ReadElement()) != null)
            {
                switch (element.Id)
                {
                    case ElementId.DefaultDuration:
                        defaultDuration = (int)ReadUInt((int)element.DataSize);
                        break;
                    case ElementId.Video:
                        ReadVideoElement(element);
                        isVideo = true;
                        break;
                    case ElementId.Audio:
                        isAudio = true;
                        break;
                    case ElementId.TrackNumber:
                        trackNumber = (int)ReadUInt((int)element.DataSize);
                        break;
                    case ElementId.Name:
                        name = ReadString((int)element.DataSize, Encoding.UTF8);
                        break;
                    case ElementId.Language:
                        language = ReadString((int)element.DataSize, Encoding.ASCII);
                        break;
                    case ElementId.CodecId:
                        codecId = ReadString((int)element.DataSize, Encoding.ASCII);
                        break;
                    case ElementId.TrackType:
                        switch (_stream.ReadByte())
                        {
                            case 1:
                                isVideo = true;
                                break;
                            case 2:
                                isAudio = true;
                                break;
                            case 17:
                                isSubtitle = true;
                                break;
                        }
                        break;
                    case ElementId.CodecPrivate:
                        codecPrivate = ReadString((int)element.DataSize, Encoding.UTF8);
                        //if (codecPrivate.Length > 20)
                        //    biCompression = codecPrivate.Substring(16, 4);
                        break;
                    case ElementId.ContentEncodings:
                        contentCompressionAlgorithm = 0; // default value
                        contentEncodingType = 0; // default value

                        var contentEncodingElement = ReadElement();
                        if (contentEncodingElement != null && contentEncodingElement.Id == ElementId.ContentEncoding)
                        {
                            ReadContentEncodingElement(element, ref contentCompressionAlgorithm, ref contentEncodingType);
                        }
                        break;
                }
                _stream.Seek(element.EndPosition, SeekOrigin.Begin);
            }

            _tracks.Add(new MatroskaTrackInfo
            {
                TrackNumber = trackNumber,
                IsVideo = isVideo,
                IsAudio = isAudio,
                IsSubtitle = isSubtitle,
                Language = language,
                CodecId = codecId,
                CodecPrivate = codecPrivate,
                Name = name,
                ContentEncodingType = contentEncodingType,
                ContentCompressionAlgorithm = contentCompressionAlgorithm
            });

            if (isVideo)
            {
                if (defaultDuration > 0)
                {
                    _frameRate = 1.0 / (defaultDuration / 1000000000.0);
                }
                _videoCodecId = codecId;
            }
        }
        private MatroskaSubtitle ReadSubtitleBlock(Element blockElement, long clusterTimeCode)
        {
            var trackNumber = (int)ReadVariableLengthUInt();
            if (trackNumber != _subtitleRipTrackNumber)
            {
                _stream.Seek(blockElement.EndPosition, SeekOrigin.Begin);
                return null;
            }

            var timeCode = ReadInt16();

            // lacing
            var flags = (byte)_stream.ReadByte();
            int frames;
            switch (flags & 6)
            {
                case 0: // 00000000 = No lacing
                    System.Diagnostics.Debug.Print("No lacing");
                    break;
                case 2: // 00000010 = Xiph lacing
                    frames = _stream.ReadByte() + 1;
                    System.Diagnostics.Debug.Print("Xiph lacing ({0} frames)", frames);
                    break;
                case 4: // 00000100 = Fixed-size lacing
                    frames = _stream.ReadByte() + 1;
                    for (var i = 0; i < frames; i++)
                    {
                        _stream.ReadByte(); // frames
                    }
                    System.Diagnostics.Debug.Print("Fixed-size lacing ({0} frames)", frames);
                    break;
                case 6: // 00000110 = EMBL lacing
                    frames = _stream.ReadByte() + 1;
                    System.Diagnostics.Debug.Print("EBML lacing ({0} frames)", frames);
                    break;
            }

            // save subtitle data
            var dataLength = (int)(blockElement.EndPosition - _stream.Position);
            var data = new byte[dataLength];
            _stream.Read(data, 0, dataLength);

            return new MatroskaSubtitle(data, clusterTimeCode + timeCode);
        }
 private void ReadInfoElement(Element infoElement)
 {
     Element element;
     while (_stream.Position < infoElement.EndPosition && (element = ReadElement()) != null)
     {
         switch (element.Id)
         {
             case ElementId.TimecodeScale:
                 // Timestamp scale in nanoseconds (1.000.000 means all timestamps in the segment are expressed in milliseconds)
                 _timecodeScale = (int)ReadUInt((int)element.DataSize);
                 break;
             case ElementId.Duration:
                 // Duration of the segment (based on TimecodeScale)
                 _duration = element.DataSize == 4 ? ReadFloat32() : ReadFloat64();
                 _duration /= _timecodeScale * 1000000.0;
                 break;
             default:
                 _stream.Seek(element.DataSize, SeekOrigin.Current);
                 break;
         }
     }
 }
 private void ReadContentEncodingElement(Element contentEncodingElement, ref int contentCompressionAlgorithm, ref int contentEncodingType)
 {
     Element element;
     while (_stream.Position < contentEncodingElement.EndPosition && (element = ReadElement()) != null)
     {
         switch (element.Id)
         {
             case ElementId.ContentEncodingOrder:
                 var contentEncodingOrder = ReadUInt((int)element.DataSize);
                 System.Diagnostics.Debug.WriteLine("ContentEncodingOrder: " + contentEncodingOrder);
                 break;
             case ElementId.ContentEncodingScope:
                 var contentEncodingScope = ReadUInt((int)element.DataSize);
                 System.Diagnostics.Debug.WriteLine("ContentEncodingScope: " + contentEncodingScope);
                 break;
             case ElementId.ContentEncodingType:
                 contentEncodingType = (int)ReadUInt((int)element.DataSize);
                 break;
             case ElementId.ContentCompression:
                 Element compElement;
                 while (_stream.Position < element.EndPosition && (compElement = ReadElement()) != null)
                 {
                     switch (compElement.Id)
                     {
                         case ElementId.ContentCompAlgo:
                             contentCompressionAlgorithm = (int)ReadUInt((int)compElement.DataSize);
                             break;
                         case ElementId.ContentCompSettings:
                             var contentCompSettings = ReadUInt((int)compElement.DataSize);
                             System.Diagnostics.Debug.WriteLine("ContentCompSettings: " + contentCompSettings);
                             break;
                         default:
                             _stream.Seek(element.DataSize, SeekOrigin.Current);
                             break;
                     }
                 }
                 break;
             default:
                 _stream.Seek(element.DataSize, SeekOrigin.Current);
                 break;
         }
     }
 }
        private void ReadCluster(Element clusterElement)
        {
            long clusterTimeCode = 0;

            Element element;
            while (_stream.Position < clusterElement.EndPosition && (element = ReadElement()) != null)
            {
                switch (element.Id)
                {
                    case ElementId.Timecode:
                        clusterTimeCode = (long)ReadUInt((int)element.DataSize);
                        break;
                    case ElementId.BlockGroup:
                        ReadBlockGroupElement(element, clusterTimeCode);
                        break;
                    case ElementId.SimpleBlock:
                        var subtitle = ReadSubtitleBlock(element, clusterTimeCode);
                        if (subtitle != null)
                        {
                            _subtitleRip.Add(subtitle);
                        }
                        break;
                    default:
                        _stream.Seek(element.DataSize, SeekOrigin.Current);
                        break;
                }
            }
        }
        private void ReadBlockGroupElement(Element clusterElement, long clusterTimeCode)
        {
            MatroskaSubtitle subtitle = null;

            Element element;
            while (_stream.Position < clusterElement.EndPosition && (element = ReadElement()) != null)
            {
                switch (element.Id)
                {
                    case ElementId.Block:
                        subtitle = ReadSubtitleBlock(element, clusterTimeCode);
                        if (subtitle == null)
                        {
                            return;
                        }
                        _subtitleRip.Add(subtitle);
                        break;
                    case ElementId.BlockDuration:
                        var duration = (long)ReadUInt((int)element.DataSize);
                        if (subtitle != null)
                        {
                            subtitle.Duration = duration;
                        }
                        break;
                    default:
                        _stream.Seek(element.DataSize, SeekOrigin.Current);
                        break;
                }
            }
        }
Beispiel #10
0
        private long FindTrackStartInCluster(Element cluster, int targetTrackNumber)
        {
            long clusterTimeCode = 0L;
            long trackStartTime = -1L;
            bool done = false;

            Element element;
            while (_stream.Position < cluster.EndPosition && (element = ReadElement()) != null && !done)
            {
                switch (element.Id)
                {
                    case ElementId.None:
                        done = true;
                        break;
                    case ElementId.Timecode:
                        // Absolute timestamp of the cluster (based on TimecodeScale)
                        clusterTimeCode = (long)ReadUInt((int)element.DataSize);
                        break;
                    case ElementId.BlockGroup:
                        ReadBlockGroupElement(element, clusterTimeCode);
                        break;
                    case ElementId.SimpleBlock:
                        var trackNumber = (int)ReadVariableLengthUInt();
                        if (trackNumber == targetTrackNumber)
                        {
                            // Timecode (relative to Cluster timecode, signed int16)
                            trackStartTime = ReadInt16();
                            done = true;
                        }
                        break;
                }
                _stream.Seek(element.EndPosition, SeekOrigin.Begin);
            }

            return (clusterTimeCode + trackStartTime) * _timecodeScale / 1000000;
        }