public static List <TransportStreamSubtitle> GetDvbSup(string fileName) { byte[] pesData = File.ReadAllBytes(fileName); var list = new List <DvbSubPes>(); int index = 0; while (index < pesData.Length - 10) { var pes = new DvbSubPes(index, pesData); index = pes.Length + 1; list.Add(pes); } var subtitles = new List <TransportStreamSubtitle>(); int seconds = 0; for (int i = 0; i < list.Count; i++) { var pes = list[i]; pes.ParseSegments(); if (pes.ObjectDataList.Count > 0) { var sub = new TransportStreamSubtitle(); sub.StartMilliseconds = (ulong)seconds * 1000UL; seconds += pes.PageCompositions[0].PageTimeOut; if (pes.PageCompositions.Count > 0) { sub.EndMilliseconds = sub.StartMilliseconds + (ulong)pes.PageCompositions[0].PageTimeOut * 1000UL; } else { sub.EndMilliseconds = sub.StartMilliseconds + 2500; } sub.Pes = pes; subtitles.Add(sub); } if (pes.PageCompositions.Count > 0) { seconds += pes.PageCompositions[0].PageTimeOut; } } return(subtitles); }
public static List<TransportStreamSubtitle> GetDvbSup(string fileName) { byte[] pesData = File.ReadAllBytes(fileName); var list = new List<DvbSubPes>(); int index = 0; while (index < pesData.Length - 10) { var pes = new DvbSubPes(index, pesData); index = pes.Length + 1; list.Add(pes); } var subtitles = new List<TransportStreamSubtitle>(); int seconds = 0; for (int i = 0; i < list.Count; i++) { var pes = list[i]; pes.ParseSegments(); if (pes.ObjectDataList.Count > 0) { var sub = new TransportStreamSubtitle(); sub.StartMilliseconds = (ulong)seconds * 1000UL; seconds += pes.PageCompositions[0].PageTimeOut; if (pes.PageCompositions.Count > 0) sub.EndMilliseconds = sub.StartMilliseconds + (ulong)pes.PageCompositions[0].PageTimeOut * 1000UL; else sub.EndMilliseconds = sub.StartMilliseconds + 2500; sub.Pes = pes; subtitles.Add(sub); } if (pes.PageCompositions.Count > 0) { seconds += pes.PageCompositions[0].PageTimeOut; } } return subtitles; }
/// <summary> /// Can be used with e.g. MemoryStream or FileStream /// </summary> /// <param name="ms">Input stream</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>(); // ProgramAssociationTables = new List<Packet>(); ms.Position = 0; const int packetLength = 188; DetectFormat(ms); var packetBuffer = new byte[packetLength]; var m2TsTimeCodeBuffer = new byte[4]; long position = 0; // 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); //var tc = (m2tsTimeCodeBuffer[0]<< 24) | (m2tsTimeCodeBuffer[1] << 16) | (m2tsTimeCodeBuffer[2] << 8) | (m2tsTimeCodeBuffer[3]); 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) { //var sb = new StringBuilder(); //sb.AppendLine("PacketNo: " + TotalNumberOfPackets + 1); //sb.AppendLine("PacketId: " + packet.PacketId); //sb.AppendLine(); //sb.AppendLine("TransportErrorIndicator: " + packet.TransportErrorIndicator); //sb.AppendLine("PayloadUnitStartIndicator: " + packet.PayloadUnitStartIndicator); //sb.AppendLine("TransportPriority: " + packet.TransportPriority); //sb.AppendLine("ScramblingControl: " + packet.ScramblingControl); //sb.AppendLine("AdaptationFieldExist: " + packet.AdaptationFieldControl); //sb.AppendLine("ContinuityCounter: " + packet.ContinuityCounter); //sb.AppendLine(); //if (packet.AdaptationField != null) //{ //sb.AppendLine("AdaptationFieldLength: " + packet.AdaptationField.Length); //sb.AppendLine("DiscontinuityIndicator: " + packet.AdaptationField.DiscontinuityIndicator); //sb.AppendLine("RandomAccessIndicator: " + packet.AdaptationField.RandomAccessIndicator); //sb.AppendLine("ElementaryStreamPriorityIndicator: " + packet.AdaptationField.ElementaryStreamPriorityIndicator); //sb.AppendLine("PcrFlag: " + packet.AdaptationField.PcrFlag); //sb.AppendLine("OpcrFlag: " + packet.AdaptationField.OpcrFlag); //sb.AppendLine("SplicingPointFlag: " + packet.AdaptationField.SplicingPointFlag); //sb.AppendLine("TransportPrivateDataFlag: " + packet.AdaptationField.TransportPrivateDataFlag); //sb.AppendLine("AdaptationFieldExtensionFlag: " + packet.AdaptationField.AdaptationFieldExtensionFlag); //sb.AppendLine(); //} //sb.AppendLine("TableId: " + packet.ProgramAssociationTable.TableId); //sb.AppendLine("SectionLength: " + packet.ProgramAssociationTable.SectionLength); //sb.AppendLine("TransportStreamId: " + packet.ProgramAssociationTable.TransportStreamId); //sb.AppendLine("VersionNumber: " + packet.ProgramAssociationTable.VersionNumber); //sb.AppendLine("CurrentNextIndicator: " + packet.ProgramAssociationTable.CurrentNextIndicator); //sb.AppendLine("SectionNumber: " + packet.ProgramAssociationTable.SectionNumber); //sb.AppendLine("LastSectionNumber: " + packet.ProgramAssociationTable.LastSectionNumber); //ProgramAssociationTables.Add(packet); } else if (packet.IsPrivateStream1 || SubtitlePacketIds.Contains(packet.PacketId)) { TotalNumberOfPrivateStream1++; SubtitlePackets.Add(packet); if (!SubtitlePacketIds.Contains(packet.PacketId)) { SubtitlePacketIds.Add(packet.PacketId); } 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) //{ //} } if (callback != null) { callback.Invoke(ms.Position, transportStreamLength); } } TotalNumberOfPackets++; position += packetLength; } 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); var startMsList = new List<ulong>(); var endMsList = new List<ulong>(); foreach (var item in list) { item.WriteToStream(bdMs); if (item.DataIdentifier == 0x16) { if (startMsList.Count <= endMsList.Count) startMsList.Add(item.PresentationTimestampToMilliseconds()); else endMsList.Add(item.PresentationTimestampToMilliseconds()); } //else if (item.DataBuffer[0] == 0x80) //{ // TODO: Load bd sub after 0x80, so we can be sure to get correct time code??? // endMsList.Add(item.PresentationTimestampToMilliseconds() / 90); //} } SubtitlesLookup.Add(pid, list); bdMs.Position = 0; var sb = new StringBuilder(); var bdList = BluRaySupParser.ParseBluRaySup(bdMs, sb, true); if (bdList.Count > 0) { var subList = new List<TransportStreamSubtitle>(); for (int k = 0; k < bdList.Count; k++) { var bdSup = bdList[k]; ulong startMs = 0; if (k < startMsList.Count) startMs = startMsList[k]; ulong endMs = 0; if (k < endMsList.Count) endMs = endMsList[k]; subList.Add(new TransportStreamSubtitle(bdSup, startMs, endMs, (ulong)((FirstVideoPts + 45) / 90.0))); } DvbSubtitlesLookup.Add(pid, subList); } } SubtitlePacketIds.Clear(); foreach (int key in DvbSubtitlesLookup.Keys) SubtitlePacketIds.Add(key); SubtitlePacketIds.Sort(); return; } // check for SubPictureStreamId = 32 SubtitlesLookup = new Dictionary<int, List<DvbSubPes>>(); foreach (int pid in SubtitlePacketIds) { var list = MakeSubtitlePesPackets(pid); bool hasImageSubtitles = false; foreach (var item in list) { if (item.IsDvbSubpicture) { hasImageSubtitles = true; break; } } if (hasImageSubtitles) { SubtitlesLookup.Add(pid, list); } } 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 + 45) / 90.0); foreach (int pid in SubtitlePacketIds) { var subtitles = new List<TransportStreamSubtitle>(); var list = GetSubtitlePesPackets(pid); if (list != null) { for (int i = 0; i < list.Count; i++) { var pes = list[i]; pes.ParseSegments(); if (pes.ObjectDataList.Count > 0) { var sub = new TransportStreamSubtitle(); sub.StartMilliseconds = pes.PresentationTimestampToMilliseconds(); sub.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 + 3500; 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(); }
/// <summary> /// Can be used with e.g. MemoryStream or FileStream /// </summary> /// <param name="ms">Input stream</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>(); // ProgramAssociationTables = new List<Packet>(); ms.Position = 0; const int packetLength = 188; DetectFormat(ms); var packetBuffer = new byte[packetLength]; var m2TsTimeCodeBuffer = new byte[4]; long position = 0; // 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); //var tc = (m2tsTimeCodeBuffer[0]<< 24) | (m2tsTimeCodeBuffer[1] << 16) | (m2tsTimeCodeBuffer[2] << 8) | (m2tsTimeCodeBuffer[3]); 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) { //var sb = new StringBuilder(); //sb.AppendLine("PacketNo: " + TotalNumberOfPackets + 1); //sb.AppendLine("PacketId: " + packet.PacketId); //sb.AppendLine(); //sb.AppendLine("TransportErrorIndicator: " + packet.TransportErrorIndicator); //sb.AppendLine("PayloadUnitStartIndicator: " + packet.PayloadUnitStartIndicator); //sb.AppendLine("TransportPriority: " + packet.TransportPriority); //sb.AppendLine("ScramblingControl: " + packet.ScramblingControl); //sb.AppendLine("AdaptationFieldExist: " + packet.AdaptationFieldControl); //sb.AppendLine("ContinuityCounter: " + packet.ContinuityCounter); //sb.AppendLine(); //if (packet.AdaptationField != null) //{ //sb.AppendLine("AdaptationFieldLength: " + packet.AdaptationField.Length); //sb.AppendLine("DiscontinuityIndicator: " + packet.AdaptationField.DiscontinuityIndicator); //sb.AppendLine("RandomAccessIndicator: " + packet.AdaptationField.RandomAccessIndicator); //sb.AppendLine("ElementaryStreamPriorityIndicator: " + packet.AdaptationField.ElementaryStreamPriorityIndicator); //sb.AppendLine("PcrFlag: " + packet.AdaptationField.PcrFlag); //sb.AppendLine("OpcrFlag: " + packet.AdaptationField.OpcrFlag); //sb.AppendLine("SplicingPointFlag: " + packet.AdaptationField.SplicingPointFlag); //sb.AppendLine("TransportPrivateDataFlag: " + packet.AdaptationField.TransportPrivateDataFlag); //sb.AppendLine("AdaptationFieldExtensionFlag: " + packet.AdaptationField.AdaptationFieldExtensionFlag); //sb.AppendLine(); //} //sb.AppendLine("TableId: " + packet.ProgramAssociationTable.TableId); //sb.AppendLine("SectionLength: " + packet.ProgramAssociationTable.SectionLength); //sb.AppendLine("TransportStreamId: " + packet.ProgramAssociationTable.TransportStreamId); //sb.AppendLine("VersionNumber: " + packet.ProgramAssociationTable.VersionNumber); //sb.AppendLine("CurrentNextIndicator: " + packet.ProgramAssociationTable.CurrentNextIndicator); //sb.AppendLine("SectionNumber: " + packet.ProgramAssociationTable.SectionNumber); //sb.AppendLine("LastSectionNumber: " + packet.ProgramAssociationTable.LastSectionNumber); //ProgramAssociationTables.Add(packet); } else if (packet.IsPrivateStream1 || SubtitlePacketIds.Contains(packet.PacketId)) { TotalNumberOfPrivateStream1++; SubtitlePackets.Add(packet); if (!SubtitlePacketIds.Contains(packet.PacketId)) { SubtitlePacketIds.Add(packet.PacketId); } 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) //{ //} } if (callback != null) { callback.Invoke(ms.Position, transportStreamLength); } } TotalNumberOfPackets++; position += packetLength; } 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); var startMsList = new List <ulong>(); var endMsList = new List <ulong>(); foreach (var item in list) { item.WriteToStream(bdMs); if (item.DataIdentifier == 0x16) { if (startMsList.Count <= endMsList.Count) { startMsList.Add(item.PresentationTimestampToMilliseconds()); } else { endMsList.Add(item.PresentationTimestampToMilliseconds()); } } //else if (item.DataBuffer[0] == 0x80) //{ // TODO: Load bd sub after 0x80, so we can be sure to get correct time code??? // endMsList.Add(item.PresentationTimestampToMilliseconds() / 90); //} } SubtitlesLookup.Add(pid, list); bdMs.Position = 0; var sb = new StringBuilder(); var bdList = BluRaySupParser.ParseBluRaySup(bdMs, sb, true); if (bdList.Count > 0) { var subList = new List <TransportStreamSubtitle>(); for (int k = 0; k < bdList.Count; k++) { var bdSup = bdList[k]; ulong startMs = 0; if (k < startMsList.Count) { startMs = startMsList[k]; } ulong endMs = 0; if (k < endMsList.Count) { endMs = endMsList[k]; } subList.Add(new TransportStreamSubtitle(bdSup, startMs, endMs, (ulong)((FirstVideoPts + 45) / 90.0))); } DvbSubtitlesLookup.Add(pid, subList); } } SubtitlePacketIds.Clear(); foreach (int key in DvbSubtitlesLookup.Keys) { SubtitlePacketIds.Add(key); } SubtitlePacketIds.Sort(); return; } // check for SubPictureStreamId = 32 SubtitlesLookup = new Dictionary <int, List <DvbSubPes> >(); foreach (int pid in SubtitlePacketIds) { var list = MakeSubtitlePesPackets(pid); bool hasImageSubtitles = false; foreach (var item in list) { if (item.IsDvbSubpicture) { hasImageSubtitles = true; break; } } if (hasImageSubtitles) { SubtitlesLookup.Add(pid, list); } } 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 + 45) / 90.0); foreach (int pid in SubtitlePacketIds) { var subtitles = new List <TransportStreamSubtitle>(); var list = GetSubtitlePesPackets(pid); if (list != null) { for (int i = 0; i < list.Count; i++) { var pes = list[i]; pes.ParseSegments(); if (pes.ObjectDataList.Count > 0) { var sub = new TransportStreamSubtitle(); sub.StartMilliseconds = pes.PresentationTimestampToMilliseconds(); sub.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 + 3500; } 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(); }