using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Skybound.Gecko;
using System.IO;
using System.Threading;
namespace DirectShowLib.Sample
{
public partial class FirefoxOverlay : Form
{
//bekommt Zugriff auf das panel1 von mainform
//wird über Konstruktor übergeben
Panel dvbPanel;
//neutral grau für FarbKeying in Hex und RGB
public static string keyColorHex = "eeeeee";
public static Color keyColorRGB = System.Drawing.Color.FromArgb(238, 238, 238);
bool dvbPanelisMaximize = false;
//enthält Informationen über das video/broadcast <object>
DvbVideoInformation information = new DvbVideoInformation();
//variable, welche den eigenen Thread stoppt
bool doCloseUpdateThread = false;
public FirefoxOverlay(Panel dvbPanel)
{
InitializeComponent();
this.dvbPanel = dvbPanel;
//Entfernt Scrollbalken. Html größe nun von Form größe abhängig, kein overflow mehr
geckoWebBrowser1.MinimumSize = new Size(1280, 720);
}
public void showWindow()
{
geckoWebBrowser1.Show();
this.BringToFront();
}
/// <summary>
/// Fügt dem HTML immer einen neutralgrauen Background ein. Unwahrscheinliche Farbe die auftritt
/// Zum background keyen erforderlich!
/// </summary>
delegate void delSetBackground();
public void setBackground()
{
//geckoWebBrowser1.Navigate("javascript:void(document.bgColor='#"+keyColorHex+"');");
GeckoElementCollection objectCollection = geckoWebBrowser1.Document.GetElementsByTagName("body");
if (objectCollection[0] != null)
objectCollection[0].SetAttribute("style", "background-color:#" + keyColorHex + ";");
}
/// <summary>
/// Funktion sucht im HTML Quelltext nach <object type="video/broadcast">
/// und übergibt dessen Informationen wie z.B Position,Größe und existenz.
/// delegate damit es vom Thread aufrufbar ist
/// </summary>
delegate void delegateSearch();
public void searchVideoBroadcastObject()
{
//Default wert setzen
information.exist(false);
//sucht alle <object> tags ab und fügt sie zu einer liste hinzu
GeckoElementCollection objectCollection = geckoWebBrowser1.Document.GetElementsByTagName("object");
for (int i = 0; i < objectCollection.Count; i++)
{
//durchgrast die liste nach type=video/broadcast
if (objectCollection[i].GetAttribute("type") == "video/broadcast")
{
//MessageBox.Show("dvb video vorhanden");
information.exist(true);
//unsicherer Code - attribut könnte nicht vorhanden sein -->Absturz
//information.setScaleX(Convert.ToInt16(objectCollection[i].GetAttribute("width")));
//information.setScaleY(Convert.ToInt16(objectCollection[i].GetAttribute("height")));
information.setIDName(objectCollection[i].GetAttribute("id"));
//findet absolute Position des Videocontainers
//indem er sich bis zum body element hochhangelt
//und von jedem übergeordneten element top und left aufaddiert
int xParameter = 0;
int yParameter = 0;
GeckoElement node = objectCollection[i];
while (node.TagName != "BODY")
{
//MessageBox.Show(node.TagName);
xParameter += node.OffsetLeft;
yParameter += node.OffsetTop;
node = node.Parent; //ebene höher gehen
}
//im Folgenden wird zusätzlich das Style Attribut (Css)analysiert nach seinen Werten
// wie left;top;height;width:
String styleString = Convert.ToString(objectCollection[i].GetAttribute("style"));
int cssX = getVideoLoc(styleString, 0);
int cssY = getVideoLoc(styleString, 1);
int cssWidth = getVideoLoc(styleString, 2);
int cssHeight = getVideoLoc(styleString, 3);
//Setzt immer Größe anhand der CSS formatierung
information.setScaleX(cssWidth);
information.setScaleY(cssHeight);
//setzt vorläufig die Position anhand der HTML verschachtelung
information.setPositionX(xParameter);
information.setPositionY(yParameter);
//wenn breite 1280,dann ist video fullscreen und top+left=0
if (cssWidth == 1280)
{
information.setPositionX(0);
information.setPositionY(0);
}
//Der Fall wenn ein kleines Video vorhanden ist
else
{
//wenn Html Verschachtelung beide 0 ergibt, dann verwende CSS,
//auch wenn es dennoch 0 sein kann
if (xParameter == 0 && yParameter == 0)
{
information.setPositionX(cssX);
information.setPositionY(cssY);
}
}
}
}
}
/// <summary>
/// Bettet den DVB Stream in das HTML ein. Eine "Durchscheinmaske" (panel1) wird erstellt,
/// welche die position und scaling des <objects..> hat. der firefox hat an der stelle
/// der Maske einen "blue-screen" bereich, mit welchem man auf die mainform drauf schauen kann
/// das video liegt im hintergrund und wurde auch repositioniert und rescaled.
/// </summary>
delegate void delegateEmbedDVB();
public void embedDVBinHTML()
{
if (information.exist() == true)
{
dvbPanel.Dock = System.Windows.Forms.DockStyle.None;
dvbPanel.Location = new Point(information.getPositionX(), information.getPositionY());
dvbPanel.Size = new Size(information.getScaleX(), information.getScaleY());
//Console.WriteLine(Convert.ToString("vorif :"+information.getScaleX()));
if (information.getScaleX() == 1280 && information.getScaleY() == 720)
{
//jetzt soll dvb Film Fullscreen sein und die schnittebene panel wird nicht mehr gebraucht
panel1.Size = new Size(0, 0);
panel1.Location = new Point(0, 0);
dvbPanelisMaximize = true;
//Dock.Fill entspricht maximaler größe bzw Ursprungszustand
if (!dvbPanelisMaximize) dvbPanel.Dock = System.Windows.Forms.DockStyle.Fill;
//Console.WriteLine(Convert.ToString(information.getScaleX()));
}
else
{
//dvb video wird nun an die richtige kleinere stelle gesetzt
panel1.Location = new Point(information.getPositionX() - 1, information.getPositionY() - 1);
panel1.Size = new Size(information.getScaleX(), information.getScaleY());
dvbPanelisMaximize = false;
}
panel1.Refresh();
}
else
{
dvbPanel.Dock = System.Windows.Forms.DockStyle.Fill;
panel1.Size = new Size(0, 0);
panel1.Location = new Point(0, 0);
}
}
public void navigate(String url)
{
geckoWebBrowser1.Navigate(url);
}
/// <summary>
/// Überwacht video-broadcast-object. Läuft nur als Thread
/// </summary>
public void updateInformation()
{
// Um als eigenständiger Thread dennoch auf die Methoden der eigenen Klasse
//zugreifen zu können, müssen die Funktionen als delegate aufgerufen werden
delegateSearch delegateSearch = new delegateSearch(this.searchVideoBroadcastObject);
delegateEmbedDVB delEmbedDVB = new delegateEmbedDVB(this.embedDVBinHTML);
delSetBackground delSetBackground = new delSetBackground(this.setBackground);
while (doCloseUpdateThread == false)
{
this.Invoke(delegateSearch);
this.Invoke(delEmbedDVB);
this.Invoke(delSetBackground);
Thread.Sleep(500); //0,5 sec warten
}
}
/// <summary>
/// Setzt cancel Variable um object ÜberwachungsThread bei ProgrammEnde zu stoppen
/// </summary>
public void cancelThread()
{
doCloseUpdateThread = true;
}
/// <summary>
/// Feuert einen Event in den Firefox
/// Event vom DSMCC Decoder
///
/// Originaler JS Code : -->
/// var ev = document.createEvent("StreamEvent");
/// ev.initStreamEvent("StreamEvent", true, false, "name", "data", "text");
/// video.dispatchEvent(ev);
/// </summary>
public delegate void delegateFireEvent(String name, String data, String text);
public void fireEvent(String name, String data, String text)
{
searchVideoBroadcastObject();
//wenn es ein objekt gibt ,dann erlaube event fire
if (information.exist() == true)
{
//Sämtliche Codes werden in den Firefox "injected" über die URL Eingabe (navigate).
//erzeugt ein neues Event vom Typ StreamEvent
geckoWebBrowser1.Navigate("javascript:var ev = document.createEvent(\"StreamEvent\")");
//holt sich das video objekt mit Hilfe der id vom <object> tag
geckoWebBrowser1.Navigate("javascript:var video = document.getElementById(\"" + information.getIDName() + "\");");
//hängt den validen addeventListener an, addstreameventlistener wird nicht verwendet, aber umgemapped
geckoWebBrowser1.Navigate("javascript:void(video.addEventListener(\"StreamEvent\"," + searchStreamEventListener() + ",true));");
//Initialisiert das StreamEvent und füllt es mit den 3 wichtigen Strings
geckoWebBrowser1.Navigate("javascript:void(ev.initStreamEvent(\"StreamEvent\", true, false, \"" + name + "\", \"" + data + "\", \"" + text + "\"));");
//feuert das Event in die Javascript Umgebung des Firefox
geckoWebBrowser1.Navigate("javascript:void(video.dispatchEvent(ev));");
}
}
/// <summary>
/// Durchsucht kompletten HTML Code nach dem dritten Argument des addstreameventlisteners
/// </summary>
public String searchStreamEventListener()
{
string path = geckoWebBrowser1.Url.ToString().Substring(8);
string s = ReadFile(path);
string funcname = "";
GeckoElementCollection objectCollection = geckoWebBrowser1.Document.GetElementsByTagName("script");
string[] pathsub = new string[objectCollection.Count];
for (int i = 0; i < objectCollection.Count; i++)
{
if (objectCollection[i].GetAttribute("type") == "text/javascript")
{
pathsub[i] = objectCollection[i].GetAttribute("src");
//MessageBox.Show(pathsub[i]);
}
}
if (s.Contains(".addStreamEventListener"))
{
funcname = getFuncName(s);
}
else
{
for (int i = 0; i < objectCollection.Count; i++)
{
path = path.Substring(0, path.LastIndexOf("/") + 1);
s = ReadFile(path + pathsub[i]);
if (s.Contains(".addStreamEventListener"))
{
funcname = getFuncName(s);
}
}
}
// Console.WriteLine(getFuncName(ReadFile(path + pathsub[1]))); //<-- test für eigenes file
//MessageBox.Show("dritter Parameter: " + funcname);
return funcname;
}
/// <summary>
/// Ließt Datei in einen langen String ein
/// </summary>
public string ReadFile(String sFilename)
{
string sContent = "";
if (File.Exists(sFilename))
{
StreamReader myFile = new StreamReader(sFilename, System.Text.Encoding.Default);
sContent = myFile.ReadToEnd();
myFile.Close();
}
return sContent;
}
/// <summary>
/// Parst aus einem String das dritte Argument der methode addstreameventlistener heraus
/// </summary>
public string getFuncName(String filecontent)
{
int posstart = filecontent.IndexOf(".addStreamEventListener");
int posend = filecontent.IndexOf(")", posstart);
string subit = filecontent.Substring(posstart, (posend - posstart));
string funcname = subit.Substring(subit.LastIndexOf(",") + 1);
return funcname;
}
public int getVideoLoc(String videostring, int art)
{
int[] videoinfo = { 0, 1, 2, 3 };
string[] videostringArr;
//initialisieren
for (int i = 0; i < 3; i++) videoinfo[i] = 0;
videostringArr = videostring.Split(';');
for (int i = 0; i < videostringArr.Length; i++)
{
if (videostringArr[i].Contains(" left:"))
{
videoinfo[0] = Convert.ToInt16(videostringArr[i].TrimStart('l', 'e', 'f', 't', ':', ' ').TrimEnd('p', 'x'));
}
if (videostringArr[i].Contains(" top:"))
{
videoinfo[1] = Convert.ToInt16(videostringArr[i].TrimStart('t', 'o', 'p', ':', ' ').TrimEnd('p', 'x'));
}
if (videostringArr[i].Contains(" width:"))
{
videoinfo[2] = Convert.ToInt16(videostringArr[i].TrimStart('w', 'i', 'd', 't', 'h', ':', ' ').TrimEnd('p', 'x'));
}
if (videostringArr[i].Contains(" height:"))
{
videoinfo[3] = Convert.ToInt16(videostringArr[i].TrimStart('h', 'e', 'i', 'g', 'h', 't', ':', ' ').TrimEnd('p', 'x'));
}
}
Console.Write(videoinfo[0]);
Console.Write(videoinfo[1]);
Console.Write(videoinfo[2]);
Console.Write(videoinfo[3]);
return videoinfo[art];
}
}
}
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Windows.Forms;
namespace DirectShowLib.Sample
{
class DsmccListener
{
//braucht instanz vom firefox_overlay um fireEvent methode zu rufen
FirefoxOverlay f_overlay = null;
//Instanz zum delegate, welcher auf fireEvent methode verweist
FirefoxOverlay.delegateFireEvent del_f_overlay = null;
Thread newThread;
//Thread Stop variable
bool stop = false;
public DsmccListener(FirefoxOverlay.delegateFireEvent instance, FirefoxOverlay instance2)
{
del_f_overlay = instance;
f_overlay = instance2;
newThread = new Thread(new ThreadStart(this.waitForEvent));
newThread.Start();
}
public void waitForEvent()
{
DSMCC_Decoder.StreamEvent e = new DSMCC_Decoder.StreamEvent();
DSMCC_Decoder.StreamEventListener.register(ref e);
while (stop == false)
{
//warte auf Eintreffen eines StreamEvents
e.isTriggered.WaitOne();
//führe fireEvent(...,..,..) als delegate aus
f_overlay.Invoke(del_f_overlay, new object[3] { e.Name, e.Data, e.Text });
e.isTriggered.Reset();
}
}
//Beim Schließen des ganzen Programmes
public void cancelThread()
{
stop = true;
newThread.Abort();
}
}
}