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(); } }