Ejemplo n.º 1
0
        public List <int> PrepareTeletext()
        {
            var pages = new List <int>();
            var i     = 1;

            while (i <= _dataBuffer.Length - 6)
            {
                var dataUnitId  = _dataBuffer[i++];
                var dataUnitLen = _dataBuffer[i++];
                if (dataUnitId == (int)Teletext.DataUnitT.DataUnitEbuTeletextNonSubtitle || dataUnitId == (int)Teletext.DataUnitT.DataUnitEbuTeletextSubtitle)
                {
                    if (dataUnitLen == 44) // teletext payload has always size 44 bytes
                    {
                        // reverse endianness (via lookup table), ETS 300 706, chapter 7.1
                        for (var j = 0; j < dataUnitLen; j++)
                        {
                            _dataBuffer[i + j] = TeletextHamming.Reverse8[_dataBuffer[i + j]];
                        }
                        var pageNumber = Teletext.GetPageNumber(new Teletext.TeletextPacketPayload(_dataBuffer, i));
                        if (!pages.Contains(pageNumber) && pageNumber > 0)
                        {
                            pages.Add(pageNumber);
                        }
                    }
                }
                i += dataUnitLen;
            }
            return(pages);
        }
Ejemplo n.º 2
0
        public Dictionary <int, Paragraph> GetTeletext(TeletextRunSettings teletextRunSettings, int pageNumber, int pageNumberBcd)
        {
            var timestamp = PresentationTimestamp.HasValue ? PresentationTimestamp.Value / 90 : 40;

            // do not allow timestamp to go back - treat lower timestamp as a reset/overflow
            var lastTimestamp = teletextRunSettings.GetLastTimestamp(pageNumber);

            teletextRunSettings.SetLastTimestamp(pageNumber, timestamp);
            timestamp += teletextRunSettings.GetAddTimestamp(pageNumber);
            if (lastTimestamp > 0 && lastTimestamp > timestamp)
            {
                teletextRunSettings.SetAddTimestamp(pageNumber, lastTimestamp);
            }

            // offset all time codes if first timestamp in ts file is > 1 sec
            timestamp = teletextRunSettings.SubtractStartMs(timestamp);

            if (timestamp < 40)
            {
                timestamp = 40; // Teletext.cs will subtract 40 ms (1 frame @25 fps) and this value must not be below 0
            }

            var teletextPages = new Dictionary <int, Paragraph>();
            var i             = 1;

            while (i <= _dataBuffer.Length - 6)
            {
                var dataUnitId  = _dataBuffer[i++];
                var dataUnitLen = _dataBuffer[i++];
                if (dataUnitId == (int)Teletext.DataUnitT.DataUnitEbuTeletextNonSubtitle || dataUnitId == (int)Teletext.DataUnitT.DataUnitEbuTeletextSubtitle)
                {
                    if (dataUnitLen == 44) // teletext payload has always size 44 bytes
                    {
                        Teletext.ProcessTelxPacket((Teletext.DataUnitT)dataUnitId, new Teletext.TeletextPacketPayload(_dataBuffer, i), timestamp, teletextRunSettings, pageNumberBcd, pageNumber);
                    }
                }
                i += dataUnitLen;
            }

            if (teletextRunSettings.PageNumberAndParagraph.ContainsKey(pageNumber) && teletextRunSettings.PageNumberAndParagraph[pageNumber] != null)
            {
                if (teletextPages.ContainsKey(pageNumber))
                {
                    teletextPages[pageNumber] = teletextRunSettings.PageNumberAndParagraph[pageNumber];
                }
                else
                {
                    teletextPages.Add(pageNumber, teletextRunSettings.PageNumberAndParagraph[pageNumber]);
                }
            }
            teletextRunSettings.PageNumberAndParagraph.Clear();
            return(teletextPages);
        }
Ejemplo n.º 3
0
        /// <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)
        {
            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 SortedDictionary <int, List <DvbSubPes> >();
            TeletextSubtitlesLookup = new SortedDictionary <int, SortedDictionary <int, List <Paragraph> > >();
            var   teletextPesList = new Dictionary <int, List <DvbSubPes> >();
            var   teletextPages   = new Dictionary <int, List <int> >();
            ulong?firstMs         = null;
            ulong?firstVideoMs    = null;

            // 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;

            ms.Seek(position, SeekOrigin.Begin);
            while (position < transportStreamLength)
            {
                if (IsM2TransportStream)
                {
                    ms.Read(m2TsTimeCodeBuffer, 0, m2TsTimeCodeBuffer.Length);
                    position += m2TsTimeCodeBuffer.Length;
                }

                var bytesRead = ms.Read(packetBuffer, 0, packetLength);
                if (bytesRead < packetLength)
                {
                    break; // incomplete packet at end-of-file
                }

                if (packetBuffer[0] == Packet.SynchronizationByte)
                {
                    var packet = new Packet(packetBuffer);
                    if (packet.IsNullPacket)
                    {
                        NumberOfNullPackets++;
                    }

                    else if (!firstVideoMs.HasValue && packet.IsVideoStream)
                    {
                        if (packet.Payload != null && packet.Payload.Length > 10)
                        {
                            int presentationTimestampDecodeTimestampFlags = packet.Payload[7] >> 6;
                            if (presentationTimestampDecodeTimestampFlags == Helper.B00000010 ||
                                presentationTimestampDecodeTimestampFlags == Helper.B00000011)
                            {
                                firstVideoMs  = (ulong)packet.Payload[9 + 4] >> 1;
                                firstVideoMs += (ulong)packet.Payload[9 + 3] << 7;
                                firstVideoMs += (ulong)(packet.Payload[9 + 2] & Helper.B11111110) << 14;
                                firstVideoMs += (ulong)packet.Payload[9 + 1] << 22;
                                firstVideoMs += (ulong)(packet.Payload[9 + 0] & Helper.B00001110) << 29;
                                firstVideoMs  = firstVideoMs / 90;
                            }
                        }
                    }

                    else if (packet.IsPrivateStream1 || SubtitlePacketIds.Contains(packet.PacketId))
                    {
                        TotalNumberOfPrivateStream1++;

                        if (!SubtitlePacketIds.Contains(packet.PacketId))
                        {
                            SubtitlePacketIds.Add(packet.PacketId);
                        }

                        if (packet.PayloadUnitStartIndicator)
                        {
                            firstMs = ProcessPackages(packet.PacketId, teletextPages, teletextPesList, firstMs);
                            SubtitlePackets.RemoveAll(p => p.PacketId == packet.PacketId);
                        }
                        SubtitlePackets.Add(packet);

                        if (packet.ContinuityCounter == 0)
                        {
                            TotalNumberOfPrivateStream1Continuation0++;
                        }
                    }
                    TotalNumberOfPackets++;
                    position += packetLength;

                    if (TotalNumberOfPackets % 100000 == 0)
                    {
                        callback?.Invoke(position, transportStreamLength);
                    }
                }
                else
                {
                    // sync byte not found - search for it (will be very slow!)
                    if (IsM2TransportStream)
                    {
                        position -= m2TsTimeCodeBuffer.Length;
                    }
                    position++;
                    ms.Seek(position, SeekOrigin.Begin);
                }
            }
            foreach (var pid in SubtitlePackets.GroupBy(p => p.PacketId))
            {
                firstMs = ProcessPackages(pid.Key, teletextPages, teletextPesList, firstMs);
            }
            SubtitlePackets.Clear();
            callback?.Invoke(transportStreamLength, transportStreamLength);

            foreach (var packetId in teletextPesList.Keys) // teletext from PES packets
            {
                if (!teletextPages.ContainsKey(packetId))
                {
                    continue;
                }

                foreach (var page in teletextPages[packetId].OrderBy(p => p))
                {
                    var pageBcd = Teletext.DecToBec(page);
                    Teletext.InitializeStaticFields(packetId, pageBcd);
                    var teletextRunSettings = new TeletextRunSettings(firstMs);
                    foreach (var pes in teletextPesList[packetId])
                    {
                        var textDictionary = pes.GetTeletext(teletextRunSettings, page, pageBcd);
                        AddToTeletextDictionary(textDictionary, packetId);
                    }

                    var lastTextDictionary = Teletext.ProcessTelxPacketPendingLeftovers(teletextRunSettings, page);
                    AddToTeletextDictionary(lastTextDictionary, packetId);
                }
            }
            if (Configuration.Settings.SubtitleSettings.TeletextItalicFix)
            {
                FixTeletextItalics(TeletextSubtitlesLookup);
            }

            foreach (var id in TeletextSubtitlesLookup.Keys)
            {
                SubtitlePacketIds = SubtitlePacketIds.Where(p => p != id).ToList();
                SubtitlesLookup.Remove(id);
            }

            DvbSubtitlesLookup = new SortedDictionary <int, List <TransportStreamSubtitle> >();
            if (IsM2TransportStream) // m2ts blu-ray images from PES packets
            {
                foreach (int pid in SubtitlesLookup.Keys)
                {
                    var bdMs        = new MemoryStream();
                    var list        = SubtitlesLookup[pid];
                    var currentList = new List <DvbSubPes>();
                    var sb          = new StringBuilder();
                    var subList     = new List <TransportStreamSubtitle>();
                    var offset      = (long)(firstVideoMs ?? 0); // when to use firstMs ?
                    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;
                                startMs = (ulong)((long)startMs - offset);
                                endMs   = (ulong)((long)endMs - offset);
                                subList.Add(new TransportStreamSubtitle(bdList[0], startMs, endMs));
                            }
                            bdMs.Dispose();
                            bdMs = new MemoryStream();
                            currentList.Clear();
                        }
                    }

                    if (subList.Count > 0)
                    {
                        DvbSubtitlesLookup.Add(pid, subList);
                        SubtitlePacketIds = SubtitlePacketIds.Where(p => p != pid).ToList();
                    }
                }
            }

            SubtitlePacketIds.Clear();
            foreach (int key in SubtitlesLookup.Keys)
            {
                SubtitlePacketIds.Add(key);
            }
            SubtitlePacketIds.Sort();

            // Merge packets and set start/end time
            foreach (int pid in SubtitlePacketIds.Where(p => !DvbSubtitlesLookup.ContainsKey(p)))
            {
                var subtitles = new List <TransportStreamSubtitle>();
                var list      = ParseAndRemoveEmpty(GetSubtitlePesPackets(pid));
                var offset    = (long)(firstVideoMs ?? 0); // when to use firstMs ?
                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;
                        }

                        if (offset <= (long)sub.StartMilliseconds || offset < 0)
                        {
                            sub.StartMilliseconds = (ulong)((long)sub.StartMilliseconds - offset);
                            sub.EndMilliseconds   = (ulong)((long)sub.EndMilliseconds - offset);
                        }
                        else
                        {
                            if (subtitles.Count > 0)
                            {
                                offset = (long)sub.StartMilliseconds - (long)subtitles[subtitles.Count - 1].EndMilliseconds + 1000;
                                sub.StartMilliseconds = (ulong)((long)sub.StartMilliseconds - offset);
                                sub.EndMilliseconds   = (ulong)((long)sub.EndMilliseconds - offset);
                            }
                        }
                        subtitles.Add(sub);
                    }
                }
                if (subtitles.Count > 0)
                {
                    DvbSubtitlesLookup.Add(pid, subtitles);
                }
            }

            SubtitlePacketIds.Clear();
            foreach (int key in DvbSubtitlesLookup.Keys)
            {
                if (DvbSubtitlesLookup[key].Count > 0 && !SubtitlePacketIds.Contains(key))
                {
                    SubtitlePacketIds.Add(key);
                }
            }
            SubtitlePacketIds.Sort();
        }