decoders: upload directly to texture

This commit is contained in:
itsmattkc
2022-05-19 16:54:18 -07:00
parent 5ae6a101c2
commit b0530cd55d
7 changed files with 74 additions and 74 deletions
+7 -7
View File
@@ -86,7 +86,7 @@ bool Decoder::Open(const CodecStream &stream)
} }
} }
FramePtr Decoder::RetrieveVideo(const rational &timecode, const RetrieveVideoParams &divider, const QAtomicInt *cancelled) bool Decoder::RetrieveVideo(TexturePtr destination, const rational &timecode, const RetrieveVideoParams &divider, const QAtomicInt *cancelled)
{ {
QMutexLocker locker(&mutex_); QMutexLocker locker(&mutex_);
@@ -94,19 +94,19 @@ FramePtr Decoder::RetrieveVideo(const rational &timecode, const RetrieveVideoPar
if (!stream_.IsValid()) { if (!stream_.IsValid()) {
qCritical() << "Can't retrieve video on a closed decoder"; qCritical() << "Can't retrieve video on a closed decoder";
return nullptr; return false;
} }
if (!SupportsVideo()) { if (!SupportsVideo()) {
qCritical() << "Decoder doesn't support video"; qCritical() << "Decoder doesn't support video";
return nullptr; return false;
} }
if (cancelled && *cancelled) { if (cancelled && *cancelled) {
return nullptr; return false;
} }
return RetrieveVideoInternal(timecode, divider, cancelled); return RetrieveVideoInternal(destination, 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) 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(); return number_only.toLongLong();
} }
FramePtr Decoder::RetrieveVideoInternal(const rational &timecode, const RetrieveVideoParams &divider, const QAtomicInt *cancelled) bool Decoder::RetrieveVideoInternal(TexturePtr destination, const rational &timecode, const RetrieveVideoParams &divider, const QAtomicInt *cancelled)
{ {
Q_UNUSED(timecode) Q_UNUSED(timecode)
Q_UNUSED(divider) Q_UNUSED(divider)
Q_UNUSED(cancelled) Q_UNUSED(cancelled)
return nullptr; return false;
} }
bool Decoder::ConformAudioInternal(const QVector<QString> &filenames, const AudioParams &params, const QAtomicInt* cancelled) bool Decoder::ConformAudioInternal(const QVector<QString> &filenames, const AudioParams &params, const QAtomicInt* cancelled)
+7 -2
View File
@@ -184,7 +184,12 @@ public:
* *
* This function is thread safe and can only run while the decoder is open. \see Open() * This function is thread safe and can only run while the decoder is open. \see Open()
*/ */
FramePtr RetrieveVideo(const rational& timecode, const RetrieveVideoParams& divider, const QAtomicInt *cancelled = nullptr); bool RetrieveVideo(TexturePtr destination, const rational& timecode, const RetrieveVideoParams& divider, const QAtomicInt *cancelled = nullptr);
virtual VideoParams GetParamsForTexture(const Decoder::RetrieveVideoParams &p) const
{
return VideoParams();
}
enum RetrieveAudioStatus { enum RetrieveAudioStatus {
kInvalid = -1, kInvalid = -1,
@@ -279,7 +284,7 @@ protected:
* Sub-classes must override this function IF they support video. Function is already mutexed * 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. * so sub-classes don't need to worry about thread safety.
*/ */
virtual FramePtr RetrieveVideoInternal(const rational& timecode, const RetrieveVideoParams& divider, const QAtomicInt *cancelled); virtual bool RetrieveVideoInternal(TexturePtr destination, const rational& timecode, const RetrieveVideoParams& divider, const QAtomicInt *cancelled);
virtual bool ConformAudioInternal(const QVector<QString>& filenames, const AudioParams &params, const QAtomicInt* cancelled); virtual bool ConformAudioInternal(const QVector<QString>& filenames, const AudioParams &params, const QAtomicInt* cancelled);
+11 -19
View File
@@ -151,38 +151,30 @@ bool FFmpegDecoder::OpenInternal()
return output_frame; return output_frame;
}*/ }*/
FramePtr FFmpegDecoder::RetrieveVideoInternal(const rational &timecode, const RetrieveVideoParams &params, const QAtomicInt *cancelled) bool FFmpegDecoder::RetrieveVideoInternal(TexturePtr destination, const rational &timecode, const RetrieveVideoParams &params, const QAtomicInt *cancelled)
{ {
FramePtr ret = nullptr;
if (AVFramePtr f = RetrieveFrame(timecode, cancelled)) { if (AVFramePtr f = RetrieveFrame(timecode, cancelled)) {
if (InitScaler(params)) { if (InitScaler(params)) {
qint64 t = QDateTime::currentMSecsSinceEpoch();
int r; int r;
r = av_buffersrc_add_frame_flags(buffersrc_ctx_, f.get(), AV_BUFFERSRC_FLAG_KEEP_REF); r = av_buffersrc_add_frame_flags(buffersrc_ctx_, f.get(), AV_BUFFERSRC_FLAG_KEEP_REF);
if (r < 0) { if (r < 0) {
return nullptr; return false;
} }
r = av_buffersink_get_frame(buffersink_ctx_, f.get()); r = av_buffersink_get_frame(buffersink_ctx_, working_frame_);
if (r < 0) { if (r < 0) {
return nullptr; return false;
} }
ret = Frame::Create(); VideoParams vp = GetParamsForTexture(params);
ret->set_video_params(GetVideoParams());
ret->allocate();
uint8_t *destination_data = reinterpret_cast<uint8_t*>(ret->data()); destination->Upload(working_frame_->data[0], working_frame_->linesize[0] / vp.GetBytesPerPixel());
int destination_linesize = ret->linesize_bytes();
av_image_copy(&destination_data, &destination_linesize, const_cast<const uint8_t**>(f->data), f->linesize, AVPixelFormat(f->format), f->width, f->height);
//sws_scale(sws_ctx_, f->data, f->linesize, 0, f->height, &destination_data, &destination_linesize); av_frame_unref(working_frame_);
qDebug() << "Converting from" << instance_.avstream()->codecpar->format << "to" << ideal_pix_fmt_ << "took" << (QDateTime::currentMSecsSinceEpoch() - t); return true;
} }
} }
return ret; return false;
} }
void FFmpegDecoder::CloseInternal() void FFmpegDecoder::CloseInternal()
@@ -944,7 +936,7 @@ void FFmpegDecoder::RemoveFirstFrame()
cache_at_zero_ = false; cache_at_zero_ = false;
} }
VideoParams FFmpegDecoder::GetVideoParams() const VideoParams FFmpegDecoder::GetParamsForTexture(const Decoder::RetrieveVideoParams &p) const
{ {
return VideoParams(instance_.avstream()->codecpar->width, return VideoParams(instance_.avstream()->codecpar->width,
instance_.avstream()->codecpar->height, instance_.avstream()->codecpar->height,
@@ -952,7 +944,7 @@ VideoParams FFmpegDecoder::GetVideoParams() const
native_channel_count_, native_channel_count_,
av_guess_sample_aspect_ratio(instance_.fmt_ctx(), instance_.avstream(), nullptr), av_guess_sample_aspect_ratio(instance_.fmt_ctx(), instance_.avstream(), nullptr),
VideoParams::kInterlaceNone, VideoParams::kInterlaceNone,
filter_params_.divider); p.divider);
} }
FFmpegDecoder::Instance::Instance() : FFmpegDecoder::Instance::Instance() :
+3 -3
View File
@@ -66,9 +66,11 @@ public:
virtual FootageDescription Probe(const QString &filename, const QAtomicInt *cancelled) const override; virtual FootageDescription Probe(const QString &filename, const QAtomicInt *cancelled) const override;
virtual VideoParams GetParamsForTexture(const Decoder::RetrieveVideoParams &p) const override;
protected: protected:
virtual bool OpenInternal() override; virtual bool OpenInternal() override;
virtual FramePtr RetrieveVideoInternal(const rational &timecode, const RetrieveVideoParams& params, const QAtomicInt *cancelled) override; virtual bool RetrieveVideoInternal(TexturePtr destination, 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 bool ConformAudioInternal(const QVector<QString>& filenames, const AudioParams &params, const QAtomicInt* cancelled) override;
virtual void CloseInternal() override; virtual void CloseInternal() override;
@@ -150,8 +152,6 @@ private:
void RemoveFirstFrame(); void RemoveFirstFrame();
VideoParams GetVideoParams() const;
RetrieveVideoParams filter_params_; RetrieveVideoParams filter_params_;
AVFilterGraph* filter_graph_; AVFilterGraph* filter_graph_;
AVFilterContext* buffersrc_ctx_; AVFilterContext* buffersrc_ctx_;
+18 -18
View File
@@ -117,48 +117,48 @@ FootageDescription OIIODecoder::Probe(const QString &filename, const QAtomicInt*
return desc; return desc;
} }
VideoParams OIIODecoder::GetParamsForTexture(const RetrieveVideoParams &p) const
{
return VideoParams(buffer_->spec().width,
buffer_->spec().height,
pix_fmt_,
channel_count_,
OIIOUtils::GetPixelAspectRatioFromOIIO(buffer_->spec()),
VideoParams::kInterlaceNone, // FIXME: Does OIIO deinterlace for us?
p.divider);
}
bool OIIODecoder::OpenInternal() bool OIIODecoder::OpenInternal()
{ {
// If we can open the filename provided, assume everything is working // If we can open the filename provided, assume everything is working
return OpenImageHandler(stream().filename(), stream().stream()); return OpenImageHandler(stream().filename(), stream().stream());
} }
FramePtr OIIODecoder::RetrieveVideoInternal(const rational &timecode, const RetrieveVideoParams &divider, const QAtomicInt *cancelled) bool OIIODecoder::RetrieveVideoInternal(TexturePtr destination, const rational &timecode, const RetrieveVideoParams &params, const QAtomicInt *cancelled)
{ {
Q_UNUSED(timecode) Q_UNUSED(timecode)
Q_UNUSED(cancelled) Q_UNUSED(cancelled)
FramePtr frame = Frame::Create(); VideoParams vp = GetParamsForTexture(params);
VideoParams vp(buffer_->spec().width, if (params.divider == 1) {
buffer_->spec().height,
pix_fmt_,
channel_count_,
OIIOUtils::GetPixelAspectRatioFromOIIO(buffer_->spec()),
VideoParams::kInterlaceNone, // FIXME: Does OIIO deinterlace for us?
divider.divider);
frame->set_video_params(vp); destination->Upload(buffer_->localpixels(), buffer_->scanline_stride() / vp.GetBytesPerPixel());
frame->allocate();
if (divider.divider == 1) {
OIIOUtils::BufferToFrame(buffer_, frame.get());
} else { } else {
// Will need to resize the image // Will need to resize the image
OIIO::ImageBuf dst(OIIO::ImageSpec(frame->width(), frame->height(), buffer_->spec().nchannels, buffer_->spec().format)); OIIO::ImageBuf dst(OIIO::ImageSpec(vp.effective_width(), vp.effective_height(), buffer_->spec().nchannels, buffer_->spec().format));
if (!OIIO::ImageBufAlgo::resample(dst, *buffer_)) { if (!OIIO::ImageBufAlgo::resample(dst, *buffer_)) {
qWarning() << "OIIO resize failed"; qWarning() << "OIIO resize failed";
} }
OIIOUtils::BufferToFrame(&dst, frame.get()); destination->Upload(dst.localpixels(), dst.scanline_stride() / vp.GetBytesPerPixel());
} }
return frame; return true;
} }
void OIIODecoder::CloseInternal() void OIIODecoder::CloseInternal()
+3 -1
View File
@@ -42,9 +42,11 @@ public:
virtual FootageDescription Probe(const QString& filename, const QAtomicInt* cancelled) const override; virtual FootageDescription Probe(const QString& filename, const QAtomicInt* cancelled) const override;
virtual VideoParams GetParamsForTexture(const Decoder::RetrieveVideoParams &p) const override;
protected: protected:
virtual bool OpenInternal() override; virtual bool OpenInternal() override;
virtual FramePtr RetrieveVideoInternal(const rational &timecode, const RetrieveVideoParams& divider, const QAtomicInt *cancelled) override; virtual bool RetrieveVideoInternal(TexturePtr destination, const rational& timecode, const RetrieveVideoParams& params, const QAtomicInt *cancelled) override;
virtual void CloseInternal() override; virtual void CloseInternal() override;
private: private:
+25 -24
View File
@@ -46,7 +46,6 @@ RenderProcessor::RenderProcessor(RenderTicketPtr ticket, Renderer *render_ctx, D
TexturePtr RenderProcessor::GenerateTexture(const rational &time, const rational &frame_length) TexturePtr RenderProcessor::GenerateTexture(const rational &time, const rational &frame_length)
{ {
TimeRange range = TimeRange(time, time + frame_length); TimeRange range = TimeRange(time, time + frame_length);
NodeValueTable table; NodeValueTable table;
@@ -451,35 +450,37 @@ void RenderProcessor::ProcessVideoFootage(TexturePtr destination, const FootageJ
p.dst_interlacing = GetCacheVideoParams().interlacing(); p.dst_interlacing = GetCacheVideoParams().interlacing();
if (!IsCancelled()) { if (!IsCancelled()) {
FramePtr frame = decoder->RetrieveVideo((stream_data.video_type() == VideoParams::kVideoTypeVideo) ? input_time : Decoder::kAnyTimecode, p, GetCancelPointer());
if (frame) { VideoParams tex_params = decoder->GetParamsForTexture(p);
// Return a texture from the derived class
TexturePtr unmanaged_texture = render_ctx_->CreateTexture(frame->video_params(),
frame->data(),
frame->linesize_pixels());
// We convert to our rendering pixel format, since that will always be float-based which if (tex_params.is_valid()) {
// is necessary for correct color conversion TexturePtr unmanaged_texture = render_ctx_->CreateTexture(tex_params);
ColorProcessorPtr processor = ColorProcessor::Create(color_manager,
using_colorspace,
color_manager->GetReferenceColorSpace());
ColorTransformJob job; bool frame = decoder->RetrieveVideo(unmanaged_texture, (stream_data.video_type() == VideoParams::kVideoTypeVideo) ? input_time : Decoder::kAnyTimecode, p, GetCancelPointer());
job.SetColorProcessor(processor); if (frame) {
job.SetInputTexture(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,
using_colorspace,
color_manager->GetReferenceColorSpace());
if (stream_data.channel_count() != VideoParams::kRGBAChannelCount ColorTransformJob job;
|| stream_data.colorspace() == color_manager->GetReferenceColorSpace()) {
job.SetInputAlphaAssociation(kAlphaNone); job.SetColorProcessor(processor);
} else if (stream_data.premultiplied_alpha()) { job.SetInputTexture(unmanaged_texture);
job.SetInputAlphaAssociation(kAlphaAssociated);
} else { if (stream_data.channel_count() != VideoParams::kRGBAChannelCount
job.SetInputAlphaAssociation(kAlphaUnassociated); || stream_data.colorspace() == color_manager->GetReferenceColorSpace()) {
job.SetInputAlphaAssociation(kAlphaNone);
} else if (stream_data.premultiplied_alpha()) {
job.SetInputAlphaAssociation(kAlphaAssociated);
} else {
job.SetInputAlphaAssociation(kAlphaUnassociated);
}
render_ctx_->BlitColorManaged(job, destination.get());
} }
render_ctx_->BlitColorManaged(job, destination.get());
} }
} }
} }