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

219 lines
5.3 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 (from 2015)
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 "AVEncoder.h"
#if !(REMOVE_AV_ENCODER)
#include "AVEncoder_p.h"
#include "version.h"
#include "internal.h"
#include "Logger.h"
namespace FAV {
AVEncoder::AVEncoder(AVEncoderPrivate &d)
:DPTR_INIT(&d)
{
}
AVEncoder::~AVEncoder()
{
close();
}
QString AVEncoder::description() const
{
return QString();
}
void AVEncoder::setCodecName(const QString &name)
{
DPTR_D(AVEncoder);
if (d.codec_name == name)
return;
d.codec_name = name;
Q_EMIT codecNameChanged();
}
QString AVEncoder::codecName() const
{
DPTR_D(const AVEncoder);
if (!d.codec_name.isEmpty())
return d.codec_name;
if (d.avctx)
return QLatin1String(avcodec_get_name(d.avctx->codec_id));
return QString();
}
void AVEncoder::setBitRate(int value)
{
DPTR_D(AVEncoder);
if (d.bit_rate == value)
return;
d.bit_rate = value;
emit bitRateChanged();
}
int AVEncoder::bitRate() const
{
return d_func().bit_rate;
}
AVEncoder::TimestampMode AVEncoder::timestampMode() const
{
return TimestampMode(d_func().timestamp_mode);
}
void AVEncoder::setTimestampMode(TimestampMode value)
{
DPTR_D(AVEncoder);
if (d.timestamp_mode == (int)value)
return;
d.timestamp_mode = (int)value;
Q_EMIT timestampModeChanged(value);
}
bool AVEncoder::open()
{
DPTR_D(AVEncoder);
if (d.avctx) {
d.applyOptionsForDict();
}
if (!d.open()) {
d.close();
return false;
}
d.is_open = true;
return true;
}
bool AVEncoder::close()
{
if (!isOpen()) {
return true;
}
DPTR_D(AVEncoder);
d.is_open = false;
// hwa extra finalize can be here
d.close();
return true;
}
bool AVEncoder::isOpen() const
{
return d_func().is_open;
}
void AVEncoder::flush()
{
if (!isOpen())
return;
if (d_func().avctx)
avcodec_flush_buffers(d_func().avctx);
}
Packet AVEncoder::encoded() const
{
return d_func().packet;
}
void* AVEncoder::codecContext() const
{
return d_func().avctx;
}
void AVEncoder::copyAVCodecContext(void* ctx)
{
if (!ctx)
return;
DPTR_D(AVEncoder);
AVCodecContext* c = static_cast<AVCodecContext*>(ctx);
if (d.avctx) {
// dest should be avcodec_alloc_context3(NULL)
AV_ENSURE_OK(avcodec_copy_context(d.avctx, c));
d.is_open = false;
return;
}
}
void AVEncoder::setOptions(const QVariantHash &dict)
{
DPTR_D(AVEncoder);
d.options = dict;
// if dict is empty, can not return here, default options will be set for AVCodecContext
// apply to AVCodecContext
d.applyOptionsForContext();
/* set AVEncoder meta properties.
* we do not check whether the property exists thus we can set dynamic properties.
*/
if (dict.isEmpty())
return;
if (name() == QLatin1String("avcodec"))
return;
QVariant opt(dict);
if (dict.contains(name()))
opt = dict.value(name());
else if (dict.contains(name().toLower()))
opt = dict.value(name().toLower());
Internal::setOptionsForQObject(opt, this);
}
QVariantHash AVEncoder::options() const
{
return d_func().options;
}
void AVEncoderPrivate::applyOptionsForDict()
{
if (dict) {
av_dict_free(&dict);
dict = 0; //aready 0 in av_free
}
if (options.isEmpty())
return;
qDebug("set AVCodecContext dict:");
// TODO: use QVariantMap only
if (!options.contains(QStringLiteral("avcodec")))
return;
// workaround for VideoDecoderFFmpeg. now it does not call av_opt_set_xxx, so set here in dict
// TODO: wrong if opt is empty
Internal::setOptionsToDict(options.value(QStringLiteral("avcodec")), &dict);
}
void AVEncoderPrivate::applyOptionsForContext()
{
if (!avctx)
return;
if (options.isEmpty()) {
// av_opt_set_defaults(avctx); //can't set default values! result maybe unexpected
return;
}
// TODO: use QVariantMap only
if (!options.contains(QStringLiteral("avcodec")))
return;
// workaround for VideoDecoderFFmpeg. now it does not call av_opt_set_xxx, so set here in dict
// TODO: wrong if opt is empty
Internal::setOptionsToFFmpegObj(options.value(QStringLiteral("avcodec")), avctx);
}
} //namespace FAV
#endif // #if !(REMOVE_AV_ENCODER)