mocked up a prototype of decoding data into the node graph
This commit is contained in:
@@ -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();
|
||||
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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_;
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user