codec system rework

Codecs are now much cleaner and thread safe by design.
This commit is contained in:
itsmattkc
2020-11-10 11:23:25 +11:00
parent 6ecdb02fd0
commit 94c0914e50
17 changed files with 932 additions and 1376 deletions
+3 -1
View File
@@ -16,7 +16,9 @@
set(OLIVE_SOURCES
${OLIVE_SOURCES}
codec/oiio/oiiodecoder.h
codec/oiio/oiiocommon.cpp
codec/oiio/oiiocommon.h
codec/oiio/oiiodecoder.cpp
codec/oiio/oiiodecoder.h
PARENT_SCOPE
)
+102
View File
@@ -0,0 +1,102 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2019 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#include "oiiocommon.h"
OLIVE_NAMESPACE_ENTER
void OIIOCommon::FrameToBuffer(FramePtr frame, OIIO::ImageBuf *buf)
{
#if OIIO_VERSION < 20112
//
// Workaround for OIIO bug that ignores destination stride in versions OLDER than 2.1.12
//
// See more: https://github.com/OpenImageIO/oiio/pull/2487
//
int width_in_bytes = frame->width() * PixelFormat::BytesPerPixel(frame->format());
for (int i=0;i<buf->spec().height;i++) {
memcpy(
#if OIIO_VERSION < 10903
reinterpret_cast<char*>(buf->localpixels()) + i * width_in_bytes,
#else
reinterpret_cast<char*>(buf->localpixels()) + i * buf->scanline_stride(),
#endif
frame->data() + i * frame->linesize_bytes(),
width_in_bytes);
}
#else
buf->set_pixels(OIIO::ROI(),
buf->spec().format,
frame->data(),
OIIO::AutoStride,
frame->linesize_bytes());
#endif
}
void OIIOCommon::BufferToFrame(OIIO::ImageBuf *buf, FramePtr frame)
{
#if OIIO_VERSION < 20112
//
// Workaround for OIIO bug that ignores destination stride in versions OLDER than 2.1.12
//
// See more: https://github.com/OpenImageIO/oiio/pull/2487
//
int width_in_bytes = frame->width() * PixelFormat::BytesPerPixel(frame->format());
for (int i=0;i<buf->spec().height;i++) {
memcpy(frame->data() + i * frame->linesize_bytes(),
#if OIIO_VERSION < 10903
reinterpret_cast<const char*>(buf->localpixels()) + i * width_in_bytes,
#else
reinterpret_cast<const char*>(buf->localpixels()) + i * buf->scanline_stride(),
#endif
width_in_bytes);
}
#else
buf->get_pixels(OIIO::ROI(),
buf->spec().format,
frame->data(),
OIIO::AutoStride,
frame->linesize_bytes());
#endif
}
PixelFormat::Format OIIOCommon::GetFormatFromOIIOBasetype(const OIIO::ImageSpec& spec)
{
if (spec.format == OIIO::TypeDesc::UINT8) {
return PixelFormat::PIX_FMT_RGBA8;
} else if (spec.format == OIIO::TypeDesc::UINT16) {
return PixelFormat::PIX_FMT_RGBA16U;
} else if (spec.format == OIIO::TypeDesc::HALF) {
return PixelFormat::PIX_FMT_RGBA16F;
} else if (spec.format == OIIO::TypeDesc::FLOAT) {
return PixelFormat::PIX_FMT_RGBA32F;
} else {
return PixelFormat::PIX_FMT_INVALID;
}
}
rational OIIOCommon::GetPixelAspectRatioFromOIIO(const OIIO::ImageSpec &spec)
{
return rational::fromDouble(spec.get_float_attribute("PixelAspectRatio", 1));
}
OLIVE_NAMESPACE_EXIT
+47
View File
@@ -0,0 +1,47 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2019 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef OIIOCOMMON_H
#define OIIOCOMMON_H
#include <OpenImageIO/imageio.h>
#include <OpenImageIO/imagebuf.h>
#include "codec/frame.h"
#include "render/pixelformat.h"
OLIVE_NAMESPACE_ENTER
class OIIOCommon
{
public:
static void FrameToBuffer(FramePtr frame, OIIO::ImageBuf* buf);
static void BufferToFrame(OIIO::ImageBuf* buf, FramePtr frame);
static PixelFormat::Format GetFormatFromOIIOBasetype(const OIIO::ImageSpec& spec);
static rational GetPixelAspectRatioFromOIIO(const OIIO::ImageSpec& spec);
};
OLIVE_NAMESPACE_EXIT
#endif // OIIOCOMMON_H
+44 -126
View File
@@ -29,6 +29,7 @@
#include "common/define.h"
#include "config/config.h"
#include "core.h"
#include "oiiocommon.h"
OLIVE_NAMESPACE_ENTER
@@ -40,6 +41,11 @@ OIIODecoder::OIIODecoder() :
{
}
OIIODecoder::~OIIODecoder()
{
CloseInternal();
}
QString OIIODecoder::id()
{
return QStringLiteral("oiio");
@@ -47,6 +53,10 @@ QString OIIODecoder::id()
FootagePtr OIIODecoder::Probe(const QString& filename, const QAtomicInt* cancelled) const
{
Q_UNUSED(cancelled)
// Filter out any file extensions that aren't expected to work - sometimes OIIO will crash trying
// to open a file that it can't if it's given one
if (!FileTypeIsSupported(filename)) {
return nullptr;
}
@@ -59,8 +69,9 @@ FootagePtr OIIODecoder::Probe(const QString& filename, const QAtomicInt* cancell
return nullptr;
}
// Filter out OIIO detecting an "FFmpeg movie", we have a native FFmpeg decoder that can handle
// it better
if (!strcmp(in->format_name(), "FFmpeg movie")) {
// If this is FFmpeg via OIIO, fall-through to our native FFmpeg decoder
return nullptr;
}
@@ -70,8 +81,8 @@ FootagePtr OIIODecoder::Probe(const QString& filename, const QAtomicInt* cancell
image_stream->set_width(in->spec().width);
image_stream->set_height(in->spec().height);
image_stream->set_format(GetFormatFromOIIOBasetype(in->spec()));
image_stream->set_pixel_aspect_ratio(GetPixelAspectRatioFromOIIO(in->spec()));
image_stream->set_format(OIIOCommon::GetFormatFromOIIOBasetype(in->spec()));
image_stream->set_pixel_aspect_ratio(OIIOCommon::GetPixelAspectRatioFromOIIO(in->spec()));
image_stream->set_video_type(VideoStream::kVideoTypeStill);
// Images will always have just one stream
@@ -95,45 +106,40 @@ FootagePtr OIIODecoder::Probe(const QString& filename, const QAtomicInt* cancell
return footage;
}
bool OIIODecoder::Open()
bool OIIODecoder::OpenInternal()
{
Q_ASSERT(stream());
// If we can open the filename provided, assume everything is working (even if this is an image
// sequence with potentially missing frame)
if (OpenImageHandler(stream()->footage()->filename())) {
VideoStreamPtr video_stream = std::static_pointer_cast<VideoStream>(stream());
if (stream()->type() != Stream::kVideo) {
// Guard against non-video types
return false;
if (video_stream->video_type() == VideoStream::kVideoTypeStill) {
last_sequence_index_ = 0;
} else {
last_sequence_index_ = GetImageSequenceIndex(stream()->footage()->filename());
}
return true;
}
VideoStreamPtr video_stream = std::static_pointer_cast<VideoStream>(stream());
if (video_stream->video_type() == VideoStream::kVideoTypeVideo) {
// This decoder only handles kVideoTypeImageSequence and kVideoTypeStill
return false;
}
if (video_stream->video_type() == VideoStream::kVideoTypeStill
&& !OpenImageHandler(stream()->footage()->filename())) {
return false;
}
open_ = true;
return true;
return false;
}
FramePtr OIIODecoder::RetrieveVideo(const rational &timecode, const int& divider)
FramePtr OIIODecoder::RetrieveVideoInternal(const rational &timecode, const int& divider)
{
if (!open_) {
qWarning() << "Tried to retrieve video on a decoder that's still closed";
return nullptr;
}
VideoStreamPtr video_stream = std::static_pointer_cast<VideoStream>(stream());
if (video_stream->video_type() == VideoStream::kVideoTypeImageSequence) {
int64_t ts = video_stream->get_time_in_timebase_units(timecode);
int64_t sequence_index;
if (!OpenImageHandler(TransformImageSequenceFileName(stream()->footage()->filename(), ts))) {
if (video_stream->video_type() == VideoStream::kVideoTypeStill) {
sequence_index = 0;
} else {
sequence_index = video_stream->get_time_in_timebase_units(timecode);
}
if (last_sequence_index_ != sequence_index) {
CloseImageHandle();
if (!OpenImageHandler(TransformImageSequenceFileName(stream()->footage()->filename(), sequence_index))) {
return nullptr;
}
}
@@ -143,14 +149,14 @@ FramePtr OIIODecoder::RetrieveVideo(const rational &timecode, const int& divider
frame->set_video_params(VideoParams(buffer_->spec().width,
buffer_->spec().height,
pix_fmt_,
GetPixelAspectRatioFromOIIO(buffer_->spec()),
OIIOCommon::GetPixelAspectRatioFromOIIO(buffer_->spec()),
VideoParams::kInterlaceNone, // FIXME: Does OIIO deinterlace for us?
divider));
frame->allocate();
if (divider == 1) {
BufferToFrame(buffer_, frame);
OIIOCommon::BufferToFrame(buffer_, frame);
} else {
@@ -161,106 +167,18 @@ FramePtr OIIODecoder::RetrieveVideo(const rational &timecode, const int& divider
qWarning() << "OIIO resize failed";
}
BufferToFrame(&dst, frame);
OIIOCommon::BufferToFrame(&dst, frame);
}
if (video_stream->video_type() == VideoStream::kVideoTypeImageSequence) {
CloseImageHandle();
}
return frame;
}
void OIIODecoder::Close()
void OIIODecoder::CloseInternal()
{
CloseImageHandle();
}
bool OIIODecoder::SupportsVideo()
{
return true;
}
void OIIODecoder::FrameToBuffer(FramePtr frame, OIIO::ImageBuf *buf)
{
#if OIIO_VERSION < 20112
//
// Workaround for OIIO bug that ignores destination stride in versions OLDER than 2.1.12
//
// See more: https://github.com/OpenImageIO/oiio/pull/2487
//
int width_in_bytes = frame->width() * PixelFormat::BytesPerPixel(frame->format());
for (int i=0;i<buf->spec().height;i++) {
memcpy(
#if OIIO_VERSION < 10903
reinterpret_cast<char*>(buf->localpixels()) + i * width_in_bytes,
#else
reinterpret_cast<char*>(buf->localpixels()) + i * buf->scanline_stride(),
#endif
frame->data() + i * frame->linesize_bytes(),
width_in_bytes);
}
#else
buf->set_pixels(OIIO::ROI(),
buf->spec().format,
frame->data(),
OIIO::AutoStride,
frame->linesize_bytes());
#endif
}
void OIIODecoder::BufferToFrame(OIIO::ImageBuf *buf, FramePtr frame)
{
#if OIIO_VERSION < 20112
//
// Workaround for OIIO bug that ignores destination stride in versions OLDER than 2.1.12
//
// See more: https://github.com/OpenImageIO/oiio/pull/2487
//
int width_in_bytes = frame->width() * PixelFormat::BytesPerPixel(frame->format());
for (int i=0;i<buf->spec().height;i++) {
memcpy(frame->data() + i * frame->linesize_bytes(),
#if OIIO_VERSION < 10903
reinterpret_cast<const char*>(buf->localpixels()) + i * width_in_bytes,
#else
reinterpret_cast<const char*>(buf->localpixels()) + i * buf->scanline_stride(),
#endif
width_in_bytes);
}
#else
buf->get_pixels(OIIO::ROI(),
buf->spec().format,
frame->data(),
OIIO::AutoStride,
frame->linesize_bytes());
#endif
}
PixelFormat::Format OIIODecoder::GetFormatFromOIIOBasetype(const OIIO::ImageSpec& spec)
{
bool has_alpha = (spec.nchannels == kRGBAChannels);
if (spec.format == OIIO::TypeDesc::UINT8) {
return has_alpha ? PixelFormat::PIX_FMT_RGBA8 : PixelFormat::PIX_FMT_RGB8;
} else if (spec.format == OIIO::TypeDesc::UINT16) {
return has_alpha ? PixelFormat::PIX_FMT_RGBA16U : PixelFormat::PIX_FMT_RGB16U;
} else if (spec.format == OIIO::TypeDesc::HALF) {
return has_alpha ? PixelFormat::PIX_FMT_RGBA16F : PixelFormat::PIX_FMT_RGB16F;
} else if (spec.format == OIIO::TypeDesc::FLOAT) {
return has_alpha ? PixelFormat::PIX_FMT_RGBA32F : PixelFormat::PIX_FMT_RGB32F;
} else {
return PixelFormat::PIX_FMT_INVALID;
}
}
rational OIIODecoder::GetPixelAspectRatioFromOIIO(const OIIO::ImageSpec &spec)
{
return rational::fromDouble(spec.get_float_attribute("PixelAspectRatio", 1));
}
bool OIIODecoder::FileTypeIsSupported(const QString& fn)
{
// We prioritize OIIO over FFmpeg to pick up still images more effectively, but some OIIO decoders (notably OpenJPEG)
@@ -299,7 +217,7 @@ bool OIIODecoder::OpenImageHandler(const QString &fn)
is_rgba_ = (spec.nchannels == kRGBAChannels);
pix_fmt_ = GetFormatFromOIIOBasetype(spec);
pix_fmt_ = OIIOCommon::GetFormatFromOIIOBasetype(spec);
if (pix_fmt_ == PixelFormat::PIX_FMT_INVALID) {
qWarning() << "Failed to convert OIIO::ImageDesc to native pixel format";
+10 -13
View File
@@ -35,23 +35,18 @@ class OIIODecoder : public Decoder
public:
OIIODecoder();
virtual ~OIIODecoder() override;
virtual QString id() override;
virtual bool SupportsVideo() override{return true;}
virtual FootagePtr Probe(const QString& filename, const QAtomicInt* cancelled) const override;
virtual bool Open() override;
virtual FramePtr RetrieveVideo(const rational &timecode, const int& divider) override;
virtual void Close() override;
virtual bool SupportsVideo() override;
static void FrameToBuffer(FramePtr frame, OIIO::ImageBuf* buf);
static void BufferToFrame(OIIO::ImageBuf* buf, FramePtr frame);
static PixelFormat::Format GetFormatFromOIIOBasetype(const OIIO::ImageSpec& spec);
static rational GetPixelAspectRatioFromOIIO(const OIIO::ImageSpec& spec);
protected:
virtual bool OpenInternal() override;
virtual FramePtr RetrieveVideoInternal(const rational &timecode, const int& divider) override;
virtual void CloseInternal() override;
private:
#if OIIO_VERSION < 10903
@@ -66,6 +61,8 @@ private:
void CloseImageHandle();
int64_t last_sequence_index_;
PixelFormat::Format pix_fmt_;
bool is_rgba_;