public static ResultOfParsingMKV GetSubFromFile(string mkvFilePath) { ResultOfParsingMKV resPars = new ResultOfParsingMKV(); using (var fs = new FileStream(mkvFilePath, FileMode.Open, FileAccess.Read)) { using (EbmlReader ebmlReader = new EbmlReader(fs)) { var segmentFound = ebmlReader.LocateElement(MatroskaElementDescriptorProvider.Segment); if (segmentFound) { StringBuilder sb = new StringBuilder(); MatroskaElementDescriptorProvider medp = new MatroskaElementDescriptorProvider(); ReadContainer(ebmlReader, medp, resPars, 0, sb); } } } // reenumerate foreach(var elm in resPars.dicSub) { int i = 1; var coll = elm.Value.Items.OrderBy(x => x.TimeStart); foreach(var elm2 in coll) { elm2.Number = i++; } } return resPars; }
public void MkvInfo(string filePath) { using (var dataStream = File.OpenRead(filePath)) { var reader = new EbmlReader(dataStream); //reader.EnterContainer(); var headDumper = MakeElementDumper( StandardDtd.EBMLDesc.EBMLVersion, StandardDtd.EBMLDesc.EBMLReadVersion, StandardDtd.EBMLDesc.DocTypeVersion, StandardDtd.EBMLDesc.DocType, StandardDtd.EBMLDesc.DocTypeReadVersion); var trackInfoDumper = MakeElementDumper( MatroskaDtd.Tracks.TrackEntry.TrackNumber, MatroskaDtd.Tracks.TrackEntry.Name, MatroskaDtd.Tracks.TrackEntry.Language, MatroskaDtd.Tracks.TrackEntry.TrackType, MatroskaDtd.Tracks.TrackEntry.CodecName ); reader.ReadNext(); Assert.AreEqual(StandardDtd.EBML.Identifier, reader.ElementId); headDumper(reader); if (reader.LocateElement(MatroskaDtd.Segment)) { reader.EnterContainer(); if (reader.LocateElement(MatroskaDtd.Tracks)) { Console.WriteLine("Tracks"); reader.EnterContainer(); while (reader.ReadNext()) { if (reader.ElementId == MatroskaDtd.Tracks.TrackEntry.Identifier) { trackInfoDumper(reader); } Console.WriteLine(); } reader.LeaveContainer(); Console.WriteLine("end of Tracks"); } if (reader.LocateElement(MatroskaDtd.Segment.Cluster)) { Console.WriteLine("Got first track"); // TODO have to deal with interlaced track data } // reader.LeaveContainer(); } } }
private static void MatroskaTagsDescriptor(EbmlReader ebmlReader, MatroskaElementDescriptorProvider medp, string tab) { //Console.WriteLine("\t " + (ebmlReader.ElementSize)); while (ebmlReader.ReadNext()) { var descriptor = medp.GetElementDescriptor(ebmlReader.ElementId); if (descriptor == null) continue; if (descriptor.Name == "Cluster") continue; if (descriptor.Name == "Cues") continue; Console.WriteLine(tab + descriptor.Name + " " + ebmlReader.ElementPosition); if (descriptor.Type == ElementType.MasterElement) { ebmlReader.EnterContainer(); MatroskaTagsDescriptor(ebmlReader, medp, tab + "\t"); } } ebmlReader.LeaveContainer(); }
// Hierarchie des tags du conteneur MKV public static void MatroskaTagsIndentator(string mkvFilePath) { MatroskaElementDescriptorProvider medp = new MatroskaElementDescriptorProvider(); using (var fs = new FileStream(mkvFilePath, FileMode.Open, FileAccess.Read)) using (EbmlReader ebmlReader = new EbmlReader(fs)) { var segmentFound = ebmlReader.LocateElement(MatroskaElementDescriptorProvider.Segment); if (segmentFound) { ebmlReader.EnterContainer(); MatroskaTagsDescriptor(ebmlReader, medp, ""); } } }
private void WriteData() { var reader = new EbmlReader(new MemoryStream(_oldSegmentInfoData), _oldSegmentInfoData.Length); // prepare writing part var infoStream= new MemoryStream(); var infoWriter = new EbmlWriter(infoStream); var writeMap = new[] { new {Id = MatroskaDtd.Segment.Info.Title.Identifier, Value = _title}, new {Id = MatroskaDtd.Segment.Info.WritingApp.Identifier, Value = _writingApp}, }; // enter the Segment block reader.ReadNext(); reader.EnterContainer(); while (reader.ReadNext()) { if (!writeMap.Any(arg => arg.Id == reader.ElementId)) { // copying data as is var buffer = new byte[reader.ElementSize]; reader.ReadBinary(buffer, 0, (int) reader.ElementSize); infoWriter.Write(reader.ElementId, buffer); } } // write title/app in case it was not present! foreach (var e in writeMap.Where(arg => !string.IsNullOrEmpty(arg.Value))) { infoWriter.WriteUtf(e.Id, e.Value); } var outStream = new MemoryStream(_dataLength); var writer = new EbmlWriter(outStream); writer.Write(MatroskaDtd.Segment.Info.Identifier, infoStream.ToArray()); var extraByteCount = _dataLength - outStream.Position; if (extraByteCount != 0) { var extraHLen = StandardDtd.Void.Identifier.Length + 2; var blankDataLen = (int) (extraByteCount - extraHLen); if (blankDataLen < 0) { throw new InvalidOperationException(string.Format("Not enough space to put the new data, {0} bytes to feet", -blankDataLen)); } writer.WriteElementHeader(StandardDtd.Void.Identifier, VInt.EncodeSize((ulong)blankDataLen, 2)); writer.Write(new byte[blankDataLen], 0, blankDataLen); } if (outStream.Length != _dataLength) throw new InvalidOperationException("Failed to prepare modified data - block length mismatch"); _stream.Position = _dataStart; _stream.Write(outStream.ToArray(), 0, _dataLength); }
private void ReadData(Stream src) { var reader = new EbmlReader(src); var readMap = new[] { new {Element = MatroskaDtd.Segment.Info.Title, Code = new Action(() => _title = reader.ReadUtf())}, new {Element = MatroskaDtd.Segment.Info.WritingApp, Code = new Action(() => _writingApp = reader.ReadUtf())}, new {Element = MatroskaDtd.Segment.Info.MuxingApp, Code = new Action(() => MuxingApp = reader.ReadUtf())}, new {Element = MatroskaDtd.Segment.Info.Duration, Code = new Action(() => Duration = TimeSpan.FromMilliseconds(reader.ReadFloat()))}, }; if (!reader.LocateElement(MatroskaDtd.Segment)) throw new InvalidDataException("Failed to locate Segment"); reader.EnterContainer(); var segmentInfoIdentifier = MatroskaDtd.Segment.Info.Identifier; // support for Void block right before SegmentInfo var priorElementId = VInt.MakeId(0); var priorElementStart = -1l; // locate SegmentInfo and track its predesessor while (reader.ReadNext()) { if (reader.ElementId == segmentInfoIdentifier) break; priorElementId = reader.ElementId; priorElementStart = reader.ElementPosition; } if (reader.ElementId != segmentInfoIdentifier) throw new InvalidDataException("Failed to locate Segment"); _dataStart = priorElementId == StandardDtd.Void.Identifier ? priorElementStart : reader.ElementPosition; var oldDataStart = reader.ElementPosition; reader.EnterContainer(); while (reader.ReadNext()) { var entry = readMap.FirstOrDefault(arg => arg.Element.Identifier == reader.ElementId); if (entry != null) entry.Code(); } reader.LeaveContainer(); // getting start of the next element reader.ReadNext(); if (reader.ElementId == StandardDtd.Void.Identifier) { reader.ReadNext(); } _dataLength = (int)(reader.ElementPosition - _dataStart); var oldDataLen = (int)(reader.ElementPosition - oldDataStart); _oldSegmentInfoData = new byte[oldDataLen]; _stream.Seek(oldDataStart, SeekOrigin.Begin); _stream.Read(_oldSegmentInfoData, 0, oldDataLen); }
public void ReusesNextFiller() { var stream = new MemoryStream(); var writer = new EbmlWriter(stream); writer.Write(VInt.MakeId(122), 321); using (var segment = writer.StartMasterElement(MatroskaDtd.Segment.Identifier)) { using (var segmentInfo = segment.StartMasterElement(MatroskaDtd.Segment.Info.Identifier)) { segmentInfo.WriteUtf(MatroskaDtd.Segment.Info.Title.Identifier, "Test data"); } // write some dummy data segment.Write(StandardDtd.Void.Identifier, new byte[1000]); segment.Write(VInt.MakeId(123), 123); // marker } stream.Position = 0; // act var infoReader = new SegmentInfoUpdater(); infoReader.Open(stream); infoReader.Title = new string('a', 500); infoReader.Write(); // verify the stream is correct stream.Position = 0; var reader = new EbmlReader(stream); reader.ReadNext(); Assert.AreEqual(122, reader.ElementId.Value, "start marker"); Assert.AreEqual(321, reader.ReadInt()); reader.ReadNext(); Assert.AreEqual(MatroskaDtd.Segment.Identifier, reader.ElementId); reader.EnterContainer(); reader.ReadNext(); Assert.AreEqual(MatroskaDtd.Segment.Info.Identifier, reader.ElementId); Assert.Greater(reader.ElementSize, 500); reader.ReadNext(); Assert.AreEqual(StandardDtd.Void.Identifier, reader.ElementId); reader.ReadNext(); Assert.AreEqual(123, reader.ElementId.Value, "end data marker"); Assert.AreEqual(123, reader.ReadInt()); }
private void GetMatroskaTags() { MatroskaElementDescriptorProvider medp = new MatroskaElementDescriptorProvider(); using (var fs = new FileStream(path + "/" + fullName, FileMode.Open, FileAccess.Read)) using (EbmlReader ebmlReader = new EbmlReader(fs)) { //Console.WriteLine("--------------" + labelName + "----------------"); var segmentFound = ebmlReader.LocateElement(MatroskaElementDescriptorProvider.Segment); if (segmentFound) { ebmlReader.EnterContainer(); while (ebmlReader.ReadNext()) { var descriptor = medp.GetElementDescriptor(ebmlReader.ElementId); if (descriptor == null) continue; if (descriptor.Name == "Tracks") { ebmlReader.EnterContainer(); while (ebmlReader.ReadNext()) { var trackDescriptor = medp.GetElementDescriptor(ebmlReader.ElementId); if (trackDescriptor == null) continue; if (trackDescriptor.Name == "TrackEntry") { ebmlReader.EnterContainer(); long trackType = 0; string trackLanguage = null; while (ebmlReader.ReadNext()) { var trackEntryDescriptor = medp.GetElementDescriptor(ebmlReader.ElementId); if (trackEntryDescriptor == null) continue; if (trackEntryDescriptor.Name == "Video") { ebmlReader.EnterContainer(); while (ebmlReader.ReadNext()) { var videoDescriptor = medp.GetElementDescriptor(ebmlReader.ElementId); if (videoDescriptor == null) continue; if (videoDescriptor.Name == "PixelWidth") { width = ebmlReader.ReadInt(); } else if (videoDescriptor.Name == "PixelHeight") { height = ebmlReader.ReadInt(); } } ebmlReader.LeaveContainer(); } else if (trackEntryDescriptor.Name == "TrackType") { trackType = ebmlReader.ReadInt(); } else if (trackEntryDescriptor.Name == "Language") { trackLanguage = ebmlReader.ReadUtf(); if (trackType == 0x11) //subtitle { listLanguageSubtitle.Add(trackLanguage); //Console.WriteLine("subtitle : ->" + trackLanguage + "<-"); } else if (trackType == 2) //audio { listLanguageAudio.Add(trackLanguage); //Console.WriteLine("audio : ->" + trackLanguage + "<-"); } } } ebmlReader.LeaveContainer(); } } ebmlReader.LeaveContainer(); break; } } } } }
private static void AnalizeTrackEntry(EbmlReader ebmlReader, MatroskaElementDescriptorProvider medp, ResultOfParsingMKV resPars, StringBuilder sb, string GroupName = "", string add = "") { ulong TrackNumber = 0; ulong TrackUID = 0; ulong TrackType = 0; ulong FlagDefault = 0; ulong FlagLacing = 0; string CodecID = ""; string Name = ""; ulong DefaultDuration = 0; string Language = ""; ebmlReader.EnterContainer(); while (ebmlReader.ReadNext()) { var descriptor = medp.GetElementDescriptor(ebmlReader.ElementId); if (descriptor == null) { sb.Append(add + "undefined \r\n"); continue; } string dName = descriptor.Name; sb.Append(add + dName); switch (descriptor.Type) { case ElementType.MasterElement: sb.Append("\r\n"); //ReadContainer(ebmlReader, medp, dicSub, CurrentClusterTimeCode, sb, descriptor.Name, add + " "); break; case ElementType.AsciiString: string strVal = ebmlReader.ReadAscii(); if(dName == "CodecID") CodecID = strVal; if (dName == "Language") Language = strVal; sb.Append(" = " + strVal); break; case ElementType.Binary: break; case ElementType.Date: sb.Append(" = " + ebmlReader.ReadDate()); break; case ElementType.Float: double flVal = ebmlReader.ReadFloat(); sb.Append(" = " + flVal); break; case ElementType.None: sb.Append(" (none)"); break; case ElementType.SignedInteger: sb.Append(" = " + ebmlReader.ReadInt()); break; case ElementType.UnsignedInteger: ulong ulVal = ebmlReader.ReadUInt(); if(dName == "TrackNumber") TrackNumber = ulVal; if(dName == "TrackType") TrackType = ulVal; if(dName == "FlagDefault") FlagDefault = ulVal; if(dName == "FlagLacing ") FlagLacing = ulVal; if(dName == "DefaultDuration") DefaultDuration = ulVal; if (dName == "TrackUID") TrackUID = ulVal; sb.Append(" = " + ulVal); break; case ElementType.Utf8String: string utfStr = ebmlReader.ReadUtf(); if (dName == "Name") Name = utfStr; sb.Append(" = " + utfStr); break; } sb.Append("\r\n"); } ebmlReader.LeaveContainer(); // If it's subtitles track if (TrackType == 17) { Subtitles sub = new Subtitles(); sub.Items = new SynchronizedObservableCollection<SubtitleItem>(); sub.Language = Language.Length == 0 ? "eng" : Language; sub.Type = Name; sub.Format = CodecID; sub.TrackUID = (long)TrackUID; resPars.dicSub.Add(Convert.ToInt16(TrackNumber),sub); } // If it's subtitles track if (TrackType == 2) { AudioTrack aud = new AudioTrack(); aud.Language = Language.Length == 0 ? "eng" : Language; aud.CodecID = CodecID; aud.Number = resPars.AudioTracks.Count + 1; resPars.AudioTracks.Add(aud); } }
private static void ReadContainer(EbmlReader ebmlReader, MatroskaElementDescriptorProvider medp, ResultOfParsingMKV resPars, ulong CurrentClusterTimeCode, StringBuilder sb, string GroupName = "", string add = "") { ebmlReader.EnterContainer(); while (ebmlReader.ReadNext()) { var descriptor = medp.GetElementDescriptor(ebmlReader.ElementId); if (descriptor == null) { sb.Append(add + "undefined \r\n"); continue; } string dName = descriptor.Name; sb.Append(add + dName); if (dName == "TrackEntry") { AnalizeTrackEntry(ebmlReader,medp,resPars,sb,GroupName,add); continue; } switch (descriptor.Type) { case ElementType.MasterElement: sb.Append("\r\n"); ReadContainer(ebmlReader, medp, resPars, CurrentClusterTimeCode, sb,descriptor.Name, add + " "); break; case ElementType.AsciiString: sb.Append(" = " + ebmlReader.ReadAscii()); break; case ElementType.Binary: if (GroupName == "BlockGroup" && (dName == "Block" || dName == "SimpleBlock")) { int lSize = ebmlReader.ElementSize > 1000?1000:Convert.ToInt16(ebmlReader.ElementSize); byte[] arr = new byte[lSize]; ebmlReader.ReadBinary(arr, 0, lSize); int TrackNumber = arr[0] & 0x0F; ulong DurationFromCluster = Convert.ToUInt64(arr[1] * 0xFF + arr[2]); if (resPars.dicSub.ContainsKey(TrackNumber)) { Subtitles lsub = resPars.dicSub[TrackNumber]; SubtitleItem subitem = new SubtitleItem(); lsub.Items.Add(subitem); //subitem.Text = System.Text.Encoding.ASCII.GetString(arr, 4, lSize-4); subitem.Text = System.Text.Encoding.UTF8.GetString(arr, 4, lSize - 4); subitem.TimeStart = ((int)(CurrentClusterTimeCode + DurationFromCluster)); // reading the BlockDuration ebmlReader.ReadNext(); ulong BlockDuration = ebmlReader.ReadUInt(); subitem.TimeEnd = subitem.TimeStart + ((int)BlockDuration); } } sb.Append(" (binary size " + ebmlReader.ElementSize + ")"); break; case ElementType.Date: sb.Append(" = " + ebmlReader.ReadDate()); break; case ElementType.Float: double flVal = ebmlReader.ReadFloat(); sb.Append(" = " + flVal); break; case ElementType.None: sb.Append(" (none)"); break; case ElementType.SignedInteger: sb.Append(" = " + ebmlReader.ReadInt()); break; case ElementType.UnsignedInteger: ulong ulVal = ebmlReader.ReadUInt(); if (GroupName == "Cluster" && dName == "Timecode") { CurrentClusterTimeCode = ulVal; } sb.Append(" = " + ulVal); break; case ElementType.Utf8String: sb.Append(" = " + ebmlReader.ReadUtf()); break; } sb.Append("\r\n"); } ebmlReader.LeaveContainer(); }