most of the interlacing is done

This commit is contained in:
itsmattkc
2018-10-11 19:59:57 +11:00
parent 55a44685a5
commit 5a082d2a28
8 changed files with 96 additions and 69 deletions
+13 -3
View File
@@ -467,19 +467,23 @@ EffectRow::EffectRow(Effect *parent, QGridLayout *uilayout, const QString &n, in
keyframe_enable->setCheckable(true);
keyframe_enable->setToolTip("Enable Keyframes");
connect(keyframe_enable, SIGNAL(clicked(bool)), this, SLOT(set_keyframe_enabled(bool)));
connect(keyframe_enable, SIGNAL(toggled(bool)), this, SLOT(keyframe_ui_enabled(bool)));
key_controls->addWidget(keyframe_enable);
QPushButton* left_key_nav = new QPushButton("<");
left_key_nav = new QPushButton("<");
left_key_nav->setVisible(false);
left_key_nav->setMaximumSize(button_size);
key_controls->addWidget(left_key_nav);
connect(left_key_nav, SIGNAL(clicked(bool)), this, SLOT(goto_previous_key()));
QPushButton* key_addremove = new QPushButton(".");
key_addremove = new QPushButton(".");
key_addremove->setVisible(false);
key_addremove->setMaximumSize(button_size);
key_controls->addWidget(key_addremove);
connect(key_addremove, SIGNAL(clicked(bool)), this, SLOT(toggle_key()));
QPushButton* right_key_nav = new QPushButton(">");
right_key_nav = new QPushButton(">");
right_key_nav->setVisible(false);
right_key_nav->setMaximumSize(button_size);
key_controls->addWidget(right_key_nav);
connect(right_key_nav, SIGNAL(clicked(bool)), this, SLOT(goto_next_key()));
@@ -515,6 +519,12 @@ void EffectRow::set_keyframe_enabled(bool enabled) {
}
}
void EffectRow::keyframe_ui_enabled(bool enabled) {
left_key_nav->setVisible(enabled);
key_addremove->setVisible(enabled);
right_key_nav->setVisible(enabled);
}
void EffectRow::goto_previous_key() {
long key = LONG_MIN;
Clip* c = parent_effect->parent_clip;
+4
View File
@@ -161,6 +161,7 @@ public:
QVector<int> keyframe_types;
private slots:
void set_keyframe_enabled(bool);
void keyframe_ui_enabled(bool);
void goto_previous_key();
void toggle_key();
void goto_next_key();
@@ -172,6 +173,9 @@ private:
QVector<EffectField*> fields;
QPushButton* keyframe_enable;
QPushButton* left_key_nav;
QPushButton* key_addremove;
QPushButton* right_key_nav;
bool just_made_unsafe_keyframe;
};
+2 -4
View File
@@ -9,7 +9,7 @@ Config config;
Config::Config()
: saved_layout(false),
show_track_lines(false),
show_track_lines(true),
scroll_zooms(false),
img_seq_formats("jpg|jpeg|bmp|tiff|tif|psd|png|tga|jp2|gif"),
edit_tool_selects_links(false),
@@ -24,9 +24,7 @@ Config::Config()
custom_title_safe_ratio(1),
enable_drag_files_to_timeline(false),
autoscale_by_default(false)
{
}
{}
void Config::load(QString path) {
QFile f(path);
+8 -1
View File
@@ -60,6 +60,7 @@ void PreviewGenerator::parse_media() {
}
ms->video_width = fmt_ctx->streams[i]->codecpar->width;
ms->video_height = fmt_ctx->streams[i]->codecpar->height;
ms->video_interlacing = VIDEO_PROGRESSIVE; // default value, we get the true value later in generate_waveform()
if (append) 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;
@@ -170,7 +171,13 @@ void PreviewGenerator::generate_waveform() {
s->video_preview = QImage(data, dstW, dstH, linesize[0], QImage::Format_RGB888);
// delete [] data;
// is video interlaced?
if (temp_frame->interlaced_frame) {
s->video_interlacing = (temp_frame->top_field_first) ? VIDEO_TOP_FIELD_FIRST : VIDEO_BOTTOM_FIELD_FIRST;
s->video_frame_rate *= 2;
} else {
s->video_interlacing = VIDEO_PROGRESSIVE;
}
s->preview_done = true;
+6 -5
View File
@@ -293,10 +293,12 @@ bool Timeline::focused() {
}
void Timeline::repaint_timeline(bool changed) {
if (playing) {
sequence->playhead = round(playhead_start + ((QDateTime::currentMSecsSinceEpoch()-start_msecs) * 0.001 * sequence->frame_rate));
} else if (changed) {
if (changed) {
reset_all_audio();
update_effect_controls();
if (!playing) panel_viewer->viewer_widget->update();
} else if (playing) {
sequence->playhead = round(playhead_start + ((QDateTime::currentMSecsSinceEpoch()-start_msecs) * 0.001 * sequence->frame_rate));
}
ui->headers->update();
@@ -304,8 +306,6 @@ void Timeline::repaint_timeline(bool changed) {
ui->audio_area->update();
panel_effect_controls->update_keyframes();
update_effect_controls();
if (sequence != NULL) {
panel_timeline->ui->horizontalScrollBar->setMaximum(qMax(0, getScreenPointFromFrame(panel_timeline->zoom, sequence->getEndFrame()) + 100 - ui->editAreas->width()));
@@ -318,6 +318,7 @@ void Timeline::repaint_timeline(bool changed) {
if (zoomChanged) {
zoomChanged = false;
int target_scroll = getScreenPointFromFrame(zoom, sequence->playhead)-(ui->editAreas->width()>>1);
// TODO find a way to gradually move towards target_scroll instead of just setting it?
ui->horizontalScrollBar->setValue(target_scroll);
}
+50 -36
View File
@@ -344,13 +344,7 @@ void cache_video_worker(Clip* c, long playhead, ClipCache* cache) {
i++;
}
}*/
if (!error) {
// setting the cache to written even if it hasn't reached_end prevents playback from
// signaling a seek/reset because it wasn't able to find the frame
cache->written = true;
cache->unread = true;
}
cache->unread = true;
/* new AVFilter solution */
if (!c->reached_end) {
@@ -392,6 +386,7 @@ void cache_video_worker(Clip* c, long playhead, ClipCache* cache) {
break;
}
} else {
cache->written = true;
i++;
cache->write_count = i;
}
@@ -400,6 +395,13 @@ void cache_video_worker(Clip* c, long playhead, ClipCache* cache) {
cache->write_count = i;
/*if (!error) {
// setting the cache to written even if it hasn't reached_end prevents playback from
// signaling a seek/reset because it wasn't able to find the frame
cache->written = true;
cache->unread = true;
}*/
cache->mutex.unlock();
}
@@ -415,26 +417,39 @@ void reset_cache(Clip* c, long target_frame) {
// flush ffmpeg codecs
avcodec_flush_buffers(c->codecCtx);
// flush filtergraph
/*while (av_buffersink_get_frame(c->buffersink_ctx, temp) >= 0) {
qDebug() << "flushed?";
av_frame_unref(temp);
}*/
double timebase = av_q2d(c->stream->time_base);
if (c->stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
// 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);
if (target_frame > 0) {
AVFrame* temp = av_frame_alloc();
// play up to the frame we actually want
long retrieved_frame = 0;
target_frame--;
AVFrame* temp = av_frame_alloc();
do {
retrieve_next_frame(c, temp);
if (retrieved_frame == 0) {
if (target_frame != -1) retrieved_frame = floor(temp->pts * timebase * av_q2d(c->stream->avg_frame_rate));
} else {
retrieved_frame++;
}
} while (retrieved_frame < target_frame);
// seeks to nearest keyframe (target_frame represents internal clip frame)
int64_t seek_ts = qRound(clip_frame_to_seconds(c, target_frame) / timebase);
av_seek_frame(c->formatCtx, ms->file_index, seek_ts - (av_q2d(av_inv_q(c->stream->time_base))), AVSEEK_FLAG_BACKWARD);
av_frame_free(&temp);
qDebug() << "seek ts:" << seek_ts;
// play up to the frame we actually want
int ret;
do {
ret = retrieve_next_frame(c, temp);
if (ret < 0) {
qDebug() << "[WARNING] Seeking terminated prematurely";
break;
}
qDebug() << "received ts:" << temp->pts;
} while (temp->pts + temp->pkt_duration + temp->pkt_duration < seek_ts);
av_frame_unref(temp);
av_frame_free(&temp);
} else {
av_seek_frame(c->formatCtx, ms->file_index, 0, AVSEEK_FLAG_BACKWARD);
}
} else if (c->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
// seek (target_frame represents timeline timecode in frames, not clip timecode)
int64_t timestamp = qRound(playhead_to_seconds(c, target_frame) / timebase); // TODO qRound here might lead to clicking? or might fix it... who knows
@@ -521,7 +536,7 @@ void open_clip_worker(Clip* clip) {
// allocate filtergraph
clip->filter_graph = avfilter_graph_alloc();
if (clip->filter_graph == NULL) {
qDebug() << "couldn't create filtergraph";
qDebug() << "[ERROR] Could not create filtergraph";
}
char filter_args[512];
@@ -544,6 +559,7 @@ void open_clip_worker(Clip* clip) {
clip->cache_size = (ms->infinite_length) ? 1 : ceil(av_q2d(clip->stream->avg_frame_rate)/4); // cache is half a second in total
// if (clip->skip_type == SKIP_TYPE_SEEK) clip->cache_size *= 2;
if (ms->video_interlacing != VIDEO_PROGRESSIVE) clip->cache_size *= 2;
clip->cache_A.frames = new AVFrame* [clip->cache_size];
clip->cache_B.frames = new AVFrame* [clip->cache_size];
@@ -571,19 +587,17 @@ void open_clip_worker(Clip* clip) {
qDebug() << "[ERROR] Could not set output pixel format";
}
bool interlaced = false;
if (interlaced) {
// TODO make better
AVFilterContext* yadif_filter;
avfilter_graph_create_filter(&yadif_filter, avfilter_get_by_name("yadif"), "yadif", "mode=3", NULL, clip->filter_graph);
clip->speed *= 2;
avfilter_link(clip->buffersrc_ctx, 0, yadif_filter, 0);
avfilter_link(yadif_filter, 0, clip->buffersink_ctx, 0);
} else {
if (ms->video_interlacing == VIDEO_PROGRESSIVE) {
avfilter_link(clip->buffersrc_ctx, 0, clip->buffersink_ctx, 0);
}
} else {
AVFilterContext* yadif_filter;
char yadif_args[100];
snprintf(yadif_args, sizeof(yadif_args), "mode=3:parity=%d", ((ms->video_interlacing == VIDEO_TOP_FIELD_FIRST) ? 0 : 1)); // try mode 1
avfilter_graph_create_filter(&yadif_filter, avfilter_get_by_name("yadif"), "yadif", yadif_args, NULL, clip->filter_graph);
avfilter_link(clip->buffersrc_ctx, 0, yadif_filter, 0);
avfilter_link(yadif_filter, 0, clip->buffersink_ctx, 0);
}
avfilter_graph_config(clip->filter_graph, NULL);
} else if (clip->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
@@ -765,7 +779,7 @@ void Cacher::run() {
open_clip_worker(clip);
while (caching) {
while (caching) {
clip->can_cache.wait(&clip->lock);
if (!caching) {
break;
+6 -6
View File
@@ -117,7 +117,7 @@ bool get_clip_frame(Clip* c, long playhead) {
double rate = c->getMediaFrameRate();
if (c->skip_type == SKIP_TYPE_DISCARD) rate *= c->speed;
long clip_time = refactor_frame_number(sequence_clip_time, c->sequence->frame_rate, rate);
long clip_time = qMax(0L, refactor_frame_number(sequence_clip_time, c->sequence->frame_rate, rate));
AVFrame* current_frame = NULL;
bool no_frame = false;
@@ -170,6 +170,8 @@ bool get_clip_frame(Clip* c, long playhead) {
}
} else {
// this is technically bad, unless we just seeked
c->cache_A.write_count = 0;
c->cache_B.write_count = 0;
c->cache_A.unread = false;
c->cache_B.unread = false;
cache_needs_reset = true;
@@ -204,8 +206,6 @@ bool get_clip_frame(Clip* c, long playhead) {
}
}
qDebug() << "current_frame is NULL:" << (current_frame == NULL);
if (current_frame != NULL) {
// set up opengl texture
if (c->texture == NULL) {
@@ -224,7 +224,7 @@ bool get_clip_frame(Clip* c, long playhead) {
return true;
} else {
texture_failed = true;
if (!no_frame) qDebug() << "[ERROR] Failed to retrieve frame from cache (R:" << clip_time << "| A:" << c->cache_A.offset << "-" << c->cache_A.offset+c->cache_size-1 << "| B:" << c->cache_B.offset << "-" << c->cache_B.offset+c->cache_size-1 << "| WA:" << c->cache_A.written << "| WB:" << c->cache_B.written << ")";
qDebug() << "[ERROR] Failed to retrieve frame from cache (R:" << clip_time << "| A:" << c->cache_A.offset << "-" << c->cache_A.offset+c->cache_size-1 << "| B:" << c->cache_B.offset << "-" << c->cache_B.offset+c->cache_size-1 << "| WA:" << c->cache_A.written << "| WB:" << c->cache_B.written << ")";
}
}
return false;
@@ -242,7 +242,7 @@ double playhead_to_seconds(Clip* c, long playhead) {
long seconds_to_clip_frame(Clip* c, double seconds) {
// returns time as frame number (according to clip's frame rate)
if (c->stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
return floor(seconds*av_q2d(c->stream->avg_frame_rate));
return floor(seconds*c->getMediaFrameRate());
} else {
qDebug() << "[ERROR] seconds_to_clip_frame only works on video streams";
return 0;
@@ -251,7 +251,7 @@ long seconds_to_clip_frame(Clip* c, double seconds) {
double clip_frame_to_seconds(Clip* c, long clip_frame) {
// returns frame number in decimal seconds
return (double) clip_frame / av_q2d(c->stream->avg_frame_rate);
return (double) clip_frame / c->getMediaFrameRate();
}
int retrieve_next_frame(Clip* c, AVFrame* f) {
+7 -14
View File
@@ -86,8 +86,7 @@ void TimelineHeader::set_out_point(long new_out) {
}
void TimelineHeader::mousePressEvent(QMouseEvent* event) {
qDebug() << "press???!?!?!??!";
if (resizing_workarea) {
if (resizing_workarea) {
sequence_end = sequence->getEndFrame();
} else {
bool shift = (event->modifiers() & Qt::ShiftModifier);
@@ -130,15 +129,11 @@ void TimelineHeader::mousePressEvent(QMouseEvent* event) {
}
set_playhead(event->pos().x());
}
}
qDebug() << "3";
dragging = true;
qDebug() << "5" << dragging;
event->accept();
}
dragging = true;
}
void TimelineHeader::mouseMoveEvent(QMouseEvent* event) {
qDebug() << "move";
if (dragging) {
if (resizing_workarea) {
long frame = getHeaderFrameFromScreenPoint(event->pos().x());
@@ -180,7 +175,7 @@ void TimelineHeader::mouseMoveEvent(QMouseEvent* event) {
panel_timeline->repaint_timeline(false);
} else {
set_playhead(event->pos().x());
}
}
} else {
resizing_workarea = false;
unsetCursor();
@@ -200,13 +195,12 @@ void TimelineHeader::mouseMoveEvent(QMouseEvent* event) {
setCursor(Qt::SizeHorCursor);
}
}
}
event->accept();
}
}
void TimelineHeader::mouseReleaseEvent(QMouseEvent* event) {
qDebug() << "release???!?!?!??!";
if (resizing_workarea) {
dragging = false;
if (resizing_workarea) {
undo_stack.push(new SetTimelineInOutCommand(sequence, true, temp_workarea_in, temp_workarea_out));
} else if (dragging_markers && selected_markers.size() > 0) {
bool moved = false;
@@ -230,7 +224,6 @@ void TimelineHeader::mouseReleaseEvent(QMouseEvent* event) {
dragging_markers = false;
panel_timeline->snapped = false;
panel_timeline->repaint_timeline(false);
event->accept();
}
void TimelineHeader::focusOutEvent(QFocusEvent*) {