more or less completed OIIO decoder

This commit is contained in:
itsmattkc
2019-09-05 01:15:50 +10:00
parent 695adea562
commit faa7f798ff
11 changed files with 134 additions and 47 deletions
+2
View File
@@ -29,4 +29,6 @@
const olive::TimecodeDisplay kTimecodeDisplay = olive::kTimecodeFrames;
const rational kDefaultImageLength = 2;
#endif // CONFIG_H
+3
View File
@@ -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>());
+1 -1
View File
@@ -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
+41 -24
View File
@@ -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)
+4
View File
@@ -54,6 +54,10 @@ private:
PixelFormatInfo pix_fmt_info_;
bool is_rgba_;
FramePtr frame_;
};
#endif // OIIODECODER_H
+7 -8
View File
@@ -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;
}
+1 -1
View File
@@ -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:
+3 -1
View File
@@ -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
View File
@@ -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;
}
}
+5
View File
@@ -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
+11 -2
View File
@@ -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);