Я пытался реализовать простейший конвейер gstreamer-1.0 с захватом видео с веб-камеры и записью его в файл. Оно работает. Однако при непрерывной записи очень небольших видео (~ 2 с) — при перезапуске конвейера в цикле — иногда я получаю следующую ошибку при перезапуске конвейера:
libv4l2: ошибка установки pixformat: устройство или ресурс занят
Кажется, что 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 — проверьте этот
Других решений пока нет …