Выдача сигналов в цикле из QThread

Я работаю над своего рода видеоплеером, но у меня проблема с реализацией функции «Воспроизвести», когда кадры отображаются через определенный интервал времени.

Пропуск кадров с помощью кнопок или ползунка работает нормально, но следующий код не работает. Более того, кажется, что он блокирует поток графического интерфейса и отображает только последний кадр.

void Player::play()
{
    for(int i = currentFrame_; i < replay_->getHeader().numberOfFrames; ++i)
    {
        setFrame(i);    // load and send frame i
        msleep(33);     // wait 33 ms
    }
}

void Player::setFrame(int frameNumber)
{
    currentFrame_ = frameNumber;
    replay_->setCurrentFrame(currentFrame_);    // load currentFrame into buffer
    updateFrame();                              // send it to the GUI to be shown
}

void Player::updateFrame()
{
    ReplayFrame colorFrame;

    colorFrame = replay_->getColorFrame();
    emit colorFrameEvent(static_cast<unsigned char *>(colorFrame.getData()));    // this is connected to MainWindow::showFrame(unsigned char *)
}

Обратите внимание, что следующий код работает нормально:

// In main window, called upon loading a replay
QObject::connect(ui->sliderFrames, SIGNAL(valueChanged(int)), kp, SLOT(setFrame(int)));

Таким образом, перемещение ползунка действительно отображает соответствующий кадр.


person jaho    schedule 04.12.2012    source источник


Ответы (1)


Что ж, конечно, это происходит... вы находитесь в жестком цикле в потоке GUI, который никогда не передает управление насосу сообщений, пока цикл не закончится! :-)

Возможно, будет возможно синхронно вызвать какую-то функцию обновления вашего виджета после updateFrame(), и вы сможете посмотреть воспроизведение... но графический интерфейс все равно будет заморожен w.r.t. кнопки, которые вы, возможно, захотите нажать (например, "пауза").

Вместо этого рассмотрите возможность использования таймера, чтобы поток GUI мог запускать насос сообщений между кадрами:

http://doc.qt.digia.com/qt/qtimer.html

person HostileFork says dont trust SE    schedule 04.12.2012
comment
Объект Player выполняется в отдельном потоке, поэтому я понимаю, что он будет выдавать colorFrameEvent каждые 33 мс, а между ними поток GUI может делать все, что захочет. Не могли бы вы объяснить немного больше, почему этого не происходит? - person jaho; 05.12.2012
comment
Вы отредактировали свой вопрос с тех пор, как я начал отвечать на него. :) Если пользовательский интерфейс заблокирован, это означает, что ваш насос графического интерфейса не работает. Вы уверены, что Player::play НЕ работает в потоке GUI? Убедились ли вы, что ваша привязка потока верна? Проверьте, распечатав идентификаторы потоков, с которыми вы работаете, чтобы убедиться, что все работает в потоках, которые вы ожидаете. - person HostileFork says dont trust SE; 05.12.2012
comment
Конечно, ты был прав. Очевидно, что только то, что находится внутри метода Player::run(), выполняется в отдельном потоке. Я как-то вообразил, что после вызова Player::start() объект просто сядет в свой поток и будет ждать сигналов от потока графического интерфейса... Так что теперь я могу заставить его работать с еще одним потоком (подобным таймеру), но как я мог сделать так, чтобы слот Player::play() выполнялся в отдельном потоке, когда on_btnPlay_clicked() выдается из графического интерфейса? Большое спасибо. - person jaho; 05.12.2012
comment
@Marian Прочтите, что я связал о moveToThread, но ... мои инстинкты говорят, что попытка создать поток обновления кадров на основе msleep на самом деле не то, что вам нужно. Тем не менее, практическое мультимедиа всегда было для меня минным полем, и именно поэтому мне нравится жить на более глубоких уровнях стека. :-/ Если вы обнаружите, что заново изобретаете колесо видеоплеера, вы можете задать более общий вопрос и получить совет от людей, которые более информированы о практической стороне теории и практики различия с видео, чем я. - person HostileFork says dont trust SE; 05.12.2012