diff --git a/io/media.h b/io/media.h index ac74a30b2..105afa0af 100644 --- a/io/media.h +++ b/io/media.h @@ -28,7 +28,7 @@ struct MediaStream { struct Media { Media(); - ~Media(); + ~Media(); QString url; QString name; diff --git a/mainwindow.cpp b/mainwindow.cpp index f75245885..b16ad2455 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -5,6 +5,8 @@ #include "project/sequence.h" +#include "ui/sourcetable.h" + #include "panels/panels.h" #include "panels/project.h" #include "panels/effectcontrols.h" @@ -590,9 +592,10 @@ void MainWindow::on_actionSlide_Tool_triggered() if (panel_timeline->focused()) panel_timeline->ui->toolSlideButton->click(); } -void MainWindow::on_actionFolder_triggered() -{ - panel_project->new_folder(); +void MainWindow::on_actionFolder_triggered() { + TimelineAction* ta = new TimelineAction(); + ta->add_media(panel_project->new_folder(0), panel_project->get_selected_folder()); + undo_stack.push(ta); } void MainWindow::fileMenu_About_To_Be_Shown() { diff --git a/mainwindow.ui b/mainwindow.ui index f5bdadc25..01eceb3b9 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -24,7 +24,7 @@ 0 0 653 - 17 + 20 @@ -151,7 +151,6 @@ - @@ -420,6 +419,9 @@ Crash + + false + diff --git a/panels/project.cpp b/panels/project.cpp index 183e075cd..1a17f1074 100644 --- a/panels/project.cpp +++ b/panels/project.cpp @@ -15,6 +15,7 @@ #include "project/undo.h" #include "mainwindow.h" #include "io/config.h" +#include "playback/cacher.h" #include #include @@ -104,6 +105,53 @@ void Project::duplicate_selected() { } } +void Project::replace_selected_file() { + QList selected_items = ui->treeWidget->selectedItems(); + if (selected_items.size() == 1) { + QTreeWidgetItem* item = selected_items.at(0); + if (get_type_from_tree(item) == MEDIA_TYPE_FOOTAGE) { + replace_media(item, ""); + } + } +} + +void Project::replace_media(QTreeWidgetItem* item, QString filename) { + Media* m = get_media_from_tree(item); + + // close any clips currently using this media + QVector all_sequences = list_all_project_sequences(); + for (int i=0;iclip_count();j++) { + Clip* c = s->get_clip(j); + if (c != NULL && c->media == m && c->open) { + close_clip(c); + c->cacher->wait(); + } + } + } + + QStringList files; + if (filename.isEmpty()) { + files.append(QFileDialog::getOpenFileName(this, "Replace '" + item->text(0) + "'", "", "All Files (*)")); + } else { + files.append(filename); + } + process_file_list(NULL, files, NULL, item); + + for (int i=0;iclip_count();j++) { + Clip* c = s->get_clip(j); + if (c != NULL && c->media == m) { + c->refresh(); + } + } + } + + panel_timeline->redraw_all_clips(true); +} + void Project::new_sequence(TimelineAction *ta, Sequence *s, bool open, QTreeWidgetItem* parent) { QTreeWidgetItem* item = new_item(); item->setText(0, s->name); @@ -134,17 +182,16 @@ void Project::start_preview_generator(QTreeWidgetItem* item, Media* media) { pg->start(QThread::LowPriority); } -QTreeWidgetItem* Project::import_file(QString file, QString imported_filename) { - QTreeWidgetItem* item = new_item(); - Media* m = new Media(); +QString Project::get_file_name_from_path(const QString& path) { + return path.mid(path.lastIndexOf('/')+1); +} + +void Project::import_file(QTreeWidgetItem* item, Media* m, QString file, QString imported_filename) { m->url = file; - m->name = imported_filename.mid(file.lastIndexOf('/')+1); - set_media_of_tree(item, m); + m->name = get_file_name_from_path(imported_filename); // generate waveform/thumbnail in another thread - start_preview_generator(item, m); - - return item; + start_preview_generator(item, m); } QTreeWidgetItem* Project::new_item() { @@ -157,13 +204,11 @@ bool Project::is_focused() { return ui->treeWidget->hasFocus(); } -QTreeWidgetItem* Project::new_folder() { +QTreeWidgetItem* Project::new_folder(QString name) { QTreeWidgetItem* item = new_item(); item->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator); - item->setText(0, "New Folder"); + item->setText(0, (name.isEmpty()) ? "New Folder" : name); set_item_to_folder(item); - ui->treeWidget->addTopLevelItem(item); - project_changed = true; return item; } @@ -299,103 +344,165 @@ void Project::delete_selected_media() { } } -void Project::process_file_list(QStringList& files) { +void Project::process_file_list(bool recursive, QStringList& files, QTreeWidgetItem* parent, QTreeWidgetItem* replace) { bool imported = false; QVector image_sequence_urls; QVector image_sequence_importassequence; QStringList image_sequence_formats = config.img_seq_formats.split("|"); - TimelineAction* ta = new TimelineAction(); + TimelineAction* ta; + if (!recursive) ta = new TimelineAction(); + for (int i=0;i file.lastIndexOf('/')) { - // image_sequence_formats - found = false; - QString ext = file.mid(lastcharindex+1); - for (int j=0;jadd_media(folder, parent); + } else { + parent->addChild(folder); + } - // Check if there are files with the same filename but just different numbers - if (QFileInfo::exists(QString(file.left(digit_test) + QString("%1").arg(file_number-1, digit_count, 10, QChar('0')) + file.mid(lastcharindex))) - || QFileInfo::exists(QString(file.left(digit_test) + QString("%1").arg(file_number+1, digit_count, 10, QChar('0')) + file.mid(lastcharindex)))) { - is_img_sequence = true; - } + imported = true; + } else { + QString file(files.at(i)); + bool skip = false; - if (is_img_sequence) { - // get the URL that we would pass to FFmpeg to force it to read the image as a sequence - QString new_filename = file.left(digit_test) + "%" + QString("%1").arg(digit_count, 2, 10, QChar('0')) + "d" + file.mid(lastcharindex); + /* Heuristic to determine whether file is part of an image sequence */ - // add image sequence url to a vector in case the user imported several files that - // we're interpreting as a possible sequence - found = false; - for (int i=0;i file.lastIndexOf('/')) { + // image_sequence_formats + found = false; + QString ext = file.mid(lastcharindex+1); + for (int j=0;jadd_media(import_file(file, files.at(i))); - imported = true; - project_changed = true; - } - } - if (imported) { - undo_stack.push(ta); - } else { - delete ta; + if (found && file[lastcharindex-1].isDigit()) { + bool is_img_sequence = false; + + // how many digits are in the filename? + int digit_count = 0; + int digit_test = lastcharindex-1; + while (file[digit_test].isDigit()) { + digit_count++; + digit_test--; + } + + // retrieve number from filename + digit_test++; + int file_number = file.mid(digit_test, digit_count).toInt(); + + // Check if there are files with the same filename but just different numbers + if (QFileInfo::exists(QString(file.left(digit_test) + QString("%1").arg(file_number-1, digit_count, 10, QChar('0')) + file.mid(lastcharindex))) + || QFileInfo::exists(QString(file.left(digit_test) + QString("%1").arg(file_number+1, digit_count, 10, QChar('0')) + file.mid(lastcharindex)))) { + is_img_sequence = true; + } + + if (is_img_sequence) { + // get the URL that we would pass to FFmpeg to force it to read the image as a sequence + QString new_filename = file.left(digit_test) + "%" + QString("%1").arg(digit_count, 2, 10, QChar('0')) + "d" + file.mid(lastcharindex); + + // add image sequence url to a vector in case the user imported several files that + // we're interpreting as a possible sequence + found = false; + for (int i=0;ireset(); + } else { + item = new_item(); + m = new Media(); + } + + import_file(item, m, file, files.at(i)); + set_media_of_tree(item, m); + + if (recursive) { + parent->addChild(item); + } else { + ta->add_media(item, parent); + } + + imported = true; + } + } } + if (!recursive) { + if (imported) { + undo_stack.push(ta); + } else { + delete ta; + } + } +} + +QTreeWidgetItem* Project::get_selected_folder() { + // if one item is selected and it's a folder, return it + QList selected_items = panel_project->source_table->selectedItems(); + if (selected_items.size() == 1 && get_type_from_tree(selected_items.at(0)) == MEDIA_TYPE_FOLDER) { + return selected_items.at(0); + } + return NULL; } void Project::import_dialog() { - QStringList files = QFileDialog::getOpenFileNames(this, "Import media...", "", "All Files (*)"); - process_file_list(files); + QFileDialog fd(this, "Import media...", "", "All Files (*)"); + fd.setFileMode(QFileDialog::ExistingFiles); + + if (fd.exec()) { + QStringList files = fd.selectedFiles(); + process_file_list(NULL, files, get_selected_folder(), NULL); + } } void set_item_to_folder(QTreeWidgetItem* item) { @@ -435,9 +542,35 @@ void Project::delete_media(QTreeWidgetItem* item) { Sequence* s = get_sequence_from_tree(item); delete s; break; - } + } +} - project_changed = true; +void Project::delete_clips_using_selected_media() { + if (sequence == NULL) { + QMessageBox::critical(this, "No active sequence", "No sequence is active, please open the sequence you want to delete clips from.", QMessageBox::Ok); + } else { + TimelineAction* ta = new TimelineAction(); + bool deleted = false; + for (int i=0;iclip_count();i++) { + Clip* c = sequence->get_clip(i); + if (c != NULL) { + QList items = source_table->selectedItems(); + for (int j=0;jmedia == m) { + ta->delete_clip(sequence, i); + deleted = true; + } + } + } + } + if (deleted) { + undo_stack.push(ta); + panel_timeline->redraw_all_clips(true); + } else { + delete ta; + } + } } void Project::clear() { @@ -516,7 +649,7 @@ bool Project::load_worker(QFile& f, QXmlStreamReader& stream, int type) { switch (type) { case MEDIA_TYPE_FOLDER: { - QTreeWidgetItem* folder = new_folder(); + QTreeWidgetItem* folder = new_folder(0); for (int j=0;jdata(0, Qt::UserRole + 4).toInt(); - if (parent > 0) { - ui->treeWidget->takeTopLevelItem(ui->treeWidget->indexOfTopLevelItem(folder)); + if (parent > 0) { find_loaded_folder_by_id(parent)->addChild(folder); - } + } else { + ui->treeWidget->addTopLevelItem(folder); + } } cont = load_worker(file, stream, MEDIA_TYPE_FOOTAGE); diff --git a/panels/project.h b/panels/project.h index 8d4d202fb..7194d03b2 100644 --- a/panels/project.h +++ b/panels/project.h @@ -51,17 +51,19 @@ public: ~Project(); bool is_focused(); void clear(); - QTreeWidgetItem* import_file(QString url, QString imported_filename); + void import_file(QTreeWidgetItem* item, Media* m, QString url, QString imported_filename); void new_sequence(TimelineAction* ta, Sequence* s, bool open, QTreeWidgetItem* parent); QString get_next_sequence_name(); void delete_media(QTreeWidgetItem* item); - void process_file_list(QStringList& files); + void process_file_list(bool recursive, QStringList& files, QTreeWidgetItem *parent, QTreeWidgetItem* replace); + void replace_media(QTreeWidgetItem* item, QString filename); + QTreeWidgetItem* get_selected_folder(); void new_project(); void load_project(); void save_project(bool autorecovery); - QTreeWidgetItem* new_folder(); + QTreeWidgetItem* new_folder(QString name); void save_recent_projects(); @@ -69,9 +71,11 @@ public: SourceTable* source_table; public slots: - void import_dialog(); + void import_dialog(); void delete_selected_media(); void duplicate_selected(); + void delete_clips_using_selected_media(); + void replace_selected_file(); private: Ui::Project *ui; QTreeWidgetItem* new_item(); @@ -92,6 +96,7 @@ private: void get_media_from_table(QList items, QList& list, int type); void start_preview_generator(QTreeWidgetItem* item, Media* media); void list_all_sequences_worker(QVector* list, QTreeWidgetItem* parent); + QString get_file_name_from_path(const QString &path); private slots: void rename_media(QTreeWidgetItem* item, int column); void clear_recent_projects(); diff --git a/panels/timeline.cpp b/panels/timeline.cpp index c6c85e7ae..2e8be1ce2 100644 --- a/panels/timeline.cpp +++ b/panels/timeline.cpp @@ -264,8 +264,7 @@ void Timeline::repaint_timeline() { } void Timeline::redraw_all_clips(bool changed) { - if (changed) { - project_changed = true; + if (changed) { if (!playing) reset_all_audio(); panel_viewer->viewer_widget->update(); } diff --git a/playback/cacher.cpp b/playback/cacher.cpp index 4ac960e83..96fbb4e3c 100644 --- a/playback/cacher.cpp +++ b/playback/cacher.cpp @@ -182,7 +182,6 @@ void reset_cache(Clip* c, long target_frame) { // seeks to nearest keyframe (target_frame represents internal clip frame) av_seek_frame(c->formatCtx, ms->file_index, (int64_t) qFloor(clip_frame_to_seconds(c, target_frame) / timebase), AVSEEK_FLAG_BACKWARD); - qDebug() << target_frame; // play up to the frame we actually want long retrieved_frame = 0; diff --git a/playback/playback.cpp b/playback/playback.cpp index 578e6099c..9f29586a3 100644 --- a/playback/playback.cpp +++ b/playback/playback.cpp @@ -246,7 +246,7 @@ void retrieve_next_frame_raw_data(Clip* c, AVFrame* output) { } bool is_clip_active(Clip* c, long playhead) { - return c->timeline_in < playhead + ceil(c->sequence->frame_rate) && c->timeline_out > playhead && c->enabled; + return c->timeline_in < playhead + ceil(c->sequence->frame_rate) && c->timeline_out > playhead && c->enabled; } void set_sequence(Sequence* s) { diff --git a/project/undo.cpp b/project/undo.cpp index 35bbf7f16..9953572b5 100644 --- a/project/undo.cpp +++ b/project/undo.cpp @@ -31,7 +31,8 @@ TimelineAction::TimelineAction() : done(false), change_seq(false), ripple_enabled(false), - change_in_out(false) + change_in_out(false), + old_project_changed(project_changed) {} TimelineAction::~TimelineAction() { @@ -129,8 +130,9 @@ void TimelineAction::delete_clip(Sequence* s, int clip) { new_action(s, TA_DELETE, clip, 0, 0); } -void TimelineAction::add_media(QTreeWidgetItem* item) { +void TimelineAction::add_media(QTreeWidgetItem* item, QTreeWidgetItem *parent) { media_to_add.append(item); + media_to_add_parents.append(parent); } void TimelineAction::delete_media(QTreeWidgetItem* item) { @@ -242,20 +244,20 @@ void TimelineAction::undo() { } // delete added clips - if (clips_to_add.size() > 0) { - int delete_count = 0; - for (int i=0;idestroy_clip(added_indexes.at(i)-delete_count, true); - delete_count++; - } - } + int delete_count = 0; + for (int i=0;idestroy_clip(added_indexes.at(i)-delete_count, true); + delete_count++; + } // remove any added media - if (media_to_add.size() > 0) { - for (int i=0;isource_table->takeTopLevelItem(panel_project->source_table->indexOfTopLevelItem(media_to_add.at(i))); - } - } + for (int i=0;isource_table->takeTopLevelItem(panel_project->source_table->indexOfTopLevelItem(media_to_add.at(i))); + } else { + media_to_add_parents.at(i)->removeChild(media_to_add.at(i)); + } + } // un-change workarea if (change_in_out) { @@ -269,6 +271,8 @@ void TimelineAction::undo() { set_sequence(old_seq); } + project_changed = old_project_changed; + done = false; } @@ -411,34 +415,34 @@ void TimelineAction::redo() { } // delete media - if (deleted_media.size() > 0) { - for (int i=0;iparent()); + for (int i=0;iparent()); - // if we're deleting the open sequence, close it - if (get_type_from_tree(item) == MEDIA_TYPE_SEQUENCE && - get_sequence_from_tree(item) == sequence && - !change_seq) { - old_seq = sequence; - new_seq = NULL; - change_seq = true; - } + // if we're deleting the open sequence, close it + if (get_type_from_tree(item) == MEDIA_TYPE_SEQUENCE && + get_sequence_from_tree(item) == sequence && + !change_seq) { + old_seq = sequence; + new_seq = NULL; + change_seq = true; + } - if (item->parent() == NULL) { - panel_project->source_table->takeTopLevelItem(panel_project->source_table->indexOfTopLevelItem(item)); - } else { - item->parent()->removeChild(item); - } - } - } + if (item->parent() == NULL) { + panel_project->source_table->takeTopLevelItem(panel_project->source_table->indexOfTopLevelItem(item)); + } else { + item->parent()->removeChild(item); + } + } // add any new media - if (media_to_add.size() > 0) { - for (int i=0;isource_table->addTopLevelItem(media_to_add.at(i)); - } - } + for (int i=0;isource_table->addTopLevelItem(media_to_add.at(i)); + } else { + media_to_add_parents.at(i)->addChild(media_to_add.at(i)); + } + } // change sequence workarea if (change_in_out) { @@ -453,6 +457,8 @@ void TimelineAction::redo() { set_sequence(new_seq); } + project_changed = true; + done = true; } diff --git a/project/undo.h b/project/undo.h index b66fdf075..12deb4131 100644 --- a/project/undo.h +++ b/project/undo.h @@ -28,7 +28,7 @@ public: void set_track(Sequence* s, int clip, int value); void increase_track(Sequence* s, int clip, int value); void delete_clip(Sequence* s, int clip); - void add_media(QTreeWidgetItem* item); + void add_media(QTreeWidgetItem* item, QTreeWidgetItem* parent); void delete_media(QTreeWidgetItem* item); void ripple(Sequence* s, long point, long length); void ripple(Sequence* s, long point, long length, QVector &ignore); @@ -68,6 +68,7 @@ private: QVector deleted_media_parents; QVector media_to_add; + QVector media_to_add_parents; Sequence* ripple_sequence; bool ripple_enabled; @@ -87,6 +88,8 @@ private: void new_action(Sequence* s, int action, int clip, long old_val, long new_val); void offset_links(QVector& clips, int offset); + + bool old_project_changed; }; class LinkCommand : public QUndoCommand { diff --git a/ui/sourcetable.cpp b/ui/sourcetable.cpp index c1748a004..1f2b9436b 100644 --- a/ui/sourcetable.cpp +++ b/ui/sourcetable.cpp @@ -12,6 +12,8 @@ #include #include #include +#include +#include #include SourceTable::SourceTable(QWidget* parent) : QTreeWidget(parent) { @@ -35,23 +37,36 @@ void SourceTable::show_context_menu(const QPoint& pos) { if (selectedItems().size() == 1) { // replace footage if (get_type_from_tree(selectedItems().at(0)) == MEDIA_TYPE_FOOTAGE) { - menu.addAction("Replace/Relink Media"); + QAction* replace_action = menu.addAction("Replace/Relink Media"); + connect(replace_action, SIGNAL(triggered(bool)), panel_project, SLOT(replace_media())); } menu.addAction("Replace Clips Using This Media"); } // duplicate item bool all_sequences = true; + bool all_footage = true; for (int i=0;imimeData(); + QTreeWidgetItem* drop_item = itemAt(event->pos()); if (mimeData->hasUrls()) { // drag files in from outside QList urls = mimeData->urls(); - if (!urls.isEmpty()) { + if (!urls.isEmpty()) { QStringList paths; - for (int i=0;iprocess_file_list(paths); + bool replace = false; + if (urls.size() == 1 + && drop_item != NULL + && get_type_from_tree(drop_item) == MEDIA_TYPE_FOOTAGE + && !QFileInfo(paths.at(0)).isDir() + && QMessageBox::question(this, "Replace Media", "You dropped a file onto '" + drop_item->text(0) + "'. Would you like to replace it with the dropped file?", QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes) { + replace = true; + panel_project->replace_media(drop_item, paths.at(0)); + } + if (!replace) { + QTreeWidgetItem* parent = NULL; + if (drop_item != NULL && get_type_from_tree(drop_item) == MEDIA_TYPE_FOLDER) { + parent = drop_item; + } + panel_project->process_file_list(NULL, paths, parent, NULL); + } } event->acceptProposedAction(); } else { // dragging files within project QVector move_items; - QTreeWidgetItem* drop_item = itemAt(event->pos()); // if we dragged to the root OR dragged to a folder if (drop_item == NULL || (drop_item != NULL && get_type_from_tree(drop_item) == MEDIA_TYPE_FOLDER)) { QList selected_items = selectedItems(); diff --git a/ui/timelinewidget.cpp b/ui/timelinewidget.cpp index 8c4381b82..b03984b60 100644 --- a/ui/timelinewidget.cpp +++ b/ui/timelinewidget.cpp @@ -815,12 +815,12 @@ void TimelineWidget::update_ghosts(QPoint& mouse_pos) { validator = g.ghost_length + frame_diff; if (validator < 1) frame_diff += (1 - validator); - // prevent clip length exceeding media length - if (c->media_type == MEDIA_TYPE_SEQUENCE + // prevent clip length exceeding media length + if (c->media_type == MEDIA_TYPE_SEQUENCE || (c->media_type == MEDIA_TYPE_FOOTAGE && !static_cast(c->media)->get_stream_from_file_index(c->media_stream)->infinite_length)) { validator = g.old_clip_in + g.ghost_length + frame_diff; if (validator > g.media_length) frame_diff -= validator - g.media_length; - } + } } // ripple ops @@ -1433,30 +1433,22 @@ void TimelineWidget::redraw_clips() { } if (clip->media_type == MEDIA_TYPE_FOOTAGE) { + bool draw_checkerboard = false; + QRect checkerboard_rect = clip_rect; Media* m = static_cast(clip->media); MediaStream* ms = m->get_stream_from_file_index(clip->media_stream); if (ms == NULL) { - // draw "error lines" if media stream is missing - clip_painter.setPen(QPen(QColor(64, 64, 64), 2)); - int limit = clip_rect.width(); - int clip_height = clip_rect.bottom()-clip_rect.top(); - for (int j=-clip_height;j clip_rect.right()) { - lines_end_y -= (clip_rect.right() - lines_end_x); - lines_end_x = clip_rect.right(); - } - clip_painter.drawLine(lines_start_x, lines_start_y, lines_end_x, lines_end_y); - } + draw_checkerboard = true; } else if (ms->preview_done) { // draw thumbnail/waveform + long media_length = m->get_length_in_frames(clip->sequence->frame_rate); + int waveform_limit = qMin(clip_rect.width(), panel_timeline->getScreenPointFromFrame(media_length - clip->clip_in)); + + if (waveform_limit < clip_rect.width()) { + draw_checkerboard = true; + checkerboard_rect.setLeft(clip_rect.left() + waveform_limit); + } + if (clip->track < 0) { int thumb_y = clip_painter.fontMetrics().height()+CLIP_TEXT_PADDING+CLIP_TEXT_PADDING; int thumb_height = clip_rect.height()-thumb_y; @@ -1465,33 +1457,47 @@ void TimelineWidget::redraw_clips() { QRect thumb_rect(thumb_x, clip_rect.y()+thumb_y, thumb_width, thumb_height); clip_painter.drawImage(thumb_rect, ms->video_preview); } - } else if (clip_rect.height() > TRACK_MIN_HEIGHT) { + } else if (clip_rect.height() > TRACK_MIN_HEIGHT) { int divider = ms->audio_channels*2; clip_painter.setPen(QColor(80, 80, 80)); int channel_height = clip_rect.height()/ms->audio_channels; - long media_length = m->get_length_in_frames(clip->sequence->frame_rate); - for (int i=0;iclip_in + ((double) i/panel_timeline->zoom))/media_length) * ms->audio_preview.size())/divider)*divider; - for (int j=0;jaudio_channels;j++) { - int mid = clip_rect.top()+channel_height*j+(channel_height/2); - int offset = waveform_index+(j*2); + for (int j=0;jaudio_channels;j++) { + int mid = clip_rect.top()+channel_height*j+(channel_height/2); + int offset = waveform_index+(j*2); - qint8 min = (double)ms->audio_preview.at(offset) / 128.0 * (channel_height/2); - qint8 max = (double)ms->audio_preview.at(offset+1) / 128.0 * (channel_height/2); - clip_painter.drawLine(clip_rect.left()+i, mid+min, clip_rect.left()+i, mid+max); - - /*if (offset >= 0 && offset < ms->audio_preview.size()) { - - } else { - QMessageBox::critical(this, "AAAAAAAAAAAAA", "Here's that terrible, no-good bug again!!! I've stepped around it but plz report the following to Matt:\n\n" + QString::number(offset) + " vs " + QString::number(clip->media_stream->audio_preview.size()), QMessageBox::Ok); - break; - }*/ - } - } + qint8 min = (double)ms->audio_preview.at(offset) / 128.0 * (channel_height/2); + qint8 max = (double)ms->audio_preview.at(offset+1) / 128.0 * (channel_height/2); + clip_painter.drawLine(clip_rect.left()+i, mid+min, clip_rect.left()+i, mid+max); + } + } } } + if (draw_checkerboard) { + // draw "error lines" if media stream is missing + clip_painter.setPen(QPen(QColor(64, 64, 64), 2)); + int limit = checkerboard_rect.width(); + int clip_height = checkerboard_rect.bottom()-checkerboard_rect.top(); + for (int j=-clip_height;j checkerboard_rect.right()) { + lines_end_y -= (checkerboard_rect.right() - lines_end_x); + lines_end_x = checkerboard_rect.right(); + } + clip_painter.drawLine(lines_start_x, lines_start_y, lines_end_x, lines_end_y); + } + } } // top left bevel diff --git a/ui/viewerwidget.cpp b/ui/viewerwidget.cpp index 8058a96e5..59723471a 100644 --- a/ui/viewerwidget.cpp +++ b/ui/viewerwidget.cpp @@ -110,19 +110,22 @@ void ViewerWidget::compose_sequence(Clip* nest, bool render_audio) { case MEDIA_TYPE_FOOTAGE: { Media* m = static_cast(c->media); - if (m->ready - && m->get_stream_from_file_index(c->media_stream) != NULL - && is_clip_active(c, playhead)) { - // if thread is already working, we don't want to touch this, - // but we also don't want to hang the UI thread - if (!c->open) { - open_clip(c, multithreaded); - } + if (m->ready) { + if (m->get_stream_from_file_index(c->media_stream) != NULL + && is_clip_active(c, playhead)) { + // if thread is already working, we don't want to touch this, + // but we also don't want to hang the UI thread + if (!c->open) { + open_clip(c, multithreaded); + } - clip_is_active = true; - } else if (c->open) { - close_clip(c); - } + clip_is_active = true; + } else if (c->open) { + close_clip(c); + } + } else { + texture_failed = true; + } } break; case MEDIA_TYPE_SEQUENCE: