improved render channel count system

This commit is contained in:
itsmattkc
2020-11-15 22:16:40 +11:00
parent ee5307336e
commit 0d0766e4fb
83 changed files with 1017 additions and 1132 deletions
+1 -1
View File
@@ -24,11 +24,11 @@
#include <QDebug>
#include <QFileInfo>
#include "codec/ffmpeg/ffmpegcommon.h"
#include "codec/ffmpeg/ffmpegdecoder.h"
#include "codec/oiio/oiiodecoder.h"
#include "codec/waveinput.h"
#include "codec/waveoutput.h"
#include "common/ffmpegutils.h"
#include "common/filefunctions.h"
#include "common/timecodefunctions.h"
#ifdef USE_OTIO
+2 -2
View File
@@ -122,9 +122,9 @@ public:
virtual void Close() = 0;
virtual PixelFormat::Format GetDesiredPixelFormat() const
virtual VideoParams::Format GetDesiredPixelFormat() const
{
return PixelFormat::PIX_FMT_INVALID;
return VideoParams::kFormatInvalid;
}
private:
-2
View File
@@ -17,8 +17,6 @@
set(OLIVE_SOURCES
${OLIVE_SOURCES}
codec/ffmpeg/avframeptr.h
codec/ffmpeg/ffmpegcommon.h
codec/ffmpeg/ffmpegcommon.cpp
codec/ffmpeg/ffmpegdecoder.h
codec/ffmpeg/ffmpegdecoder.cpp
codec/ffmpeg/ffmpegencoder.h
-125
View File
@@ -1,125 +0,0 @@
/***
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 "ffmpegcommon.h"
OLIVE_NAMESPACE_ENTER
AVPixelFormat FFmpegCommon::GetCompatiblePixelFormat(const AVPixelFormat &pix_fmt)
{
AVPixelFormat possible_pix_fmts[] = {
AV_PIX_FMT_RGBA,
AV_PIX_FMT_RGBA64,
AV_PIX_FMT_NONE
};
return avcodec_find_best_pix_fmt_of_list(possible_pix_fmts,
pix_fmt,
1,
nullptr);
}
SampleFormat::Format FFmpegCommon::GetNativeSampleFormat(const AVSampleFormat &smp_fmt)
{
switch (smp_fmt) {
case AV_SAMPLE_FMT_U8:
return SampleFormat::SAMPLE_FMT_U8;
case AV_SAMPLE_FMT_S16:
return SampleFormat::SAMPLE_FMT_S16;
case AV_SAMPLE_FMT_S32:
return SampleFormat::SAMPLE_FMT_S32;
case AV_SAMPLE_FMT_S64:
return SampleFormat::SAMPLE_FMT_S64;
case AV_SAMPLE_FMT_FLT:
return SampleFormat::SAMPLE_FMT_FLT;
case AV_SAMPLE_FMT_DBL:
return SampleFormat::SAMPLE_FMT_DBL;
case AV_SAMPLE_FMT_U8P :
case AV_SAMPLE_FMT_S16P:
case AV_SAMPLE_FMT_S32P:
case AV_SAMPLE_FMT_S64P:
case AV_SAMPLE_FMT_FLTP:
case AV_SAMPLE_FMT_DBLP:
case AV_SAMPLE_FMT_NONE:
case AV_SAMPLE_FMT_NB:
break;
}
return SampleFormat::SAMPLE_FMT_INVALID;
}
AVSampleFormat FFmpegCommon::GetFFmpegSampleFormat(const SampleFormat::Format &smp_fmt)
{
switch (smp_fmt) {
case SampleFormat::SAMPLE_FMT_U8:
return AV_SAMPLE_FMT_U8;
case SampleFormat::SAMPLE_FMT_S16:
return AV_SAMPLE_FMT_S16;
case SampleFormat::SAMPLE_FMT_S32:
return AV_SAMPLE_FMT_S32;
case SampleFormat::SAMPLE_FMT_S64:
return AV_SAMPLE_FMT_S64;
case SampleFormat::SAMPLE_FMT_FLT:
return AV_SAMPLE_FMT_FLT;
case SampleFormat::SAMPLE_FMT_DBL:
return AV_SAMPLE_FMT_DBL;
case SampleFormat::SAMPLE_FMT_INVALID:
case SampleFormat::SAMPLE_FMT_COUNT:
break;
}
return AV_SAMPLE_FMT_NONE;
}
AVPixelFormat FFmpegCommon::GetFFmpegPixelFormat(const PixelFormat::Format &pix_fmt)
{
switch (pix_fmt) {
case PixelFormat::PIX_FMT_RGBA8:
return AV_PIX_FMT_RGBA;
case PixelFormat::PIX_FMT_RGBA16U:
return AV_PIX_FMT_RGBA64;
case PixelFormat::PIX_FMT_RGBA16F:
case PixelFormat::PIX_FMT_RGBA32F:
case PixelFormat::PIX_FMT_INVALID:
case PixelFormat::PIX_FMT_COUNT:
break;
}
return AV_PIX_FMT_NONE;
}
PixelFormat::Format FFmpegCommon::GetCompatiblePixelFormat(const PixelFormat::Format &pix_fmt)
{
switch (pix_fmt) {
case PixelFormat::PIX_FMT_RGBA8:
return PixelFormat::PIX_FMT_RGBA8;
case PixelFormat::PIX_FMT_RGBA16U:
case PixelFormat::PIX_FMT_RGBA16F:
case PixelFormat::PIX_FMT_RGBA32F:
return PixelFormat::PIX_FMT_RGBA16U;
case PixelFormat::PIX_FMT_INVALID:
case PixelFormat::PIX_FMT_COUNT:
break;
}
return PixelFormat::PIX_FMT_INVALID;
}
OLIVE_NAMESPACE_EXIT
-63
View File
@@ -1,63 +0,0 @@
/***
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 FFMPEGABSTRACTION_H
#define FFMPEGABSTRACTION_H
extern "C" {
#include <libavformat/avformat.h>
}
#include "audio/sampleformat.h"
#include "render/pixelformat.h"
OLIVE_NAMESPACE_ENTER
class FFmpegCommon {
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);
/**
* @brief Returns a native pixel format that can be used to convert from a native frame to an AVFrame with minimal data loss
*/
static PixelFormat::Format GetCompatiblePixelFormat(const PixelFormat::Format& pix_fmt);
/**
* @brief Returns an FFmpeg pixel format for a given native pixel format
*/
static AVPixelFormat GetFFmpegPixelFormat(const PixelFormat::Format& pix_fmt);
/**
* @brief Returns a native sample format type for a given AVSampleFormat
*/
static SampleFormat::Format GetNativeSampleFormat(const AVSampleFormat& smp_fmt);
/**
* @brief Returns an FFmpeg sample format type for a given native type
*/
static AVSampleFormat GetFFmpegSampleFormat(const SampleFormat::Format &smp_fmt);
};
OLIVE_NAMESPACE_EXIT
#endif // FFMPEGABSTRACTION_H
+36 -12
View File
@@ -38,13 +38,12 @@ extern "C" {
#include "codec/waveinput.h"
#include "common/define.h"
#include "common/ffmpegutils.h"
#include "common/filefunctions.h"
#include "common/functiontimer.h"
#include "common/timecodefunctions.h"
#include "ffmpegcommon.h"
#include "render/framehashcache.h"
#include "render/diskmanager.h"
#include "render/pixelformat.h"
OLIVE_NAMESPACE_ENTER
@@ -73,13 +72,17 @@ bool FFmpegDecoder::OpenInternal()
if (stream()->type() == Stream::kVideo) {
// Get an Olive compatible AVPixelFormat
ideal_pix_fmt_ = FFmpegCommon::GetCompatiblePixelFormat(static_cast<AVPixelFormat>(s->codecpar->format));
ideal_pix_fmt_ = FFmpegUtils::GetCompatiblePixelFormat(static_cast<AVPixelFormat>(s->codecpar->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_channel_count_ = GetNativeChannelCount(ideal_pix_fmt_);
if (native_pix_fmt_ == PixelFormat::PIX_FMT_INVALID) {
qDebug() << "Set channel count to:" << native_channel_count_;
if (native_pix_fmt_ == VideoParams::kFormatInvalid
|| native_channel_count_ == 0) {
qDebug() << "Failed to find valid native pixel format for" << ideal_pix_fmt_;
return false;
}
@@ -124,6 +127,7 @@ FramePtr FFmpegDecoder::RetrieveStillImage(const rational &timecode, const int &
output_frame->set_video_params(VideoParams(frame->width,
frame->height,
native_pix_fmt_,
native_channel_count_,
std::static_pointer_cast<VideoStream>(stream())->pixel_aspect_ratio(),
std::static_pointer_cast<VideoStream>(stream())->interlacing(),
divider));
@@ -172,7 +176,7 @@ FramePtr FFmpegDecoder::RetrieveVideoInternal(const rational &timecode, const in
ClearFrameCache();
// Set new frame pool parameters
pool_.SetParameters(divided_width, divided_height, native_pix_fmt_);
pool_.SetParameters(divided_width, divided_height, native_pix_fmt_, native_channel_count_);
}
// Retrieve frame
@@ -184,6 +188,7 @@ FramePtr FFmpegDecoder::RetrieveVideoInternal(const rational &timecode, const in
copy->set_video_params(VideoParams(vs->width(),
vs->height(),
native_pix_fmt_,
native_channel_count_,
std::static_pointer_cast<VideoStream>(stream())->pixel_aspect_ratio(),
std::static_pointer_cast<VideoStream>(stream())->interlacing(),
divider));
@@ -328,10 +333,13 @@ FootagePtr FFmpegDecoder::Probe(const QString& filename, const QAtomicInt* cance
video_stream->set_width(avstream->codecpar->width);
video_stream->set_height(avstream->codecpar->height);
video_stream->set_format(GetNativePixelFormat(FFmpegCommon::GetCompatiblePixelFormat(static_cast<AVPixelFormat>(avstream->codecpar->format))));
video_stream->set_interlacing(interlacing);
video_stream->set_pixel_aspect_ratio(pixel_aspect_ratio);
AVPixelFormat compatible_pix_fmt = FFmpegUtils::GetCompatiblePixelFormat(static_cast<AVPixelFormat>(avstream->codecpar->format));
video_stream->set_format(GetNativePixelFormat(compatible_pix_fmt));
video_stream->set_channel_count(GetNativeChannelCount(compatible_pix_fmt));
str = video_stream;
} else {
@@ -460,7 +468,7 @@ bool FFmpegDecoder::ConformAudioInternal(const QString &filename, const AudioPar
// Create resampling context
SwrContext* resampler = swr_alloc_set_opts(nullptr,
params.channel_layout(),
FFmpegCommon::GetFFmpegSampleFormat(params.format()),
FFmpegUtils::GetFFmpegSampleFormat(params.format()),
params.sample_rate(),
channel_layout,
static_cast<AVSampleFormat>(instance_.avstream()->codecpar->format),
@@ -542,15 +550,31 @@ bool FFmpegDecoder::ConformAudioInternal(const QString &filename, const AudioPar
return success;
}
PixelFormat::Format FFmpegDecoder::GetNativePixelFormat(AVPixelFormat pix_fmt)
VideoParams::Format FFmpegDecoder::GetNativePixelFormat(AVPixelFormat pix_fmt)
{
switch (pix_fmt) {
case AV_PIX_FMT_RGB24:
case AV_PIX_FMT_RGBA:
return PixelFormat::PIX_FMT_RGBA8;
return VideoParams::kFormatUnsigned8;
case AV_PIX_FMT_RGB48:
case AV_PIX_FMT_RGBA64:
return PixelFormat::PIX_FMT_RGBA16U;
return VideoParams::kFormatUnsigned16;
default:
return PixelFormat::PIX_FMT_INVALID;
return VideoParams::kFormatInvalid;
}
}
int FFmpegDecoder::GetNativeChannelCount(AVPixelFormat pix_fmt)
{
switch (pix_fmt) {
case AV_PIX_FMT_RGB24:
case AV_PIX_FMT_RGB48:
return VideoParams::kRGBChannelCount;
case AV_PIX_FMT_RGBA:
case AV_PIX_FMT_RGBA64:
return VideoParams::kRGBAChannelCount;
default:
return 0;
}
}
@@ -729,7 +753,7 @@ FFmpegFramePool::ElementPtr FFmpegDecoder::RetrieveFrame(const int64_t& target_t
// Store in queue, converting to native format
uint8_t* destination_data = cached->data();
int destination_linesize = Frame::generate_linesize_bytes(VideoParams::GetScaledDimension(instance_.avstream()->codecpar->width, divider), native_pix_fmt_);
int destination_linesize = Frame::generate_linesize_bytes(VideoParams::GetScaledDimension(instance_.avstream()->codecpar->width, divider), native_pix_fmt_, native_channel_count_);
FFmpegBufferToNativeBuffer(working_frame->data, working_frame->linesize, &destination_data, &destination_linesize);
// Set timestamp so this frame can be identified later
+4 -3
View File
@@ -32,7 +32,6 @@ extern "C" {
#include <QVector>
#include <QWaitCondition>
#include "audio/sampleformat.h"
#include "avframeptr.h"
#include "codec/decoder.h"
#include "codec/waveoutput.h"
@@ -126,7 +125,8 @@ private:
FramePtr RetrieveStillImage(const rational& timecode, const int& divider);
static PixelFormat::Format GetNativePixelFormat(AVPixelFormat pix_fmt);
static VideoParams::Format GetNativePixelFormat(AVPixelFormat pix_fmt);
static int GetNativeChannelCount(AVPixelFormat pix_fmt);
static uint64_t ValidateChannelLayout(AVStream *stream);
@@ -143,7 +143,8 @@ private:
SwsContext* scale_ctx_;
int scale_divider_;
AVPixelFormat ideal_pix_fmt_;
PixelFormat::Format native_pix_fmt_;
VideoParams::Format native_pix_fmt_;
int native_channel_count_;
FFmpegFramePool pool_;
+50 -22
View File
@@ -26,8 +26,7 @@ extern "C" {
#include <QFile>
#include "ffmpegcommon.h"
#include "render/pixelformat.h"
#include "common/ffmpegutils.h"
OLIVE_NAMESPACE_ENTER
@@ -36,7 +35,8 @@ FFmpegEncoder::FFmpegEncoder(const EncodingParams &params) :
fmt_ctx_(nullptr),
video_stream_(nullptr),
video_codec_ctx_(nullptr),
video_scale_ctx_(nullptr),
video_alpha_scale_ctx_(nullptr),
video_noalpha_scale_ctx_(nullptr),
audio_stream_(nullptr),
audio_codec_ctx_(nullptr),
audio_resample_ctx_(nullptr),
@@ -72,29 +72,49 @@ bool FFmpegEncoder::Open()
}
// This is the format we will expect frames received in Write() to be in
PixelFormat::Format native_pixel_fmt = params().video_params().format();
VideoParams::Format native_pixel_fmt = params().video_params().format();
// This is the format we will need to convert the frame to for swscale to understand it
video_conversion_fmt_ = FFmpegCommon::GetCompatiblePixelFormat(native_pixel_fmt);
video_conversion_fmt_ = FFmpegUtils::GetCompatiblePixelFormat(native_pixel_fmt);
// This is the equivalent pixel format above as an AVPixelFormat that swscale can understand
AVPixelFormat src_pix_fmt = FFmpegCommon::GetFFmpegPixelFormat(video_conversion_fmt_);
AVPixelFormat src_alpha_pix_fmt = FFmpegUtils::GetFFmpegPixelFormat(video_conversion_fmt_,
VideoParams::kRGBAChannelCount);
AVPixelFormat src_noalpha_pix_fmt = FFmpegUtils::GetFFmpegPixelFormat(video_conversion_fmt_,
VideoParams::kRGBChannelCount);
if (src_alpha_pix_fmt == AV_PIX_FMT_NONE || src_noalpha_pix_fmt == AV_PIX_FMT_NONE) {
Error(QStringLiteral("Failed to find suitable pixel format for this buffer"));
return false;
}
// This is the pixel format the encoder wants to encode to
AVPixelFormat encoder_pix_fmt = video_codec_ctx_->pix_fmt;
// Set up a scaling context - if the native pixel format is not equal to the encoder's, we'll need to convert it
// before encoding. Even if we don't, this may be useful for converting between linesizes, etc.
video_scale_ctx_ = sws_getContext(params().video_params().width(),
params().video_params().height(),
src_pix_fmt,
params().video_params().width(),
params().video_params().height(),
encoder_pix_fmt,
0,
nullptr,
nullptr,
nullptr);
video_alpha_scale_ctx_ = sws_getContext(params().video_params().width(),
params().video_params().height(),
src_alpha_pix_fmt,
params().video_params().width(),
params().video_params().height(),
encoder_pix_fmt,
0,
nullptr,
nullptr,
nullptr);
video_noalpha_scale_ctx_ = sws_getContext(params().video_params().width(),
params().video_params().height(),
src_noalpha_pix_fmt,
params().video_params().width(),
params().video_params().height(),
encoder_pix_fmt,
0,
nullptr,
nullptr,
nullptr);
}
// Initialize an audio stream if it's enabled
@@ -157,19 +177,22 @@ bool FFmpegEncoder::WriteFrame(FramePtr frame, rational time)
// We may need to convert this frame to a frame that swscale will understand
if (frame->format() != video_conversion_fmt_) {
frame = PixelFormat::ConvertPixelFormat(frame, video_conversion_fmt_);
frame = frame->convert(video_conversion_fmt_);
}
// Use swscale context to convert formats/linesizes
input_data = frame->const_data();
input_linesize = frame->linesize_bytes();
error_code = sws_scale(video_scale_ctx_,
error_code = sws_scale((frame->channel_count() == VideoParams::kRGBAChannelCount) ? video_alpha_scale_ctx_ : video_noalpha_scale_ctx_,
reinterpret_cast<const uint8_t**>(&input_data),
&input_linesize,
0,
frame->height(),
encoded_frame->data,
encoded_frame->linesize);
if (error_code < 0) {
FFmpegError("Failed to scale frame", error_code);
goto fail;
@@ -208,7 +231,7 @@ void FFmpegEncoder::WriteAudio(AudioParams pcm_info, QIODevice* file)
audio_codec_ctx_->sample_fmt,
audio_codec_ctx_->sample_rate,
static_cast<int64_t>(pcm_info.channel_layout()),
FFmpegCommon::GetFFmpegSampleFormat(pcm_info.format()),
FFmpegUtils::GetFFmpegSampleFormat(pcm_info.format()),
pcm_info.sample_rate(),
0,
nullptr);
@@ -300,9 +323,14 @@ void FFmpegEncoder::Close()
open_ = false;
}
if (video_scale_ctx_) {
sws_freeContext(video_scale_ctx_);
video_scale_ctx_ = nullptr;
if (video_alpha_scale_ctx_) {
sws_freeContext(video_alpha_scale_ctx_);
video_alpha_scale_ctx_ = nullptr;
}
if (video_noalpha_scale_ctx_) {
sws_freeContext(video_noalpha_scale_ctx_);
video_noalpha_scale_ctx_ = nullptr;
}
if (video_codec_ctx_) {
+4 -3
View File
@@ -47,7 +47,7 @@ public:
virtual void Close() override;
virtual PixelFormat::Format GetDesiredPixelFormat() const override
virtual VideoParams::Format GetDesiredPixelFormat() const override
{
return video_conversion_fmt_;
}
@@ -85,8 +85,9 @@ private:
AVStream* video_stream_;
AVCodecContext* video_codec_ctx_;
SwsContext* video_scale_ctx_;
PixelFormat::Format video_conversion_fmt_;
SwsContext* video_alpha_scale_ctx_;
SwsContext* video_noalpha_scale_ctx_;
VideoParams::Format video_conversion_fmt_;
AVStream* audio_stream_;
AVCodecContext* audio_codec_ctx_;
+5 -3
View File
@@ -28,22 +28,24 @@ FFmpegFramePool::FFmpegFramePool(int element_count) :
MemoryPool(element_count),
width_(0),
height_(0),
format_(PixelFormat::PIX_FMT_INVALID)
format_(VideoParams::kFormatInvalid),
channel_count_(0)
{
}
void FFmpegFramePool::SetParameters(int width, int height, PixelFormat::Format format)
void FFmpegFramePool::SetParameters(int width, int height, VideoParams::Format format, int channel_count)
{
Clear();
width_ = width;
height_ = height;
format_ = format;
channel_count_ = channel_count;
}
size_t FFmpegFramePool::GetElementSize()
{
return Frame::generate_linesize_bytes(width_, format_) * height_;
return Frame::generate_linesize_bytes(width_, format_, channel_count_) * height_;
}
OLIVE_NAMESPACE_EXIT
+4 -3
View File
@@ -22,7 +22,6 @@
#define FFMPEGFRAMEPOOL_H
#include "common/memorypool.h"
#include "render/pixelformat.h"
#include "render/videoparams.h"
OLIVE_NAMESPACE_ENTER
@@ -32,7 +31,7 @@ class FFmpegFramePool : public MemoryPool<uint8_t>
public:
FFmpegFramePool(int element_count);
void SetParameters(int width, int height, PixelFormat::Format format);
void SetParameters(int width, int height, VideoParams::Format format, int channel_count);
const int& width() const
{
@@ -52,7 +51,9 @@ private:
int height_;
PixelFormat::Format format_;
VideoParams::Format format_;
int channel_count_;
};
+43 -9
View File
@@ -20,10 +20,13 @@
#include "frame.h"
#include <OpenImageIO/imagebuf.h>
#include <QDebug>
#include <QtGlobal>
#include <QtMath>
#include "common/oiioutils.h"
OLIVE_NAMESPACE_ENTER
Frame::Frame() :
@@ -45,14 +48,14 @@ void Frame::set_video_params(const VideoParams &params)
{
params_ = params;
linesize_ = generate_linesize_bytes(width(), params_.format());
linesize_pixels_ = linesize_ / PixelFormat::BytesPerPixel(params_.format());
linesize_ = generate_linesize_bytes(width(), params_.format(), params_.channel_count());
linesize_pixels_ = linesize_ / params_.GetBytesPerPixel();
}
int Frame::generate_linesize_bytes(int width, PixelFormat::Format format)
int Frame::generate_linesize_bytes(int width, VideoParams::Format format, int channel_count)
{
// Align to 32 bytes (not sure if this is necessary?)
return PixelFormat::BytesPerPixel(format) * ((width + 31) & ~31);
return VideoParams::GetBytesPerPixel(format, channel_count) * ((width + 31) & ~31);
}
Color Frame::get_pixel(int x, int y) const
@@ -61,9 +64,9 @@ Color Frame::get_pixel(int x, int y) const
return Color();
}
int byte_offset = y * linesize_bytes() + x * PixelFormat::BytesPerPixel(video_params().format());
int byte_offset = y * linesize_bytes() + x * video_params().GetBytesPerPixel();
return Color(data_.data() + byte_offset, video_params().format());
return Color(data_.data() + byte_offset, video_params().format(), video_params().channel_count());
}
bool Frame::contains_pixel(int x, int y) const
@@ -77,9 +80,9 @@ void Frame::set_pixel(int x, int y, const Color &c)
return;
}
int byte_offset = y * linesize_bytes() + x * PixelFormat::BytesPerPixel(video_params().format());
int byte_offset = y * linesize_bytes() + x * video_params().GetBytesPerPixel();
c.toData(data_.data() + byte_offset, video_params().format());
c.toData(data_.data() + byte_offset, video_params().format(), video_params().channel_count());
}
bool Frame::allocate()
@@ -90,9 +93,40 @@ bool Frame::allocate()
return false;
}
data_.resize(PixelFormat::GetBufferSize(params_.format(), linesize_, height()));
data_.resize(VideoParams::GetBufferSize(linesize_, height(), params_.format(), params_.channel_count()));
return true;
}
FramePtr Frame::convert(VideoParams::Format format) const
{
// Create new params with destination format
VideoParams params = params_;
params.set_format(format);
// Create new frame
FramePtr converted = Frame::Create();
converted->set_video_params(params);
converted->set_timestamp(timestamp_);
converted->allocate();
// Do the conversion through OIIO for convenience
OIIO::ImageBuf src(OIIO::ImageSpec(width(), height(),
channel_count(),
OIIOUtils::GetOIIOBaseTypeFromFormat(this->format())));
OIIOUtils::FrameToBuffer(this, &src);
OIIO::ImageBuf dst(OIIO::ImageSpec(converted->width(), converted->height(),
channel_count(),
OIIOUtils::GetOIIOBaseTypeFromFormat(format)));
if (dst.copy_pixels(src)) {
OIIOUtils::BufferToFrame(&dst, converted.get());
return converted;
} else {
return nullptr;
}
}
OLIVE_NAMESPACE_EXIT
+9 -3
View File
@@ -26,7 +26,6 @@
#include "common/rational.h"
#include "render/color.h"
#include "render/pixelformat.h"
#include "render/videoparams.h"
OLIVE_NAMESPACE_ENTER
@@ -47,7 +46,7 @@ public:
const VideoParams& video_params() const;
void set_video_params(const VideoParams& params);
static int generate_linesize_bytes(int width, PixelFormat::Format format);
static int generate_linesize_bytes(int width, VideoParams::Format format, int channel_count);
int linesize_pixels() const
{
@@ -69,11 +68,16 @@ public:
return params_.effective_height();
}
PixelFormat::Format format() const
VideoParams::Format format() const
{
return params_.format();
}
int channel_count() const
{
return params_.channel_count();
}
Color get_pixel(int x, int y) const;
bool contains_pixel(int x, int y) const;
void set_pixel(int x, int y, const Color& c);
@@ -144,6 +148,8 @@ public:
return data_.size();
}
FramePtr convert(VideoParams::Format format) const;
private:
VideoParams params_;
-2
View File
@@ -16,8 +16,6 @@
set(OLIVE_SOURCES
${OLIVE_SOURCES}
codec/oiio/oiiocommon.cpp
codec/oiio/oiiocommon.h
codec/oiio/oiiodecoder.cpp
codec/oiio/oiiodecoder.h
PARENT_SCOPE
-102
View File
@@ -1,102 +0,0 @@
/***
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
@@ -1,47 +0,0 @@
/***
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
+18 -11
View File
@@ -27,9 +27,9 @@
#include <QMessageBox>
#include "common/define.h"
#include "common/oiioutils.h"
#include "config/config.h"
#include "core.h"
#include "oiiocommon.h"
OLIVE_NAMESPACE_ENTER
@@ -81,8 +81,9 @@ 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(OIIOCommon::GetFormatFromOIIOBasetype(in->spec()));
image_stream->set_pixel_aspect_ratio(OIIOCommon::GetPixelAspectRatioFromOIIO(in->spec()));
image_stream->set_format(OIIOUtils::GetFormatFromOIIOBasetype(static_cast<OIIO::TypeDesc::BASETYPE>(in->spec().format.basetype)));
image_stream->set_channel_count(in->spec().nchannels);
image_stream->set_pixel_aspect_ratio(OIIOUtils::GetPixelAspectRatioFromOIIO(in->spec()));
image_stream->set_video_type(VideoStream::kVideoTypeStill);
// Images will always have just one stream
@@ -149,14 +150,15 @@ FramePtr OIIODecoder::RetrieveVideoInternal(const rational &timecode, const int&
frame->set_video_params(VideoParams(buffer_->spec().width,
buffer_->spec().height,
pix_fmt_,
OIIOCommon::GetPixelAspectRatioFromOIIO(buffer_->spec()),
channel_count_,
OIIOUtils::GetPixelAspectRatioFromOIIO(buffer_->spec()),
VideoParams::kInterlaceNone, // FIXME: Does OIIO deinterlace for us?
divider));
frame->allocate();
if (divider == 1) {
OIIOCommon::BufferToFrame(buffer_, frame);
OIIOUtils::BufferToFrame(buffer_, frame.get());
} else {
@@ -167,7 +169,7 @@ FramePtr OIIODecoder::RetrieveVideoInternal(const rational &timecode, const int&
qWarning() << "OIIO resize failed";
}
OIIOCommon::BufferToFrame(&dst, frame);
OIIOUtils::BufferToFrame(&dst, frame.get());
}
@@ -215,18 +217,23 @@ bool OIIODecoder::OpenImageHandler(const QString &fn)
// Check if we can work with this pixel format
const OIIO::ImageSpec& spec = image_->spec();
//is_rgba_ = (spec.nchannels == kRGBAChannels);
// Store channel count
channel_count_ = spec.nchannels;
// We use RGBA frames because that tends to be the native format of GPUs
pix_fmt_ = OIIOCommon::GetFormatFromOIIOBasetype(spec);
pix_fmt_ = OIIOUtils::GetFormatFromOIIOBasetype(static_cast<OIIO::TypeDesc::BASETYPE>(spec.format.basetype));
if (pix_fmt_ == PixelFormat::PIX_FMT_INVALID) {
if (pix_fmt_ == VideoParams::kFormatInvalid) {
qWarning() << "Failed to convert OIIO::ImageDesc to native pixel format";
return false;
}
// FIXME: Many OIIO pixel formats are not handled here
OIIO::TypeDesc type = PixelFormat::GetOIIOTypeDesc(pix_fmt_);
OIIO::TypeDesc::BASETYPE type = OIIOUtils::GetOIIOBaseTypeFromFormat(pix_fmt_);
if (type == OIIO::TypeDesc::UNKNOWN) {
qCritical() << "Failed to determine appropriate OIIO basetype from native format";
return false;
}
#if OIIO_VERSION < 20100
buffer_ = new OIIO::ImageBuf(OIIO::ImageSpec(spec.width, spec.height, spec.nchannels, type));
+2 -3
View File
@@ -25,7 +25,6 @@
#include <OpenImageIO/imagebuf.h>
#include "codec/decoder.h"
#include "render/pixelformat.h"
OLIVE_NAMESPACE_ENTER
@@ -63,9 +62,9 @@ private:
int64_t last_sequence_index_;
PixelFormat::Format pix_fmt_;
VideoParams::Format pix_fmt_;
//bool is_rgba_;
int channel_count_;
OIIO::ImageBuf* buffer_;
+7 -7
View File
@@ -108,27 +108,27 @@ bool WaveInput::open()
uint16_t bits_per_sample;
data_stream >> bits_per_sample;
SampleFormat::Format format;
AudioParams::Format format;
switch (bits_per_sample) {
case 8:
format = SampleFormat::SAMPLE_FMT_U8;
format = AudioParams::kFormatUnsigned8;
break;
case 16:
format = SampleFormat::SAMPLE_FMT_S16;
format = AudioParams::kFormatSigned16;
break;
case 32:
if (data_is_float) {
format = SampleFormat::SAMPLE_FMT_FLT;
format = AudioParams::kFormatFloat32;
} else {
format = SampleFormat::SAMPLE_FMT_S32;
format = AudioParams::kFormatSigned32;
}
break;
case 64:
if (data_is_float) {
format = SampleFormat::SAMPLE_FMT_DBL;
format = AudioParams::kFormatFloat64;
} else {
format = SampleFormat::SAMPLE_FMT_S64;
format = AudioParams::kFormatSigned64;
}
break;
default:
+10 -8
View File
@@ -20,6 +20,8 @@
#include "waveoutput.h"
#include "render/audioparams.h"
OLIVE_NAMESPACE_ENTER
const int16_t kWAVIntegerFormat = 1;
@@ -60,18 +62,18 @@ bool WaveOutput::open()
// Type of format
switch (params_.format()) {
case SampleFormat::SAMPLE_FMT_U8:
case SampleFormat::SAMPLE_FMT_S16:
case SampleFormat::SAMPLE_FMT_S32:
case SampleFormat::SAMPLE_FMT_S64:
case AudioParams::kFormatUnsigned8:
case AudioParams::kFormatSigned16:
case AudioParams::kFormatSigned32:
case AudioParams::kFormatSigned64:
write_int<int16_t>(&file_, kWAVIntegerFormat);
break;
case SampleFormat::SAMPLE_FMT_FLT:
case SampleFormat::SAMPLE_FMT_DBL:
case AudioParams::kFormatFloat32:
case AudioParams::kFormatFloat64:
write_int<int16_t>(&file_, kWAVFloatFormat);
break;
case SampleFormat::SAMPLE_FMT_INVALID:
case SampleFormat::SAMPLE_FMT_COUNT:
case AudioParams::kFormatInvalid:
case AudioParams::kFormatCount:
qWarning() << "Invalid sample format for WAVE audio";
file_.close();
return false;
-1
View File
@@ -24,7 +24,6 @@
#include <QByteArray>
#include <QFile>
#include "audio/sampleformat.h"
#include "render/audioparams.h"
OLIVE_NAMESPACE_ENTER