Play media file with gstream and sdl2
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