LibVLC media player within Juce


#1

Can anyone please help - I am trying to create a LibVLC media player within a Juce component, and I’m totally lost.

I can compile the standalone media player when I link to vlc headers and run it just fine, using LibVLC - http://wiki.videolan.org/Libvlc

Here is a screen shot showing the standalone application, compile and run. You can see the console app launching a “VLC Xvideo output” window.
[attachment=0]ss2.png[/attachment]

But when I try to add it into my Juce component, I have no clue how to draw it centered in the Juce component and have juce control the runtime of the LibVLC media player. I have a MediaWindow DocumentWindow and inside of this, I have a juce VideoComponent. The LibVLC media player instance is defined inside of the constructor for the VideoComponent. The vlc code compiles with my juce application, but when I launch the video player component, the libvlc media player starts but it isn’t inside of the VideoComponent. I have no way of controlling how large or small the media player is and hooking it inside of a juce window. Here is my Juce code showing the constructor for the VideoComponent:

#include "VideoComponent.h"
#include "MediaWindow.h"
#include "SkinWorker.h"
#include "ImageData.h"
#include <vlc/vlc.h>

static void raise(libvlc_exception_t * ex)
{
    if (libvlc_exception_raised (ex))
    {
         fprintf (stderr, "error: %s\n", libvlc_exception_get_message(ex));
         exit (-1);
    }
}

VideoComponent::VideoComponent()
{

    const char * const vlc_args[] = {
              "-I", "dummy",
              "--ignore-config"};
    libvlc_exception_t ex;
    libvlc_instance_t * inst;
    libvlc_media_player_t *mp;
    libvlc_media_t *m;

    libvlc_exception_init (&ex);
    inst = libvlc_new (sizeof(vlc_args) / sizeof(vlc_args[0]), vlc_args, &ex);
    raise (&ex);

    m = libvlc_media_new (inst, "out.ogv", &ex);
    raise (&ex);

    mp = libvlc_media_player_new_from_media (m, &ex);
    raise (&ex);

    libvlc_media_release (m);

    libvlc_media_player_play (mp, &ex);
    raise (&ex);
    
    //sleep(10);

    //libvlc_media_player_stop (mp, &ex);

    //libvlc_media_player_release (mp);

    //libvlc_release (inst);
    //raise (&ex);
    setBoundsRelative(0.0547f, 0.0931f, 0.8860f, 0.7022f);
}

Can anyone please help? I’d like to be able to have Juce set the LibVLC media player perfectly within the bounds of my VideoComponent, so that shutting down my VideoComponent will stop the media player. I don’t know where to start with what class can do this.


#2

Look at the SDL example in LibVLC, it does practically this: uses the vlc video framebuffer to fill a SDL window.
Should be pretty straightforward to adapt the code to fill a juce Image and blit it on a Graphics inside your component.


#3

revize like me your source code, and work with you.

I speak Spanish.


#4

Kraken: Thanks for the heads up - will check it out and get back to you.

yosvaniscc: De nada. Hablo porquito espanol. Yo no sé el significado de las frases, “revize like me”. Favor de clarificar? Que te vayas bien.


#5

kraken que me gustaria revizar tu codigo y trabajar contigo en ese proyecto


#6

send me mail yosvaniscc@gmail.com you juce project.

español: mandame a mi correo yosvaniscc@gmail.com tú proyecto juce.


#7

I’ll send it over to you via email.

What OS do you use? I use Ubuntu Linux so the tarball will be a GNU Makefile project. Not sure what your OS is…if it isn’t Linux, you’ll have to adapt the build system for your OS environment / IDE - but source and header files are all the same and will compile the Juce application, obviously.


#8

I use Debian Linux and WinXP.

IDE is CodeBlocks.


#9

I sent the video player juce project to your email address.


#10

Have been studying the libvlc source code and juce source, trying hard to learn how to do this. I still don’t see how to fill the media player output instance inside of the juce Image. I continue to study the juce Image class member documentation and I don’t see what member would allow this. Can you please provide a hint? Is there a Juce Image class member that can easily do this with video output?

For example, I know I can create an image:
Image mediaPlayerImage (Image::RGB, 500, 500, true);

I also figured out how to use LibVLC to set the size of the video output to 500 x 500:
libvlc_video_set_size(inst,500,500,&ex);

However, hooking the video output inside of the Juce image is still a mystery to me. So that when you move the juce component or resize it, the video output will follow instead of being independent of the Juce image.

I also wasn’t familiar with blitting but I think this is the code that would copy the image on a Graphics context:
Graphics g (mediaPlayerImage);


#11

An option can be looking up in the libvcl some method that returns the image of the video and going charging in an image Its juce.

español:una opción puede ser buscar en la libvcl algún método que devuelva la imagen del video y ir cargándola en una imagen juce.


#12

Jules, Kraken, or anyone:

After further research, the QT example media player code has helped me, and I’m very close.

It looks like libvlc has a set_drawable function call. It looks like the following call in Linux will set the drawable:
libvlc_media_player_set_drawable(_mp, _videoWidget->winId(), &_vlcexcep );

The second parameter, “_videoWidget->winId()”, is for QT - what would the equivalent be for Juce on Linux?

Here is the code snipet from “vlc_on_qt.cpp” at the LibVLC SampleCode QT Wiki URL - http://wiki.videolan.org/LibVLC_SampleCode_Qt
It took me 5 minutes to build this QT VLC media player application in Linux and the media player perfectly resized and “follows” the parent QT application. I’d love to be able to do this same thing in Juce, as I think Juce has a much better look and feel. I will post this code to the sample apps Cookbook after I get it going.

#include "vlc_on_qt.h"
#include <stdio.h>

#include <QVBoxLayout>
#include <QPushButton>
#include <QSlider>
#include <QTimer>
#include <QFrame>

Player::Player()
: QWidget()
{
    //preparation of the vlc command
    const char * const vlc_args[] = {
              "-I", "dummy", /* Don't use any interface */
              "--ignore-config", /* Don't use VLC's config */
              "--extraintf=logger", //log anything
              "--verbose=2", //be much more verbose then normal for debugging purpose
              "--plugin-path=C:\\vlc-0.9.9-win32\\plugins\\" };

    _videoWidget=new QFrame(this);

    _volumeSlider=new QSlider(Qt::Horizontal,this);
    _volumeSlider->setMaximum(100); //the volume is between 0 and 100
    _volumeSlider->setToolTip("Audio slider");

    // Note: if you use streaming, there is no ability to use the position slider
    _positionSlider=new QSlider(Qt::Horizontal,this); 
    _positionSlider->setMaximum(POSITION_RESOLUTION);

    QVBoxLayout *layout = new QVBoxLayout;
    layout->addWidget(_videoWidget);
    layout->addWidget(_positionSlider);
    layout->addWidget(_volumeSlider);
    setLayout(layout);

    _isPlaying=false;
    poller=new QTimer(this);

    //Initialize an instance of vlc
    //a structure for the exception is neede for this initalization
    libvlc_exception_init(&_vlcexcep);

    //create a new libvlc instance
    _vlcinstance=libvlc_new(sizeof(vlc_args) / sizeof(vlc_args[0]), vlc_args,&_vlcexcep);  //tricky calculation of the char space used
    raise (&_vlcexcep);
    
    // Create a media player playing environement 
    _mp = libvlc_media_player_new (_vlcinstance, &_vlcexcep);
    raise (&_vlcexcep);

    //connect the two sliders to the corresponding slots (uses Qt's signal / slots technology)
    connect(poller, SIGNAL(timeout()), this, SLOT(updateInterface()));
    connect(_positionSlider, SIGNAL(sliderMoved(int)), this, SLOT(changePosition(int)));
    connect(_volumeSlider, SIGNAL(sliderMoved(int)), this, SLOT(changeVolume(int)));

    poller->start(100); //start timer to trigger every 100 ms the updateInterface slot
}

//desctructor
Player::~Player()
{
    /* Stop playing */
    libvlc_media_player_stop (_mp, &_vlcexcep);

    /* Free the media_player */
    libvlc_media_player_release (_mp);

    libvlc_release (_vlcinstance);
    raise (&_vlcexcep);
}

void Player::playFile(QString file)
{
    //the file has to be in one of the following formats /perhaps a little bit outdated)
    /*
    [file://]filename              Plain media file
    http://ip:port/file            HTTP URL
    ftp://ip:port/file             FTP URL
    mms://ip:port/file             MMS URL
    screen://                      Screen capture
    [dvd://][device][@raw_device]  DVD device
    [vcd://][device]               VCD device
    [cdda://][device]              Audio CD device
    udp:[[<source address>]@[<bind address>][:<bind port>]]
    */

    /* Create a new LibVLC media descriptor */
    _m = libvlc_media_new (_vlcinstance, file.toAscii(), &_vlcexcep);
    //_m = libvlc_media_new (_vlcinstance, "sample-video.ogv", &_vlcexcep);
    raise(&_vlcexcep);
    
    libvlc_media_player_set_media (_mp, _m, &_vlcexcep);
    raise(&_vlcexcep);

    // /!\ Please note /!\
    //
    // passing the widget to the lib shows vlc at which position it should show up
    // vlc automatically resizes the video to the ´given size of the widget
    // and it even resizes it, if the size changes at the playing
    
    /* Get our media instance to use our window */
    #if defined(Q_OS_WIN)
        libvlc_media_player_set_drawable(_mp, reinterpret_cast<unsigned int>(_videoWidget->winId()), &_vlcexcep );
        //libvlc_media_player_set_hwnd(_mp, _videoWidget->winId(), &_vlcexcep ); // for vlc 1.0
    #elif defined(Q_OS_MAC)
        libvlc_media_player_set_drawable(_mp, _videoWidget->winId(), &_vlcexcep );
        //libvlc_media_player_set_agl (_mp, _videoWidget->winId(), &_vlcexcep); // for vlc 1.0
    #else //Linux
        libvlc_media_player_set_drawable(_mp, _videoWidget->winId(), &_vlcexcep );
        //libvlc_media_player_set_xwindow(_mp, _videoWidget->winId(), &_vlcexcep ); // for vlc 1.0
    #endif
    raise(&_vlcexcep);

    /* Play */
    libvlc_media_player_play (_mp, &_vlcexcep );
    raise(&_vlcexcep);

    _isPlaying=true;
}

void Player::changeVolume(int newVolume)
{
    libvlc_exception_clear(&_vlcexcep);
    libvlc_audio_set_volume (_vlcinstance,newVolume , &_vlcexcep);
    raise(&_vlcexcep);
}

void Player::changePosition(int newPosition)
{
    libvlc_exception_clear(&_vlcexcep);
    // It's possible that the vlc doesn't play anything
    // so check before
    libvlc_media_t *curMedia = libvlc_media_player_get_media (_mp, &_vlcexcep);
    libvlc_exception_clear(&_vlcexcep);
    if (curMedia == NULL)
        return;

    float pos=(float)(newPosition)/(float)POSITION_RESOLUTION;
    libvlc_media_player_set_position (_mp, pos, &_vlcexcep);
    raise(&_vlcexcep);
}

void Player::updateInterface()
{
    if(!_isPlaying)
        return;

    // It's possible that the vlc doesn't play anything
    // so check before
    libvlc_media_t *curMedia = libvlc_media_player_get_media (_mp, &_vlcexcep);
    libvlc_exception_clear(&_vlcexcep);
    if (curMedia == NULL)
        return;

    float pos=libvlc_media_player_get_position (_mp, &_vlcexcep);
    int siderPos=(int)(pos*(float)(POSITION_RESOLUTION));
    _positionSlider->setValue(siderPos);
    int volume=libvlc_audio_get_volume (_vlcinstance,&_vlcexcep);
    _volumeSlider->setValue(volume);
}
void Player::raise(libvlc_exception_t * ex)
{
    if (libvlc_exception_raised (ex))
    {
         //fprintf (stderr, "error: %s\n", libvlc_exception_get_message(ex));
         fprintf (stderr, "error: %s\n", libvlc_exception_get_message(ex));
         exit (-1);
    }
}

#13

Does anyone know how to find the X Window ID for a juce window or component?

It looks like I have to just find the X Window ID in Linux for a given Juce component - then LibVLC will automatically take care of following the Juce window.

Here is the QT example for a Widget, but the code should be very similar, except for a Juce Component instead of the _videoWidget:

    // /!\ Please note /!\
    //
    // passing the widget to the lib shows vlc at which position it should show up
    // vlc automatically resizes the video to the ´given size of the widget
    // and it even resizes it, if the size changes at the playing

    /* Get our media instance to use our window */
    #if defined(Q_OS_WIN)
        libvlc_media_player_set_drawable(_mp, reinterpret_cast<unsigned int>(_videoWidget->winId()), &_vlcexcep );
        //libvlc_media_player_set_hwnd(_mp, _videoWidget->winId(), &_vlcexcep ); // for vlc 1.0
    #elif defined(Q_OS_MAC)
        libvlc_media_player_set_drawable(_mp, _videoWidget->winId(), &_vlcexcep );
        //libvlc_media_player_set_agl (_mp, _videoWidget->winId(), &_vlcexcep); // for vlc 1.0
    #else //Linux
        libvlc_media_player_set_drawable(_mp, _videoWidget->winId(), &_vlcexcep );
        //libvlc_media_player_set_xwindow(_mp, _videoWidget->winId(), &_vlcexcep ); // for vlc 1.0
    #endif
    raise(&_vlcexcep);

In VLC source code, here is the implementation of 'libvlc_media_player_set_drawable() :

/**************************************************************************
 * Set Drawable
 **************************************************************************/
void libvlc_media_player_set_drawable( libvlc_media_player_t *p_mi,
                                       libvlc_drawable_t drawable,
                                       libvlc_exception_t *p_e )
{
#ifdef WIN32
    if (sizeof (HWND) <= sizeof (libvlc_drawable_t))
        p_mi->drawable.hwnd = (HWND)drawable;
    else
        libvlc_exception_raise(p_e, "Operation not supported");
#elif defined(__APPLE__)
    p_mi->drawable.agl = drawable;
    (void) p_e;
#else
    p_mi->drawable.xid = drawable;
    (void) p_e;
#endif
}

#14

Component::getWindowHandle is probably the right value - you can check by looking in the linux native windowing code.


#15

Component::getWindowHandle does the trick for this, on Ubuntu Linux 9.10.

I was able to tell LibVLC to hook into the Juce Window, and whenever you resize or move the position of the DocumentWindow, the media player follows. Works great.

Here is the code sample. This code is inside of the component constructor, and it hooks LibVLC into the parent DocumentWindow. Need to play with the code further to get it to hook into the Juce component instead of the DocumentWindow:

// First add the Component to the Desktop
addToDesktop(ComponentPeer::windowIsResizable,0);

int windowID;
windowID = (int) getWindowHandle();

// hook LibVLC into the Juce DocumentWindow
libvlc_media_player_set_drawable(mp, windowID - 1, &ex);

#16

The window is out of service

const char * const vlc_args[] = {
              "-I", "dummy",
              "--ignore-config",
               "--plugin-path=C:\\plugins\\"};
    libvlc_exception_t ex;
    libvlc_instance_t * inst;
    libvlc_media_player_t *mp;
    libvlc_media_t *m;

    libvlc_exception_init (&ex);
    inst = libvlc_new (sizeof(vlc_args) / sizeof(vlc_args[0]), vlc_args, &ex);
    raise (&ex);

    m = libvlc_media_new (inst, "Susanita.mpg", &ex);
    raise (&ex);

    mp = libvlc_media_player_new_from_media (m, &ex);
    raise (&ex);

    libvlc_media_release (m);
/******************************************/
    addToDesktop(ComponentPeer::windowIsResizable,0);
    int windowID;
    windowID = (int) getWindowHandle();
    libvlc_media_player_set_drawable(mp,  windowID-1, &ex );

/********************************************/
    libvlc_media_player_play (mp, &ex);
    raise (&ex);

#17

what the hell is

?

Never seen anything like that… it’s not a socket select !


#18

From vlc source, media_player.c, this function sets the drawable for LibVLC media player:

/**************************************************************************
 * Set Drawable
 **************************************************************************/
void libvlc_media_player_set_drawable( libvlc_media_player_t *p_mi,
                                       libvlc_drawable_t drawable,
                                       libvlc_exception_t *p_e )

LibVLC crashes when with Component’s window ID is passed as the second parameter:
libvlc_media_player_set_drawable(mp, windowID, &ex );

It only works with the parent DocumentWindow’s window ID, but the user has no control over any Component buttons, as the media player covers them. Works like this:
libvlc_media_player_set_drawable(mp, windowID - 1, &ex );


#19

Looks like the drawable, libvlc_drawable_t drawable, to tell LibVLC what window to draw into.


#20

I think kraken understood the context, but his point was that randomly subtracting 1 from an opaque window handle is complete madness.