From e3422949170e5a65f8027d04206ba534804a9e73 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Mon, 5 Nov 2018 17:59:29 +1100 Subject: [PATCH] fixed urgent bug that irreparably deleted sequences --- io/previewgenerator.cpp | 31 ++++++++++++++------------- mainwindow.cpp | 15 +++++++++---- mainwindow.h | 4 ++++ mainwindow.ui | 18 ++++++++++++++++ panels/project.cpp | 4 +++- panels/timeline.cpp | 47 +++++++++++++++++++++++++++++------------ panels/timeline.h | 2 +- panels/viewer.cpp | 7 +++++- playback/cacher.cpp | 16 ++++++-------- project/clip.cpp | 7 +++--- project/undo.cpp | 2 +- ui/timelinewidget.cpp | 7 ++---- 12 files changed, 104 insertions(+), 56 deletions(-) diff --git a/io/previewgenerator.cpp b/io/previewgenerator.cpp index 91e328a8a..4432e2050 100644 --- a/io/previewgenerator.cpp +++ b/io/previewgenerator.cpp @@ -203,26 +203,26 @@ void PreviewGenerator::generate_waveform() { } } } - AVPacket packet; + AVPacket* packet = av_packet_alloc(); 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); + 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); + 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) dout << "[ERROR] Failed to read packet for preview generation" << read_ret; break; } - if (codec_ctx[packet.stream_index] != NULL) { - int send_ret = avcodec_send_packet(codec_ctx[packet.stream_index], &packet); + if (codec_ctx[packet->stream_index] != NULL) { + int send_ret = avcodec_send_packet(codec_ctx[packet->stream_index], packet); if (send_ret < 0 && send_ret != AVERROR(EAGAIN)) { dout << "[ERROR] Failed to send packet for preview generation - aborting" << send_ret; end_of_file = true; @@ -231,9 +231,9 @@ void PreviewGenerator::generate_waveform() { } } if (!end_of_file) { - MediaStream* s = media->get_stream_from_file_index(fmt_ctx->streams[packet.stream_index]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO, packet.stream_index); + MediaStream* s = media->get_stream_from_file_index(fmt_ctx->streams[packet->stream_index]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO, packet->stream_index); if (s != NULL) { - if (fmt_ctx->streams[packet.stream_index]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { + if (fmt_ctx->streams[packet->stream_index]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { if (!s->preview_done) { int dstH = 120; int dstW = dstH * ((float)temp_frame->width/(float)temp_frame->height); @@ -267,12 +267,12 @@ void PreviewGenerator::generate_waveform() { sws_freeContext(sws_ctx); if (!retrieve_duration) { - avcodec_close(codec_ctx[packet.stream_index]); - codec_ctx[packet.stream_index] = NULL; + avcodec_close(codec_ctx[packet->stream_index]); + codec_ctx[packet->stream_index] = NULL; } } - media_lengths[packet.stream_index]++; - } else if (fmt_ctx->streams[packet.stream_index]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { + media_lengths[packet->stream_index]++; + } 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(); @@ -349,13 +349,14 @@ void PreviewGenerator::generate_waveform() { break; } } - av_packet_unref(&packet); + av_packet_unref(packet); } } for (int i=0;iaudio_tracks.size();i++) { media->audio_tracks.at(i)->preview_done = true; } av_frame_free(&temp_frame); + av_packet_free(&packet); for (unsigned int i=0;inb_streams;i++) { if (codec_ctx[i] != NULL) { avcodec_close(codec_ctx[i]); diff --git a/mainwindow.cpp b/mainwindow.cpp index f17059b91..0b19ee10a 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -729,13 +729,12 @@ void MainWindow::on_actionLink_Unlink_triggered() if (panel_timeline->focused()) panel_timeline->toggle_links(); } -void MainWindow::on_actionRipple_To_In_Point_triggered() -{ - if (panel_timeline->focused()) panel_timeline->ripple_to_in_point(true); +void MainWindow::on_actionRipple_To_In_Point_triggered() { + if (panel_timeline->focused()) panel_timeline->ripple_to_in_point(true, true); } void MainWindow::on_actionRipple_to_Out_Point_triggered() { - if (panel_timeline->focused()) panel_timeline->ripple_to_in_point(false); + if (panel_timeline->focused()) panel_timeline->ripple_to_in_point(false, true); } void MainWindow::on_actionSet_In_Point_triggered() { @@ -880,3 +879,11 @@ void MainWindow::on_actionAudio_Scrubbing_triggered() { void MainWindow::on_actionTransition_Tool_triggered() { if (panel_timeline->focused()) panel_timeline->ui->toolTransitionButton->click(); } + +void MainWindow::on_actionEdit_to_In_Point_triggered() { + if (panel_timeline->focused()) panel_timeline->ripple_to_in_point(true, false); +} + +void MainWindow::on_actionEdit_to_Out_Point_triggered() { + if (panel_timeline->focused()) panel_timeline->ripple_to_in_point(false, false); +} diff --git a/mainwindow.h b/mainwindow.h index d6e00f45b..efbe84c2c 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -193,6 +193,10 @@ private slots: void on_actionTransition_Tool_triggered(); + void on_actionEdit_to_In_Point_triggered(); + + void on_actionEdit_to_Out_Point_triggered(); + private: Ui::MainWindow *ui; void setup_layout(); diff --git a/mainwindow.ui b/mainwindow.ui index de637c292..c52fd9677 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -87,6 +87,8 @@ + + @@ -824,6 +826,22 @@ T + + + Edit to In Point + + + Ctrl+Alt+Q + + + + + Edit to Out Point + + + Ctrl+Alt+W + + diff --git a/panels/project.cpp b/panels/project.cpp index 41114e251..29203f305 100644 --- a/panels/project.cpp +++ b/panels/project.cpp @@ -416,14 +416,16 @@ void Project::process_file_list(bool recursive, QStringList& files, QTreeWidgetI } imported = true; - } else { + } else if (!files.at(i).isEmpty()) { QString file(files.at(i)); bool skip = false; /* Heuristic to determine whether file is part of an image sequence */ // check file extension (assume it's not a + int lastcharindex = file.lastIndexOf("."); + dout << "INFO:" << file << lastcharindex; bool found = true; if (lastcharindex != -1 && lastcharindex > file.lastIndexOf('/')) { // image_sequence_formats diff --git a/panels/timeline.cpp b/panels/timeline.cpp index 3d28829e0..9cea7bcf7 100644 --- a/panels/timeline.cpp +++ b/panels/timeline.cpp @@ -702,7 +702,7 @@ void Timeline::paste() { } } -void Timeline::ripple_to_in_point(bool in) { +void Timeline::ripple_to_in_point(bool in, bool ripple) { if (sequence != NULL) { // get track count int track_min = 0; @@ -736,29 +736,48 @@ void Timeline::ripple_to_in_point(bool in) { } } - if (one_frame_mode) { + QVector areas; + ComboAction* ca = new ComboAction(); + if (one_frame_mode) { + // set up deletion areas based on track count + if (in) { + in_point = sequence->playhead; + } else { + in_point = sequence->playhead - 1; + } + + for (int i=track_min;i<=track_max;i++) { + Selection s; + s.in = in_point; + s.out = in_point + 1; + s.track = i; + areas.append(s); + } + + // trim and move clips around the in point + delete_areas_and_relink(ca, areas); + if (ripple) ca->append(new RippleCommand(sequence, in_point, -1)); } else { - // set up deletion areas based on track count - QVector areas; + // set up deletion areas based on track count for (int i=track_min;i<=track_max;i++) { Selection s; s.in = qMin(in_point, sequence->playhead); s.out = qMax(in_point, sequence->playhead); s.track = i; areas.append(s); - } + } - // trim and move clips around the in point - ComboAction* ca = new ComboAction(); - delete_areas_and_relink(ca, areas); - ca->append(new RippleCommand(sequence, in_point, (in) ? (in_point - sequence->playhead) : (sequence->playhead - in_point))); - undo_stack.push(ca); - - update_ui(true); - - if (in) panel_sequence_viewer->seek(in_point); + // trim and move clips around the in point + delete_areas_and_relink(ca, areas); + if (ripple) ca->append(new RippleCommand(sequence, in_point, (in) ? (in_point - sequence->playhead) : (sequence->playhead - in_point))); } + + undo_stack.push(ca); + + update_ui(true); + + if (in_point < sequence->playhead && ripple) panel_sequence_viewer->seek(in_point); } } diff --git a/panels/timeline.h b/panels/timeline.h index bd8ed3ba6..9e11bd2d6 100644 --- a/panels/timeline.h +++ b/panels/timeline.h @@ -92,7 +92,7 @@ public: QVector get_tracks_of_linked_clips(int i); bool has_clip_been_split(int c); void toggle_links(); - void ripple_to_in_point(bool in); + void ripple_to_in_point(bool in, bool ripple); void delete_in_out(bool ripple); void previous_cut(); void next_cut(); diff --git a/panels/viewer.cpp b/panels/viewer.cpp index 7e6e5df58..dadbb17a9 100644 --- a/panels/viewer.cpp +++ b/panels/viewer.cpp @@ -311,11 +311,14 @@ void Viewer::pause() { // add it to the sequence Clip* c = new Clip(seq); Media* m = panel_project->last_imported_media.at(0); + + m->ready_lock.lock(); + c->media = m; // latest media c->media_type = MEDIA_TYPE_FOOTAGE; c->media_stream = 0; c->timeline_in = recording_start; - c->timeline_out = seq->playhead; + c->timeline_out = m->get_length_in_frames(seq->frame_rate); c->clip_in = 0; c->track = recording_track; c->color_r = 128; @@ -323,6 +326,8 @@ void Viewer::pause() { c->color_b = 128; c->name = m->name; + m->ready_lock.unlock(); + QVector add_clips; add_clips.append(c); undo_stack.push(new AddClipCommand(seq, add_clips)); // add clip diff --git a/playback/cacher.cpp b/playback/cacher.cpp index 026a7146b..d8188bdb3 100644 --- a/playback/cacher.cpp +++ b/playback/cacher.cpp @@ -70,6 +70,8 @@ void apply_audio_effects(Clip* c, double timecode_start, AVFrame* frame, int nb_ } } +#define AUDIO_BUFFER_PADDING 2048 + void cache_audio_worker(Clip* c, bool scrubbing, Clip* nest) { long timeline_in = c->timeline_in; long timeline_out = c->timeline_out; @@ -270,7 +272,7 @@ void cache_audio_worker(Clip* c, bool scrubbing, Clip* nest) { #endif if (c->audio_buffer_write == 0) c->audio_buffer_write = get_buffer_offset_from_frame(c->sequence, qMax(timeline_in, c->audio_target_frame)); - int offset = (audio_ibuffer_read + 512) - c->audio_buffer_write; + int offset = (audio_ibuffer_read + AUDIO_BUFFER_PADDING) - c->audio_buffer_write; if (offset > 0) { c->audio_buffer_write += offset; c->frame_sample_index += offset; @@ -325,16 +327,8 @@ void cache_audio_worker(Clip* c, bool scrubbing, Clip* nest) { long buffer_timeline_out = get_buffer_offset_from_frame(c->sequence, timeline_out); audio_write_lock.lock(); while (c->frame_sample_index < nb_bytes - && c->audio_buffer_write < audio_ibuffer_read+audio_ibuffer_size-512 + && c->audio_buffer_write < audio_ibuffer_read+audio_ibuffer_size-AUDIO_BUFFER_PADDING && c->audio_buffer_write < buffer_timeline_out) { - - /*dout << "F (" << - c->frame_sample_index << "/" << nb_bytes - << ") (" << - c->audio_buffer_write << "/" << (audio_ibuffer_read+audio_ibuffer_size-512) - << ") (" << - c->audio_buffer_write << "/" << buffer_timeline_out << ")";*/ - int upper_byte_index = (c->audio_buffer_write+1)%audio_ibuffer_size; int lower_byte_index = (c->audio_buffer_write)%audio_ibuffer_size; qint16 old_sample = static_cast((audio_ibuffer[upper_byte_index] & 0xFF) << 8 | (audio_ibuffer[lower_byte_index] & 0xFF)); @@ -590,6 +584,7 @@ void open_clip_worker(Clip* clip) { char err[1024]; av_strerror(errCode, err, 1024); dout << "[ERROR] Could not open" << filename << "-" << err; + return; } errCode = avformat_find_stream_info(clip->formatCtx, NULL); @@ -597,6 +592,7 @@ void open_clip_worker(Clip* clip) { char err[1024]; av_strerror(errCode, err, 1024); dout << "[ERROR] Could not open" << filename << "-" << err; + return; } av_dump_format(clip->formatCtx, 0, filename, 0); diff --git a/project/clip.cpp b/project/clip.cpp index 6f1f49b1b..6dad0aaef 100644 --- a/project/clip.cpp +++ b/project/clip.cpp @@ -26,8 +26,7 @@ Clip::Clip(Sequence* s) : speed(1.0), media(NULL), opening_transition(NULL), - closing_transition(NULL), - pkt(new AVPacket()), + closing_transition(NULL), replaced(false), filter_graph(NULL), texture(NULL), @@ -38,6 +37,7 @@ Clip::Clip(Sequence* s) : use_existing_frame(false), ignore_reverse(false) { + pkt = av_packet_alloc(); reset(); } @@ -160,8 +160,7 @@ Clip::~Clip() { for (int i=0;isource_table->takeTopLevelItem(panel_project->source_table->indexOfTopLevelItem(item)); } else { parent->removeChild(item); diff --git a/ui/timelinewidget.cpp b/ui/timelinewidget.cpp index 362d22304..bae3ad872 100644 --- a/ui/timelinewidget.cpp +++ b/ui/timelinewidget.cpp @@ -493,10 +493,7 @@ void TimelineWidget::wheelEvent(QWheelEvent *event) { void TimelineWidget::dragLeaveEvent(QDragLeaveEvent*) { if (sequence != NULL && panel_timeline->importing) { if (panel_timeline->importing_files) { - for (int i=0;ilast_imported_media.size();i++) { - // hack? but seems to work - undo_stack.undo(); - } + undo_stack.undo(); } panel_timeline->ghosts.clear(); panel_timeline->importing = false; @@ -2391,7 +2388,7 @@ void TimelineWidget::paintEvent(QPaintEvent*) { if (clip_rect.bottom() >= 0 && clip_rect.bottom() < height()) p.drawLine(QPoint(qMax(0, clip_rect.left()), clip_rect.bottom()), QPoint(qMin(width(), clip_rect.right()), clip_rect.bottom())); // draw transition tool - if (panel_timeline->tool == TIMELINE_TOOL_TRANSITION && panel_timeline->transition_tool_clip > -1) { + if (panel_timeline->tool == TIMELINE_TOOL_TRANSITION && panel_timeline->transition_tool_clip == i) { QRect transition_tool_rect = clip_rect; if (panel_timeline->transition_tool_type == TA_CLOSING_TRANSITION) { transition_tool_rect.setLeft(transition_tool_rect.left() + (3*(transition_tool_rect.width()>>2)));