利用GStreamer 将cv::Mat 硬编码成h264文件

一,需求

采集工业相机图片 ,h264编码,之后保存到h264文件

二,

三,代码

#pragma once
#include <opencv2/core/core.hpp>
#include <string>
#include <gst/gst.h>

namespace Transmit
{
    class VideoEncode : public std::enable_shared_from_this<VideoEncode>
    {
    public:
        using Ptr = std::shared_ptr<VideoEncode>;
        ~VideoEncode();

        /**
         * @brief 打开视频, url为视频的文件路径或者网络地址
         */
        int Open(const std::string url);

        /**
         * @brief 设置视频帧率
         * @param fps = framerate.first/framerate.second
         */
        void SetFramerate(std::pair<int, int> framerate)
        {
            framerate_ = framerate;
        }

        /**
         * @brief 设置视频分辨率
         */
        void SetSize(int width, int height)
        {
            width_ = width;
            height_ = height;
        }

        /**
         * @brief 设置视频码率
         * @param bitrate 单位bit/sec
         */
        void SetBitrate(int bitrate)
        {
            bitrate_ = bitrate;
        }

        /**
         * @brief 写入视频帧
         */
        int Write(const cv::Mat &frame);

    private:
        int PushData2Pipeline(const cv::Mat &frame);
        GstElement *pipeline_;
        GstElement *appSrc_;
        GstElement *queue_;
        GstElement *videoConvert_;
        GstElement *encoder_;
        GstElement *capsFilter1_;
        GstElement *capsFilter2_;
        GstElement *mux_;
        GstElement *sink_;
        GstElement *parser_;
        int width_ = 0;
        int height_ = 0;
        int bitrate_ = 2;
        std::pair<int, int> framerate_{30, 1};
        GstClockTime timestamp{0};
    };
}
#include <transmit/video_encode.h>
#include <iostream>
#include <stdio.h>
#include <unistd.h>

using namespace std;
namespace Transmit
{
    VideoEncode::~VideoEncode()
    {
        if (appSrc_)
        {
            GstFlowReturn retflow;
            g_signal_emit_by_name(appSrc_, "end-of-stream", &retflow);
            std::cout << "EOS sended. Writing last several frame..." << std::endl;
            g_usleep(4000000); // 等待4s,写数据
            std::cout << "Writing Done!" << std::endl;
            if (retflow != GST_FLOW_OK)
            {
                std::cerr << "We got some error when sending eos!" << std::endl;
            }
        }
        if (pipeline_)
        {
            gst_element_set_state(pipeline_, GST_STATE_NULL);
            gst_object_unref(pipeline_);
            pipeline_ = nullptr;
        }
    }

    int VideoEncode::Open(const std::string url)
    {
        pipeline_ = gst_pipeline_new("pipeline");
        appSrc_ = gst_element_factory_make("appsrc", "AppSrc");
        capsFilter1_ = gst_element_factory_make("capsfilter", "Capsfilter");
        capsFilter2_ = gst_element_factory_make("capsfilter", "Capsfilter2");
        encoder_ = gst_element_factory_make("omxh264enc", "Omxh264enc");
        parser_ = gst_element_factory_make("h264parse", "H264parse");
        mux_ = gst_element_factory_make("qtmux", "muxer");
        sink_ = gst_element_factory_make("filesink", "OutputFile");

        if (!pipeline_ || !appSrc_  || !encoder_ || !parser_ ||!capsFilter2_||!capsFilter1_ || !sink_||!mux_)
        {
            std::cerr << "Not all elements could be created" << std::endl;
            return -1;
        }
        // 设置 src format
        std::string srcFmt = "I420";

        //Set up appsrc
        g_object_set (appSrc_, "format", GST_FORMAT_TIME, NULL);
        g_object_set(G_OBJECT(capsFilter1_), "caps",gst_caps_new_simple ("video/x-raw",
                                                         "format", G_TYPE_STRING, srcFmt.c_str(),
                                                         "width", G_TYPE_INT, width_,
                                                         "height", G_TYPE_INT, height_,
                                                         "framerate", GST_TYPE_FRACTION,framerate_.first, framerate_.second,nullptr),NULL);

        g_object_set(G_OBJECT(capsFilter2_), "caps", gst_caps_new_simple("video/x-h264", 
                                                                    "stream-format", G_TYPE_STRING,"byte-stream",nullptr), nullptr);


        // Set up x264enc
        g_object_set(G_OBJECT(encoder_), "bitrate", bitrate_* 1024 * 1024 * 8, NULL);

        // Set up filesink
        g_object_set(G_OBJECT(sink_), "location", url.c_str(), NULL);

        // BAdd elements to pipeline
        gst_bin_add_many(GST_BIN(pipeline_), appSrc_, capsFilter1_,encoder_, capsFilter2_, parser_,mux_,sink_, nullptr);

        // Link elements
        if (gst_element_link_many(appSrc_, capsFilter1_,encoder_,capsFilter2_ ,parser_,mux_,sink_, nullptr) != TRUE)
        {
            std::cerr << "appSrc, capsFilter2, parser, encoder, capsFilter, mux and sink could not be linked" << std::endl;
            return -1;
        }

        // Start playing
        auto ret = gst_element_set_state(pipeline_, GST_STATE_PLAYING);
        if (ret == GST_STATE_CHANGE_FAILURE)
        {
            std::cerr << "Unable to set the pipeline to the playing state" << std::endl;
            return -1;
        }

        return 0;
    }

    int VideoEncode::PushData2Pipeline(const cv::Mat &frame)
    {
        GstBuffer *buffer;
        GstFlowReturn ret;
        GstMapInfo map;

        // Create a new empty buffer
        uint size = frame.total() * frame.elemSize();
        buffer = gst_buffer_new_and_alloc(size);

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

        // debug
        // std::cout << "wrote size:" << size << std::endl;

        // 必须写入时间戳和每帧画面持续时间
        gst_buffer_unmap(buffer, &map);
        GST_BUFFER_PTS(buffer) = timestamp; // static_cast<uint64>(timestamp * GST_SECOND);
        GST_BUFFER_DTS(buffer) = timestamp;
        GST_BUFFER_DURATION(buffer) = gst_util_uint64_scale_int(1, GST_SECOND, framerate_.first / framerate_.second);
        timestamp += GST_BUFFER_DURATION(buffer);

        // std::cout << "send data into buffer" << std::endl;
        // std::cout << "GST_BUFFER_DURATION(buffer):" << GST_BUFFER_DURATION(buffer) << std::endl;
        // std::cout << "timestamp:" << static_cast<uint64>(_timestamp * GST_SECOND) << std::endl;

        // Push the buffer into the appsrc
        g_signal_emit_by_name(appSrc_, "push-buffer", buffer, &ret);

        // Free the buffer now that we are done with it
        gst_buffer_unref(buffer);

        if (ret != GST_FLOW_OK)
        {
            // We got some error, stop sending data
            std::cout << "We got some error, stop sending data" << std::endl;
            return -1;
        }
        return 0;
    }

    int VideoEncode::Write(const cv::Mat &frame)
    {
        return PushData2Pipeline(frame);
    }
}

参考:【gstreamer opencv::Mat】使用gstreamer读取视频中的每一帧为cv::Mat_jjungle666的博客-CSDN博客

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

土拨鼠不是老鼠

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

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

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

打赏作者

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

抵扣说明:

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

余额充值