Merge branch 'master' into hashremoval

This commit is contained in:
itsmattkc
2022-05-30 17:32:39 -07:00
10 changed files with 185 additions and 53 deletions
+7 -7
View File
@@ -86,7 +86,7 @@ bool Decoder::Open(const CodecStream &stream)
}
}
bool Decoder::RetrieveVideo(TexturePtr destination, const rational &timecode, const RetrieveVideoParams &divider, const QAtomicInt *cancelled)
TexturePtr Decoder::RetrieveVideo(Renderer *renderer, const rational &timecode, const RetrieveVideoParams &divider, const QAtomicInt *cancelled)
{
QMutexLocker locker(&mutex_);
@@ -94,19 +94,19 @@ bool Decoder::RetrieveVideo(TexturePtr destination, const rational &timecode, co
if (!stream_.IsValid()) {
qCritical() << "Can't retrieve video on a closed decoder";
return false;
return nullptr;
}
if (!SupportsVideo()) {
qCritical() << "Decoder doesn't support video";
return false;
return nullptr;
}
if (cancelled && *cancelled) {
return false;
return nullptr;
}
return RetrieveVideoInternal(destination, timecode, divider, cancelled);
return RetrieveVideoInternal(renderer, timecode, divider, cancelled);
}
Decoder::RetrieveAudioStatus Decoder::RetrieveAudio(SampleBuffer &dest, const TimeRange &range, const AudioParams &params, const QString& cache_path, Footage::LoopMode loop_mode, RenderMode::Mode mode)
@@ -264,12 +264,12 @@ int64_t Decoder::GetImageSequenceIndex(const QString &filename)
return number_only.toLongLong();
}
bool Decoder::RetrieveVideoInternal(TexturePtr destination, const rational &timecode, const RetrieveVideoParams &divider, const QAtomicInt *cancelled)
TexturePtr Decoder::RetrieveVideoInternal(Renderer *renderer, const rational &timecode, const RetrieveVideoParams &divider, const QAtomicInt *cancelled)
{
Q_UNUSED(timecode)
Q_UNUSED(divider)
Q_UNUSED(cancelled)
return false;
return nullptr;
}
bool Decoder::ConformAudioInternal(const QVector<QString> &filenames, const AudioParams &params, const QAtomicInt* cancelled)
+5 -3
View File
@@ -150,9 +150,11 @@ public:
RetrieveVideoParams()
{
divider = 1;
maximum_format = VideoParams::kFormatInvalid;
}
int divider;
VideoParams::Format maximum_format;
void reset()
{
@@ -161,7 +163,7 @@ public:
bool operator==(const RetrieveVideoParams& rhs) const
{
return divider == rhs.divider;
return divider == rhs.divider && maximum_format == rhs.maximum_format;
}
bool operator!=(const RetrieveVideoParams& rhs) const
@@ -180,7 +182,7 @@ public:
*
* This function is thread safe and can only run while the decoder is open. \see Open()
*/
bool RetrieveVideo(TexturePtr destination, const rational& timecode, const RetrieveVideoParams& divider, const QAtomicInt *cancelled = nullptr);
TexturePtr RetrieveVideo(Renderer *renderer, const rational& timecode, const RetrieveVideoParams& params, const QAtomicInt *cancelled = nullptr);
enum RetrieveAudioStatus {
kInvalid = -1,
@@ -275,7 +277,7 @@ protected:
* Sub-classes must override this function IF they support video. Function is already mutexed
* so sub-classes don't need to worry about thread safety.
*/
virtual bool RetrieveVideoInternal(TexturePtr destination, const rational& timecode, const RetrieveVideoParams& divider, const QAtomicInt *cancelled);
virtual TexturePtr RetrieveVideoInternal(Renderer *renderer, const rational& timecode, const RetrieveVideoParams& params, const QAtomicInt *cancelled);
virtual bool ConformAudioInternal(const QVector<QString>& filenames, const AudioParams &params, const QAtomicInt* cancelled);
+115 -21
View File
@@ -46,16 +46,20 @@ extern "C" {
#include "common/timecodefunctions.h"
#include "render/framehashcache.h"
#include "render/diskmanager.h"
#include "render/renderer.h"
#include "render/subtitleparams.h"
namespace olive {
QVariant Yuv2RgbShader;
FFmpegDecoder::FFmpegDecoder() :
filter_graph_(nullptr),
buffersrc_ctx_(nullptr),
buffersink_ctx_(nullptr),
input_fmt_(AV_PIX_FMT_NONE),
native_pix_fmt_(VideoParams::kFormatInvalid),
native_internal_pix_fmt_(VideoParams::kFormatInvalid),
native_output_pix_fmt_(VideoParams::kFormatInvalid),
working_frame_(nullptr),
working_packet_(nullptr),
is_working_(false),
@@ -137,36 +141,121 @@ bool FFmpegDecoder::OpenInternal()
return output_frame;
}*/
bool FFmpegDecoder::RetrieveVideoInternal(TexturePtr destination, const rational &timecode, const RetrieveVideoParams &params, const QAtomicInt *cancelled)
TexturePtr FFmpegDecoder::RetrieveVideoInternal(Renderer *renderer, const rational &timecode, const RetrieveVideoParams &params, const QAtomicInt *cancelled)
{
if (AVFramePtr f = RetrieveFrame(timecode, cancelled)) {
if (InitScaler(f.get(), params)) {
int r;
r = av_buffersrc_add_frame_flags(buffersrc_ctx_, f.get(), AV_BUFFERSRC_FLAG_KEEP_REF);
if (r < 0) {
return false;
}
r = av_buffersink_get_frame(buffersink_ctx_, working_frame_);
if (r < 0) {
return false;
}
VideoParams vp(instance_.avstream()->codecpar->width,
instance_.avstream()->codecpar->height,
native_pix_fmt_,
native_output_pix_fmt_,
native_channel_count_,
av_guess_sample_aspect_ratio(instance_.fmt_ctx(), instance_.avstream(), nullptr),
VideoParams::kInterlaceNone,
params.divider);
destination->Upload(working_frame_->data[0], working_frame_->linesize[0] / vp.GetBytesPerPixel());
TexturePtr tex = nullptr;
const bool hwscale = true;
av_frame_unref(working_frame_);
return true;
// Attempt to use GLSL shader for faster YUV to RGB conversion
if (hwscale) {
AVPixelFormat src_fmt = AVPixelFormat(f.get()->format);
if (src_fmt == AV_PIX_FMT_YUV420P
|| src_fmt == AV_PIX_FMT_YUV422P
|| src_fmt == AV_PIX_FMT_YUV444P
|| src_fmt == AV_PIX_FMT_YUV420P10LE
|| src_fmt == AV_PIX_FMT_YUV422P10LE
|| src_fmt == AV_PIX_FMT_YUV444P10LE
|| src_fmt == AV_PIX_FMT_YUV420P12LE
|| src_fmt == AV_PIX_FMT_YUV422P12LE
|| src_fmt == AV_PIX_FMT_YUV444P12LE) {
if (Yuv2RgbShader.isNull()) {
// Compile shader
Yuv2RgbShader = renderer->CreateNativeShader(ShaderCode(FileFunctions::ReadFileAsString(QStringLiteral(":/shaders/yuv2rgb.frag"))));
}
if (!Yuv2RgbShader.isNull()) {
int px_size;
int bits_per_pixel;
switch (src_fmt) {
case AV_PIX_FMT_YUV420P:
case AV_PIX_FMT_YUV422P:
case AV_PIX_FMT_YUV444P:
default:
px_size = 1;
bits_per_pixel = 8;
break;
case AV_PIX_FMT_YUV420P10LE:
case AV_PIX_FMT_YUV422P10LE:
case AV_PIX_FMT_YUV444P10LE:
px_size = 2;
bits_per_pixel = 10;
break;
case AV_PIX_FMT_YUV420P12LE:
case AV_PIX_FMT_YUV422P12LE:
case AV_PIX_FMT_YUV444P12LE:
px_size = 2;
bits_per_pixel = 12;
break;
}
VideoParams plane_params = vp;
plane_params.set_channel_count(1);
plane_params.set_divider(1);
plane_params.set_format(native_internal_pix_fmt_);
TexturePtr y_plane = renderer->CreateTexture(plane_params, f->data[0], f->linesize[0] / px_size);
if (src_fmt == AV_PIX_FMT_YUV420P
|| src_fmt == AV_PIX_FMT_YUV422P
|| src_fmt == AV_PIX_FMT_YUV420P10LE
|| src_fmt == AV_PIX_FMT_YUV422P10LE
|| src_fmt == AV_PIX_FMT_YUV420P12LE
|| src_fmt == AV_PIX_FMT_YUV422P12LE) {
plane_params.set_width(plane_params.width()/2);
}
if (src_fmt == AV_PIX_FMT_YUV420P
|| src_fmt == AV_PIX_FMT_YUV420P10LE
|| src_fmt == AV_PIX_FMT_YUV420P12LE) {
plane_params.set_height(plane_params.height()/2);
}
TexturePtr u_plane = renderer->CreateTexture(plane_params, f->data[1], f->linesize[1] / px_size);
TexturePtr v_plane = renderer->CreateTexture(plane_params, f->data[2], f->linesize[2] / px_size);
ShaderJob job;
job.Insert(QStringLiteral("y_channel"), NodeValue(NodeValue::kTexture, QVariant::fromValue(y_plane)));
job.Insert(QStringLiteral("u_channel"), NodeValue(NodeValue::kTexture, QVariant::fromValue(u_plane)));
job.Insert(QStringLiteral("v_channel"), NodeValue(NodeValue::kTexture, QVariant::fromValue(v_plane)));
job.Insert(QStringLiteral("bits_per_pixel"), NodeValue(NodeValue::kInt, bits_per_pixel));
tex = renderer->CreateTexture(vp);
renderer->BlitToTexture(Yuv2RgbShader, job, tex.get(), false);
}
}
}
if (!tex) {
// Fallback to software pixel format conversion
int r;
r = av_buffersrc_add_frame_flags(buffersrc_ctx_, f.get(), AV_BUFFERSRC_FLAG_KEEP_REF);
if (r < 0) {
return nullptr;
}
r = av_buffersink_get_frame(buffersink_ctx_, working_frame_);
if (r < 0) {
return nullptr;
}
tex = renderer->CreateTexture(vp, working_frame_->data[0], working_frame_->linesize[0] / vp.GetBytesPerPixel());
av_frame_unref(working_frame_);
}
return tex;
}
}
return false;
return nullptr;
}
void FFmpegDecoder::CloseInternal()
@@ -187,7 +276,8 @@ void FFmpegDecoder::CloseInternal()
instance_.Close();
input_fmt_ = AV_PIX_FMT_NONE;
native_pix_fmt_ = VideoParams::kFormatInvalid;
native_internal_pix_fmt_ = VideoParams::kFormatInvalid;
native_output_pix_fmt_ = VideoParams::kFormatInvalid;
}
QString FFmpegDecoder::id() const
@@ -797,14 +887,18 @@ bool FFmpegDecoder::InitScaler(AVFrame *input, const RetrieveVideoParams& params
}
// Get an Olive compatible AVPixelFormat
AVPixelFormat ideal_pix_fmt = FFmpegUtils::GetCompatiblePixelFormat(static_cast<AVPixelFormat>(input_fmt_));
AVPixelFormat ideal_pix_fmt = FFmpegUtils::GetCompatiblePixelFormat(static_cast<AVPixelFormat>(input_fmt_), params.maximum_format);
// Determine which Olive native pixel format we retrieved
// Note that FFmpeg doesn't support float formats
native_pix_fmt_ = GetNativePixelFormat(ideal_pix_fmt);
native_output_pix_fmt_ = GetNativePixelFormat(ideal_pix_fmt);
native_channel_count_ = GetNativeChannelCount(ideal_pix_fmt);
if (native_pix_fmt_ == VideoParams::kFormatInvalid
AVPixelFormat ideal_internal_pix_fmt = FFmpegUtils::GetCompatiblePixelFormat(static_cast<AVPixelFormat>(input_fmt_));
native_internal_pix_fmt_ = GetNativePixelFormat(ideal_internal_pix_fmt);
if (native_output_pix_fmt_ == VideoParams::kFormatInvalid
|| native_internal_pix_fmt_ == VideoParams::kFormatInvalid
|| native_channel_count_ == 0) {
qCritical() << "Failed to find valid native pixel format for" << ideal_pix_fmt;
return false;
+3 -2
View File
@@ -68,7 +68,7 @@ public:
protected:
virtual bool OpenInternal() override;
virtual bool RetrieveVideoInternal(TexturePtr destination, const rational& timecode, const RetrieveVideoParams& params, const QAtomicInt *cancelled) override;
virtual TexturePtr RetrieveVideoInternal(Renderer *renderer, const rational& timecode, const RetrieveVideoParams& params, const QAtomicInt *cancelled) override;
virtual bool ConformAudioInternal(const QVector<QString>& filenames, const AudioParams &params, const QAtomicInt* cancelled) override;
virtual void CloseInternal() override;
@@ -160,7 +160,8 @@ private:
AVFilterContext* buffersrc_ctx_;
AVFilterContext* buffersink_ctx_;
AVPixelFormat input_fmt_;
VideoParams::Format native_pix_fmt_;
VideoParams::Format native_internal_pix_fmt_;
VideoParams::Format native_output_pix_fmt_;
int native_channel_count_;
AVFrame *working_frame_;
+3 -4
View File
@@ -29,6 +29,7 @@
#include "common/oiioutils.h"
#include "config/config.h"
#include "core.h"
#include "render/renderer.h"
namespace olive {
@@ -115,7 +116,7 @@ bool OIIODecoder::OpenInternal()
return OpenImageHandler(stream().filename(), stream().stream());
}
bool OIIODecoder::RetrieveVideoInternal(TexturePtr destination, const rational &timecode, const RetrieveVideoParams &params, const QAtomicInt *cancelled)
TexturePtr OIIODecoder::RetrieveVideoInternal(Renderer *renderer, const rational &timecode, const RetrieveVideoParams &params, const QAtomicInt *cancelled)
{
Q_UNUSED(timecode)
Q_UNUSED(cancelled)
@@ -152,9 +153,7 @@ bool OIIODecoder::RetrieveVideoInternal(TexturePtr destination, const rational &
}
}
destination->Upload(buffer_.data(), buffer_.linesize_pixels());
return true;
return renderer->CreateTexture(vp, buffer_.data(), buffer_.linesize_pixels());
}
void OIIODecoder::CloseInternal()
+1 -1
View File
@@ -44,7 +44,7 @@ public:
protected:
virtual bool OpenInternal() override;
virtual bool RetrieveVideoInternal(TexturePtr destination, const rational& timecode, const RetrieveVideoParams& params, const QAtomicInt *cancelled) override;
virtual TexturePtr RetrieveVideoInternal(Renderer *renderer, const rational& timecode, const RetrieveVideoParams& params, const QAtomicInt *cancelled) override;
virtual void CloseInternal() override;
private:
+12 -9
View File
@@ -22,17 +22,20 @@
namespace olive {
AVPixelFormat FFmpegUtils::GetCompatiblePixelFormat(const AVPixelFormat &pix_fmt)
AVPixelFormat FFmpegUtils::GetCompatiblePixelFormat(const AVPixelFormat &pix_fmt, VideoParams::Format maximum)
{
AVPixelFormat possible_pix_fmts[] = {
// RGBA formats only because GPUs always upconvert to RGBA, so if it's RGB, that adds extra
// conversion overhead
AV_PIX_FMT_RGBA,
AV_PIX_FMT_RGBA64,
AV_PIX_FMT_NONE
};
std::vector<AVPixelFormat> possible_pix_fmts(3);
return avcodec_find_best_pix_fmt_of_list(possible_pix_fmts,
possible_pix_fmts[0] = AV_PIX_FMT_RGBA;
if (maximum == VideoParams::kFormatUnsigned8) {
possible_pix_fmts[1] = AV_PIX_FMT_NONE;
} else {
possible_pix_fmts[1] = AV_PIX_FMT_RGBA64;
possible_pix_fmts[2] = AV_PIX_FMT_NONE;
}
return avcodec_find_best_pix_fmt_of_list(possible_pix_fmts.data(),
pix_fmt,
1,
nullptr);
+1 -1
View File
@@ -36,7 +36,7 @@ public:
/**
* @brief Returns an AVPixelFormat that can be used to convert a frame to a data type Olive supports with minimal data loss
*/
static AVPixelFormat GetCompatiblePixelFormat(const AVPixelFormat& pix_fmt);
static AVPixelFormat GetCompatiblePixelFormat(const AVPixelFormat& pix_fmt, VideoParams::Format maximum = VideoParams::kFormatInvalid);
/**
* @brief Returns a native pixel format that can be used to convert from a native frame to an AVFrame with minimal data loss
+3 -5
View File
@@ -434,17 +434,15 @@ void RenderProcessor::ProcessVideoFootage(TexturePtr destination, const FootageJ
if (decoder) {
Decoder::RetrieveVideoParams p;
p.divider = stream.video_params().divider();
p.maximum_format = destination->format();
if (!IsCancelled()) {
VideoParams tex_params = stream.video_params();
if (tex_params.is_valid()) {
TexturePtr unmanaged_texture = render_ctx_->CreateTexture(tex_params);
TexturePtr unmanaged_texture = decoder->RetrieveVideo(render_ctx_, (stream_data.video_type() == VideoParams::kVideoTypeVideo) ? input_time : Decoder::kAnyTimecode, p, GetCancelPointer());
bool frame = decoder->RetrieveVideo(unmanaged_texture, (stream_data.video_type() == VideoParams::kVideoTypeVideo) ? input_time : Decoder::kAnyTimecode, p, GetCancelPointer());
if (!IsCancelled() && frame) {
if (!IsCancelled() && unmanaged_texture) {
// We convert to our rendering pixel format, since that will always be float-based which
// is necessary for correct color conversion
ColorProcessorPtr processor = ColorProcessor::Create(color_manager,
+35
View File
@@ -0,0 +1,35 @@
uniform sampler2D y_channel;
uniform sampler2D u_channel;
uniform sampler2D v_channel;
uniform int bits_per_pixel;
in vec2 ove_texcoord;
out vec4 frag_color;
void main() {
vec4 rgba;
vec3 yuv;
yuv.r = texture(y_channel, ove_texcoord).r;
yuv.g = texture(u_channel, ove_texcoord).r;
yuv.b = texture(v_channel, ove_texcoord).r;
if (bits_per_pixel == 10) {
yuv *= 64.0;
} else if (bits_per_pixel == 12) {
yuv *= 16.0;
}
yuv.r = 1.1643 * (yuv.r - 0.0625);
yuv.g = yuv.g - 0.5;
yuv.b = yuv.b - 0.5;
rgba.r = yuv.r + 1.5958 * yuv.b;
rgba.g = yuv.r - 0.39173 * yuv.g - 0.81290 * yuv.b;
rgba.b = yuv.r + 2.017 * yuv.g;
rgba.a = 1.0;
frag_color = rgba;
}