【问题标题】:How to play a PCM data array with GStreamer如何使用 GStreamer 播放 PCM 数据数组
【发布时间】:2019-05-26 01:58:43
【问题描述】:

我是gstreamer 的新手,我可以简单地使用gst-launch 来播放这样的PCM 文件:

$ gst-launch-1.0 filesrc location=output.pcm ! audio/x-raw, format=S16LE, 
channels=1, rate=16000 ! autoaudiosink

但在我的应用程序中,我得到的是一个带有 PCM 原始数据的 char 数组。 google了一下,知道应该用appsrc作为源码,但是测试代码根本没有输出。

有没有示例代码可以告诉我如何播放这个包含一个通道 16K PCM 原始数据的字符数组?

这里附上我的测试代码:

std::ifstream file("output.pcm");
char data[22120];
file.read(data, 22120);
file.close();

std::cout << "read success";

GstElement *m_pipeline;
GstElement *m_source;
GMainLoop *m_loop;
GstBuffer *m_last_buffer;
GstElement *m_sink;
GstCaps *audioCaps;

gst_init(NULL, NULL);

audioCaps = gst_caps_new_simple("audio/x-raw", "format", G_TYPE_STRING, "S16LE", "rate", G_TYPE_INT, 16000,
                                "channels", G_TYPE_INT, 1, nullptr);

if (audioCaps == nullptr)
{
    std::cout << "error" << std::endl;
    return 0;
}

m_source = gst_element_factory_make("appsrc", "source");
m_sink = gst_element_factory_make("autoaudiosink", "sink");
m_pipeline = gst_pipeline_new("audio-pipeline");
m_loop = g_main_loop_new(NULL, FALSE);

gst_bin_add_many(GST_BIN(m_pipeline), m_source, m_sink, NULL);
gst_element_link_many(m_source, m_sink, NULL);

gst_app_src_set_caps(GST_APP_SRC(m_source), audioCaps);

gst_caps_unref(audioCaps);

GstBuffer *buffer = gst_buffer_new_allocate(NULL, 22120, NULL);
gst_buffer_fill(buffer, 0, data, 22120);
gst_app_src_push_buffer(GST_APP_SRC(m_source), buffer);

gst_element_set_state(m_pipeline, GST_STATE_PLAYING);

g_main_loop_run(m_loop);

/* free resources */
gst_element_set_state(m_pipeline, GST_STATE_NULL);
gst_object_unref(m_pipeline);

【问题讨论】:

    标签: c++ gstreamer


    【解决方案1】:

    步骤 1. 创建我自己的输入测试文件:

    gst-launch-1.0 audiotestsrc num-buffers=10 ! audio/x-raw, channels=1, rate=16000, format=S16LE ! filesink location=out.raw
    

    第 2 步。这是一个示例应用程序:

    #include <gst/gst.h>
    #include <gst/app/gstappsrc.h>
    #include <stdio.h>
    
    int main()
    {
        gst_init(NULL, NULL);
    
        GstElement* p = gst_parse_launch("appsrc name=src ! audio/x-raw, channels=1, rate=16000, format=S16LE ! autoaudiosink", NULL);
        GstElement* appsrc = gst_bin_get_by_name(GST_BIN(p), "src");
        GstBus* bus = gst_pipeline_get_bus(GST_PIPELINE(p));
    
        gst_element_set_state(p, GST_STATE_PLAYING);
    
        FILE* fp = fopen("out.raw", "rb");
    
        for (int i  = 0; i < 10; i++) {
                gchar buf[2048];
    
                fread(buf, 2048, 1, fp);
    
                GstBuffer *buffer = gst_buffer_new_allocate(NULL, 2048, NULL);
                gst_buffer_fill(buffer, 0, buf, 2048);
                gst_app_src_push_buffer(GST_APP_SRC(appsrc), buffer);
        }
        gst_app_src_end_of_stream(GST_APP_SRC(appsrc));
    
        gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE, GST_MESSAGE_EOS);
    
        gst_element_set_state(p, GST_STATE_NULL);
    
        gst_object_unref(bus);
        gst_object_unref(appsrc);
        gst_object_unref(p);
    
        fclose(fp);
    }
    

    它通过使用gst_parse_launch() 简化了一些事情。完整的管道创建和上限设置。

    为了更简单,创建的示例文件为 2048 字节 * 10 块。您不需要知道原始块大小(只要它是样本对齐的 - 1 个通道和 16 位为 2 个字节)。我只是不想检查文件的 EOF。

    基本上,我认为您应该在发送任何数据之前将管道置于 PLAYING 状态。

    【讨论】:

    • 非常感谢!您提供的代码对于像我这样的初学者来说确实是一个很好的例子!现在我可以根据你的代码成功播放 pcm 数据库了:)
    猜你喜欢
    • 2015-05-27
    • 2015-12-10
    • 2012-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-29
    • 2011-08-18
    • 1970-01-01
    相关资源
    最近更新 更多