folder support added

This commit is contained in:
itsmattkc
2018-07-11 00:59:53 +01:00
parent 31f4a5d0be
commit 6389eebbbe
15 changed files with 337 additions and 235 deletions
+1 -1
View File
@@ -4,8 +4,8 @@
#include <QLabel>
#include <QtMath>
#include <QDebug>
#include <stdint.h>
#include "playback/audio.h"
#include "ui/labelslider.h"
#include "ui/collapsiblewidget.h"
+1 -3
View File
@@ -6,9 +6,7 @@ extern "C" {
#include <libavformat/avformat.h>
}
Media::Media() {
}
Media::Media() {}
Media::~Media() {
for (int i=0;i<video_tracks.size();i++) {
+1 -8
View File
@@ -8,11 +8,6 @@
#include <QMutex>
#include <QPixmap>
#define MEDIA_TYPE_FOOTAGE 0
#define MEDIA_TYPE_SEQUENCE 1
#define MEDIA_TYPE_FOLDER 2
#define MEDIA_TYPE_SOLID 3
struct Sequence;
struct MediaStream {
@@ -34,12 +29,10 @@ struct Media
~Media();
QString url;
QString name;
char type;
QString name;
int64_t length;
QVector<MediaStream*> video_tracks;
QVector<MediaStream*> audio_tracks;
Sequence* sequence;
int save_id;
long get_length_in_frames(float frame_rate);
MediaStream* get_stream_from_file_index(int index);
+143 -151
View File
@@ -26,170 +26,162 @@ PreviewGenerator::PreviewGenerator(QObject* parent) : QThread(parent) {
#define WAVEFORM_RESOLUTION 64
void PreviewGenerator::run() {
if (media == NULL) {
qDebug() << "[ERROR] No media was set for preview generation";
} else {
if (media->type == MEDIA_TYPE_SEQUENCE) {
qDebug() << "[ERROR] Cannot run preview generation on a sequence";
} else {
SwsContext* sws_ctx;
SwrContext* swr_ctx;
AVFrame* temp_frame = av_frame_alloc();
AVCodecContext** codec_ctx = new AVCodecContext* [fmt_ctx->nb_streams];
for (unsigned int i=0;i<fmt_ctx->nb_streams;i++) {
codec_ctx[i] = NULL;
if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO || fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
AVCodec* codec = avcodec_find_decoder(fmt_ctx->streams[i]->codecpar->codec_id);
codec_ctx[i] = avcodec_alloc_context3(codec);
avcodec_parameters_to_context(codec_ctx[i], fmt_ctx->streams[i]->codecpar);
avcodec_open2(codec_ctx[i], codec, NULL);
Q_ASSERT(media != NULL);
if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && codec_ctx[i]->channel_layout == 0) {
codec_ctx[i]->channel_layout = guess_layout_from_channels(fmt_ctx->streams[i]->codecpar->channels);
}
SwsContext* sws_ctx;
SwrContext* swr_ctx;
AVFrame* temp_frame = av_frame_alloc();
AVCodecContext** codec_ctx = new AVCodecContext* [fmt_ctx->nb_streams];
for (unsigned int i=0;i<fmt_ctx->nb_streams;i++) {
codec_ctx[i] = NULL;
if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO || fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
AVCodec* codec = avcodec_find_decoder(fmt_ctx->streams[i]->codecpar->codec_id);
codec_ctx[i] = avcodec_alloc_context3(codec);
avcodec_parameters_to_context(codec_ctx[i], fmt_ctx->streams[i]->codecpar);
avcodec_open2(codec_ctx[i], codec, NULL);
if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && codec_ctx[i]->channel_layout == 0) {
codec_ctx[i]->channel_layout = guess_layout_from_channels(fmt_ctx->streams[i]->codecpar->channels);
}
}
}
AVPacket packet;
bool done = true;
bool end_of_file = false;
// get the ball rolling
av_read_frame(fmt_ctx, &packet);
avcodec_send_packet(codec_ctx[packet.stream_index], &packet);
while (!end_of_file) {
while (codec_ctx[packet.stream_index] == NULL || avcodec_receive_frame(codec_ctx[packet.stream_index], temp_frame) == AVERROR(EAGAIN)) {
av_packet_unref(&packet);
int read_ret = av_read_frame(fmt_ctx, &packet);
if (read_ret < 0) {
end_of_file = true;
if (read_ret != AVERROR_EOF) qDebug() << "[ERROR] Failed to read packet for preview generation";
break;
} else if (codec_ctx[packet.stream_index] != NULL) {
int send_ret = avcodec_send_packet(codec_ctx[packet.stream_index], &packet);
if (send_ret < 0) {
qDebug() << "[ERROR] Failed to send packet for preview generation - aborting";
end_of_file = true;
break;
}
}
AVPacket packet;
bool done = true;
}
if (!end_of_file) {
MediaStream* s = media->get_stream_from_file_index(packet.stream_index);
if (s != NULL && !s->preview_done) {
if (fmt_ctx->streams[packet.stream_index]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
int dstH = 120;
int dstW = dstH * ((float)temp_frame->width/(float)temp_frame->height);
uint8_t* data = new uint8_t[dstW*dstH*3];
bool end_of_file = false;
sws_ctx = sws_getContext(
temp_frame->width,
temp_frame->height,
static_cast<AVPixelFormat>(temp_frame->format),
dstW,
dstH,
static_cast<AVPixelFormat>(AV_PIX_FMT_RGB24),
SWS_FAST_BILINEAR,
NULL,
NULL,
NULL
);
// get the ball rolling
av_read_frame(fmt_ctx, &packet);
avcodec_send_packet(codec_ctx[packet.stream_index], &packet);
int linesize[AV_NUM_DATA_POINTERS];
linesize[0] = dstW*3;
sws_scale(sws_ctx, temp_frame->data, temp_frame->linesize, 0, temp_frame->height, &data, linesize);
while (!end_of_file) {
while (codec_ctx[packet.stream_index] == NULL || avcodec_receive_frame(codec_ctx[packet.stream_index], temp_frame) == AVERROR(EAGAIN)) {
av_packet_unref(&packet);
int read_ret = av_read_frame(fmt_ctx, &packet);
if (read_ret < 0) {
end_of_file = true;
if (read_ret != AVERROR_EOF) qDebug() << "[ERROR] Failed to read packet for preview generation";
break;
} else if (codec_ctx[packet.stream_index] != NULL) {
int send_ret = avcodec_send_packet(codec_ctx[packet.stream_index], &packet);
if (send_ret < 0) {
qDebug() << "[ERROR] Failed to send packet for preview generation - aborting";
end_of_file = true;
s->video_preview = QImage(data, dstW, dstH, linesize[0], QImage::Format_RGB888);
// delete [] data;
s->preview_done = true;
sws_freeContext(sws_ctx);
avcodec_close(codec_ctx[packet.stream_index]);
codec_ctx[packet.stream_index] = NULL;
} else if (fmt_ctx->streams[packet.stream_index]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
int interval = qFloor((temp_frame->sample_rate/WAVEFORM_RESOLUTION)/4)*4;
AVFrame* swr_frame = av_frame_alloc();
swr_frame->channel_layout = temp_frame->channel_layout;
swr_frame->sample_rate = temp_frame->sample_rate;
swr_frame->format = AV_SAMPLE_FMT_S16;
swr_ctx = swr_alloc_set_opts(
NULL,
temp_frame->channel_layout,
static_cast<AVSampleFormat>(swr_frame->format),
temp_frame->sample_rate,
temp_frame->channel_layout,
static_cast<AVSampleFormat>(temp_frame->format),
temp_frame->sample_rate,
0,
NULL
);
swr_init(swr_ctx);
swr_convert_frame(swr_ctx, swr_frame, temp_frame);
int channel_skip = swr_frame->channels * 2;
for (int i=0;i<swr_frame->nb_samples;i+=interval) {
for (int j=0;j<swr_frame->channels;j++) {
qint16 min = 0;
qint16 max = 0;
for (int k=j*2;k<interval;k+=channel_skip) {
qint16 sample = ((swr_frame->data[0][i+k+1] << 8) | swr_frame->data[0][i+k]);
if (sample > max) {
max = sample;
} else if (sample < min) {
min = sample;
}
}
min /= 256;
max /= 256;
s->audio_preview.append(min);
s->audio_preview.append(max);
}
}
swr_free(&swr_ctx);
av_frame_free(&swr_frame);
}
// check if we've got all our previews
if (media->audio_tracks.size() == 0) {
done = true;
for (int i=0;i<media->video_tracks.size();i++) {
if (!media->video_tracks.at(i)->preview_done) {
done = false;
break;
}
}
}
if (!end_of_file) {
MediaStream* s = media->get_stream_from_file_index(packet.stream_index);
if (s != NULL && !s->preview_done) {
if (fmt_ctx->streams[packet.stream_index]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
int dstH = 120;
int dstW = dstH * ((float)temp_frame->width/(float)temp_frame->height);
uint8_t* data = new uint8_t[dstW*dstH*3];
sws_ctx = sws_getContext(
temp_frame->width,
temp_frame->height,
static_cast<AVPixelFormat>(temp_frame->format),
dstW,
dstH,
static_cast<AVPixelFormat>(AV_PIX_FMT_RGB24),
SWS_FAST_BILINEAR,
NULL,
NULL,
NULL
);
int linesize[AV_NUM_DATA_POINTERS];
linesize[0] = dstW*3;
sws_scale(sws_ctx, temp_frame->data, temp_frame->linesize, 0, temp_frame->height, &data, linesize);
s->video_preview = QImage(data, dstW, dstH, linesize[0], QImage::Format_RGB888);
// delete [] data;
s->preview_done = true;
sws_freeContext(sws_ctx);
avcodec_close(codec_ctx[packet.stream_index]);
codec_ctx[packet.stream_index] = NULL;
} else if (fmt_ctx->streams[packet.stream_index]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
int interval = qFloor((temp_frame->sample_rate/WAVEFORM_RESOLUTION)/4)*4;
AVFrame* swr_frame = av_frame_alloc();
swr_frame->channel_layout = temp_frame->channel_layout;
swr_frame->sample_rate = temp_frame->sample_rate;
swr_frame->format = AV_SAMPLE_FMT_S16;
swr_ctx = swr_alloc_set_opts(
NULL,
temp_frame->channel_layout,
static_cast<AVSampleFormat>(swr_frame->format),
temp_frame->sample_rate,
temp_frame->channel_layout,
static_cast<AVSampleFormat>(temp_frame->format),
temp_frame->sample_rate,
0,
NULL
);
swr_init(swr_ctx);
swr_convert_frame(swr_ctx, swr_frame, temp_frame);
int channel_skip = swr_frame->channels * 2;
for (int i=0;i<swr_frame->nb_samples;i+=interval) {
for (int j=0;j<swr_frame->channels;j++) {
qint16 min = 0;
qint16 max = 0;
for (int k=j*2;k<interval;k+=channel_skip) {
qint16 sample = ((swr_frame->data[0][i+k+1] << 8) | swr_frame->data[0][i+k]);
if (sample > max) {
max = sample;
} else if (sample < min) {
min = sample;
}
}
min /= 256;
max /= 256;
s->audio_preview.append(min);
s->audio_preview.append(max);
}
}
swr_free(&swr_ctx);
av_frame_free(&swr_frame);
}
// check if we've got all our previews
if (media->audio_tracks.size() == 0) {
done = true;
for (int i=0;i<media->video_tracks.size();i++) {
if (!media->video_tracks.at(i)->preview_done) {
done = false;
break;
}
}
if (done) {
end_of_file = true;
break;
}
}
if (done) {
end_of_file = true;
break;
}
av_packet_unref(&packet);
}
}
for (int i=0;i<media->audio_tracks.size();i++) {
media->audio_tracks.at(i)->preview_done = true;
}
av_frame_free(&temp_frame);
for (unsigned int i=0;i<fmt_ctx->nb_streams;i++) {
if (codec_ctx[i] != NULL) {
avcodec_close(codec_ctx[i]);
}
}
delete [] codec_ctx;
av_packet_unref(&packet);
}
}
if (fmt_ctx != NULL) {
avformat_close_input(&fmt_ctx);
for (int i=0;i<media->audio_tracks.size();i++) {
media->audio_tracks.at(i)->preview_done = true;
}
av_frame_free(&temp_frame);
for (unsigned int i=0;i<fmt_ctx->nb_streams;i++) {
if (codec_ctx[i] != NULL) {
avcodec_close(codec_ctx[i]);
}
}
delete [] codec_ctx;
avformat_close_input(&fmt_ctx);
}
+14
View File
@@ -24,6 +24,7 @@
#include <QFileDialog>
#include <QStandardPaths>
#include <QTimer>
#include <QCloseEvent>
#define OLIVE_FILE_FILTER "Olive Project (*.ove)"
@@ -304,6 +305,14 @@ bool MainWindow::can_close_project() {
return true;
}
void MainWindow::closeEvent(QCloseEvent *e) {
if (can_close_project()) {
e->accept();
} else {
e->ignore();
}
}
void MainWindow::on_action_Save_Project_triggered()
{
save_project();
@@ -531,3 +540,8 @@ void MainWindow::on_actionSlide_Tool_triggered()
{
if (panel_timeline->focused()) panel_timeline->ui->toolSlideButton->click();
}
void MainWindow::on_actionFolder_triggered()
{
panel_project->new_folder();
}
+5
View File
@@ -20,6 +20,9 @@ public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
protected:
void closeEvent(QCloseEvent *);
private slots:
void on_action_Import_triggered();
@@ -139,6 +142,8 @@ private slots:
void on_actionSlide_Tool_triggered();
void on_actionFolder_triggered();
private:
Ui::MainWindow *ui;
void setup_layout();
+6
View File
@@ -38,6 +38,7 @@
<addaction name="actionProject"/>
<addaction name="separator"/>
<addaction name="actionSequence"/>
<addaction name="actionFolder"/>
</widget>
<addaction name="menu_New"/>
<addaction name="action_Open_Project"/>
@@ -583,6 +584,11 @@
<string>U</string>
</property>
</action>
<action name="actionFolder">
<property name="text">
<string>Folder</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources>
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 4.6.2, 2018-07-10T01:01:52. -->
<!-- Written by QtCreator 4.6.2, 2018-07-10T13:36:23. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>
+74 -39
View File
@@ -38,7 +38,7 @@ Project::Project(QWidget *parent) :
ui(new Ui::Project)
{
ui->setupUi(this);
source_table = ui->treeWidget;
connect(ui->treeWidget, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, SLOT(rename_media(QTreeWidgetItem*,int)));
}
@@ -70,35 +70,30 @@ QString Project::get_next_sequence_name() {
}
void Project::rename_media(QTreeWidgetItem* item, int column) {
Media* m = get_media_from_tree(item);
m->name = item->text(column);
if (m->type == MEDIA_TYPE_SEQUENCE) {
m->sequence->name = m->name;
int type = get_type_from_tree(item);
QString n = item->text(column);
switch (type) {
case MEDIA_TYPE_FOOTAGE: get_media_from_tree(item)->name = n; break;
case MEDIA_TYPE_SEQUENCE: get_sequence_from_tree(item)->name = n; break;
}
}
void Project::duplicate_selected() {
QList<QTreeWidgetItem*> items = ui->treeWidget->selectedItems();
for (int i=0;i<items.size();i++) {
Media* m = get_media_from_tree(items.at(i));
if (m->type == MEDIA_TYPE_SEQUENCE) {
new_sequence(m->sequence->copy(), false);
int type = get_type_from_tree(items.at(i));
if (type == MEDIA_TYPE_SEQUENCE) {
new_sequence(get_sequence_from_tree(items.at(i))->copy(), false);
}
}
}
void Project::new_sequence(Sequence *s, bool open) {
Media* m = new Media();
m->type = MEDIA_TYPE_SEQUENCE;
m->sequence = s;
QTreeWidgetItem* item = new QTreeWidgetItem();
item->setFlags(item->flags() | Qt::ItemIsEditable);
QTreeWidgetItem* item = new_item();
item->setText(0, s->name);
set_media_of_tree(item, m);
set_sequence_of_tree(item, s);
ui->treeWidget->addTopLevelItem(item);
source_table = ui->treeWidget;
project_changed = true;
@@ -128,7 +123,6 @@ Media* Project::import_file(QString file) {
av_dump_format(pFormatCtx, 0, filename, 0);
m = new Media();
m->type = MEDIA_TYPE_FOOTAGE;
m->url = file;
m->name = file.mid(file.lastIndexOf('/')+1);
@@ -155,8 +149,7 @@ Media* Project::import_file(QString file) {
}
m->length = pFormatCtx->duration;
QTreeWidgetItem* item = new QTreeWidgetItem();
item->setFlags(item->flags() | Qt::ItemIsEditable);
QTreeWidgetItem* item = new_item();
if (m->video_tracks.size() == 0) {
item->setIcon(0, QIcon(":/icons/audiosource.png"));
} else {
@@ -169,23 +162,39 @@ Media* Project::import_file(QString file) {
ui->treeWidget->addTopLevelItem(item);
project_changed = true;
// generate waveform/thumbnail in another thread
PreviewGenerator* pg = new PreviewGenerator();
pg->fmt_ctx = pFormatCtx; // cleaned up in PG
pg->media = m;
connect(pg, SIGNAL(finished()), pg, SLOT(deleteLater()));
pg->start(QThread::LowPriority);
}
}
PreviewGenerator* pg = new PreviewGenerator();
pg->fmt_ctx = pFormatCtx; // cleaned up in PG
pg->media = m;
connect(pg, SIGNAL(finished()), pg, SLOT(deleteLater()));
pg->start(QThread::LowPriority);
delete [] filename;
return m;
}
QTreeWidgetItem* Project::new_item() {
QTreeWidgetItem* item = new QTreeWidgetItem();
item->setFlags(item->flags() | Qt::ItemIsEditable);
return item;
}
bool Project::is_focused() {
return ui->treeWidget->hasFocus();
}
void Project::new_folder() {
QTreeWidgetItem* item = new_item();
item->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator);
item->setText(0, "New Folder");
set_item_to_folder(item);
ui->treeWidget->addTopLevelItem(item);
project_changed = true;
}
void Project::delete_selected_media() {
QList<QTreeWidgetItem*> items = ui->treeWidget->selectedItems();
bool remove = true;
@@ -193,8 +202,9 @@ void Project::delete_selected_media() {
// check if media is in use
for (int i=0;i<items.size();i++) {
Media* m = get_media_from_tree(items.at(i));
if (m->type == MEDIA_TYPE_FOOTAGE && sequence != NULL) {
QTreeWidgetItem* item = items.at(i);
Media* m = get_media_from_tree(item);
if (get_type_from_tree(item) == MEDIA_TYPE_FOOTAGE && sequence != NULL) {
for (int j=0;j<sequence->clip_count();j++) {
Clip* c = sequence->get_clip(j);
if (c != NULL && c->media == m) {
@@ -292,23 +302,47 @@ void Project::import_dialog() {
process_file_list(files);
}
void Project::set_item_to_folder(QTreeWidgetItem* item) {
item->setData(0, Qt::UserRole + 1, MEDIA_TYPE_FOLDER);
}
Media* Project::get_media_from_tree(QTreeWidgetItem* item) {
return reinterpret_cast<Media*>(item->data(0, Qt::UserRole + 1).value<quintptr>());
return reinterpret_cast<Media*>(item->data(0, Qt::UserRole + 2).value<quintptr>());
}
void Project::set_media_of_tree(QTreeWidgetItem* item, Media* media) {
item->setData(0, Qt::UserRole + 1, QVariant::fromValue(reinterpret_cast<quintptr>(media)));
item->setData(0, Qt::UserRole + 1, MEDIA_TYPE_FOOTAGE);
item->setData(0, Qt::UserRole + 2, QVariant::fromValue(reinterpret_cast<quintptr>(media)));
}
Sequence* Project::get_sequence_from_tree(QTreeWidgetItem* item) {
return reinterpret_cast<Sequence*>(item->data(0, Qt::UserRole + 2).value<quintptr>());
}
void Project::set_sequence_of_tree(QTreeWidgetItem* item, Sequence* sequence) {
item->setData(0, Qt::UserRole + 1, MEDIA_TYPE_SEQUENCE);
item->setData(0, Qt::UserRole + 2, QVariant::fromValue(reinterpret_cast<quintptr>(sequence)));
}
int Project::get_type_from_tree(QTreeWidgetItem* item) {
return item->data(0, Qt::UserRole + 1).toInt();
}
void Project::delete_media(QTreeWidgetItem* item) {
Media* m = get_media_from_tree(item);
if (m->type == MEDIA_TYPE_SEQUENCE) {
if (sequence == m->sequence) {
int type = get_type_from_tree(item);
switch (type) {
case MEDIA_TYPE_FOOTAGE:
delete get_media_from_tree(item);
break;
case MEDIA_TYPE_SEQUENCE:
Sequence* s = get_sequence_from_tree(item);
if (sequence == s) {
set_sequence(NULL);
}
delete m->sequence;
delete s;
break;
}
delete m;
project_changed = true;
}
@@ -573,8 +607,9 @@ void Project::save_project() {
int len = ui->treeWidget->topLevelItemCount();
stream.writeStartElement("media");
for (int i=0;i<len;i++) {
Media* m = get_media_from_tree(ui->treeWidget->topLevelItem(i));
if (m->type == MEDIA_TYPE_FOOTAGE) {
QTreeWidgetItem* item = ui->treeWidget->topLevelItem(i);
if (get_type_from_tree(item) == MEDIA_TYPE_FOOTAGE) {
Media* m = get_media_from_tree(item);
m->save_id = i;
stream.writeStartElement("footage");
stream.writeAttribute("id", QString::number(i));
@@ -587,9 +622,9 @@ void Project::save_project() {
stream.writeStartElement("timeline");
for (int i=0;i<len;i++) {
Media* m = get_media_from_tree(ui->treeWidget->topLevelItem(i));
if (m->type == MEDIA_TYPE_SEQUENCE) {
Sequence* s = m->sequence;
QTreeWidgetItem* item = ui->treeWidget->topLevelItem(i);
if (get_type_from_tree(item) == MEDIA_TYPE_SEQUENCE) {
Sequence* s = get_sequence_from_tree(item);
stream.writeStartElement("sequence");
stream.writeTextElement("name", s->name);
stream.writeTextElement("width", QString::number(s->width));
+12
View File
@@ -11,6 +11,11 @@ class Viewer;
class SourceTable;
class QTreeWidgetItem;
#define MEDIA_TYPE_FOOTAGE 0
#define MEDIA_TYPE_SEQUENCE 1
#define MEDIA_TYPE_FOLDER 2
#define MEDIA_TYPE_SOLID 3
namespace Ui {
class Project;
}
@@ -40,12 +45,19 @@ public:
void load_project();
void save_project();
void new_folder();
int get_type_from_tree(QTreeWidgetItem* item);
Media* get_media_from_tree(QTreeWidgetItem* item);
void set_media_of_tree(QTreeWidgetItem* item, Media* media);
Sequence* get_sequence_from_tree(QTreeWidgetItem* item);
void set_sequence_of_tree(QTreeWidgetItem* item, Sequence* sequence);
void set_item_to_folder(QTreeWidgetItem* item);
SourceTable* source_table;
private:
Ui::Project *ui;
QTreeWidgetItem* new_item();
private slots:
void rename_media(QTreeWidgetItem* item, int column);
};
+7 -1
View File
@@ -35,6 +35,9 @@
</property>
<item>
<widget class="SourceTable" name="treeWidget">
<property name="acceptDrops">
<bool>true</bool>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
@@ -51,7 +54,10 @@
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="rootIsDecorated">
<bool>false</bool>
<bool>true</bool>
</property>
<property name="itemsExpandable">
<bool>true</bool>
</property>
<property name="sortingEnabled">
<bool>true</bool>
+17 -1
View File
@@ -10,6 +10,7 @@
#include <QtMath>
#include <QDebug>
#define AUDIO_MONITOR_PEAK_HEIGHT 15
#define AUDIO_MONITOR_GAP 3
extern "C" {
@@ -39,24 +40,39 @@ void AudioMonitor::paintEvent(QPaintEvent *) {
QPainter p(this);
int channel_x = AUDIO_MONITOR_GAP;
int channel_count = av_get_channel_layout_nb_channels(sequence->audio_layout);
if (peaks.size() != channel_count) {
peaks.resize(channel_count);
peaks.fill(false);
}
int channel_width = (width()/channel_count) - AUDIO_MONITOR_GAP;
long playhead_offset = -1;
int i;
for (i=0;i<channel_count;i++) {
QRect r(channel_x, 0, channel_width, height());
QRect r(channel_x, AUDIO_MONITOR_PEAK_HEIGHT + AUDIO_MONITOR_GAP, channel_width, height());
p.fillRect(r, gradient);
if (sample_cache_offset != -1) {
playhead_offset = (panel_timeline->playhead - sample_cache_offset) * channel_count;
if (playhead_offset >= 0 && playhead_offset < sample_cache.size()) {
double multiplier = 1 - qAbs((double) sample_cache.at(playhead_offset+i) / 32768.0); // 16-bit int divided to float
if (multiplier == (double) 0) {
peaks[i] = true;
}
r.setHeight(r.height()*multiplier);
} else {
reset();
}
}
QRect peak_rect(channel_x, 0, channel_width, AUDIO_MONITOR_PEAK_HEIGHT);
if (peaks.at(i)) {
p.fillRect(peak_rect, QColor(255, 0, 0));
} else {
p.fillRect(peak_rect, QColor(64, 0, 0));
}
p.fillRect(r, QColor(0, 0, 0, 160));
channel_x += channel_width + AUDIO_MONITOR_GAP;
}
if (playhead_offset > -1) {
+1
View File
@@ -22,6 +22,7 @@ public slots:
private:
QLinearGradient gradient;
QVector<bool> peaks;
};
#endif // AUDIOMONITOR_H
+31 -9
View File
@@ -13,14 +13,9 @@
SourceTable::SourceTable(QWidget* parent) : QTreeWidget(parent) {
sortByColumn(0, Qt::AscendingOrder);
setAcceptDrops(true);
editing_item = NULL;
rename_timer.setInterval(500);
connect(&rename_timer, SIGNAL(timeout()), this, SLOT(rename_interval()));
connect(this, SIGNAL(itemClicked(QTreeWidgetItem*,int)), this, SLOT(item_click(QTreeWidgetItem*,int)));
// connect(this, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)), this, SLOT(stop_rename_timer()));
// connect(this, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, )
}
void SourceTable::stop_rename_timer() {
@@ -50,9 +45,8 @@ void SourceTable::mouseDoubleClickEvent(QMouseEvent* ) {
panel_project->import_dialog();
} else if (selectedItems().count() == 1) {
QTreeWidgetItem* item = selectedItems().at(0);
Media* m = reinterpret_cast<Media*>(item->data(0, Qt::UserRole + 1).value<quintptr>());
if (m->type == MEDIA_TYPE_SEQUENCE) {
set_sequence(m->sequence);
if (panel_project->get_type_from_tree(item) == MEDIA_TYPE_SEQUENCE) {
set_sequence(panel_project->get_sequence_from_tree(item));
}
}
}
@@ -75,7 +69,6 @@ void SourceTable::dragMoveEvent(QDragMoveEvent *event) {
void SourceTable::dropEvent(QDropEvent* event) {
const QMimeData* mimeData = event->mimeData();
if (mimeData->hasUrls()) {
QList<QUrl> urls = mimeData->urls();
if (!urls.isEmpty()) {
@@ -87,5 +80,34 @@ void SourceTable::dropEvent(QDropEvent* event) {
panel_project->process_file_list(paths);
}
event->acceptProposedAction();
} else {
QTreeWidgetItem* item = itemAt(event->pos());
if (item == NULL || (item != NULL && panel_project->get_type_from_tree(item) == MEDIA_TYPE_FOLDER)) {
QList<QTreeWidgetItem*> items = selectedItems();
for (int i=0;i<items.size();i++) {
QTreeWidgetItem* s = items.at(i);
bool ignore = false;
if (s->parent() == NULL) {
takeTopLevelItem(indexOfTopLevelItem(s));
} else {
// if child belongs to a selected parent, assume the user is just moving the parent and ignore the child
for (int j=0;j<items.size();j++) {
if (s->parent() == items.at(j)) {
ignore = true;
break;
}
}
if (!ignore) s->parent()->takeChild(s->parent()->indexOfChild(s));
}
if (!ignore) {
if (item == NULL) {
addTopLevelItem(s);
} else {
item->addChild(s);
}
}
}
project_changed = true;
}
}
}
+23 -21
View File
@@ -59,27 +59,29 @@ void TimelineWidget::dragEnterEvent(QDragEnterEvent *event) {
panel_timeline->drag_frame_start = entry_point + panel_timeline->getFrameFromScreenPoint(50);
panel_timeline->drag_track_start = (bottom_align) ? -1 : 0;
for (int i=0;i<items.size();i++) {
bool ignore_infinite_length = false;
Media* m = panel_project->get_media_from_tree(items.at(i));
Ghost g;
g.clip = -1;
g.media = m;
g.old_clip_in = g.clip_in = 0;
g.in = entry_point;
entry_point += m->get_length_in_frames(sequence->frame_rate);
g.out = entry_point;
g.trimming = false;
for (int j=0;j<m->audio_tracks.size();j++) {
g.track = j;
g.media_stream = m->audio_tracks.at(j);
ignore_infinite_length = true;
panel_timeline->ghosts.append(g);
}
for (int j=0;j<m->video_tracks.size();j++) {
g.track = -1-j;
g.media_stream = m->video_tracks.at(j);
if (m->video_tracks[j]->infinite_length && !ignore_infinite_length) g.out = g.in + 100;
panel_timeline->ghosts.append(g);
QTreeWidgetItem* item = items.at(i);
if (panel_project->get_type_from_tree(item) == MEDIA_TYPE_FOOTAGE) {
Media* m = panel_project->get_media_from_tree(item);
bool ignore_infinite_length = (m->audio_tracks.size() > 0);
Ghost g;
g.clip = -1;
g.media = m;
g.old_clip_in = g.clip_in = 0;
g.in = entry_point;
entry_point += m->get_length_in_frames(sequence->frame_rate);
g.out = entry_point;
g.trimming = false;
for (int j=0;j<m->audio_tracks.size();j++) {
g.track = j;
g.media_stream = m->audio_tracks.at(j);
panel_timeline->ghosts.append(g);
}
for (int j=0;j<m->video_tracks.size();j++) {
g.track = -1-j;
g.media_stream = m->video_tracks.at(j);
if (m->video_tracks[j]->infinite_length && !ignore_infinite_length) g.out = g.in + 100;
panel_timeline->ghosts.append(g);
}
}
}
for (int i=0;i<panel_timeline->ghosts.size();i++) {