Переинициализация 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 р. 22:58
C++ - Тест 004. Указатели, Массивы и Циклы
- Результат:50бали,
- Рейтинг балів-4
- molni99
- 26 жовтня 2024 р. 08:37
C++ - Тест 004. Указатели, Массивы и Циклы
- Результат:80бали,
- Рейтинг балів4
- molni99
- 26 жовтня 2024 р. 08: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
Проблема решилась. Сам ступил. При переключении канала отсылал видео не на тот адрес.