implemented a footage viewer
Essentially a minor derivation of a viewer type that can automatically view footage from the project (i.e. not in a sequence).
This commit is contained in:
@@ -25,6 +25,7 @@
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "common/define.h"
|
||||
#include "core.h"
|
||||
#include "dialog/footageproperties/footageproperties.h"
|
||||
|
||||
ProjectExplorer::ProjectExplorer(QWidget *parent) :
|
||||
@@ -38,8 +39,8 @@ ProjectExplorer::ProjectExplorer(QWidget *parent) :
|
||||
|
||||
// Set up navigation bar
|
||||
nav_bar_ = new ProjectExplorerNavigation(this);
|
||||
connect(nav_bar_, SIGNAL(SizeChanged(int)), this, SLOT(SizeChangedSlot(int)));
|
||||
connect(nav_bar_, SIGNAL(DirectoryUpClicked()), this, SLOT(DirUpSlot()));
|
||||
connect(nav_bar_, &ProjectExplorerNavigation::SizeChanged, this, &ProjectExplorer::SizeChangedSlot);
|
||||
connect(nav_bar_, &ProjectExplorerNavigation::DirectoryUpClicked, this, &ProjectExplorer::DirUpSlot);
|
||||
layout->addWidget(nav_bar_);
|
||||
|
||||
// Set up stacked widget
|
||||
@@ -111,8 +112,9 @@ void ProjectExplorer::AddView(QAbstractItemView *view)
|
||||
{
|
||||
view->setModel(&model_);
|
||||
view->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||||
connect(view, SIGNAL(DoubleClickedView(const QModelIndex&)), this, SLOT(DoubleClickViewSlot(const QModelIndex&)));
|
||||
connect(view, SIGNAL(clicked(const QModelIndex&)), this, SLOT(ItemClickedSlot(const QModelIndex&)));
|
||||
connect(view, &QAbstractItemView::clicked, this, &ProjectExplorer::ItemClickedSlot);
|
||||
connect(view, &QAbstractItemView::doubleClicked, this, &ProjectExplorer::ItemDoubleClickedSlot);
|
||||
connect(view, SIGNAL(DoubleClickedEmptyArea()), this, SLOT(ViewEmptyAreaDoubleClickedSlot()));
|
||||
stacked_widget_->addWidget(view);
|
||||
}
|
||||
|
||||
@@ -162,30 +164,34 @@ void ProjectExplorer::ItemClickedSlot(const QModelIndex &index)
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectExplorer::DoubleClickViewSlot(const QModelIndex &index)
|
||||
void ProjectExplorer::ViewEmptyAreaDoubleClickedSlot()
|
||||
{
|
||||
if (index.isValid()) {
|
||||
// Ensure no attempts to rename are made
|
||||
clicked_index_ = QModelIndex();
|
||||
rename_timer_.stop();
|
||||
|
||||
// Retrieve source item from index
|
||||
Item* i = static_cast<Item*>(index.internalPointer());
|
||||
emit DoubleClickedItem(nullptr);
|
||||
}
|
||||
|
||||
// If the item is a folder, browse to it
|
||||
if (i->CanHaveChildren()
|
||||
&& (view_type() == ProjectToolbar::ListView || view_type() == ProjectToolbar::IconView)) {
|
||||
void ProjectExplorer::ItemDoubleClickedSlot(const QModelIndex &index)
|
||||
{
|
||||
// Ensure no attempts to rename are made
|
||||
clicked_index_ = QModelIndex();
|
||||
rename_timer_.stop();
|
||||
|
||||
BrowseToFolder(index);
|
||||
// Retrieve source item from index
|
||||
Item* i = static_cast<Item*>(index.internalPointer());
|
||||
|
||||
}
|
||||
// If the item is a folder, browse to it
|
||||
if (i->CanHaveChildren()
|
||||
&& (view_type() == ProjectToolbar::ListView || view_type() == ProjectToolbar::IconView)) {
|
||||
|
||||
// Emit a signal
|
||||
emit DoubleClickedItem(i);
|
||||
|
||||
} else {
|
||||
|
||||
// Emit nullptr since no item was actually clicked on
|
||||
emit DoubleClickedItem(nullptr);
|
||||
BrowseToFolder(index);
|
||||
|
||||
}
|
||||
|
||||
// Emit a signal
|
||||
emit DoubleClickedItem(i);
|
||||
}
|
||||
|
||||
void ProjectExplorer::SizeChangedSlot(int s)
|
||||
@@ -218,9 +224,6 @@ void ProjectExplorer::RenameTimerSlot()
|
||||
rename_timer_.stop();
|
||||
}
|
||||
|
||||
// FIXME: This is down here because of the code in ShowContextMenu() which may be unnecessary allowing this to be removed
|
||||
#include "core.h"
|
||||
|
||||
void ProjectExplorer::ShowContextMenu()
|
||||
{
|
||||
QMenu menu;
|
||||
@@ -231,17 +234,17 @@ void ProjectExplorer::ShowContextMenu()
|
||||
if (selected_items.isEmpty()) {
|
||||
// FIXME: These are both duplicates of items from MainMenu, is there any way to re-use the code?
|
||||
QAction* import_action = menu.addAction(tr("&Import..."));
|
||||
connect(import_action, SIGNAL(triggered(bool)), Core::instance(), SLOT(DialogImportShow()));
|
||||
connect(import_action, &QAction::triggered, Core::instance(), &Core::DialogImportShow);
|
||||
|
||||
menu.addSeparator();
|
||||
|
||||
QAction* project_properties = menu.addAction(tr("&Project Properties..."));
|
||||
connect(project_properties, SIGNAL(triggered(bool)), Core::instance(), SLOT(DialogProjectPropertiesShow()));
|
||||
connect(project_properties, &QAction::triggered, Core::instance(), &Core::DialogProjectPropertiesShow);
|
||||
} else {
|
||||
QAction* properties_action = menu.addAction(tr("P&roperties"));
|
||||
|
||||
if (selected_items.first()->type() == Item::kFootage) {
|
||||
connect(properties_action, SIGNAL(triggered(bool)), this, SLOT(ShowFootagePropertiesDialog()));
|
||||
connect(properties_action, &QAction::triggered, this, &ProjectExplorer::ShowFootagePropertiesDialog);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -135,7 +135,9 @@ private:
|
||||
private slots:
|
||||
void ItemClickedSlot(const QModelIndex& index);
|
||||
|
||||
void DoubleClickViewSlot(const QModelIndex& index);
|
||||
void ViewEmptyAreaDoubleClickedSlot();
|
||||
|
||||
void ItemDoubleClickedSlot(const QModelIndex& index);
|
||||
|
||||
void SizeChangedSlot(int s);
|
||||
|
||||
|
||||
@@ -43,9 +43,8 @@ void ProjectExplorerListViewBase::mouseDoubleClickEvent(QMouseEvent *event)
|
||||
// Perform default double click functions
|
||||
QListView::mouseDoubleClickEvent(event);
|
||||
|
||||
// Get the index at whatever position was double clicked
|
||||
QModelIndex index = indexAt(event->pos());
|
||||
|
||||
// Emit the signal with this index
|
||||
emit DoubleClickedView(index);
|
||||
// QAbstractItemView already has a doubleClicked() signal, but we emit another here for double clicking empty space
|
||||
if (!indexAt(event->pos()).isValid()) {
|
||||
emit DoubleClickedEmptyArea();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ class ProjectExplorerListViewBase : public QListView
|
||||
public:
|
||||
ProjectExplorerListViewBase(QWidget* parent);
|
||||
|
||||
protected:
|
||||
protected:
|
||||
/**
|
||||
* @brief Double click event override
|
||||
*
|
||||
@@ -48,9 +48,9 @@ signals:
|
||||
/**
|
||||
* @brief Unconditional double click signal
|
||||
*
|
||||
* Emits a signal when the view is double clicked, regardless of whether the double clicked index was valid.
|
||||
* Emits a signal when the view is double clicked but not on any particular item
|
||||
*/
|
||||
void DoubleClickedView(const QModelIndex& index);
|
||||
void DoubleClickedEmptyArea();
|
||||
};
|
||||
|
||||
#endif // PROJECTEXPLORERLISTVIEWBASE_H
|
||||
|
||||
@@ -46,9 +46,8 @@ void ProjectExplorerTreeView::mouseDoubleClickEvent(QMouseEvent *event)
|
||||
// Perform default double click functions
|
||||
QTreeView::mouseDoubleClickEvent(event);
|
||||
|
||||
// Get the index at whatever position was double clicked
|
||||
QModelIndex index = indexAt(event->pos());
|
||||
|
||||
// Emit the signal with this index
|
||||
emit DoubleClickedView(index);
|
||||
// QAbstractItemView already has a doubleClicked() signal, but we emit another here for double clicking empty space
|
||||
if (!indexAt(event->pos()).isValid()) {
|
||||
emit DoubleClickedEmptyArea();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,9 +50,9 @@ signals:
|
||||
/**
|
||||
* @brief Unconditional double click signal
|
||||
*
|
||||
* Emits a signal when the view is double clicked, regardless of whether the double clicked index was valid.
|
||||
* Emits a signal when the view is double clicked but not on any particular item
|
||||
*/
|
||||
void DoubleClickedView(const QModelIndex& index);
|
||||
void DoubleClickedEmptyArea();
|
||||
};
|
||||
|
||||
#endif // PROJECTEXPLORERTREEVIEW_H
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
set(OLIVE_SOURCES
|
||||
${OLIVE_SOURCES}
|
||||
widget/viewer/footageviewer.h
|
||||
widget/viewer/footageviewer.cpp
|
||||
widget/viewer/viewer.h
|
||||
widget/viewer/viewer.cpp
|
||||
widget/viewer/viewerglwidget.h
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
#include "footageviewer.h"
|
||||
|
||||
#include "project/project.h"
|
||||
|
||||
FootageViewerWidget::FootageViewerWidget(QWidget *parent) :
|
||||
ViewerWidget(parent),
|
||||
footage_(nullptr)
|
||||
{
|
||||
video_node_ = new VideoInput();
|
||||
audio_node_ = new AudioInput();
|
||||
viewer_node_ = new ViewerOutput();
|
||||
|
||||
NodeParam::ConnectEdge(video_node_->output(), viewer_node_->texture_input());
|
||||
NodeParam::ConnectEdge(audio_node_->output(), viewer_node_->samples_input());
|
||||
NodeParam::ConnectEdge(video_node_->output(), viewer_node_->length_input());
|
||||
}
|
||||
|
||||
void FootageViewerWidget::SetFootage(Footage *footage)
|
||||
{
|
||||
if (footage_) {
|
||||
DisconnectViewerNode();
|
||||
}
|
||||
|
||||
footage_ = footage;
|
||||
|
||||
if (footage_) {
|
||||
VideoStreamPtr video_stream = nullptr;
|
||||
AudioStreamPtr audio_stream = nullptr;
|
||||
|
||||
foreach (StreamPtr s, footage->streams()) {
|
||||
if (!audio_stream && s->type() == Stream::kAudio) {
|
||||
audio_stream = std::static_pointer_cast<AudioStream>(s);
|
||||
}
|
||||
|
||||
if (!video_stream
|
||||
&& (s->type() == Stream::kVideo || s->type() == Stream::kImage)) {
|
||||
video_stream = std::static_pointer_cast<VideoStream>(s);
|
||||
}
|
||||
|
||||
if (audio_stream && video_stream) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (video_stream) {
|
||||
video_node_->SetFootage(video_stream);
|
||||
viewer_node_->set_video_params(VideoParams(video_stream->width(), video_stream->height(), video_stream->frame_rate().flipped()));
|
||||
}
|
||||
|
||||
if (audio_stream) {
|
||||
audio_node_->SetFootage(audio_stream);
|
||||
qDebug() << "Audio stream channel layout:" << audio_stream->channel_layout();
|
||||
viewer_node_->set_audio_params(AudioParams(audio_stream->sample_rate(), audio_stream->channel_layout()));
|
||||
}
|
||||
|
||||
ConnectViewerNode(viewer_node_, footage->project()->color_manager());
|
||||
video_renderer_->InvalidateCache(0, viewer_node_->Length());
|
||||
audio_renderer_->InvalidateCache(0, viewer_node_->Length());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
#ifndef FOOTAGEVIEWERWIDGET_H
|
||||
#define FOOTAGEVIEWERWIDGET_H
|
||||
|
||||
#include "node/input/media/audio/audio.h"
|
||||
#include "node/input/media/video/video.h"
|
||||
#include "node/output/viewer/viewer.h"
|
||||
#include "viewer.h"
|
||||
|
||||
class FootageViewerWidget : public ViewerWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
FootageViewerWidget(QWidget* parent = nullptr);
|
||||
|
||||
void SetFootage(Footage* footage);
|
||||
|
||||
private:
|
||||
Footage* footage_;
|
||||
|
||||
VideoInput* video_node_;
|
||||
|
||||
AudioInput* audio_node_;
|
||||
|
||||
ViewerOutput* viewer_node_;
|
||||
|
||||
};
|
||||
|
||||
#endif // FOOTAGEVIEWERWIDGET_H
|
||||
@@ -133,7 +133,7 @@ bool ViewerWidget::IsPlaying() const
|
||||
return playback_timer_.isActive();
|
||||
}
|
||||
|
||||
void ViewerWidget::ConnectViewerNode(ViewerOutput *node)
|
||||
void ViewerWidget::ConnectViewerNode(ViewerOutput *node, ColorManager* color_manager)
|
||||
{
|
||||
if (viewer_node_ != nullptr) {
|
||||
SetTimebase(0);
|
||||
@@ -153,6 +153,9 @@ void ViewerWidget::ConnectViewerNode(ViewerOutput *node)
|
||||
// Set texture to new texture (or null if no viewer node is available)
|
||||
UpdateTextureFromNode(GetTime());
|
||||
|
||||
video_renderer_->SetViewerNode(viewer_node_);
|
||||
audio_renderer_->SetViewerNode(viewer_node_);
|
||||
|
||||
if (viewer_node_ != nullptr) {
|
||||
SetTimebase(viewer_node_->video_params().time_base());
|
||||
|
||||
@@ -163,14 +166,17 @@ void ViewerWidget::ConnectViewerNode(ViewerOutput *node)
|
||||
SizeChangedSlot(viewer_node_->video_params().width(), viewer_node_->video_params().height());
|
||||
LengthChangedSlot(viewer_node_->Length());
|
||||
|
||||
gl_widget_->ConnectColorManager(static_cast<Sequence*>(viewer_node_->parent())->project()->color_manager());
|
||||
if (color_manager) {
|
||||
gl_widget_->ConnectColorManager(color_manager);
|
||||
} else if (viewer_node_->parent()) {
|
||||
gl_widget_->ConnectColorManager(static_cast<Sequence*>(viewer_node_->parent())->project()->color_manager());
|
||||
} else {
|
||||
qWarning() << "Failed to find a suitable color manager for the connected viewer node";
|
||||
}
|
||||
|
||||
video_renderer_->SetParameters(VideoRenderingParams(viewer_node_->video_params(), PixelFormat::PIX_FMT_RGBA16F, RenderMode::kOffline, 2));
|
||||
audio_renderer_->SetParameters(AudioRenderingParams(viewer_node_->audio_params(), SAMPLE_FMT_FLT));
|
||||
}
|
||||
|
||||
video_renderer_->SetViewerNode(viewer_node_);
|
||||
video_renderer_->SetParameters(VideoRenderingParams(viewer_node_->video_params(), PixelFormat::PIX_FMT_RGBA16F, RenderMode::kOffline, 2));
|
||||
|
||||
audio_renderer_->SetViewerNode(viewer_node_);
|
||||
audio_renderer_->SetParameters(AudioRenderingParams(viewer_node_->audio_params(), SAMPLE_FMT_FLT));
|
||||
}
|
||||
|
||||
void ViewerWidget::DisconnectViewerNode()
|
||||
|
||||
@@ -63,7 +63,7 @@ public:
|
||||
|
||||
bool IsPlaying() const;
|
||||
|
||||
void ConnectViewerNode(ViewerOutput* node);
|
||||
void ConnectViewerNode(ViewerOutput* node, ColorManager *color_manager = nullptr);
|
||||
|
||||
void DisconnectViewerNode();
|
||||
|
||||
@@ -136,6 +136,9 @@ signals:
|
||||
protected:
|
||||
virtual void resizeEvent(QResizeEvent *event) override;
|
||||
|
||||
OpenGLBackend* video_renderer_;
|
||||
AudioBackend* audio_renderer_;
|
||||
|
||||
private:
|
||||
void UpdateTimeInternal(int64_t i);
|
||||
|
||||
@@ -145,9 +148,6 @@ private:
|
||||
|
||||
void PushScrubbedAudio();
|
||||
|
||||
OpenGLBackend* video_renderer_;
|
||||
AudioBackend* audio_renderer_;
|
||||
|
||||
ViewerSizer* sizer_;
|
||||
|
||||
ViewerGLWidget* gl_widget_;
|
||||
|
||||
@@ -147,6 +147,12 @@ void ViewerGLWidget::paintGL()
|
||||
|
||||
void ViewerGLWidget::RefreshColorPipeline()
|
||||
{
|
||||
if (!color_manager_) {
|
||||
color_service_ = nullptr;
|
||||
pipeline_ = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
QStringList displays = color_manager_->ListAvailableDisplays();
|
||||
if (!displays.contains(ocio_display_)) {
|
||||
ocio_display_ = color_manager_->GetDefaultDisplay();
|
||||
|
||||
Reference in New Issue
Block a user