gstreamer 编码 cv::Mat 为h264 并推流到rtmp服务器

gstreamer 编码cv::Mat rgb图片为 h264视频流,并推松到 rtmp服务器

#pragma once

#include <memory>
#include <mutex>
#include <opencv4/opencv2/opencv.hpp>

extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
}

namespace Base
{

    class FFmpegStreamDecoder
    {
    public:
        int32_t Init(int width,int height);

        int32_t DeInit();

        int32_t Decode(const uint8_t *data, size_t length,cv::Mat& bgrMat);

    private:
        std::mutex decode_mutex;
        AVCodecContext *pCodecCtx = nullptr;
        AVCodec *pCodec = nullptr;
        AVCodecParserContext *pCodecParserCtx = nullptr;
        SwsContext *pSwsCtx = nullptr;

        AVFrame *pFrameYUV = nullptr;
        AVFrame *pFrameRGB = nullptr;
        uint8_t *rgbBuf = nullptr;
        size_t bufSize = 0;
        int32_t decode_width;
        int32_t decode_hight;

        std::mutex image_mutex;
    };

}
#include "GstreamerEncoder.h"
#include <thread>
#include <Util/logger.h>
#include <chrono>
#include <core/Configure.hpp>

using namespace toolkit;
namespace Base
{
    bool Encoder::Init()
    {
        isRuning.store(false);

        pipeline = gst_pipeline_new("opencv-rtmp-pipeline");
        appsrc = gst_element_factory_make("appsrc", "video-src");
        videoconvert = gst_element_factory_make("videoconvert", "convert");
        nvvidconv = gst_element_factory_make("nvvidconv", "nvconv");
        encoder = gst_element_factory_make("nvv4l2h264enc", "encoder");
        h264parse = gst_element_factory_make("h264parse", "parser");
        flvmux = gst_element_factory_make("flvmux", "mux");
        rtmpsink = gst_element_factory_make("rtmpsink", "sink");

        if (!pipeline || !appsrc || !videoconvert || !encoder || !flvmux || !rtmpsink || !nvvidconv || !h264parse)
        {
            ErrorL << "GStreamer 元素创建失败";
            return false;
        }

        std::string rtmpAddress = Configure::getInstance().RtmpAddress();
        InfoL << "RTMP 服务器地址: " << rtmpAddress;
        if (rtmpAddress.empty())
            return false;

        int fps = Configure::getInstance().Fps();
        InfoL << "帧率: " << fps;

        int bitrate = Configure::getInstance().Bitrate();
        InfoL << "码率:  " << bitrate;

        int width = Configure::getInstance().ImageWidth();
        int height = Configure::getInstance().ImageHeight();
        InfoL << "图片大小W*H:  " << width << " " << height;
        if (width == 0 || height == 0)
        {
            return false;
        }

        // 设置推流地址
        g_object_set(G_OBJECT(rtmpsink), "location", rtmpAddress.c_str(), nullptr);

        // 设置编码器属性
        g_object_set(encoder, "insert-sps-pps", TRUE, "idrinterval", 15, "iframeinterval", 15, "control-rate", 1, "bitrate", bitrate, "preset-level", 1, "profile", 1, "insert-vui", 1, NULL);

        // 设置 appsrc 的属性
        g_object_set(G_OBJECT(appsrc), "caps", gst_caps_new_simple("video/x-raw", "format", G_TYPE_STRING, "BGR", "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, "framerate", GST_TYPE_FRACTION, fps, 1, nullptr, NULL), NULL);
        g_object_set(G_OBJECT(appsrc), "is-live", TRUE, "format", GST_FORMAT_TIME, "do-timestamp", TRUE, NULL);

        // 元素加入管道
        gst_bin_add_many(GST_BIN(pipeline), appsrc, videoconvert, nvvidconv, encoder, h264parse, flvmux, rtmpsink, nullptr);

        // 链接
        if (!gst_element_link_many(appsrc, videoconvert, nvvidconv, encoder, h264parse, flvmux, rtmpsink, nullptr))
        {
            ErrorL << "GStreamer 元素连接失败";
            return false;
        }

        // 启动管道
        auto ret = gst_element_set_state(pipeline, GST_STATE_PLAYING);
        if (ret == GST_STATE_CHANGE_FAILURE)
        {
            ErrorL << "Gstreamer 启动管道失败!" << std::endl;
            return -1;
        }

        return true;
    }

    void Encoder::Start()
    {
        isRuning.store(true);
        std::thread t([&]()
                      {
            InfoL<<"编码 开始!";
            while (isRuning.load())
            {
               cv::Mat frame;
              if(Data::getInstance().imageQueue.tryPop(frame)){

                    // 创建 GstBuffer
                    int size = frame.total() * frame.elemSize();
                    GstBuffer *buffer = gst_buffer_new_and_alloc(size);

                    GstMapInfo map;
                    gst_buffer_map(buffer, &map, GST_MAP_WRITE);
                    memcpy(map.data, frame.data, size);

                    // 发送 buffer
                    GstFlowReturn ret;
                    g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);

                    //析构
                    gst_buffer_unmap(buffer, &map);
                    gst_buffer_unref(buffer);

                    if (ret != GST_FLOW_OK) {
                       ErrorL << "推送失败,GstFlowReturn: " << ret;
                       break;
                    }
              }
              //std::this_thread::sleep_for(std::chrono::milliseconds(20));
            }
            InfoL<<"编码 停止!"; });
        t.detach();
    }

    void Encoder::DeInit()
    {
        isRuning.store(false);
        std::this_thread::sleep_for(std::chrono::seconds(1));

        // 关闭
        if (appsrc)
        {
            GstFlowReturn retflow;
            g_signal_emit_by_name(appsrc, "end-of-stream", &retflow);
            InfoL << "EOS sended. Writing last several frame...";
            g_usleep(4000000); // 等待4s,写数据
            if (retflow != GST_FLOW_OK)
            {
                ErrorL << "We got some error when sending eos!";
            }
        }
        if (pipeline)
        {
            gst_element_set_state(pipeline, GST_STATE_NULL);
            gst_object_unref(pipeline);
            pipeline = nullptr;
        }
    }
}

开始运行后,默认从一个队列取图。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

土拨鼠不是老鼠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值