mirror of
https://github.com/wang-bin/QtAV.git
synced 2026-10-28 11:07:07 +08:00
allow null a/v thread. demux thread exits only when a/v thread exits
TODO: if demuxer read the eof packet, then it will not get that again if seek again, why? miss resetting something?
This commit is contained in:
+110
-35
@@ -75,23 +75,41 @@ void AVDemuxThread::setDemuxer(AVDemuxer *dmx)
|
||||
|
||||
void AVDemuxThread::setAudioThread(AVThread *thread)
|
||||
{
|
||||
if (audio_thread == thread)
|
||||
return;
|
||||
if (audio_thread) {
|
||||
audio_thread->stop();
|
||||
if (audio_thread->isRunning())
|
||||
audio_thread->stop();
|
||||
disconnect(audio_thread, SIGNAL(terminated()), this, SLOT(notifyEnd()));
|
||||
disconnect(audio_thread, SIGNAL(finished()), this, SLOT(notifyEnd()));
|
||||
delete audio_thread;
|
||||
audio_thread = 0;
|
||||
}
|
||||
if (!thread)
|
||||
return;
|
||||
audio_thread = thread;
|
||||
connect(audio_thread, SIGNAL(terminated()), this, SLOT(notifyEnd()), Qt::DirectConnection);
|
||||
connect(audio_thread, SIGNAL(finished()), this, SLOT(notifyEnd()), Qt::DirectConnection);
|
||||
audio_thread->packetQueue()->setEmptyCallback(new QueueEmptyCall(this));
|
||||
}
|
||||
|
||||
void AVDemuxThread::setVideoThread(AVThread *thread)
|
||||
{
|
||||
if (video_thread == thread)
|
||||
return;
|
||||
if (video_thread) {
|
||||
video_thread->stop();
|
||||
if (video_thread->isRunning())
|
||||
video_thread->stop();
|
||||
disconnect(video_thread, SIGNAL(terminated()), this, SLOT(notifyEnd()));
|
||||
disconnect(video_thread, SIGNAL(finished()), this, SLOT(notifyEnd()));
|
||||
delete video_thread;
|
||||
video_thread = 0;
|
||||
}
|
||||
if (!thread)
|
||||
return;
|
||||
video_thread = thread;
|
||||
connect(video_thread, SIGNAL(terminated()), this, SLOT(notifyEnd()), Qt::DirectConnection);
|
||||
connect(video_thread, SIGNAL(finished()), this, SLOT(notifyEnd()), Qt::DirectConnection);
|
||||
video_thread->packetQueue()->setEmptyCallback(new QueueEmptyCall(this));
|
||||
}
|
||||
|
||||
@@ -107,58 +125,89 @@ AVThread* AVDemuxThread::audioThread()
|
||||
|
||||
void AVDemuxThread::seek(qreal pos)
|
||||
{
|
||||
qDebug("demux thread start to seek...");
|
||||
seeking = true;
|
||||
audio_thread->packetQueue()->clear();
|
||||
video_thread->packetQueue()->clear();
|
||||
end = false;
|
||||
if (audio_thread) {
|
||||
audio_thread->setDemuxEnded(false);
|
||||
audio_thread->packetQueue()->clear();
|
||||
}
|
||||
if (video_thread) {
|
||||
video_thread->setDemuxEnded(false);
|
||||
video_thread->packetQueue()->clear();
|
||||
}
|
||||
demuxer->seek(pos);
|
||||
seeking = false;
|
||||
seek_cond.wakeAll();
|
||||
if (isPaused()) {
|
||||
pause(false);
|
||||
video_thread->pause(false);
|
||||
AVThread *avthread = video_thread;
|
||||
if (!avthread)
|
||||
avthread = audio_thread;
|
||||
avthread->pause(false);
|
||||
QEventLoop loop;
|
||||
QTimer::singleShot(40, &loop, SLOT(quit()));
|
||||
loop.exec();
|
||||
pause(true);
|
||||
video_thread->pause(true);
|
||||
avthread->pause(true);
|
||||
}
|
||||
}
|
||||
|
||||
void AVDemuxThread::seekForward()
|
||||
{
|
||||
seeking = true;
|
||||
audio_thread->packetQueue()->clear();
|
||||
video_thread->packetQueue()->clear();
|
||||
end = false;
|
||||
if (audio_thread) {
|
||||
audio_thread->setDemuxEnded(false);
|
||||
audio_thread->packetQueue()->clear();
|
||||
}
|
||||
if (video_thread) {
|
||||
video_thread->setDemuxEnded(false);
|
||||
video_thread->packetQueue()->clear();
|
||||
}
|
||||
demuxer->seekForward();
|
||||
seeking = false;
|
||||
seek_cond.wakeAll();
|
||||
if (isPaused()) {
|
||||
pause(false);
|
||||
video_thread->pause(false);
|
||||
AVThread *avthread = video_thread;
|
||||
if (!avthread)
|
||||
avthread = audio_thread;
|
||||
avthread->pause(false);
|
||||
QEventLoop loop;
|
||||
QTimer::singleShot(40, &loop, SLOT(quit()));
|
||||
loop.exec();
|
||||
pause(true);
|
||||
video_thread->pause(true);
|
||||
avthread->pause(true);
|
||||
}
|
||||
}
|
||||
|
||||
void AVDemuxThread::seekBackward()
|
||||
{
|
||||
seeking = true;
|
||||
audio_thread->packetQueue()->clear();
|
||||
video_thread->packetQueue()->clear();
|
||||
end = false;
|
||||
if (audio_thread) {
|
||||
audio_thread->setDemuxEnded(false);
|
||||
audio_thread->packetQueue()->clear();
|
||||
}
|
||||
if (video_thread) {
|
||||
video_thread->setDemuxEnded(false);
|
||||
video_thread->packetQueue()->clear();
|
||||
}
|
||||
demuxer->seekBackward();
|
||||
seeking = false;
|
||||
seek_cond.wakeAll();
|
||||
if (isPaused()) {
|
||||
pause(false);
|
||||
video_thread->pause(false);
|
||||
AVThread *avthread = video_thread;
|
||||
if (!avthread)
|
||||
avthread = audio_thread;
|
||||
avthread->pause(false);
|
||||
QEventLoop loop;
|
||||
QTimer::singleShot(40, &loop, SLOT(quit()));
|
||||
loop.exec();
|
||||
pause(true);
|
||||
video_thread->pause(true);
|
||||
avthread->pause(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,16 +227,22 @@ void AVDemuxThread::stop()
|
||||
qDebug("void AVDemuxThread::stop()");
|
||||
end = true;
|
||||
//this will not affect the pause state if we pause the output
|
||||
audio_thread->setDemuxEnded(true);
|
||||
video_thread->setDemuxEnded(true);
|
||||
//TODO: why remove the following 2 lines can not play another file?
|
||||
audio_thread->packetQueue()->blockFull(false); //??
|
||||
video_thread->packetQueue()->blockFull(false); //?
|
||||
//TODO: why remove blockFull(false) can not play another file?
|
||||
if (audio_thread) {
|
||||
audio_thread->setDemuxEnded(true);
|
||||
audio_thread->packetQueue()->blockFull(false); //??
|
||||
}
|
||||
if (video_thread) {
|
||||
video_thread->setDemuxEnded(false);
|
||||
video_thread->packetQueue()->clear();
|
||||
video_thread->packetQueue()->blockFull(false); //?
|
||||
}
|
||||
pause(false);
|
||||
}
|
||||
|
||||
void AVDemuxThread::pause(bool p)
|
||||
{
|
||||
qDebug("demux thread pause %d", p);
|
||||
if (paused == p)
|
||||
return;
|
||||
paused = p;
|
||||
@@ -195,34 +250,50 @@ void AVDemuxThread::pause(bool p)
|
||||
cond.wakeAll();
|
||||
}
|
||||
|
||||
void AVDemuxThread::notifyEnd()
|
||||
{
|
||||
qDebug("avthread end. notify demux thread<<<<<<");
|
||||
end = true;
|
||||
seek_cond.wakeAll();
|
||||
cond.wakeAll();
|
||||
}
|
||||
|
||||
void AVDemuxThread::run()
|
||||
{
|
||||
qDebug("demux thread start running...");
|
||||
end = false;
|
||||
//TODO: no video thread is ok
|
||||
Q_ASSERT(audio_thread != 0);
|
||||
Q_ASSERT(video_thread != 0);
|
||||
if (!audio_thread->isRunning())
|
||||
if (audio_thread && !audio_thread->isRunning())
|
||||
audio_thread->start(QThread::HighPriority);
|
||||
if (!video_thread->isRunning())
|
||||
if (video_thread && !video_thread->isRunning())
|
||||
video_thread->start();
|
||||
|
||||
audio_stream = demuxer->audioStream();
|
||||
video_stream = demuxer->videoStream();
|
||||
int index = 0;
|
||||
Packet pkt;
|
||||
end = false;
|
||||
pause(false);
|
||||
PacketQueue *aqueue = audio_thread->packetQueue();
|
||||
PacketQueue *vqueue = video_thread->packetQueue();
|
||||
aqueue->setBlocking(true);
|
||||
vqueue->setBlocking(true);
|
||||
bool _has_audio = audio_thread->decoder()->isAvailable();
|
||||
bool _has_video = video_thread->decoder()->isAvailable();
|
||||
while (!end) {
|
||||
qDebug("get av queue");
|
||||
PacketQueue *aqueue = audio_thread ? audio_thread->packetQueue() : 0;
|
||||
PacketQueue *vqueue = video_thread ? video_thread->packetQueue() : 0;
|
||||
if (aqueue)
|
||||
aqueue->setBlocking(true);
|
||||
if (vqueue)
|
||||
vqueue->setBlocking(true);
|
||||
while (true) {
|
||||
if (tryPause())
|
||||
continue; //the queue is empty and will block
|
||||
QMutexLocker locker(&buffer_mutex);
|
||||
Q_UNUSED(locker);
|
||||
if (end) {
|
||||
if ((audio_thread && audio_thread->isRunning())
|
||||
|| (video_thread && video_thread->isRunning())) {
|
||||
qDebug("demux read end but avthread still running. waiting for finish...");
|
||||
seek_cond.wait(&buffer_mutex);
|
||||
}
|
||||
if (end)
|
||||
break;
|
||||
}
|
||||
if (seeking) {
|
||||
qDebug("Demuxer is seeking... wait for seek end");
|
||||
if (!seek_cond.wait(&buffer_mutex, 1000)) { //will return the same state(i.e. lock)
|
||||
@@ -255,13 +326,17 @@ void AVDemuxThread::run()
|
||||
/* if vqueue if not blocked and full, and aqueue is empty, then put to
|
||||
* vqueue will block demuex thread
|
||||
*/
|
||||
if (_has_video)
|
||||
if (aqueue) {
|
||||
qDebug("put aqueue");
|
||||
aqueue->blockFull(vqueue->size() >= vqueue->threshold());
|
||||
aqueue->put(pkt); //affect video_thread
|
||||
aqueue->put(pkt); //affect video_thread
|
||||
}
|
||||
} else if (index == video_stream) {
|
||||
if (_has_audio)
|
||||
if (vqueue) {
|
||||
qDebug("put vqueue");
|
||||
vqueue->blockFull(aqueue->size() >= aqueue->threshold());
|
||||
vqueue->put(pkt); //affect audio_thread
|
||||
vqueue->put(pkt); //affect audio_thread
|
||||
}
|
||||
} else { //subtitle
|
||||
continue;
|
||||
}
|
||||
|
||||
+1
-1
@@ -344,7 +344,7 @@ bool AVDemuxer::loadFile(const QString &fileName)
|
||||
|
||||
if (ret < 0) {
|
||||
//if (avformat_open_input(&format_context, qPrintable(filename), NULL, NULL)) {
|
||||
qWarning("Can't open video: %s", av_err2str(ret));
|
||||
qWarning("Can't open media: %s", av_err2str(ret));
|
||||
return false;
|
||||
}
|
||||
format_context->flags |= AVFMT_FLAG_GENPTS;
|
||||
|
||||
+105
-41
@@ -53,6 +53,10 @@ namespace QtAV {
|
||||
|
||||
AVPlayer::AVPlayer(QObject *parent) :
|
||||
QObject(parent),loaded(false),capture_dir("capture"),_renderer(0),_audio(0)
|
||||
, audio_dec(0)
|
||||
, video_dec(0)
|
||||
, audio_thread(0)
|
||||
, video_thread(0)
|
||||
, event_filter(0),video_capture(0)
|
||||
{
|
||||
qDebug("%s", aboutQtAV_PlainText().toUtf8().constData());
|
||||
@@ -65,33 +69,9 @@ AVPlayer::AVPlayer(QObject *parent) :
|
||||
//clock->setClockType(AVClock::ExternalClock);
|
||||
demuxer.setClock(clock);
|
||||
connect(&demuxer, SIGNAL(started()), clock, SLOT(start()));
|
||||
#if HAVE_OPENAL
|
||||
_audio = new AOOpenAL();
|
||||
#elif HAVE_PORTAUDIO
|
||||
_audio = new AOPortAudio();
|
||||
#endif
|
||||
if (_audio) {
|
||||
_audio->setStatistics(&mStatistics);
|
||||
}
|
||||
audio_dec = new AudioDecoder();
|
||||
audio_thread = new AudioThread(this);
|
||||
audio_thread->setClock(clock);
|
||||
//audio_thread->setPacketQueue(&audio_queue);
|
||||
audio_thread->setDecoder(audio_dec);
|
||||
audio_thread->setOutput(_audio);
|
||||
audio_thread->setStatistics(&mStatistics);
|
||||
|
||||
video_dec = new VideoDecoder();
|
||||
|
||||
video_thread = new VideoThread(this);
|
||||
video_thread->setClock(clock);
|
||||
video_thread->setDecoder(video_dec);
|
||||
video_thread->setStatistics(&mStatistics);
|
||||
|
||||
demuxer_thread = new AVDemuxThread(this);
|
||||
demuxer_thread->setDemuxer(&demuxer);
|
||||
demuxer_thread->setAudioThread(audio_thread);
|
||||
demuxer_thread->setVideoThread(video_thread);
|
||||
|
||||
setPlayerEventFilter(new EventFilter(this));
|
||||
setVideoCapture(new VideoCapture());
|
||||
@@ -122,13 +102,23 @@ AVClock* AVPlayer::masterClock()
|
||||
//TODO: check components compatiblity(also when change the filter chain)
|
||||
VideoRenderer* AVPlayer::setRenderer(VideoRenderer *r)
|
||||
{
|
||||
qDebug(">>>>>>>>>>>>>>>AVPlayer::setRenderer");
|
||||
if (r == _renderer) {
|
||||
qDebug("renderer not changed");
|
||||
if (video_thread && video_thread->output() == r)
|
||||
return 0;
|
||||
}
|
||||
VideoRenderer *old = _renderer;
|
||||
_renderer = r;
|
||||
if (!video_thread) {
|
||||
qDebug("video thread not ready. can not set output.");
|
||||
return 0;
|
||||
}
|
||||
//FIXME: what if isPaused()==false but pause(true) in another thread?
|
||||
bool need_lock = isPlaying() && !video_thread->isPaused();
|
||||
if (need_lock)
|
||||
video_thread->lock();
|
||||
|
||||
qDebug("set video thread renderer");
|
||||
video_thread->setOutput(_renderer);
|
||||
if (_renderer) {
|
||||
_renderer->setStatistics(&mStatistics);
|
||||
@@ -136,6 +126,7 @@ VideoRenderer* AVPlayer::setRenderer(VideoRenderer *r)
|
||||
video_thread->unlock();
|
||||
_renderer->resizeRenderer(_renderer->rendererSize()); //IMPORTANT: the swscaler will resize
|
||||
}
|
||||
//old may be in stack. do not delete here
|
||||
return old;
|
||||
}
|
||||
|
||||
@@ -144,6 +135,11 @@ VideoRenderer *AVPlayer::renderer()
|
||||
return _renderer;
|
||||
}
|
||||
|
||||
AudioOutput* AVPlayer::setAudioOutput(AudioOutput* ao)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
AudioOutput* AVPlayer::audio()
|
||||
{
|
||||
return _audio;
|
||||
@@ -210,7 +206,6 @@ VideoCapture* AVPlayer::setVideoCapture(VideoCapture *cap)
|
||||
{
|
||||
VideoCapture *old = video_capture;
|
||||
video_capture = cap;
|
||||
video_thread->setVideoCapture(video_capture);
|
||||
return old;
|
||||
}
|
||||
|
||||
@@ -231,7 +226,7 @@ void AVPlayer::setCaptureSaveDir(const QString &dir)
|
||||
|
||||
bool AVPlayer::captureVideo()
|
||||
{
|
||||
if (!video_capture)
|
||||
if (!video_capture || !video_thread)
|
||||
return false;
|
||||
bool pause_old = isPaused();
|
||||
if (!video_capture->isAsync())
|
||||
@@ -260,7 +255,9 @@ bool AVPlayer::play(const QString& path)
|
||||
|
||||
bool AVPlayer::isPlaying() const
|
||||
{
|
||||
return demuxer_thread->isRunning() || audio_thread->isRunning() || video_thread->isRunning();
|
||||
return (demuxer_thread &&demuxer_thread->isRunning())
|
||||
|| (audio_thread && audio_thread->isRunning())
|
||||
|| (video_thread && video_thread->isRunning());
|
||||
}
|
||||
|
||||
void AVPlayer::togglePause()
|
||||
@@ -327,15 +324,77 @@ bool AVPlayer::load()
|
||||
formatCtx = demuxer.formatContext();
|
||||
aCodecCtx = demuxer.audioCodecContext();
|
||||
vCodecCtx = demuxer.videoCodecContext();
|
||||
if (_audio && aCodecCtx) {
|
||||
if (aCodecCtx) {
|
||||
qDebug("has audio");
|
||||
if (!audio_dec) {
|
||||
audio_dec = new AudioDecoder();
|
||||
}
|
||||
qDebug("setCodecContext");
|
||||
audio_dec->setCodecContext(aCodecCtx);
|
||||
//TODO: setAudioOutput() like vo
|
||||
if (!_audio) {
|
||||
qDebug("new audio output");
|
||||
#if HAVE_OPENAL
|
||||
_audio = new AOOpenAL();
|
||||
#elif HAVE_PORTAUDIO
|
||||
_audio = new AOPortAudio();
|
||||
#endif
|
||||
_audio->setStatistics(&mStatistics);
|
||||
}
|
||||
_audio->setSampleRate(aCodecCtx->sample_rate);
|
||||
_audio->setChannels(aCodecCtx->channels);
|
||||
if (!_audio->open()) {
|
||||
//return; //audio not ready
|
||||
}
|
||||
if (!audio_thread) {
|
||||
qDebug("new audio thread");
|
||||
audio_thread = new AudioThread(this);
|
||||
audio_thread->setClock(clock);
|
||||
//audio_thread->setPacketQueue(&audio_queue);
|
||||
audio_thread->setDecoder(audio_dec);
|
||||
audio_thread->setOutput(_audio);
|
||||
audio_thread->setStatistics(&mStatistics);
|
||||
}
|
||||
} else {
|
||||
//releaseAudioResource()
|
||||
if (audio_thread) {
|
||||
audio_thread->terminate();
|
||||
delete audio_thread;
|
||||
audio_thread = 0;
|
||||
}
|
||||
if (audio_dec) {
|
||||
delete audio_dec;
|
||||
audio_dec = 0;
|
||||
}
|
||||
//DO NOT delete AVOutput. it is setted by user
|
||||
}
|
||||
audio_dec->setCodecContext(aCodecCtx);
|
||||
video_dec->setCodecContext(vCodecCtx);
|
||||
qDebug("demux thread setAudioThread");
|
||||
demuxer_thread->setAudioThread(audio_thread);
|
||||
if (vCodecCtx) {
|
||||
if (!video_dec) {
|
||||
video_dec = new VideoDecoder();
|
||||
}
|
||||
video_dec->setCodecContext(vCodecCtx);
|
||||
if (!video_thread) {
|
||||
video_thread = new VideoThread(this);
|
||||
video_thread->setClock(clock);
|
||||
video_thread->setDecoder(video_dec);
|
||||
video_thread->setVideoCapture(video_capture);
|
||||
}
|
||||
setRenderer(_renderer);
|
||||
} else {
|
||||
if (video_thread) {
|
||||
video_thread->terminate();
|
||||
delete video_thread;
|
||||
video_thread = 0;
|
||||
}
|
||||
if (video_dec) {
|
||||
delete video_dec;
|
||||
video_dec = 0;
|
||||
}
|
||||
//DO NOT delete AVOutput. it is setted by user
|
||||
}
|
||||
demuxer_thread->setVideoThread(video_thread);
|
||||
//TODO: init statistics
|
||||
return loaded;
|
||||
}
|
||||
@@ -374,19 +433,19 @@ void AVPlayer::play()
|
||||
int queue_min = 0.61803*qMax<qreal>(24.0, mStatistics.video.fps);
|
||||
int queue_max = int(1.61803*(qreal)queue_min); //about 1 second
|
||||
if (vCodecCtx) {
|
||||
connect(video_thread, SIGNAL(finished()), this, SIGNAL(stopped()), Qt::DirectConnection);
|
||||
video_thread->packetQueue()->setThreshold(queue_min);
|
||||
video_thread->packetQueue()->setCapacity(queue_max);
|
||||
qDebug("Starting video thread...");
|
||||
video_thread->start();
|
||||
connect(video_thread, SIGNAL(finished()), this, SIGNAL(stopped()), Qt::DirectConnection);
|
||||
}
|
||||
if (aCodecCtx) {
|
||||
if (!vCodecCtx) //avoid emit stopped() mulltiple times
|
||||
connect(audio_thread, SIGNAL(finished()), this, SIGNAL(stopped()), Qt::DirectConnection);
|
||||
audio_thread->packetQueue()->setThreshold(queue_min);
|
||||
audio_thread->packetQueue()->setCapacity(queue_max);
|
||||
qDebug("Starting audio thread...");
|
||||
audio_thread->start(QThread::HighestPriority);
|
||||
if (!vCodecCtx) //avoid emit stopped() mulltiple times
|
||||
connect(audio_thread, SIGNAL(finished()), this, SIGNAL(stopped()), Qt::DirectConnection);
|
||||
audio_thread->start();
|
||||
}
|
||||
demuxer_thread->start();
|
||||
//blockSignals(false);
|
||||
@@ -398,8 +457,10 @@ void AVPlayer::stop()
|
||||
if (!isPlaying())
|
||||
return;
|
||||
qDebug("AVPlayer::stop");
|
||||
disconnect(video_thread, SIGNAL(finished()), this, SIGNAL(stopped()));
|
||||
disconnect(audio_thread, SIGNAL(finished()), this, SIGNAL(stopped()));
|
||||
if (video_thread)
|
||||
disconnect(video_thread, SIGNAL(finished()), this, SIGNAL(stopped()));
|
||||
if (audio_thread)
|
||||
disconnect(audio_thread, SIGNAL(finished()), this, SIGNAL(stopped()));
|
||||
//blockSignals(true); //TODO: move emit stopped() before it. or connect avthread.finished() to tryEmitStop() {if (!called_by_stop) emit}
|
||||
if (demuxer_thread->isRunning()) {
|
||||
qDebug("stop d");
|
||||
@@ -410,7 +471,7 @@ void AVPlayer::stop()
|
||||
demuxer_thread->terminate(); //Terminate() causes the wait condition destroyed without waking up
|
||||
}
|
||||
}
|
||||
if (audio_thread->isRunning()) {
|
||||
if (audio_thread && audio_thread->isRunning()) {
|
||||
qDebug("stop a");
|
||||
audio_thread->stop();
|
||||
if (!audio_thread->wait(1000)) {
|
||||
@@ -418,7 +479,7 @@ void AVPlayer::stop()
|
||||
audio_thread->terminate();
|
||||
}
|
||||
}
|
||||
if (video_thread->isRunning()) {
|
||||
if (video_thread && video_thread->isRunning()) {
|
||||
qDebug("stopv");
|
||||
video_thread->stop();
|
||||
if (!video_thread->wait(1000)) {
|
||||
@@ -427,6 +488,7 @@ void AVPlayer::stop()
|
||||
}
|
||||
}
|
||||
//TODO: why AVThread not trigger the signal?
|
||||
qDebug("demux thread, avthreads stopped...");
|
||||
emit stopped();
|
||||
}
|
||||
//FIXME: If not playing, it will just play but not play one frame.
|
||||
@@ -437,8 +499,10 @@ void AVPlayer::playNextFrame()
|
||||
}
|
||||
demuxer_thread->pause(false);
|
||||
clock->pause(false);
|
||||
audio_thread->nextAndPause();
|
||||
video_thread->nextAndPause();
|
||||
if (audio_thread)
|
||||
audio_thread->nextAndPause();
|
||||
if (video_thread)
|
||||
video_thread->nextAndPause();
|
||||
clock->pause(true);
|
||||
demuxer_thread->pause(true);
|
||||
}
|
||||
|
||||
@@ -73,6 +73,7 @@ void AudioThread::run()
|
||||
if (d.packets.isEmpty() && !d.stop) {
|
||||
d.stop = d.demux_end;
|
||||
if (d.stop) {
|
||||
qDebug("audio queue empty and demux end. break audio thread");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,6 +51,8 @@ public:
|
||||
public slots:
|
||||
void stop();
|
||||
void pause(bool p);
|
||||
private slots:
|
||||
void notifyEnd();
|
||||
|
||||
protected:
|
||||
virtual void run();
|
||||
|
||||
@@ -48,6 +48,15 @@ class Q_EXPORT AVDemuxer : public QObject //QIODevice?
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum SeekFlag {
|
||||
SeekByByte,
|
||||
SeekByTime
|
||||
};
|
||||
enum SeekFrame {
|
||||
SeekIframe,
|
||||
SeekAnyFrame
|
||||
};
|
||||
|
||||
AVDemuxer(const QString& fileName = QString(), QObject *parent = 0);
|
||||
~AVDemuxer();
|
||||
|
||||
|
||||
@@ -69,6 +69,7 @@ public:
|
||||
//TODO: addRenderer; renderers()
|
||||
VideoRenderer* setRenderer(VideoRenderer* renderer);
|
||||
VideoRenderer* renderer();
|
||||
AudioOutput* setAudioOutput(AudioOutput* ao);
|
||||
AudioOutput* audio();
|
||||
void setMute(bool mute);
|
||||
bool isMute() const;
|
||||
|
||||
@@ -101,6 +101,7 @@ void VideoThread::run()
|
||||
if (d.packets.isEmpty() && !d.stop) {
|
||||
d.stop = d.demux_end;
|
||||
if (d.stop) {
|
||||
qDebug("video queue empty and demux end. break video thread");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user