Privacy policyContactsAbout siteOpinionsGitHubDonate
© EVILEG 2015-2018
Recommend hosting
TIMEWEB
Dec. 24, 2018, 1:25 p.m.

Переинициализация cv::VideoWriter

OpenCV

Все привет! Имею два компа, на которых подняты два сетевых интерфейса: локалку и 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 и создавать заново, но это тоже не помогло.

5

на вход 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

т.е., строки отличаются только адресами, на который нужно слать видео

0
  • Dec. 24, 2018, 2:06 p.m.

Может вам стоит посмотреть в сторону QMediaPlayer с помощью него и других вспомогательных классов, вы сможете сделать трансляцию без GStreamer чисто на Qt

0

Боюсь, что он не поможет, т.к. нужно обрабатывать кадры с помощью opencv, да и на отправляющем компе проект без Qt.

0

Если не ошибаюсь, то Qt тоже использует gstreamer с той лишь разницей, что напрямую к нему не придётся обращаться, поскольку он скрыт за фасадом Qt

0
  • Dec. 25, 2018, 8:58 a.m.
  • The answer was marked as a solution.

Проблема решилась. Сам ступил. При переключении канала отсылал видео не на тот адрес.

1

Comments

Only authorized users can post comments.
Please, Log in or Sign up
v
Jan. 17, 2019, 11:51 a.m.
vitalir12

C ++ - Test 004. Pointers, Arrays and Loops

  • Result:20points,
  • Rating points-10
v
Jan. 17, 2019, 11:49 a.m.
vitalir12

C++ - Test 002. Constants

  • Result:50points,
  • Rating points-4
v
Jan. 17, 2019, 11:13 a.m.
vitalir12

C++ - Тест 003. Условия и циклы

  • Result:28points,
  • Rating points-10
Last comments
I
Jan. 16, 2019, 8:06 a.m.
IscanderChe

Заработало. Забыл model->select(); вписать.
I
Jan. 16, 2019, 8:02 a.m.
IscanderChe

Всё равно пусто, хотя строка с данными в базу добавляется.
Jan. 16, 2019, 7:51 a.m.
Евгений Легоцкой

потому, что нужно сохранять информацию для всех остальных ролей и столбцов через вызов переопределённого метода. Да к тому же вы ещё и зациклили вызов метода data. QVariant MySqlTableModel:...
I
Jan. 16, 2019, 7:43 a.m.
IscanderChe

Сделал вот так. В tableView ничего нет, кроме заголовка. QVariant MySqlTableModel::data(const QModelIndex &index, int role) const{ if (role == Qt::DisplayRole) { QTime ...
Now discuss on the forum
Jan. 18, 2019, 11:26 a.m.
nayk1982

Для Desktop делал так: void pause(int ms){ QTimer timer; timer.setInterval( qBound(1, ms, 3600000) ); timer.setSingleShot(true); QEventLoop loop; QObject::connect(&...
Jan. 17, 2019, 12:01 p.m.
Алексей Внуков

у меня просто есть отдельное поле с чекбоксамими какие колонки нужно отображать CheckBox { id: checkBox text: qsTr("some text") checked: true onC...
Jan. 15, 2019, 4:53 p.m.
Михаиллл

Спасибо, заработало.Но выдало обычный текст без форатирования HTML.Придется искать дальше
Jan. 15, 2019, 12:52 p.m.
BlinCT

Я же вам выше написал CLion умеет работать с ремоут машинами. И Qt так же собирает.
Join us in social networks

For registered users on the site there is a minimum amount of advertising