Embed an application inside a Qt Window [SOLVED]



  • Currently trying to figure out how I would embed Mplayer into Qt on windows(so I can use it's rtsp functionality in my program).

    However after trawling the net there is very little documentation on it and so far I haven't found an example of how to do this. Supposedly it has something to do with "QWindow::fromWinId" and " QWidget::createWindowContainer" however as I have no example code to work from I'm struggling to even get my head round what I actually have to do.

    If anyone has any example links or advice for me on how to implement this I would be eternally grateful (to give you an idea tried breaking down smplayer but it's so large for me to get my head around the problem). If there is a better way to implement this functionality aswell please let me know.


  • Moderators


  • Moderators

    Hi,

    I was just investigating this myself recently. I found a number of issues with embedding external windows on Windows, however.

    You can find short example code and a description of issues at https://bugreports.qt-project.org/browse/QTBUG-40320 (in the code, ignore the calls to QObject::connect())



  • Currently this is my implementation but it doesn't work correctly cause I am unsure if my order is correct/parenting etc. What is does is show the video but it's not embedded into the the main widget. To be honest now at this point I'm completely lost. All I what to do is embed the video inside a Qt application, if anyone has any ideas where i'm going wrong that would be great.

    @#include "widget.h"
    #include "ui_widget.h"

    Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
    {
    ui->setupUi(this);
    QString program;
    program = "E:\Downloads\mplayer\mplayer.exe";

    QStringList arguments;
    arguments << "E:\\Downloads\\BigBuckBunny_320x180.mp4";
    WId winid = this->winId();
    QWindow *container = QWindow::fromWinId(winid);
    QWidget *program_start  = createWindowContainer(container);
    QPushButton *button = new QPushButton("&Download", this);
    //QWidget *container = new QWidget(parent);
    //QProcess *myProcess = new QProcess(parent);
    QVBoxLayout *layout = new QVBoxLayout;
    QProcess *myProcess = new QProcess(parent);
    myProcess->start(program, arguments);
    
    layout->addWidget(program_start);
    layout->addWidget(button);
    setLayout(layout);
    
    myProcess->waitForFinished();
    

    }

    Widget::~Widget()
    {
    delete ui;
    }

    @

    But thanks for the help so far every bit helps.


  • Moderators

    [quote]
    @
    WId winid = this->winId();
    QWindow *container = QWindow::fromWinId(winid);
    QWidget *program_start = createWindowContainer(container);
    @
    [/quote]You embedded your Widget object.

    You need to get the WId (HWND) of your MPlayer window after you launch the process.



  • Ok well only way I have found, that i could set or get the mplayer HWND, is via setting it's parameters ("-wid 1234"). Which should set the ID for the process.

    However there must be a way to get the ID via winID or am I looking in the wrong direction. I expected that I had the container in the wrong place in the code however haven't been able to get it to work yet.

    This is the line, that is my main problem, can't see which object should be used.
    @WId winid = this->winId();@

    Tried doing what you said but know that I am still lost with winID (HWND).
    @ QString program;
    program = "E:\Downloads\mplayer\mplayer.exe";

    QStringList arguments;
    arguments << "-wid" << QString::number((int)winId()) << "E:\\Downloads\\BigBuckBunny_320x180.mp4";
    
    QVBoxLayout *layout = new QVBoxLayout;
    
    QPushButton *button = new QPushButton("Test2");
    QPushButton *button2 = new QPushButton("Test");
    
    
    QProcess *m_process = new QProcess(this);
    
    m_process->setProgram(program);
    m_process->setArguments(arguments);
    
    m_process->start();
    
    WId winid = winId();
    QWindow *container = QWindow::fromWinId(winid);
    QWidget *program_start  = createWindowContainer(container);@

  • Moderators

    Every window has its own HWND. When you create a new widget and show it, your OS will give it a HWND. When you launch MPlayer, your OS will give it a different HWND.

    (Note: HWND is specific to the Windows OS. Linux and Mac OS X use other types of ID)

    [quote]This is the line, that is my main problem, can’t see which object should be used.
    @WId winid = this->winId();@
    [/quote]The object you want does not exist. Qt cannot find the HWND of a non-Qt window.

    You need to use native OS functions to find the HWND of the external MPlayer window. Something like FindWindow(): http://msdn.microsoft.com/en-us/library/windows/desktop/ms633499(v=vs.85).aspx Also scroll down to the comments of that page -- other uses have posted alternative ways to find HWND.

    See the link in my first post for an example.



  • Well think I am now getting the correct ID (using find window). However code builds but just plays the video outside of the window. I must be getting very close however as not getting the same functional errors (no windows are crashing etc).

    @ WId id = (WId)FindWindow(NULL, L"Mplayer");
    //if (!id)
    // return -1;

    QString program;
    program = "C:\\Users\\Downloads\\MPlayer\\mplayer.exe";
    
    QStringList arguments;
    arguments << "-vo directx:noaccel" << "-wid " << QString::number((int)winId()) << "C:\\Users\\Downloads\\big_buck_bunny_480p_surround-fix.avi";
    
    QProcess *m_process = new QProcess(this);
    m_process->setProgram(program);
    m_process->setArguments(arguments);
    
    m_process->start();
    
    QWindow *container = QWindow::fromWinId(id);
    QWidget *program_start  = QWidget::createWindowContainer(container);
    
    QMessageBox test;
    test.setText(QString::number(id));
    test.exec&#40;&#41;;
    
    setCentralWidget(program_start&#41;;
    program_start->setMinimumSize(400,400&#41;;
    program_start->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding&#41;;
    QVBoxLayout *layout = new QVBoxLayout;
    layout->addWidget(program_start);
    program_start->setLayout(layout);
    

    @

    Currently what happens if I only pass the video file name to arguments the video will play. If I include the -wid and or -vo the program no longer runs, if anyone has an idea where I am going wrong please let me know. As currently thinking I have two problems one being my mplayer parameters and the other being related to the container (again not sure though what exactly is the problem line). Thanks for everyones help so far.



  • From the mplayer man page
    @
    -wid <window ID> (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.
    @

    -wid takes a window id of your app or widget and mplayer will use it to output a video. But you will have to control "aspect scaling, panscan, etc".

    Take a look on the sources of "smplayer":http://smplayer.sourceforge.net/ I think they use this embeded mplayer approach.



  • Yea sadly my problem isn't really related to what "-wid" does but why when adding it to the parameters does it not show any video. Either way to give you an idea smplayer is actually where i started this adventure and even they use the same method i do.

    Below is the code of smplayer that inserts the "-wid" into the arguement/parameter list.

    @ proc->addArgument("-wid");
    #if defined(Q_OS_OS2)
    #define WINIDFROMHWND(hwnd) ( ( hwnd ) - 0x80000000UL )
    proc->addArgument( QString::number( WINIDFROMHWND( (int) mplayerwindow->videoLayer()->winId() ) ));
    #else
    proc->addArgument( QString::number( (qint64) mplayerwindow->videoLayer()->winId() ) );@

    and sadly what it looks like to me is that they are using the same method to insert the winID as I have(apart from adding that define before winid). So not really sure what else it might be. Could be a mplayer problem i guess so going to test it tonight to see if i get the same problems on a different machine.

    Thanks for the quote on "-wid" even though I knew that already it will be really helpful for anyone trying to follow this forum post. Hopefully at some point I'll be able to solve it so it's a little more useful than completely useless :P



  • Ah, I did not read the line with -wid correctly in your code. Somehow I thought that you put the result of FindWindow as a parameter of -wid.



  • lol you did actually it was me who made the mistake and still had my program independant method (that's the fromwinid method). Helps if i actually use the winid of the container not mplayer itself :P.



  • Well sadly it looks like I can't get either way to work, but yea think the other method is meant to work in general and the implementation below is supposed to work with mplayer, but failing with application errors atm oh fun.

    @ QWindow *container;

    WId winid = container->winId();
    //QWindow *container = QWindow::fromWinId(winid);
    QWidget *program_start  = createWindowContainer(container);
    
    QString program;
    program = "E:\\Downloads\\mplayer\\mplayer.exe";
    
    QStringList arguments;
    arguments << "-wid" << QString::number(winid) << "E:\\Downloads\\BigBuckBunny_320x180.mp4";
    
    //QStringList arguments;
    //arguments << "E:\\Downloads\\BigBuckBunny_320x180.mp4";
    
    QVBoxLayout *layout = new QVBoxLayout;
    
    QPushButton *button = new QPushButton("Test2");
    QPushButton *button2 = new QPushButton("Test");
    
    
    QProcess *m_process = new QProcess();
    
    m_process->setProgram(program);
    m_process->setArguments(arguments);
    
    m_process->start();
    

    @

    Any advice on either method would be good really.



  • I think you don't need to create a QWindow (BTW, in your code above you don't allocate it)
    Try to use QWidget and get winId() from it.



  • This code works on Linux.
    I created a simple QMainWindow app added QWidget on it in designer and couple QPushButton to start and stop the player.
    This is a
    @
    void MainWindow::on_playButton_clicked()
    {
    if (m_process == nullptr) {
    ui->playButton->setEnabled(false);
    ui->stopButton->setEnabled(true);
    QStringList arguments;
    arguments << "-wid" << QString::number(ui->widget->winId())
    << m_fileName;
    m_process = new QProcess();
    m_process->setProgram(m_player);
    m_process->setArguments(arguments);
    m_process->start();
    }
    }

    void MainWindow::on_stopButton_clicked()
    {
    if (m_process != nullptr) {
    ui->playButton->setEnabled(true);
    ui->stopButton->setEnabled(false);
    delete m_process;
    m_process = nullptr;
    }
    }
    @



  • Well that's kind of weird (but hopeful) I can hear the audio and the widget appears but it's completely green(which is a good sign as it's the same green you get when moving an mplayer screen) , did also try a widget within a widget but got the same result just without the green widget only problem was I couldn't call "program_start->show();" otherwise just crashed on runtime with memory errors. Wish I was doing it on Linux would make my life so much easier :P, pretty sure this is a windows specific problem though but gonna play with a linux implementation anyway as it's a handy thing to know. Hopefully I can resolve these issues and get back to actually coding something, instead of banging my head against a wall :P.

    @ //QWindow *container = null_ptr;

    // WId winid = container->winId();
    //QWindow *container = QWindow::fromWinId(winid);
    //QWidget *program_start = new QWidget();
    WId winid = this->winId();
    QString program;

    program = "E:\\Downloads\\mplayer\\mplayer.exe";
    
    QStringList arguments;
    arguments << "-wid" << QString::number(winid) << "E:\\Downloads\\BigBuckBunny_320x180.mp4";
    
    //QStringList arguments;
    //arguments << "E:\\Downloads\\BigBuckBunny_320x180.mp4";
    
    QVBoxLayout *layout = new QVBoxLayout;
    
    QPushButton *button = new QPushButton("Test2");
    QPushButton *button2 = new QPushButton("Test");
    
    
    QProcess *m_process = new QProcess(this);
    
    m_process->setProgram(program);
    m_process->setArguments(arguments);
    // program_start->show();
    this->show();
    m_process->start();
    

    @



  • After a bit of playing with mplayer I have found it's because you also need to change in the config and change the default render method. config listed below

    @# Write your default config options here!
    #-wid 1234
    #vo=directx
    #vo=direct3d
    vo=gl
    #vo=gl_tiled
    #vo=sdl@

    you can't use directx otherwise you'll just see a green screen. Currently using opengl and it seems the fastest for this usage.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.