public List <DvbSubPes> GetSubtitlePesPackets(int packetId) { if (SubtitlesLookup.ContainsKey(packetId)) { return(SubtitlesLookup[packetId]); } return(null); }
private ulong?ProcessPackages(int packetId, Dictionary <int, List <int> > teletextPages, Dictionary <int, List <DvbSubPes> > teletextPesList, ulong?firstVideoMs) { var list = MakeSubtitlePesPackets(packetId, SubtitlePackets); if (list.Count == 0) { return(firstVideoMs); } if (!firstVideoMs.HasValue) { foreach (var pes in list) { if (pes.PresentationTimestamp.HasValue) { firstVideoMs = pes.PresentationTimestampToMilliseconds(); break; } } } if (list.Any(p => p.IsDvbSubPicture) || IsM2TransportStream) { if (SubtitlesLookup.ContainsKey(packetId)) { SubtitlesLookup[packetId].AddRange(list); } else { SubtitlesLookup.Add(packetId, list); } } foreach (var item in list.Where(p => p.IsTeletext)) { foreach (var pageNumber in item.PrepareTeletext().Where(p => p > 0)) { if (!teletextPages.ContainsKey(packetId)) { teletextPages.Add(packetId, new List <int> { pageNumber }); } else { if (!teletextPages[packetId].Contains(pageNumber)) { teletextPages[packetId].Add(pageNumber); } } } if (teletextPesList.ContainsKey(packetId)) { teletextPesList[packetId].Add(item); } else { teletextPesList.Add(packetId, new List <DvbSubPes> { item }); } } return(firstVideoMs); }
/// <summary> /// Can be used with e.g. MemoryStream or FileStream /// </summary> /// <param name="ms">Input stream</param> /// <param name="callback">Optional callback event to follow progress</param> public void Parse(Stream ms, LoadTransportStreamCallback callback) { bool firstVideoPtsFound = false; IsM2TransportStream = false; NumberOfNullPackets = 0; TotalNumberOfPackets = 0; TotalNumberOfPrivateStream1 = 0; TotalNumberOfPrivateStream1Continuation0 = 0; SubtitlePacketIds = new List <int>(); SubtitlePackets = new List <Packet>(); ms.Position = 0; const int packetLength = 188; IsM2TransportStream = IsM3TransportStream(ms); var packetBuffer = new byte[packetLength]; var m2TsTimeCodeBuffer = new byte[4]; long position = 0; SubtitlesLookup = new Dictionary <int, List <DvbSubPes> >(); // check for Topfield .rec file ms.Seek(position, SeekOrigin.Begin); ms.Read(m2TsTimeCodeBuffer, 0, 3); if (m2TsTimeCodeBuffer[0] == 0x54 && m2TsTimeCodeBuffer[1] == 0x46 && m2TsTimeCodeBuffer[2] == 0x72) { position = 3760; } long transportStreamLength = ms.Length; while (position < transportStreamLength) { ms.Seek(position, SeekOrigin.Begin); if (IsM2TransportStream) { ms.Read(m2TsTimeCodeBuffer, 0, m2TsTimeCodeBuffer.Length); position += m2TsTimeCodeBuffer.Length; } ms.Read(packetBuffer, 0, packetLength); byte syncByte = packetBuffer[0]; if (syncByte == Packet.SynchronizationByte) { var packet = new Packet(packetBuffer); if (packet.IsNullPacket) { NumberOfNullPackets++; } else if (!firstVideoPtsFound && packet.IsVideoStream) { if (packet.Payload != null && packet.Payload.Length > 10) { int presentationTimestampDecodeTimestampFlags = packet.Payload[7] >> 6; if (presentationTimestampDecodeTimestampFlags == Helper.B00000010 || presentationTimestampDecodeTimestampFlags == Helper.B00000011) { FirstVideoPts = (ulong)packet.Payload[9 + 4] >> 1; FirstVideoPts += (ulong)packet.Payload[9 + 3] << 7; FirstVideoPts += (ulong)(packet.Payload[9 + 2] & Helper.B11111110) << 14; FirstVideoPts += (ulong)packet.Payload[9 + 1] << 22; FirstVideoPts += (ulong)(packet.Payload[9 + 0] & Helper.B00001110) << 29; firstVideoPtsFound = true; } } } else if (packet.IsProgramAssociationTable) { } else if (packet.IsPrivateStream1 || SubtitlePacketIds.Contains(packet.PacketId)) { TotalNumberOfPrivateStream1++; if (!SubtitlePacketIds.Contains(packet.PacketId)) { SubtitlePacketIds.Add(packet.PacketId); } if (!IsM2TransportStream && packet.PayloadUnitStartIndicator) { var list = MakeSubtitlePesPackets(packet.PacketId, SubtitlePackets); bool hasImageSubtitles = false; foreach (var item in list) { if (item.IsDvbSubpicture) { hasImageSubtitles = true; break; } } if (hasImageSubtitles) { if (SubtitlesLookup.ContainsKey(packet.PacketId)) { SubtitlesLookup[packet.PacketId].AddRange(list); } else { SubtitlesLookup.Add(packet.PacketId, list); } } SubtitlePackets.RemoveAll(p => p.PacketId == packet.PacketId); } SubtitlePackets.Add(packet); if (packet.ContinuityCounter == 0) { TotalNumberOfPrivateStream1Continuation0++; //int pesExtensionlength = 0; //if (12 + packet.AdaptionFieldLength < packetBuffer.Length) // pesExtensionlength = 0xFF & packetBuffer[12 + packet.AdaptionFieldLength]; //int pesOffset = 13 + packet.AdaptionFieldLength + pesExtensionlength; //bool isTeletext = (pesExtensionlength == 0x24 && (0xFF & packetBuffer[pesOffset]) >> 4 == 1); //// workaround uk freesat teletext //if (!isTeletext) // isTeletext = (pesExtensionlength == 0x24 && (0xFF & packetBuffer[pesOffset]) == 0x99); //if (!isTeletext) //{ //} } } TotalNumberOfPackets++; position += packetLength; if (TotalNumberOfPackets % 100000 == 0) { callback.Invoke(ms.Position, transportStreamLength); } } else { position++; } } if (IsM2TransportStream) { DvbSubtitlesLookup = new Dictionary <int, List <TransportStreamSubtitle> >(); SubtitlesLookup = new Dictionary <int, List <DvbSubPes> >(); foreach (int pid in SubtitlePacketIds) { var bdMs = new MemoryStream(); var list = MakeSubtitlePesPackets(pid, SubtitlePackets); var currentList = new List <DvbSubPes>(); var sb = new StringBuilder(); var subList = new List <TransportStreamSubtitle>(); for (var index = 0; index < list.Count; index++) { var item = list[index]; item.WriteToStream(bdMs); currentList.Add(item); if (item.DataIdentifier == 0x80) { bdMs.Position = 0; var bdList = BluRaySupParser.ParseBluRaySup(bdMs, sb, true); if (bdList.Count > 0) { var startMs = currentList.First().PresentationTimestampToMilliseconds(); var endMs = index + 1 < list.Count ? list[index + 1].PresentationTimestampToMilliseconds() : startMs + (ulong)Configuration.Settings.General.NewEmptyDefaultMs; subList.Add(new TransportStreamSubtitle(bdList[0], startMs, endMs, (ulong)(FirstVideoPts / 90.0))); } bdMs = new MemoryStream(); currentList.Clear(); } } SubtitlesLookup.Add(pid, list); DvbSubtitlesLookup.Add(pid, subList); } SubtitlePacketIds.Clear(); foreach (int key in DvbSubtitlesLookup.Keys) { SubtitlePacketIds.Add(key); } SubtitlePacketIds.Sort(); return; } // check for SubPictureStreamId = 32 foreach (int pid in SubtitlePacketIds) { var list = MakeSubtitlePesPackets(pid, SubtitlePackets); bool hasImageSubtitles = false; foreach (var item in list) { if (item.IsDvbSubpicture) { hasImageSubtitles = true; break; } } if (hasImageSubtitles) { if (SubtitlesLookup.ContainsKey(pid)) { SubtitlesLookup[pid].AddRange(list); } else { SubtitlesLookup.Add(pid, list); } } SubtitlePackets.RemoveAll(p => p.PacketId == pid); } SubtitlePacketIds.Clear(); foreach (int key in SubtitlesLookup.Keys) { SubtitlePacketIds.Add(key); } SubtitlePacketIds.Sort(); // Merge packets and set start/end time DvbSubtitlesLookup = new Dictionary <int, List <TransportStreamSubtitle> >(); var firstVideoMs = (ulong)(FirstVideoPts / 90.0); foreach (int pid in SubtitlePacketIds) { var subtitles = new List <TransportStreamSubtitle>(); var list = ParseAndRemoveEmpty(GetSubtitlePesPackets(pid)); for (int i = 0; i < list.Count; i++) { var pes = list[i]; pes.ParseSegments(); if (pes.ObjectDataList.Count > 0) { var sub = new TransportStreamSubtitle { StartMilliseconds = pes.PresentationTimestampToMilliseconds(), Pes = pes }; if (i + 1 < list.Count && list[i + 1].PresentationTimestampToMilliseconds() > 25) { sub.EndMilliseconds = list[i + 1].PresentationTimestampToMilliseconds() - 25; } if (sub.EndMilliseconds < sub.StartMilliseconds || sub.EndMilliseconds - sub.StartMilliseconds > (ulong)Configuration.Settings.General.SubtitleMaximumDisplayMilliseconds) { sub.EndMilliseconds = sub.StartMilliseconds + (ulong)Configuration.Settings.General.SubtitleMaximumDisplayMilliseconds; } subtitles.Add(sub); if (sub.StartMilliseconds < firstVideoMs) { firstVideoMs = sub.StartMilliseconds; } } } foreach (var s in subtitles) { s.OffsetMilliseconds = firstVideoMs; } DvbSubtitlesLookup.Add(pid, subtitles); } SubtitlePacketIds.Clear(); foreach (int key in DvbSubtitlesLookup.Keys) { if (DvbSubtitlesLookup[key].Count > 0) { SubtitlePacketIds.Add(key); } } SubtitlePacketIds.Sort(); }