Computer vision 关于通过appsrc将cv::Mat保存到mp4文件的问题

Computer vision 关于通过appsrc将cv::Mat保存到mp4文件的问题,computer-vision,gstreamer,mat,pts,Computer Vision,Gstreamer,Mat,Pts,我想通过appsrc将CV::mat保存为MP4文件,或者通过RTMP转发它。我实现了一个简单的代码,可以成功运行,但获得的MP4文件无法播放。有人能告诉我问题出在哪里吗?我想可能PTS设置错误,但我不知道如何解决。提前谢谢 #include <gst/gst.h> #include <glib.h> #include <gst/app/gstappsrc.h> #include <opencv2/opencv.hpp> #include <

我想通过appsrc将CV::mat保存为MP4文件,或者通过RTMP转发它。我实现了一个简单的代码,可以成功运行,但获得的MP4文件无法播放。有人能告诉我问题出在哪里吗?我想可能PTS设置错误,但我不知道如何解决。提前谢谢

#include <gst/gst.h>
#include <glib.h>
#include <gst/app/gstappsrc.h>
#include <opencv2/opencv.hpp>
#include <unistd.h>

typedef struct {
    GstPipeline *pipeline = nullptr;
    GstAppSrc  *app_src = nullptr;
    GstElement *video_convert = nullptr;
    GstElement *encoder = nullptr;
    GstElement *h264_parser = nullptr;
    GstElement *qt_mux = nullptr;
    GstElement *file_sink = nullptr;
}CustomData;



int main(int argc,char * argv[]){
    CustomData data;
    GstBus *bus = nullptr;
    GstMessage *msg = nullptr;
    GstStateChangeReturn ret;
    gboolean terminate = false;
    GstClockTime timestamp = 0;
    gst_init(&argc, &argv); 

    data.pipeline = (GstPipeline*)gst_pipeline_new("m_pipeline");
    data.app_src = (GstAppSrc*)gst_element_factory_make("appsrc","m_app_src");
    data.video_convert = gst_element_factory_make("videoconvert","m_video_convert");
    data.encoder = gst_element_factory_make("x264enc","m_x264enc");
    data.h264_parser = gst_element_factory_make("h264parse","m_h264_parser");
    data.qt_mux = gst_element_factory_make("qtmux","qt_mux");
    data.file_sink = gst_element_factory_make("filesink","file_sink");


    if (!data.app_src || !data.video_convert || !data.encoder || !data.h264_parser || !data.qt_mux || !data.file_sink || !data.pipeline){
        g_printerr("failed to create all elements\n");
        return -1;
    }

    gst_bin_add_many(GST_BIN(data.pipeline), (GstElement*)data.app_src, data.video_convert, data.encoder, data.h264_parser, data.qt_mux, data.file_sink, NULL);

    g_assert(gst_element_link_many((GstElement*)data.app_src, data.video_convert, data.encoder, data.h264_parser, data.qt_mux, data.file_sink,NULL));

    GstCaps *caps = gst_caps_new_simple("video/x-raw","format",G_TYPE_STRING,"BGR",
                                        "width",G_TYPE_INT,1280,
                                        "height",G_TYPE_INT,720,
                                        "framerate",GST_TYPE_FRACTION,25,1,
                                        NULL);

    gst_app_src_set_caps(GST_APP_SRC(data.app_src), caps);
    g_object_set(data.app_src,"is_live",true,NULL);
    g_object_set(data.app_src,"format",GST_FORMAT_TIME,NULL);

    std::string mp4_url = "des.mp4";

    g_object_set(data.file_sink,"location",mp4_url.c_str(),NULL);

    ret = gst_element_set_state((GstElement*)data.pipeline, GST_STATE_PLAYING);
    if (ret == GST_STATE_CHANGE_FAILURE){
        g_printerr("Unable to set the pipeline to the playing state. \n");
        gst_object_unref(data.pipeline);
        return -1;
    }

    cv::VideoCapture cap;
    cap.open("src.mp4");
    
    if(!cap.isOpened())
        return -2;
    cv::Mat frame;
    while(true){
        cap.read(frame);
        if(frame.empty()){
            break;
        }
        GstBuffer *buffer;
        buffer = gst_buffer_new_wrapped(frame.data, frame.size().width * frame.size().height * frame.channels());

        GST_BUFFER_PTS (buffer) = timestamp;
        GST_BUFFER_DURATION (buffer) = gst_util_uint64_scale_int (1, GST_SECOND, 25);
        timestamp += GST_BUFFER_DURATION (buffer);
        GstFlowReturn ret;

        g_signal_emit_by_name(data.app_src, "push-buffer", buffer, &ret);
        usleep(1000000/25);
    }

    gst_element_set_state((GstElement*)data.pipeline, GST_STATE_NULL);
    gst_object_unref(data.pipeline);
    return 0;
}


#包括
#包括
#包括
#包括
#包括
类型定义结构{
GstPipeline*管道=nullptr;
GstAppSrc*app_src=nullptr;
GstElement*video_convert=nullptr;
GstElement*编码器=空PTR;
GstElement*h264_解析器=nullptr;
GstElement*qt_mux=nullptr;
GstElement*file_sink=nullptr;
}海关数据;
int main(int argc,char*argv[]){
客户数据;
GstBus*总线=空PTR;
GstMessage*msg=nullptr;
GSTStateChangeRet;
gboolean终止=false;
GstClockTime时间戳=0;
gst_init(&argc,&argv);
data.pipeline=(GstPipeline*)gst_管道新(“m_管道”);
data.app_src=(gstapsrc*)商品及服务税元素工厂制造(“appsrc”、“m_app_src”);
data.video_convert=gst_元素_工厂制造(“videoconvert”、“m_video_convert”);
data.encoder=gst元素工厂制造(“x264enc”、“MX264ENC”);
data.h264_parser=gst_元素_工厂_制造(“h264parse”,“m_h264_parser”);
data.qt_mux=gst_元素_工厂制造(“qtmux”、“qt_mux”);
data.file_sink=gst_元素_工厂制造(“filesink”、“file_sink”);
如果(!data.app_src | | |!data.video_convert | |!data.encoder | |!data.h264_parser | |!data.qt_mux | |!data.file | u sink | | data.pipeline){
g_printerr(“未能创建所有元素\n”);
返回-1;
}
gst_bin_add_many(gst_bin(data.pipeline),(GstElement*)data.app_src,data.video_convert,data.encoder,data.h264_解析器,data.qt_mux,data.file_sink,NULL);
g_断言(gst_元素_链接_多((GstElement*)data.app_src,data.video_convert,data.encoder,data.h264_解析器,data.qt_mux,data.file_sink,NULL));
GstCaps*caps=gst\u caps\u new\u simple(“视频/x-raw”,“格式”,G\u类型\u字符串,“BGR”,
“宽度”,G_TYPE_INT,1280,
“高度”,G_TYPE_INT,720,
“帧率”,GST_类型_分数,25,1,
无效);
gst\u app\u src\u set\u caps(gst\u app\u src(data.app\u src),caps);
g_object_set(data.app_src,“is_live”,true,NULL);
g_对象集(data.app_src,“format”,GST_format_TIME,NULL);
std::string mp4_url=“des.mp4”;
g_object_set(data.file_sink,“location”,mp4_url.c_str(),NULL);
ret=gst\U元素\U集合\U状态((GstElement*)数据管道,gst\U状态\U播放);
如果(ret==GST\u状态\u变化\u失败){
g_printerr(“无法将管道设置为播放状态。\n”);
gst_object_unref(数据管道);
返回-1;
}
cv::视频捕获帽;
未结章(“src.mp4”);
如果(!cap.isOpened())
返回-2;
cv::垫架;
while(true){
阅读(框架);
if(frame.empty()){
打破
}
GstBuffer*缓冲区;
buffer=gst\u buffer\u new\u wrapped(frame.data,frame.size().width*frame.size().height*frame.channels());
GST_BUFFER_PTS(BUFFER)=时间戳;
GST_缓冲时间(缓冲)=GST_util_uint64_scale_int(1,GST_SECOND,25);
时间戳+=GST\u缓冲区\u持续时间(缓冲区);
GSTFlowRet;
g_信号按名称发出(data.app_src,“push buffer”、buffer和ret);
美国LEEP(1000000/25);
}
gst_元素_集合_状态((GstElement*)data.pipeline,gst_状态_NULL);
gst_object_unref(数据管道);
返回0;
}

您不能简单地将管道状态设置为
NULL
。相反,您需要向管道发送EOS事件,并等待EOS信号在管道总线上报告回来。如果您不这样做,那么MP4文件将不会写入一些需求头,并且该文件无法播放

有关如何检查总线上的EOS消息,请参阅

检查如何告知您的
appsrc
上一个数据缓冲区已被推送