Skip to content

Instantly share code, notes, and snippets.

@msilvestre
Created May 15, 2023 15:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save msilvestre/a0232d2552d0173b3495626163d8444f to your computer and use it in GitHub Desktop.
Save msilvestre/a0232d2552d0173b3495626163d8444f to your computer and use it in GitHub Desktop.
gstreamer with SDL
#include <gst/gst.h>
#include <thread>
#include <iostream>
#include <gst/app/gstappsink.h>
#include <SDL.h>
// SDL window dimensions
#define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 480
bool quit = false;
#define VERIFY_GST_NULL(ELEMENT) if (!ELEMENT) {std::cout << ">>>>>>>" << #ELEMENT " is null!" << std::endl; return 0;}
int main(int argc, char *argv[]) {
// Initialize GStreamer
gst_init(0, NULL);
// Create the pipeline
GstElement *pipeline = gst_pipeline_new("video-player");
GstElement* videoSrc = gst_element_factory_make("videotestsrc", "video_src");
GstElement *videoConvert = gst_element_factory_make("videoconvert", "video_decoder");
GstAppSink *sink = GST_APP_SINK(gst_element_factory_make("appsink", "sink"));
VERIFY_GST_NULL(pipeline)
VERIFY_GST_NULL(videoConvert)
VERIFY_GST_NULL(sink)
auto videoConvert_src_pad = gst_element_get_static_pad(videoConvert, "src");
auto videoConvert_src_caps = gst_caps_new_simple("video/x-raw",
"format", G_TYPE_STRING, "BGRA",
"width", G_TYPE_INT, SCREEN_WIDTH,
"height", G_TYPE_INT, SCREEN_HEIGHT,
NULL);
gst_pad_set_caps(videoConvert_src_pad, videoConvert_src_caps);
// Set the sink element to push data to the app
gst_app_sink_set_emit_signals(sink, true);
gst_app_sink_set_drop(sink, true);
gst_app_sink_set_max_buffers(sink, 1);
gst_app_sink_set_caps(sink, gst_caps_new_simple("video/x-raw",
"format", G_TYPE_STRING, "BGRA",
"width", G_TYPE_INT, SCREEN_WIDTH,
"height", G_TYPE_INT, SCREEN_HEIGHT,
NULL));
gst_bin_add_many(GST_BIN (pipeline),
videoSrc,
videoConvert,
sink,
NULL);
gst_element_link_many(videoSrc, videoConvert, sink, NULL);
// Start the pipeline
gst_element_set_state(pipeline, GST_STATE_PLAYING);
// Create the SDL window
SDL_Init(SDL_INIT_VIDEO);
SDL_Window *window = SDL_CreateWindow("GStreamer + SDL", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
// Create the SDL renderer
auto renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
// Create the SDL surface
auto surface = SDL_CreateRGBSurface(0, SCREEN_WIDTH, SCREEN_HEIGHT, 32, 0, 0, 0, 0);
SDL_Event e;
while (!quit) {
// Get the buffer from the appsink
GstSample *sample = gst_app_sink_pull_sample(sink);
if (!sample)
{
std::cout << ">>>>> No Sample from appsink!\n";
std::this_thread::sleep_for(std::chrono::milliseconds(100));
continue;
}
GstBuffer *buffer = gst_sample_get_buffer(sample);
// Get the buffer data
GstMapInfo info;
gst_buffer_map(buffer, &info, GST_MAP_READ);
SDL_LockSurface(surface);
memcpy(surface->pixels, info.data, surface->pitch * surface->h);
SDL_UnlockSurface(surface);
// Unmap the buffer
gst_buffer_unmap(buffer, &info);
// Release the sample
gst_sample_unref(sample);
auto texture = SDL_CreateTextureFromSurface(renderer, surface);
SDL_RenderCopy(renderer, texture, NULL, NULL);
SDL_DestroyTexture(texture);
SDL_RenderPresent(renderer);
while (SDL_PollEvent(&e)) {
if (e.type == SDL_QUIT) {
quit = 1;
break;
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
// Stop the pipeline
gst_element_set_state(pipeline, GST_STATE_NULL);
// Release the GStreamer elements
//gst_object_unref(sink);
//gst_object_unref(videoConvert);
//gst_object_unref(videoSrc);
//gst_object_unref(pipeline);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment