Gstreamermm从BaseTransform构建插件并修改buffer的记录

Gstreamer作为一个音视频开发的开源框架,应用得非常广泛。Gstreamermm是gstreamer的c++封装,结合glibmm和libsigc++等库,大大简化了gstreamer的开发。但奇怪网上关于gstreamermm的文章和教程凤毛菱角,要想深入掌握使用该库,只有以我有限的水平阅读源码,磕磕碰碰,总算有一点心得。现记录一下在该框架下实现一个gstreamer的filter插件,并添加属性的过程

从BaseTransform类构建插件

直接上代码

#include<iostream>
#include <gstreamermm.h>
#include <gstreamermm/private/basetransform_p.h>
#include<glibmm/main.h>
#include <vector>
#include<opencv2/opencv.hpp>

using namespace Gst;
using namespace std;

class DerivedFromBaseTransform : public Gst::BaseTransform
{
public:
  static void class_init(Gst::ElementClass<DerivedFromBaseTransform> *klass) {
    klass->set_metadata("derivedfrombasetransform_longname",
          "derivedfrombasetransform_classification", 			   "derivedfrombasetransform_detail_description", 
"derivedfrombasetransform_detail_author");

    klass->add_pad_template(Gst::PadTemplate::create("sink", Gst::PAD_SINK, Gst::PAD_ALWAYS,
                    Gst::Caps::create_from_string("video/x-raw, format=BGRA")));
    klass->add_pad_template(Gst::PadTemplate::create("src", Gst::PAD_SRC, Gst::PAD_ALWAYS,
                    Gst::Caps::create_from_string("video/x-raw, format=BGRA")));
    } 

    Glib::RefPtr<Gst::Pad> source;
    Glib::RefPtr<Gst::Buffer> wbuf;

  explicit DerivedFromBaseTransform(GstBaseTransform *gobj)
  : Glib::ObjectBase(typeid (DerivedFromBaseTransform)), // type must be registered before use
    Gst::BaseTransform(gobj) {
    set_passthrough(true);
        //set_in_place(true);
        //source = get_static_pad("src");
  }
    Gst::FlowReturn transform_ip_vfunc(const Glib::RefPtr<Gst::Buffer> &buf) override {
        //cout << "Hello buffer" << endl;
        Gst::MapInfo mapinfo;
        buf->map(mapinfo, Gst::MAP_READ);        
        //wbuf = buf->create_writable();
        //wbuf->map(mapinfo, Gst::MAP_WRITE);
        //cout << mapinfo.get_size() / 320 / 240 << endl;
        cv::Mat mat{240, 320, CV_8UC4, mapinfo.get_data()};
        cv::circle(mat, {100, 100}, 30, {0,0,255,255}, 3);
        buf->unmap(mapinfo);        
        //source->push(move(wbuf));
        return Gst::FLOW_OK;
    }
  static bool register_element(Glib::RefPtr<Gst::Plugin> plugin) {
    return Gst::ElementFactory::register_element(plugin, "myfilter",
                10, Gst::register_mm_type<DerivedFromBaseTransform>("myfilter"));
  }
};

main函数

int main() {
    Gst::init();
  bool plugin_registered = Plugin::register_static(GST_VERSION_MAJOR, GST_VERSION_MINOR, 
            "derivedfrombasetransform", "exemplary element C++-derived from Gst::BaseTransform",
            sigc::ptr_fun(&DerivedFromBaseTransform::register_element), "0.123", "LGPL",
            "source?", "package?", "http://example.com");

  auto element = Gst::ElementFactory::create_element("myfilter");
    auto loop = Glib::MainLoop::create();
    auto pipe = Gst::Pipeline::create();
    auto queue1 = Gst::ElementFactory::create_element("queue2");
    auto queue2 = Gst::ElementFactory::create_element("queue2");
    auto src = Gst::ElementFactory::create_element("videotestsrc");
    auto out = Gst::ElementFactory::create_element("autovideosink");
    auto conv = Gst::ElementFactory::create_element("videoconvert");
    auto conv2 = Gst::ElementFactory::create_element("videoconvert");
    pipe->add(src)->add(element)->add(conv)->add(out)->add(conv2)->add(queue1)->add(queue2);
    src->link(conv)->link(queue1)->link(element)->link(queue2)->link(conv2)->link(out);

    pipe->set_state(Gst::STATE_PLAYING);
    loop->run();
    pipe->set_state(Gst::STATE_NULL);
    }

添加属性

如果要为插件添加属性,并接受set_property对属性进行修改,可以在插件中采取下面的方法

#include<iostream>
#include <gstreamermm.h>
#include <gstreamermm/private/basetransform_p.h>
#include<glibmm/main.h>
#include <vector>
#include<opencv2/opencv.hpp>

using namespace Gst;
using namespace std;

// 默认颜色是黑色
#define DEFAULT_COLOR cv::Scalar{0,0,0,255}

class DerivedFromBaseTransform : public Gst::BaseTransform
{
	Glib::Property<Glib::ustring> color;		//这里定义一个color属性,字符串类型,格式为#RRGGBB
private:
  cv::Scalar m_color{DEFAULT_COLOR};			//这里定义将color属性转化成cv::Scalar颜色值的私有变量
	
  // 定义一个私有函数,将颜色属性的#RRGGBB格式的字符串转化为cv::Scalar,保存在m_color中
  void convertColor() {
    Glib::ustring colorCode = color.get_value();
    g_print("You want to change the color to %s. String size: %d\n", colorCode.c_str(), colorCode.size());
    if (colorCode.size() != 7 || colorCode[0] != '#'){
      g_printerr("Error format of color property: %s\n. It must be in #RRBBGG format", colorCode.c_str());
      m_color = DEFAULT_COLOR;
      return;
    }
    // Parse each component of the color code
    std::string redCode = colorCode.substr(1, 2);
    std::string greenCode = colorCode.substr(3, 2);
    std::string blueCode = colorCode.substr(5, 2);

    // Convert the color code components from hex to decimal
    int red, green, blue;
    try{
      red = stoi(redCode, nullptr, 16);
      green = stoi(greenCode, nullptr, 16);
      blue = stoi(blueCode, nullptr, 16);
      m_color = cv::Scalar(blue, green, red, 255);
    }catch(std::invalid_argument const& e){
      g_printerr("Failed to convert the string to number. Use the default #000000 instead\n");
      m_color = DEFAULT_COLOR;
    }
}

public:
  static void class_init(Gst::ElementClass<DerivedFromBaseTransform> *klass) {
    klass->set_metadata("derivedfrombasetransform_longname",
          "derivedfrombasetransform_classification", 			   "derivedfrombasetransform_detail_description", 
"derivedfrombasetransform_detail_author");

    klass->add_pad_template(Gst::PadTemplate::create("sink", Gst::PAD_SINK, Gst::PAD_ALWAYS,
                    Gst::Caps::create_from_string("video/x-raw, format=BGRA")));
    klass->add_pad_template(Gst::PadTemplate::create("src", Gst::PAD_SRC, Gst::PAD_ALWAYS,
                    Gst::Caps::create_from_string("video/x-raw, format=BGRA")));
    } 

    Glib::RefPtr<Gst::Pad> source;
    Glib::RefPtr<Gst::Buffer> wbuf;

  explicit DerivedFromBaseTransform(GstBaseTransform *gobj)
  : Glib::ObjectBase(typeid (DerivedFromBaseTransform)), // type must be registered before use
    Gst::BaseTransform(gobj) ,
	color(*this, "color", "#00FF00")				// 在构造函数中初始化该属性的值为绿色
	{
    set_passthrough(true);
        //set_in_place(true);
        //source = get_static_pad("src");
	convertColor();			// 将缺省color属性转化为cv::Scalar

	// 关键是下面这行,将修改属性的的信号signal_changed链接到本类的convertColor函数,实现set_property的响应
	// 试了好久才试出来是这样的方式连接。但有个小问题,就是运行过程中会出现
	// GStreamer-CRITICAL **: 18:15:19.763: The created element should be floating, this is probably caused by faulty bindings
	// 告警,并且关闭显示窗口后,管道不能自己终结,非要按CTRL-C才能终止程序运行,暂时不知道怎么解决
    color.get_proxy().signal_changed().connect(sigc::mem_fun(*this, &DerivedFromBaseTransform::convertColor));
  }
    Gst::FlowReturn transform_ip_vfunc(const Glib::RefPtr<Gst::Buffer> &buf) override {
        //cout << "Hello buffer" << endl;
        Gst::MapInfo mapinfo;
        buf->map(mapinfo, Gst::MAP_READ);        
        //wbuf = buf->create_writable();
        //wbuf->map(mapinfo, Gst::MAP_WRITE);
        //cout << mapinfo.get_size() / 320 / 240 << endl;
	
		// 使用属性中的颜色画圆
		cv::Mat mat{240, 320, CV_8UC4, mapinfo.get_data()};
	    cv::circle(mat, {100, 100}, 30, m_color, 3);
    
	    buf->unmap(mapinfo);        
        //source->push(move(wbuf));
        return Gst::FLOW_OK;
    }

  static bool register_element(Glib::RefPtr<Gst::Plugin> plugin) {
    return Gst::ElementFactory::register_element(plugin, "myfilter",
                10, Gst::register_mm_type<DerivedFromBaseTransform>("myfilter"));
  }
};

// main函数
Gst::init();
  bool plugin_registered = Plugin::register_static(GST_VERSION_MAJOR, GST_VERSION_MINOR,
                                                   "derivedfrombasetransform", "exemplary element C++-derived from Gst::BaseTransform",
                                                   sigc::ptr_fun(&DerivedFromBaseTransform::register_element), "0.123", "LGPL",
                                                   "source?", "package?", "http://example.com");
  auto loop = Glib::MainLoop::create();
  auto pipe = Gst::Pipeline::create();
  auto element = Gst::ElementFactory::create_element("myfilter");
  auto queue1 = Gst::ElementFactory::create_element("queue2");
  auto queue2 = Gst::ElementFactory::create_element("queue2");
  auto src = Gst::ElementFactory::create_element("videotestsrc");
  auto out = Gst::ElementFactory::create_element("autovideosink");
  auto conv = Gst::ElementFactory::create_element("videoconvert");
  auto conv2 = Gst::ElementFactory::create_element("videoconvert");

  // 这里设置属性
  element->set_property("color", Glib::ustring("#0000FF"));
  pipe->add(src)->add(element)->add(conv)->add(out)->add(conv2)->add(queue1)->add(queue2);
  src->link(conv)->link(queue1)->link(element)->link(queue2)->link(conv2)->link(out);
  
  pipe->set_state(Gst::STATE_PLAYING);
  loop->run();
  pipe->set_state(Gst::STATE_NULL);
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值