reimplemented optimized reversing and various improvements
This commit is contained in:
+44
-38
@@ -157,6 +157,9 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||
|
||||
connect(ui->action_Undo, SIGNAL(triggered(bool)), this, SLOT(undo()));
|
||||
connect(ui->action_Redo, SIGNAL(triggered(bool)), this, SLOT(redo()));
|
||||
connect(ui->actionCu_t, SIGNAL(triggered(bool)), this, SLOT(cut()));
|
||||
connect(ui->actionCop_y, SIGNAL(triggered(bool)), this, SLOT(copy()));
|
||||
connect(ui->action_Paste, SIGNAL(triggered(bool)), this, SLOT(paste()));
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow() {
|
||||
@@ -309,6 +312,24 @@ void MainWindow::openSpeedDialog() {
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::cut() {
|
||||
if (panel_timeline->focused() && sequence != NULL) {
|
||||
panel_timeline->copy(true);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::copy() {
|
||||
if (panel_timeline->focused() && sequence != NULL) {
|
||||
panel_timeline->copy(false);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::paste() {
|
||||
if (panel_timeline->focused() && sequence != NULL) {
|
||||
panel_timeline->paste();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::on_actionSplit_at_Playhead_triggered()
|
||||
{
|
||||
if (panel_timeline->focused()) {
|
||||
@@ -316,27 +337,6 @@ void MainWindow::on_actionSplit_at_Playhead_triggered()
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::on_actionCu_t_triggered()
|
||||
{
|
||||
if (panel_timeline->focused()) {
|
||||
panel_timeline->copy(true);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::on_actionCop_y_triggered()
|
||||
{
|
||||
if (panel_timeline->focused()) {
|
||||
panel_timeline->copy(false);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::on_action_Paste_triggered()
|
||||
{
|
||||
if (panel_timeline->focused()) {
|
||||
panel_timeline->paste();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::autorecover_interval() {
|
||||
if (isWindowModified()) {
|
||||
panel_project->save_project(true);
|
||||
@@ -456,37 +456,43 @@ void MainWindow::on_actionReset_to_default_layout_triggered()
|
||||
|
||||
void MainWindow::on_actionGo_to_start_triggered()
|
||||
{
|
||||
if (sequence != NULL && (panel_timeline->focused() || panel_sequence_viewer->is_focused() || panel_effect_controls->keyframe_focus())) {
|
||||
if (panel_timeline->focused() || panel_sequence_viewer->is_focused() || panel_effect_controls->keyframe_focus()) {
|
||||
panel_sequence_viewer->go_to_start();
|
||||
} else if (panel_footage_viewer->is_focused()) {
|
||||
panel_footage_viewer->go_to_start();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::on_actionPrevious_Frame_triggered()
|
||||
{
|
||||
if (sequence != NULL && (panel_timeline->focused() || panel_sequence_viewer->is_focused() || panel_effect_controls->keyframe_focus())) {
|
||||
void MainWindow::on_actionPrevious_Frame_triggered() {
|
||||
if (panel_timeline->focused() || panel_sequence_viewer->is_focused() || panel_effect_controls->keyframe_focus()) {
|
||||
panel_sequence_viewer->previous_frame();
|
||||
}
|
||||
} else if (panel_footage_viewer->is_focused()) {
|
||||
panel_footage_viewer->previous_frame();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::on_actionNext_Frame_triggered()
|
||||
{
|
||||
if (sequence != NULL && (panel_timeline->focused() || panel_sequence_viewer->is_focused() || panel_effect_controls->keyframe_focus())) {
|
||||
void MainWindow::on_actionNext_Frame_triggered() {
|
||||
if (panel_timeline->focused() || panel_sequence_viewer->is_focused() || panel_effect_controls->keyframe_focus()) {
|
||||
panel_sequence_viewer->next_frame();
|
||||
}
|
||||
} else if (panel_footage_viewer->is_focused()) {
|
||||
panel_footage_viewer->next_frame();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::on_actionGo_to_End_triggered()
|
||||
{
|
||||
if (sequence != NULL && (panel_timeline->focused() || panel_sequence_viewer->is_focused() || panel_effect_controls->keyframe_focus())) {
|
||||
void MainWindow::on_actionGo_to_End_triggered() {
|
||||
if (panel_timeline->focused() || panel_sequence_viewer->is_focused() || panel_effect_controls->keyframe_focus()) {
|
||||
panel_sequence_viewer->go_to_end();
|
||||
}
|
||||
} else if (panel_footage_viewer->is_focused()) {
|
||||
panel_footage_viewer->go_to_end();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::on_actionPlay_Pause_triggered()
|
||||
{
|
||||
if (sequence != NULL && (panel_timeline->focused() || panel_sequence_viewer->is_focused() || panel_effect_controls->keyframe_focus())) {
|
||||
void MainWindow::on_actionPlay_Pause_triggered() {
|
||||
if (panel_timeline->focused() || panel_sequence_viewer->is_focused() || panel_effect_controls->keyframe_focus()) {
|
||||
panel_sequence_viewer->toggle_play();
|
||||
}
|
||||
} else if (panel_footage_viewer->is_focused()) {
|
||||
panel_footage_viewer->toggle_play();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::on_actionEdit_Tool_triggered()
|
||||
|
||||
+4
-7
@@ -26,6 +26,9 @@ public slots:
|
||||
void undo();
|
||||
void redo();
|
||||
void openSpeedDialog();
|
||||
void cut();
|
||||
void copy();
|
||||
void paste();
|
||||
|
||||
protected:
|
||||
void closeEvent(QCloseEvent *);
|
||||
@@ -60,13 +63,7 @@ private slots:
|
||||
|
||||
void on_actionRipple_Delete_triggered();
|
||||
|
||||
void on_actionSplit_at_Playhead_triggered();
|
||||
|
||||
void on_actionCu_t_triggered();
|
||||
|
||||
void on_actionCop_y_triggered();
|
||||
|
||||
void on_action_Paste_triggered();
|
||||
void on_actionSplit_at_Playhead_triggered();
|
||||
|
||||
void on_action_Save_Project_triggered();
|
||||
|
||||
|
||||
+38
-20
@@ -29,7 +29,8 @@ Viewer::Viewer(QWidget *parent) :
|
||||
ui(new Ui::Viewer),
|
||||
seq(NULL),
|
||||
playing(false),
|
||||
created_sequence(false)
|
||||
created_sequence(false),
|
||||
disable_viewer(false)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->headers->viewer = this;
|
||||
@@ -162,15 +163,31 @@ void Viewer::seek(long p) {
|
||||
}
|
||||
|
||||
void Viewer::go_to_start() {
|
||||
seek(0);
|
||||
if (seq != NULL) {
|
||||
if (seq->using_workarea && seq->playhead != seq->workarea_in) {
|
||||
seek(seq->workarea_in);
|
||||
} else {
|
||||
seek(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Viewer::previous_frame() {
|
||||
if (seq->playhead > 0) seek(seq->playhead-1);
|
||||
if (seq != NULL && seq->playhead > 0) seek(seq->playhead-1);
|
||||
}
|
||||
|
||||
void Viewer::next_frame() {
|
||||
seek(seq->playhead+1);
|
||||
if (seq != NULL) seek(seq->playhead+1);
|
||||
}
|
||||
|
||||
void Viewer::go_to_end() {
|
||||
if (seq != NULL) {
|
||||
if (seq->using_workarea && seq->playhead != seq->workarea_out) {
|
||||
seek(seq->workarea_out);
|
||||
} else {
|
||||
seek(seq->getEndFrame());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Viewer::toggle_play() {
|
||||
@@ -182,17 +199,19 @@ void Viewer::toggle_play() {
|
||||
}
|
||||
|
||||
void Viewer::play() {
|
||||
if (audio_output->format().sampleRate() != seq->audio_frequency
|
||||
|| audio_output->format().channelCount() != av_get_channel_layout_nb_channels(seq->audio_layout)) {
|
||||
init_audio(seq);
|
||||
if (seq != NULL) {
|
||||
if (audio_output->format().sampleRate() != seq->audio_frequency
|
||||
|| audio_output->format().channelCount() != av_get_channel_layout_nb_channels(seq->audio_layout)) {
|
||||
init_audio(seq);
|
||||
}
|
||||
reset_all_audio();
|
||||
playhead_start = seq->playhead;
|
||||
start_msecs = QDateTime::currentMSecsSinceEpoch();
|
||||
playback_updater.start();
|
||||
playing = true;
|
||||
set_playpause_icon(false);
|
||||
audio_thread->notifyReceiver();
|
||||
}
|
||||
reset_all_audio();
|
||||
playhead_start = seq->playhead;
|
||||
start_msecs = QDateTime::currentMSecsSinceEpoch();
|
||||
playback_updater.start();
|
||||
playing = true;
|
||||
set_playpause_icon(false);
|
||||
audio_thread->notifyReceiver();
|
||||
}
|
||||
|
||||
void Viewer::pause() {
|
||||
@@ -201,10 +220,6 @@ void Viewer::pause() {
|
||||
playback_updater.stop();
|
||||
}
|
||||
|
||||
void Viewer::go_to_end() {
|
||||
seek(seq->getEndFrame());
|
||||
}
|
||||
|
||||
void Viewer::update_playhead_timecode(long p) {
|
||||
ui->currentTimecode->set_value(p, false);
|
||||
}
|
||||
@@ -287,6 +302,7 @@ void Viewer::set_media(int type, void* media) {
|
||||
seq->width = 1920;
|
||||
seq->height = 1080;
|
||||
seq->frame_rate = 30;
|
||||
disable_viewer = true;
|
||||
}
|
||||
|
||||
if (footage->audio_tracks.size() > 0) {
|
||||
@@ -348,6 +364,8 @@ void Viewer::timer_update() {
|
||||
}
|
||||
|
||||
void Viewer::clean_created_seq() {
|
||||
disable_viewer = false;
|
||||
|
||||
if (created_sequence) {
|
||||
// TODO delete undo commands referencing this sequence to avoid crashes
|
||||
/*for (int i=0;i<undo_stack.count();i++) {
|
||||
@@ -370,8 +388,8 @@ void Viewer::set_sequence(bool main, Sequence *s) {
|
||||
|
||||
ui->headers->setEnabled(!null_sequence);
|
||||
ui->currentTimecode->setEnabled(!null_sequence);
|
||||
ui->openGLWidget->setEnabled(!null_sequence);
|
||||
ui->openGLWidget->setVisible(!null_sequence);
|
||||
ui->openGLWidget->setEnabled(!null_sequence && !disable_viewer);
|
||||
ui->openGLWidget->setVisible(!null_sequence && !disable_viewer);
|
||||
ui->pushButton->setEnabled(!null_sequence);
|
||||
ui->pushButton_2->setEnabled(!null_sequence);
|
||||
ui->pushButton_3->setEnabled(!null_sequence);
|
||||
|
||||
@@ -74,6 +74,7 @@ private:
|
||||
void set_sequence(bool main, Sequence* s);
|
||||
bool main_sequence;
|
||||
bool created_sequence;
|
||||
bool disable_viewer;
|
||||
};
|
||||
|
||||
#endif // VIEWER_H
|
||||
|
||||
+64
-69
@@ -71,8 +71,6 @@ void apply_audio_effects(Clip* c, double timecode_start, AVFrame* frame, int nb_
|
||||
}
|
||||
|
||||
void cache_audio_worker(Clip* c, Clip* nest) {
|
||||
qDebug() << "caw called";
|
||||
|
||||
long timeline_in = c->timeline_in;
|
||||
long timeline_out = c->timeline_out;
|
||||
if (nest != NULL) {
|
||||
@@ -358,39 +356,71 @@ void cache_audio_worker(Clip* c, Clip* nest) {
|
||||
|
||||
void cache_video_worker(Clip* c) {
|
||||
int read_ret, send_ret, retr_ret;
|
||||
while (c->queue.size() < c->max_queue_size) {
|
||||
AVFrame* frame = av_frame_alloc();
|
||||
|
||||
// SKIP TYPE SEEK
|
||||
// SKIP TYPE SEEK
|
||||
|
||||
while ((retr_ret = av_buffersink_get_frame(c->buffersink_ctx, frame)) == AVERROR(EAGAIN)) {
|
||||
AVFrame* send_frame = c->frame;
|
||||
read_ret = (c->use_existing_frame) ? 0 : retrieve_next_frame(c, send_frame);
|
||||
c->use_existing_frame = false;
|
||||
if (read_ret >= 0 || read_ret == AVERROR_EOF) {
|
||||
if (read_ret == AVERROR_EOF) send_frame = NULL;
|
||||
if ((send_ret = av_buffersrc_add_frame_flags(c->buffersrc_ctx, send_frame, AV_BUFFERSRC_FLAG_KEEP_REF)) < 0) {
|
||||
qDebug() << "[ERROR] Failed to add frame to buffer source." << send_ret;
|
||||
break;
|
||||
}
|
||||
if (read_ret >= 0) {
|
||||
av_frame_unref(c->frame);
|
||||
}
|
||||
} else {
|
||||
qDebug() << "[ERROR] Failed to read frame." << read_ret;
|
||||
break;
|
||||
int limit = c->max_queue_size;
|
||||
if (c->reverse) limit *= 2;
|
||||
|
||||
if (c->queue.size() < limit) {
|
||||
int64_t smallest_pts = INT64_MAX;
|
||||
if (c->reverse && c->queue.size() > 0) {
|
||||
int64_t quarter_sec = qRound(av_q2d(av_inv_q(c->stream->time_base))) >> 2;
|
||||
for (int i=0;i<c->queue.size();i++) {
|
||||
smallest_pts = qMin(smallest_pts, c->queue.at(i)->pts);
|
||||
}
|
||||
avcodec_flush_buffers(c->codecCtx);
|
||||
av_seek_frame(c->formatCtx, c->stream->index, qMax(static_cast<int64_t>(0), smallest_pts - quarter_sec), AVSEEK_FLAG_BACKWARD);
|
||||
} else {
|
||||
smallest_pts = seconds_to_timestamp(c, playhead_to_clip_seconds(c, c->cacher->playhead));
|
||||
}
|
||||
|
||||
if (retr_ret < 0) {
|
||||
if (retr_ret != AVERROR_EOF) qDebug() << "[ERROR] Failed to retrieve frame from buffersink." << retr_ret;
|
||||
av_frame_free(&frame);
|
||||
break;
|
||||
} else {
|
||||
// thread-safety while adding frame to the queue
|
||||
c->queue_lock.lock();
|
||||
c->queue.append(frame);
|
||||
c->queue_lock.unlock();
|
||||
while (true) {
|
||||
AVFrame* frame = av_frame_alloc();
|
||||
|
||||
while ((retr_ret = av_buffersink_get_frame(c->buffersink_ctx, frame)) == AVERROR(EAGAIN)) {
|
||||
AVFrame* send_frame = c->frame;
|
||||
read_ret = (c->use_existing_frame) ? 0 : retrieve_next_frame(c, send_frame);
|
||||
c->use_existing_frame = false;
|
||||
if (read_ret >= 0) {
|
||||
/*if (read_ret == AVERROR_EOF) send_frame = NULL;
|
||||
if ((send_ret = av_buffersrc_add_frame_flags(c->buffersrc_ctx, send_frame, AV_BUFFERSRC_FLAG_KEEP_REF)) < 0) {
|
||||
qDebug() << "[ERROR] Failed to add frame to buffer source." << send_ret;
|
||||
break;
|
||||
}
|
||||
if (read_ret >= 0) {
|
||||
av_frame_unref(c->frame);
|
||||
}*/
|
||||
if ((send_ret = av_buffersrc_add_frame_flags(c->buffersrc_ctx, send_frame, AV_BUFFERSRC_FLAG_KEEP_REF)) < 0) {
|
||||
qDebug() << "[ERROR] Failed to add frame to buffer source." << send_ret;
|
||||
break;
|
||||
}
|
||||
av_frame_unref(c->frame);
|
||||
} else {
|
||||
if (read_ret != AVERROR_EOF) qDebug() << "[ERROR] Failed to read frame." << read_ret;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (retr_ret < 0) {
|
||||
if (retr_ret != AVERROR_EOF) qDebug() << "[ERROR] Failed to retrieve frame from buffersink." << retr_ret;
|
||||
av_frame_free(&frame);
|
||||
break;
|
||||
} else {
|
||||
if (c->reverse && smallest_pts != INT64_MAX && frame->pts >= smallest_pts) {
|
||||
av_frame_free(&frame);
|
||||
break;
|
||||
} else {
|
||||
// thread-safety while adding frame to the queue
|
||||
c->queue_lock.lock();
|
||||
c->queue.append(frame);
|
||||
c->queue_lock.unlock();
|
||||
|
||||
qDebug() << "appended" << frame->pts << "/ min:" << smallest_pts;
|
||||
|
||||
if ((!c->reverse || smallest_pts == INT64_MAX) && c->queue.size() == limit) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -409,10 +439,10 @@ void reset_cache(Clip* c, long target_frame) {
|
||||
|
||||
// seeks to nearest keyframe (target_frame represents internal clip frame)
|
||||
int64_t target_ts = seconds_to_timestamp(c, playhead_to_clip_seconds(c, target_frame));
|
||||
// if (ms->video_interlacing != VIDEO_PROGRESSIVE) target_ts *= 2;
|
||||
int64_t seek_ts = target_ts;
|
||||
|
||||
int64_t timebase_half_second = qRound(av_q2d(av_inv_q(c->stream->time_base)));
|
||||
if (c->reverse) seek_ts -= timebase_half_second;
|
||||
|
||||
while (true) {
|
||||
// flush ffmpeg codecs
|
||||
avcodec_flush_buffers(c->codecCtx);
|
||||
@@ -420,23 +450,6 @@ void reset_cache(Clip* c, long target_frame) {
|
||||
if (seek_ts > 0) {
|
||||
av_seek_frame(c->formatCtx, ms->file_index, seek_ts, AVSEEK_FLAG_BACKWARD);
|
||||
|
||||
// play up to the frame we actually want
|
||||
/*int ret;
|
||||
do {
|
||||
av_frame_unref(c->frame);
|
||||
ret = retrieve_next_frame(c, c->frame);
|
||||
if (ret < 0) {
|
||||
qDebug() << "[WARNING] Seeking terminated prematurely";
|
||||
break;
|
||||
}
|
||||
qDebug() << "ret pts:" << c->frame->pts << "dur:" << c->frame->pkt_duration << "target:" << target_ts;
|
||||
} while (c->frame->pts + c->frame->pkt_duration + c->frame->pkt_duration < target_ts);
|
||||
if (c->frame->pts <= target_ts) {
|
||||
c->use_existing_frame = true;
|
||||
break;
|
||||
} else {
|
||||
seek_ts -= timebase_second;
|
||||
}*/
|
||||
av_frame_unref(c->frame);
|
||||
int ret = retrieve_next_frame(c, c->frame);
|
||||
if (ret < 0) {
|
||||
@@ -523,7 +536,7 @@ void open_clip_worker(Clip* clip) {
|
||||
clip->codecCtx = avcodec_alloc_context3(clip->codec);
|
||||
avcodec_parameters_to_context(clip->codecCtx, clip->stream->codecpar);
|
||||
|
||||
clip->max_queue_size = 30;
|
||||
clip->max_queue_size = (ms->infinite_length) ? 1 : 15;
|
||||
|
||||
AVDictionary* opts = NULL;
|
||||
|
||||
@@ -604,26 +617,8 @@ void open_clip_worker(Clip* clip) {
|
||||
|
||||
avfilter_graph_config(clip->filter_graph, NULL);
|
||||
} else if (clip->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
|
||||
// if FFmpeg can't pick up the channel layout (usually WAV), assume
|
||||
// based on channel count (doesn't support surround sound sources yet)
|
||||
if (clip->codecCtx->channel_layout == 0) clip->codecCtx->channel_layout = av_get_default_channel_layout(clip->stream->codecpar->channels);
|
||||
|
||||
// init resampling context
|
||||
/*
|
||||
clip->swr_ctx = swr_alloc_set_opts(
|
||||
NULL,
|
||||
sequence->audio_layout,
|
||||
static_cast<AVSampleFormat>(sample_format),
|
||||
sequence->audio_frequency / clip->speed,
|
||||
clip->codecCtx->channel_layout,
|
||||
static_cast<AVSampleFormat>(clip->stream->codecpar->format),
|
||||
clip->stream->codecpar->sample_rate,
|
||||
0,
|
||||
NULL
|
||||
);
|
||||
swr_init(clip->swr_ctx);
|
||||
*/
|
||||
|
||||
// set up cache
|
||||
clip->queue.append(av_frame_alloc());
|
||||
if (clip->reverse) {
|
||||
@@ -713,7 +708,7 @@ void open_clip_worker(Clip* clip) {
|
||||
qDebug() << "[INFO] Clip opened on track" << clip->track;
|
||||
}
|
||||
|
||||
void cache_clip_worker(Clip* clip, long playhead, bool reset, Clip* nest) {
|
||||
void cache_clip_worker(Clip* clip, long playhead, bool reset, Clip* nest) {
|
||||
if (reset) {
|
||||
// note: for video, playhead is in "internal clip" frames - for audio, it's the timeline playhead
|
||||
reset_cache(clip, playhead);
|
||||
|
||||
+44
-58
@@ -115,69 +115,55 @@ void get_clip_frame(Clip* c, long playhead) {
|
||||
}
|
||||
AVFrame* target_frame = NULL;
|
||||
|
||||
// qDebug() << "target pts:" << target_pts;
|
||||
|
||||
bool reset = false;
|
||||
|
||||
/*while (c->queue.size() > 0) {
|
||||
if (c->queue.first()->pts == target_pts) {
|
||||
target_frame = c->queue.first();
|
||||
|
||||
qDebug() << "GCF ==> USE PRECISE";
|
||||
break;
|
||||
} else if (c->queue.size() > 1 && c->queue.at(1)->pts > target_pts) {
|
||||
// use this frame
|
||||
target_frame = c->queue.first();
|
||||
|
||||
qDebug() << "GCF ==> USE IMPRECISE";
|
||||
break;
|
||||
} else {
|
||||
|
||||
break;
|
||||
} else {
|
||||
// skip this frame
|
||||
c->queue_mutex.lock(); // thread safety when removing from queue
|
||||
av_frame_free(&c->queue.first()); // may be a little heavy for the UI thread?
|
||||
c->queue.removeFirst();
|
||||
c->queue_mutex.unlock();
|
||||
qDebug() << "GCF ==> SKIP";
|
||||
}
|
||||
}*/
|
||||
qDebug() << "QS:" << c->queue.size();
|
||||
|
||||
if (c->queue.size() > 0) {
|
||||
// correct frame may be somewhere else in the queue
|
||||
int closest_frame = 0;
|
||||
for (int i=1;i<c->queue.size();i++) {
|
||||
if (c->queue.at(i)->pts == target_pts) {
|
||||
qDebug() << "GCF ==> USE PRECISE";
|
||||
closest_frame = i;
|
||||
break;
|
||||
} else if (c->queue.at(i)->pts > c->queue.at(closest_frame)->pts && c->queue.at(i)->pts < target_pts) {
|
||||
closest_frame = i;
|
||||
}
|
||||
}
|
||||
|
||||
// remove all frames earlier than this one from the queue
|
||||
target_frame = c->queue.at(closest_frame);
|
||||
c->queue_lock.lock();
|
||||
for (int i=0;i<c->queue.size();i++) {
|
||||
if (c->queue.at(i)->pts < target_frame->pts) {
|
||||
av_frame_free(&c->queue[i]); // may be a little heavy for the UI thread?
|
||||
c->queue.removeAt(i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
c->queue_lock.unlock();
|
||||
|
||||
// if this frame is more than one second out, we probably need to reset
|
||||
if (qAbs(target_pts - target_frame->pts) > second_pts) {
|
||||
target_frame = NULL;
|
||||
// qDebug() << "GCF ==> COMPLACENT";
|
||||
qDebug() << "GCF ==> RESET";
|
||||
reset = true;
|
||||
if (ms->infinite_length) {
|
||||
target_frame = c->queue.at(0);
|
||||
qDebug() << "GCF ==> USE PRECISE (INFINITE)";
|
||||
} else {
|
||||
qDebug() << "GCF ==> USE IMPRECISE";
|
||||
// correct frame may be somewhere else in the queue
|
||||
int closest_frame = 0;
|
||||
for (int i=1;i<c->queue.size();i++) {
|
||||
if (c->queue.at(i)->pts == target_pts) {
|
||||
qDebug() << "GCF ==> USE PRECISE";
|
||||
closest_frame = i;
|
||||
break;
|
||||
} else if (c->queue.at(i)->pts > c->queue.at(closest_frame)->pts && c->queue.at(i)->pts < target_pts) {
|
||||
closest_frame = i;
|
||||
}
|
||||
}
|
||||
|
||||
// remove all frames earlier than this one from the queue
|
||||
target_frame = c->queue.at(closest_frame);
|
||||
c->queue_lock.lock();
|
||||
for (int i=0;i<c->queue.size();i++) {
|
||||
if (c->queue.at(i)->pts != target_frame->pts) {
|
||||
if ((c->queue.at(i)->pts < target_frame->pts) == (!c->reverse)) {
|
||||
qDebug() << "removed frame whose pts was" << c->queue.at(i)->pts << "compared to target" << target_frame->pts;
|
||||
|
||||
av_frame_free(&c->queue[i]); // may be a little heavy for the UI thread?
|
||||
c->queue.removeAt(i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
c->queue_lock.unlock();
|
||||
|
||||
// if this frame is more than one second out, we probably need to reset
|
||||
if (qAbs(target_pts - target_frame->pts) > second_pts) {
|
||||
target_frame = NULL;
|
||||
// qDebug() << "GCF ==> COMPLACENT";
|
||||
qDebug() << "GCF ==> RESET";
|
||||
reset = true;
|
||||
} else {
|
||||
qDebug() << "GCF ==> USE IMPRECISE";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
reset = true;
|
||||
}
|
||||
|
||||
// get more frames
|
||||
@@ -186,7 +172,7 @@ void get_clip_frame(Clip* c, long playhead) {
|
||||
if (target_frame == NULL || reset) {
|
||||
// reset cache
|
||||
texture_failed = true;
|
||||
qDebug() << "[INFO] Cache couldn't keep up - either the user seeked or the system is overloaded";
|
||||
qDebug() << "[INFO] Frame queue couldn't keep up - either the user seeked or the system is overloaded (queue size:" << c->queue.size() << ")";
|
||||
}
|
||||
|
||||
if (target_frame != NULL) {
|
||||
|
||||
@@ -320,7 +320,7 @@ void TimelineHeader::paintEvent(QPaintEvent*) {
|
||||
// draw sub-line markers
|
||||
for (int j=1;j<sublineCount;j++) {
|
||||
int sublineX = lineX+(qRound(j*interval/sublineCount)*zoom);
|
||||
p.drawLine(sublineX, yoff, sublineX, yoff+(yoff>>1));
|
||||
p.drawLine(sublineX, yoff, sublineX, yoff+(height()/4));
|
||||
}
|
||||
}
|
||||
i++;
|
||||
|
||||
@@ -133,8 +133,11 @@ void TimelineWidget::show_context_menu(const QPoint& pos) {
|
||||
menu.addAction("Sequence settings coming soon...");
|
||||
} else {
|
||||
QAction* cutAction = menu.addAction("C&ut");
|
||||
connect(cutAction, SIGNAL(triggered(bool)), mainWindow, SLOT(cut()));
|
||||
QAction* copyAction = menu.addAction("Cop&y");
|
||||
connect(copyAction, SIGNAL(triggered(bool)), mainWindow, SLOT(copy()));
|
||||
QAction* pasteAction = menu.addAction("&Paste");
|
||||
connect(pasteAction, SIGNAL(triggered(bool)), mainWindow, SLOT(paste()));
|
||||
menu.addSeparator();
|
||||
QAction* speedAction = menu.addAction("&Speed/Duration");
|
||||
connect(speedAction, SIGNAL(triggered(bool)), mainWindow, SLOT(openSpeedDialog()));
|
||||
|
||||
Reference in New Issue
Block a user