Welcome to Doom9's Forum, THE in-place to be for everyone interested in DVD conversion.

Before you start posting please read the forum rules. By posting to this forum you agree to abide by the rules.

 

Go Back   Doom9's Forum > Programming and Hacking > Development

Reply
 
Thread Tools Search this Thread Display Modes
Old 3rd November 2020, 13:05   #1  |  Link
FranceBB
Broadcast Encoder
 
FranceBB's Avatar
 
Join Date: Nov 2013
Location: Royal Borough of Kensington & Chelsea, UK
Posts: 2,904
Superimposing a process view (ffplay) to my program view C#

Hi there,
since the need of an open source and free to use Waveform Monitor was growing among my colleagues, I gave them my VideoTek which is great.
Too bad, none of them knows how to code in Avisynth 'cause they're QC-guys, it's not their job to encode.
So I was like: "fine, I can automatize it and put it in a graphical user interface", but it's turning out to be more complicated than I thought.

With this code:

Code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Threading;

namespace VideoTek
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        //Getting installation directory to load .DLLs
        string my_program_directory = System.IO.Directory.GetCurrentDirectory();

        // "Open File" Button
        private void button1_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog1 = new OpenFileDialog();
            openFileDialog1.InitialDirectory = "c:\\";
            openFileDialog1.RestoreDirectory = true;

            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                string selectedFileName = openFileDialog1.FileName;

                //Save the path, name + extension of the selected file
                System.IO.File.WriteAllText(my_program_directory + @"\MyFile.ini", selectedFileName);

                //Creating .avs Script
                string escape = "\"";
                string myplugin1 = @"LoadPlugin(" + escape + my_program_directory + @"\LSMASHSource.dll" + escape + ")";
                string myplugin2 = @"Import(" + escape + my_program_directory + @"\Videotek.avs" + escape + ")";
                string my_AVS_Script = myplugin1 + System.Environment.NewLine + myplugin2 + System.Environment.NewLine + @"LWLibavVideoSource(" + escape + selectedFileName + escape + @")" + System.Environment.NewLine + @"VideoTek()";
                System.IO.File.WriteAllText(my_program_directory + @"\AVS_Script.avs", my_AVS_Script);

            }
        }

        // "Play" Button
        private void button2_Click(object sender, EventArgs e)
        {
            //Importing dependencies
            [DllImport("user32.dll", SetLastError = true)]
            static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);

            [DllImport("user32.dll")]
            static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);


            // start ffplay 
            var ffplay = new Process
            {
                StartInfo =
            {
                FileName = "ffplay",
                //open the AVS Script
                Arguments = my_program_directory + @"\AVS_Script.avs",
                // hides the command window
                CreateNoWindow = true, 
                // redirect input, output, and error streams..
                RedirectStandardError = true,
                RedirectStandardOutput = true,
                UseShellExecute = false
            }
            };

            ffplay.EnableRaisingEvents = true;
            ffplay.OutputDataReceived += (o, e) => Debug.WriteLine(e.Data ?? "NULL", "ffplay");
            ffplay.ErrorDataReceived += (o, e) => Debug.WriteLine(e.Data ?? "NULL", "ffplay");
            ffplay.Exited += (o, e) => Debug.WriteLine("Exited", "ffplay");
            ffplay.Start();

            Thread.Sleep(200); // you need to wait/check the process started, then...

            // child, new parent
            // make 'this' the parent of ffmpeg (presuming you are in scope of a Form or Control)
            SetParent(ffplay.MainWindowHandle, this.Handle);

            // window, x, y, width, height, repaint
            // move the ffplayer window to the top-left corner and set the size to 1280x720
            MoveWindow(ffplay.MainWindowHandle, 0, 0, 1280, 720, true);

            var mymonitor = ffplay.MainWindowHandle;

            //groupBox1.Controls.Add();

        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }

        private void groupBox1_Enter(object sender, EventArgs e)
        {
            

        }
    }
}
I'm using the button1_Click action to basically prompt the user to pick-up a video. After that, I store the path of wherever the program has been installed and I save the whole name in an .ini file. After that, it's just a matter of creating an Avisynth Script with an Indexer (LWLibav) and VideoTek().
After that, FFPlay is called and compiles the Avisynth Script in real time, thus showing the result to the user.
So far so good, but there's a problem.
FFPlay generates a different, separate process and as such, it generates a different window which I'm desperately trying to "overlay/redraw" inside my program, in particular inside groupBox1. The problem is that I don't know how to do that.
I thought that this was going to do it:

Code:
            // child, new parent
            // make 'this' the parent of ffmpeg (presuming you are in scope of a Form or Control)
            SetParent(ffplay.MainWindowHandle, this.Handle);

            // window, x, y, width, height, repaint
            // move the ffplayer window to the top-left corner and set the size to 1280x720
            MoveWindow(ffplay.MainWindowHandle, 0, 0, 1280, 720, true);
by setting the ffplay.MainWindowHandle to this.Handle, however it really doesn't do what I wanted...

Any suggestion?
FranceBB is offline   Reply With Quote
Old 3rd November 2020, 15:31   #2  |  Link
LoRd_MuldeR
Software Developer
 
LoRd_MuldeR's Avatar
 
Join Date: Jun 2005
Location: Last House on Slunk Street
Posts: 13,248
I'm not sure whether what you are trying to do - embed the contents (client area) of another process window into your own window - can be done without special support from the other process

SetParent() only changes the "parent" window of a popup window. I'm not even sure that works with windows belonging to a "foreign" process. But even if Windows actually does allow that, changing the "parent" window of a popup window is something very different from "absorbing" that windows' content; it certainly does not "magically" make the contents of the "child" window appear within your own window. There still would be two separate windows!

I'm not sure about FFplay, but MPlayer does offer a special "slave" mode, in which it will render its video output in the client area of another process' window. That is how MPlayer front-ends, such as MPUI or SMPlayer, work.

The relevant options include:

Quote:
-slave (also see -input)
Switches on slave mode, in which MPlayer works as a backend for other programs. Instead of intercepting keyboard events, MPlayer will read commands separated by a newline (\n) from stdin.
NOTE: See -input cmdlist for a list of slave commands and DOCS/tech/slave.txt for their description. Also, this is not intended to disable other inputs, e.g. via the video window, use some other method like -input nodefault-bindings:conf=/dev/null for that.
Quote:
-wid (also see -gui-wid) (X11, OpenGL and DirectX only)
This tells MPlayer to attach to an existing window. Useful to embed MPlayer in a browser (e.g. the plugger extension). This option fills the given window completely, thus aspect scaling, panscan, etc are no longer handled by MPlayer but must be managed by the application that created the window.
__________________
Go to https://standforukraine.com/ to find legitimate Ukrainian Charities 🇺🇦✊

Last edited by LoRd_MuldeR; 3rd November 2020 at 15:45.
LoRd_MuldeR is offline   Reply With Quote
Old 9th November 2020, 01:26   #3  |  Link
FranceBB
Broadcast Encoder
 
FranceBB's Avatar
 
Join Date: Nov 2013
Location: Royal Borough of Kensington & Chelsea, UK
Posts: 2,904
Quote:
Originally Posted by LoRd_MuldeR View Post
I'm not sure whether what you are trying to do - embed the contents (client area) of another process window into your own window - can be done without special support from the other process
Yes, that's exactly what I'm trying to do.
Ideally I'd like to have something like this:



in which the left part and the top part are part of the C# program, so the main window, while the one on the right that has the picture, luma, chroma, loudness and Lissajou is the output displayed by FFPlay as it reads the content of Avisynth using my script called VideoTek: https://forum.doom9.org/showthread.php?t=175249

This is to allow people who don't know how to write something silly like:

Code:
LWLibavVideoSource("file.mxf")
VideoTek()
to actually use my plugin.


Quote:
Originally Posted by LoRd_MuldeR View Post
SetParent() only changes the "parent" window of a popup window. I'm not even sure that works with windows belonging to a "foreign" process. But even if Windows actually does allow that, changing the "parent" window of a popup window is something very different from "absorbing" that windows' content; it certainly does not "magically" make the contents of the "child" window appear within your own window. There still would be two separate windows!
I see! That's why I didn't see anything!

Quote:
Originally Posted by LoRd_MuldeR View Post
I'm not sure about FFplay, but MPlayer does offer a special "slave" mode, in which it will render its video output in the client area of another process' window. That is how MPlayer front-ends, such as MPUI or SMPlayer, work.
Ah... I never used MPlayer, though. I should take a look at it, but I thought FFPlay was going to work...
A temporary bad workaround I was thinking about was to use FFMpeg to output a local video stream, like an m3u8 or something like that so that I could use something like:

Code:
webBrowser1.Navigate(new Uri(mystream));
with a string called "mystream" that has the local URL of the stream, however those resulted in an error:

Code:
ffmpeg.exe -i "AVS_Script.avs" -vcodec copy -acodec copy -f mpegts udp://localhost:8080/feed1.ts
as I wasn't able to open localhost:8080/feed1.ts
I mean, it's supposed to be something internal that can be used by other programs internally, right? Why is it giving me an error saying that it can't open the URL? I mean, FFMpeg is indeed outputting something as it doesn't give me any error...
FranceBB is offline   Reply With Quote
Old 9th November 2020, 16:41   #4  |  Link
LoRd_MuldeR
Software Developer
 
LoRd_MuldeR's Avatar
 
Join Date: Jun 2005
Location: Last House on Slunk Street
Posts: 13,248
Quote:
Originally Posted by FranceBB View Post
A temporary bad workaround I was thinking about was to use FFMpeg to output a local video stream, like an m3u8 or something like that so that I could use something like:

Code:
webBrowser1.Navigate(new Uri(mystream));
with a string called "mystream" that has the local URL of the stream, however those resulted in an error:

Code:
ffmpeg.exe -i "AVS_Script.avs" -vcodec copy -acodec copy -f mpegts udp://localhost:8080/feed1.ts
as I wasn't able to open localhost:8080/feed1.ts
I mean, it's supposed to be something internal that can be used by other programs internally, right? Why is it giving me an error saying that it can't open the URL? I mean, FFMpeg is indeed outputting something as it doesn't give me any error...
AFAIK, the "WebBrowser" control in .NET is nothing but a wrapper for an InternetExplorer (Edge?) frame. So, if you open an URL in the "WebBrowser" control, it is pretty much like you open that URL in a normal InternetExplorer window.

Can you open an "udp://..." URL directly in InternetExplorer, or in any other mainstream web-browser? I don't think so.

Note that, even though modern HTML5-based web-browsers do support video streaming without the need for a separate plug-in, you cannot simply open the video stream URL directly from the address bar. Instead, you need at least a minimal "web page" containing some HTML code with a 〈Video〉 tag and the proper parameters. And even then you will be restricted to the streaming protocols and video formats that are supported by the individual web browser...

(most web-browsers probably only support "progressive download" via HTTP, but not "real" streaming via something like RTSP)
__________________
Go to https://standforukraine.com/ to find legitimate Ukrainian Charities 🇺🇦✊

Last edited by LoRd_MuldeR; 9th November 2020 at 16:54.
LoRd_MuldeR is offline   Reply With Quote
Old 9th November 2020, 23:26   #5  |  Link
FranceBB
Broadcast Encoder
 
FranceBB's Avatar
 
Join Date: Nov 2013
Location: Royal Borough of Kensington & Chelsea, UK
Posts: 2,904
Quote:
Originally Posted by LoRd_MuldeR View Post
AFAIK, the "WebBrowser" control in .NET is nothing but a wrapper for an InternetExplorer (Edge?) frame. So, if you open an URL in the "WebBrowser" control, it is pretty much like you open that URL in a normal InternetExplorer window.
Yep, it is.

Quote:
Originally Posted by LoRd_MuldeR View Post
Can you open an "udp://..." URL directly in InternetExplorer, or in any other mainstream web-browser? I don't think so.

Note that, even though modern HTML5-based web-browsers do support video streaming without the need for a separate plug-in, you cannot simply open the video stream URL directly from the address bar. Instead, you need at least a minimal "web page" containing some HTML code with a 〈Video〉 tag and the proper parameters. And even then you will be restricted to the streaming protocols and video formats that are supported by the individual web browser...

(most web-browsers probably only support "progressive download" via HTTP, but not "real" streaming via something like RTSP)
Ah... silly me, I thought I could.
I really gotta check MPlayer and try to use it then...
FranceBB is offline   Reply With Quote
Reply

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +1. The time now is 14:01.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.