void AVPlayer::stop() { if (!isPlaying()) return; qDebug("AVPlayer::stop"); //blockSignals(true); //TODO: move emit stopped() before it. or connect avthread.finished() to tryEmitStop() {if (!called_by_stop) emit} struct avthreads_t { AVThread *thread; const char *name; } threads[] = { { audio_thread, "audio thread" }, { video_thread, "video thread" }, { 0, 0 } }; for (int i = 0; threads[i].name; ++i) { AVThread *thread = threads[i].thread; if (!thread) continue; if (thread->isRunning()) { qDebug("stopping %s...", threads[i].name); //avoid emit stopped multiple times. AVThread.stopped() connects to AVDemuxThread.stopped(). thread->blockSignals(true); thread->stop(); if (!thread->wait(1000)) { qWarning("Timeout waiting for %s stopped. Terminate it.", threads[i].name); thread->terminate(); } thread->blockSignals(false); } } //stop demux thread after avthread is better. otherwise demux thread may be terminated when waiting for avthread ? if (demuxer_thread->isRunning()) { qDebug("stopping demux thread..."); demuxer_thread->stop(); //wait for finish then we can safely set the vars, e.g. a/v decoders if (!demuxer_thread->wait(1000)) { qWarning("Timeout waiting for demux thread stopped. Terminate it."); demuxer_thread->terminate(); //Terminate() causes the wait condition destroyed without waking up } } qDebug("all threads [a|v|d] stopped..."); emit stopped(); }
//No more data to put. So stop blocking the queue to take the reset elements void AVDemuxThread::stop() { //this will not affect the pause state if we pause the output //TODO: why remove blockFull(false) can not play another file? AVThread* av[] = { audio_thread, video_thread}; for (size_t i = 0; i < sizeof(av)/sizeof(av[0]); ++i) { AVThread* t = av[i]; if (!t) continue; t->packetQueue()->clear(); t->packetQueue()->blockFull(false); //?? while (t->isRunning()) { qDebug() << "stopping thread " << t; t->stop(); t->wait(500); } } pause(false); cond.wakeAll(); qDebug("all avthread finished. try to exit demux thread<<<<<<"); end = true; }