GStreamer audiofirfilter使用求助:管道故障及无FFT示例需求
解决GStreamer audiofirfilter单位脉冲响应管道无声音问题
我完全理解你在嵌入式系统上折腾audiofirfilter的烦恼——找不到可用示例,自己写的管道又没声音。先帮你排查代码里的几个关键问题,再给一个不需要FFT的极简可运行示例。
你的代码里的核心问题
Kernel数组的GValueArray初始化错误
你创建了一个长度为1的GValueArray,然后循环追加16个值,这会导致数组长度异常,audiofirfilter无法正确读取内核数据。应该直接初始化对应长度的数组,或者用更便捷的GStreamer辅助函数。Latency计算错误
FIR滤波器的延迟是(内核长度 - 1)/2,你的内核长度是16,所以正确的latency应该是(16-1)/2 = 7,而不是16/2=8,错误的延迟设置可能导致音频被丢弃或不同步。FakeSrc的Handoff回调未生成正确的单位脉冲数据
如果你的SourceHandoffCallback没有填充单位脉冲的音频样本(第一个样本为最大值,其余为0),管道自然输出静音。
修正后的无FFT示例代码
下面是一个简化且可运行的版本,专注于单位脉冲响应的实现:
#include <gst/gst.h> #include <glib.h> typedef struct _CustomData { GstElement *pipeline; GstElement *fakesrc; GstElement *capsfilter; GstElement *audioconvert; GstElement *audiofirfilter; GstElement *alsasink; gboolean pulse_generated; // 标记是否已经发送了单位脉冲 } CustomData; // Handoff回调:生成单位脉冲数据 static void SourceHandoffCallback(GstElement *src, GstBuffer *buffer, GstPad *pad, CustomData *data) { if (data->pulse_generated) { // 已经发送过脉冲,后续填充静音 GstMapInfo map; if (gst_buffer_map(buffer, &map, GST_MAP_WRITE)) { memset(map.data, 0, map.size); gst_buffer_unmap(buffer, &map); } return; } // 生成单位脉冲:第一个样本设为S16LE的最大值,其余为0 GstMapInfo map; if (gst_buffer_map(buffer, &map, GST_MAP_WRITE)) { gint16 *samples = (gint16 *)map.data; // 立体声,所以第一个左声道样本设为32767,右声道也设为32767(或者按需调整) samples[0] = G_MAXINT16; samples[1] = G_MAXINT16; // 其余样本填充0 memset(samples + 2, 0, map.size - sizeof(gint16)*2); gst_buffer_unmap(buffer, &map); data->pulse_generated = TRUE; } } int main(int argc, char *argv[]) { CustomData data = {0}; GstCaps *caps; gdouble filter_kernel[16] = {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; gst_init(&argc, &argv); // 创建元素 data.pipeline = gst_pipeline_new("pipeline"); data.fakesrc = gst_element_factory_make("fakesrc", NULL); data.capsfilter = gst_element_factory_make("capsfilter", NULL); data.audioconvert = gst_element_factory_make("audioconvert", NULL); data.audiofirfilter = gst_element_factory_make("audiofirfilter", NULL); data.alsasink = gst_element_factory_make("alsasink", NULL); if (!data.pipeline || !data.fakesrc || !data.capsfilter || !data.audioconvert || !data.audiofirfilter || !data.alsasink) { g_printerr("Failed to create elements!\n"); return -1; } // 添加元素到管道并链接 gst_bin_add_many(GST_BIN(data.pipeline), data.fakesrc, data.capsfilter, data.audioconvert, data.audiofirfilter, data.alsasink, NULL); if (!gst_element_link_many(data.fakesrc, data.capsfilter, data.audioconvert, data.audiofirfilter, data.alsasink, NULL)) { g_printerr("Failed to link elements!\n"); return -1; } // 设置Caps:立体声S16LE,44.1kHz(可根据你的SAMPLING_FREQUENCY调整) caps = gst_caps_new_simple("audio/x-raw", "format", G_TYPE_STRING, "S16LE", "rate", G_TYPE_INT, 44100, "channels", G_TYPE_INT, 2, "layout", G_TYPE_STRING, "interleaved", NULL); g_object_set(G_OBJECT(data.capsfilter), "caps", caps, NULL); gst_caps_unref(caps); // 设置FakeSrc:开启handoff回调,同步,设置合适的缓冲区大小 g_object_set(G_OBJECT(data.fakesrc), "sync", TRUE, "signal-handoffs", TRUE, "sizemax", 4096, "sizetype", 2, NULL); g_signal_connect(data.fakesrc, "handoff", G_CALLBACK(SourceHandoffCallback), &data); // 设置audiofirfilter的Kernel:用更便捷的辅助函数 GValueArray *kernel_array = gst_value_array_from_double_array(filter_kernel, 16); g_object_set(G_OBJECT(data.audiofirfilter), "kernel", kernel_array, NULL); g_value_array_free(kernel_array); // 设置正确的Latency gint kernel_length = 16; g_object_set(G_OBJECT(data.audiofirfilter), "latency", (gint64)((kernel_length - 1)/2), NULL); // 启动管道 gst_element_set_state(data.pipeline, GST_STATE_PLAYING); // 等待用户输入退出 g_print("Press enter to stop...\n"); gchar *line = g_get_line(stdin); g_free(line); // 清理资源 gst_element_set_state(data.pipeline, GST_STATE_NULL); gst_object_unref(data.pipeline); return 0; }
关键说明
- Kernel设置:用
gst_value_array_from_double_array直接从double数组生成GValueArray,避免手动初始化的错误。 - Latency修正:按照
(内核长度-1)/2计算,确保音频同步。 - 单位脉冲生成:在handoff回调中,只在第一次缓冲区填充脉冲信号,后续填充静音,这样你能清晰听到脉冲的输出。
- 嵌入式适配:这个示例没有依赖FFT相关库,完全基于GStreamer基础组件,适合嵌入式系统编译运行。
编译时记得链接GStreamer库,比如:
gcc your_code.c -o audiofir_test `pkg-config --cflags --libs gstreamer-1.0 gstreamer-audio-1.0`
内容的提问来源于stack exchange,提问作者NoobNoob
相关产品推荐
相关产品推荐

