mocked up a prototype of decoding data into the node graph

This commit is contained in:
itsmattkc
2019-08-04 14:45:17 +10:00
parent fb8d5df24b
commit 298ae2f36c
15 changed files with 178 additions and 32 deletions
+4 -3
View File
@@ -21,7 +21,8 @@
#include "decoder.h"
Decoder::Decoder() :
open_(false)
open_(false),
stream_(nullptr)
{
}
@@ -35,12 +36,12 @@ Decoder::~Decoder()
{
}
Stream *Decoder::stream()
const Stream *Decoder::stream()
{
return stream_;
}
void Decoder::set_stream(Stream *fs)
void Decoder::set_stream(const Stream *fs)
{
Close();
+3 -3
View File
@@ -54,8 +54,8 @@ public:
virtual ~Decoder();
Stream* stream();
void set_stream(Stream* fs);
const Stream* stream();
void set_stream(const Stream *fs);
/**
* @brief Probe a footage file and dump metadata about it
@@ -148,7 +148,7 @@ protected:
bool open_;
private:
Stream* stream_;
const Stream* stream_;
};
using DecoderPtr = std::shared_ptr<Decoder>;
+48 -2
View File
@@ -122,12 +122,58 @@ bool FFmpegDecoder::Open()
FramePtr FFmpegDecoder::Retrieve(const rational &timecode, const rational &length)
{
// FIXME: Fill this out
if (!open_ && !Open()) {
return nullptr;
}
// avcodec_flush_buffers(codec_ctx_);
// av_seek_frame(fmt_ctx_, avstream_->index, 0, AVSEEK_FLAG_BACKWARD);
AVFrame* frame = av_frame_alloc();
AVPacket pkt;
av_init_packet(&pkt);
int ret = 69;
bool eof = false;
while ((ret = avcodec_receive_frame(codec_ctx_, frame)) == AVERROR(EAGAIN) && !eof) {
ret = av_read_frame(fmt_ctx_, &pkt);
if (ret == AVERROR_EOF) {
// Don't break so that receive gets called again, but don't try to read again
eof = true;
// Send a null packet to signal end of
avcodec_send_packet(codec_ctx_, nullptr);
} else if (ret < 0) {
// Handle other error
break;
} else {
// Successful read, send the packet
ret = avcodec_send_packet(codec_ctx_, &pkt);
av_packet_unref(&pkt);
if (ret < 0) {
break;
}
}
}
if (ret < 0) {
qWarning() << tr("Failed to retrieve frame from FFmpeg decoder: %1").arg(ret);
av_frame_free(&frame);
return nullptr;
}
FramePtr frame_container = std::make_shared<Frame>();
frame_container->SetAVFrame(frame, avstream_->time_base);
Q_UNUSED(timecode)
Q_UNUSED(length)
return nullptr;
// Close();
return frame_container;
}
void FFmpegDecoder::Close()
+2 -1
View File
@@ -20,6 +20,7 @@
#include "frame.h"
#include <QDebug>
#include <QtGlobal>
Frame::Frame() :
@@ -71,7 +72,7 @@ void Frame::SetAVFrame(AVFrame *f, AVRational timebase)
{
FreeChild();
f = frame_;
frame_ = f;
timestamp_ = rational(timebase.num*f->pts, timebase.den);
}
+14
View File
@@ -23,6 +23,7 @@
#include "output.h"
NodeInput::NodeInput() :
keyframing_(false),
can_accept_multiple_inputs_(false)
{
// Have at least one keyframe/value active at any time
@@ -87,6 +88,19 @@ QVariant NodeInput::get_value(const rational &time)
}
}
void NodeInput::set_value(const rational &time, const QVariant &value)
{
if (keyframing()) {
// FIXME: Keyframing code
Q_UNUSED(time)
} else {
keyframes_.first().set_value(value);
// FIXME: Put correct values here
emit ValueChanged(0, 0);
}
}
bool NodeInput::keyframing()
{
return keyframing_;
+11
View File
@@ -29,6 +29,7 @@
*/
class NodeInput : public NodeParam
{
Q_OBJECT
public:
NodeInput();
@@ -81,6 +82,13 @@ public:
*/
QVariant get_value(const rational &time);
/**
* @brief Set the value at a given time
*
* This function will only work if there are no outputs connected.
*/
void set_value(const rational& time, const QVariant& value);
/**
* @brief Return whether keyframing is enabled on this input or not
*/
@@ -96,6 +104,9 @@ public:
*/
const QList<DataType>& inputs();
signals:
void ValueChanged(const rational& start, const rational& end);
private:
/**
* @brief Internal list of accepted data types
+46 -7
View File
@@ -21,11 +21,16 @@
#include "media.h"
#include <QDebug>
#include <QOpenGLPixelTransferOptions>
#include "project/item/footage/footage.h"
// FIXME: Test code only
#include "decoder/ffmpeg/ffmpegdecoder.h"
// End test code
MediaInput::MediaInput() :
texture_(nullptr)
texture_(0)
{
footage_input_ = new NodeInput();
footage_input_->add_data_input(NodeInput::kFootage);
@@ -34,6 +39,10 @@ MediaInput::MediaInput() :
texture_output_ = new NodeOutput();
texture_output_->set_data_type(NodeOutput::kTexture);
AddParameter(texture_output_);
// FIXME: Test code only
decoder_ = new FFmpegDecoder(); // FIXME: Doesn't ever get free'd
// End test code
}
QString MediaInput::Name()
@@ -81,13 +90,43 @@ void MediaInput::Process(const rational &time)
// Grab frame from decoder
// FIXME: Test code
if (texture_ == nullptr) {
QImage img("/home/matt/Desktop/oof.png");
texture_ = new QOpenGLTexture(img);
if (decoder_->stream() == nullptr) {
decoder_->set_stream(footage->stream(0));
}
texture_output_->set_value(texture_->textureId());
FramePtr frame = decoder_->Retrieve(time);
if (frame == nullptr) {
texture_output_->set_value(0);
return;
}
// FIXME: Test code
if (texture_ == 0) {
glGenTextures(1, &texture_);
glBindTexture(GL_TEXTURE_2D, texture_);
// Set texture filtering to bilinear
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Set texture wrapping to clamp
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D,
0,
GL_RGBA8,
frame->width(),
frame->height(),
0,
GL_RGBA,
GL_UNSIGNED_BYTE,
frame->data()[0]);
}
texture_output_->set_value(texture_);
// End test code
}
+4 -1
View File
@@ -23,6 +23,7 @@
#include <QOpenGLTexture>
#include "decoder/decoder.h"
#include "node/node.h"
/**
@@ -52,7 +53,9 @@ private:
NodeOutput* texture_output_;
QOpenGLTexture* texture_;
GLuint texture_;
Decoder* decoder_;
};
#endif // IMAGE_H
+4 -4
View File
@@ -41,7 +41,7 @@ void Stream::set_type(const Stream::Type &type)
type_ = type;
}
Footage *Stream::footage()
Footage *Stream::footage() const
{
return footage_;
}
@@ -51,7 +51,7 @@ void Stream::set_footage(Footage *f)
footage_ = f;
}
const rational &Stream::timebase()
const rational &Stream::timebase() const
{
return timebase_;
}
@@ -61,7 +61,7 @@ void Stream::set_timebase(const rational &timebase)
timebase_ = timebase;
}
const int &Stream::index()
const int &Stream::index() const
{
return index_;
}
@@ -71,7 +71,7 @@ void Stream::set_index(const int &index)
index_ = index;
}
const int64_t &Stream::duration()
const int64_t &Stream::duration() const
{
return duration_;
}
+4 -4
View File
@@ -59,16 +59,16 @@ public:
const Type& type();
void set_type(const Type& type);
Footage* footage();
Footage* footage() const;
void set_footage(Footage* f);
const rational& timebase();
const rational& timebase() const;
void set_timebase(const rational& timebase);
const int& index();
const int& index() const;
void set_index(const int& index);
const int64_t& duration();
const int64_t& duration() const;
void set_duration(const int64_t& duration);
private:
+19 -3
View File
@@ -1,11 +1,13 @@
#include "footagecombobox.h"
#include <QAction>
#include <QDebug>
#include <QMenu>
FootageComboBox::FootageComboBox(QWidget *parent) :
QComboBox(parent),
root_(nullptr)
root_(nullptr),
footage_(nullptr)
{
}
@@ -25,11 +27,14 @@ void FootageComboBox::showPopup()
QAction* selected = menu.exec(parentWidget()->mapToGlobal(pos()));
if (selected != nullptr) {
// Use combobox functions to show the footage name
clear();
addItem(selected->text());
emit FootageChanged(reinterpret_cast<Footage*>(selected->data().value<quintptr>()));
footage_ = reinterpret_cast<Footage*>(selected->data().value<quintptr>());
emit FootageChanged(footage_);
}
}
@@ -40,11 +45,22 @@ void FootageComboBox::SetRoot(const Folder *p)
clear();
}
Footage *FootageComboBox::SelectedFootage()
{
return footage_;
}
void FootageComboBox::SetFootage(Footage *f)
{
// Remove existing single item used to show the footage name
clear();
addItem(f->name());
footage_ = f;
if (footage_ != nullptr) {
// Use combobox functions to show the footage name
addItem(footage_->name());
}
}
void FootageComboBox::TraverseFolder(const Folder *f, QMenu *m)
@@ -17,6 +17,8 @@ public:
void SetRoot(const Folder *p);
Footage* SelectedFootage();
public slots:
void SetFootage(Footage* f);
@@ -27,6 +29,8 @@ private:
void TraverseFolder(const Folder *f, QMenu* m);
const Folder* root_;
Footage* footage_;
};
#endif // FOOTAGECOMBOBOX_H
@@ -156,6 +156,7 @@ void NodeParamViewItemTitleBar::paintEvent(QPaintEvent *event)
QPainter p(this);
// Draw bottom border using text color
int bottom = height() - 1;
p.setPen(palette().text().color());
p.drawLine(0, height() - 1, width(), height() - 1);
p.drawLine(0, bottom, width(), bottom);
}
@@ -4,6 +4,7 @@
#include <QLineEdit>
#include <QCheckBox>
#include "node/node.h"
#include "widget/footagecombobox/footagecombobox.h"
// FIXME: Test code only
@@ -79,7 +80,8 @@ void NodeParamViewWidgetBridge::CreateWidgets()
// Pretty hacky way of getting the root folder for this node's sequence
ProjectPanel* pp = olive::panel_focus_manager->MostRecentlyFocused<ProjectPanel>();
footage_combobox->SetRoot(pp->project()->root());
footage_combobox->SetFootage(Node::ValueToPtr<Footage>(input_->get_value(Now())));
connect(footage_combobox, SIGNAL(FootageChanged(Footage*)), this, SLOT(WidgetCallback()));
// End test code
widgets_.append(footage_combobox);
@@ -89,6 +91,12 @@ void NodeParamViewWidgetBridge::CreateWidgets()
}
}
rational NodeParamViewWidgetBridge::Now()
{
// FIXME: Actually implement this
return 0;
}
void NodeParamViewWidgetBridge::WidgetCallback()
{
switch (input_->inputs().first()) {
@@ -132,8 +140,8 @@ void NodeParamViewWidgetBridge::WidgetCallback()
case NodeParam::kFootage:
{
// Widget is a FootageComboBox
//FootageComboBox* footage_combobox = static_cast<FootageComboBox*>(sender());
FootageComboBox* footage_combobox = static_cast<FootageComboBox*>(sender());
input_->set_value(Now(), Node::PtrToValue(footage_combobox->SelectedFootage()));
break;
}
}
@@ -20,6 +20,8 @@ private:
void CreateWidgets();
rational Now();
private slots:
void WidgetCallback();
};