From c21a21c219de3969cff97df8db51b19983170fbb Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Mon, 1 Oct 2018 00:03:43 +1000 Subject: [PATCH] returned to AVFilter solution --- main.cpp | 2 + olive.pro | 6 +-- playback/cacher.cpp | 97 ++++++++++++++++++++++++++++++++++++++++--- playback/playback.cpp | 2 +- project/clip.cpp | 1 + project/clip.h | 9 +++- 6 files changed, 106 insertions(+), 11 deletions(-) diff --git a/main.cpp b/main.cpp index 02fed7c16..2615101ab 100644 --- a/main.cpp +++ b/main.cpp @@ -3,12 +3,14 @@ extern "C" { #include + #include } int main(int argc, char *argv[]) { // init ffmpeg subsystem av_register_all(); + avfilter_register_all(); QApplication a(argc, argv); MainWindow w; diff --git a/olive.pro b/olive.pro index fbc8644d4..21b0b7225 100644 --- a/olive.pro +++ b/olive.pro @@ -157,17 +157,17 @@ FORMS += \ win32 { RC_FILE = icons/resources.rc - LIBS += -lavutil -lavformat -lavcodec -lswscale -lswresample -lopengl32 + LIBS += -lavutil -lavformat -lavcodec -lavfilter -lswscale -lswresample -lopengl32 } mac { - LIBS += -L/usr/local/lib -lavutil -lavformat -lavcodec -lswscale -lswresample + LIBS += -L/usr/local/lib -lavutil -lavformat -lavcodec -lavfilter -lswscale -lswresample ICON = icons/olive.icns INCLUDEPATH = /usr/local/include } linux { - LIBS += -lavutil -lavformat -lavcodec -lswscale -lswresample + LIBS += -lavutil -lavformat -lavcodec -lavfilter -lswscale -lswresample } RESOURCES += \ diff --git a/playback/cacher.cpp b/playback/cacher.cpp index 319c86a57..2ffb12e27 100644 --- a/playback/cacher.cpp +++ b/playback/cacher.cpp @@ -15,6 +15,10 @@ extern "C" { #include #include #include + #include + #include + #include + #include } #include @@ -203,6 +207,7 @@ void cache_video_worker(Clip* c, long playhead, ClipCache* cache) { int i = 0; + /* old swscale solution if (!c->reached_end) { while (i < c->cache_size) { retrieve_next_frame_raw_data(c, cache->frames[i]); @@ -210,6 +215,44 @@ void cache_video_worker(Clip* c, long playhead, ClipCache* cache) { if (c->reached_end) break; i++; } + }*/ + + /* new AVFilter solution */ + if (!c->reached_end) { + while (i < c->cache_size) { + av_frame_unref(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)) { + 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) { + qDebug() << "[ERROR] Could not feed filtergraph -" << ret; + error = true; + break; + } + } else { + if (ret == AVERROR_EOF) { + c->reached_end = true; + } else { + qDebug() << "[WARNING] Raw frame data could not be retrieved." << ret; + error = true; + } + break; + } + } else { + if (ret != AVERROR_EOF) { + qDebug() << "[ERROR] Could not pull from filtergraph"; + error = true; + } + break; + } + } else { + i++; + } + } } cache->write_count = i; @@ -335,10 +378,11 @@ void open_clip_worker(Clip* clip) { if (clip->stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { // set up swscale context - primarily used for colorspace conversion // 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; - clip->sws_ctx = sws_getContext( + //int dstW = ceil(clip->stream->codecpar->width/2)*2; + //int dstH = ceil(clip->stream->codecpar->height/2)*2; + + /*clip->sws_ctx = sws_getContext( clip->stream->codecpar->width, clip->stream->codecpar->height, static_cast(clip->stream->codecpar->format), @@ -349,15 +393,20 @@ void open_clip_worker(Clip* clip) { NULL, NULL, NULL - ); + );*/ // create memory cache for video clip->cache_size = (ms->infinite_length) ? 1 : ceil(av_q2d(clip->stream->avg_frame_rate)/4); // cache is half a second in total - // infinite length doesn't need cache B clip->cache_A.frames = new AVFrame* [clip->cache_size]; clip->cache_B.frames = new AVFrame* [clip->cache_size]; + for (int i=0;icache_size;i++) { + clip->cache_A.frames[i] = av_frame_alloc(); + clip->cache_B.frames[i] = av_frame_alloc(); + } + + /*for (int i=0;icache_size;i++) { clip->cache_A.frames[i] = av_frame_alloc(); av_frame_make_writable(clip->cache_A.frames[i]); clip->cache_A.frames[i]->width = dstW; @@ -375,7 +424,42 @@ void open_clip_worker(Clip* clip) { if (av_frame_get_buffer(clip->cache_B.frames[i], 0)) { qDebug() << "[ERROR] Could not allocate buffer for sws_frame"; } + }*/ + + clip->filter_graph = avfilter_graph_alloc(); + if (clip->filter_graph == NULL) { + qDebug() << "couldn't create filtergraph"; } + + 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 + ); + + char errormsg[100]; + + AVFilter* buffersrc = avfilter_get_by_name("buffer"); + AVFilter* buffersink = avfilter_get_by_name("buffersink"); + + if (buffersrc == NULL || buffersink == NULL) { + qDebug() << "lol"; + } + + avfilter_graph_create_filter(&clip->buffersrc_ctx, buffersrc, "in", args, NULL, clip->filter_graph); + avfilter_graph_create_filter(&clip->buffersink_ctx, buffersink, "out", NULL, NULL, clip->filter_graph); + + 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); + + avfilter_link(clip->buffersrc_ctx, 0, clip->buffersink_ctx, 0); + + 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) @@ -469,7 +553,8 @@ void close_clip_worker(Clip* clip) { // closes ffmpeg file handle and frees any memory used for caching MediaStream* ms = static_cast(clip->media)->get_stream_from_file_index(clip->track < 0, clip->media_stream); if (clip->track < 0) { - sws_freeContext(clip->sws_ctx); +// sws_freeContext(clip->sws_ctx); + avfilter_graph_free(&clip->filter_graph); } else { swr_free(&clip->swr_ctx); } diff --git a/playback/playback.cpp b/playback/playback.cpp index f7c76b7ab..0e3f56a4a 100644 --- a/playback/playback.cpp +++ b/playback/playback.cpp @@ -277,7 +277,7 @@ void retrieve_next_frame_raw_data(Clip* c, AVFrame* output) { int ret = retrieve_next_frame(c, c->frame); if (ret >= 0) { if (c->stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { - sws_scale(c->sws_ctx, c->frame->data, c->frame->linesize, 0, c->stream->codecpar->height, output->data, output->linesize); +// sws_scale(c->sws_ctx, c->frame->data, c->frame->linesize, 0, c->stream->codecpar->height, output->data, output->linesize); // output->pts = c->frame->best_effort_timestamp; } else if (c->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { output->pts = c->frame->pts; diff --git a/project/clip.cpp b/project/clip.cpp index ee8bc1c43..ccbcf9501 100644 --- a/project/clip.cpp +++ b/project/clip.cpp @@ -29,6 +29,7 @@ Clip::Clip(Sequence* s) : closing_transition(NULL), pkt(new AVPacket()), replaced(false), + filter_graph(NULL), texture(NULL), fbo(NULL), autoscale(config.autoscale_by_default) diff --git a/project/clip.h b/project/clip.h index fe8c48204..eb5545b49 100644 --- a/project/clip.h +++ b/project/clip.h @@ -21,6 +21,8 @@ struct AVFrame; struct AVPacket; struct SwsContext; struct SwrContext; +struct AVFilterGraph; +struct AVFilterContext; class QOpenGLTexture; struct ClipCache { @@ -98,8 +100,13 @@ struct Clip QMutex lock; QMutex open_lock; + // converters/filters + AVFilterGraph* filter_graph; + AVFilterContext* buffersink_ctx; + AVFilterContext* buffersrc_ctx; + // video playback variables - SwsContext* sws_ctx; +// SwsContext* sws_ctx; QOpenGLFramebufferObject** fbo; QOpenGLTexture* texture; long texture_frame;