diff --git a/icons/icons.qrc b/icons/icons.qrc
index facafcbdd..3fc0faaf0 100644
--- a/icons/icons.qrc
+++ b/icons/icons.qrc
@@ -29,5 +29,6 @@
slip-disabled.png
slide.png
slide-disabled.png
+ throbber.png
diff --git a/icons/throbber.png b/icons/throbber.png
new file mode 100644
index 000000000..208c0aecc
Binary files /dev/null and b/icons/throbber.png differ
diff --git a/io/previewgenerator.cpp b/io/previewgenerator.cpp
index 5b808e8aa..2804adced 100644
--- a/io/previewgenerator.cpp
+++ b/io/previewgenerator.cpp
@@ -1,7 +1,3 @@
-//
-// TODO: Fold this file into a multithreaded "file processor"
-//
-
#include "previewgenerator.h"
#include "media.h"
@@ -10,6 +6,9 @@
#include
#include
#include
+#include
+
+#define WAVEFORM_RESOLUTION 64
extern "C" {
#include
@@ -18,16 +17,46 @@ extern "C" {
#include
}
-PreviewGenerator::PreviewGenerator(QObject* parent) : QThread(parent) {
- media = NULL;
- fmt_ctx = NULL;
+PreviewGenerator::PreviewGenerator(QTreeWidgetItem* i, Media* m) : QThread(0), fmt_ctx(NULL), item(i), media(m) {
+ connect(this, SIGNAL(finished()), this, SLOT(deleteLater()));
}
-#define WAVEFORM_RESOLUTION 64
+void PreviewGenerator::parse_media() {
+ // detect video/audio streams in file
+ for (int i=0;i<(int)fmt_ctx->nb_streams;i++) {
+ // Find the decoder for the video stream
+ if (avcodec_find_decoder(fmt_ctx->streams[i]->codecpar->codec_id) == NULL) {
+ qDebug() << "[ERROR] Unsupported codec in stream %d.\n";
+ } else {
+ MediaStream* ms = new MediaStream();
+ ms->preview_done = false;
+ ms->file_index = i;
+ if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
+ bool infinite_length = (fmt_ctx->streams[i]->avg_frame_rate.den == 0);
+ ms->video_width = fmt_ctx->streams[i]->codecpar->width;
+ ms->video_height = fmt_ctx->streams[i]->codecpar->height;
+ ms->infinite_length = infinite_length;
+ media->video_tracks.append(ms);
+ } else if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
+ ms->audio_channels = fmt_ctx->streams[i]->codecpar->channels;
+ media->audio_tracks.append(ms);
+ }
+ }
+ }
+ media->length = fmt_ctx->duration;
-void PreviewGenerator::run() {
- Q_ASSERT(media != NULL);
+ media->ready = true;
+ if (media->video_tracks.size() == 0) {
+ emit set_icon(ICON_TYPE_AUDIO);
+ } else {
+ emit set_icon(ICON_TYPE_VIDEO);
+ }
+
+ item->setText(1, QString::number(media->length));
+}
+
+void PreviewGenerator::generate_waveform() {
SwsContext* sws_ctx;
SwrContext* swr_ctx;
AVFrame* temp_frame = av_frame_alloc();
@@ -99,7 +128,7 @@ void PreviewGenerator::run() {
s->video_preview = QImage(data, dstW, dstH, linesize[0], QImage::Format_RGB888);
- // delete [] data;
+// delete [] data;
s->preview_done = true;
@@ -183,6 +212,41 @@ void PreviewGenerator::run() {
}
}
delete [] codec_ctx;
+}
- avformat_close_input(&fmt_ctx);
+void PreviewGenerator::run() {
+ Q_ASSERT(media != NULL);
+ Q_ASSERT(item != NULL);
+
+ QByteArray ba = media->url.toLatin1();
+ char* filename = new char[ba.size()+1];
+ strcpy(filename, ba.data());
+
+ bool error = false;
+ int errCode = avformat_open_input(&fmt_ctx, filename, NULL, NULL);
+ if(errCode != 0) {
+ char err[1024];
+ av_strerror(errCode, err, 1024);
+ item->setToolTip(0, "Could not open file - " + QString(err));
+ error = true;
+ } else {
+ errCode = avformat_find_stream_info(fmt_ctx, NULL);
+ if (errCode < 0) {
+ char err[1024];
+ av_strerror(errCode, err, 1024);
+ item->setToolTip(0, "Could not find stream information - " + QString(err));
+ error = true;
+ } else {
+ av_dump_format(fmt_ctx, 0, filename, 0);
+ parse_media();
+ generate_waveform();
+ }
+ avformat_close_input(&fmt_ctx);
+ }
+ if (error) {
+ emit set_icon(ICON_TYPE_ERROR);
+ } else {
+ item->setToolTip(0, QString());
+ }
+ delete [] filename;
}
diff --git a/io/previewgenerator.h b/io/previewgenerator.h
index 35ffc3b5d..293c57614 100644
--- a/io/previewgenerator.h
+++ b/io/previewgenerator.h
@@ -3,15 +3,27 @@
#include
+#define ICON_TYPE_VIDEO 0
+#define ICON_TYPE_AUDIO 1
+#define ICON_TYPE_ERROR 2
+
struct Media;
struct MediaStream;
struct AVFormatContext;
+class QTreeWidgetItem;
class PreviewGenerator : public QThread
{
+ Q_OBJECT
public:
- PreviewGenerator(QObject* parent = 0);
+ PreviewGenerator(QTreeWidgetItem*, Media*);
void run();
+signals:
+ void set_icon(int);
+private:
+ void parse_media();
+ void generate_waveform();
+ QTreeWidgetItem* item;
Media* media;
AVFormatContext* fmt_ctx;
};
diff --git a/mainwindow.cpp b/mainwindow.cpp
index 76bdbe5be..33f303884 100644
--- a/mainwindow.cpp
+++ b/mainwindow.cpp
@@ -27,6 +27,7 @@
#include
#include
#include
+#include
#define OLIVE_FILE_FILTER "Olive Project (*.ove)"
@@ -58,7 +59,7 @@ MainWindow::MainWindow(QWidget *parent) :
darkPalette.setColor(QPalette::WindowText, Qt::white);
darkPalette.setColor(QPalette::Base, QColor(25,25,25));
darkPalette.setColor(QPalette::AlternateBase, QColor(53,53,53));
- darkPalette.setColor(QPalette::ToolTipBase, Qt::white);
+ darkPalette.setColor(QPalette::ToolTipBase, QColor(25,25,25));
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
darkPalette.setColor(QPalette::Text, Qt::white);
darkPalette.setColor(QPalette::Button, QColor(53,53,53));
diff --git a/panels/project.cpp b/panels/project.cpp
index 6b0705edb..28fe01996 100644
--- a/panels/project.cpp
+++ b/panels/project.cpp
@@ -111,77 +111,22 @@ void Project::new_sequence(Sequence *s, bool open, QTreeWidgetItem* parent) {
}
QTreeWidgetItem* Project::import_file(QString file) {
- QByteArray ba = file.toLatin1();
- char* filename = new char[ba.size()+1];
- strcpy(filename, ba.data());
-
QTreeWidgetItem* item = new_item();
Media* m = new Media();
m->url = file;
m->name = file.mid(file.lastIndexOf('/')+1);
item->setText(0, m->name);
- AVFormatContext* pFormatCtx = NULL;
- int errCode = avformat_open_input(&pFormatCtx, filename, NULL, NULL);
- if(errCode != 0) {
- char err[1024];
- av_strerror(errCode, err, 1024);
- qDebug() << "[ERROR] Could not open" << filename << "-" << err;
- } else {
- errCode = avformat_find_stream_info(pFormatCtx, NULL);
- if (errCode < 0) {
- char err[1024];
- av_strerror(errCode, err, 1024);
- fprintf(stderr, "[ERROR] Could not find stream information. %s\n", err);
- } else {
- av_dump_format(pFormatCtx, 0, filename, 0);
-
- // detect video/audio streams in file
- for (int i=0;i<(int)pFormatCtx->nb_streams;i++) {
- // Find the decoder for the video stream
- if (avcodec_find_decoder(pFormatCtx->streams[i]->codecpar->codec_id) == NULL) {
- qDebug() << "[ERROR] Unsupported codec in stream %d.\n";
- } else {
- MediaStream* ms = new MediaStream();
- ms->preview_done = false;
- ms->file_index = i;
- if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
- bool infinite_length = (pFormatCtx->streams[i]->avg_frame_rate.den == 0);
- ms->video_width = pFormatCtx->streams[i]->codecpar->width;
- ms->video_height = pFormatCtx->streams[i]->codecpar->height;
- ms->infinite_length = infinite_length;
- m->video_tracks.append(ms);
- } else if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
- ms->audio_channels = pFormatCtx->streams[i]->codecpar->channels;
- m->audio_tracks.append(ms);
- }
- }
- }
- m->length = pFormatCtx->duration;
-
- if (m->video_tracks.size() == 0) {
- item->setIcon(0, QIcon(":/icons/audiosource.png"));
- } else {
- item->setIcon(0, QIcon(":/icons/videosource.png"));
- }
- item->setText(1, QString::number(m->length));
-
- m->ready = 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);
- }
- }
-
set_media_of_tree(item, m);
- project_changed = true;
+ // set up throbber animation
+ MediaThrobber* throbber = new MediaThrobber(item);
+
+ // generate waveform/thumbnail in another thread
+ PreviewGenerator* pg = new PreviewGenerator(item, m);
+ connect(pg, SIGNAL(set_icon(int)), throbber, SLOT(stop(int)));
+ pg->start(QThread::LowPriority);
- delete [] filename;
return item;
}
@@ -377,6 +322,7 @@ void Project::process_file_list(QStringList& files) {
ta->add_media(import_file(file));
imported = true;
+ project_changed = true;
}
if (imported) {
undo_stack.push(ta);
@@ -935,3 +881,33 @@ void Project::add_recent_project(QString url) {
}
save_recent_projects();
}
+
+#define THROBBER_LIMIT 20
+#define THROBBER_SIZE 50
+
+MediaThrobber::MediaThrobber(QTreeWidgetItem* i) : pixmap(":/icons/throbber.png"), item(i), animation(0) {
+ // set up throbber
+ animation_update();
+ animator.setInterval(20);
+ connect(&animator, SIGNAL(timeout()), this, SLOT(animation_update()));
+ animator.start();
+}
+
+void MediaThrobber::animation_update() {
+ if (animation == THROBBER_LIMIT) {
+ animation = 0;
+ }
+ item->setIcon(0, QIcon(pixmap.copy(THROBBER_SIZE*animation, 0, THROBBER_SIZE, THROBBER_SIZE)));
+ animation++;
+}
+
+void MediaThrobber::stop(int icon_type) {
+ animator.stop();
+ switch (icon_type) {
+ case ICON_TYPE_VIDEO: item->setIcon(0, QIcon(":/icons/videosource.png")); break;
+ case ICON_TYPE_AUDIO: item->setIcon(0, QIcon(":/icons/audiosource.png")); break;
+ case ICON_TYPE_ERROR: item->setIcon(0, QIcon::fromTheme("dialog-error")); break;
+ }
+ panel_project->source_table->viewport()->update();
+ deleteLater();
+}
diff --git a/panels/project.h b/panels/project.h
index 773f4d23b..07525755c 100644
--- a/panels/project.h
+++ b/panels/project.h
@@ -3,6 +3,7 @@
#include
#include
+#include
struct Media;
struct Sequence;
@@ -84,4 +85,19 @@ private slots:
void clear_recent_projects();
};
+class MediaThrobber : public QObject {
+ Q_OBJECT
+public:
+ MediaThrobber(QTreeWidgetItem*);
+public slots:
+ void stop(int);
+private slots:
+ void animation_update();
+private:
+ QPixmap pixmap;
+ int animation;
+ QTreeWidgetItem* item;
+ QTimer animator;
+};
+
#endif // PROJECT_H
diff --git a/project/effect.cpp b/project/effect.cpp
index bec57d341..dd8575f8e 100644
--- a/project/effect.cpp
+++ b/project/effect.cpp
@@ -35,11 +35,5 @@ bool Effect::is_enabled() {
Effect* Effect::copy(Clip*) {return NULL;}
void Effect::load(QXmlStreamReader*) {}
void Effect::save(QXmlStreamWriter*) {}
-/*void Effect::import_values(float* val, int count) {
- qDebug() << "[ERROR] import_values MUST be overridden";
-}
-void Effect::export_values(float* val, int* count) {
- qDebug() << "[ERROR] export_values MUST be overridden";
-}*/
void Effect::process_gl(int*, int*) {}
void Effect::process_audio(uint8_t*, int) {}