more or less completed OIIO decoder
This commit is contained in:
@@ -29,4 +29,6 @@
|
||||
|
||||
const olive::TimecodeDisplay kTimecodeDisplay = olive::kTimecodeFrames;
|
||||
|
||||
const rational kDefaultImageLength = 2;
|
||||
|
||||
#endif // CONFIG_H
|
||||
|
||||
@@ -62,6 +62,9 @@ void Decoder::set_stream(StreamPtr fs)
|
||||
QVector<DecoderPtr> ReceiveListOfAllDecoders() {
|
||||
QVector<DecoderPtr> decoders;
|
||||
|
||||
// The order in which these decoders are added is their priority when probing. Hence FFmpeg should usually be last,
|
||||
// since it supports so many formats and we presumably want to override those formats with a more specific decoder.
|
||||
|
||||
decoders.append(std::make_shared<OIIODecoder>());
|
||||
decoders.append(std::make_shared<FFmpegDecoder>());
|
||||
|
||||
|
||||
@@ -142,7 +142,7 @@ bool FFmpegDecoder::Open()
|
||||
output_fmt_ = olive::PIX_FMT_RGBA8;
|
||||
break;
|
||||
case AV_PIX_FMT_RGBA64:
|
||||
output_fmt_ = olive::PIX_FMT_RGBA16;
|
||||
output_fmt_ = olive::PIX_FMT_RGBA16U;
|
||||
break;
|
||||
default:
|
||||
// We should never get here, but if we do there's nothing we can do with this format
|
||||
|
||||
@@ -22,7 +22,11 @@
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
OIIODecoder::OIIODecoder()
|
||||
#include "common/define.h"
|
||||
|
||||
OIIODecoder::OIIODecoder() :
|
||||
image_(nullptr),
|
||||
frame_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -67,25 +71,24 @@ bool OIIODecoder::Open()
|
||||
width_ = spec.width;
|
||||
height_ = spec.height;
|
||||
|
||||
// Weirdly, compiler complains this is a boolean value without casting to int
|
||||
switch (static_cast<int>(spec.format)) {
|
||||
case OIIO::TypeDesc::UINT8:
|
||||
// Weirdly, switch statement doesn't work correctly here
|
||||
if (spec.format == OIIO::TypeDesc::UINT8) {
|
||||
pix_fmt_ = olive::PIX_FMT_RGBA8;
|
||||
break;
|
||||
case OIIO::TypeDesc::UINT16:
|
||||
pix_fmt_ = olive::PIX_FMT_RGBA16;
|
||||
break;
|
||||
case OIIO::TypeDesc::HALF:
|
||||
} else if (spec.format == OIIO::TypeDesc::UINT16) {
|
||||
pix_fmt_ = olive::PIX_FMT_RGBA16U;
|
||||
} else if (spec.format == OIIO::TypeDesc::HALF) {
|
||||
pix_fmt_ = olive::PIX_FMT_RGBA16F;
|
||||
break;
|
||||
case OIIO::TypeDesc::FLOAT:
|
||||
} else if (spec.format == OIIO::TypeDesc::FLOAT) {
|
||||
pix_fmt_ = olive::PIX_FMT_RGBA32F;
|
||||
break;
|
||||
default:
|
||||
} else {
|
||||
qWarning() << "Failed to convert OIIO::ImageDesc to native pixel format";
|
||||
return false;
|
||||
}
|
||||
|
||||
// FIXME: Many OIIO pixel formats are not handled here
|
||||
|
||||
is_rgba_ = (spec.nchannels == kRGBAChannels);
|
||||
|
||||
pix_fmt_info_ = PixelService::GetPixelFormatInfo(static_cast<olive::PixelFormat>(pix_fmt_));
|
||||
|
||||
return true;
|
||||
@@ -93,27 +96,41 @@ bool OIIODecoder::Open()
|
||||
|
||||
FramePtr OIIODecoder::Retrieve(const rational &timecode, const rational &length)
|
||||
{
|
||||
if (!open_ && !Open()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Q_UNUSED(timecode)
|
||||
Q_UNUSED(length)
|
||||
|
||||
FramePtr f = Frame::Create();
|
||||
if (frame_ == nullptr) {
|
||||
frame_ = Frame::Create();
|
||||
|
||||
f->set_width(width_);
|
||||
f->set_height(height_);
|
||||
f->set_format(pix_fmt_);
|
||||
f->allocate();
|
||||
frame_->set_width(width_);
|
||||
frame_->set_height(height_);
|
||||
frame_->set_format(pix_fmt_);
|
||||
frame_->allocate();
|
||||
|
||||
// Use the native format to determine what format OIIO should return
|
||||
// FIXME: Behavior of RGB images as opposed to RGBA?
|
||||
image_->read_image(pix_fmt_info_.oiio_desc, f->data());
|
||||
// Use the native format to determine what format OIIO should return
|
||||
// FIXME: Behavior of RGB images as opposed to RGBA?
|
||||
image_->read_image(pix_fmt_info_.oiio_desc, frame_->data());
|
||||
|
||||
return f;
|
||||
if (!is_rgba_) {
|
||||
PixelService::ConvertRGBtoRGBA(frame_);
|
||||
}
|
||||
}
|
||||
|
||||
return frame_;
|
||||
}
|
||||
|
||||
void OIIODecoder::Close()
|
||||
{
|
||||
image_->close();
|
||||
image_ = nullptr;
|
||||
if (image_ != nullptr) {
|
||||
image_->close();
|
||||
image_ = nullptr;
|
||||
}
|
||||
|
||||
frame_ = nullptr;
|
||||
}
|
||||
|
||||
int64_t OIIODecoder::GetTimestampFromTime(const rational &time)
|
||||
|
||||
@@ -54,6 +54,10 @@ private:
|
||||
|
||||
PixelFormatInfo pix_fmt_info_;
|
||||
|
||||
bool is_rgba_;
|
||||
|
||||
FramePtr frame_;
|
||||
|
||||
};
|
||||
|
||||
#endif // OIIODECODER_H
|
||||
|
||||
@@ -146,23 +146,22 @@ void Footage::UpdateIcon()
|
||||
|
||||
// Prioritize the video icon
|
||||
set_icon(olive::icon::Video);
|
||||
|
||||
// FIXME: When image sources can be reliably picked up, use image icon instead
|
||||
// Perhaps all image sources can be left to OpenImageIO meaning only video sources need to be here
|
||||
break;
|
||||
|
||||
} else if (HasStreamsOfType(Stream::kAudio)) {
|
||||
|
||||
// Otherwise assume it's audio only
|
||||
set_icon(olive::icon::Audio);
|
||||
break;
|
||||
|
||||
} else {
|
||||
} else if (HasStreamsOfType(Stream::kImage)) {
|
||||
|
||||
// FIXME Icon/indicator for a media file with no video or audio streams?
|
||||
// The footage should probably be deemed kInvalid in this state
|
||||
// Otherwise assume it's an image
|
||||
set_icon(olive::icon::Image);
|
||||
break;
|
||||
|
||||
}
|
||||
break;
|
||||
case kInvalid:
|
||||
[[clang::fallthrough]]; case kInvalid:
|
||||
set_icon(olive::icon::Error);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ void ColorService::AssociateAlphaPixFmtFilter(ColorService::AlphaAction action,
|
||||
qWarning() << "Alpha association functions received an invalid pixel format";
|
||||
break;
|
||||
case olive::PIX_FMT_RGBA8:
|
||||
case olive::PIX_FMT_RGBA16:
|
||||
case olive::PIX_FMT_RGBA16U:
|
||||
qWarning() << "Alpha association functions only works on float-based pixel formats at this time";
|
||||
break;
|
||||
case olive::PIX_FMT_RGBA16F:
|
||||
|
||||
@@ -28,10 +28,12 @@ namespace olive {
|
||||
*/
|
||||
enum PixelFormat {
|
||||
PIX_FMT_INVALID = -1,
|
||||
|
||||
PIX_FMT_RGBA8,
|
||||
PIX_FMT_RGBA16,
|
||||
PIX_FMT_RGBA16U,
|
||||
PIX_FMT_RGBA16F,
|
||||
PIX_FMT_RGBA32F,
|
||||
|
||||
PIX_FMT_COUNT
|
||||
};
|
||||
|
||||
|
||||
+56
-10
@@ -41,7 +41,7 @@ PixelFormatInfo PixelService::GetPixelFormatInfo(const olive::PixelFormat &forma
|
||||
info.pixel_type = GL_UNSIGNED_BYTE;
|
||||
info.oiio_desc = OIIO::TypeDesc::UINT8;
|
||||
break;
|
||||
case olive::PIX_FMT_RGBA16:
|
||||
case olive::PIX_FMT_RGBA16U:
|
||||
info.name = tr("16-bit Integer");
|
||||
info.internal_format = GL_RGBA16;
|
||||
info.pixel_type = GL_UNSIGNED_SHORT;
|
||||
@@ -59,7 +59,8 @@ PixelFormatInfo PixelService::GetPixelFormatInfo(const olive::PixelFormat &forma
|
||||
info.pixel_type = GL_FLOAT;
|
||||
info.oiio_desc = OIIO::TypeDesc::FLOAT;
|
||||
break;
|
||||
default:
|
||||
case olive::PIX_FMT_INVALID:
|
||||
case olive::PIX_FMT_COUNT:
|
||||
qFatal("Invalid pixel format requested");
|
||||
}
|
||||
|
||||
@@ -84,14 +85,17 @@ int PixelService::BytesPerChannel(const olive::PixelFormat &format)
|
||||
switch (format) {
|
||||
case olive::PIX_FMT_RGBA8:
|
||||
return 1;
|
||||
case olive::PIX_FMT_RGBA16:
|
||||
case olive::PIX_FMT_RGBA16U:
|
||||
case olive::PIX_FMT_RGBA16F:
|
||||
return 2;
|
||||
case olive::PIX_FMT_RGBA32F:
|
||||
return 4;
|
||||
default:
|
||||
qFatal("Invalid pixel format requested");
|
||||
case olive::PIX_FMT_INVALID:
|
||||
case olive::PIX_FMT_COUNT:
|
||||
break;
|
||||
}
|
||||
|
||||
qFatal("Invalid pixel format requested");
|
||||
}
|
||||
|
||||
FramePtr PixelService::ConvertPixelFormat(FramePtr frame, const olive::PixelFormat &dest_format)
|
||||
@@ -121,7 +125,7 @@ FramePtr PixelService::ConvertPixelFormat(FramePtr frame, const olive::PixelForm
|
||||
uint8_t* source = frame->data();
|
||||
|
||||
switch (dest_format) {
|
||||
case olive::PIX_FMT_RGBA16: // 8-bit Integer -> 16-bit Integer
|
||||
case olive::PIX_FMT_RGBA16U: // 8-bit Integer -> 16-bit Integer
|
||||
{
|
||||
uint16_t* destination = reinterpret_cast<uint16_t*>(converted->data());
|
||||
for (int i=0;i<pix_count;i++) {
|
||||
@@ -152,7 +156,7 @@ FramePtr PixelService::ConvertPixelFormat(FramePtr frame, const olive::PixelForm
|
||||
}
|
||||
break;
|
||||
}
|
||||
case olive::PIX_FMT_RGBA16:
|
||||
case olive::PIX_FMT_RGBA16U:
|
||||
{
|
||||
uint16_t* source = reinterpret_cast<uint16_t*>(frame->data());
|
||||
|
||||
@@ -182,7 +186,7 @@ FramePtr PixelService::ConvertPixelFormat(FramePtr frame, const olive::PixelForm
|
||||
break;
|
||||
}
|
||||
case olive::PIX_FMT_INVALID:
|
||||
case olive::PIX_FMT_RGBA16:
|
||||
case olive::PIX_FMT_RGBA16U:
|
||||
case olive::PIX_FMT_COUNT:
|
||||
valid = false;
|
||||
}
|
||||
@@ -201,7 +205,7 @@ FramePtr PixelService::ConvertPixelFormat(FramePtr frame, const olive::PixelForm
|
||||
}
|
||||
break;
|
||||
}
|
||||
case olive::PIX_FMT_RGBA16: // 16-bit Float -> 16-bit Integer
|
||||
case olive::PIX_FMT_RGBA16U: // 16-bit Float -> 16-bit Integer
|
||||
{
|
||||
uint16_t* destination = reinterpret_cast<uint16_t*>(converted->data());
|
||||
for (int i=0;i<pix_count;i++) {
|
||||
@@ -237,7 +241,7 @@ FramePtr PixelService::ConvertPixelFormat(FramePtr frame, const olive::PixelForm
|
||||
}
|
||||
break;
|
||||
}
|
||||
case olive::PIX_FMT_RGBA16: // 32-bit Float -> 16-bit Integer
|
||||
case olive::PIX_FMT_RGBA16U: // 32-bit Float -> 16-bit Integer
|
||||
{
|
||||
uint16_t* destination = reinterpret_cast<uint16_t*>(converted->data());
|
||||
for (int i=0;i<pix_count;i++) {
|
||||
@@ -272,3 +276,45 @@ FramePtr PixelService::ConvertPixelFormat(FramePtr frame, const olive::PixelForm
|
||||
qWarning() << tr("Invalid parameters called for pixel format conversion");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void PixelService::ConvertRGBtoRGBA(FramePtr frame)
|
||||
{
|
||||
olive::PixelFormat dest_format = static_cast<olive::PixelFormat>(frame->format());
|
||||
|
||||
int rgb_pixel_size = BytesPerChannel(dest_format) * kRGBChannels;
|
||||
int rgb_frame_size = frame->width() * frame->height() * rgb_pixel_size;
|
||||
int rgb_iter = rgb_frame_size - rgb_pixel_size;
|
||||
|
||||
int rgba_pixel_size = BytesPerChannel(dest_format) * kRGBAChannels;
|
||||
int rgba_frame_size = frame->width() * frame->height() * rgba_pixel_size;
|
||||
int rgba_iter = rgba_frame_size - rgba_pixel_size;
|
||||
|
||||
// Work backwards to save time
|
||||
while (rgb_iter >= 0) {
|
||||
memcpy(&frame->data()[rgba_iter], &frame->data()[rgb_iter], static_cast<size_t>(rgb_pixel_size));
|
||||
|
||||
uint8_t* alpha_ptr = &frame->data()[rgba_iter + rgb_pixel_size];
|
||||
|
||||
// Write a full alpha value according to the format
|
||||
switch (dest_format) {
|
||||
case olive::PIX_FMT_RGBA8:
|
||||
*alpha_ptr = UINT8_MAX;
|
||||
break;
|
||||
case olive::PIX_FMT_RGBA16U:
|
||||
*reinterpret_cast<uint16_t*>(alpha_ptr) = UINT16_MAX;
|
||||
break;
|
||||
case olive::PIX_FMT_RGBA16F:
|
||||
*reinterpret_cast<qfloat16*>(alpha_ptr) = 1.0f;
|
||||
break;
|
||||
case olive::PIX_FMT_RGBA32F:
|
||||
*reinterpret_cast<float*>(alpha_ptr) = 1.0f;
|
||||
break;
|
||||
case olive::PIX_FMT_INVALID:
|
||||
case olive::PIX_FMT_COUNT:
|
||||
qFatal("Invalid pixel format requested");
|
||||
}
|
||||
|
||||
rgb_iter -= rgb_pixel_size;
|
||||
rgba_iter -= rgba_pixel_size;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,6 +97,11 @@ public:
|
||||
*/
|
||||
static FramePtr ConvertPixelFormat(FramePtr frame, const olive::PixelFormat &dest_format);
|
||||
|
||||
/**
|
||||
* @brief Convert an RGB image to an RGBA image
|
||||
*/
|
||||
static void ConvertRGBtoRGBA(FramePtr frame);
|
||||
|
||||
};
|
||||
|
||||
#endif // PIXELSERVICE_H
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#include <QMimeData>
|
||||
|
||||
#include "config/config.h"
|
||||
#include "common/qtversionabstraction.h"
|
||||
#include "node/input/media/media.h"
|
||||
|
||||
@@ -72,8 +73,16 @@ void TimelineView::ImportTool::DragEnter(QDragEnterEvent *event)
|
||||
|
||||
TimelineViewGhostItem* ghost = new TimelineViewGhostItem();
|
||||
|
||||
rational footage_duration(stream->timebase().numerator() * stream->duration(),
|
||||
stream->timebase().denominator());
|
||||
rational footage_duration;
|
||||
|
||||
if (stream->type() == Stream::kImage) {
|
||||
// Stream is essentially length-less - use config's default image length
|
||||
footage_duration = kDefaultImageLength;
|
||||
} else {
|
||||
// Use duration from file
|
||||
footage_duration = rational(stream->timebase().numerator() * stream->duration(),
|
||||
stream->timebase().denominator());
|
||||
}
|
||||
|
||||
ghost->SetIn(ghost_start);
|
||||
ghost->SetOut(ghost_start + footage_duration);
|
||||
|
||||
Reference in New Issue
Block a user