c++ - 使用 v4l2scr 重启 gstreamer 管道的正确方法

标签 c++ video gstreamer video-capture v4l2

我试图通过从网络摄像头捕获视频并将其写入文件来实现最简单的 gstreamer-1.0 管道。有用。然而,在连续录制非常小的视频(~2 秒)时 - 在循环中重新启动管道 - 我有时会在管道重新启动时收到以下错误:

libv4l2: error setting pixformat: Device or resource busy

v4l2src 元素似乎在之前的记录步骤中没有正确释放。

正确重启管道必须做什么?

#include <iostream>
#include <thread>
#include <gst/gst.h>

static GstElement* makeCamSrc(int deviceId)
{
    GstElement* cam = gst_element_factory_make("v4l2src", "camSrc");

    if(!cam)
        return NULL;

    std::string devPath = std::string("/dev/video") + std::to_string(deviceId);
    g_object_set(cam, "device", devPath.c_str(), NULL);
    g_object_set(cam, "do-timestamp", true, NULL);

    //Setup camera controls
    GstStructure* extraCtrls = gst_structure_new("logitech_controls",
                                                 "sharpness", G_TYPE_INT, 220,
                                                 "contrast", G_TYPE_INT, 100,
                                                 "saturation", G_TYPE_INT, 160,
                                                 "focus_auto", G_TYPE_BOOLEAN, false,
                                                 "white_balance_temperature_auto", G_TYPE_BOOLEAN, false,
                                                 "white_balance_temperature", G_TYPE_INT, 3500,
                                                 NULL);

    g_object_set(cam, "extra-controls" , extraCtrls, NULL);

    return cam;
}

int main()
{
    gst_init(NULL, NULL);

    GstElement* vPipeline = gst_pipeline_new("vPipeline");
    GstElement* camSrc = makeCamSrc(1);
    GstElement* converter = gst_element_factory_make("videoconvert", "converter");
    GstElement* tee = gst_element_factory_make("tee", "tee");
    GstElement* vQueue = gst_element_factory_make("queue", "vQueue");
    GstElement* vEncoder = gst_element_factory_make("x264enc", "vEncoder");
    GstElement* vMuxer = gst_element_factory_make("mp4mux", "muxer");
    GstElement* vFileSink = gst_element_factory_make("filesink", "vFileSink");

    GstCaps* camCaps = gst_caps_new_simple("video/x-raw",
                                           "format", G_TYPE_STRING,  "RGB",
                                           "width",  G_TYPE_INT,     1280,
                                           "height", G_TYPE_INT,     720,
                                           NULL);

    gst_bin_add_many(GST_BIN(vPipeline), camSrc, converter, tee, vQueue, vEncoder, vMuxer, vFileSink, NULL);

    gst_element_link_filtered(camSrc, converter, camCaps);
    gst_caps_unref(camCaps);

    gst_element_link(converter, tee);
    gst_element_link_many(vQueue, vEncoder, vMuxer, vFileSink, NULL);

    GstPadTemplate* padTemplate = gst_element_class_get_pad_template(GST_ELEMENT_GET_CLASS(tee), "src_%u");
    GstPad* vTeePad = gst_element_request_pad(tee, padTemplate, NULL, NULL);

    GstPad* vQueuePad =  gst_element_get_static_pad(vQueue, "sink");
    gst_pad_link(vTeePad, vQueuePad);

    GstBus* bus = gst_element_get_bus(vPipeline);

    for(int i = 0; i < 11; ++i)
    {
        std::string file = std::string("stream_") + std::to_string(i) + std::string(".mp4");
        g_object_set(vFileSink, "location", file.c_str(), NULL);

        gst_element_set_state(vPipeline, GST_STATE_PLAYING);

        std::thread([&]
                    {
                        std::this_thread::sleep_for(std::chrono::milliseconds(2000));
                        gst_element_send_event(vPipeline, gst_event_new_eos());
                    }).detach();

        GstMessage* msg = gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE, (GstMessageType)(GST_MESSAGE_ERROR | GST_MESSAGE_EOS));
        if (msg != NULL)
        {
            if(GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR)
                return -1;

            gst_message_unref (msg);
        }
        gst_element_set_state(vPipeline, GST_STATE_NULL);
    }

    gst_object_unref(vPipeline);
}

最佳答案

tl dr - 也许这会起作用:

尝试添加

gst_element_set_state(camSrc, GST_STATE_NULL); 

管道一之前

或者先将其设置为 GST_STATE_PAUSED,然后延迟一段时间再设置为 NULL..

也许您应该使用 glib 主事件循环来调用您的 eos - 检查 this

关于c++ - 使用 v4l2scr 重启 gstreamer 管道的正确方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37785298/

相关文章:

c++ - 在 C++ 中使用 std::set 的最长递增子序列

c++ - malloc() 可能导致内存泄漏

ios - 如何合并两个透明的视频

c++ - 如何在 VS2005 中提高大型 C++ 应用程序的链接性能

java - 如何修复无法播放此视频 android 表单 url

javascript - 如何通过 API "input type=' 文件'“标记...NO Jquery 或外部库更改本地文件的视频源

c - 在特定接收器传输了多少数据

video-streaming - 使用 gstreamer 通过 rtp 流式传输 H.264 视频

audio - 使用 Gstreamer 将多个音频流混合成一个播放声音

c++ - 如果之前调用了 CancelIo,则 ReadDirectoryChangesW 失败并显示错误 995