- added support for Hisense HIS_DVB.BIN channel lists

This commit is contained in:
Horst Beham
2023-01-23 00:28:49 +01:00
parent ff452d3a6c
commit f21cef5b6d
8 changed files with 459 additions and 5 deletions

View File

@@ -59,4 +59,9 @@
<ItemGroup>
<Content Remove="C:\Users\horst\.nuget\packages\sqlitepclraw.lib.e_sqlite3\2.1.2\buildTransitive\net461\..\..\runtimes\win-arm\native\e_sqlite3.dll" />
</ItemGroup>
<ItemGroup>
<Reference Include="DevExpress.PivotGrid.v22.1.Core">
<HintPath>..\..\..\..\..\Program Files\DevExpress 22.1\Components\Bin\Framework\DevExpress.PivotGrid.v22.1.Core.dll</HintPath>
</Reference>
</ItemGroup>
</Project>

View File

@@ -1,4 +1,8 @@
[Header]
; ========================================
; HIS_SVL.BIN, HIS_TSL.BIN and HIS_FAV.BIN
; ========================================
[Header]
RecordSize=40
ID=0
Name=2
@@ -86,3 +90,42 @@ DisplayNumber=4
DisplayNumberLength=10
ChannelName=15
ChannelNameLength=64
; ========================================
; HIS_DVB.BIN
; ========================================
[HIS_DVB.BIN]
HeaderSize=16
Version=0
NumChannelsDvbT=4
NumChannelsDvbC=8
NumChannelsDvbS=12
[HIS_DVB.BIN_Record]
RecordSizeDvbT=498
RecordSizeDvbC=498
RecordSizeDvbS=562
Skip=21
Lock=22
TvRadioData=29
Fav=30
ServiceType=35
PcrPid=36
VideoPid=38
ProgNum=40
PmtPid=46
ServiceId=48
;@62: languages[3]
AudioPid=68
Name=286
NameLength=50
Provider=336
ProviderLength=50
Tsid=398
Onid=400
Frequency=408
SymbolRate=420
SatName=500
SatNameLength=32
SatOrbitalPos=548

View File

@@ -0,0 +1,321 @@
using System.IO;
using System.Linq;
using System.Text;
using ChanSort.Api;
namespace ChanSort.Loader.Hisense.HisBin;
/*
* Loads Hisense HIS_DVB.BIN channel lists
*
* See also the his-dvb.h file in Information/FileStructures_for_HHD_Hex_Editor_Neo
*
* Some properties of these lists:
* - channel records are physically ordered by their program number
* - TV and radio are managed in separate lists, both starting at 1
* - channel and provider names are raw DVB strings including control bytes
*/
public class HisDvbBinSerializer : SerializerBase
{
private readonly ChannelList antTvChannels = new(SignalSource.DvbT | SignalSource.Tv, "Antenna TV");
private readonly ChannelList antRadioChannels = new(SignalSource.DvbT | SignalSource.Radio, "Antenna Radio");
private readonly ChannelList antDataChannels = new(SignalSource.DvbT | SignalSource.Data, "Antenna Data");
private readonly ChannelList cabTvChannels = new(SignalSource.DvbC | SignalSource.Tv, "Cable TV");
private readonly ChannelList cabRadioChannels = new(SignalSource.DvbC | SignalSource.Radio, "Cable Radio");
private readonly ChannelList cabDataChannels = new(SignalSource.DvbC | SignalSource.Data, "Cable Data");
private readonly ChannelList satTvChannels = new(SignalSource.DvbS | SignalSource.Tv, "Sat TV");
private readonly ChannelList satRadioChannels = new(SignalSource.DvbS | SignalSource.Radio, "Sat Radio");
private readonly ChannelList satDataChannels = new(SignalSource.DvbS | SignalSource.Data, "Sat Data");
private SubListInfo[] subListInfos;
private byte[] fileContent;
private int headerRecordSize, antRecordSize, cabRecordSize, satRecordSize;
private const string ERR_badFileFormat = "The content of the file doesn't match the expected format.";
private IniFile ini;
private DataMapping headerMapping, dvbMapping;
private DvbStringDecoder dvbStringDecoder;
#region class SubListInfo
private struct SubListInfo
{
public int Count;
public int Size;
public ChannelList TvList;
public ChannelList RadioList;
public ChannelList DataList;
public bool IsSat;
public SubListInfo(int count, int size, ChannelList tvList, ChannelList radioList, ChannelList dataList, bool isSat)
{
Count = count;
Size = size;
TvList = tvList;
RadioList = radioList;
DataList = dataList;
IsSat = isSat;
}
}
#endregion
#region ctor()
public HisDvbBinSerializer(string inputFile) : base(inputFile)
{
this.Features.ChannelNameEdit = ChannelNameEditMode.None;
this.Features.CanSkipChannels = true;
this.Features.CanLockChannels = true;
this.Features.CanHideChannels = false;
this.Features.FavoritesMode = FavoritesMode.Flags;
this.Features.MaxFavoriteLists = 1;
this.Features.DeleteMode = DeleteMode.Physically;
this.Features.CanHaveGaps = true;
this.Features.AllowGapsInFavNumbers = false;
this.ReadConfigurationFromIniFile();
this.DataRoot.AddChannelList(antTvChannels);
this.DataRoot.AddChannelList(antRadioChannels);
this.DataRoot.AddChannelList(antDataChannels);
this.DataRoot.AddChannelList(cabTvChannels);
this.DataRoot.AddChannelList(cabRadioChannels);
this.DataRoot.AddChannelList(cabDataChannels);
this.DataRoot.AddChannelList(satTvChannels);
this.DataRoot.AddChannelList(satRadioChannels);
this.DataRoot.AddChannelList(satDataChannels);
foreach (var list in this.DataRoot.ChannelLists)
{
list.VisibleColumnFieldNames.Remove(nameof(ChannelInfo.ChannelOrTransponder));
list.VisibleColumnFieldNames.Remove(nameof(ChannelInfo.Encrypted));
list.VisibleColumnFieldNames.Add(nameof(ChannelInfo.ServiceType));
}
}
#endregion
#region ReadConfigurationFromIniFile()
private void ReadConfigurationFromIniFile()
{
string iniFile = this.GetType().Assembly.Location.ToLower().Replace(".dll", ".ini");
this.ini = new IniFile(iniFile);
this.headerMapping = new DataMapping(ini.GetSection("HIS_DVB.BIN"));
this.headerRecordSize = headerMapping.Settings.GetInt("HeaderSize");
this.dvbMapping = new DataMapping(ini.GetSection("HIS_DVB.BIN_Record"));
this.antRecordSize = this.dvbMapping.Settings.GetInt("RecordSizeDvbT");
this.cabRecordSize = this.dvbMapping.Settings.GetInt("RecordSizeDvbC");
this.satRecordSize = this.dvbMapping.Settings.GetInt("RecordSizeDvbS");
this.dvbMapping.DefaultEncoding = this.DefaultEncoding;
}
#endregion
#region Load()
public override void Load()
{
this.fileContent = File.ReadAllBytes(this.FileName);
this.headerMapping.SetDataPtr(this.fileContent, 0);
var antChannelCount = this.headerMapping.GetWord("NumChannelsDvbT");
var cabChannelCount = this.headerMapping.GetWord("NumChannelsDvbC");
var satChannelCount = this.headerMapping.GetWord("NumChannelsDvbS");
var expectedSize = headerRecordSize + antChannelCount * antRecordSize + cabChannelCount * cabRecordSize + satChannelCount * satRecordSize;
if (this.fileContent.Length != expectedSize)
throw new FileLoadException(ERR_badFileFormat);
this.dvbStringDecoder = new DvbStringDecoder(this.DefaultEncoding);
var nameOffset = dvbMapping.Settings.GetInt("Name");
var nameLength = dvbMapping.Settings.GetInt("NameLength");
var providerOffset = dvbMapping.Settings.GetInt("Provider");
var providerLength = dvbMapping.Settings.GetInt("ProviderLength");
this.subListInfos = new SubListInfo[]
{
new (antChannelCount, antRecordSize, antTvChannels, antRadioChannels, antDataChannels, false),
new (cabChannelCount, cabRecordSize, cabTvChannels, cabRadioChannels, cabDataChannels, false),
new (satChannelCount, satRecordSize, satTvChannels, satRadioChannels, satDataChannels, true)
};
var off = headerRecordSize;
foreach (var info in this.subListInfos)
{
for (int index = 0; index < info.Count; index++)
{
dvbMapping.SetDataPtr(fileContent, off);
var ci = ReadChannel(index, info.IsSat, nameOffset, nameLength, providerOffset, providerLength);
if (ci != null)
{
var src = ci.SignalSource & SignalSource.MaskTvRadioData;
var channels = src == SignalSource.Tv ? info.TvList : src == SignalSource.Radio ? info.RadioList : info.DataList;
this.DataRoot.AddChannel(channels, ci);
}
off += info.Size;
}
}
}
#endregion
#region ReadChannel()
private ChannelInfo ReadChannel(int index, bool isSat, int nameOffset, int nameLength, int providerOffset, int providerLength)
{
ChannelInfo ci = new ChannelInfo(0, index, 0, "");
ci.RawDataOffset = dvbMapping.BaseOffset;
var type = dvbMapping.GetByte("TvRadioData");
if (type == 1)
ci.SignalSource |= SignalSource.Tv;
else if (type == 2)
ci.SignalSource |= SignalSource.Radio;
else
ci.SignalSource |= SignalSource.Data;
ci.Favorites = dvbMapping.GetByte("Fav") != 0 ? Favorites.A : 0;
ci.Skip = dvbMapping.GetByte("Skip") != 0;
ci.Lock = dvbMapping.GetByte("Lock") != 0;
ci.ServiceType = dvbMapping.GetByte("ServiceType");
ci.PcrPid = dvbMapping.GetWord("PcrPid");
ci.VideoPid = dvbMapping.GetWord("VideoPid");
ci.OldProgramNr = dvbMapping.GetWord("ProgNum");
ci.ServiceId = dvbMapping.GetWord("ServiceId");
ci.AudioPid = dvbMapping.GetWord("AudioPid");
this.dvbStringDecoder.GetChannelNames(fileContent, ci.RawDataOffset + nameOffset, nameLength, out var longName, out var shortName);
ci.Name = longName;
ci.ShortName = shortName;
this.dvbStringDecoder.GetChannelNames(fileContent, ci.RawDataOffset + providerOffset, providerLength, out var provider, out _);
ci.Provider = provider;
ci.TransportStreamId = dvbMapping.GetWord("Tsid");
ci.OriginalNetworkId = dvbMapping.GetWord("Onid");
ci.FreqInMhz = dvbMapping.GetDword("Frequency");
if (ci.FreqInMhz > 20000) // DVB-C/T has value in kHZ, DVB-S in MHz
ci.FreqInMhz /= 1000;
ci.SymbolRate = dvbMapping.GetWord("SymbolRate");
if (isSat)
ci.Satellite = dvbMapping.GetString("SatName", dvbMapping.Settings.GetInt("SatNameLength"));
return ci;
}
#endregion
// Saving ====================================
#region Save()
public override void Save()
{
using var mem = new MemoryStream(this.fileContent.Length);
using var writer = new BinaryWriter(mem);
writer.Write(this.fileContent, 0, this.headerRecordSize);
foreach (var info in this.subListInfos)
{
int newIndex = 0;
foreach (var list in new[] { info.TvList, info.RadioList, info.DataList })
{
var order = list.Channels.OrderBy(c => c, new DelegateComparer<ChannelInfo>(OrderChannelsComparer)).ToList();
foreach (var channel in order)
{
if (channel.IsDeleted)
continue;
// copy original data
var offset = writer.BaseStream.Position;
writer.Write(this.fileContent, channel.RawDataOffset, info.Size);
writer.Flush();
// prepare to overwrite with some new values
dvbMapping.SetDataPtr(mem.GetBuffer(), (int)offset);
dvbMapping.SetWord("ProgNum", channel.NewProgramNr);
dvbMapping.SetByte("Skip", channel.Skip ? 1 : 0);
dvbMapping.SetByte("Lock", channel.Lock ? 1 : 0);
dvbMapping.SetByte("Fav", channel.Favorites != 0 ? 1 : 0);
channel.RecordIndex = newIndex++;
channel.RawDataOffset = (int)offset;
}
// update number of channels in header
headerMapping.SetDataPtr(mem.GetBuffer(), 0);
headerMapping.SetDword("NumSatChannels", newIndex);
}
}
// write to file
this.fileContent = new byte[mem.Length];
Tools.MemCopy(mem.GetBuffer(), 0, this.fileContent, 0, (int)mem.Length);
File.WriteAllBytes(this.FileName, this.fileContent);
}
#endregion
#region OrderChannelsComparer()
private int OrderChannelsComparer(ChannelInfo a, ChannelInfo b)
{
// deleted channels to the end
if (a.NewProgramNr < 0)
return b.NewProgramNr == 0 ? a.RecordIndex.CompareTo(b.RecordIndex) : +1;
if (b.NewProgramNr < 0)
return -1;
return a.NewProgramNr.CompareTo(b.NewProgramNr);
}
#endregion
// Infrastructure ============================
#region DefaultEncoding
public override Encoding DefaultEncoding
{
get => base.DefaultEncoding;
set
{
if (value == this.DefaultEncoding)
return;
base.DefaultEncoding = value;
this.dvbMapping.DefaultEncoding = value;
if (this.dvbStringDecoder != null)
{
this.dvbStringDecoder.DefaultEncoding = value;
this.ReparseNames();
}
}
}
#endregion
#region ReparseNames()
private void ReparseNames()
{
var nameOffset = dvbMapping.Settings.GetInt("Name");
var nameLength = dvbMapping.Settings.GetInt("NameLength");
var providerOffset = dvbMapping.Settings.GetInt("Provider");
var providerLength = dvbMapping.Settings.GetInt("ProviderLength");
foreach (var list in this.DataRoot.ChannelLists)
{
if (list.IsMixedSourceFavoritesList)
continue;
foreach (var chan in list.Channels)
{
dvbMapping.BaseOffset = chan.RawDataOffset;
this.dvbStringDecoder.GetChannelNames(this.fileContent, chan.RawDataOffset + nameOffset, nameLength, out var longName, out var shortName);
chan.Name = longName;
chan.ShortName = shortName;
this.dvbStringDecoder.GetChannelNames(this.fileContent, chan.RawDataOffset + providerOffset, providerLength, out var provider, out _);
chan.Provider = provider;
}
}
}
#endregion
}

View File

@@ -22,7 +22,7 @@ namespace ChanSort.Loader.Hisense.HisBin;
* - favorite lists allow mixing channels from different inputs and also radio and TV
* - character encoding is implicit and can be UTF8 or latin-1
*/
public class HisBinSerializer : SerializerBase
public class HisSvlBinSerializer : SerializerBase
{
private readonly ChannelList dvbtChannels = new (SignalSource.DvbT | SignalSource.Tv | SignalSource.Radio, "DVB-T");
private readonly ChannelList dvbcChannels = new (SignalSource.DvbC | SignalSource.Tv | SignalSource.Radio, "DVB-C");
@@ -45,7 +45,7 @@ public class HisBinSerializer : SerializerBase
private readonly Dictionary<int, Transponder> transponder = new ();
#region ctor()
public HisBinSerializer(string inputFile) : base(inputFile)
public HisSvlBinSerializer(string inputFile) : base(inputFile)
{
this.Features.ChannelNameEdit = ChannelNameEditMode.All;
this.Features.CanSkipChannels = true;

View File

@@ -19,8 +19,11 @@ namespace ChanSort.Loader.Hisense
if (name.Contains("servicelist")) // models 2017 and later
return new ServicelistDb.ServicelistDbSerializer(inputFile);
if (name.StartsWith("his_") && name.EndsWith(".bin"))
return new HisBin.HisBinSerializer(inputFile);
if (name.StartsWith("his_dvb") && name.EndsWith(".bin")) // HIS_DVB.BIN
return new HisBin.HisDvbBinSerializer(inputFile);
if (name.StartsWith("his_") && name.EndsWith(".bin")) // HIS_SVL.BIN, HIS_TSL.BIN, HIS_FAV.BIN
return new HisBin.HisSvlBinSerializer(inputFile);
return null;
}
}

View File

@@ -115,6 +115,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "HDD Hex Edit Neo", "HDD Hex
Information\FileStructures_for_HHD_Hex_Editor_Neo\dtv_cmdb_1-bin.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\dtv_cmdb_1-bin.h
Information\FileStructures_for_HHD_Hex_Editor_Neo\dtv_cmdb_2-bin.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\dtv_cmdb_2-bin.h
Information\FileStructures_for_HHD_Hex_Editor_Neo\get_doc_size.js = Information\FileStructures_for_HHD_Hex_Editor_Neo\get_doc_size.js
Information\FileStructures_for_HHD_Hex_Editor_Neo\his-dvb.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\his-dvb.h
Information\FileStructures_for_HHD_Hex_Editor_Neo\his-svl.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\his-svl.h
Information\FileStructures_for_HHD_Hex_Editor_Neo\LaSat_lst.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\LaSat_lst.h
Information\FileStructures_for_HHD_Hex_Editor_Neo\panasonic_idtvChannelBin.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\panasonic_idtvChannelBin.h

View File

@@ -0,0 +1,75 @@
#include "chansort.h"
[display(format("{0}", trim(lang)))]
struct LanguageInfo
{
byte lang[4];
byte u2[2];
word audioPid;
byte u2[6];
};
enum SubList : byte
{
TV=1, Radio=2, Data=3
};
[display(format("{0} - {1}", progNr, trim(name)))]
struct DvbChannel
{
byte u1[21];
byte skip;
byte lock;
byte u2[6];
SubList list;
byte isFav;
byte u3[4];
ServiceType serviceType;
word pcrPid;
word videoPid;
word progNr;
byte u4[4];
word pmtPid;
word serviceId;
byte u5[12];
LanguageInfo languages[3];
byte u6[182];
char name[50];
char provider[50];
byte u7[10];
word u8;
word tsid;
word onid1;
word onid2;
byte u9[4];
word freq;
byte u10[10];
dword symbolRate;
byte u11[74];
};
[display(format("{0}.{1} - {2}", dvb.list, dvb.progNr, trim(dvb.name)))]
struct SatChannel
{
DvbChannel dvb;
word u1;
char satName[32];
byte u11a[2];
word lowFreq;
word highFreq;
byte u11b[10];
byte orbitalPos;
byte u12[13];
};
public struct HIS_DVB_BIN
{
dword versionMaybe;
dword numAntennaChannels;
dword numCableChannels;
dword numSatChannels;
DvbChannel antennaChannels[numAntennaChannels];
DvbChannel cableChannels[numCableChannels];
SatChannel satChannels[numSatChannels];
};

View File

@@ -1,6 +1,12 @@
ChanSort Change Log
===================
2023-01-23
- added support for Hisense HIS_DVB.BIN channel lists
2023-01-18
- added support for Hisense HIS_SVL.BIN / HIS_TSL.BIN / HIS_FAV.BIN channel lists
2023-01-15
- added support for Vision EDGE 4K set-top-box (DVB-S only)
- TCL: separate lists for DVB-C/T/S, each starting at 1