public VobSubMergedPack(byte[] subPictureData, TimeSpan presentationTimestamp, int streamId, IdxParagraph idxLine) { SubPicture = new SubPicture(subPictureData); StartTime = presentationTimestamp; StreamId = streamId; IdxLine = idxLine; }
/// <summary> /// Demultiplex multiplexed packs together each streamId at a time + removing bad packs + fixing displaytimes /// </summary> /// <returns>List of complete packs each with a complete sub image</returns> public List <VobSubMergedPack> MergeVobSubPacks() { var list = new List <VobSubMergedPack>(); var pts = new TimeSpan(); var ms = new MemoryStream(); int streamId = 0; float ticksPerMillisecond = 90.000F; if (!IsPal) { ticksPerMillisecond = 90.090F; // TODO: What should this be for NTSC? } // get unique streamIds var uniqueStreamIds = new List <int>(); foreach (var p in VobSubPacks) { if (p.PacketizedElementaryStream != null && p.PacketizedElementaryStream.SubPictureStreamId.HasValue && !uniqueStreamIds.Contains(p.PacketizedElementaryStream.SubPictureStreamId.Value)) { uniqueStreamIds.Add(p.PacketizedElementaryStream.SubPictureStreamId.Value); } } IdxParagraph lastIdxParagraph = null; foreach (int uniqueStreamId in uniqueStreamIds) // packets must be merged in streamId order (so they don't get mixed) { foreach (var p in VobSubPacks) { if (p.PacketizedElementaryStream != null && p.PacketizedElementaryStream.SubPictureStreamId.HasValue && p.PacketizedElementaryStream.SubPictureStreamId.Value == uniqueStreamId) { if (p.PacketizedElementaryStream.PresentationTimestampDecodeTimestampFlags > 0) { if (lastIdxParagraph == null || p.IdxLine.FilePosition != lastIdxParagraph.FilePosition) { if (ms.Length > 0) { list.Add(new VobSubMergedPack(ms.ToArray(), pts, streamId, lastIdxParagraph)); } ms.Close(); ms = new MemoryStream(); pts = TimeSpan.FromMilliseconds(Convert.ToDouble(p.PacketizedElementaryStream.PresentationTimestamp / ticksPerMillisecond)); //90000F * 1000)); (PAL) streamId = p.PacketizedElementaryStream.SubPictureStreamId.Value; } } lastIdxParagraph = p.IdxLine; p.PacketizedElementaryStream.WriteToStream(ms); } } if (ms.Length > 0) { list.Add(new VobSubMergedPack(ms.ToArray(), pts, streamId, lastIdxParagraph)); ms.Close(); ms = new MemoryStream(); } } ms.Close(); // Remove any bad packs for (int i = list.Count - 1; i >= 0; i--) { VobSubMergedPack pack = list[i]; if (pack.SubPicture == null || pack.SubPicture.ImageDisplayArea.Width <= 3 || pack.SubPicture.ImageDisplayArea.Height <= 2) { list.RemoveAt(i); } else if (pack.EndTime.TotalSeconds - pack.StartTime.TotalSeconds < 0.1 && pack.SubPicture.ImageDisplayArea.Width <= 10 && pack.SubPicture.ImageDisplayArea.Height <= 10) { list.RemoveAt(i); } } // Fix subs with no duration (completely normal) or negative duration or duration > 10 seconds for (int i = 0; i < list.Count; i++) { VobSubMergedPack pack = list[i]; if (pack.SubPicture.Delay.TotalMilliseconds > 0) { pack.EndTime = pack.StartTime.Add(pack.SubPicture.Delay); } if (pack.EndTime < pack.StartTime || pack.EndTime.TotalSeconds - pack.StartTime.TotalSeconds > 10.0) { if (i + 1 < list.Count) { pack.EndTime = TimeSpan.FromMilliseconds(list[i].StartTime.TotalMilliseconds - 100); } else { pack.EndTime = TimeSpan.FromMilliseconds(pack.StartTime.TotalMilliseconds + 3000); } } } return(list); }
public Idx(string[] lines) { int languageIndex = 0; foreach (string line in lines) { if (_timeCodeLinePattern.IsMatch(line)) { IdxParagraph p = GetTimeCodeAndFilePosition(line); if (p != null) { IdxParagraphs.Add(p); } } else if (line.StartsWith("palette:", StringComparison.OrdinalIgnoreCase) && line.Length > 10) { string s = line.Substring("palette:".Length + 1); string[] colors = s.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); foreach (string hex in colors) { Palette.Add(HexToColor(hex)); } } else if (line.StartsWith("id:", StringComparison.OrdinalIgnoreCase) && line.Length > 4) { //id: en, index: 1 //id: es, index: 2 var parts = line.Split(new[] { ':', ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); if (parts.Length > 1) { string twoLetterLanguageId = parts[1]; string nativeName; if (IfoParser.LanguageCodes.Contains(twoLetterLanguageId)) { nativeName = IfoParser.LanguageNames[IfoParser.LanguageCodes.IndexOf(twoLetterLanguageId)]; } else { try { nativeName = CultureInfo.GetCultureInfoByIetfLanguageTag(twoLetterLanguageId).NativeName; } catch { nativeName = "Unknown (" + twoLetterLanguageId + ")"; } } if (parts.Length > 3 && parts[2].Equals("index", StringComparison.OrdinalIgnoreCase)) { int index; if (int.TryParse(parts[3], out index)) { languageIndex = index; } } // Use U+200E (LEFT-TO-RIGHT MARK) to support right-to-left scripts Languages.Add(string.Format("{0} \x200E(0x{1:x})", nativeName, languageIndex + 32)); languageIndex++; } } } }