Last active
March 5, 2024 04:43
-
-
Save jwinarske/dda0f7154a0bf34c3e7b6606907ad0f7 to your computer and use it in GitHub Desktop.
gstreamer appsink vulkan sample
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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