internal static LanguageItem Create(Section section, int offset, int length) { // Test for length if (length < 4) return null; // Create return new LanguageItem(section, offset); }
internal static TeletextItem Create(Section section, int offset, int length) { // Check if (length < 5) return null; // Create return new TeletextItem(section, offset); }
private LanguageItem(Section section, int offset) { // Load the string ISOLanguage = section.ReadString(offset, 3); // Load the effect Effect = (AudioTypes)section[offset + 3]; }
/// <summary> /// Create a duration representation from the <see cref="Section"/> /// raw data. /// </summary> /// <remarks> /// Please refer to the original document for the encoding algorithm used, e.g /// e.g. <i>ETSI EN 300 468 V1.6.1 (2004-06)</i> or alternate versions. /// </remarks> /// <param name="section">The raw data holder.</param> /// <param name="offset">The offset to the first of three bytes in /// the raw data.</param> /// <returns>The corresponding duration.</returns> public static TimeSpan DecodeDuration(Section section, int offset) { // Read all parts int d0 = FromBCD(section[offset + 0]); int d1 = FromBCD(section[offset + 1]); int d2 = FromBCD(section[offset + 2]); // Calculate return new TimeSpan(d0, d1, d2); }
private TeletextItem(Section section, int offset) { // Load ISOLanguage = section.ReadString(offset + 0, 3); Type = (TeletextTypes)(section[offset + 3]>>3); MagazineNumber = (byte)(section[offset + 3]&0x7); // Decode PageNumberBCD = section[offset + 4]; }
/// <summary> /// Create a GMT/UTC time representation from the <see cref="Section"/> /// raw data. /// </summary> /// <remarks> /// Please refer to the original document for the encoding algorithm used, e.g /// e.g. <i>ETSI EN 300 468 V1.6.1 (2004-06)</i> or alternate versions. /// </remarks> /// <param name="section">The raw data holder.</param> /// <param name="offset">The offset to the first of five bytes in /// the raw data.</param> /// <returns>The corresponding GMT/UTC date and time.</returns> public static DateTime DecodeTime(Section section, int offset) { // Read all parts byte t0 = section[offset + 0]; byte t1 = section[offset + 1]; int t2 = FromBCD(section[offset + 2]); int t3 = FromBCD(section[offset + 3]); int t4 = FromBCD(section[offset + 4]); // Calculate return new DateTime(1970, 1, 1, t2, t3, t4).AddDays(MergeBytesToWord(t1, t0) - 40587); }
/// <summary> /// Erzeugt eine neue Beschreibung. /// </summary> /// <param name="section">Der SI Bereich, in dem die Information gefunden wurde.</param> /// <param name="offset">Der Index des ersten Bytes dieser Information in den Rohdaten des SI Bereichs.</param> /// <param name="length">Die Anzahl der Bytes für diese Information.</param> /// <returns>Die zugehörige Information oder <i>null</i>, wenn eine Rekonstruktion nicht möglich war.</returns> public static CellInformation Create( Section section, int offset, int length ) { // Check minimum length if (length < 10) return null; // Correct length length -= 10; // Read length of extension data int extlen = section[offset + 9]; // Validate if (extlen > length) return null; // Read direct data ushort cellId = Tools.MergeBytesToWord( section[offset + 1], section[offset + 0] ); int latitude = Tools.MergeBytesToWord( section[offset + 3], section[offset + 2] ); int longitude = Tools.MergeBytesToWord( section[offset + 5], section[offset + 4] ); // Read to be merged data int ext0 = section[offset + 6]; int ext1 = section[offset + 7]; int ext2 = section[offset + 8]; // Merge extends int latitude_ext = (ext1 >> 4) + 16 * ext0; int longitude_ext = ext2 + 256 * (ext1 & 0x0f); // Create new CellInformation info = new CellInformation { Length = 10 + extlen, Identifier = cellId, Latitude = Rescale(latitude, 16, 90), Longitude = Rescale(longitude, 16, 180), LatitudeExtension = Rescale(latitude_ext, 13, 90), LongitudeExtension = Rescale(longitude_ext, 13, 180) }; // Report return info; }
/// <summary> /// Find the handler <see cref="Type"/> for a table identifier and create /// a new instance of it. /// <seealso cref="JMS.DVB.EPG.Section.TableIdentifier"/> /// </summary> /// <param name="section">The related <see cref="Section"/>.</param> /// <returns>A new instance of the corresponding handler class. The <see cref="IsValid"/> /// of the instance reports if the table is consistent and should be used.</returns> static public Table Create( Section section ) { // Attach to the type Type pHandler = (Type) m_HandlerForIdentifier[section.TableIdentifier]; // Create return (Table) Activator.CreateInstance( pHandler, new object[] { section } ); }
/// <summary> /// Erzeugt eine neue Informationsinstanz. /// </summary> /// <param name="section">Die SI Tabelle, in der die Informationen abgelegt sind.</param> /// <param name="offset">Das erste Byte, das Informationen zu Untertiteln enthält.</param> private SubtitleInfo( Section section, int offset ) { // Load the language ISOLanguage = section.ReadString( offset, 3 ); // Load the type Type = (SubtitleTypes) section[offset + 3]; // Load pages CompositionPage = Tools.MergeBytesToWord( section[offset + 5], section[offset + 4] ); AncillaryPage = Tools.MergeBytesToWord( section[offset + 7], section[offset + 6] ); }
/// <summary> /// Parse some EPG information and try to extract the data of the current /// service group. /// </summary> /// <param name="section">Currently parsed SI table.</param> private void EPGSectionFound(Section section) { // Test Tables.EIT eit = section.Table as Tables.EIT; // Not us if ( null == eit ) return; // Process all events foreach ( EventEntry evt in eit.Entries ) { // What to add ArrayList ids = new ArrayList(), names = new ArrayList(); // Make sure that this is us bool found = false; // Run over foreach ( Descriptor descr in evt.Descriptors ) { // Check type Descriptors.Linkage info = descr as Descriptors.Linkage; if ( null == info ) continue; // Check type (PREMIERE) if ( 176 != info.LinkType ) continue; // Create identifier Identifier id = new Identifier(info.OriginalNetworkIdentifier, info.TransportStreamIdentifier, info.ServiceIdentifier); // Try to locate the related station Station real = DVBDevice.FindStation(id); if ( null == real ) { // Could be service channel id = new Identifier(info.ServiceIdentifier, 0xffff, info.ServiceIdentifier); real = DVBDevice.FindStation(id); // Try again if ( null == real ) continue; } // Check the first one if ( !found ) found = Equals(id, CurrentPortal); // Remember names.Add(string.Format("{0},{1}", names.Count, CodePage.GetString(info.PrivateData))); ids.Add(id); } // Register if ( found ) lock (m_ServiceNames) for ( int i = ids.Count ; i-- > 0 ; ) m_ServiceNames[ids[i]] = names[i]; } }
/// <summary> /// Create a GMT/UTC date representation from the <see cref="Section"/> /// raw data. /// </summary> /// <remarks> /// Please refer to the original document for the encoding algorithm used, e.g /// e.g. <i>ETSI EN 300 468 V1.6.1 (2004-06)</i> or alternate versions. /// </remarks> /// <param name="section">The raw data holder.</param> /// <param name="offset">The offset to the first of two bytes in /// the raw data.</param> /// <returns>The corresponding GMT/UTC date and.</returns> static public DateTime DecodeDate( Section section, int offset ) { // Read all parts byte t0 = section[offset + 0]; byte t1 = section[offset + 1]; // Calculate return new DateTime( 1970, 1, 1, 0, 0, 0 ).AddDays( MergeBytesToWord( t1, t0 ) - 40587 ); }
/// <summary> /// Ermittelt aus der aktuellen <i>Program Map Table</i> die Informationen zum /// Porgramm des eingehenden Transport Streams. /// </summary> /// <remarks> /// Dabei wird das Bild- und das gewünschte Tonsignal ermittelt und in den Transport /// Stream für den DirectShow Graphen übertragen. Dieser kann so mit festen PIDs /// arbeiten, wodurch die weitere Handhabung im DVB.NET DirectShow Graphen vereinfacht wird. /// Man kann die Arbeit dieser Methode daher als Auswahl der Tonspur und PID Mapping /// beschreiben. /// </remarks> /// <param name="pmt">Eine SI Tabelle.</param> private void ProcessPMT( Section pmt ) { // Not active if (!IsRunning) return; // Validate if (!pmt.IsValid) return; // Attach to table PMT table = pmt.Table as PMT; // Validate if (null == table) return; if (!table.IsValid) return; if (null == table.ProgramEntries) return; if (table.ProgramEntries.Length < 1) return; // Remember m_CurrentService = table.ProgramNumber; // All audio List<AudioItem> audios = new List<AudioItem>(); // Video and audio ushort video = 0, audio = 0, ttx = 0; bool mpeg4 = false, ac3 = false; // Process all programs foreach (ProgramEntry program in table.ProgramEntries) if ((program.StreamType == StreamTypes.Audio11172) || (program.StreamType == StreamTypes.Audio13818)) { // Remember MP2 audios.Add( new AudioItem( program, false, audios.Count ) ); } else if ((program.StreamType == StreamTypes.Video13818) || (program.StreamType == StreamTypes.H264)) { // Only first video if (0 != video) continue; // Remember mpeg4 = (StreamTypes.H264 == program.StreamType); video = program.ElementaryPID; } else if (program.StreamType == StreamTypes.PrivateData) { // Modes bool ac3Found = false, ttxFound = false; // Scan descriptors foreach (Descriptor descriptor in program.Descriptors) if (!ac3Found && (descriptor is AC3)) { // Add to list audios.Add( new AudioItem( program, true, audios.Count ) ); // Done ac3Found = true; } else if (!ttxFound && (descriptor is Teletext)) { // Remember ttx = program.ElementaryPID; // Done ttxFound = true; } } // Always update name list m_AudioNames = audios.ConvertAll<string>( item => item.Name ).ToArray(); // Read the audio index int audioIndex = AudioIndex; // Reset to default if ((audioIndex < 0) || (audioIndex >= audios.Count)) audioIndex = 0; // Check result if (audioIndex < audios.Count) { // Load item AudioItem item = audios[AudioIndex]; // Copy all audio = item.PID; ac3 = item.AC3; } // Check changes bool videoDecChanged = (mpeg4 != m_MPEG4) || m_RestartAV; bool videoChanged = (video != m_Video) || m_RestartAV; bool audioChanged = (audio != m_Audio) || m_RestartAV; bool audioDecChanged = (ac3 != m_AC3) || m_RestartAV; bool ttxChanged = (ttx != m_TTX) || m_RestartAV; // No change at all if (!videoChanged) if (!videoDecChanged) if (!audioChanged) if (!audioDecChanged) if (!ttxChanged) return; // Discard old if (null != m_TSParser) { // De-register if (videoChanged && (0 != m_Video)) m_TSParser.RemoveFilter( m_Video ); if (audioChanged && (0 != m_Audio)) m_TSParser.RemoveFilter( m_Audio ); if (ttxChanged && (0 != m_TTX)) m_TSParser.RemoveFilter( m_TTX ); } // Check for enforcement bool first = ((0 == m_Video) && (0 == m_Audio)) || m_RestartAV; // Change AudioIndex = audioIndex; m_RestartAV = false; m_Video = video; m_Audio = audio; m_MPEG4 = mpeg4; m_AC3 = ac3; m_TTX = ttx; // Register new if (null != m_TSParser) { // De-register if (videoChanged && (0 != m_Video)) m_TSParser.SetFilter( m_Video, false, AddVideo ); if (audioChanged && (0 != m_Audio)) m_TSParser.SetFilter( m_Audio, false, AddAudio ); if (ttxChanged && (0 != m_TTX)) m_TSParser.SetFilter( m_TTX, false, m_TTXStream.AddPayload ); } // Attach to client var streamChanged = StreamChanged; if (streamChanged != null) streamChanged( first || videoDecChanged || audioDecChanged ); }
/// <summary> /// Versucht, aus der aktuellen <i>Program Access Table</i> das Programm des /// eingehenden Transport Streams zu ermitteln. /// </summary> /// <remarks> /// Nur das erste Programm wird berücksichtigt. /// </remarks> /// <param name="pat">Eine SI Tabelle.</param> private void ProcessPAT( Section pat ) { // Not active if (!IsRunning) return; // Validate if (!pat.IsValid) return; // Attach to table PAT table = pat.Table as PAT; // Validate if (null == table) return; if (!table.IsValid) return; if (null == table.ProgramIdentifier) return; // Get the first IEnumerator<KeyValuePair<ushort, ushort>> programEnum = table.ProgramIdentifier.GetEnumerator(); if (!programEnum.MoveNext()) return; // Compare current PMT if (m_CurrentPMT == programEnum.Current.Value) return; // Remove the audio names m_AudioNames = new string[0]; // Stop current PMT if (0 != m_CurrentPMT) m_TSParser.RemoveFilter( m_CurrentPMT ); // Re-create parser m_PMTParser = new Parser(); // Connect to handler m_PMTParser.SectionFound += ProcessPMT; // Change m_CurrentPMT = programEnum.Current.Value; m_CurrentService = null; CurrentEntry = null; NextEntry = null; // Create PMT m_TSParser.SetFilter( m_CurrentPMT, true, m_PMTParser.OnData ); }
/// <summary> /// Prüft, ob in der Programmzeitschrift Daten zur aktuellen Aufzeichnung vorliegen. /// </summary> /// <param name="section">Eintrag aus der Programmzeitschrift.</param> private void ProcessEPG( Section section ) { // Not valid if (null == section) return; if (!section.IsValid) return; // Get the table EIT eit = section.Table as EIT; // Not valid if (null == eit) return; if (!eit.IsValid) return; // See if filter is active int? service = m_CurrentService; // Only current events are of interest if (!service.HasValue) return; if (service.Value != eit.ServiceIdentifier) return; // Set flags bool gotCurrent = false, gotNext = false; // Find all foreach (EventEntry entry in eit.Entries) { // Check for current if (!gotCurrent) if (EventStatus.Running == entry.Status) { // Remember CurrentEntry = entry; gotCurrent = true; // Done if (gotNext) break; else continue; } // Check for next if (!gotNext) if (EventStatus.NotRunning == entry.Status) { // Remember NextEntry = entry; gotNext = true; // Done if (gotCurrent) break; } } }
/// <summary> /// Called for each section the driver parsed from the stream. /// </summary> /// <param name="section">Section parsed.</param> protected override void OnSectionFound(Section section) { // We are already done if (m_Complete.WaitOne(0, false)) return; // Not useable if ((null == section) || !section.IsValid) return; // Be safe try { // Nothing to do if ((null == section.Table) || !section.Table.IsValid) return; // Call implementation if (OnTableFound(section.Table)) m_Complete.Set(); } catch { // Ignore any error } }
/// <summary> /// Fire <see cref="SectionFound"/>. /// </summary> /// <param name="section">A <see cref="Section"/> constructed from /// the raw input stream.</param> protected virtual void OnSectionFound(Section section) { // Load SectionFoundHandler handler = SectionFound; // Send if (null != handler) handler(section); }
/// <summary> /// Erzeugt eine neue Informationsinstanz. /// </summary> /// <param name="section">Die SI Tabelle, in der die Informationen abgelegt sind.</param> /// <param name="offset">Das erste Byte, das Informationen zu Untertiteln enthält.</param> /// <param name="length">Die Anzahl der Bytes, die für die Beschreibung zur Verfügung stehen.</param> /// <returns>Die Informationsinstanz oder <i>null</i>, wenn keine aus den Daten erstellt /// werden konnte.</returns> internal static SubtitleInfo Create( Section section, int offset, int length ) { // Test for length if (length < 8) return null; // Create return new SubtitleInfo( section, offset ); }
/// <summary> /// Initialize the instance. /// </summary> /// <param name="section">The related <see cref="Section"/>.</param> protected Table( Section section ) { // Remember m_Section = section; // Direct load Version = (section[2] >> 1) & 0x1f; IsCurrent = (0 != (section[2] & 1)); SectionNumber = section[3]; LastSectionNumber = section[4]; }
private void SectionFound( Section section ) { // Check if ((null == section) || !section.IsValid) return; // Test all if (ProcessEITEvents( section.Table as EIT )) return; if (ProcessCITEvents( section.Table as CITPremiere )) return; }