简体   繁体   English

GStreamer 插件 src -> opusdec sink 给出“错误:解码器未初始化”

[英]GStreamer plugin src -> opusdec sink gives "error: decoder not initialized"

I have the following two pipelines to transmit opus encoded audio from server to client:我有以下两个管道将 opus 编码的音频从服务器传输到客户端:

The server:服务器:

gst-launch-1.0 -v alsasrc ! audioconvert ! audioresample ! audio/x-raw, rate=16000, channels=1, format=S16LE ! opusenc ! rtpopuspay ! udpsink host=0.0.0.0 port=4000

The client:客户端:

gst-launch-1.0 udpsrc port=4000 ! application/x-rtp,payload=96,encoding-name=OPUS ! rtpopusdepay ! opusdec ! autoaudiosink

I try to create a custom GstElement based plugin to replace rtpopusdepay in the client side with a hand-crafted one (to be backward compatible with an existing server implementation that doesn't use rtpopuspay but uses a hand-crafted byte-format to wrap the opus encoded data).我尝试创建一个基于GstElement的自定义插件,用手工制作的插件替换客户端中的rtpopusdepay (与不使用rtpopuspay但使用手工制作的字节格式包装的现有服务器实现向后兼容作品编码数据)。

To test the concept I would like to use the pipelines above, but replace the client side with:为了测试这个概念,我想使用上面的管道,但将客户端替换为:

GST_PLUGIN_PATH=. gst-launch-1.0 udpsrc port=4000 ! simpacketdepay ! opusdec ! autoaudiosink

Where simpacketdepay is the plugin I created. simpacketdepay是我创建的插件。 The plugin is quite simple, it has fixed caps (ANY for its sink and "audio/x-opus" for its src).该插件非常简单,它有固定的大写字母(ANY 表示它的 sink,“audio/x-opus”表示它的 src)。 In its chain function I simply remove the payload rtpopuspay adds to the encoded opus stream (first 96 bits) and push the data forward.在其链 function 中,我只需删除rtpopuspay添加到编码作品 stream(前 96 位)的有效负载,然后将数据向前推送。

The full code:完整代码:

#include "gstsimpacketdepay.h"

#include <stdio.h>
#include <string.h>
#include <gst/gst.h>
#include <gst/gstcaps.h>

GST_DEBUG_CATEGORY_STATIC (gst_simpacketdepay_debug);
#define GST_CAT_DEFAULT gst_simpacketdepay_debug

/* Enum to identify properties */
enum
{
    PROP_0
};

static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE(
    "sink",
    GST_PAD_SINK,
    GST_PAD_ALWAYS,
    GST_STATIC_CAPS("ANY")
);

static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE (
    "src",
    GST_PAD_SRC,
    GST_PAD_ALWAYS,
    GST_STATIC_CAPS("audio/x-opus, rate=16000, channels=1, channel-mapping-family=0, stream-count=1, coupled-count=0")
);

/* Define our element type. Standard GObject/GStreamer boilerplate stuff */
#define gst_simpacketdepay_parent_class parent_class
G_DEFINE_TYPE(GstSimpacketdepay, gst_simpacketdepay, GST_TYPE_ELEMENT);

static GstFlowReturn gst_simpacketdepay_chain (GstPad *pad, GstObject *parent, GstBuffer *buf);

static void gst_simpacketdepay_class_init (GstSimpacketdepayClass * klass)
{
    GObjectClass *gobject_class;
    GstElementClass *gstelement_class;

    gstelement_class = (GstElementClass *) klass;

    /* Set sink and src pad capabilities */
    gst_element_class_add_pad_template (gstelement_class, gst_static_pad_template_get(&src_factory));
    gst_element_class_add_pad_template (gstelement_class, gst_static_pad_template_get(&sink_factory));

    /* Set metadata describing the element */
    gst_element_class_set_details_simple (
        gstelement_class,
        "simpacketdepay plugin",
        "simpacketdepay plugin",
        "Sim Packet depay",
        "Test"
    );
}

static void gst_simpacketdepay_init (GstSimpacketdepay * simpacketdepay)
{
    simpacketdepay->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");
    simpacketdepay->srcpad = gst_pad_new_from_static_template (&src_factory, "src");

    gst_pad_use_fixed_caps(simpacketdepay->sinkpad);
    gst_pad_use_fixed_caps(simpacketdepay->srcpad);

    gst_element_add_pad (GST_ELEMENT (simpacketdepay), simpacketdepay->sinkpad);
    gst_element_add_pad (GST_ELEMENT (simpacketdepay), simpacketdepay->srcpad);

    gst_pad_set_chain_function (simpacketdepay->sinkpad, gst_simpacketdepay_chain);
}

static GstFlowReturn gst_simpacketdepay_chain (GstPad *pad, GstObject *parent, GstBuffer *inBuf)
{
    GstSimpacketdepay *filter = GST_SIMPACKETDEPAY(parent);
    GstMapInfo info;
    gst_buffer_map(inBuf, &info, GST_MAP_READ);

    const size_t inSize = info.size;
    printf("Incoming size %lu\n", info.size);
    gst_buffer_unmap(inBuf, &info);

    GstBuffer* outBuf = gst_buffer_copy(inBuf);

    GstMemory* const inMemory = gst_buffer_get_memory(inBuf, 0);
    GstMemory* const outMemory = gst_memory_share(inMemory, 12, inSize - 12);
    gst_buffer_remove_all_memory(outBuf);
    gst_buffer_prepend_memory(outBuf, outMemory);

    gst_buffer_map(outBuf, &info, GST_MAP_READ);

    printf("Outgoing size: %lu\n", info.size);
    fflush(stdout);
    gst_buffer_unmap(outBuf, &info);

    gst_buffer_unref (inBuf);

    GstFlowReturn result = gst_pad_push (filter->srcpad, outBuf);

    return result;
}

static gboolean simpacketdepay_plugin_init (GstPlugin * plugin)
{
    GST_DEBUG_CATEGORY_INIT (gst_simpacketdepay_debug, "simpacketdepay", 0, "simpacketdepay");

    return gst_element_register (plugin, "simpacketdepay", GST_RANK_NONE, GST_TYPE_SIMPACKETDEPAY);
}

#ifndef VERSION
#define VERSION "1.0.0"
#endif
#ifndef PACKAGE
#define PACKAGE "FIXME_package"
#endif
#ifndef PACKAGE_NAME
#define PACKAGE_NAME "FIXME_package_name"
#endif
#ifndef GST_PACKAGE_ORIGIN
#define GST_PACKAGE_ORIGIN "http://FIXME.org/"
#endif

GST_PLUGIN_DEFINE (
    GST_VERSION_MAJOR,
    GST_VERSION_MINOR,
    simpacketdepay,
    "FIXME plugin description",
    simpacketdepay_plugin_init,
    VERSION,
    "LGPL",
    PACKAGE_NAME,
    GST_PACKAGE_ORIGIN
)

The negotiations and everything goes well, until I push the first buffer to the source pad from gst_simpacketdepay_chain with GstFlowReturn result = gst_pad_push (filter->srcpad, outBuf);谈判和一切都很顺利,直到我将第一个缓冲区从gst_simpacketdepay_chain推送到源焊盘GstFlowReturn result = gst_pad_push (filter->srcpad, outBuf);

Then I get the following error (pasted the detailed debug log here )然后我收到以下错误(在此处粘贴详细的调试日志

0:00:00.510871708 42302 0x55fbd0c44000 LOG             audiodecoder gstaudiodecoder.c:2034:gst_audio_decoder_chain:<opusdec0> received buffer of size 160 with ts 0:00:00.006492658, duration 99:99:99.999999999
0:00:00.510877845 42302 0x55fbd0c44000 WARN            audiodecoder gstaudiodecoder.c:2084:gst_audio_decoder_chain:<opusdec0> error: decoder not initialized
0:00:00.510882963 42302 0x55fbd0c44000 DEBUG            GST_MESSAGE gstelement.c:2110:gst_element_message_full_with_details:<opusdec0> start
0:00:00.510896592 42302 0x55fbd0c44000 INFO        GST_ERROR_SYSTEM gstelement.c:2140:gst_element_message_full_with_details:<opusdec0> posting message: GStreamer error: negotiation problem.
0:00:00.510910301 42302 0x55fbd0c44000 LOG              GST_MESSAGE gstmessage.c:303:gst_message_new_custom: source opusdec0: creating new message 0x7f519c002910 error
0:00:00.510919198 42302 0x55fbd0c44000 WARN               structure gststructure.c:1861:priv_gst_structure_append_to_gstring: No value transform to serialize field 'gerror' of type 'GError'
0:00:00.510929043 42302 0x55fbd0c44000 DEBUG                GST_BUS gstbus.c:315:gst_bus_post:<bus1> [msg 0x7f519c002910] posting on bus error message: 0x7f519c002910, time 99:99:99.999999999, seq-num 43, element 'opusdec0', GstMessageError, gerror=(GError)NULL, debug=(string)"gstaudiodecoder.c\(2084\):\ gst_audio_decoder_chain\ \(\):\ /GstPipeline:pipeline0/GstOpusDec:opusdec0:\012decoder\ not\ initialized";
0:00:00.510937098 42302 0x55fbd0c44000 DEBUG                    bin gstbin.c:3718:gst_bin_handle_message_func:<pipeline0> [msg 0x7f519c002910] handling child opusdec0 message of type error
0:00:00.510942210 42302 0x55fbd0c44000 DEBUG                    bin gstbin.c:3727:gst_bin_handle_message_func:<pipeline0> got ERROR message, unlocking state change
0:00:00.510947151 42302 0x55fbd0c44000 DEBUG                    bin gstbin.c:4065:gst_bin_handle_message_func:<pipeline0> posting message upward
0:00:00.510955219 42302 0x55fbd0c44000 WARN               structure gststructure.c:1861:priv_gst_structure_append_to_gstring: No value transform to serialize field 'gerror' of type 'GError'
0:00:00.510962328 42302 0x55fbd0c44000 DEBUG                GST_BUS gstbus.c:315:gst_bus_post:<bus2> [msg 0x7f519c002910] posting on bus error message: 0x7f519c002910, time 99:99:99.999999999, seq-num 43, element 'opusdec0', GstMessageError, gerror=(GError)NULL, debug=(string)"gstaudiodecoder.c\(2084\):\ gst_audio_decoder_chain\ \(\):\ /GstPipeline:pipeline0/GstOpusDec:opusdec0:\012decoder\ not\ initialized";

<opusdec0> error: decoder not initialized ? <opusdec0> error: decoder not initialized Do I need to do something special to initialize the opus decoder?我需要做一些特别的事情来初始化 opus 解码器吗? What step do I miss?我错过了哪一步?

I was able to solve the issue.我能够解决这个问题。 When the plugin element enters playing state we should push a gst_event_new_caps event to the source pad.当插件元素进入播放 state 时,我们应该将gst_event_new_caps事件推送到源垫。 Even with fixed caps... I haven't found anything in the documentation that can explains this requirement.即使使用固定上限...我在文档中也没有找到任何可以解释此要求的内容。

So I added the following state change handler and the pipeline started to work:所以我添加了以下 state 更改处理程序,管道开始工作:

static GstStateChangeReturn gst_simpacketdepay_change_state (GstElement *element, GstStateChange transition)
{
    const GstStateChangeReturn result = GST_ELEMENT_CLASS(parent_class)->change_state (element, transition);
    if (result == GST_STATE_CHANGE_FAILURE) {
        return result;
    }

    switch (transition) {
    case GST_STATE_CHANGE_PAUSED_TO_PLAYING: {
        GstSimpacketdepay *filter = GST_SIMPACKETDEPAY(element);
        gst_pad_push_event(filter->srcpad, gst_event_new_caps(gst_pad_template_get_caps(gst_static_pad_template_get(&src_factory))));
    } break;
    default:
        break;
    }

    return result;
}

I'm sad to see how underdocumented this part of GStreamer is.我很难过看到 GStreamer 的这部分文档记录不足。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM