first commit

This commit is contained in:
2026-02-21 17:11:31 +09:00
commit 18b4338361
4001 changed files with 365464 additions and 0 deletions

View File

@@ -0,0 +1,455 @@
/******************************************************************************
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 "_fav_constants.h"
#include <QtCore/QLibraryInfo>
#include <QtCore/QObject>
#include <QtCore/QRegExp>
#include "version.h"
#include "AVCompat.h"
#include "internal.h"
#include "Logger.h"
#if (PLAY_SYNC_FIX2)
#include <QElapsedTimer>
QElapsedTimer g_et;
#endif // #if (PLAY_SYNC_FIX2)
unsigned QtAV_Version()
{
return QTAV_VERSION;
}
QString QtAV_Version_String()
{
// vs<2015: C2308: concatenating mismatched strings for QStringLiteral("a" "b")
return QString::fromLatin1(QTAV_VERSION_STR);
}
#define QTAV_VERSION_STR_LONG QTAV_VERSION_STR "(" __DATE__ ", " __TIME__ ")"
QString QtAV_Version_String_Long()
{
return QString::fromLatin1(QTAV_VERSION_STR_LONG);
}
int g_SkipCount = 0; // none
int g_firstCorruptFrameSkipWait = 10; // 10ms
namespace FAV {
namespace Internal {
// disable logging for release. you can manually enable it.
#if defined(QT_NO_DEBUG)// && !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(Q_OS_WINRT)
static FAV::LogLevel gLogLevel = FAV::LogOff;
#else
static FAV::LogLevel gLogLevel = FAV::LogAll; // LogOff; //LogAll,LogOff;
#endif
static bool gLogLevelSet = false;
bool isLogLevelSet() { return gLogLevelSet;}
static int gAVLogLevel = AV_LOG_ERROR;//AV_LOG_ERROR;//AV_LOG_ERROR, AV_LOG_QUIET;// AV_LOG_TRACE;//AV_LOG_INFO;
} //namespace Internal
//TODO: auto add new depend libraries information
QString aboutFFmpeg_PlainText()
{
return aboutFFmpeg_HTML().remove(QRegExp(QStringLiteral("<[^>]*>")));
}
namespace Internal {
typedef struct depend_component {
const char* lib;
unsigned build_version;
unsigned rt_version;
const char *config;
const char *license;
} depend_component;
static unsigned get_qt_version() {
int major = 0, minor = 0, patch = 0;
if (sscanf(qVersion(), "%d.%d.%d", &major, &minor, &patch) != 3)
qWarning("Can not recognize Qt runtime version");
return QT_VERSION_CHECK(major, minor, patch);
}
static const depend_component* get_depend_component(const depend_component* info = 0)
{
// DO NOT use QStringLiteral here because the install script use strings to search "Qt-" in the library. QStringLiteral will place it in .ro and strings can not find it
static const QByteArray qt_license(QLibraryInfo::licensee().prepend(QLatin1String("Qt-" QT_VERSION_STR " licensee: ")).toUtf8());
#if QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)
static const char* qt_build_info = get_qt_version() >= QT_VERSION_CHECK(5, 3, 0) ? QLibraryInfo::build() : "";
#else
static const char* qt_build_info = "";
#endif
static const depend_component components[] = {
{ "Qt", QT_VERSION, get_qt_version(), qt_build_info, qt_license.constData() },
//TODO: auto check loaded libraries
#define FF_COMPONENT(name, NAME) #name, LIB##NAME##_VERSION_INT, name##_version(), name##_configuration(), name##_license()
{ FF_COMPONENT(avutil, AVUTIL) },
{ FF_COMPONENT(avcodec, AVCODEC) },
{ FF_COMPONENT(avformat, AVFORMAT) },
#if QTAV_HAVE(AVFILTER)
{ FF_COMPONENT(avfilter, AVFILTER) },
#endif //QTAV_HAVE(AVFILTER)
#if QTAV_HAVE(AVDEVICE)
{ FF_COMPONENT(avdevice, AVDEVICE) },
#endif //QTAV_HAVE(AVDEVICE)
#if QTAV_HAVE(AVRESAMPLE)
{ FF_COMPONENT(avresample, AVRESAMPLE) },
#endif //QTAV_HAVE(AVRESAMPLE)
#if QTAV_HAVE(SWRESAMPLE)
{ FF_COMPONENT(swresample, SWRESAMPLE) },
#endif //QTAV_HAVE(SWRESAMPLE)
{ FF_COMPONENT(swscale, SWSCALE) },
#undef FF_COMPONENT
{ 0, 0, 0, 0, 0 }
};
if (!info)
return &components[0];
// invalid input ptr
if (((ptrdiff_t)info - (ptrdiff_t)(&components[0]))%sizeof(depend_component))
return 0;
const depend_component *next = info;
next++;
if (!next->lib)
return 0;
return next;
}
void print_library_info()
{
//qDebug() << aboutQtAV_PlainText().toUtf8().constData();
const depend_component* info = Internal::get_depend_component(0);
while (info) {
if (!qstrcmp(info->lib, "avutil"))
qDebug("FFmpeg/Libav configuration: %s", info->config);
qDebug("Build with %s-%u.%u.%u"
, info->lib
, QTAV_VERSION_MAJOR(info->build_version)
, QTAV_VERSION_MINOR(info->build_version)
, QTAV_VERSION_PATCH(info->build_version)
);
unsigned rt_version = info->rt_version;
if (info->build_version != rt_version) {
qWarning("Warning: %s runtime version %u.%u.%u mismatch!"
, info->lib
, QTAV_VERSION_MAJOR(rt_version)
, QTAV_VERSION_MINOR(rt_version)
, QTAV_VERSION_PATCH(rt_version)
);
}
info = Internal::get_depend_component(info);
}
}
} //namespace Internal
QString aboutFFmpeg_HTML()
{
QString text = QStringLiteral("<h3>FFmpeg/Libav</h3>\n");
const Internal::depend_component* info = Internal::get_depend_component(0);
while (info) {
text += QStringLiteral("<h4>%1: %2-%3.%4.%5</h4>\n")
.arg("Build version")
.arg(QLatin1String(info->lib))
.arg(QTAV_VERSION_MAJOR(info->build_version))
.arg(QTAV_VERSION_MINOR(info->build_version))
.arg(QTAV_VERSION_PATCH(info->build_version))
;
unsigned rt_version = info->rt_version;
if (info->build_version != rt_version) {
text += QStringLiteral("<h4 style='color:#ff0000;'>%1: %2.%3.%4</h4>\n")
.arg("Runtime version")
.arg(QTAV_VERSION_MAJOR(rt_version))
.arg(QTAV_VERSION_MINOR(rt_version))
.arg(QTAV_VERSION_PATCH(rt_version))
;
}
text += QStringLiteral("<p>%1</p>\n<p>%2</p>\n").arg(QString::fromUtf8(info->config)).arg(QString::fromUtf8(info->license));
info = Internal::get_depend_component(info);
}
return text;
}
QString aboutQtAV_PlainText()
{
return aboutQtAV_HTML().remove(QRegExp(QStringLiteral("<[^>]*>")));
}
QString aboutQtAV_HTML()
{
return "";
}
void setLogLevel(LogLevel value)
{
Internal::gLogLevelSet = true;
Internal::gLogLevel = value;
}
LogLevel logLevel()
{
return (LogLevel)Internal::gLogLevel;
}
void setFFmpegLogHandler(void (*callback)(void *, int, const char *, va_list))
{
// libav does not check null callback
if (!callback)
callback = av_log_default_callback;
av_log_set_callback(callback);
}
void setFFmpegLogLevel(const QByteArray &level)
{
if (level.isEmpty())
return;
bool ok = false;
const int value = level.toInt(&ok);
if ((ok && value == 0) || level == "off" || level == "quiet")
Internal::gAVLogLevel = AV_LOG_QUIET;
else if (level == "panic")
Internal::gAVLogLevel = AV_LOG_PANIC;
else if (level == "fatal")
Internal::gAVLogLevel = AV_LOG_FATAL;
else if (level == "error")
Internal::gAVLogLevel = AV_LOG_ERROR;
else if (level.startsWith("warn"))
Internal::gAVLogLevel = AV_LOG_WARNING;
else if (level == "info")
Internal::gAVLogLevel = AV_LOG_INFO;
else if (level == "verbose")
Internal::gAVLogLevel = AV_LOG_VERBOSE;
else if (level == "debug")
Internal::gAVLogLevel = AV_LOG_DEBUG;
#ifdef AV_LOG_TRACE
else if (level == "trace")
Internal::gAVLogLevel = AV_LOG_TRACE;
#endif
else
Internal::gAVLogLevel = AV_LOG_INFO;
av_log_set_level(Internal::gAVLogLevel);
}
static void qtav_ffmpeg_log_callback(void* ctx, int level,const char* fmt, va_list vl)
{
// AV_LOG_DEBUG is used by ffmpeg developers
if (level > Internal::gAVLogLevel)
return;
AVClass *c = ctx ? *(AVClass**)ctx : 0;
QString qmsg = QString().sprintf("[FFmpeg:%s] ", c ? c->item_name(ctx) : "?") + QString().vsprintf(fmt, vl);
qmsg = qmsg.trimmed();
if (level > AV_LOG_WARNING)
qDebug() << qPrintable(qmsg);
else if (level > AV_LOG_PANIC)
qWarning() << qPrintable(qmsg);
}
QString avformatOptions()
{
static QString opts;
if (!opts.isEmpty())
return opts;
void* obj = const_cast<void*>(reinterpret_cast<const void*>(avformat_get_class()));
opts = Internal::optionsToString((void*)&obj);
opts.append(ushort('\n'));
av_register_all();
AVInputFormat *i = NULL;
while ((i = av_iformat_next(i))) {
QString opt(Internal::optionsToString((void*)&i->priv_class).trimmed());
if (opt.isEmpty())
continue;
opts.append(QStringLiteral("options for input format %1:\n%2\n\n")
.arg(QLatin1String(i->name))
.arg(opt));
}
AVOutputFormat *o = NULL;
while ((o = av_oformat_next(o))) {
QString opt(Internal::optionsToString((void*)&o->priv_class).trimmed());
if (opt.isEmpty())
continue;
opts.append(QStringLiteral("options for output format %1:\n%2\n\n")
.arg(QLatin1String(o->name))
.arg(opt));
}
return opts;
}
QString avcodecOptions()
{
static QString opts;
if (!opts.isEmpty())
return opts;
void* obj = const_cast<void*>(reinterpret_cast<const void*>(avcodec_get_class()));
opts = Internal::optionsToString((void*)&obj);
opts.append(ushort('\n'));
avcodec_register_all();
AVCodec* c = NULL;
while ((c=av_codec_next(c))) {
QString opt(Internal::optionsToString((void*)&c->priv_class).trimmed());
if (opt.isEmpty())
continue;
opts.append(QStringLiteral("Options for codec %1:\n%2\n\n").arg(QLatin1String(c->name)).arg(opt));
}
return opts;
}
#if 0
const QStringList& supportedInputMimeTypes()
{
static QStringList mimes;
if (!mimes.isEmpty())
return mimes;
av_register_all(); // MUST register all input/output formats
AVOutputFormat *i = av_oformat_next(NULL);
QStringList list;
while (i) {
list << QString(i->mime_type).split(QLatin1Char(','), QString::SkipEmptyParts);
i = av_oformat_next(i);
}
foreach (const QString& v, list) {
mimes.append(v.trimmed());
}
mimes.removeDuplicates();
return mimes;
}
static QStringList s_audio_mimes, s_video_mimes, s_subtitle_mimes;
static void init_supported_codec_info() {
const AVCodecDescriptor* cd = avcodec_descriptor_next(NULL);
while (cd) {
QStringList list;
if (cd->mime_types) {
for (int i = 0; cd->mime_types[i]; ++i) {
list.append(QString(cd->mime_types[i]).trimmed());
}
}
switch (cd->type) {
case AVMEDIA_TYPE_AUDIO:
s_audio_mimes << list;
break;
case AVMEDIA_TYPE_VIDEO:
s_video_mimes << list;
case AVMEDIA_TYPE_SUBTITLE:
s_subtitle_mimes << list;
default:
break;
}
cd = avcodec_descriptor_next(cd);
}
s_audio_mimes.removeDuplicates();
s_video_mimes.removeDuplicates();
s_subtitle_mimes.removeDuplicates();
}
const QStringList& supportedAudioMimeTypes()
{
if (s_audio_mimes.isEmpty())
init_supported_codec_info();
return s_audio_mimes;
}
const QStringList& supportedVideoMimeTypes()
{
if (s_video_mimes.isEmpty())
init_supported_codec_info();
return s_video_mimes;
}
// TODO: subtitleprocessor support
const QStringList& supportedSubtitleMimeTypes()
{
if (s_subtitle_mimes.isEmpty())
init_supported_codec_info();
return s_subtitle_mimes;
}
#endif
/*
* AVColorSpace:
* libav11 libavutil54.3.0 pixfmt.h, ffmpeg2.1*libavutil52.48.101 frame.h
* ffmpeg2.5 pixfmt.h. AVFrame.colorspace
* earlier versions: avcodec.h, avctx.colorspace
*/
ColorSpace colorSpaceFromFFmpeg(AVColorSpace cs)
{
switch (cs) {
// from ffmpeg: order of coefficients is actually GBR
case AVCOL_SPC_RGB: return ColorSpace_GBR;
case AVCOL_SPC_BT709: return ColorSpace_BT709;
case AVCOL_SPC_BT470BG: return ColorSpace_BT601;
case AVCOL_SPC_SMPTE170M: return ColorSpace_BT601;
default: return ColorSpace_Unknown;
}
}
ColorRange colorRangeFromFFmpeg(AVColorRange cr)
{
switch (cr) {
case AVCOL_RANGE_MPEG: return ColorRange_Limited;
case AVCOL_RANGE_JPEG: return ColorRange_Full;
default: return ColorRange_Unknown;
}
}
namespace
{
static const struct RegisterMetaTypes {
RegisterMetaTypes() {
qRegisterMetaType<FAV::MediaStatus>("FAV::MediaStatus");
}
} _registerMetaTypes;
}
// TODO: static link. move all into 1
namespace {
class InitFFmpegLog {
public:
InitFFmpegLog() {
setFFmpegLogHandler(qtav_ffmpeg_log_callback);
FAV::setFFmpegLogLevel(qgetenv("QTAV_FFMPEG_LOG").toLower());
}
};
InitFFmpegLog fflog;
}
}
// Initialize Qt Resource System when the library is built
// statically
static void initResources() {
#if (PLAYER_ONLY_LIBRARY_MODE)
Q_INIT_RESOURCE(shaders_lib);
#else // SUPPORT_LIBRARY_MODE
Q_INIT_RESOURCE(shaders);
#endif // SUPPORT_LIBRARY_MODE
//Q_INIT_RESOURCE(FAV);
}
namespace {
class ResourceLoader {
public:
ResourceLoader() { initResources(); }
};
ResourceLoader FAV_QRCLoader;
}