From: Date: Subject: X-Git-Url: http://quickgit.kde.org/?p=ffmpegthumbs.git&a=commitdiff&h=3978c762072b7bc16b2096819b7cfa2052deaf5e --- --- --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,7 +36,7 @@ add_library(ffmpegthumbs MODULE ${ffmpegthumbs_PART_SRCS}) -target_link_libraries(ffmpegthumbs Qt5::Gui KF5::KIOWidgets ${AVUTIL_LIBRARIES} ${AVFORMAT_LIBRARIES} ${AVCODEC_LIBRARIES} ${SWSCALE_LIBRARIES} ) +target_link_libraries(ffmpegthumbs Qt5::Gui KF5::KIOWidgets ${AVUTIL_LIBRARIES} ${AVFILTER_LIBRARIES} ${AVFORMAT_LIBRARIES} ${AVCODEC_LIBRARIES} ${SWSCALE_LIBRARIES} ) install(TARGETS ffmpegthumbs DESTINATION ${PLUGIN_INSTALL_DIR}) --- a/cmake/FindFFmpeg.cmake +++ b/cmake/FindFFmpeg.cmake @@ -99,6 +99,7 @@ # Check for all possible component. find_component(AVCODEC libavcodec avcodec libavcodec/avcodec.h) + find_component(AVFILTER libavfilter avfilter libavfilter/avfilter.h) find_component(AVFORMAT libavformat avformat libavformat/avformat.h) find_component(AVDEVICE libavdevice avdevice libavdevice/avdevice.h) find_component(AVUTIL libavutil avutil libavutil/avutil.h) --- a/ffmpegthumbnailer/moviedecoder.cpp +++ b/ffmpegthumbnailer/moviedecoder.cpp @@ -40,6 +40,10 @@ , m_FormatContextWasGiven(pavContext != NULL) , m_AllowSeek(true) , m_initialized(false) + , m_bufferSinkContext(nullptr) + , m_bufferSourceContext(nullptr) + , m_filterGraph(nullptr) + , m_filterFrame(nullptr) { initialize(filename); } @@ -51,6 +55,9 @@ void MovieDecoder::initialize(const QString& filename) { + m_lastWidth = -1; + m_lastHeight = -1; + m_lastPixfmt = AV_PIX_FMT_NONE; av_register_all(); avcodec_register_all(); @@ -67,7 +74,7 @@ } initializeVideo(); - m_pFrame = avcodec_alloc_frame(); + m_pFrame = av_frame_alloc(); if (m_pFrame) { m_initialized=true; @@ -82,6 +89,7 @@ void MovieDecoder::destroy() { + deleteFilterGraph(); if (m_pVideoCodecContext) { avcodec_close(m_pVideoCodecContext); m_pVideoCodecContext = NULL; @@ -93,13 +101,13 @@ } if (m_pPacket) { - av_free_packet(m_pPacket); + av_packet_unref(m_pPacket); delete m_pPacket; m_pPacket = NULL; } if (m_pFrame) { - av_free(m_pFrame); + av_frame_free(&m_pFrame); m_pFrame = NULL; } @@ -239,7 +247,7 @@ return false; } - avcodec_get_frame_defaults(m_pFrame); + av_frame_unref(m_pFrame); int frameFinished = 0; @@ -264,7 +272,7 @@ int attempts = 0; if (m_pPacket) { - av_free_packet(m_pPacket); + av_packet_unref(m_pPacket); delete m_pPacket; } @@ -275,7 +283,7 @@ if (framesAvailable) { frameDecoded = m_pPacket->stream_index == m_VideoStream; if (!frameDecoded) { - av_free_packet(m_pPacket); + av_packet_unref(m_pPacket); } } } @@ -283,15 +291,100 @@ return frameDecoded; } +void MovieDecoder::deleteFilterGraph() +{ + if (m_filterGraph) { + av_frame_free(&m_filterFrame); + avfilter_graph_free(&m_filterGraph); + m_filterGraph = nullptr; + } +} + +bool MovieDecoder::initFilterGraph(enum AVPixelFormat pixfmt, int width, int height) +{ + AVFilterInOut *inputs = nullptr, *outputs = nullptr; + + deleteFilterGraph(); + m_filterGraph = avfilter_graph_alloc(); + + QByteArray arguments("buffer="); + arguments += "video_size=" + QByteArray::number(width) + "x" + QByteArray::number(height) + ":"; + arguments += "pix_fmt=" + QByteArray::number(pixfmt) + ":"; + arguments += "time_base=1/1:pixel_aspect=0/1[in];"; + arguments += "[in]yadif[out];"; + arguments += "[out]buffersink"; + + int ret = avfilter_graph_parse2(m_filterGraph, arguments.constData(), &inputs, &outputs); + if (ret < 0) { + qWarning() << "Unable to parse filter graph"; + return false; + } + + if(inputs || outputs) + return -1; + + ret = avfilter_graph_config(m_filterGraph, nullptr); + if (ret < 0) { + qWarning() << "Unable to validate filter graph"; + return false; + } + + m_bufferSourceContext = avfilter_graph_get_filter(m_filterGraph, "Parsed_buffer_0"); + m_bufferSinkContext = avfilter_graph_get_filter(m_filterGraph, "Parsed_buffersink_2"); + if (!m_bufferSourceContext || !m_bufferSinkContext) { + qWarning() << "Unable to get source or sink"; + return false; + } + m_filterFrame = av_frame_alloc(); + m_lastWidth = width; + m_lastHeight = height; + m_lastPixfmt = pixfmt; + + return true; +} + +bool MovieDecoder::processFilterGraph(AVPicture *dst, const AVPicture *src, + enum AVPixelFormat pixfmt, int width, int height) +{ + if (!m_filterGraph || width != m_lastWidth || + height != m_lastHeight || pixfmt != m_lastPixfmt) { + + if (!initFilterGraph(pixfmt, width, height)) { + return false; + } + } + + memcpy(m_filterFrame->data, src->data, sizeof(src->data)); + memcpy(m_filterFrame->linesize, src->linesize, sizeof(src->linesize)); + m_filterFrame->width = width; + m_filterFrame->height = height; + m_filterFrame->format = pixfmt; + + int ret = av_buffersrc_add_frame(m_bufferSourceContext, m_filterFrame); + if (ret < 0) { + return false; + } + + ret = av_buffersink_get_frame(m_bufferSinkContext, m_filterFrame); + if (ret < 0) { + return false; + } + + av_picture_copy(dst, (const AVPicture *) m_filterFrame, pixfmt, width, height); + av_frame_unref(m_filterFrame); + + return true; +} + void MovieDecoder::getScaledVideoFrame(int scaledSize, bool maintainAspectRatio, VideoFrame& videoFrame) { if (m_pFrame->interlaced_frame) { - avpicture_deinterlace((AVPicture*) m_pFrame, (AVPicture*) m_pFrame, m_pVideoCodecContext->pix_fmt, + processFilterGraph((AVPicture*) m_pFrame, (AVPicture*) m_pFrame, m_pVideoCodecContext->pix_fmt, m_pVideoCodecContext->width, m_pVideoCodecContext->height); } int scaledWidth, scaledHeight; - convertAndScaleFrame(PIX_FMT_RGB24, scaledSize, maintainAspectRatio, scaledWidth, scaledHeight); + convertAndScaleFrame(AV_PIX_FMT_RGB24, scaledSize, maintainAspectRatio, scaledWidth, scaledHeight); videoFrame.width = scaledWidth; videoFrame.height = scaledHeight; @@ -302,7 +395,7 @@ memcpy((&(videoFrame.frameData.front())), m_pFrame->data[0], videoFrame.lineSize * videoFrame.height); } -void MovieDecoder::convertAndScaleFrame(PixelFormat format, int scaledSize, bool maintainAspectRatio, int& scaledWidth, int& scaledHeight) +void MovieDecoder::convertAndScaleFrame(AVPixelFormat format, int scaledSize, bool maintainAspectRatio, int& scaledWidth, int& scaledHeight) { calculateDimensions(scaledSize, maintainAspectRatio, scaledWidth, scaledHeight); SwsContext* scaleContext = sws_getContext(m_pVideoCodecContext->width, m_pVideoCodecContext->height, @@ -323,7 +416,7 @@ convertedFrame->data, convertedFrame->linesize); sws_freeContext(scaleContext); - av_free(m_pFrame); + av_frame_free(&m_pFrame); av_free(m_pFrameBuffer); m_pFrame = convertedFrame; @@ -355,9 +448,9 @@ } } -void MovieDecoder::createAVFrame(AVFrame** avFrame, quint8** frameBuffer, int width, int height, PixelFormat format) -{ - *avFrame = avcodec_alloc_frame(); +void MovieDecoder::createAVFrame(AVFrame** avFrame, quint8** frameBuffer, int width, int height, AVPixelFormat format) +{ + *avFrame = av_frame_alloc(); int numBytes = avpicture_get_size(format, width, height); *frameBuffer = reinterpret_cast(av_malloc(numBytes)); --- a/ffmpegthumbnailer/moviedecoder.h +++ b/ffmpegthumbnailer/moviedecoder.h @@ -23,6 +23,9 @@ extern "C" { #include #include +#include +#include +#include } namespace ffmpegthumbnailer @@ -52,9 +55,13 @@ bool decodeVideoPacket(); bool getVideoPacket(); - void convertAndScaleFrame(PixelFormat format, int scaledSize, bool maintainAspectRatio, int& scaledWidth, int& scaledHeight); - void createAVFrame(AVFrame** avFrame, quint8** frameBuffer, int width, int height, PixelFormat format); + void convertAndScaleFrame(AVPixelFormat format, int scaledSize, bool maintainAspectRatio, int& scaledWidth, int& scaledHeight); + void createAVFrame(AVFrame** avFrame, quint8** frameBuffer, int width, int height, AVPixelFormat format); void calculateDimensions(int squareSize, bool maintainAspectRatio, int& destWidth, int& destHeight); + + void deleteFilterGraph(); + bool initFilterGraph(enum AVPixelFormat pixfmt, int width, int height); + bool processFilterGraph(AVPicture *dst, const AVPicture *src, enum AVPixelFormat pixfmt, int width, int height); private: int m_VideoStream; @@ -68,6 +75,13 @@ bool m_FormatContextWasGiven; bool m_AllowSeek; bool m_initialized; + AVFilterContext* m_bufferSinkContext; + AVFilterContext* m_bufferSourceContext; + AVFilterGraph* m_filterGraph; + AVFrame* m_filterFrame; + int m_lastWidth; + int m_lastHeight; + enum AVPixelFormat m_lastPixfmt; }; } --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -19,7 +19,7 @@ add_executable(ffmpegthumbtest ${ffmpegthumbtest_SRCS} ) -target_link_libraries(ffmpegthumbtest Qt5::Gui KF5::KIOWidgets ${AVUTIL_LIBRARIES} ${AVFORMAT_LIBRARIES} ${AVCODEC_LIBRARIES} ${SWSCALE_LIBRARIES}) +target_link_libraries(ffmpegthumbtest Qt5::Gui KF5::KIOWidgets ${AVUTIL_LIBRARIES} ${AVFILTER_LIBRARIES} ${AVFORMAT_LIBRARIES} ${AVCODEC_LIBRARIES} ${SWSCALE_LIBRARIES})