Skip to content

Instantly share code, notes, and snippets.

@jwinarske
Last active March 5, 2024 04:43
Show Gist options
  • Save jwinarske/dda0f7154a0bf34c3e7b6606907ad0f7 to your computer and use it in GitHub Desktop.
Save jwinarske/dda0f7154a0bf34c3e7b6606907ad0f7 to your computer and use it in GitHub Desktop.
gstreamer appsink vulkan sample
#include <gst/gst.h>
#include <gst/vulkan/vulkan.h>
#include <cstdlib>
int main(int argc, char* argv[]) {
GstElement *pipeline, *sink;
gint width, height;
GstSample* sample;
gchar* descr;
GError* error = nullptr;
gint64 duration, position;
GstStateChangeReturn ret;
gboolean res;
GstMapInfo map;
gst_init(&argc, &argv);
if (argc != 2) {
g_print("usage: %s <uri>\n Writes snapshot.png in the current directory\n ",
argv[0]);
exit(-1);
}
// create a new pipeline
descr = g_strdup_printf(
"videotestsrc ! warptv ! videoconvert ! vulkanupload ! "
"vulkancolorconvert ! appsink name=sink");
pipeline = gst_parse_launch(descr, &error);
if (error != nullptr) {
g_print("could not construct pipeline: %s\n", error->message);
g_error_free(error);
exit(-1);
}
// get sink
sink = gst_bin_get_by_name(GST_BIN(pipeline), "sink");
// set to PAUSED to make the first frame arrive in the sink
ret = gst_element_set_state(pipeline, GST_STATE_PAUSED);
switch (ret) {
case GST_STATE_CHANGE_FAILURE:
g_print("failed to play the file\n");
exit(-1);
case GST_STATE_CHANGE_NO_PREROLL:
// for live sources, we need to set the pipeline to PLAYING before we can
// receive a buffer. We don’t do that yet
g_print("live sources not supported yet\n");
exit(-1);
default:
break;
}
// This can block for up to 5 seconds. If your machine is really overloaded,
// it might time out before the pipeline pre-rolled, and we generate an error.
// A better way is to run a mainloop and catch errors there.
ret = gst_element_get_state(pipeline, nullptr, nullptr, 5 * GST_SECOND);
if (ret == GST_STATE_CHANGE_FAILURE) {
g_print("failed to play the file\n");
exit(-1);
}
// get the duration
gst_element_query_duration(pipeline, GST_FORMAT_TIME, &duration);
if (duration != -1)
// we have a duration, seek to 5 %
position = duration * 5 / 100;
else
// no duration, seek to 1 second, this could EOS
position = 1 * GST_SECOND;
// seek to the a position in the file. Most files have a black firs t frame so
// by seeking to somewhere else we have a bigger chance of getting something
// more interesting.An optimisation would be to detect black images and then*
// seek a little more
GstVulkanDevice* device;
if (gst_vulkan_device_run_context_query(sink, &device)) {
guint major, minor, patch;
gst_vulkan_instance_get_version(device->instance, &major, &minor, &patch);
g_print("version: %d.%d.%d\n", major, minor, patch);
g_print("n_physical_devices: %d\n", device->instance->n_physical_devices);
g_print("device: %p\n", device->device);
// g_print("parent: %p\n", device->parent);
g_print("physical_device: %p\n", device->physical_device);
}
gst_element_seek_simple(
pipeline, GST_FORMAT_TIME,
(GstSeekFlags)(GST_SEEK_FLAG_KEY_UNIT | GST_SEEK_FLAG_FLUSH), position);
// get the pre-roll buffer from appsink, this block untils appsink really
// pre-rolls
g_signal_emit_by_name(sink, "pull-preroll", &sample, nullptr);
// if we have a buffer now, convert it to a pixbuf. It’s possible that we
// don’t have a buffer because we went EOS right away or had an error.
if (sample) {
// get the snapshot buffer format now. We set the caps on the appsink so
// that it can only be a rgb buffer. The only thing we have not specified on
// the caps is the height, which is dependent on the pixel - aspect - ratio
// of the source material
GstCaps* caps = gst_sample_get_caps(sample);
if (!caps) {
g_print("could not get sample capabilities\n");
exit(-1);
}
guint count = gst_caps_get_size(caps);
for (int index = 0; index < count; index++) {
GstCapsFeatures* features = gst_caps_get_features(caps, index);
g_print("cap feature: %s\n", gst_caps_features_to_string(features));
}
GstStructure* s = gst_caps_get_structure(caps, 0);
g_print("structure: %s\n", gst_structure_to_string(s));
// 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);
}
GstBuffer* buffer = gst_sample_get_buffer(sample);
GstMemory* mem = gst_buffer_peek_memory(buffer, 0);
if (gst_is_vulkan_image_memory(mem)) {
auto vulkan_image_memory =
static_cast<GstVulkanImageMemory*>((GstVulkanImageMemory*)mem);
g_print("width=%d\n",
gst_vulkan_image_memory_get_width(vulkan_image_memory));
g_print("height=%d\n",
gst_vulkan_image_memory_get_height(vulkan_image_memory));
g_print("width: %d\n", vulkan_image_memory->create_info.extent.width);
g_print("height: %d\n", vulkan_image_memory->create_info.extent.height);
g_print("depth: %d\n", vulkan_image_memory->create_info.extent.depth);
g_print("flags: %d\n", vulkan_image_memory->create_info.flags);
g_print("imageType: %d\n", vulkan_image_memory->create_info.imageType);
g_print("format: %d\n", vulkan_image_memory->create_info.format);
g_print("mipLevels: %d\n", vulkan_image_memory->create_info.mipLevels);
g_print("arrayLayers: %d\n",
vulkan_image_memory->create_info.arrayLayers);
g_print("samples: %d\n", vulkan_image_memory->create_info.samples);
g_print("tiling: %d\n", vulkan_image_memory->create_info.tiling);
g_print("usage: %d\n", vulkan_image_memory->create_info.usage);
g_print("sharingMode: %d\n",
vulkan_image_memory->create_info.sharingMode);
g_print("queueFamilyIndexCount: %d\n",
vulkan_image_memory->create_info.queueFamilyIndexCount);
g_print("initialLayout: %d\n",
vulkan_image_memory->create_info.initialLayout);
}
}
// cleanup and exit
gst_element_set_state(pipeline, GST_STATE_NULL);
gst_object_unref(pipeline);
exit(0);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment