[graphics/krita/krita/6.0] libs/ui/animation: Split off common libav context functionality
Carsten Hartenfels <[email protected]>
| Newsgroups | gmane.comp.kde.cvs |
|---|---|
| Message-ID | <[email protected]> |
Git commit 36380b153c91b03c0dd2e5d43d0506ba4b4b9dbb by Carsten Hartenfels.
Committed on 27/07/2026 at 17:19.
Pushed by hartenfels into branch 'krita/6.0'.
Split off common libav context functionality
It will be used in a libav media encoder implementation coming in
subsequent commits, this pulls some common parts out of the Android
encoder.
M +8 -66 libs/ui/animation/KisAndroidMediaEncoderRunnable.cpp
A +98 -0 libs/ui/animation/KisLibavEncoderContext.h [License: GPL(v3.0+)]
https://invent.kde.org/graphics/krita/-/commit/36380b153c91b03c0dd2e5d43d0506ba4b4b9dbb
diff --git a/libs/ui/animation/KisAndroidMediaEncoderRunnable.cpp b/libs/ui/animation/KisAndroidMediaEncoderRunnable.cpp
index b4390f684f9..a0dc30f2b1e 100644
--- a/libs/ui/animation/KisAndroidMediaEncoderRunnable.cpp
+++ b/libs/ui/animation/KisAndroidMediaEncoderRunnable.cpp
@@ -31,6 +31,8 @@ extern "C" {
#include <libswscale/swscale.h>
}
+#include "KisLibavEncoderContext.h"
+
struct KisAndroidMediaEncoderRunnable::EncoderImage {
uint8_t *bufferY;
uint8_t *bufferU;
@@ -210,20 +212,16 @@ private:
int m_formatId;
};
-class KisAndroidMediaEncoderRunnable::Context
+class KisAndroidMediaEncoderRunnable::Context : public KisLibavEncoderContext
{
public:
explicit Context(QString *outErrorMessage = nullptr)
- : m_outErrorMessage(outErrorMessage)
+ : KisLibavEncoderContext(outErrorMessage)
{
}
- ~Context()
+ ~Context() override
{
- if (m_imageFormat != AV_PIX_FMT_NONE) {
- av_freep(&m_imageBuffers[0]);
- }
- sws_freeContext(m_swsContext);
clearEncoder();
}
@@ -273,15 +271,11 @@ public:
return true;
} else if (result == STATUS_ERROR_START_ENCODER) {
warnFile << "Start encoder error" << result;
- if (m_outErrorMessage) {
- *m_outErrorMessage = i18n("Unsupported video parameters, try lowering the video FPS or size");
- }
+ setErrorMessage(i18n("Unsupported video parameters, try lowering the video FPS or size"));
return true;
} else if (result == STATUS_ERROR_DRAIN_MUXER_ADD_TRACK) {
warnFile << "Muxer track error" << result;
- if (m_outErrorMessage) {
- *m_outErrorMessage = i18n("Unsupported format");
- }
+ setErrorMessage(i18n("Unsupported format"));
return true;
} else if (isErrorResult(result)) {
setInternalErrorMessage(QStringLiteral("%1 failed with code %2").arg(title).arg(result));
@@ -303,27 +297,6 @@ public:
}
}
- SwsContext *getSwsContextFor(int inputWidth,
- int inputHeight,
- AVPixelFormat inputFormat,
- int outputWidth,
- int outputHeight,
- AVPixelFormat outputFormat,
- int flags)
- {
- return sws_getCachedContext(m_swsContext,
- inputWidth,
- inputHeight,
- inputFormat,
- outputWidth,
- outputHeight,
- outputFormat,
- flags,
- nullptr,
- nullptr,
- nullptr);
- }
-
int imageFormat() const
{
return m_imageFormat;
@@ -358,16 +331,6 @@ public:
}
}
- void setInternalErrorMessage(const QString &detail)
- {
- warnFile << "Media encoder error:" << detail;
- if (m_outErrorMessage) {
- // Internal encoder errors are only really useful for developers,
- // so there's no point in translating them.
- *m_outErrorMessage = i18n("Internal error (%1)", detail);
- }
- }
-
private:
static bool isErrorResult(int result)
{
@@ -376,8 +339,6 @@ private:
QJniEnvironment m_env;
QJniObject m_encoder;
- QString *m_outErrorMessage;
- SwsContext *m_swsContext = nullptr;
uint8_t *m_imageBuffers[4] = {nullptr, nullptr, nullptr, nullptr};
int m_imageLinesizes[4] = {0, 0, 0, 0};
AVPixelFormat m_imageFormat = AV_PIX_FMT_NONE;
@@ -486,26 +447,7 @@ KisMediaEncoderRunnable::EncodeResult KisAndroidMediaEncoderRunnable::encode(QSt
// Grab the next frame from disk.
QImage inputImage;
AVPixelFormat inputPixelFormat;
- if (frame.readImage(inputImage)) {
- switch (inputImage.format()) {
- case QImage::Format_RGB32:
- inputPixelFormat = AV_PIX_FMT_BGR0;
- break;
- case QImage::Format_ARGB32:
- inputPixelFormat = AV_PIX_FMT_BGRA;
- break;
- default:
- // The above are the only formats I can get the the recorder to
- // produce, so I'm not gonna get experimental with this.
- inputPixelFormat = AV_PIX_FMT_BGRA;
- inputImage = inputImage.convertToFormat(QImage::Format_ARGB32);
- if (inputImage.isNull()) {
- warnFile << "Frame conversion from" << inputImage.format() << "failed";
- continue;
- }
- break;
- }
- } else {
+ if (!frame.readImage(inputImage) || !ctx.convertFrame(inputImage, inputPixelFormat)) {
continue; // Keep going, some frames may be corrupted.
}
diff --git a/libs/ui/animation/KisLibavEncoderContext.h b/libs/ui/animation/KisLibavEncoderContext.h
new file mode 100644
index 00000000000..01536d4c7c8
--- /dev/null
+++ b/libs/ui/animation/KisLibavEncoderContext.h
@@ -0,0 +1,98 @@
+/*
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+#ifndef KISLIBAVENCODERCONTEXT
+#define KISLIBAVENCODERCONTEXT
+
+#include <QImage>
+#include <QString>
+
+#include <klocalizedstring.h>
+
+#include <kis_debug.h>
+
+extern "C" {
+#include <libavutil/imgutils.h>
+#include <libavutil/pixfmt.h>
+#include <libswscale/swscale.h>
+}
+
+class KisLibavEncoderContext
+{
+ Q_DISABLE_COPY_MOVE(KisLibavEncoderContext)
+public:
+ explicit KisLibavEncoderContext(QString *outErrorMessage = nullptr)
+ : m_outErrorMessage(outErrorMessage)
+ {
+ }
+
+ virtual ~KisLibavEncoderContext()
+ {
+ sws_freeContext(m_swsContext);
+ };
+
+ bool convertFrame(QImage &inOutImage, AVPixelFormat &outPixelFormat) const
+ {
+ switch (inOutImage.format()) {
+ case QImage::Format_RGB32:
+ outPixelFormat = AV_PIX_FMT_BGR0;
+ break;
+ case QImage::Format_ARGB32:
+ outPixelFormat = AV_PIX_FMT_BGRA;
+ break;
+ default:
+ // The above are the only formats I can get the the recorder to
+ // produce, so I'm not gonna get experimental with this.
+ outPixelFormat = AV_PIX_FMT_BGRA;
+ inOutImage = inOutImage.convertToFormat(QImage::Format_ARGB32);
+ if (inOutImage.isNull()) {
+ warnFile << "Frame conversion from" << inOutImage.format() << "failed";
+ return false;
+ }
+ break;
+ }
+ return true;
+ }
+
+ SwsContext *getSwsContextFor(int inputWidth,
+ int inputHeight,
+ AVPixelFormat inputFormat,
+ int outputWidth,
+ int outputHeight,
+ AVPixelFormat outputFormat,
+ int flags)
+ {
+ return sws_getCachedContext(m_swsContext,
+ inputWidth,
+ inputHeight,
+ inputFormat,
+ outputWidth,
+ outputHeight,
+ outputFormat,
+ flags,
+ nullptr,
+ nullptr,
+ nullptr);
+ }
+
+ void setInternalErrorMessage(const QString &detail)
+ {
+ warnFile << "Media encoder error:" << detail;
+ // Internal encoder errors are only really useful for developers,
+ // so there's no point in translating them.
+ setErrorMessage(i18n("Internal error (%1)", detail));
+ }
+
+ void setErrorMessage(const QString &errorMessage)
+ {
+ if (m_outErrorMessage) {
+ *m_outErrorMessage = errorMessage;
+ }
+ }
+
+private:
+ QString *m_outErrorMessage;
+ SwsContext *m_swsContext = nullptr;
+};
+
+#endif