Play media file with gstream and sdl2

Posted on December 9, 2019

I did not manage to find any tutorial for so I m

This tutorial is based on appsink example from gstreamer documentation:
https://gstreamer.freedesktop.org/documentation/application-development/advanced/pipeline-manipulation.html#appsink-example

first we install gstreamer1.0 and sdl2 if we haven't already

sudo apt-get install libsdl2-dev
sudo apt-get install libgstreamer1.0-0 gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gstreamer1.0-libav gstreamer1.0-doc gstreamer1.0-tools
sudo apt-get install libgstreamer-plugins-base1.0-dev

On a new file gst-player.cpp we start the definitions

#include <gst/gst.h>
#include <SDL2/SDL.h>

#define CAPS "video/x-raw,format=RGB,width=400,pixel-aspect-ratio=1/1"

void SDL_init();
SDL_Window *window;
SDL_Renderer *renderer;
SDL_Texture *texture;
SDL_Event event;
SDL_Rect rect = {0,0,400,300};

we will display on a 400x300 pixel window and get the pixels from gstreamer in RGB format. We add SDL_int() at the end of the file, it will be called from main() to initialize the sld variables.

void SDL_init() {

    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s", SDL_GetError());
        return;
    }

    window = SDL_CreateWindow("SDL_CreateTexture",
        SDL_WINDOWPOS_UNDEFINED,
        SDL_WINDOWPOS_UNDEFINED,
        400, 300,
        SDL_WINDOW_RESIZABLE);

    renderer = SDL_CreateRenderer(window, -1, 0);

    texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGB24, SDL_TEXTUREACCESS_STATIC, 400, 300);
}

In main function we create the pipeline that will end on a appsink. Using a while, every 40 milisecond we'll try to get a snapshot from the sink and display on the sdl window.

int main (int argc, char *argv[])
{
  GstElement *pipeline, *sink;
  gint width, height;
  GstSample *sample;
  gchar *descr;
  GError *error = NULL;
  gint64 duration, position;
  GstStateChangeReturn ret;
  gboolean res;
  GstMapInfo map;

  gst_init (&argc, &argv);
  SDL_init();

  /* we'll use an argument to pass the video file path*/
  if (argc != 2) {
    g_print ("Opens video file\nusage: %s \nExample: %s file:///home/myfile.mp4 \n",
        argv[0],argv[0]);
    exit (-1);
  }

  /* create a new pipeline */
  descr =
      g_strdup_printf ("uridecodebin uri=%s ! videoconvert ! videoscale ! "
      " appsink name=sink caps=\"" CAPS "\"", argv[1]);
  pipeline = gst_parse_launch (descr, &error);

  if (error != NULL) {
    g_print ("could not construct pipeline: %s\n", error->message);
    g_clear_error (&error);
    exit (-1);
  }

  /* get sink */
  sink = gst_bin_get_by_name (GST_BIN (pipeline), "sink");

  /* the video player loop */
  while (1) {
    SDL_PollEvent(&event);

    if(event.type == SDL_QUIT) break; /* exit loop */
    SDL_Delay(40);

    /* get the preroll buffer from appsink */
    gst_element_set_state (pipeline, GST_STATE_PAUSED);
    g_signal_emit_by_name (sink, "pull-preroll", &sample, NULL);
    gst_element_set_state (pipeline, GST_STATE_PLAYING);

    /* if we have a buffer now, convert it to a pixbuf */
    if (sample) {
      GstBuffer *buffer;
      GstCaps *caps;
      GstStructure *s;

      /* get the snapshot buffer format now. We set the caps on the appsink so
       * that it can only be an rgb buffer. The only thing we have not specified
       * on the caps is the height, which is dependant on the pixel-aspect-ratio
       * of the source material */
      caps = gst_sample_get_caps (sample);
      if (!caps) {
        g_print ("could not get snapshot format\n");
        exit (-1);
      }
      s = gst_caps_get_structure (caps, 0);

      /* we need to get the final caps on the buffer to get the size */
      res = gst_structure_get_int (s, "width", &width);
      res |= gst_structure_get_int (s, "height", &height);
      if (!res) {
        g_print ("could not get snapshot dimension\n");
        exit (-1);
      }

      /* get the pixbuf */
      buffer = gst_sample_get_buffer (sample);

      if (gst_buffer_map (buffer, &map, GST_MAP_READ)) {
        /* update the texture with the mapped buffer */
        SDL_UpdateTexture(texture, &rect, map.data, width*3);
        SDL_RenderCopy(renderer, texture, NULL, NULL);
        SDL_RenderPresent(renderer);
        gst_buffer_unmap (buffer, &map);
      }
      gst_sample_unref (sample);
    } else {
      g_print ("could not make snapshot\n");
    } /*end if(sample)*/
  }

  /* cleanup and exit */
  gst_element_set_state (pipeline, GST_STATE_NULL);
  gst_object_unref (pipeline);
  SDL_DestroyRenderer(renderer);
  SDL_Quit();
  exit (0);
}

 

To compile and run

 

g++ gst-player.cpp -o gst-player `pkg-config --cflags --libs gstreamer-1.0` `sdl2-config --cflags --libs` -lSDL2_image -std=c++11


./gst-player file:///home/user/Videos/sample.mp4