Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: GStreamer SDK and SFML  (Read 13734 times)

0 Members and 1 Guest are viewing this topic.

Zapfyr

  • Newbie
  • *
  • Posts: 29
    • View Profile
    • Email
GStreamer SDK and SFML
« on: October 09, 2012, 03:23:02 pm »
Hi,

Using  GStreamer SDK (http://gstreamer.com/, i.e. GStreamer that is cross-platform) together with SFML would be cool. I.e. it would be pretty awesome to use it to decode a movie to a texture and use it in a sprite in SFML. As I am pretty new to both SFML and GStreamer SDK it would be awesome if someone with a bit more experience could give me hint or two how I could achieve the whole decode a movie to a texture and render it trough a sprite-process. :)

// Zap

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: GStreamer SDK and SFML
« Reply #1 on: October 09, 2012, 03:30:22 pm »
The sfeMovie project does what you want. You can use it directly if using ffmpeg instead of GStreamer is not a problem for you, or you can look at its sources if you want to implement your own movie library.
Laurent Gomila - SFML developer

Zapfyr

  • Newbie
  • *
  • Posts: 29
    • View Profile
    • Email
Re: GStreamer SDK and SFML
« Reply #2 on: October 09, 2012, 03:37:45 pm »
Sorry, I should have mentioned that I have tried sfeMovie, but I found it quite heavy (performance-wise), and if I am not mistaken; lacking the ability to seek in a movie. Using gstreamer the possibillity for hardware acceleration (for example using the vaapi plugin) opens up as well. But I will take a second look into the sfeMovie project, thanks.

// Zap

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: GStreamer SDK and SFML
« Reply #3 on: October 09, 2012, 03:40:36 pm »
Yes, but its sources can answer your question
Quote
how I could achieve the whole decode a movie to a texture and render it trough a sprite-process.
Laurent Gomila - SFML developer

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11034
    • View Profile
    • development blog
    • Email
Re: GStreamer SDK and SFML
« Reply #4 on: October 09, 2012, 04:47:56 pm »
Someone once wrote a GStreamer wrapper for/with SFML, but that post was removed on the forum and I don't remember the GitHub adress...
Maybe some Googling will bring it to the light. ;)
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11034
    • View Profile
    • development blog
    • Email
Re: GStreamer SDK and SFML
« Reply #5 on: October 19, 2012, 01:17:17 pm »
If you're still interested in that wrapper I mentioned, I've just noticed that I stared the project on GitHub so I was able to find it again. ;D
But it seems like he switched from SFML to SDL, so you might need to rewrite some parts or checkout a older commit and apply the changes manually...

_2RealGStreamerWrapper
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Zapfyr

  • Newbie
  • *
  • Posts: 29
    • View Profile
    • Email
Re: GStreamer SDK and SFML
« Reply #6 on: October 19, 2012, 01:23:12 pm »
Thanks, man! :)

I, however, started building my own, based on OSSBuild, as GStreamer SDK doesn't include the OpenGL plugin (which OSSBuild does).

I will report back how it goes, later. ;)

// Zap

Ceylo

  • Hero Member
  • *****
  • Posts: 2325
    • View Profile
    • http://sfemovie.yalir.org/
    • Email
Re: GStreamer SDK and SFML
« Reply #7 on: October 19, 2012, 07:56:20 pm »
Sorry, I should have mentioned that I have tried sfeMovie, but I found it quite heavy (performance-wise), and if I am not mistaken; lacking the ability to seek in a movie. Using gstreamer the possibillity for hardware acceleration (for example using the vaapi plugin) opens up as well. But I will take a second look into the sfeMovie project, thanks.

// Zap
You're right about CPU usage, sfeMovie is heavy although it's usable. You're also right about the missing seeking feature.

However I don't think making your own player from scratch is the best idea. Here is why:
- sfeMovie is already *a lot* of work. I've been working on it for two years now, so unless you're targeting very specific software/hardware or unless you're already much experienced with video stuff/really smart, I believe you would get things done in less time if you rather fixed what's missing in sfeMovie (as your own project or by participating to sfeMovie, that's up to you)
- concerning hardware accelerators, FFmpeg (on which sfeMovie relies) provides these ones:
Code: [Select]
h263_vaapi mpeg2_dxva2 vc1_vaapi
h264_dxva2 mpeg2_vaapi wmv3_dxva2
h264_vaapi mpeg2_vdpau wmv3_vaapi
h264_vda mpeg4_vaapi
mpeg1_vdpau vc1_dxva2
I guess these would fit your needs. In order to be enabled, FFmpeg must be built on a host that support these accelerators, that way the FFmpeg configure script will be able to detect and enable support for these accelerators.
- as for seeking, I had been working on it but never included the changes as it isn't finished yet. You can look at what had been done on the seeking branch.

If you still want to make your own player, here are some points you should have a close look at:
- audio/video syncing
- audio/video decoding latency handling
- video stream structure: especially the fact that most frames in a video file are incomplete frames, which prevents you from simply seeking to a specific time

In any case, good luck :)
Ceylo
Want to play movies in your SFML application? Check out sfeMovie!

Zapfyr

  • Newbie
  • *
  • Posts: 29
    • View Profile
    • Email
Re: GStreamer SDK and SFML
« Reply #8 on: October 19, 2012, 08:46:47 pm »
The sfeMovie project seems awesome, and I do not doubt that I could use it. However trying out the tutorials for GStreamer SDK I found it good performance-wise as well as quite easy to use and install, for being a very flexible, large and complex SDK. Which that is why I will try to use it in my project. However if that fails miserably I will probably try to use sfeMovie instead.

My (initial) plan is to use GStreamers playbin2 and the gst-plugin-gl (OpenGL plugin for GStreamer, which is included in the OSSBuild) to draw video as a sprite (or at least on a textured quad). As the plugin will give you an actual OpenGL-texture-id when a frame has been decoded. The plugin enables the current frame to be uploaded to the GPU without any work, except for the actual setup of the pipeline . Decoding a 1080p h264 movie with the help of playbin2 works very nice, getting a very similar preformenc as VLC and similar media-players on Windows (haven't tried it on *nix just yet).

Quote
If you still want to make your own player, here are some points you should have a close look at:
- audio/video syncing
- audio/video decoding latency handling
- video stream structure: especially the fact that most frames in a video file are incomplete frames, which prevents you from simply seeking to a specific time
As far as I know GStreamer does all this for you.

Some interesting links:
GStreamer SDK tutorials: http://docs.gstreamer.com/display/GstSDK/Tutorials
OSSBuild, GStreamer that includes the OpenGL plugin and a lot more. http://code.google.com/p/ossbuild/

GStreamer SDK and the OSSBuild works nicely on Windows in VS2010.

Here is a very simple example (from gst-plugin-gl) of how to use the OpenGL plugin, drawing a test video on the sides of a cube:
#include <GL/glew.h>
#include <gst/gst.h>

#include <iostream>
#include <string>

static gboolean bus_call (GstBus *bus, GstMessage *msg, gpointer data)
{
    GMainLoop *loop = (GMainLoop*)data;

    switch (GST_MESSAGE_TYPE (msg))
    {
        case GST_MESSAGE_EOS:
              g_print ("End-of-stream\n");
              g_main_loop_quit (loop);
              break;
        case GST_MESSAGE_ERROR:
          {
              gchar *debug = NULL;
              GError *err = NULL;

              gst_message_parse_error (msg, &err, &debug);

              g_print ("Error: %s\n", err->message);
              g_error_free (err);

              if (debug)
              {
                  g_print ("Debug deails: %s\n", debug);
                  g_free (debug);
              }

              g_main_loop_quit (loop);
              break;
          }
        default:
          break;
    }

    return TRUE;
}

//client reshape callback
void reshapeCallback (GLuint width, GLuint height, gpointer data)
{
    glViewport(0, 0, width, height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45, (gfloat)width/(gfloat)height, 0.1, 100);
    glMatrixMode(GL_MODELVIEW);
}

//client draw callback
gboolean drawCallback (GLuint texture, GLuint width, GLuint height, gpointer data)
{
    static GLfloat      xrot = 0;
    static GLfloat      yrot = 0;
    static GLfloat      zrot = 0;
    static GTimeVal current_time;
    static glong last_sec = current_time.tv_sec;
    static gint nbFrames = 0;

    g_get_current_time (&current_time);
    nbFrames++ ;

    if ((current_time.tv_sec - last_sec) >= 1)
    {
        std::cout << "GRPHIC FPS = " << nbFrames << std::endl;
        nbFrames = 0;
        last_sec = current_time.tv_sec;
    }

    glEnable(GL_DEPTH_TEST);

    glEnable (GL_TEXTURE_RECTANGLE_ARB);
    glBindTexture (GL_TEXTURE_RECTANGLE_ARB, texture);
    glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glTranslatef(0.0f,0.0f,-5.0f);

    glRotatef(xrot,1.0f,0.0f,0.0f);
    glRotatef(yrot,0.0f,1.0f,0.0f);
    glRotatef(zrot,0.0f,0.0f,1.0f);

    glBegin(GL_QUADS);
              // Front Face
              glTexCoord2f((gfloat)width, 0.0f); glVertex3f(-1.0f, -1.0f,  1.0f);
              glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f,  1.0f);
              glTexCoord2f(0.0f, (gfloat)height); glVertex3f( 1.0f,  1.0f,  1.0f);
              glTexCoord2f((gfloat)width, (gfloat)height); glVertex3f(-1.0f,  1.0f,  1.0f);
              // Back Face
              glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
              glTexCoord2f(0.0f, (gfloat)height); glVertex3f(-1.0f,  1.0f, -1.0f);
              glTexCoord2f((gfloat)width, (gfloat)height); glVertex3f( 1.0f,  1.0f, -1.0f);
              glTexCoord2f((gfloat)width, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
              // Top Face
              glTexCoord2f((gfloat)width, (gfloat)height); glVertex3f(-1.0f,  1.0f, -1.0f);
              glTexCoord2f((gfloat)width, 0.0f); glVertex3f(-1.0f,  1.0f,  1.0f);
              glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f,  1.0f,  1.0f);
              glTexCoord2f(0.0f, (gfloat)height); glVertex3f( 1.0f,  1.0f, -1.0f);
              // Bottom Face
              glTexCoord2f((gfloat)width, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
              glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
              glTexCoord2f(0.0f, (gfloat)height); glVertex3f( 1.0f, -1.0f,  1.0f);
              glTexCoord2f((gfloat)width,(gfloat)height); glVertex3f(-1.0f, -1.0f,  1.0f);
              // Right face
              glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
              glTexCoord2f(0.0f, (gfloat)height); glVertex3f( 1.0f,  1.0f, -1.0f);
              glTexCoord2f((gfloat)width, (gfloat)height); glVertex3f( 1.0f,  1.0f,  1.0f);
              glTexCoord2f((gfloat)width, 0.0f); glVertex3f( 1.0f, -1.0f,  1.0f);
              // Left Face
              glTexCoord2f((gfloat)width, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
              glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f,  1.0f);
              glTexCoord2f(0.0f, (gfloat)height); glVertex3f(-1.0f,  1.0f,  1.0f);
              glTexCoord2f((gfloat)width, (gfloat)height); glVertex3f(-1.0f,  1.0f, -1.0f);
    glEnd();

    xrot+=0.3f;
    yrot+=0.2f;
    zrot+=0.4f;

    //return TRUE causes a postRedisplay
    return TRUE;
}


//gst-launch-0.10 videotestsrc num_buffers=400 ! video/x-raw-rgb, width=320, height=240 !
//glgraphicmaker ! glfiltercube ! video/x-raw-gl, width=800, height=600 ! glimagesink
gint main (gint argc, gchar *argv[])
{
    GstStateChangeReturn ret;
    GstElement *pipeline, *videosrc, *glupload, *glimagesink;

    GMainLoop *loop;
    GstBus *bus;

    /* initialization */
    gst_init (&argc, &argv);
    loop = g_main_loop_new (NULL, FALSE);

    /* create elements */
    pipeline = gst_pipeline_new ("pipeline");

    /* watch for messages on the pipeline's bus (note that this will only
     * work like this when a GLib main loop is running) */

    bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
    gst_bus_add_watch (bus, bus_call, loop);
    gst_object_unref (bus);

    /* create elements */
    videosrc = gst_element_factory_make ("videotestsrc", "videotestsrc0");
    glupload  = gst_element_factory_make ("glupload", "glupload0");
    glimagesink  = gst_element_factory_make ("glimagesink", "glimagesink0");


    if (!videosrc || !glupload || !glimagesink)
    {
        g_print ("one element could not be found \n");
        return -1;
    }

    /* change video source caps */
    GstCaps *caps = gst_caps_new_simple("video/x-raw-rgb",
                                        "width", G_TYPE_INT, 320,
                                        "height", G_TYPE_INT, 240,
                                        "framerate", GST_TYPE_FRACTION, 25, 1,
                                        NULL) ;


    GstCaps *outcaps = gst_caps_new_simple("video/x-raw-gl",
                                        "width", G_TYPE_INT, 800,
                                        "height", G_TYPE_INT, 600,
                                        NULL) ;

    /* configure elements */
    g_object_set(G_OBJECT(videosrc), "num-buffers", 400, NULL);
    g_object_set(G_OBJECT(glimagesink), "client-reshape-callback", reshapeCallback, NULL);
    g_object_set(G_OBJECT(glimagesink), "client-draw-callback", drawCallback, NULL);
    g_object_set(G_OBJECT(glimagesink), "client-data", NULL, NULL);

    /* add elements */
    gst_bin_add_many (GST_BIN (pipeline), videosrc, glupload, glimagesink, NULL);

    /* link elements */
    gboolean link_ok = gst_element_link_filtered(videosrc, glupload, caps) ;
    gst_caps_unref(caps) ;
    if(!link_ok)
    {
        g_warning("Failed to link videosrc to glupload!\n") ;
        return -1 ;
    }
    link_ok = gst_element_link_filtered(glupload, glimagesink, outcaps) ;
    gst_caps_unref(outcaps) ;
    if(!link_ok)
    {
        g_warning("Failed to link glupload to glimagesink!\n") ;
        return -1 ;
    }


    /* run */
    ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
    if (ret == GST_STATE_CHANGE_FAILURE)
    {
        g_print ("Failed to start up pipeline!\n");

        /* check if there is an error message with details on the bus */
        GstMessage* msg = gst_bus_poll (bus, GST_MESSAGE_ERROR, 0);
        if (msg)
        {
          GError *err = NULL;

          gst_message_parse_error (msg, &err, NULL);
          g_print ("ERROR: %s\n", err->message);
          g_error_free (err);
          gst_message_unref (msg);
        }
        return -1;
    }

    g_main_loop_run (loop);

    /* clean up */
    gst_element_set_state (pipeline, GST_STATE_NULL);
    gst_object_unref (pipeline);

    return 0;

}
 

I do not yet know exacly how I will setup the actual rendering of the quad in SFML, I might try to sub-class the Drawable(?) class or draw the thing in "pure" OpenGL.

The goal is to be able to draw at-least 3 (hopefully more) 1080p movies at the same time. :P

// Zap

Ceylo

  • Hero Member
  • *****
  • Posts: 2325
    • View Profile
    • http://sfemovie.yalir.org/
    • Email
Re: GStreamer SDK and SFML
« Reply #9 on: October 19, 2012, 09:43:49 pm »
Looks really interesting! I had seen GStreamer but I didn't do any deep searches as FFmpeg fitted my needs.

I would really like to read your comments about GStreamer once you've got it to work with SFML.
From what I saw it's indeed much better documented. I do not know what about the ease of use. It does seem to support decoding/playing but not encoding though (which is quite useless for sfeMovie, I agree).
Want to play movies in your SFML application? Check out sfeMovie!

Zapfyr

  • Newbie
  • *
  • Posts: 29
    • View Profile
    • Email
Re: GStreamer SDK and SFML
« Reply #10 on: October 26, 2012, 10:00:12 am »
Hi,

Just reporting on how the project is working out. I have given up on using the OpenGL plugin for GStreamer. However I have successfully drawn a full HD movie to a texture using an other pipeline (a modified playbin2). Using PBOs (2 actually) and preforming a kinda buffer ping-ponging to make use of the DMA (async coping etc. that does not block the CPU) I have managed to get pretty good performance. What remains now is to properly subclass SFMLs Drawable and Transformable so that my "VideoSprite" works similar to SFMLs sprite.

This is my system info (graphics: AMD HD7870 Eyefinity Edition):


When running two 1080p movies at the same time on a windows that is 3840x1080:


// Zap
« Last Edit: October 26, 2012, 11:37:18 am by Zapfyr »

Zapfyr

  • Newbie
  • *
  • Posts: 29
    • View Profile
    • Email
Re: GStreamer SDK and SFML
« Reply #11 on: November 12, 2012, 09:22:44 am »
Hi (again).

Since I last wrote much testing using GStreamer have been done. It seems to be working great .... on Linux ....  on Windows it SEEMS to be not that mature. I have run into trouble when trying to run a looped movie for a long time, it loops for maybe half a day (4 - 12 hours) and then something inside GStreamer breaks and I get a general streaming error. I have tested it both with the GStreamer SDK and OSSBuild and with multiple movies coded in a number of different ways. Now this may of course be my fault, but as I can't find much when googling and can't see anything wrong with my code I will now look for other solutions.

As for GStreamer SDK vs. OSSBuild, in many cases GStreamer SDK gives at lot less choppy playback and seems to get better performance (not that surprising as the SDK uses someting like 0.10.36 and OSSBuild 0.10.28 of GStreamer).

GStreamer SDK using GStreamer 1.0 is about to be release some time this month (Nov. 2012) which may make it more stable for Windows.

As of now I will be looking into sfeMovie instead. :)

// Zap

Ceylo

  • Hero Member
  • *****
  • Posts: 2325
    • View Profile
    • http://sfemovie.yalir.org/
    • Email
Re: GStreamer SDK and SFML
« Reply #12 on: November 13, 2012, 09:35:25 pm »
Did you ask GStreamer's people for your looping issue?
Want to play movies in your SFML application? Check out sfeMovie!

Zapfyr

  • Newbie
  • *
  • Posts: 29
    • View Profile
    • Email
Re: GStreamer SDK and SFML
« Reply #13 on: November 14, 2012, 10:57:53 am »
I tried posting about it on one of their mailing-lists. Haven't got a response from anyone yet tho. As far as I know there are no "normal" forums or similar that I can turn to, which kinda makes it hard to find any good answers to what is happening inside gstreamer. :(

I haven't asked about it on sites like stackoverflow, yet.

// Zap

Ceylo

  • Hero Member
  • *****
  • Posts: 2325
    • View Profile
    • http://sfemovie.yalir.org/
    • Email
Re: GStreamer SDK and SFML
« Reply #14 on: November 14, 2012, 06:03:58 pm »
Your question on the mailing list is just too big. I don't expect anyone to answer. And I don't think you'll get better results on stackoverflow with such a big message. Write a much shorter one if you want answers.

Now if you wish to help at improving sfeMovie, which feature is the most important to you?
- performance: I don't think much can be done except hardware acceleration if available
- seeking: some seeking algorithms can be done rather easily (see here) but the most interesting one requires much more work
- looping: non-smooth looping can also be done easily, but good looping also needs much more work (most probably a complete redesign to do pipelined and buffered decoding)

I would of course also help in case you're interested in this :)
Ceylo
Want to play movies in your SFML application? Check out sfeMovie!

 

anything