using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;
using Jellyfin.Plugin.Enigma2;
using MediaBrowser.Model.Entities;
/// Self-authored DVB bitmap fixtures; no broadcaster samples or receiver connection.
public static class SyntheticBroadcastFixture
{
public static BroadcastTracks Tracks(bool normalize = true) => new(new MediaStream[] {
new BroadcastMediaStream { Type=MediaStreamType.Video,Index=0,TransportId=256,Codec="h264",Width=640,Height=360 },
new BroadcastMediaStream { Type=MediaStreamType.Audio,Index=1,TransportId=257,Codec="aac",Language="pol",Title="Polski",Channels=2,SampleRate=48000,IsDefault=true },
new BroadcastMediaStream { Type=MediaStreamType.Audio,Index=2,TransportId=258,Codec="aac",Language="eng",Title="English",Channels=2,SampleRate=48000 },
new BroadcastMediaStream { Type=MediaStreamType.Subtitle,Index=3,TransportId=259,Codec="DVBSUB",Language="pol",SubtitleExtraData=new byte[]{0,1,0,1},IsHearingImpaired=true },
new BroadcastMediaStream { Type=MediaStreamType.Subtitle,Index=4,TransportId=260,Codec="DVBSUB",Language="eng",SubtitleExtraData=new byte[]{0,1,0,1},IsForced=true },
new BroadcastMediaStream { Type=MediaStreamType.Subtitle,Index=5,TransportId=261,Codec="DVBTXT",Language="pol",SubtitleExtraData=new byte[]{16,136} }
},normalize);
private static long Pts(byte[] b,int p) => ((long)(b[p]&14)<<29)|((long)b[p+1]<<22)|((long)(b[p+2]&254)<<14)|((long)b[p+3]<<7)|((long)b[p+4]>>1);
private static byte[] Stamp(long t) => new[]{(byte)(33L|((t>>29)&14)),(byte)(t>>22),(byte)(1L|((t>>14)&254)),(byte)(t>>7),(byte)(1L|(t<<1))};
public static byte[] AddSubtitles(byte[] input)
{
input=BroadcastSlateProgram.Apply(input,Tracks(),false);
using var output=new MemoryStream();long next=0;var counters=new int[3];
for(var pos=0;pospos+188||input[p]!=0||input[p+1]!=0||input[p+2]!=1||(input[p+7]&128)==0)continue;
var pts=Pts(input,p+9);if(pts{0,0,1,189};var length=bitmap.Length+8;
pes.Add((byte)(length>>8));pes.Add((byte)length);pes.AddRange(new byte[]{128,128,5});pes.AddRange(Stamp(pts));pes.AddRange(bitmap);
var result=new List();
for(var i=0;i>8)|(i==0?64:0));packet[2]=(byte)pid;
var count=Math.Min(184,pes.Count-i);var p=4;
if(count<184){packet[3]=(byte)(48|(counter++&15));packet[4]=(byte)(183-count);if(packet[4]>0)packet[5]=0;p+=184-count;}
else packet[3]=(byte)(16|(counter++&15));
pes.CopyTo(i,packet,p,count);i+=count;result.Add(packet);
}
return result.ToArray();
}
private static byte[] Teletext()
{
// A self-authored page 888, using standard Hamming-address and odd-parity text bytes.
byte Reverse(byte value) { byte result=0;for(var bit=0;bit<8;bit++)result=(byte)((result<<1)|((value>>bit)&1));return result; }
var hamming=new byte[]{21,2,73,94,100,115,56,47,208,199,140,155,161,182,253,234};
byte Character(char c) { var value=(byte)(c&127);if(System.Numerics.BitOperations.PopCount((uint)value)%2==0)value|=128;return Reverse(value); }
var result=new List{16};
void Row(int row,byte[] text){result.AddRange(new byte[]{3,44,199,228,Reverse(hamming[(row&1)<<3]),Reverse(hamming[row>>1])});result.AddRange(text);}
var header=new List();foreach(var n in new[]{8,8,0,8,0,8,0,0})header.Add(Reverse(hamming[n]));header.AddRange(Enumerable.Repeat(Character(' '),32));Row(0,header.ToArray());
Row(1,"SYNTHETIC TELETEXT SUBTITLE".PadRight(40).Select(Character).ToArray());return result.ToArray();
}
public static byte[] Bitmap(int variant)
{
var result=new List{32,0};
void Segment(byte type,byte[] data){result.AddRange(new byte[]{15,type,0,1,(byte)(data.Length>>8),(byte)data.Length});result.AddRange(data);}
Segment(20,new byte[]{0,2,127,1,103}); // display 640 x 360
Segment(16,new byte[]{2,11,0,255,0,64,1,44});
Segment(17,new byte[]{0,7,0,96,0,32,39,0,0,3,0,0,0,0,240,0});
var field=new List();
for(var y=0;y<16;y++)
{
field.Add(16);
for(var x=0;x<24;x++)field.Add((byte)((x/4+y/4+variant)%2==0?85:170));
field.Add(0);field.Add(240);
}
var data=new List{0,0,0,(byte)(field.Count>>8),(byte)field.Count,(byte)(field.Count>>8),(byte)field.Count};
data.AddRange(field);data.AddRange(field);Segment(19,data.ToArray());Segment(128,Array.Empty());result.Add(255);
return result.ToArray();
}
}