Переинициализация cv::VideoWriter
Все привет!
Имею два компа, на которых подняты два сетевых интерфейса: локалку и LTE-модем (со статичными адресами).
Нужно перегонять видео с одного компа на другой, но при этом должна быть возможность смены канала передачи: т.е., если была трансляция по локалке, и скомандовали перейти на модем, то видео должно перейти на модем.
Для передачи использую связку cv::VideoWriter+GStreamer.
void Video_sender::onConnected(const std::string & ip) { std::string gst = "appsrc ! videoconvert ! video/x-raw,format=YV12,width="; gst+=std::to_string(WIDTH)+",height="+std::to_string(HEIGHT)+" ! jpegenc ! rtpjpegpay ! udpsink host="; _ip = ip; gst += _ip + " port="+std::to_string(PORT_NUM); changeBroadcastingPath(gst); } void Video_sender::changeBroadcastingPath(const std::string &gstr_string) { std::lock_guard<std::mutex> lock(mut_write_to_rmo); _gst = gstr_string; std::cout << "GSTREAMER STRING: " << _gst << std::endl; if(write_to_RMO!=nullptr) { write_to_RMO->release(); bool res=write_to_RMO->open(_gst, cv::CAP_GSTREAMER, 0, FPS, cv::Size(WIDTH,HEIGHT), true); std::cout << "write_to_RMO reinitialized: " << std::boolalpha << res << std::endl; } else { write_to_RMO = std::make_unique<cv::VideoWriter>(_gst, cv::CAP_GSTREAMER, 0, FPS, cv::Size(WIDTH,HEIGHT), true); } }
Само считывание кадра из камеры и передача на второй комп происходит в отдельном потоке.
int Video_sender::ThreadMain() { /*Считывание кадра в cv::Mat из videoCapture*/ if(!inMat.empty()) { mut_write_to_rmo.lock(); if(write_to_RMO != nullptr) /// если нет коннекта с РМО даже пытаться не будем что то передавать { if(write_to_RMO->isOpened()) { if(inMat.cols!=WIDTH && inMat.rows!=HEIGHT)//if(vec_frame[(xxx%(vec_p_cap.size()*100))/100.].cols != WIDTH && vec_frame[(xxx%(vec_p_cap.size()*100))/100.].rows != HEIGHT ) { cv::Mat out; //cv::resize(vec_frame[(xxx%(vec_p_cap.size()*100))/100.],out,cv::Size(WIDTH,HEIGHT)); /// изменим размер картинки на 720х1280, если он не соответствует cv::resize(inMat, out, cv::Size(WIDTH,HEIGHT)); /// изменим размер картинки на 720х1280, если он не соответствует //cv::imshow(" != ",out); cv::waitKey(1); /// debug //std::cout << "sending frame to rmo after resizing..." << std::endl; write_to_RMO->write(out); /// отправка на РМО } else { //cv::imshow("640x480",inMat); cv::waitKey(1); /// debug std::cout << "sending frame to rmo... " << _gst << std::endl; write_to_RMO->write(inMat); /// отпрака на РМО } } else { GetLog().log("write_to_rmo not opened"); } } else { GetLog().log("write_to_rmo == nullptr"); } mut_write_to_rmo.unlock(); }
По отдельности все работает. Но при попытке переключить канал, видео перестает передаваться. Хотя кадр отсылается. Текст в коде ниже выводится
std::cout << "sending frame to rmo... " << _gst << std::endl;
Можно было бы при переключении канала связи просто грохнуть поток и заново его создать, но чтение кадров из камеры не должно прерываться.
На приемном компе создается cv::VideoCapture, в который передается строка Gstreamer:
const std::string vrstr("udpsrc port=5000 ! application/x-rtp, media=video, clock-rate=90000, encoding-name=JPEG, payload=26 ! rtpjpegdepay ! jpegdec ! videoconvert ! video/x-raw, format=BGR ! appsink sync=0");
и в потоке кадры считываются из него.
В какую сторону копать? С opencv дело практически не имел.
В методе changeBroadcastingPath пробовал грохать write_to_RMO и создавать заново, но это тоже не помогло.
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.Вам это нравится? Поделитесь в социальных сетях!
Комментарии
Пожалуйста, авторизуйтесь или зарегистрируйтесь
- Akiv Doros
- 11 ноября 2024 г. 14:58
C++ - Тест 004. Указатели, Массивы и Циклы
- Результат:50баллов,
- Очки рейтинга-4
- molni99
- 26 октября 2024 г. 1:37
C++ - Тест 004. Указатели, Массивы и Циклы
- Результат:80баллов,
- Очки рейтинга4
- molni99
- 26 октября 2024 г. 1:29
C++ - Тест 004. Указатели, Массивы и Циклы
- Результат:20баллов,
- Очки рейтинга-10
на вход videoWriter на отправляющем компе подаются строки:
appsrc ! videoconvert ! video/x-raw,format=YV12,width=640,height=480 ! jpegenc ! rtpjpegpay ! udpsink host=YYY.YYY.YYY.YYY port=5000
При смене канала:
appsrc ! videoconvert ! video/x-raw,format=YV12,width=640,height=480 ! jpegenc ! rtpjpegpay ! udpsink host=XXX.XXX.XXX.XXX port=5000
т.е., строки отличаются только адресами, на который нужно слать видео
Может вам стоит посмотреть в сторону QMediaPlayer с помощью него и других вспомогательных классов, вы сможете сделать трансляцию без GStreamer чисто на Qt
Боюсь, что он не поможет, т.к. нужно обрабатывать кадры с помощью opencv, да и на отправляющем компе проект без Qt.
Если не ошибаюсь, то Qt тоже использует gstreamer с той лишь разницей, что напрямую к нему не придётся обращаться, поскольку он скрыт за фасадом Qt
Проблема решилась. Сам ступил. При переключении канала отсылал видео не на тот адрес.