Gstreamer自定义插件中GstBuffer Pool实现及多帧传递问题咨询
Hey there! Let's work through your GStreamer questions step by step—since you're new to the ecosystem, I'll break down concepts and share practical code examples to clear things up.
First, a quick correction about GstBufferPool
You’re a bit off on how buffer pools work: they’re not meant to be a "storage container" for pre-filled frames. Instead, they’re a mechanism to efficiently allocate and reuse empty buffer memory to avoid repeated memory allocation overhead. Upstream elements don’t "add" frames to the pool—they acquire empty buffers from the pool, fill them with data, then push them to downstream elements.
Question 1: How does an upstream element use a GstBufferPool to pass frames downstream?
Here’s the correct workflow for your ROI element, plus fixed code to implement it:
- Initialize the pool in your ROI element (manage it as part of the element’s state, not a global shared variable—downstream elements never pull directly from upstream pools):
- Acquire empty buffers from the pool when you need to generate new ROI frames.
- Fill the buffer with your cropped ROI data.
- Push the filled buffer to the downstream element via your ROI’s src pad.
Fixed ROI Element Code (Buffer Pool Implementation)
// Add the pool to your ROI element's struct typedef struct _GstROI { GstVideoFilter parent; GstBufferPool *pool; // Add your ROI parameters (x, y, width, height) here } GstROI; // Initialize the buffer pool during element setup static void gst_ROI_init(GstROI *ROI) { ROI->pool = gst_buffer_pool_new(); GstBufferPoolConfig *config = gst_buffer_pool_get_config(ROI->pool); // Use precise caps matching your video format (not just "video/x-raw") GstCaps *caps = gst_caps_from_string("video/x-raw,format=RGB,width=420,height=420"); guint buffer_size = 420 * 420 * 3; // RGB24 pixel size guint min_buffers = 2; guint max_buffers = 10; gst_buffer_pool_config_set_params(config, caps, buffer_size, min_buffers, max_buffers); gst_caps_unref(caps); if (!gst_buffer_pool_set_config(ROI->pool, config)) { g_printerr("[ERROR] Failed to set buffer pool config\n"); gst_buffer_pool_unref(ROI->pool); ROI->pool = NULL; return; } if (!gst_buffer_pool_set_active(ROI->pool, TRUE)) { g_printerr("[ERROR] Failed to activate buffer pool\n"); gst_buffer_pool_unref(ROI->pool); ROI->pool = NULL; return; } g_print("[INFO] Buffer pool initialized successfully\n"); } // Clean up the pool when the element is destroyed static void gst_ROI_finalize(GObject *object) { GstROI *ROI = GST_ROI(object); if (ROI->pool) { gst_buffer_pool_set_active(ROI->pool, FALSE); gst_buffer_pool_unref(ROI->pool); } G_OBJECT_CLASS(parent_class)->finalize(object); } // Core frame processing function to generate multiple ROI frames static GstFlowReturn gst_ROI_transform_frame_ip(GstVideoFilter *filter, GstVideoFrame *frame) { GstROI *ROI = GST_ROI(filter); if (!ROI->pool) { g_printerr("[ERROR] Buffer pool not available\n"); return GST_FLOW_ERROR; } // Define your ROI region (adjust these values as needed) guint roi_x = 100; guint roi_y = 100; guint roi_w = 200; guint roi_h = 200; // Generate 3 example ROI frames for (int i = 0; i < 3; i++) { GstBuffer *buf; GstFlowReturn ret = gst_buffer_pool_acquire_buffer(ROI->pool, &buf, NULL); if (ret != GST_FLOW_OK) { g_printerr("[ERROR] Failed to acquire buffer for ROI frame %d\n", i); continue; } // Map frames to access memory GstMapInfo src_map, dst_map; if (!gst_video_frame_map(frame, &src_map, GST_MAP_READ) || !gst_buffer_map(buf, &dst_map, GST_MAP_WRITE)) { g_printerr("[ERROR] Failed to map buffers\n"); gst_buffer_unref(buf); gst_video_frame_unmap(frame, &src_map); return GST_FLOW_ERROR; } // Copy ROI data from source frame to new buffer guint src_stride = GST_VIDEO_FRAME_PLANE_STRIDE(frame, 0); guint dst_stride = roi_w * 3; // RGB24 per-pixel size for (guint y = 0; y < roi_h; y++) { memcpy(dst_map.data + y * dst_stride, src_map.data + (roi_y + y) * src_stride + roi_x * 3, roi_w * 3); } // Unmap buffers gst_buffer_unmap(buf, &dst_map); gst_video_frame_unmap(frame, &src_map); // Set timestamp for synchronization (critical for downstream sinks) GST_BUFFER_PTS(buf) = GST_BUFFER_PTS(frame->buffer) + i * GST_MSECOND * 33; // Simulate 30fps // Push the ROI frame to downstream element B GstPad *src_pad = gst_element_get_static_pad(GST_ELEMENT(ROI), "src"); ret = gst_pad_push(src_pad, buf); gst_object_unref(src_pad); if (ret != GST_FLOW_OK) { g_printerr("[ERROR] Failed to push ROI frame %d\n", i); } } // Optionally pass through the original frame (remove if not needed) return GST_FLOW_OK; }
Question 2: Is there a simpler alternative to GstBufferPool?
Absolutely! For small-scale multi-frame generation, you can skip buffer pools entirely and create independent GstBuffer instances directly. This is more intuitive for beginners and avoids pool configuration overhead.
Simplified ROI Element Code (No Buffer Pool)
static GstFlowReturn gst_ROI_transform_frame_ip(GstVideoFilter *filter, GstVideoFrame *frame) { // Define your ROI region guint roi_x = 100; guint roi_y = 100; guint roi_w = 200; guint roi_h = 200; guint roi_size = roi_w * roi_h * 3; // RGB24 size // Generate 2 example ROI frames for (int i = 0; i < 2; i++) { // Allocate memory for ROI data and wrap it in a GstBuffer guint8 *roi_data = g_malloc(roi_size); GstBuffer *buf = gst_buffer_new_wrapped_full( GST_MEMORY_FLAG_READWRITE, roi_data, roi_size, 0, roi_size, g_free, roi_data ); // Copy ROI data from source frame GstMapInfo src_map; if (!gst_video_frame_map(frame, &src_map, GST_MAP_READ)) { g_printerr("[ERROR] Failed to map source frame\n"); gst_buffer_unref(buf); return GST_FLOW_ERROR; } guint src_stride = GST_VIDEO_FRAME_PLANE_STRIDE(frame, 0); for (guint y = 0; y < roi_h; y++) { memcpy(roi_data + y * roi_w * 3, src_map.data + (roi_y + y) * src_stride + roi_x * 3, roi_w * 3); } gst_video_frame_unmap(frame, &src_map); // Set timestamp GST_BUFFER_PTS(buf) = GST_BUFFER_PTS(frame->buffer) + i * GST_MSECOND * 50; // Push to downstream GstPad *src_pad = gst_element_get_static_pad(GST_ELEMENT(filter), "src"); GstFlowReturn ret = gst_pad_push(src_pad, buf); gst_object_unref(src_pad); if (ret != GST_FLOW_OK) { g_printerr("[ERROR] Failed to push frame %d\n", i); } } // Pass through original frame return GST_FLOW_OK; }
Extra Tips for Your Pipeline
- If you need full control over frame generation, consider using the
chainfunction instead oftransform_frame_ip—it lets you completely replace the input frame processing logic. - Always manage GStreamer object references (e.g.,
gst_buffer_unref,gst_object_unref) to avoid memory leaks. - Timestamping is critical for downstream elements like sinks—make sure to set
GST_BUFFER_PTS/GST_BUFFER_DTSto ensure proper synchronization.
内容的提问来源于stack exchange,提问作者Preeti Gill

