LibVLC media player within Juce

Jules / Kraken,

windowID in this context:

        int windowID;
        windowID = (int) getWindowHandle();
        addToDesktop(ComponentPeer::windowIsResizable,0);
        windowID = (int) getWindowHandle();

is always the Component’s Window ID, but LibVLC crashes when I try to use the Component’s window.

The parent’s Window (the Document Window that the content component is set to) ID is always 1 less than the Component’s window ID. How is this random and madness? What am I missing on this?

It sounds like you are saying that opaque true or false has to do with 1 of these 2 problems:

  1. LibVLC crashing when I try to use the content components Window ID (windowID)
  2. Trying to pass the document window’s Window ID (windowID - 1): complete madness, random, what the hell is this? (I basically shouldn’t be doing this)

Thanks for the clue. I will look into this.

Sorry, just to clarify, I didn’t mean ‘opaque’ as in the window’s transparency, I meant that the window ID is an opaque value: it’s a handle. It’s not a number. You shouldn’t even treat it as a pointer. You shouldn’t cast it to an integer (it might be 64-bits in size). And obviously doing any kind of arithmetic to it is just bonkers!

Sorry but the getWindowHandle function returns a void*. How do I use this with what libvlc expects? Because I tried to typecast to a Window before and it didn’t work, so then I typecasted to an integer and it seemed like I was getting somewhere.

The Linux Windowing getNativeHandle returns a pointer to a Window handle:
return (void*) windowH;

I tried this:

libvlc_media_player_set_drawable(mp, getWindowHandle(), &ex);

And I get a compile error (obviously):
VideoComponent.cpp:83: error: invalid conversion from ‘void*’ to ‘libvlc_drawable_t’
VideoComponent.cpp:83: error: initializing argument 2 of ‘void libvlc_media_player_set_drawable(libvlc_media_player_t*, libvlc_drawable_t, libvlc_exception_t*)’

Well if you’re sure that this handle is what vlc is expecting, then you could just reinterpret_cast <libvlc_drawable_t> (getWindowHandle()). Or preferably use static_cast if the type allows that.

puckhead Try with this

libvlc_media_player_set_agl
libvlc_media_player_set_xwindow

Well that certainly sounds more feasible!

Aren’t they COMPATIBLE? uint32 and uint32_t

getComponentUID () return uint32
libvlc_media_player_set_xwindow (libvlc_media_player_t *p_mi, uint32_t drawable, libvlc_exception_t *p_e)

Beware of reinterpret_cast. Don’t use it unless you master C++ better than the compiler (that is, unless you’re Jules or Bjarne).
reinterpret_cast hides error (because, basically it tells the compiler “hey, you’re dumb, I know this object is of this type”.
While it can crash immediatly on first use after casting (you’re lucky), I had issue with something that looked like it worked at first (because of the way the memory was layout), but suddenly crashed when we had changed the initial structure format (removed a member to be clear).
The compiler usually would have sent its red alarm on this, but, eh, “it’s dumb, and you know better than it”.
Sure an ugly cast is harder to grep for in a large code base, but at least the compiler still checks for it.

So, please don’t reinterpret_cast in your code, 99,9999999999% of good C++ code don’t need this anyway.

Good call, I will try that. I’m troubleshooting a separate vlc linking / library issue right now, so I can’t even test those functions yet until I resolve this issue at hand. Thanks.

Both “libvlc_media_player_set_xwindow” and “libvlc_media_player_set_drawable” exhibit the same behavior.

I have a better grasp of the problem now. LibVLC crashes when you attempt to set the X Window ID handle to a non-existent handle, and I was trying to find out what that value is, but it doesn’t appear that my Juce implementation has a X Window ID value for my content component. In fact I’m starting to think that it isn’t possible for a content component to have a unique X Window ID handle. Thus the juce application crashes when you try to set the window to anything other than a known value (DocumentWindow’s value), like so:

[attachment=2]ss1.png[/attachment]

While the media player runs, I used the “xwininfo” tool to find the value of the X Window ID, and the only value that can be found is that of the juce DocumentWindow - there doesn’t appear to be a X Window ID value for the content component.

Is it possible that a content component can have a unique X Window ID handle value that is different from the DocumentWindow that it was set to? If so, how do I implement my code and find the handle? Because I was looking at Component::getNativeHandle:

void* Component::getWindowHandle() const throw()
{
        const ComponentPeer* const peer = getPeer();

        if (peer != 0)
                return peer->getNativeHandle();

        return 0;
}

I see that this member uses getPeer() to return the heavyweight window used by the content component. I wasn’t sure if adding the component to the desktop with Component::addToDesktop made a difference in being able to produce a unique X Window ID handle for the content component.

What I am trying to achieve in my Juce application: I’d like to hook the LibVLC player into the smaller content component’s dimensions (1134 x 562), rather than the larger DocumentWindow’s dimensions (1136 x 590). Why do I want to do this? Because it will be hard to control and use the media player if the media player output uses the exact dimensions of the parent DocumentWindow (1136 x 590). I’ll try to depict why here. First, here is a screen shot of the application before the user has pushed the “Play” textButton.

[attachment=1]ss2.png[/attachment]

Then when the user selects the “Play” textButton, this is what they see:

[attachment=0]ss3.png[/attachment]

As you can see, the LibVLC media player has filled the exact dimensions (1136 x 590) of the DocumentWindow. As a result, the user can no longer see the title bar or the maximise/minimise/close buttons on the DocumentWindow. This makes the application less user friendly. That’s why I would like to hook the LibVLC media player into a smaller dimension window, such as the size of the content component (1134 x 562). Then I could add the control buttons (play, stop, pause) to the top of the component. For a good and simple design, I wanted to keep the video output and video control within the same component. If I can’t set the video output to a smaller X Window ID, then I’ll have to have two components. One for video output, and the other for video control - and I’ll have to share libvlc variables between the components.

So in the hopes that I am just too close to this problem to think outside the box, is there any way to creatively solve this problem, setting the VLC output to a smaller resolution X Window ID that doesn’t fill the entire DocumentWindow?

Here is my VideoComponent constructor:

VideoComponent::VideoComponent()
    : textButtonPlay (0),
      textButtonPause (0),
      textButtonStop (0)
{

        addAndMakeVisible (textButtonPlay = new TextButton (T("new button")));
        textButtonPlay->setButtonText (T("Play"));
        textButtonPlay->addButtonListener (this);

        addAndMakeVisible (textButtonPause = new TextButton (T("new button")));
        textButtonPause->setButtonText (T("Pause"));
        textButtonPause->addButtonListener (this);

        addAndMakeVisible (textButtonStop = new TextButton (T("new button")));
        textButtonStop->setButtonText (T("Stop"));
        textButtonStop->addButtonListener (this);

        addToDesktop(ComponentPeer::windowIsResizable,0);
        int windowID;
        windowID = (int) getWindowHandle();
        printf("In Constructor, Window ID: %d\n",windowID);

        //Set Bounds 
        setBoundsRelative(0.0547f, 0.0931f, 0.8860f, 0.7022f);
}

and here is the listener for Play:

void VideoComponent::buttonClicked (Button* buttonThatWasClicked)
{


    if (buttonThatWasClicked == textButtonPlay)
    {

        char width[32], height[32];
        sprintf(width, "%i", VIDEOWIDTH);
        sprintf(height, "%i", VIDEOHEIGHT);
        const char * const vlc_args[] =
        {
                "-I", "dummy",
                "--vmem-width", width,
                "--vmem-height", height,
                "--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, "sample-video.mov", &ex);
        raise (&ex);

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

        int pwidth = getParentWidth();
        int pheight = getParentHeight();
        printf("parent dimensions:  %d x %d\n",pwidth,pheight);
        int cwidth = getWidth();
        int cheight = getHeight();
        printf("component dimensions:  %d x %d\n",cwidth,cheight);
        int WinId = (int) getWindowHandle();
        printf("After pushing Play button, Window ID:  %d\n",WinId);

        libvlc_media_player_set_xwindow(mp, (uint32_t) getWindowHandle(), &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);

    }

Have you tried using the second argument of addToDesktop:

virtual void Component::addToDesktop  (int windowStyleFlags, void* nativeWindowToAttachTo = 0	) 

and pass your Window object of your second smaller window ? don’t know actually if it’s implemented on linux, but we could take the chance to implement it…

Sounds like you’ll need to use the same approach I’ve used for things like ActiveX, Quicktime, etc - creating a special component that’s controls its own a heavyweight window which is embedded inside the juce window. Unfortunately that’s definitely ‘advanced juce’, and I can’t give you a quick explanation of how to do it, other than to try to learn how ComponentPeers work, and look at the code for things like Quicktime on windows.

Overlaying components on any kind of native window is a can of worms - as a general problem it’s extraordinarily difficult to solve, which is why I’ve not yet attempted to do so for Quicktime, activeX, etc…

Not sure how to pass the smaller window’s object.

My component VLC juce.

Lack

1 than this always on the same level than the window of the component
2 that the window of the video in the bar of tasks does not give the appearance of being you

And keeping on adding new functionalities.

VideoVLC.h[code]
#ifndef JUCER_HEADER_VIDEOVLC_VIDEOVLC_8098838B
#define JUCER_HEADER_VIDEOVLC_VIDEOVLC_8098838B
//[Headers]
#include <vlc/vlc.h>
#include “juce.h”
//[/Headers]

class VideoVLC : public Component,
private Timer
{
public:
//==============================================================================
VideoVLC ();
~VideoVLC();

void play();
void stop();
void pause();
void setPosition(float p_posi);
float getPosition();
void setRate(float p_rate);
float getRate();
void loadMedia(String media);
bool isLoadMedia;

void paint (Graphics& g);
void resized();

juce_UseDebuggingNewOperator

private:
void timerCallback();
DocumentWindow *vlc_visor;
libvlc_exception_t vlc_except;
libvlc_instance_t *vlc_instan;
libvlc_media_player_t *vlc_mplayer;
libvlc_media_t *vlc_media;

// (prevent copy constructor and operator= being generated..)
VideoVLC (const VideoVLC&);
const VideoVLC& operator= (const VideoVLC&);

};

#endif // JUCER_HEADER_VIDEOVLC_VIDEOVLC_8098838B

[/code]

VideoVLC.cpp[code]
#include “VideoVLC.h”
//[MiscUserDefs] You can add your own user definitions and misc code here…
static void raise(libvlc_exception_t * ex)
{
if (libvlc_exception_raised (ex))
{
AlertWindow::showMessageBox (AlertWindow::InfoIcon,
T(“VCLPlayer”),
libvlc_exception_get_message(ex));
fprintf (stderr, “error: %s\n”, libvlc_exception_get_message(ex));
//exit (-1);
}
}
//[/MiscUserDefs]
//==============================================================================
VideoVLC::VideoVLC ()
: Component (T(“VideoVLC”))
{ //[UserPreSize]
//[/UserPreSize]
setSize (400, 200);
//[Constructor] You can add your own custom stuff here…
vlc_visor=new DocumentWindow(T(""),
Colours::black,
0,
true);
vlc_visor->setAlwaysOnTop(true);
vlc_visor->setTitleBarHeight(0);
vlc_visor->setDropShadowEnabled(false);

libvlc_exception_init (&vlc_except);
isLoadMedia=false;
//[/Constructor]

}

VideoVLC::~VideoVLC()
{
//[Destructor_pre]. You can add your own custom destruction code here…
//[/Destructor_pre]
//[Destructor]. You can add your own custom destruction code here…
delete vlc_instan;
delete vlc_media;
delete vlc_mplayer;
delete vlc_visor;
//[/Destructor]
}

//==============================================================================
void VideoVLC::paint (Graphics& g)
{
//[UserPrePaint] Add your own custom painting code here…
//[/UserPrePaint]
g.fillAll (Colours::black);
//[UserPaint] Add your own custom painting code here…
//[/UserPaint]
}

void VideoVLC::resized()
{
//[UserResized] Add your own custom resize handling here…
//[/UserResized]
}
void VideoVLC::timerCallback(){
vlc_visor->setBounds(getScreenX(),getScreenY(),getWidth(),getHeight());
//vlc_visor->toFront(true);
}
void VideoVLC::play(){
if(isLoadMedia==false){return;}
libvlc_media_player_play (vlc_mplayer, &vlc_except);
raise (&vlc_except);
startTimer(1);
vlc_visor->setVisible(true);
}
void VideoVLC::stop(){
if(isLoadMedia==false){return;}
libvlc_media_player_stop(vlc_mplayer, &vlc_except);
raise (&vlc_except);
vlc_visor->setVisible(false);
stopTimer();
}
void VideoVLC::pause(){
if(isLoadMedia==false){return;}
libvlc_media_player_pause(vlc_mplayer, &vlc_except);
raise (&vlc_except);
}
void VideoVLC::setRate(float p_rate){
if(isLoadMedia==false){return;}
libvlc_media_player_set_rate(vlc_mplayer,p_rate ,&vlc_except);//SPEED
raise (&vlc_except);
}
float VideoVLC::getRate(){
if(isLoadMedia==false){return -1;}
float vr=libvlc_media_player_get_rate(vlc_mplayer,&vlc_except);//SPEED
raise (&vlc_except);
return vr;
}
void VideoVLC::setPosition(float p_posi){
if(isLoadMedia==false){return;}
libvlc_media_player_set_position(vlc_mplayer,p_posi ,&vlc_except);//SPEED
raise (&vlc_except);
}
float VideoVLC::getPosition(){
if(isLoadMedia==false){return -1;}
float vr=libvlc_media_player_get_position(vlc_mplayer,&vlc_except);//SPEED
raise (&vlc_except);
return vr;
}
void VideoVLC::loadMedia(String pmedia){

const char * const vlc_args[] = {
          "-I", "dummy",
          "--ignore-config",
          "--plugin-path=C:\\plugins\\"};

if(vlc_instan !=0){delete vlc_instan;}
vlc_instan = libvlc_new (sizeof(vlc_args) / sizeof(vlc_args[0]), vlc_args, &vlc_except);
raise (&vlc_except);

if(vlc_media !=0){delete vlc_media;}
vlc_media = libvlc_media_new (vlc_instan,pmedia,&vlc_except);
raise (&vlc_except);

if(vlc_mplayer !=0){
    stop();
    delete vlc_mplayer;}
vlc_mplayer = libvlc_media_player_new_from_media (vlc_media, &vlc_except);
raise (&vlc_except);
libvlc_media_release (vlc_media);

libvlc_media_player_set_hwnd(vlc_mplayer,vlc_visor->getWindowHandle(),&vlc_except);
raise (&vlc_except);
isLoadMedia=true;

}

[/code]

I see…Jules, would it be possible for a Juce expert to help implement this, as a new feature (libvlc media player plugin support)? I think this would be a worthwhile endeavor and useful because libvlc is cross-platform, and will work with more than just Linux OSes.

I’m a bit tied up in other areas at the moment, but might help out a bit at some point. Keep me posted with your progress…

puckhead Try my component, he always to be in the window it is what I have achieved for the moment.

español:prueba mi componente, siempre esta en la ventana es lo que he logrado por el momento.

Thanks. Will do.

Thanks yosvaniscc. How are you implementing when you add your component? I see the cpp and header files but I don’t see how you are adding the VideoVLC component in your code. Because I add a DocumentWindow and set the content component to VideoComponent - this might differ from your code.

When I sent you my code a while back, can you send the tarball to me with all of the code you have? My email address: jpo@pobox.com.