Added a failed attempt at OpenTV Parsing.
This commit is contained in:
parent
6302a25f26
commit
7d218ade9c
@ -0,0 +1,275 @@
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// Copyright © 2005-2020 nzsjb //
|
||||
// //
|
||||
// This Program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation; either version 2, or (at your option) //
|
||||
// any later version. //
|
||||
// //
|
||||
// This Program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with GNU Make; see the file COPYING. If not, write to //
|
||||
// the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. //
|
||||
// http://www.gnu.org/copyleft/gpl.html //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
using DomainObjects;
|
||||
|
||||
namespace DVBServices
|
||||
{
|
||||
/// <summary>
|
||||
/// The class that describes a dictionary entry for a single tree Huffman scenario.
|
||||
/// </summary>
|
||||
public class SingleTreeDictionaryEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Get or set the flag for not starting at the first bit in the compressed string.
|
||||
/// </summary>
|
||||
public static bool OffsetStart
|
||||
{
|
||||
get { return (offsetStart); }
|
||||
set { offsetStart = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the decode string.
|
||||
/// </summary>
|
||||
public string Decode { get { return (decode); } }
|
||||
|
||||
private string decode;
|
||||
private string pattern;
|
||||
|
||||
private static HuffmanEntry[] roots = new HuffmanEntry[2];
|
||||
private static bool offsetStart = true;
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new instance of the SingleTreeDictionaryEntry class.
|
||||
/// </summary>
|
||||
/// <param name="pattern">The Huffman bit pattern.</param>
|
||||
/// <param name="decode">The decode for the bit pattern.</param>
|
||||
public SingleTreeDictionaryEntry(string pattern, string decode)
|
||||
{
|
||||
this.pattern = pattern;
|
||||
this.decode = decode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load the dictionary entries ino the first root.
|
||||
/// </summary>
|
||||
/// <returns>True if the file has been loaded; false otherwise.</returns>
|
||||
public static bool Load(string fileName)
|
||||
{
|
||||
return (Load(fileName, 1));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load the dictionary entries.
|
||||
/// </summary>
|
||||
/// <returns>True if the file has been loaded; false otherwise.</returns>
|
||||
public static bool Load(string fileName, int rootNumber)
|
||||
{
|
||||
FileStream fileStream = null;
|
||||
|
||||
Logger.Instance.Write("Loading Huffman Dictionary from " + fileName);
|
||||
|
||||
try { fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read); }
|
||||
catch (IOException e)
|
||||
{
|
||||
Logger.Instance.Write("Huffman Dictionary file " + fileName + " not available");
|
||||
Logger.Instance.Write(e.Message);
|
||||
return (false);
|
||||
}
|
||||
|
||||
StreamReader streamReader = new StreamReader(fileStream);
|
||||
roots[rootNumber - 1] = null;
|
||||
|
||||
while (!streamReader.EndOfStream)
|
||||
{
|
||||
string line = streamReader.ReadLine();
|
||||
|
||||
if (line != string.Empty && !line.StartsWith("####"))
|
||||
{
|
||||
string[] parts = line.Split(new char[] { '=' });
|
||||
if (parts.Length == 2)
|
||||
addEntry(rootNumber, parts[1], getDecode(parts[0]));
|
||||
else
|
||||
{
|
||||
if (parts.Length == 3 && parts[0] == string.Empty && parts[1] == string.Empty)
|
||||
addEntry(rootNumber, parts[2], "=");
|
||||
else
|
||||
Logger.Instance.Write("Dictionary line '" + line + "' format wrong - line ignored ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
streamReader.Close();
|
||||
fileStream.Close();
|
||||
|
||||
Logger.Instance.Write("Dictionary loaded");
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
private static void addEntry(int rootNumber, string pattern, string decode)
|
||||
{
|
||||
if (roots[rootNumber - 1] == null)
|
||||
roots[rootNumber - 1] = new HuffmanEntry();
|
||||
|
||||
HuffmanEntry currentEntry = roots[rootNumber - 1];
|
||||
|
||||
for (int index = 0; index < pattern.Length; index++)
|
||||
{
|
||||
char patternChar = pattern[index];
|
||||
|
||||
switch (patternChar)
|
||||
{
|
||||
case '0':
|
||||
if (currentEntry.P0 == null)
|
||||
{
|
||||
currentEntry.P0 = new HuffmanEntry();
|
||||
currentEntry = currentEntry.P0;
|
||||
if (index == pattern.Length - 1)
|
||||
currentEntry.Value = decode;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentEntry = currentEntry.P0;
|
||||
if (currentEntry.Value != null && index == pattern.Length - 1)
|
||||
Logger.Instance.Write("Dictionary entry already set");
|
||||
}
|
||||
break;
|
||||
case '1':
|
||||
if (currentEntry.P1 == null)
|
||||
{
|
||||
currentEntry.P1 = new HuffmanEntry();
|
||||
currentEntry = currentEntry.P1;
|
||||
if (index == pattern.Length - 1)
|
||||
currentEntry.Value = decode;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentEntry = currentEntry.P1;
|
||||
if (currentEntry.Value != null && index == pattern.Length - 1)
|
||||
Logger.Instance.Write("Dictionary entry already set");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static string getDecode(string originalParameter)
|
||||
{
|
||||
if (originalParameter.Length != 4)
|
||||
return (originalParameter);
|
||||
|
||||
if (originalParameter[0] != '<' || originalParameter[3] != '>')
|
||||
return (originalParameter);
|
||||
|
||||
return (((char)(Int32.Parse(originalParameter.Substring(1, 2), NumberStyles.HexNumber))).ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decompress a compressed Huffman string using the first root table.
|
||||
/// </summary>
|
||||
/// <param name="byteData">The compressed byte data.</param>
|
||||
/// <returns>The decompressed string.</returns>
|
||||
public static string DecodeData(byte[] byteData)
|
||||
{
|
||||
return (DecodeData(1, byteData));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decompress a compressed Huffman string.
|
||||
/// </summary>
|
||||
/// <param name="rootNumber">The root table to use.</param>
|
||||
/// <param name="byteData">The compressed byte data.</param>
|
||||
/// <returns>The decompressed string.</returns>
|
||||
public static string DecodeData(int rootNumber, byte[] byteData)
|
||||
{
|
||||
StringBuilder outputString = new StringBuilder();
|
||||
|
||||
HuffmanEntry currentEntry = roots[rootNumber - 1];
|
||||
|
||||
byte mask;
|
||||
if (offsetStart)
|
||||
mask = 0x20;
|
||||
else
|
||||
mask = 0x80;
|
||||
|
||||
StringBuilder bitString = new StringBuilder();
|
||||
|
||||
for (int index = 0; index < byteData.Length; index++)
|
||||
{
|
||||
byte dataByte = byteData[index];
|
||||
|
||||
while (mask > 0)
|
||||
{
|
||||
if (currentEntry.Value != null)
|
||||
{
|
||||
if (currentEntry.Value != "??")
|
||||
outputString.Append(currentEntry.Value);
|
||||
currentEntry = roots[rootNumber - 1];
|
||||
bitString = new StringBuilder();
|
||||
}
|
||||
|
||||
if ((dataByte & mask) == 0)
|
||||
{
|
||||
bitString.Append("0");
|
||||
|
||||
if (currentEntry.P0 != null)
|
||||
currentEntry = currentEntry.P0;
|
||||
else
|
||||
{
|
||||
Logger.Instance.Write(" ** DECOMPRESSION FAILED **");
|
||||
Logger.Instance.Write("Original data: " + Utils.ConvertToHex(byteData));
|
||||
Logger.Instance.Write("Decoded data: " + outputString.ToString());
|
||||
Logger.Instance.Write("Bit string: " + bitString.ToString());
|
||||
return (outputString.ToString() + " ** DECOMPRESSION FAILED **");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bitString.Append("1");
|
||||
|
||||
if (currentEntry.P1 != null)
|
||||
currentEntry = currentEntry.P1;
|
||||
else
|
||||
{
|
||||
Logger.Instance.Write(" ** DECOMPRESSION FAILED **");
|
||||
Logger.Instance.Write("Original data: " + Utils.ConvertToHex(byteData));
|
||||
Logger.Instance.Write("Decoded data: " + outputString.ToString());
|
||||
Logger.Instance.Write("Bit string: " + bitString.ToString());
|
||||
return (outputString.ToString() + " ** DECOMPRESSION FAILED **");
|
||||
}
|
||||
}
|
||||
|
||||
mask = (byte)(mask >> 1);
|
||||
}
|
||||
|
||||
mask = 0x80;
|
||||
}
|
||||
|
||||
/*if (currentEntry.Value != null && currentEntry.Value != "??")
|
||||
outputString.Append(currentEntry.Value);*/
|
||||
|
||||
if (currentEntry.Value != null)
|
||||
outputString.Append(currentEntry.Value);
|
||||
|
||||
return(outputString.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,149 @@
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// Copyright © 2005-2020 nzsjb //
|
||||
// //
|
||||
// This Program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation; either version 2, or (at your option) //
|
||||
// any later version. //
|
||||
// //
|
||||
// This Program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with GNU Make; see the file COPYING. If not, write to //
|
||||
// the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. //
|
||||
// http://www.gnu.org/copyleft/gpl.html //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
using System;
|
||||
|
||||
namespace DVBServices
|
||||
{
|
||||
/// <summary>
|
||||
/// The class that describes an MPEG2 extended header.
|
||||
/// </summary>
|
||||
public class Mpeg2ExtendedHeader : Mpeg2BasicHeader
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the table identification extension.
|
||||
/// </summary>
|
||||
public int TableIDExtension { get { return (tableIDExtension); } }
|
||||
/// <summary>
|
||||
/// Return true if the MPEG2 section is current; false otherwise.
|
||||
/// </summary>
|
||||
public bool CurrentNextIndicator { get { return (currentNextIndicator); } }
|
||||
/// <summary>
|
||||
/// Get the version number.
|
||||
/// </summary>
|
||||
public int VersionNumber { get { return (versionNumber); } }
|
||||
/// <summary>
|
||||
/// Get the section number.
|
||||
/// </summary>
|
||||
public int SectionNumber { get { return (sectionNumber); } }
|
||||
/// <summary>
|
||||
/// Get the last section number.
|
||||
/// </summary>
|
||||
public int LastSectionNumber { get { return (lastSectionNumber); } }
|
||||
|
||||
/// <summary>
|
||||
/// Return true if the MPEG2 section is current; false otherwise.
|
||||
/// </summary>
|
||||
public bool Current { get { return (currentNextIndicator); } }
|
||||
|
||||
/// <summary>
|
||||
/// Get the index of the next byte in the MPEG2 section following the header.
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// The header has not been processed.
|
||||
/// </exception>
|
||||
public override int Index
|
||||
{
|
||||
get
|
||||
{
|
||||
if (lastIndex == -1)
|
||||
throw (new InvalidOperationException("Mpeg2ExtendedHeader: Index requested before block processed"));
|
||||
return (lastIndex);
|
||||
}
|
||||
}
|
||||
|
||||
private int tableIDExtension;
|
||||
private bool currentNextIndicator;
|
||||
private int versionNumber;
|
||||
private int sectionNumber;
|
||||
private int lastSectionNumber;
|
||||
|
||||
private int lastIndex = -1;
|
||||
|
||||
// MPEG extended header layout is as follows
|
||||
//
|
||||
// table ID extension word uimsbf
|
||||
//
|
||||
// reserved 2 bits bslbf
|
||||
// version no 5 bits uimsbf
|
||||
// current/next ind 1 bit bslbf
|
||||
//
|
||||
// section no byte uimsbf
|
||||
// last section no byte uimsbf
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new instance of the Mpeg2ExtendedHeader class.
|
||||
/// </summary>
|
||||
public Mpeg2ExtendedHeader() { }
|
||||
|
||||
/// <summary>
|
||||
/// Parse the header.
|
||||
/// </summary>
|
||||
/// <param name="byteData">The MPEG2 section containing the header.</param>
|
||||
public override void Process(byte[] byteData)
|
||||
{
|
||||
base.Process(byteData);
|
||||
lastIndex = base.Index;
|
||||
|
||||
try
|
||||
{
|
||||
tableIDExtension = (byteData[lastIndex] * 256) + (int)byteData[lastIndex + 1];
|
||||
lastIndex += 2;
|
||||
|
||||
versionNumber = ((int)((byteData[lastIndex] >> 1) & 0x1f));
|
||||
currentNextIndicator = (byteData[lastIndex] & 0x01) != 0;
|
||||
lastIndex++;
|
||||
|
||||
sectionNumber = (int)byteData[lastIndex];
|
||||
lastIndex++;
|
||||
|
||||
lastSectionNumber = (int)byteData[lastIndex];
|
||||
lastIndex++;
|
||||
|
||||
Validate();
|
||||
}
|
||||
catch (IndexOutOfRangeException)
|
||||
{
|
||||
throw (new ArgumentOutOfRangeException("MPEG2 extended header short"));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validate the header fields.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// A header field is not valid.
|
||||
/// </exception>
|
||||
public override void Validate()
|
||||
{
|
||||
base.Validate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Log the header fields.
|
||||
/// </summary>
|
||||
public override void LogMessage()
|
||||
{
|
||||
base.LogMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,111 @@
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// Copyright © 2005-2020 nzsjb //
|
||||
// //
|
||||
// This Program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation; either version 2, or (at your option) //
|
||||
// any later version. //
|
||||
// //
|
||||
// This Program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with GNU Make; see the file COPYING. If not, write to //
|
||||
// the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. //
|
||||
// http://www.gnu.org/copyleft/gpl.html //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
using System;
|
||||
|
||||
using DomainObjects;
|
||||
|
||||
namespace DVBServices
|
||||
{
|
||||
/// <summary>
|
||||
/// The class that describes an OpenTV extended description record.
|
||||
/// </summary>
|
||||
internal class OpenTVExtendedDescriptionRecord : OpenTVRecordBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the tag value for this record.
|
||||
/// </summary>
|
||||
public const int TagValue = 0xbb;
|
||||
|
||||
/// <summary>
|
||||
/// Get the extended description.
|
||||
/// </summary>
|
||||
public string Description { get { return (SingleTreeDictionaryEntry.DecodeData(description)); } }
|
||||
|
||||
/// <summary>
|
||||
/// Get the index of the next byte in the MPEG2 section following the record.
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// The record has not been processed.
|
||||
/// </exception>
|
||||
public override int Index
|
||||
{
|
||||
get
|
||||
{
|
||||
if (lastIndex == -1)
|
||||
throw (new InvalidOperationException("OpenTVExtendedDescriptionRecord: Index requested before block processed"));
|
||||
return (lastIndex);
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] description;
|
||||
|
||||
private int lastIndex = -1;
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new instance of the OpenTVExtendedDescriptionRecord class.
|
||||
/// </summary>
|
||||
internal OpenTVExtendedDescriptionRecord() { }
|
||||
|
||||
/// <summary>
|
||||
/// Parse the record.
|
||||
/// </summary>
|
||||
/// <param name="byteData">The MPEG2 section containing the record.</param>
|
||||
/// <param name="index">Index of the first byte of the record data in the MPEG2 section.</param>
|
||||
internal override void Process(byte[] byteData, int index)
|
||||
{
|
||||
lastIndex = index;
|
||||
|
||||
try
|
||||
{
|
||||
description = Utils.GetBytes(byteData, lastIndex, Length);
|
||||
lastIndex += Length;
|
||||
|
||||
Validate();
|
||||
}
|
||||
catch (IndexOutOfRangeException)
|
||||
{
|
||||
throw (new ArgumentOutOfRangeException("lastIndex = " + lastIndex));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validate the record data fields.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// A record data field is not valid.
|
||||
/// </exception>
|
||||
internal override void Validate() { }
|
||||
|
||||
/// <summary>
|
||||
/// Log the record data fields.
|
||||
/// </summary>
|
||||
internal override void LogMessage()
|
||||
{
|
||||
if (Logger.ProtocolLogger == null)
|
||||
return;
|
||||
|
||||
Logger.ProtocolLogger.Write(Logger.ProtocolIndent + "");
|
||||
Logger.ProtocolLogger.Write(Logger.ProtocolIndent + "OPENTV EXTENDED DESCRIPTION RECORD: Description: " + Utils.ConvertToHex(description));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,195 @@
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// Copyright © 2005-2020 nzsjb //
|
||||
// //
|
||||
// This Program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation; either version 2, or (at your option) //
|
||||
// any later version. //
|
||||
// //
|
||||
// This Program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with GNU Make; see the file COPYING. If not, write to //
|
||||
// the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. //
|
||||
// http://www.gnu.org/copyleft/gpl.html //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
using DomainObjects;
|
||||
|
||||
namespace DVBServices
|
||||
{
|
||||
/// <summary>
|
||||
/// The base OpenTV record class.
|
||||
/// </summary>
|
||||
internal class OpenTVRecordBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the tag of the record.
|
||||
/// </summary>
|
||||
internal int Tag { get { return (tag); } }
|
||||
/// <summary>
|
||||
/// Get the length of the record data.
|
||||
/// </summary>
|
||||
internal int Length { get { return (length); } }
|
||||
/// <summary>
|
||||
/// Get the record data.
|
||||
/// </summary>
|
||||
internal byte[] Data { get { return (data); } }
|
||||
|
||||
/// <summary>
|
||||
/// Get the total length of the record.
|
||||
/// </summary>
|
||||
internal int TotalLength { get { return (Length + 2); } }
|
||||
/// <summary>
|
||||
/// Return true if the record is undefined; false otherwise.
|
||||
/// </summary>
|
||||
internal bool IsUndefined { get { return (isUndefined); } }
|
||||
|
||||
/// <summary>
|
||||
/// Return the collection of unknown records.
|
||||
/// </summary>
|
||||
internal static Collection<OpenTVRecordBase> UnknownRecords { get { return (unknownRecords); } }
|
||||
|
||||
/// <summary>
|
||||
/// Get the index of the next byte in the MPEG2 section following this record.
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// The descriptor has not been processed.
|
||||
/// </exception>
|
||||
public virtual int Index
|
||||
{
|
||||
get
|
||||
{
|
||||
if (lastIndex == -1)
|
||||
throw (new InvalidOperationException("OpenTVRecordBase: Index requested before block processed"));
|
||||
return (lastIndex);
|
||||
}
|
||||
}
|
||||
|
||||
private int lastIndex = -1;
|
||||
|
||||
private int tag;
|
||||
private int length;
|
||||
private byte[] data;
|
||||
|
||||
private bool isUndefined;
|
||||
|
||||
private static Collection<OpenTVRecordBase> unknownRecords;
|
||||
|
||||
/// <summary>
|
||||
/// Create an instance of the record class.
|
||||
/// </summary>
|
||||
/// <param name="byteData">The MPEG2 section containing the record.</param>
|
||||
/// <param name="index">The index of the tag byte of the record.</param>
|
||||
/// <returns>A descriptor instance.</returns>
|
||||
internal static OpenTVRecordBase Instance(byte[] byteData, int index)
|
||||
{
|
||||
OpenTVRecordBase record;
|
||||
|
||||
switch ((int)byteData[index])
|
||||
{
|
||||
case OpenTVTitleDataRecord.TagValue:
|
||||
record = new OpenTVTitleDataRecord();
|
||||
break;
|
||||
case OpenTVShortDescriptionRecord.TagValue:
|
||||
record = new OpenTVShortDescriptionRecord();
|
||||
break;
|
||||
case OpenTVExtendedDescriptionRecord.TagValue:
|
||||
record = new OpenTVExtendedDescriptionRecord();
|
||||
break;
|
||||
case OpenTVSeriesLinkRecord.TagValue:
|
||||
record = new OpenTVSeriesLinkRecord();
|
||||
break;
|
||||
default:
|
||||
record = new OpenTVRecordBase();
|
||||
|
||||
if (DebugEntry.IsDefined(DebugName.LogUnknownRecords))
|
||||
{
|
||||
if (unknownRecords == null)
|
||||
unknownRecords = new Collection<OpenTVRecordBase>();
|
||||
unknownRecords.Add(record);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
record.tag = (int)byteData[index];
|
||||
index++;
|
||||
|
||||
record.length = (int)byteData[index];
|
||||
index++;
|
||||
|
||||
record.Process(byteData, index);
|
||||
|
||||
return (record);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new instance of the OpenTVRecordBase class.
|
||||
/// </summary>
|
||||
internal OpenTVRecordBase() { }
|
||||
|
||||
/// <summary>
|
||||
/// Parse the descriptor.
|
||||
/// </summary>
|
||||
/// <param name="byteData">The MPEG2 section containing the record.</param>
|
||||
/// <param name="index">Index of the byte in the MPEG2 section following the descriptor length.</param>
|
||||
internal virtual void Process(byte[] byteData, int index)
|
||||
{
|
||||
lastIndex = index;
|
||||
|
||||
if (Length != 0)
|
||||
{
|
||||
data = Utils.GetBytes(byteData, 0, Length);
|
||||
lastIndex += Length;
|
||||
}
|
||||
|
||||
isUndefined = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validate the record fields.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// A record field is not valid.
|
||||
/// </exception>
|
||||
internal virtual void Validate() { }
|
||||
|
||||
/// <summary>
|
||||
/// Log the descriptor fields.
|
||||
/// </summary>
|
||||
internal virtual void LogMessage()
|
||||
{
|
||||
if (DebugEntry.IsDefined(DebugName.LogUnknownRecords))
|
||||
logMessage(Logger.Instance);
|
||||
else
|
||||
{
|
||||
if (Logger.ProtocolLogger == null)
|
||||
return;
|
||||
|
||||
if (!TraceEntry.IsDefined(TraceName.GenericOpenTvRecord))
|
||||
return;
|
||||
|
||||
logMessage(Logger.ProtocolLogger);
|
||||
}
|
||||
}
|
||||
|
||||
private void logMessage(Logger logger)
|
||||
{
|
||||
logger.Write(Logger.ProtocolIndent + "OPENTV GENERIC RECORD: Tag: " + Utils.ConvertToHex(tag) +
|
||||
" Length: " + length);
|
||||
|
||||
if (length != 0)
|
||||
logger.Dump("OpenTV Generic Record Data", data, data.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,111 @@
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// Copyright © 2005-2020 nzsjb //
|
||||
// //
|
||||
// This Program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation; either version 2, or (at your option) //
|
||||
// any later version. //
|
||||
// //
|
||||
// This Program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with GNU Make; see the file COPYING. If not, write to //
|
||||
// the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. //
|
||||
// http://www.gnu.org/copyleft/gpl.html //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
using System;
|
||||
|
||||
using DomainObjects;
|
||||
|
||||
namespace DVBServices
|
||||
{
|
||||
/// <summary>
|
||||
/// The class that describes an OpenTV series link record.
|
||||
/// </summary>
|
||||
internal class OpenTVSeriesLinkRecord : OpenTVRecordBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the tag value for this record.
|
||||
/// </summary>
|
||||
public const int TagValue = 0xc1;
|
||||
|
||||
/// <summary>
|
||||
/// Get the series link.
|
||||
/// </summary>
|
||||
public int SeriesLink { get { return (seriesLink); } }
|
||||
|
||||
/// <summary>
|
||||
/// Get the index of the next byte in the MPEG2 section following the record.
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// The record has not been processed.
|
||||
/// </exception>
|
||||
public override int Index
|
||||
{
|
||||
get
|
||||
{
|
||||
if (lastIndex == -1)
|
||||
throw (new InvalidOperationException("OpenTVSeriesLinkRecord: Index requested before block processed"));
|
||||
return (lastIndex);
|
||||
}
|
||||
}
|
||||
|
||||
private int seriesLink;
|
||||
|
||||
private int lastIndex = -1;
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new instance of the OpenTVSeriesLinkRecord class.
|
||||
/// </summary>
|
||||
internal OpenTVSeriesLinkRecord() { }
|
||||
|
||||
/// <summary>
|
||||
/// Parse the record.
|
||||
/// </summary>
|
||||
/// <param name="byteData">The MPEG2 section containing the record.</param>
|
||||
/// <param name="index">Index of the first byte of the record data in the MPEG2 section.</param>
|
||||
internal override void Process(byte[] byteData, int index)
|
||||
{
|
||||
lastIndex = index;
|
||||
|
||||
try
|
||||
{
|
||||
seriesLink = Utils.Convert2BytesToInt(byteData, lastIndex);
|
||||
lastIndex += 2;
|
||||
|
||||
Validate();
|
||||
}
|
||||
catch (IndexOutOfRangeException)
|
||||
{
|
||||
throw (new ArgumentOutOfRangeException("lastIndex = " + lastIndex));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validate the record data fields.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// A record data field is not valid.
|
||||
/// </exception>
|
||||
internal override void Validate() { }
|
||||
|
||||
/// <summary>
|
||||
/// Log the record data fields.
|
||||
/// </summary>
|
||||
internal override void LogMessage()
|
||||
{
|
||||
if (Logger.ProtocolLogger == null)
|
||||
return;
|
||||
|
||||
Logger.ProtocolLogger.Write(Logger.ProtocolIndent + "");
|
||||
Logger.ProtocolLogger.Write(Logger.ProtocolIndent + "OPENTV SERIES LINK RECORD: Series link: " + seriesLink);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,116 @@
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// Copyright © 2005-2020 nzsjb //
|
||||
// //
|
||||
// This Program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation; either version 2, or (at your option) //
|
||||
// any later version. //
|
||||
// //
|
||||
// This Program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with GNU Make; see the file COPYING. If not, write to //
|
||||
// the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. //
|
||||
// http://www.gnu.org/copyleft/gpl.html //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
using System;
|
||||
|
||||
using DomainObjects;
|
||||
|
||||
namespace DVBServices
|
||||
{
|
||||
/// <summary>
|
||||
/// The class that describes an OpenTV short description record.
|
||||
/// </summary>
|
||||
internal class OpenTVShortDescriptionRecord : OpenTVRecordBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the tag value for this record.
|
||||
/// </summary>
|
||||
public const int TagValue = 0xb9;
|
||||
|
||||
/// <summary>
|
||||
/// Get the short description.
|
||||
/// </summary>
|
||||
public string Description { get { return (SingleTreeDictionaryEntry.DecodeData(description)); } }
|
||||
|
||||
/// <summary>
|
||||
/// Get the short description bytes.
|
||||
/// </summary>
|
||||
public byte[] DescriptionBytes { get { return (description); } }
|
||||
|
||||
/// <summary>
|
||||
/// Get the index of the next byte in the MPEG2 section following the record.
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// The record has not been processed.
|
||||
/// </exception>
|
||||
public override int Index
|
||||
{
|
||||
get
|
||||
{
|
||||
if (lastIndex == -1)
|
||||
throw (new InvalidOperationException("OpenTVShortDescriptionRecord: Index requested before block processed"));
|
||||
return (lastIndex);
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] description;
|
||||
|
||||
private int lastIndex = -1;
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new instance of the OpenTVShortDescriptionRecord class.
|
||||
/// </summary>
|
||||
internal OpenTVShortDescriptionRecord() { }
|
||||
|
||||
/// <summary>
|
||||
/// Parse the record.
|
||||
/// </summary>
|
||||
/// <param name="byteData">The MPEG2 section containing the record.</param>
|
||||
/// <param name="index">Index of the first byte of the record data in the MPEG2 section.</param>
|
||||
internal override void Process(byte[] byteData, int index)
|
||||
{
|
||||
lastIndex = index;
|
||||
|
||||
try
|
||||
{
|
||||
description = Utils.GetBytes(byteData, lastIndex, Length);
|
||||
lastIndex += Length;
|
||||
|
||||
Validate();
|
||||
}
|
||||
catch (IndexOutOfRangeException)
|
||||
{
|
||||
throw (new ArgumentOutOfRangeException("lastIndex = " + lastIndex));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validate the record data fields.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// A record data field is not valid.
|
||||
/// </exception>
|
||||
internal override void Validate() { }
|
||||
|
||||
/// <summary>
|
||||
/// Log the record data fields.
|
||||
/// </summary>
|
||||
internal override void LogMessage()
|
||||
{
|
||||
if (Logger.ProtocolLogger == null)
|
||||
return;
|
||||
|
||||
Logger.ProtocolLogger.Write(Logger.ProtocolIndent + "");
|
||||
Logger.ProtocolLogger.Write(Logger.ProtocolIndent + "OPENTV SHORT DESCRIPTION RECORD: Description: " + Utils.ConvertToHex(description));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,244 @@
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// Copyright © 2005-2020 nzsjb //
|
||||
// //
|
||||
// This Program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation; either version 2, or (at your option) //
|
||||
// any later version. //
|
||||
// //
|
||||
// This Program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with GNU Make; see the file COPYING. If not, write to //
|
||||
// the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. //
|
||||
// http://www.gnu.org/copyleft/gpl.html //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
using DomainObjects;
|
||||
|
||||
namespace DVBServices
|
||||
{
|
||||
/// <summary>
|
||||
/// The class that describes Open TV summary data.
|
||||
/// </summary>
|
||||
public class OpenTVSummaryData
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the event identification.
|
||||
/// </summary>
|
||||
public int EventID { get { return (eventID); } }
|
||||
|
||||
/// <summary>
|
||||
/// Get the short description of the event.
|
||||
/// </summary>
|
||||
public string ShortDescription
|
||||
{
|
||||
get
|
||||
{
|
||||
OpenTVShortDescriptionRecord record = (OpenTVShortDescriptionRecord)getRecord(OpenTVShortDescriptionRecord.TagValue);
|
||||
if (record != null)
|
||||
return (record.Description);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the raw bytes of short description of the event.
|
||||
/// </summary>
|
||||
public byte[] ShortDescriptionBytes
|
||||
{
|
||||
get
|
||||
{
|
||||
OpenTVShortDescriptionRecord record = (OpenTVShortDescriptionRecord)getRecord(OpenTVShortDescriptionRecord.TagValue);
|
||||
if (record != null)
|
||||
return (record.DescriptionBytes);
|
||||
else
|
||||
return (new byte[] { 0x00 });
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the extended description of the event.
|
||||
/// </summary>
|
||||
public string ExtendedDescription
|
||||
{
|
||||
get
|
||||
{
|
||||
OpenTVExtendedDescriptionRecord record = (OpenTVExtendedDescriptionRecord)getRecord(OpenTVExtendedDescriptionRecord.TagValue);
|
||||
if (record != null)
|
||||
return (record.Description);
|
||||
else
|
||||
return (null);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the series link of the event.
|
||||
/// </summary>
|
||||
public int SeriesLink
|
||||
{
|
||||
get
|
||||
{
|
||||
OpenTVSeriesLinkRecord record = (OpenTVSeriesLinkRecord)getRecord(OpenTVSeriesLinkRecord.TagValue);
|
||||
if (record != null)
|
||||
return (record.SeriesLink);
|
||||
else
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the collection of records for this summary section.
|
||||
/// </summary>
|
||||
internal Collection<OpenTVRecordBase> Records
|
||||
{
|
||||
get
|
||||
{
|
||||
if (records == null)
|
||||
records = new Collection<OpenTVRecordBase>();
|
||||
return (records);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the collection of undefined records for this summary section.
|
||||
/// </summary>
|
||||
internal Collection<OpenTVRecordBase> UndefinedRecords
|
||||
{
|
||||
get
|
||||
{
|
||||
if (records == null)
|
||||
return (null);
|
||||
|
||||
Collection<OpenTVRecordBase> undefinedRecords = new Collection<OpenTVRecordBase>();
|
||||
|
||||
foreach (OpenTVRecordBase record in records)
|
||||
{
|
||||
if (record.IsUndefined)
|
||||
undefinedRecords.Add(record);
|
||||
}
|
||||
|
||||
return (undefinedRecords);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the index of the next byte in the MPEG2 section following the summary data.
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// The summary data has not been processed.
|
||||
/// </exception>
|
||||
public int Index
|
||||
{
|
||||
get
|
||||
{
|
||||
if (lastIndex == -1)
|
||||
throw (new InvalidOperationException("OpenTVSummaryData: Index requested before block processed"));
|
||||
return (lastIndex);
|
||||
}
|
||||
}
|
||||
|
||||
private int eventID;
|
||||
private int length;
|
||||
|
||||
private Collection<OpenTVRecordBase> records;
|
||||
|
||||
private int lastIndex = -1;
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new instance of the OpenTVSummaryData class.
|
||||
/// </summary>
|
||||
public OpenTVSummaryData() { }
|
||||
|
||||
/// <summary>
|
||||
/// Parse the summary data.
|
||||
/// </summary>
|
||||
/// <param name="byteData">The MPEG2 section containing the summary data.</param>
|
||||
/// <param name="index">Index of the first byte of the summary data in the MPEG2 section.</param>
|
||||
/// <param name="baseDate">The base date for the program events.</param>
|
||||
internal void Process(byte[] byteData, int index, DateTime baseDate)
|
||||
{
|
||||
lastIndex = index;
|
||||
|
||||
try
|
||||
{
|
||||
eventID = Utils.Convert2BytesToInt(byteData, lastIndex);
|
||||
lastIndex += 2;
|
||||
|
||||
length = ((byteData[lastIndex] & 0x0f) * 256) + byteData[lastIndex + 1];
|
||||
lastIndex += 2;
|
||||
|
||||
int recordLength = length;
|
||||
|
||||
while (recordLength != 0)
|
||||
{
|
||||
OpenTVRecordBase record = OpenTVRecordBase.Instance(byteData, lastIndex);
|
||||
Records.Add(record);
|
||||
|
||||
lastIndex += record.TotalLength;
|
||||
recordLength -= record.TotalLength;
|
||||
}
|
||||
|
||||
Validate();
|
||||
}
|
||||
catch (IndexOutOfRangeException)
|
||||
{
|
||||
throw (new ArgumentOutOfRangeException("The Open TV Summary Data message is short"));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validate the summary data fields.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// A summary data field is not valid.
|
||||
/// </exception>
|
||||
public void Validate() { }
|
||||
|
||||
/// <summary>
|
||||
/// Log the summary data fields.
|
||||
/// </summary>
|
||||
public void LogMessage()
|
||||
{
|
||||
if (Logger.ProtocolLogger == null)
|
||||
return;
|
||||
|
||||
Logger.ProtocolLogger.Write(Logger.ProtocolIndent + "OPENTV SUMMARY DATA: Event ID: " + eventID +
|
||||
" Length: " + length);
|
||||
|
||||
if (records != null)
|
||||
{
|
||||
Logger.IncrementProtocolIndent();
|
||||
|
||||
foreach (OpenTVRecordBase record in records)
|
||||
record.LogMessage();
|
||||
|
||||
Logger.DecrementProtocolIndent();
|
||||
}
|
||||
}
|
||||
|
||||
private OpenTVRecordBase getRecord(int tag)
|
||||
{
|
||||
if (records == null)
|
||||
return (null);
|
||||
|
||||
foreach (OpenTVRecordBase record in records)
|
||||
{
|
||||
if (record.Tag == tag)
|
||||
return (record);
|
||||
}
|
||||
|
||||
return (null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,161 @@
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// Copyright © 2005-2020 nzsjb //
|
||||
// //
|
||||
// This Program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation; either version 2, or (at your option) //
|
||||
// any later version. //
|
||||
// //
|
||||
// This Program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with GNU Make; see the file COPYING. If not, write to //
|
||||
// the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. //
|
||||
// http://www.gnu.org/copyleft/gpl.html //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
using DomainObjects;
|
||||
|
||||
namespace DVBServices
|
||||
{
|
||||
/// <summary>
|
||||
/// The class that describes an Open TV summary header.
|
||||
/// </summary>
|
||||
public class OpenTVSummaryHeader
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the channel identification.
|
||||
/// </summary>
|
||||
public int ChannelID { get { return (channelID); } }
|
||||
/// <summary>
|
||||
/// Get the title date base.
|
||||
/// </summary>
|
||||
public DateTime BaseDate { get { return (baseDate); } }
|
||||
/// <summary>
|
||||
/// Get the data collection related to this summary.
|
||||
/// </summary>
|
||||
public Collection<OpenTVSummaryData> SummaryData { get { return (summaryData); } }
|
||||
|
||||
/// <summary>
|
||||
/// Get the index of the next byte in the MPEG2 section following the summary header.
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// The summary header has not been processed.
|
||||
/// </exception>
|
||||
public int Index
|
||||
{
|
||||
get
|
||||
{
|
||||
if (lastIndex == -1)
|
||||
throw (new InvalidOperationException("OpenTVSummaryHeader: Index requested before block processed"));
|
||||
return (lastIndex);
|
||||
}
|
||||
}
|
||||
|
||||
private int channelID;
|
||||
private DateTime baseDate;
|
||||
private Collection<OpenTVSummaryData> summaryData;
|
||||
|
||||
private int lastIndex = -1;
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new instance of the OpenTVSummaryHeader class.
|
||||
/// </summary>
|
||||
public OpenTVSummaryHeader() { }
|
||||
|
||||
/// <summary>
|
||||
/// Parse the summary header.
|
||||
/// </summary>
|
||||
/// <param name="byteData">The MPEG2 section containing the summary header.</param>
|
||||
/// <param name="index">Index of the first byte of the summary header in the MPEG2 section.</param>
|
||||
/// <param name="mpeg2Header">The MPEG2 header of the section.</param>
|
||||
internal void Process(byte[] byteData, int index, Mpeg2ExtendedHeader mpeg2Header)
|
||||
{
|
||||
lastIndex = index;
|
||||
|
||||
channelID = mpeg2Header.TableIDExtension;
|
||||
|
||||
try
|
||||
{
|
||||
baseDate = getDate(Utils.Convert2BytesToInt(byteData, lastIndex));
|
||||
lastIndex += 2;
|
||||
|
||||
while (lastIndex < byteData.Length - 4)
|
||||
{
|
||||
OpenTVSummaryData data = new OpenTVSummaryData();
|
||||
data.Process(byteData, lastIndex, baseDate);
|
||||
|
||||
if (summaryData == null)
|
||||
summaryData = new Collection<OpenTVSummaryData>();
|
||||
|
||||
summaryData.Add(data);
|
||||
|
||||
lastIndex = data.Index;
|
||||
}
|
||||
|
||||
Validate();
|
||||
}
|
||||
catch (IndexOutOfRangeException)
|
||||
{
|
||||
throw (new ArgumentOutOfRangeException("The Open TV Summary Header message is short"));
|
||||
}
|
||||
}
|
||||
|
||||
private DateTime getDate(int mjd)
|
||||
{
|
||||
int j = mjd + 2400001 + 68569;
|
||||
int c = 4 * j / 146097;
|
||||
j = j - (146097 * c + 3) / 4;
|
||||
|
||||
int y = 4000 * (j + 1) / 1461001;
|
||||
j = j - 1461 * y / 4 + 31;
|
||||
int m = 80 * j / 2447;
|
||||
|
||||
int day = j - 2447 * m / 80;
|
||||
j = m / 11;
|
||||
int month = m + 2 - (12 * j);
|
||||
int year = 100 * (c - 49) + y + j;
|
||||
|
||||
return (new DateTime(year, month, day) + new TimeSpan(1, 0, 0, 0));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validate the summary header fields.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// A summary header field is not valid.
|
||||
/// </exception>
|
||||
public void Validate() { }
|
||||
|
||||
/// <summary>
|
||||
/// Log the summary header fields.
|
||||
/// </summary>
|
||||
public void LogMessage()
|
||||
{
|
||||
if (Logger.ProtocolLogger == null)
|
||||
return;
|
||||
|
||||
Logger.ProtocolLogger.Write(Logger.ProtocolIndent + "OPENTV SUMMARY HEADER: Channel ID: " + channelID +
|
||||
" Base date : " + baseDate);
|
||||
|
||||
if (summaryData != null)
|
||||
{
|
||||
Logger.IncrementProtocolIndent();
|
||||
|
||||
foreach (OpenTVSummaryData data in summaryData)
|
||||
data.LogMessage();
|
||||
|
||||
Logger.DecrementProtocolIndent();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,151 @@
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// Copyright © 2005-2020 nzsjb //
|
||||
// //
|
||||
// This Program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation; either version 2, or (at your option) //
|
||||
// any later version. //
|
||||
// //
|
||||
// This Program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with GNU Make; see the file COPYING. If not, write to //
|
||||
// the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. //
|
||||
// http://www.gnu.org/copyleft/gpl.html //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
using DomainObjects;
|
||||
|
||||
namespace DVBServices
|
||||
{
|
||||
/// <summary>
|
||||
/// The class that describes an Open TV Summary section.
|
||||
/// </summary>
|
||||
public class OpenTVSummarySection
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the collection of Open TV Title sections.
|
||||
/// </summary>
|
||||
public static Collection<OpenTVSummarySection> OpenTVSummarySections
|
||||
{
|
||||
get
|
||||
{
|
||||
if (openTVSummarySections == null)
|
||||
openTVSummarySections = new Collection<OpenTVSummarySection>();
|
||||
return (openTVSummarySections);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the section number.
|
||||
/// </summary>
|
||||
public int SectionNumber { get { return (sectionNumber); } }
|
||||
/// <summary>
|
||||
/// Get the section number.
|
||||
/// </summary>
|
||||
public int LastSectionNumber { get { return (lastSectionNumber); } }
|
||||
/// <summary>
|
||||
/// Get the title header.
|
||||
/// </summary>
|
||||
public OpenTVSummaryHeader SummaryHeader { get { return (summaryHeader); } }
|
||||
|
||||
private int sectionNumber;
|
||||
private int lastSectionNumber;
|
||||
private OpenTVSummaryHeader summaryHeader;
|
||||
|
||||
private static Collection<OpenTVSummarySection> openTVSummarySections;
|
||||
|
||||
private int lastIndex = -1;
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new instance of the OpenTVSummarySection class.
|
||||
/// </summary>
|
||||
internal OpenTVSummarySection() { }
|
||||
|
||||
/// <summary>
|
||||
/// Parse the section.
|
||||
/// </summary>
|
||||
/// <param name="byteData">The MPEG2 section containing the section.</param>
|
||||
/// <param name="mpeg2Header">The MPEG2 header that preceedes the section.</param>
|
||||
internal void Process(byte[] byteData, Mpeg2ExtendedHeader mpeg2Header)
|
||||
{
|
||||
lastIndex = mpeg2Header.Index;
|
||||
sectionNumber = mpeg2Header.SectionNumber;
|
||||
lastSectionNumber = mpeg2Header.LastSectionNumber;
|
||||
|
||||
summaryHeader = new OpenTVSummaryHeader();
|
||||
summaryHeader.Process(byteData, lastIndex, mpeg2Header);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Log the section fields.
|
||||
/// </summary>
|
||||
public void LogMessage()
|
||||
{
|
||||
if (Logger.ProtocolLogger == null)
|
||||
return;
|
||||
|
||||
summaryHeader.LogMessage();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process an MPEG2 section from the Open TV Summary table.
|
||||
/// </summary>
|
||||
/// <param name="byteData">The MPEG2 section.</param>
|
||||
/// <returns>An Open TV Summary Section instance.</returns>
|
||||
public static OpenTVSummarySection ProcessOpenTVSummaryTable(byte[] byteData)
|
||||
{
|
||||
Mpeg2ExtendedHeader mpeg2Header = new Mpeg2ExtendedHeader();
|
||||
|
||||
try
|
||||
{
|
||||
mpeg2Header.Process(byteData);
|
||||
|
||||
if (mpeg2Header.Current)
|
||||
{
|
||||
OpenTVSummarySection openTVSummarySection = new OpenTVSummarySection();
|
||||
openTVSummarySection.Process(byteData, mpeg2Header);
|
||||
openTVSummarySection.LogMessage();
|
||||
return (openTVSummarySection);
|
||||
}
|
||||
else
|
||||
return (null);
|
||||
}
|
||||
catch (ArgumentOutOfRangeException e)
|
||||
{
|
||||
Logger.Instance.Write("<e> Error processing Summary Section: " + e.Message);
|
||||
return (null);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a section to the collection.
|
||||
/// </summary>
|
||||
/// <param name="newSection">The section to be added.</param>
|
||||
public static void AddSection(OpenTVSummarySection newSection)
|
||||
{
|
||||
/*foreach (OpenTVSummarySection oldSection in OpenTVSummarySections)
|
||||
{
|
||||
if (oldSection.sectionNumber == newSection.sectionNumber)
|
||||
return;
|
||||
|
||||
if (oldSection.SectionNumber > newSection.SectionNumber)
|
||||
{
|
||||
OpenTVSummarySections.Insert(OpenTVSummarySections.IndexOf(oldSection), newSection);
|
||||
return;
|
||||
}
|
||||
}*/
|
||||
|
||||
OpenTVSummarySections.Add(newSection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,289 @@
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// Copyright © 2005-2020 nzsjb //
|
||||
// //
|
||||
// This Program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation; either version 2, or (at your option) //
|
||||
// any later version. //
|
||||
// //
|
||||
// This Program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with GNU Make; see the file COPYING. If not, write to //
|
||||
// the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. //
|
||||
// http://www.gnu.org/copyleft/gpl.html //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
using DomainObjects;
|
||||
|
||||
namespace DVBServices
|
||||
{
|
||||
/// <summary>
|
||||
/// The class that describes Open TV title data.
|
||||
/// </summary>
|
||||
public class OpenTVTitleData
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the event identification.
|
||||
/// </summary>
|
||||
public int EventID { get { return (eventID); } }
|
||||
|
||||
/// <summary>
|
||||
/// Get the start time of the event.
|
||||
/// </summary>
|
||||
public DateTime StartTime
|
||||
{
|
||||
get
|
||||
{
|
||||
OpenTVTitleDataRecord record = (OpenTVTitleDataRecord)getRecord(OpenTVTitleDataRecord.TagValue);
|
||||
return (baseDate + record.StartTimeOffset);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the duration of the event.
|
||||
/// </summary>
|
||||
public TimeSpan Duration
|
||||
{
|
||||
get
|
||||
{
|
||||
OpenTVTitleDataRecord record = (OpenTVTitleDataRecord)getRecord(OpenTVTitleDataRecord.TagValue);
|
||||
return (record.Duration);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the theme identification of the event.
|
||||
/// </summary>
|
||||
public int CategoryID
|
||||
{
|
||||
get
|
||||
{
|
||||
OpenTVTitleDataRecord record = (OpenTVTitleDataRecord)getRecord(OpenTVTitleDataRecord.TagValue);
|
||||
return (record.CategoryID);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the name of the event.
|
||||
/// </summary>
|
||||
public string EventName
|
||||
{
|
||||
get
|
||||
{
|
||||
OpenTVTitleDataRecord record = (OpenTVTitleDataRecord)getRecord(OpenTVTitleDataRecord.TagValue);
|
||||
return (record.DecodedEventName);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the raw bytes of the event name.
|
||||
/// </summary>
|
||||
public byte[] EventNameBytes
|
||||
{
|
||||
get
|
||||
{
|
||||
OpenTVTitleDataRecord record = (OpenTVTitleDataRecord)getRecord(OpenTVTitleDataRecord.TagValue);
|
||||
return (record.EventName);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the flags field of the event.
|
||||
/// </summary>
|
||||
public byte[] Flags
|
||||
{
|
||||
get
|
||||
{
|
||||
OpenTVTitleDataRecord record = (OpenTVTitleDataRecord)getRecord(OpenTVTitleDataRecord.TagValue);
|
||||
return (record.Flags);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the collection of records for this title section.
|
||||
/// </summary>
|
||||
internal Collection<OpenTVRecordBase> Records
|
||||
{
|
||||
get
|
||||
{
|
||||
if (records == null)
|
||||
records = new Collection<OpenTVRecordBase>();
|
||||
return (records);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the collection of undefined records for this title section.
|
||||
/// </summary>
|
||||
internal Collection<OpenTVRecordBase> UndefinedRecords
|
||||
{
|
||||
get
|
||||
{
|
||||
if (records == null)
|
||||
return (null);
|
||||
|
||||
Collection<OpenTVRecordBase> undefinedRecords = new Collection<OpenTVRecordBase>();
|
||||
|
||||
foreach (OpenTVRecordBase record in records)
|
||||
{
|
||||
if (record.IsUndefined)
|
||||
undefinedRecords.Add(record);
|
||||
}
|
||||
|
||||
return (undefinedRecords);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return true if the entry is empty; false otherwise.
|
||||
/// </summary>
|
||||
public bool IsEmpty { get { return (records == null || records.Count == 0); } }
|
||||
|
||||
/// <summary>
|
||||
/// Get the PID of the section containing the data.
|
||||
/// </summary>
|
||||
public int PID { get { return (pid); } }
|
||||
/// <summary>
|
||||
/// Get the table ID of the section containing the data.
|
||||
/// </summary>
|
||||
public int Table { get { return (table); } }
|
||||
/// <summary>
|
||||
/// Get the timestamp when the data arrived.
|
||||
/// </summary>
|
||||
public DateTime TimeStamp { get { return (timeStamp); } }
|
||||
|
||||
/// <summary>
|
||||
/// Get the index of the next byte in the MPEG2 section following the title data.
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// The title data has not been processed.
|
||||
/// </exception>
|
||||
public int Index
|
||||
{
|
||||
get
|
||||
{
|
||||
if (lastIndex == -1)
|
||||
throw (new InvalidOperationException("OpenTVTitleData: Index requested before block processed"));
|
||||
return (lastIndex);
|
||||
}
|
||||
}
|
||||
|
||||
private int eventID;
|
||||
private int length;
|
||||
|
||||
private DateTime baseDate;
|
||||
|
||||
private int pid;
|
||||
private int table;
|
||||
private DateTime timeStamp;
|
||||
|
||||
private Collection<OpenTVRecordBase> records;
|
||||
|
||||
private int lastIndex = -1;
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new instance of the OpenTVTitleData class.
|
||||
/// </summary>
|
||||
public OpenTVTitleData() { }
|
||||
|
||||
/// <summary>
|
||||
/// Parse the title data.
|
||||
/// </summary>
|
||||
/// <param name="byteData">The MPEG2 section containing the title data.</param>
|
||||
/// <param name="index">Index of the first byte of the title data in the MPEG2 section.</param>
|
||||
/// <param name="baseDate">The base date for the programs.</param>
|
||||
/// <param name="channel">The channel for the data.</param>
|
||||
/// <param name="pid">The PID of the section.</param>
|
||||
/// <param name="table">The table ID of the section.</param>
|
||||
internal void Process(byte[] byteData, int index, DateTime baseDate, int channel, int pid, int table)
|
||||
{
|
||||
lastIndex = index;
|
||||
|
||||
this.pid = pid;
|
||||
this.table = table;
|
||||
this.baseDate = baseDate;
|
||||
|
||||
try
|
||||
{
|
||||
eventID = Utils.Convert2BytesToInt(byteData, lastIndex);
|
||||
lastIndex += 2;
|
||||
|
||||
length = ((byteData[lastIndex] & 0x0f) * 256) + byteData[lastIndex + 1];
|
||||
lastIndex += 2;
|
||||
|
||||
int recordLength = length;
|
||||
|
||||
while (recordLength != 0)
|
||||
{
|
||||
OpenTVRecordBase record = OpenTVRecordBase.Instance(byteData, lastIndex);
|
||||
Records.Add(record);
|
||||
|
||||
lastIndex += record.TotalLength;
|
||||
recordLength -= record.TotalLength;
|
||||
}
|
||||
|
||||
timeStamp = DateTime.Now;
|
||||
|
||||
Validate();
|
||||
}
|
||||
catch (IndexOutOfRangeException)
|
||||
{
|
||||
throw (new ArgumentOutOfRangeException("lastIndex = " + lastIndex));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validate the title data fields.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// A title data field is not valid.
|
||||
/// </exception>
|
||||
public void Validate() { }
|
||||
|
||||
/// <summary>
|
||||
/// Log the title data fields.
|
||||
/// </summary>
|
||||
public void LogMessage()
|
||||
{
|
||||
if (Logger.ProtocolLogger == null)
|
||||
return;
|
||||
|
||||
Logger.ProtocolLogger.Write(Logger.ProtocolIndent + "OPENTV TITLE DATA: Event ID: " + eventID +
|
||||
" Length: " + length);
|
||||
|
||||
if (records != null)
|
||||
{
|
||||
Logger.IncrementProtocolIndent();
|
||||
|
||||
foreach (OpenTVRecordBase record in records)
|
||||
record.LogMessage();
|
||||
|
||||
Logger.DecrementProtocolIndent();
|
||||
}
|
||||
}
|
||||
|
||||
private OpenTVRecordBase getRecord(int tag)
|
||||
{
|
||||
if (records == null)
|
||||
return(null);
|
||||
|
||||
foreach (OpenTVRecordBase record in records)
|
||||
{
|
||||
if (record.Tag == tag)
|
||||
return(record);
|
||||
}
|
||||
|
||||
return(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,164 @@
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// Copyright © 2005-2020 nzsjb //
|
||||
// //
|
||||
// This Program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation; either version 2, or (at your option) //
|
||||
// any later version. //
|
||||
// //
|
||||
// This Program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with GNU Make; see the file COPYING. If not, write to //
|
||||
// the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. //
|
||||
// http://www.gnu.org/copyleft/gpl.html //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
using System;
|
||||
|
||||
using DomainObjects;
|
||||
|
||||
namespace DVBServices
|
||||
{
|
||||
/// <summary>
|
||||
/// The class that describes an OpenTV title data record.
|
||||
/// </summary>
|
||||
internal class OpenTVTitleDataRecord : OpenTVRecordBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the tag value for this record.
|
||||
/// </summary>
|
||||
public const int TagValue = 0xb5;
|
||||
|
||||
/// <summary>
|
||||
/// Get the start time of the event.
|
||||
/// </summary>
|
||||
public TimeSpan StartTimeOffset { get { return (startTimeOffset); } }
|
||||
/// <summary>
|
||||
/// Get the duration of the event.
|
||||
/// </summary>
|
||||
public TimeSpan Duration { get { return (duration); } }
|
||||
/// <summary>
|
||||
/// Get the theme identification of the event.
|
||||
/// </summary>
|
||||
public int CategoryID { get { return (categoryID); } }
|
||||
/// <summary>
|
||||
/// Get the flags field of the event.
|
||||
/// </summary>
|
||||
public byte[] Flags { get { return (flags); } }
|
||||
/// <summary>
|
||||
/// Get the name of the event.
|
||||
/// </summary>
|
||||
public byte[] EventName { get { return (eventName); } }
|
||||
|
||||
/// <summary>
|
||||
/// Get the decompressed event name.
|
||||
/// </summary>
|
||||
public string DecodedEventName { get { return (SingleTreeDictionaryEntry.DecodeData(eventName)); } }
|
||||
|
||||
/// <summary>
|
||||
/// Get the index of the next byte in the MPEG2 section following the record.
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// The record has not been processed.
|
||||
/// </exception>
|
||||
public override int Index
|
||||
{
|
||||
get
|
||||
{
|
||||
if (lastIndex == -1)
|
||||
throw (new InvalidOperationException("OpenTVTitleDataRecord: Index requested before block processed"));
|
||||
return (lastIndex);
|
||||
}
|
||||
}
|
||||
|
||||
private TimeSpan startTimeOffset;
|
||||
private TimeSpan duration;
|
||||
private int categoryID;
|
||||
private byte[] flags;
|
||||
private byte[] eventName;
|
||||
|
||||
private int lastIndex = -1;
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new instance of the OpenTVTitleDataRecord class.
|
||||
/// </summary>
|
||||
internal OpenTVTitleDataRecord() { }
|
||||
|
||||
/// <summary>
|
||||
/// Parse the record.
|
||||
/// </summary>
|
||||
/// <param name="byteData">The MPEG2 section containing the record.</param>
|
||||
/// <param name="index">Index of the first byte of the record data in the MPEG2 section.</param>
|
||||
internal override void Process(byte[] byteData, int index)
|
||||
{
|
||||
lastIndex = index;
|
||||
|
||||
try
|
||||
{
|
||||
// Source value to 2 second resolution
|
||||
startTimeOffset = getTime((byteData[lastIndex] * 512) + (byteData[lastIndex + 1] * 2));
|
||||
lastIndex += 2;
|
||||
|
||||
duration = getTime(Utils.Convert2BytesToInt(byteData, lastIndex) * 2);
|
||||
lastIndex += 2;
|
||||
|
||||
categoryID = (int)byteData[lastIndex];
|
||||
lastIndex++;
|
||||
|
||||
flags = Utils.GetBytes(byteData, lastIndex, 2);
|
||||
lastIndex += 2;
|
||||
|
||||
eventName = Utils.GetBytes(byteData, lastIndex, Length - 7);
|
||||
lastIndex += Length - 7;
|
||||
|
||||
Validate();
|
||||
}
|
||||
catch (IndexOutOfRangeException)
|
||||
{
|
||||
throw (new ArgumentOutOfRangeException("lastIndex = " + lastIndex));
|
||||
}
|
||||
}
|
||||
|
||||
private TimeSpan getTime(int totalSeconds)
|
||||
{
|
||||
int days = totalSeconds / 86400;
|
||||
int hours = (totalSeconds - (days * 86400)) / 3600;
|
||||
int minutes = (totalSeconds - ((days * 86400) + (hours * 3600))) / 60;
|
||||
int seconds = totalSeconds % 60;
|
||||
|
||||
return (new TimeSpan(days, hours, minutes, seconds));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validate the record data fields.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// A record data field is not valid.
|
||||
/// </exception>
|
||||
internal override void Validate() { }
|
||||
|
||||
/// <summary>
|
||||
/// Log the record data fields.
|
||||
/// </summary>
|
||||
internal override void LogMessage()
|
||||
{
|
||||
if (Logger.ProtocolLogger == null)
|
||||
return;
|
||||
|
||||
Logger.ProtocolLogger.Write(Logger.ProtocolIndent + "");
|
||||
Logger.ProtocolLogger.Write(Logger.ProtocolIndent + "OPENTV TITLE DATA RECORD: " +
|
||||
"Start time: " + startTimeOffset +
|
||||
" Duration: " + duration +
|
||||
" Category: " + categoryID +
|
||||
" Unknown: " + Utils.ConvertToHex(flags) +
|
||||
" Name: " + Utils.ConvertToHex(eventName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,165 @@
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// Copyright © 2005-2020 nzsjb //
|
||||
// //
|
||||
// This Program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation; either version 2, or (at your option) //
|
||||
// any later version. //
|
||||
// //
|
||||
// This Program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with GNU Make; see the file COPYING. If not, write to //
|
||||
// the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. //
|
||||
// http://www.gnu.org/copyleft/gpl.html //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
using DomainObjects;
|
||||
|
||||
namespace DVBServices
|
||||
{
|
||||
/// <summary>
|
||||
/// The class that describes an Open TV title header.
|
||||
/// </summary>
|
||||
public class OpenTVTitleHeader
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the channel identification.
|
||||
/// </summary>
|
||||
public int ChannelID { get { return (channelID); } }
|
||||
/// <summary>
|
||||
/// Get the title date base.
|
||||
/// </summary>
|
||||
public DateTime BaseDate { get { return (baseDate); } }
|
||||
/// <summary>
|
||||
/// Get the data collection related to this title.
|
||||
/// </summary>
|
||||
public Collection<OpenTVTitleData> TitleData { get { return (titleData); } }
|
||||
|
||||
/// <summary>
|
||||
/// Get the index of the next byte in the MPEG2 section following the title header.
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// The title header has not been processed.
|
||||
/// </exception>
|
||||
public int Index
|
||||
{
|
||||
get
|
||||
{
|
||||
if (lastIndex == -1)
|
||||
throw (new InvalidOperationException("OpenTVTitleHeader: Index requested before block processed"));
|
||||
return (lastIndex);
|
||||
}
|
||||
}
|
||||
|
||||
private int channelID;
|
||||
private DateTime baseDate;
|
||||
private Collection<OpenTVTitleData> titleData;
|
||||
|
||||
private int lastIndex = -1;
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new instance of the OpenTVTitleHeader class.
|
||||
/// </summary>
|
||||
public OpenTVTitleHeader() { }
|
||||
|
||||
/// <summary>
|
||||
/// Parse the title header.
|
||||
/// </summary>
|
||||
/// <param name="byteData">The MPEG2 section containing the title header.</param>
|
||||
/// <param name="index">Index of the first byte of the title header in the MPEG2 section.</param>
|
||||
/// <param name="mpeg2Header">The MPEG2 header of the section.</param>
|
||||
/// <param name="pid">The PID of the section.</param>
|
||||
/// <param name="tid">The table ID of the section.</param>
|
||||
internal void Process(byte[] byteData, int index, Mpeg2ExtendedHeader mpeg2Header, int pid, int tid)
|
||||
{
|
||||
lastIndex = index;
|
||||
|
||||
channelID = mpeg2Header.TableIDExtension;
|
||||
|
||||
try
|
||||
{
|
||||
baseDate = getDate(Utils.Convert2BytesToInt(byteData, lastIndex));
|
||||
lastIndex += 2;
|
||||
|
||||
while (lastIndex < byteData.Length - 4)
|
||||
{
|
||||
OpenTVTitleData data = new OpenTVTitleData();
|
||||
data.Process(byteData, lastIndex, baseDate, channelID, pid, tid);
|
||||
|
||||
if (!data.IsEmpty)
|
||||
{
|
||||
if (titleData == null)
|
||||
titleData = new Collection<OpenTVTitleData>();
|
||||
titleData.Add(data);
|
||||
}
|
||||
|
||||
lastIndex = data.Index;
|
||||
}
|
||||
|
||||
Validate();
|
||||
}
|
||||
catch (IndexOutOfRangeException)
|
||||
{
|
||||
throw (new ArgumentOutOfRangeException("lastIndex = " + lastIndex));
|
||||
}
|
||||
}
|
||||
|
||||
private DateTime getDate(int mjd)
|
||||
{
|
||||
int j = mjd + 2400001 + 68569;
|
||||
int c = 4 * j / 146097;
|
||||
j = j - (146097 * c + 3) / 4;
|
||||
|
||||
int y = 4000 * (j + 1) / 1461001;
|
||||
j = j - 1461 * y / 4 + 31;
|
||||
int m = 80 * j / 2447;
|
||||
|
||||
int day = j - 2447 * m / 80;
|
||||
j = m / 11;
|
||||
int month = m + 2 - (12 * j);
|
||||
int year = 100 * (c - 49) + y + j;
|
||||
|
||||
return (new DateTime(year, month, day));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validate the title header fields.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// A title header field is not valid.
|
||||
/// </exception>
|
||||
public void Validate() { }
|
||||
|
||||
/// <summary>
|
||||
/// Log the title header fields.
|
||||
/// </summary>
|
||||
public void LogMessage()
|
||||
{
|
||||
if (Logger.ProtocolLogger == null)
|
||||
return;
|
||||
|
||||
Logger.ProtocolLogger.Write(Logger.ProtocolIndent + "OPENTV TITLE HEADER: Channel ID: " + channelID +
|
||||
" Base date : " + baseDate);
|
||||
|
||||
if (titleData != null)
|
||||
{
|
||||
Logger.IncrementProtocolIndent();
|
||||
|
||||
foreach (OpenTVTitleData data in titleData)
|
||||
data.LogMessage();
|
||||
|
||||
Logger.DecrementProtocolIndent();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,126 @@
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// Copyright © 2005-2020 nzsjb //
|
||||
// //
|
||||
// This Program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation; either version 2, or (at your option) //
|
||||
// any later version. //
|
||||
// //
|
||||
// This Program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with GNU Make; see the file COPYING. If not, write to //
|
||||
// the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. //
|
||||
// http://www.gnu.org/copyleft/gpl.html //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
using System;
|
||||
|
||||
using DomainObjects;
|
||||
|
||||
namespace DVBServices
|
||||
{
|
||||
/// <summary>
|
||||
/// The class that describes an Open TV Title section.
|
||||
/// </summary>
|
||||
public class OpenTVTitleSection
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the section number.
|
||||
/// </summary>
|
||||
public int SectionNumber { get { return (sectionNumber); } }
|
||||
/// <summary>
|
||||
/// Get the section number.
|
||||
/// </summary>
|
||||
public int LastSectionNumber { get { return (lastSectionNumber); } }
|
||||
/// <summary>
|
||||
/// Get the title header.
|
||||
/// </summary>
|
||||
public OpenTVTitleHeader TitleHeader { get { return (titleHeader); } }
|
||||
|
||||
private int sectionNumber;
|
||||
private int lastSectionNumber;
|
||||
private OpenTVTitleHeader titleHeader;
|
||||
|
||||
private int lastIndex = -1;
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new instance of the OpenTVTitleSection class.
|
||||
/// </summary>
|
||||
internal OpenTVTitleSection() { }
|
||||
|
||||
/// <summary>
|
||||
/// Parse the section.
|
||||
/// </summary>
|
||||
/// <param name="byteData">The MPEG2 section containing the section.</param>
|
||||
/// <param name="mpeg2Header">The MPEG2 header that preceedes the section.</param>
|
||||
/// <param name="pid">The PID containing the section.</param>
|
||||
/// <param name="tid">The table ID containing the section.</param>
|
||||
internal void Process(byte[] byteData, Mpeg2ExtendedHeader mpeg2Header, int pid, int tid)
|
||||
{
|
||||
lastIndex = mpeg2Header.Index;
|
||||
sectionNumber = mpeg2Header.SectionNumber;
|
||||
lastSectionNumber = mpeg2Header.LastSectionNumber;
|
||||
|
||||
titleHeader = new OpenTVTitleHeader();
|
||||
titleHeader.Process(byteData, lastIndex, mpeg2Header, pid, tid);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Log the section fields.
|
||||
/// </summary>
|
||||
public void LogMessage()
|
||||
{
|
||||
if (Logger.ProtocolLogger == null)
|
||||
return;
|
||||
|
||||
titleHeader.LogMessage();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process an MPEG2 section from the Open TV Title table.
|
||||
/// </summary>
|
||||
/// <param name="byteData">The MPEG2 section.</param>
|
||||
/// <param name="pid">The PID containing the section.</param>
|
||||
/// <param name="table">The table ID containing the section.</param>
|
||||
/// <returns>An Open TV Title Section instance or null if a section is not created.</returns>
|
||||
public static OpenTVTitleSection ProcessOpenTVTitleTable(byte[] byteData, int pid, int table)
|
||||
{
|
||||
Mpeg2ExtendedHeader mpeg2Header = new Mpeg2ExtendedHeader();
|
||||
|
||||
try
|
||||
{
|
||||
mpeg2Header.Process(byteData);
|
||||
|
||||
if (mpeg2Header.Current)
|
||||
{
|
||||
OpenTVTitleSection openTVTitleSection = new OpenTVTitleSection();
|
||||
openTVTitleSection.Process(byteData, mpeg2Header, pid, table);
|
||||
openTVTitleSection.LogMessage();
|
||||
return (openTVTitleSection);
|
||||
}
|
||||
else
|
||||
return (null);
|
||||
}
|
||||
catch (ArgumentOutOfRangeException e)
|
||||
{
|
||||
Logger.Instance.Write("<e> Error processing Title Section: " + e.Message);
|
||||
|
||||
if (DebugEntry.IsDefined(DebugName.TitleSection))
|
||||
{
|
||||
Logger.Instance.Write(e.Message);
|
||||
Logger.Instance.Write(e.StackTrace);
|
||||
Logger.Instance.Dump("Title Section", byteData, byteData.Length);
|
||||
}
|
||||
|
||||
return (null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -138,5 +138,42 @@ namespace DVBServices
|
||||
temp = "";
|
||||
return temp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert an integer value to a hex string.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to be converted.</param>
|
||||
/// <returns>The converted string.</returns>
|
||||
public static string ConvertToHex(int value)
|
||||
{
|
||||
if (value == 0)
|
||||
return ("0x00");
|
||||
|
||||
uint tempValue = (uint)value;
|
||||
|
||||
char[] outputChars = new char[8];
|
||||
|
||||
int outputIndex = 7;
|
||||
|
||||
for (int index = 3; index > -1; index--)
|
||||
{
|
||||
uint hexByte = (tempValue << 24) >> 24;
|
||||
int hexByteLeft = (int)(hexByte >> 4);
|
||||
int hexByteRight = (int)(hexByte & 0x0f);
|
||||
|
||||
outputChars[outputIndex] = getHex(hexByteRight);
|
||||
outputChars[outputIndex - 1] = getHex(hexByteLeft);
|
||||
|
||||
outputIndex -= 2;
|
||||
tempValue = tempValue >> 8;
|
||||
}
|
||||
|
||||
string replyString = new string(outputChars).TrimStart(new char[] { '0' });
|
||||
|
||||
if (replyString.Length % 2 == 0)
|
||||
return ("0x" + replyString);
|
||||
else
|
||||
return ("0x0" + replyString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,266 @@
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// Copyright © 2005-2020 nzsjb //
|
||||
// //
|
||||
// This Program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation; either version 2, or (at your option) //
|
||||
// any later version. //
|
||||
// //
|
||||
// This Program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with GNU Make; see the file COPYING. If not, write to //
|
||||
// the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. //
|
||||
// http://www.gnu.org/copyleft/gpl.html //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace DomainObjects
|
||||
{
|
||||
/// <summary>
|
||||
/// The class that describes a trace parameter entry.
|
||||
/// </summary>
|
||||
public class TraceEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the last error message.
|
||||
/// </summary>
|
||||
public static string LastError { get { return (lastError); } }
|
||||
|
||||
/// <summary>
|
||||
/// Get the entry name.
|
||||
/// </summary>
|
||||
public TraceName Name { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Get or set the number entry parameter.
|
||||
/// </summary>
|
||||
public int NumberParameter
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!numberParameterSet)
|
||||
throw (new InvalidOperationException("TraceEntry number parameter not set"));
|
||||
|
||||
return (numberParameter);
|
||||
}
|
||||
set
|
||||
{
|
||||
numberParameter = value;
|
||||
numberParameterSet = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get or set the string entry parameter.
|
||||
/// </summary>
|
||||
public string StringParameter
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!stringParameterSet)
|
||||
throw (new InvalidOperationException("TraceEntry string parameter not set"));
|
||||
|
||||
return (stringParameter);
|
||||
}
|
||||
set
|
||||
{
|
||||
stringParameter = value;
|
||||
stringParameterSet = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return true if the entry number parameter has been set; false otherwise.
|
||||
/// </summary>
|
||||
public bool NumberParameterSet { get { return (numberParameterSet); } }
|
||||
/// <summary>
|
||||
/// Return true if the entry string parameter has been set; false otherwise.
|
||||
/// </summary>
|
||||
public bool StringParameterSet { get { return (stringParameterSet); } }
|
||||
|
||||
private int numberParameter;
|
||||
private bool numberParameterSet;
|
||||
private string stringParameter;
|
||||
private bool stringParameterSet;
|
||||
|
||||
private static string lastError;
|
||||
|
||||
private TraceEntry() { }
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new instance of the TraceEntry class with a name.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the entry.</param>
|
||||
public TraceEntry(TraceName name)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new entry of the TraceEntry class with a name and number parameter.
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="parameter"></param>
|
||||
public TraceEntry(TraceName name, int parameter) : this(name)
|
||||
{
|
||||
NumberParameter = parameter;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new entry of the TraceEntry class with a name and string parameter.
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="parameter"></param>
|
||||
public TraceEntry(TraceName name, string parameter) : this(name)
|
||||
{
|
||||
StringParameter = parameter;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a string representation of the instance.
|
||||
/// </summary>
|
||||
/// <returns>A string representing the instance.</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
if (numberParameterSet)
|
||||
return (Name.ToString() + "-" + NumberParameter);
|
||||
else
|
||||
{
|
||||
if (stringParameterSet)
|
||||
return (Name.ToString() + "-" + '"' + StringParameter + '"');
|
||||
else
|
||||
return (Name.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy the instance.
|
||||
/// </summary>
|
||||
/// <returns>A new instance of the TraceEntry class with the same values as this instance.</returns>
|
||||
public TraceEntry Clone()
|
||||
{
|
||||
TraceEntry newEntry = new TraceEntry(Name);
|
||||
|
||||
if (numberParameterSet)
|
||||
newEntry.NumberParameter = NumberParameter;
|
||||
if (stringParameterSet)
|
||||
newEntry.StringParameter = StringParameter;
|
||||
|
||||
return (newEntry);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get an instance of the TraceEntry from a parameter file entry.
|
||||
/// </summary>
|
||||
/// <param name="parameter">The parameter file entry.</param>
|
||||
/// <returns>A new instance of the class.</returns>
|
||||
public static TraceEntry GetInstance(string parameter)
|
||||
{
|
||||
string[] parameterParts = parameter.Split(new char[] { '-' });
|
||||
|
||||
if (parameterParts.Length == 2 && string.IsNullOrWhiteSpace(parameterParts[1]))
|
||||
return(null);
|
||||
|
||||
try
|
||||
{
|
||||
TraceEntry traceEntry = new TraceEntry((TraceName)Enum.Parse(typeof(TraceName), parameterParts[0].Trim(), true));
|
||||
|
||||
if (parameterParts.Length == 2)
|
||||
{
|
||||
if (parameterParts[1].Trim()[0] != '"')
|
||||
{
|
||||
try
|
||||
{
|
||||
traceEntry.NumberParameter = Int32.Parse(parameterParts[1]);
|
||||
}
|
||||
catch (FormatException)
|
||||
{
|
||||
lastError = "The Trace name '" + parameterParts[0].Trim() + "' has a parameter in the wrong format.";
|
||||
return (null);
|
||||
}
|
||||
catch (OverflowException)
|
||||
{
|
||||
lastError = "The Trace name '" + parameterParts[0].Trim() + "' has a parameter out of range.";
|
||||
return (null);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (parameterParts[1].Trim().Length < 3 || parameterParts[1].Trim()[parameterParts[1].Length - 1] != '"')
|
||||
return (null);
|
||||
|
||||
traceEntry.StringParameter = parameterParts[1].Trim().Substring(1, parameterParts[1].Length - 2);
|
||||
}
|
||||
}
|
||||
|
||||
return (traceEntry);
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
lastError = "The Trace ID '" + parameter.Trim() + "' is undefined and will be ignored.";
|
||||
return (null);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if a trace name is present.
|
||||
/// </summary>
|
||||
/// <param name="traceName">The name of the trace entry.</param>
|
||||
/// <returns>True if the trace name is present; false otherwise.</returns>
|
||||
public static bool IsDefined(TraceName traceName)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find a trace entry.
|
||||
/// </summary>
|
||||
/// <param name="traceName">The name of the trace entry.</param>
|
||||
/// <returns>The trace entry if it is found; otherwise null</returns>
|
||||
public static TraceEntry FindEntry(TraceName traceName)
|
||||
{
|
||||
return (FindEntry(traceName, false));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find a trace entry.
|
||||
/// </summary>
|
||||
/// <param name="traceName">The name of the trace entry.</param>
|
||||
/// <param name="withParameter">True if a parameter must be present; false otherwise.</param>
|
||||
/// <returns>The trace entry if it is found; otherwise null</returns>
|
||||
public static TraceEntry FindEntry(TraceName traceName, bool withParameter)
|
||||
{
|
||||
//feyris-tan: We don't use these in skyscraper, so we'll just always return null
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find a trace entry.
|
||||
/// </summary>
|
||||
/// <param name="traceEntries">The list of trace entries to search.</param>
|
||||
/// <param name="identifier">The string representation of the debug entry.</param>
|
||||
/// <returns>The trace entry if it is found; otherwise null</returns>
|
||||
public static TraceEntry FindEntry(Collection<TraceEntry> traceEntries, string identifier)
|
||||
{
|
||||
if (traceEntries == null)
|
||||
return (null);
|
||||
|
||||
foreach (TraceEntry traceEntry in traceEntries)
|
||||
{
|
||||
if (traceEntry.ToString().ToUpperInvariant() == identifier.ToUpperInvariant())
|
||||
return (traceEntry);
|
||||
}
|
||||
|
||||
return (null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,68 @@
|
||||
using skyscraper5.Data.PostgreSql;
|
||||
using skyscraper5.Skyscraper.Scraper.Storage.InMemory;
|
||||
using skyscraper8.EPGCollectorPort.SkyscraperSide.MediaHighway2;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace skyscraper8.EPGCollectorPort.SkyscraperSide.OpenTV
|
||||
{
|
||||
internal interface IOpenTvDataStorage
|
||||
{
|
||||
bool TestForTitles(int skyscraperContextCurrentNetworkId, int skyscraperContextCurrentTransportStreamId, int titleDataEventId, DateTime titleDataStartTime);
|
||||
}
|
||||
|
||||
internal class OpenTvDataStorageImpl : IOpenTvDataStorage
|
||||
{
|
||||
private IOpenTvDataStorage _storageEngine;
|
||||
|
||||
public OpenTvDataStorageImpl(object[] getPluginConnector)
|
||||
{
|
||||
object o = getPluginConnector[0];
|
||||
switch (o)
|
||||
{
|
||||
case InMemoryPluginToken t1:
|
||||
_storageEngine = new OpenTvDataStorageMemory();
|
||||
break;
|
||||
case PostgresqlToken t2:
|
||||
_storageEngine = new OpenTvDataStoragePostgresql(t2);
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException(o.GetType().FullName);
|
||||
}
|
||||
}
|
||||
|
||||
public bool TestForTitles(int skyscraperContextCurrentNetworkId, int skyscraperContextCurrentTransportStreamId,
|
||||
int titleDataEventId, DateTime titleDataStartTime)
|
||||
{
|
||||
return _storageEngine.TestForTitles(skyscraperContextCurrentNetworkId, skyscraperContextCurrentTransportStreamId, titleDataEventId, titleDataStartTime);
|
||||
}
|
||||
}
|
||||
|
||||
internal class OpenTvDataStorageMemory : IOpenTvDataStorage
|
||||
{
|
||||
public bool TestForTitles(int skyscraperContextCurrentNetworkId, int skyscraperContextCurrentTransportStreamId,
|
||||
int titleDataEventId, DateTime titleDataStartTime)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
internal class OpenTvDataStoragePostgresql : IOpenTvDataStorage
|
||||
{
|
||||
private readonly PostgresqlToken _postgresql;
|
||||
|
||||
public OpenTvDataStoragePostgresql(PostgresqlToken postgresql)
|
||||
{
|
||||
_postgresql = postgresql;
|
||||
}
|
||||
|
||||
public bool TestForTitles(int skyscraperContextCurrentNetworkId, int skyscraperContextCurrentTransportStreamId,
|
||||
int titleDataEventId, DateTime titleDataStartTime)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace skyscraper8.EPGCollectorPort.SkyscraperSide.OpenTV
|
||||
{
|
||||
internal enum OpenTvExpectedDataType
|
||||
{
|
||||
Titles,
|
||||
Summaries
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using DVBServices;
|
||||
|
||||
namespace skyscraper8.EPGCollectorPort.SkyscraperSide.OpenTV
|
||||
{
|
||||
internal interface OpenTvHandler
|
||||
{
|
||||
void OnNonOpenTvTraffic(int sourcePid, OpenTvExpectedDataType titles, int sectionTableId);
|
||||
void OnTitles(int sourcePid, int sectionTableId, OpenTVTitleSection titleSection);
|
||||
void OnSummaries(int sourcePid, int sectionTableId, OpenTVSummarySection summarySection);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,59 @@
|
||||
using DVBServices;
|
||||
using skyscraper5.Skyscraper.Scraper;
|
||||
using skyscraper8.Skyscraper.Plugins;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace skyscraper8.EPGCollectorPort.SkyscraperSide.OpenTV
|
||||
{
|
||||
internal class OpenTvScraper : OpenTvHandler
|
||||
{
|
||||
private readonly SkyscraperContext _skyscraperContext;
|
||||
private readonly IOpenTvDataStorage storage;
|
||||
private static PluginLogger _logger;
|
||||
|
||||
public OpenTvScraper(SkyscraperContext skyscraperContext)
|
||||
{
|
||||
_skyscraperContext = skyscraperContext;
|
||||
storage = new OpenTvDataStorageImpl(skyscraperContext.DataStorage.GetPluginConnector());
|
||||
if (_logger == null)
|
||||
{
|
||||
_logger = PluginLogManager.GetLogger(GetType());
|
||||
}
|
||||
}
|
||||
|
||||
public void OnNonOpenTvTraffic(int sourcePid, OpenTvExpectedDataType titles, int sectionTableId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void OnTitles(int sourcePid, int sectionTableId, OpenTVTitleSection titleSection)
|
||||
{
|
||||
if (!_skyscraperContext.CurrentNetworkId.HasValue)
|
||||
return;
|
||||
if (!_skyscraperContext.CurrentTransportStreamId.HasValue)
|
||||
return;
|
||||
|
||||
foreach (OpenTVTitleData titleData in titleSection.TitleHeader.TitleData)
|
||||
{
|
||||
if (!storage.TestForTitles(_skyscraperContext.CurrentNetworkId.Value, _skyscraperContext.CurrentTransportStreamId.Value, titleData.EventID, titleData.StartTime))
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnSummaries(int sourcePid, int sectionTableId, OpenTVSummarySection summarySection)
|
||||
{
|
||||
if (!_skyscraperContext.CurrentNetworkId.HasValue)
|
||||
return;
|
||||
if (!_skyscraperContext.CurrentTransportStreamId.HasValue)
|
||||
return;
|
||||
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,68 @@
|
||||
using DVBServices;
|
||||
using skyscraper5.Mpeg2;
|
||||
using skyscraper5.Skyscraper.Plugins;
|
||||
using skyscraper5.Skyscraper.Scraper;
|
||||
using skyscraper5.Skyscraper.Scraper.StreamAutodetection;
|
||||
using skyscraper8.EPGCollectorPort.SkyscraperSide.MediaHighway2;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace skyscraper8.EPGCollectorPort.SkyscraperSide.OpenTV
|
||||
{
|
||||
////Disabled due to the Huffmann Table being dynamically determined.
|
||||
//[SkyscraperPlugin]
|
||||
internal class OpenTvSummaryContestant : Contestant, OpenTvHandler
|
||||
{
|
||||
public OpenTvSummaryContestant(int pid)
|
||||
: base("OpenTV Summaries", pid)
|
||||
{
|
||||
PacketProcessor = new PsiDecoder(pid, new OpenTvSummaryParser(this));
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void DeclareWinner(SkyscraperContext skyscraperContext, int pid, ProgramContext programContext)
|
||||
{
|
||||
OpenTvScraper openTvScraper = skyscraperContext.PluginContext.FirstOrDefault(x => x is OpenTvScraper) as OpenTvScraper;
|
||||
if (openTvScraper == null)
|
||||
{
|
||||
openTvScraper = new OpenTvScraper(skyscraperContext);
|
||||
skyscraperContext.PluginContext.Add(openTvScraper);
|
||||
}
|
||||
|
||||
skyscraperContext.DvbContext.RegisterPacketProcessor(pid, new PsiDecoder(pid, new OpenTvSummaryParser(openTvScraper)));
|
||||
}
|
||||
|
||||
public override void Introduce(ProgramContext programContext)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private byte[] nonTrafficMarkers;
|
||||
public void OnNonOpenTvTraffic(int sourcePid, OpenTvExpectedDataType titles, int sectionTableId)
|
||||
{
|
||||
if (nonTrafficMarkers == null)
|
||||
nonTrafficMarkers = new byte[byte.MaxValue];
|
||||
|
||||
nonTrafficMarkers[sectionTableId]++;
|
||||
if (nonTrafficMarkers[sectionTableId] == 1)
|
||||
Score++;
|
||||
}
|
||||
|
||||
public void OnTitles(int sourcePid, int sectionTableId, OpenTVTitleSection titleSection)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void OnSummaries(int sourcePid, int sectionTableId, OpenTVSummarySection summarySection)
|
||||
{
|
||||
Score++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using DVBServices;
|
||||
using skyscraper5.Mpeg2;
|
||||
|
||||
namespace skyscraper8.EPGCollectorPort.SkyscraperSide.OpenTV
|
||||
{
|
||||
internal class OpenTvSummaryParser : IPsiProcessor
|
||||
{
|
||||
private readonly OpenTvHandler _openTvScraper;
|
||||
|
||||
public OpenTvSummaryParser(OpenTvHandler openTvScraper)
|
||||
{
|
||||
_openTvScraper = openTvScraper;
|
||||
}
|
||||
|
||||
public void GatherPsi(PsiSection section, int sourcePid)
|
||||
{
|
||||
if (section.TableId >= 0xa8 && section.TableId <= 0xab)
|
||||
{
|
||||
OpenTVSummarySection summarySection = OpenTVSummarySection.ProcessOpenTVSummaryTable(section.GetData());
|
||||
if (summarySection != null)
|
||||
{
|
||||
_openTvScraper.OnSummaries(sourcePid, section.TableId, summarySection);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (section.TableId >= 0xa0 && section.TableId <= 0xa7)
|
||||
{
|
||||
//Titles
|
||||
return;
|
||||
}
|
||||
|
||||
_openTvScraper.OnNonOpenTvTraffic(sourcePid, OpenTvExpectedDataType.Summaries, section.TableId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,62 @@
|
||||
using DVBServices;
|
||||
using skyscraper5.Mpeg2;
|
||||
using skyscraper5.Skyscraper.Plugins;
|
||||
using skyscraper5.Skyscraper.Scraper;
|
||||
using skyscraper5.Skyscraper.Scraper.StreamAutodetection;
|
||||
using skyscraper8.EPGCollectorPort.SkyscraperSide.MediaHighway2;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace skyscraper8.EPGCollectorPort.SkyscraperSide.OpenTV
|
||||
{
|
||||
//Disabled due to the Huffmann Table being dynamically determined.
|
||||
//[SkyscraperPlugin]
|
||||
internal class OpenTvTitleContestant : Contestant, OpenTvHandler
|
||||
{
|
||||
public OpenTvTitleContestant(int pid)
|
||||
: base("OpenTV Titles", pid)
|
||||
{
|
||||
PacketProcessor = new PsiDecoder(pid, new OpenTvTitleParser(this));
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void DeclareWinner(SkyscraperContext skyscraperContext, int pid, ProgramContext programContext)
|
||||
{
|
||||
OpenTvScraper openTvScraper = skyscraperContext.PluginContext.FirstOrDefault(x => x is OpenTvScraper) as OpenTvScraper;
|
||||
if (openTvScraper == null)
|
||||
{
|
||||
openTvScraper = new OpenTvScraper(skyscraperContext);
|
||||
skyscraperContext.PluginContext.Add(openTvScraper);
|
||||
}
|
||||
|
||||
skyscraperContext.DvbContext.RegisterPacketProcessor(pid, new PsiDecoder(pid, new OpenTvTitleParser(openTvScraper)));
|
||||
}
|
||||
|
||||
public override void Introduce(ProgramContext programContext)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void OnNonOpenTvTraffic(int sourcePid, OpenTvExpectedDataType titles, int sectionTableId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void OnTitles(int sourcePid, int sectionTableId, OpenTVTitleSection titleSection)
|
||||
{
|
||||
Score++;
|
||||
}
|
||||
|
||||
public void OnSummaries(int sourcePid, int sectionTableId, OpenTVSummarySection summarySection)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using DVBServices;
|
||||
using skyscraper5.Mpeg2;
|
||||
|
||||
namespace skyscraper8.EPGCollectorPort.SkyscraperSide.OpenTV
|
||||
{
|
||||
internal class OpenTvTitleParser : IPsiProcessor
|
||||
{
|
||||
private readonly OpenTvHandler _handler;
|
||||
|
||||
public OpenTvTitleParser(OpenTvHandler handler)
|
||||
{
|
||||
_handler = handler;
|
||||
}
|
||||
|
||||
public void GatherPsi(PsiSection section, int sourcePid)
|
||||
{
|
||||
if (section.TableId >= 0xa0 && section.TableId <= 0xa7)
|
||||
{
|
||||
OpenTVTitleSection titleSection = OpenTVTitleSection.ProcessOpenTVTitleTable(section.GetData(),sourcePid,section.TableId);
|
||||
if (titleSection != null)
|
||||
{
|
||||
_handler.OnTitles(sourcePid, section.TableId, titleSection);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (section.TableId >= 0xa8 && section.TableId <= 0xab)
|
||||
{
|
||||
//Summaries.
|
||||
return;
|
||||
}
|
||||
|
||||
_handler.OnNonOpenTvTraffic(sourcePid,OpenTvExpectedDataType.Titles, section.TableId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -40,6 +40,7 @@ namespace skyscraper5
|
||||
|
||||
private static void IntegrationTest()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static void Main(string[] args)
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
"profiles": {
|
||||
"skyscraper8": {
|
||||
"commandName": "Project",
|
||||
"commandLineArgs": "cscan-live tcp://tetsuro:6969",
|
||||
"commandLineArgs": "file-live \"C:\\Temp\\sky-uk-000000.ts\"",
|
||||
"remoteDebugEnabled": false
|
||||
},
|
||||
"Container (Dockerfile)": {
|
||||
|
||||
@ -633,12 +633,7 @@ namespace skyscraper5.Skyscraper.Scraper
|
||||
interactionChannelDecoder.Handler = this;
|
||||
DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, new PsiDecoder(mappingStream.ElementaryPid, interactionChannelDecoder));
|
||||
break;
|
||||
case StreamType.OpenTvPrivate:
|
||||
DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, new OpenTvPrivate());
|
||||
break;
|
||||
case StreamType.BSkyBPrivate:
|
||||
DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, new BSkyBPrivate());
|
||||
break;
|
||||
|
||||
case StreamType.Id3:
|
||||
DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, new PesDecoder(new Id3PesProcessor(this)));
|
||||
break;
|
||||
@ -934,18 +929,6 @@ namespace skyscraper5.Skyscraper.Scraper
|
||||
}
|
||||
}
|
||||
|
||||
if (stream.PrivateDataSpecifier == 0x00000002)
|
||||
{
|
||||
if (stream.UnknownUserDefines != null)
|
||||
{
|
||||
UserDefinedDescriptor userDefinedDescriptor = stream.UnknownUserDefines.Find(x => x.DescriptorTag == 0xb0);
|
||||
if (userDefinedDescriptor != null)
|
||||
{
|
||||
//BSkyB EPG Related descriptor
|
||||
return StreamType.BSkyBPrivate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (stream.MetadataApplicationFormat == 0xffff && stream.MetadataApplicationFormatIdentifier == 0x49443320 && stream.MetadataFormat == 0xff && stream.MetadataFormatIdentifier == 0x49443320)
|
||||
{
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user