Files
fmviewer3/project/fm_viewer/fav/AVOutput.cpp
2026-02-21 17:11:31 +09:00

190 lines
4.7 KiB
C++

/******************************************************************************
QtAV: Multimedia framework based on Qt and FFmpeg
Copyright (C) 2012-2016 Wang Bin <wbsecg1@gmail.com>
* This file is part of QtAV
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
******************************************************************************/
#include "AVOutput.h"
#include "AVOutput_p.h"
#include "Filter.h"
#include "FilterContext.h"
#include "FilterManager.h"
#include "OutputSet.h"
#include "Logger.h"
namespace FAV {
AVOutputPrivate::~AVOutputPrivate() {
cond.wakeAll(); //WHY: failed to wake up
}
AVOutput::AVOutput()
{
}
AVOutput::AVOutput(AVOutputPrivate &d)
:DPTR_INIT(&d)
{
}
AVOutput::~AVOutput()
{
pause(false); //Does not work. cond may still waiting when destroyed
detach();
DPTR_D(AVOutput);
if (d.filter_context) {
delete d.filter_context;
d.filter_context = 0;
}
foreach (Filter *f, d.pending_uninstall_filters) {
d.filters.removeAll(f);
}
QList<Filter*>::iterator it = d.filters.begin();
while (it != d.filters.end()) {
// if not uninstall here, if AVOutput is also an QObject (for example, widget based renderers)
// then qobject children filters will be deleted when parent is destroying and call FilterManager::uninstallFilter()
// and FilterManager::instance().unregisterFilter(filter, this) too late that AVOutput is almost be destroyed
uninstallFilter(*it);
// 1 filter has 1 target. so if has output filter in manager, the output is this output
/*FilterManager::instance().hasOutputFilter(*it) && */
if ((*it)->isOwnedByTarget() && !(*it)->parent())
delete *it;
++it;
}
d.filters.clear();
}
bool AVOutput::isAvailable() const
{
return d_func().available;
}
void AVOutput::pause(bool p)
{
DPTR_D(AVOutput);
if (d.paused == p)
return;
d.paused = p;
}
bool AVOutput::isPaused() const
{
return d_func().paused;
}
//TODO: how to call this automatically before write()?
bool AVOutput::tryPause()
{
DPTR_D(AVOutput);
if (!d.paused)
return false;
QMutexLocker lock(&d.mutex);
Q_UNUSED(lock);
d.cond.wait(&d.mutex);
return true;
}
void AVOutput::addOutputSet(OutputSet *set)
{
d_func().output_sets.append(set);
}
void AVOutput::removeOutputSet(OutputSet *set)
{
d_func().output_sets.removeAll(set);
}
void AVOutput::attach(OutputSet *set)
{
set->addOutput(this);
}
void AVOutput::detach(OutputSet *set)
{
DPTR_D(AVOutput);
if (set) {
set->removeOutput(this);
return;
}
foreach(OutputSet *set, d.output_sets) {
set->removeOutput(this);
}
}
QList<Filter*>& AVOutput::filters()
{
return d_func().filters;
}
void AVOutput::setStatistics(Statistics *statistics)
{
DPTR_D(AVOutput);
d.statistics = statistics;
}
bool AVOutput::installFilter(Filter *filter, int index)
{
return onInstallFilter(filter, index);
}
bool AVOutput::onInstallFilter(Filter *filter, int index)
{
if (!FilterManager::instance().registerFilter(filter, this, index)) {
return false;
}
DPTR_D(AVOutput);
d.filters = FilterManager::instance().outputFilters(this);
return true;
}
/*
* FIXME: how to ensure thread safe using mutex etc? for a video filter, both are in main thread.
* an audio filter on audio output may be in audio thread
*/
bool AVOutput::uninstallFilter(Filter *filter)
{
return onUninstallFilter(filter);
}
bool AVOutput::onUninstallFilter(Filter *filter)
{
DPTR_D(AVOutput);
FilterManager::instance().unregisterFilter(filter, this);
d.pending_uninstall_filters.push_back(filter);
return true;
}
void AVOutput::hanlePendingTasks()
{
onHanlePendingTasks();
}
bool AVOutput::onHanlePendingTasks()
{
DPTR_D(AVOutput);
if (d.pending_uninstall_filters.isEmpty())
return false;
foreach (Filter *filter, d.pending_uninstall_filters) {
d.filters.removeAll(filter);
}
d.pending_uninstall_filters.clear();
return true;
}
} //namespace FAV