From 2dde8bde77640c1cec60f1da499abf48a46982f0 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 17 Aug 2018 21:21:18 +1000 Subject: [PATCH] further progress on ffmpeg filters --- playback/cacher.cpp | 97 ++++---------- project/clip.cpp | 1 + ui/timelinewidget.cpp | 304 +++++++++++++++++++++--------------------- 3 files changed, 180 insertions(+), 222 deletions(-) diff --git a/playback/cacher.cpp b/playback/cacher.cpp index d43d4f0e3..20e4584a0 100644 --- a/playback/cacher.cpp +++ b/playback/cacher.cpp @@ -25,6 +25,8 @@ extern "C" { #include #include +int dest_format = AV_PIX_FMT_RGBA; + void apply_audio_effects(Clip* c, AVFrame* frame, int nb_bytes) { // perform all audio effects for (int j=0;jeffects.size();j++) { @@ -188,9 +190,35 @@ void cache_video_worker(Clip* c, long playhead, ClipCache* cache) { if (!c->reached_end) { while (i < c->cache_size) { av_frame_unref(cache->frames[i]); - int ret = av_buffersink_get_frame(c->buffersink_ctx, cache->frames[i]); + + int ret = (c->filter_graph == NULL) ? AVERROR(EAGAIN) : av_buffersink_get_frame(c->buffersink_ctx, cache->frames[i]); + if (ret < 0) { if (ret == AVERROR(EAGAIN)) { + if (c->filter_graph != NULL) { + avfilter_graph_free(&c->filter_graph); + } + c->filter_graph = avfilter_graph_alloc(); + char args[512]; + snprintf(args, sizeof(args), + "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d", + c->stream->codecpar->width, c->stream->codecpar->height, c->stream->codecpar->format, + c->stream->time_base.num, c->stream->time_base.den, + c->stream->codecpar->sample_aspect_ratio.num, c->stream->codecpar->sample_aspect_ratio.den); + avfilter_graph_create_filter(&c->buffersrc_ctx, avfilter_get_by_name("buffer"), "in", args, NULL, c->filter_graph); + avfilter_graph_create_filter(&c->buffersink_ctx, avfilter_get_by_name("buffersink"), "out", NULL, NULL, c->filter_graph); + enum AVPixelFormat pix_fmts[] = { static_cast(dest_format), AV_PIX_FMT_NONE }; + av_opt_set_int_list(c->buffersink_ctx, "pix_fmts", pix_fmts, AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN); + + AVFilterContext* gblur_ctx; +// avfilter_graph_create_filter(&gblur_ctx, avfilter_get_by_name("gblur"), "ol_gblur", "sigma=20:steps=1", NULL, c->filter_graph); + avfilter_graph_create_filter(&gblur_ctx, avfilter_get_by_name("negate"), "ol_gblur", NULL, NULL, c->filter_graph); +// avfilter_graph_create_filter(&gblur_ctx, avfilter_get_by_name("null"), "ol_gblur", NULL, NULL, c->filter_graph); + avfilter_link(c->buffersrc_ctx, 0, gblur_ctx, 0); + avfilter_link(gblur_ctx, 0, c->buffersink_ctx, 0); + + avfilter_graph_config(c->filter_graph, NULL); + ret = retrieve_next_frame(c, c->frame); if (ret >= 0) { if ((ret = av_buffersrc_add_frame_flags(c->buffersrc_ctx, c->frame, AV_BUFFERSRC_FLAG_KEEP_REF)) < 0) { @@ -334,7 +362,6 @@ void open_clip_worker(Clip* clip) { // as "scaling" is actually done by OpenGL int dstW = ceil(clip->stream->codecpar->width/2)*2; int dstH = ceil(clip->stream->codecpar->height/2)*2; - int dest_format = AV_PIX_FMT_RGBA; clip->sws_ctx = sws_getContext( clip->stream->codecpar->width, @@ -374,71 +401,6 @@ void open_clip_worker(Clip* clip) { qDebug() << "[ERROR] Could not allocate buffer for sws_frame"; } clip->sws_frame->linesize[0] = clip->stream->codecpar->width*4; - - // SET UP FFMPEG FILTERGRAPH - AVFilter *buffersrc = avfilter_get_by_name("buffer"); - AVFilter *buffersink = avfilter_get_by_name("buffersink"); - AVFilterInOut *outputs = avfilter_inout_alloc(); - AVFilterInOut *inputs = avfilter_inout_alloc(); - - clip->filter_graph = avfilter_graph_alloc(); - - if (outputs == NULL || inputs == NULL || clip->filter_graph == NULL) { - qDebug() << "[ERROR] Couldn't alloc filter graphs. Out of memory?"; - } else { - char args[512]; - snprintf(args, sizeof(args), - "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d", - clip->stream->codecpar->width, clip->stream->codecpar->height, clip->stream->codecpar->format, - clip->stream->time_base.num, clip->stream->time_base.den, - clip->stream->codecpar->sample_aspect_ratio.num, clip->stream->codecpar->sample_aspect_ratio.den); - - int ret = avfilter_graph_create_filter(&clip->buffersrc_ctx, buffersrc, "in", args, NULL, clip->filter_graph); - if (ret < 0) { - qDebug() << "[ERROR] Could not create buffer source"; - } else { - ret = avfilter_graph_create_filter(&clip->buffersink_ctx, buffersink, "out", NULL, NULL, clip->filter_graph); - if (ret < 0) { - qDebug() << "[ERROR] Could not create buffer sink"; - } else { - enum AVPixelFormat pix_fmts[] = { static_cast(dest_format), AV_PIX_FMT_NONE }; - av_opt_set_int_list(clip->buffersink_ctx, "pix_fmts", pix_fmts, AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN); - - outputs->name = av_strdup("in"); - outputs->filter_ctx = clip->buffersrc_ctx; - outputs->pad_idx = 0; - outputs->next = NULL; - - inputs->name = av_strdup("out"); - inputs->filter_ctx = clip->buffersink_ctx; - inputs->pad_idx = 0; - inputs->next = 0; - - /*ret = avfilter_graph_config(clip->filter_graph, NULL); - if (ret < 0) { - qDebug() << "[ERROR] AVFilter config failed"; - }*/ - - ret = avfilter_graph_parse_ptr(clip->filter_graph, "gblur=sigma=20:steps=4", &inputs, &outputs, NULL); - if (ret < 0) { - qDebug() << "[ERROR] Couldn't parse filters." << ret; - } else { - ret = avfilter_graph_config(clip->filter_graph, NULL); - if (ret < 0) { - qDebug() << "[ERROR] AVFilter config failed." << ret; - } - - /*ret = avfilter_graph_send_command(clip->filter_graph, "gblur", "enable", "2", NULL, 0, 0); - if (ret < 0) { - qDebug() << "[ERROR] Failed to send graph command." << ret << AVERROR(ENOSYS); - }*/ - } - } - } - } - - avfilter_inout_free(&inputs); - avfilter_inout_free(&outputs); } 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) @@ -509,7 +471,6 @@ void close_clip_worker(Clip* clip) { sws_freeContext(clip->sws_ctx); // TODO will eventually be in audio too - avfilter_graph_free(&clip->filter_graph); av_frame_free(&clip->sws_frame); } else if (clip->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { swr_free(&clip->swr_ctx); diff --git a/project/clip.cpp b/project/clip.cpp index 7ad166217..288fa30e3 100644 --- a/project/clip.cpp +++ b/project/clip.cpp @@ -26,6 +26,7 @@ Clip::Clip(Sequence* s) : opening_transition(NULL), closing_transition(NULL), pkt(new AVPacket()), + filter_graph(NULL), replaced(false), texture(NULL) { diff --git a/ui/timelinewidget.cpp b/ui/timelinewidget.cpp index 3d7d9ebee..bd30ca091 100644 --- a/ui/timelinewidget.cpp +++ b/ui/timelinewidget.cpp @@ -512,187 +512,183 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) { repaint = true; if (panel_timeline->ghosts.size() > 0) { const Ghost& first_ghost = panel_timeline->ghosts.at(0); - if (first_ghost.old_in != first_ghost.in - || first_ghost.old_out != first_ghost.out - || first_ghost.old_clip_in != first_ghost.clip_in - || first_ghost.old_track != first_ghost.track) { - TimelineAction* ta = new TimelineAction(); - // if we were RIPPLING, move all the clips - if (panel_timeline->tool == TIMELINE_TOOL_RIPPLE) { - long ripple_length, ripple_point; + TimelineAction* ta = new TimelineAction(); - // ripple_length becomes the length/number of frames we trimmed - // ripple point becomes the point to ripple (i.e. the point after or before which we move every clip) - if (panel_timeline->trim_in_point) { - ripple_length = first_ghost.old_in - panel_timeline->ghosts.at(0).in; - ripple_point = first_ghost.old_in; - } else { - // if we're trimming an out-point - ripple_length = first_ghost.old_out - panel_timeline->ghosts.at(0).out; - ripple_point = first_ghost.old_out; - } - QVector ignore_clips; - for (int i=0;ighosts.size();i++) { - const Ghost& g = panel_timeline->ghosts.at(i); + // if we were RIPPLING, move all the clips + if (panel_timeline->tool == TIMELINE_TOOL_RIPPLE) { + long ripple_length, ripple_point; - // push rippled clips forward if necessary - if (panel_timeline->trim_in_point) { - ignore_clips.append(g.clip); - panel_timeline->ghosts[i].in += ripple_length; - panel_timeline->ghosts[i].out += ripple_length; - } - - long comp_point = panel_timeline->trim_in_point ? g.old_in : g.old_out; - ripple_point = qMin(ripple_point, comp_point); - } - if (!panel_timeline->trim_in_point) ripple_length = -ripple_length; - ta->ripple(sequence, ripple_point, ripple_length, ignore_clips); + // ripple_length becomes the length/number of frames we trimmed + // ripple point becomes the point to ripple (i.e. the point after or before which we move every clip) + if (panel_timeline->trim_in_point) { + ripple_length = first_ghost.old_in - panel_timeline->ghosts.at(0).in; + ripple_point = first_ghost.old_in; + } else { + // if we're trimming an out-point + ripple_length = first_ghost.old_out - panel_timeline->ghosts.at(0).out; + ripple_point = first_ghost.old_out; } + QVector ignore_clips; + for (int i=0;ighosts.size();i++) { + const Ghost& g = panel_timeline->ghosts.at(i); - if (panel_timeline->tool == TIMELINE_TOOL_POINTER - && (event->modifiers() & Qt::AltModifier) - && panel_timeline->trim_target == -1) { // if holding alt (and not trimming), duplicate rather than move - // duplicate clips - QVector old_clips; - QVector new_clips; + // push rippled clips forward if necessary + if (panel_timeline->trim_in_point) { + ignore_clips.append(g.clip); + panel_timeline->ghosts[i].in += ripple_length; + panel_timeline->ghosts[i].out += ripple_length; + } + + long comp_point = panel_timeline->trim_in_point ? g.old_in : g.old_out; + ripple_point = qMin(ripple_point, comp_point); + } + if (!panel_timeline->trim_in_point) ripple_length = -ripple_length; + ta->ripple(sequence, ripple_point, ripple_length, ignore_clips); + } + + if (panel_timeline->tool == TIMELINE_TOOL_POINTER + && (event->modifiers() & Qt::AltModifier) + && panel_timeline->trim_target == -1) { // if holding alt (and not trimming), duplicate rather than move + // duplicate clips + QVector old_clips; + QVector new_clips; + QVector delete_areas; + for (int i=0;ighosts.size();i++) { + const Ghost& g = panel_timeline->ghosts.at(i); + if (g.old_in != g.in || g.old_out != g.out || g.track != g.old_track || g.clip_in != g.old_clip_in) { + // create copy of clip + Clip* c = sequence->get_clip(g.clip)->copy(sequence); + + c->timeline_in = g.in; + c->timeline_out = g.out; + c->track = g.track; + + Selection s; + s.in = g.in; + s.out = g.out; + s.track = g.track; + delete_areas.append(s); + + old_clips.append(g.clip); + new_clips.append(c); + } + } + if (new_clips.size() > 0) { + panel_timeline->delete_areas_and_relink(ta, delete_areas); + + // relink duplicated clips + panel_timeline->relink_clips_using_ids(old_clips, new_clips); + + for (int i=0;iadd_clips(sequence, new_clips); + } + } + } else { + // move clips + if (panel_timeline->tool == TIMELINE_TOOL_POINTER) { QVector delete_areas; for (int i=0;ighosts.size();i++) { + // step 1 - set clips that are moving to "undeletable" (to avoid step 2 deleting any part of them) const Ghost& g = panel_timeline->ghosts.at(i); - if (g.old_in != g.in || g.old_out != g.out || g.track != g.old_track || g.clip_in != g.old_clip_in) { - // create copy of clip - Clip* c = sequence->get_clip(g.clip)->copy(sequence); - c->timeline_in = g.in; - c->timeline_out = g.out; - c->track = g.track; + sequence->get_clip(g.clip)->undeletable = true; - Selection s; - s.in = g.in; - s.out = g.out; - s.track = g.track; - delete_areas.append(s); - - old_clips.append(g.clip); - new_clips.append(c); - } - } - if (new_clips.size() > 0) { - panel_timeline->delete_areas_and_relink(ta, delete_areas); - - // relink duplicated clips - panel_timeline->relink_clips_using_ids(old_clips, new_clips); - - for (int i=0;iadd_clips(sequence, new_clips); - } - } - } else { - // move clips - if (panel_timeline->tool == TIMELINE_TOOL_POINTER) { - QVector delete_areas; - for (int i=0;ighosts.size();i++) { - // step 1 - set clips that are moving to "undeletable" (to avoid step 2 deleting any part of them) - const Ghost& g = panel_timeline->ghosts.at(i); - - sequence->get_clip(g.clip)->undeletable = true; - - Selection s; - s.in = g.in; - s.out = g.out; - s.track = g.track; - delete_areas.append(s); - } - panel_timeline->delete_areas_and_relink(ta, delete_areas); - for (int i=0;ighosts.size();i++) { - sequence->get_clip(panel_timeline->ghosts[i].clip)->undeletable = false; - } + Selection s; + s.in = g.in; + s.out = g.out; + s.track = g.track; + delete_areas.append(s); } + panel_timeline->delete_areas_and_relink(ta, delete_areas); for (int i=0;ighosts.size();i++) { - Ghost& g = panel_timeline->ghosts[i]; + sequence->get_clip(panel_timeline->ghosts[i].clip)->undeletable = false; + } + } + for (int i=0;ighosts.size();i++) { + Ghost& g = panel_timeline->ghosts[i]; - // step 3 - move clips - Clip* c = sequence->get_clip(g.clip); - if (g.transition == NULL) { - ta->increase_timeline_in(sequence, g.clip, g.in - g.old_in); - ta->increase_timeline_out(sequence, g.clip, g.out - g.old_out); - ta->increase_track(sequence, g.clip, g.track - g.old_track); - ta->increase_clip_in(sequence, g.clip, g.clip_in - g.old_clip_in); + // step 3 - move clips + Clip* c = sequence->get_clip(g.clip); + if (g.transition == NULL) { + ta->increase_timeline_in(sequence, g.clip, g.in - g.old_in); + ta->increase_timeline_out(sequence, g.clip, g.out - g.old_out); + ta->increase_track(sequence, g.clip, g.track - g.old_track); + ta->increase_clip_in(sequence, g.clip, g.clip_in - g.old_clip_in); - // adjust transitions if we need to - long new_clip_length = (g.out - g.in); - if (c->opening_transition != NULL) { - long max_open_length = new_clip_length; - if (c->closing_transition != NULL && !panel_timeline->trim_in_point) { - max_open_length -= c->closing_transition->length; - } - if (max_open_length <= 0) { - ta->delete_transition(sequence, g.clip, TA_OPENING_TRANSITION); - } else if (c->opening_transition->length > max_open_length) { - ta->modify_transition(sequence, g.clip, TA_OPENING_TRANSITION, max_open_length); - } + // adjust transitions if we need to + long new_clip_length = (g.out - g.in); + if (c->opening_transition != NULL) { + long max_open_length = new_clip_length; + if (c->closing_transition != NULL && !panel_timeline->trim_in_point) { + max_open_length -= c->closing_transition->length; } + if (max_open_length <= 0) { + ta->delete_transition(sequence, g.clip, TA_OPENING_TRANSITION); + } else if (c->opening_transition->length > max_open_length) { + ta->modify_transition(sequence, g.clip, TA_OPENING_TRANSITION, max_open_length); + } + } + if (c->closing_transition != NULL) { + long max_open_length = new_clip_length; + if (c->opening_transition != NULL && panel_timeline->trim_in_point) { + max_open_length -= c->opening_transition->length; + } + if (max_open_length <= 0) { + ta->delete_transition(sequence, g.clip, TA_CLOSING_TRANSITION); + } else if (c->closing_transition->length > max_open_length) { + ta->modify_transition(sequence, g.clip, TA_CLOSING_TRANSITION, max_open_length); + } + } + } else { + bool is_opening_transition = (g.transition == c->opening_transition); + long new_transition_length = g.out - g.in; + ta->modify_transition( + sequence, + g.clip, + is_opening_transition ? TA_OPENING_TRANSITION : TA_CLOSING_TRANSITION, + new_transition_length + ); + + long clip_length = c->getLength(); + if (is_opening_transition) { + if (g.in != g.old_in) { + // if transition is going to make the clip bigger, make the clip bigger + ta->increase_timeline_in(sequence, g.clip, g.in - g.old_in); + clip_length -= (g.in - g.old_in); + ta->increase_clip_in(sequence, g.clip, g.clip_in - g.old_clip_in); + } + if (c->closing_transition != NULL) { - long max_open_length = new_clip_length; - if (c->opening_transition != NULL && panel_timeline->trim_in_point) { - max_open_length -= c->opening_transition->length; - } - if (max_open_length <= 0) { + if (new_transition_length == clip_length) { ta->delete_transition(sequence, g.clip, TA_CLOSING_TRANSITION); - } else if (c->closing_transition->length > max_open_length) { - ta->modify_transition(sequence, g.clip, TA_CLOSING_TRANSITION, max_open_length); + } else if (new_transition_length > clip_length - c->closing_transition->length) { + ta->modify_transition(sequence, g.clip, TA_CLOSING_TRANSITION, clip_length - new_transition_length); } } } else { - bool is_opening_transition = (g.transition == c->opening_transition); - long new_transition_length = g.out - g.in; - ta->modify_transition( - sequence, - g.clip, - is_opening_transition ? TA_OPENING_TRANSITION : TA_CLOSING_TRANSITION, - new_transition_length - ); + if (g.out != g.old_out) { + // if transition is going to make the clip bigger, make the clip bigger + ta->increase_timeline_out(sequence, g.clip, g.out - g.old_out); + clip_length += (g.out - g.old_out); + } - long clip_length = c->getLength(); - if (is_opening_transition) { - if (g.in != g.old_in) { - // if transition is going to make the clip bigger, make the clip bigger - ta->increase_timeline_in(sequence, g.clip, g.in - g.old_in); - clip_length -= (g.in - g.old_in); - ta->increase_clip_in(sequence, g.clip, g.clip_in - g.old_clip_in); - } - - if (c->closing_transition != NULL) { - if (new_transition_length == clip_length) { - ta->delete_transition(sequence, g.clip, TA_CLOSING_TRANSITION); - } else if (new_transition_length > clip_length - c->closing_transition->length) { - ta->modify_transition(sequence, g.clip, TA_CLOSING_TRANSITION, clip_length - new_transition_length); - } - } - } else { - if (g.out != g.old_out) { - // if transition is going to make the clip bigger, make the clip bigger - ta->increase_timeline_out(sequence, g.clip, g.out - g.old_out); - clip_length += (g.out - g.old_out); - } - - if (c->opening_transition != NULL) { - if (new_transition_length == clip_length) { - ta->delete_transition(sequence, g.clip, TA_OPENING_TRANSITION); - } else if (new_transition_length > clip_length - c->opening_transition->length) { - ta->modify_transition(sequence, g.clip, TA_OPENING_TRANSITION, clip_length - new_transition_length); - } + if (c->opening_transition != NULL) { + if (new_transition_length == clip_length) { + ta->delete_transition(sequence, g.clip, TA_OPENING_TRANSITION); + } else if (new_transition_length > clip_length - c->opening_transition->length) { + ta->modify_transition(sequence, g.clip, TA_OPENING_TRANSITION, clip_length - new_transition_length); } } } } } - - undo_stack.push(ta); - - panel_timeline->redraw_all_clips(true); - repaint = false; } + + undo_stack.push(ta); + + panel_timeline->redraw_all_clips(true); + repaint = false; } } else if (panel_timeline->selecting || panel_timeline->rect_select_proc) { repaint = true;