Port to libavfilter for deinterlacing.

Based on a patch from Andreas Cadhalpun
<andreas.cadhalpun@googlemail.com>.
parent 4996f994
...@@ -36,7 +36,7 @@ set( ffmpegthumbs_PART_SRCS ...@@ -36,7 +36,7 @@ set( ffmpegthumbs_PART_SRCS
add_library(ffmpegthumbs MODULE ${ffmpegthumbs_PART_SRCS}) 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}) install(TARGETS ffmpegthumbs DESTINATION ${PLUGIN_INSTALL_DIR})
......
...@@ -99,6 +99,7 @@ if (NOT FFMPEG_LIBRARIES) ...@@ -99,6 +99,7 @@ if (NOT FFMPEG_LIBRARIES)
# Check for all possible component. # Check for all possible component.
find_component(AVCODEC libavcodec avcodec libavcodec/avcodec.h) 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(AVFORMAT libavformat avformat libavformat/avformat.h)
find_component(AVDEVICE libavdevice avdevice libavdevice/avdevice.h) find_component(AVDEVICE libavdevice avdevice libavdevice/avdevice.h)
find_component(AVUTIL libavutil avutil libavutil/avutil.h) find_component(AVUTIL libavutil avutil libavutil/avutil.h)
......
...@@ -40,6 +40,10 @@ MovieDecoder::MovieDecoder(const QString& filename, AVFormatContext* pavContext) ...@@ -40,6 +40,10 @@ MovieDecoder::MovieDecoder(const QString& filename, AVFormatContext* pavContext)
, m_FormatContextWasGiven(pavContext != NULL) , m_FormatContextWasGiven(pavContext != NULL)
, m_AllowSeek(true) , m_AllowSeek(true)
, m_initialized(false) , m_initialized(false)
, m_bufferSinkContext(nullptr)
, m_bufferSourceContext(nullptr)
, m_filterGraph(nullptr)
, m_filterFrame(nullptr)
{ {
initialize(filename); initialize(filename);
} }
...@@ -51,6 +55,9 @@ MovieDecoder::~MovieDecoder() ...@@ -51,6 +55,9 @@ MovieDecoder::~MovieDecoder()
void MovieDecoder::initialize(const QString& filename) void MovieDecoder::initialize(const QString& filename)
{ {
m_lastWidth = -1;
m_lastHeight = -1;
m_lastPixfmt = AV_PIX_FMT_NONE;
av_register_all(); av_register_all();
avcodec_register_all(); avcodec_register_all();
...@@ -67,7 +74,7 @@ void MovieDecoder::initialize(const QString& filename) ...@@ -67,7 +74,7 @@ void MovieDecoder::initialize(const QString& filename)
} }
initializeVideo(); initializeVideo();
m_pFrame = avcodec_alloc_frame(); m_pFrame = av_frame_alloc();
if (m_pFrame) { if (m_pFrame) {
m_initialized=true; m_initialized=true;
...@@ -82,6 +89,7 @@ bool MovieDecoder::getInitialized() ...@@ -82,6 +89,7 @@ bool MovieDecoder::getInitialized()
void MovieDecoder::destroy() void MovieDecoder::destroy()
{ {
deleteFilterGraph();
if (m_pVideoCodecContext) { if (m_pVideoCodecContext) {
avcodec_close(m_pVideoCodecContext); avcodec_close(m_pVideoCodecContext);
m_pVideoCodecContext = NULL; m_pVideoCodecContext = NULL;
...@@ -93,13 +101,13 @@ void MovieDecoder::destroy() ...@@ -93,13 +101,13 @@ void MovieDecoder::destroy()
} }
if (m_pPacket) { if (m_pPacket) {
av_free_packet(m_pPacket); av_packet_unref(m_pPacket);
delete m_pPacket; delete m_pPacket;
m_pPacket = NULL; m_pPacket = NULL;
} }
if (m_pFrame) { if (m_pFrame) {
av_free(m_pFrame); av_frame_free(&m_pFrame);
m_pFrame = NULL; m_pFrame = NULL;
} }
...@@ -239,7 +247,7 @@ bool MovieDecoder::decodeVideoPacket() ...@@ -239,7 +247,7 @@ bool MovieDecoder::decodeVideoPacket()
return false; return false;
} }
avcodec_get_frame_defaults(m_pFrame); av_frame_unref(m_pFrame);
int frameFinished = 0; int frameFinished = 0;
...@@ -264,7 +272,7 @@ bool MovieDecoder::getVideoPacket() ...@@ -264,7 +272,7 @@ bool MovieDecoder::getVideoPacket()
int attempts = 0; int attempts = 0;
if (m_pPacket) { if (m_pPacket) {
av_free_packet(m_pPacket); av_packet_unref(m_pPacket);
delete m_pPacket; delete m_pPacket;
} }
...@@ -275,7 +283,7 @@ bool MovieDecoder::getVideoPacket() ...@@ -275,7 +283,7 @@ bool MovieDecoder::getVideoPacket()
if (framesAvailable) { if (framesAvailable) {
frameDecoded = m_pPacket->stream_index == m_VideoStream; frameDecoded = m_pPacket->stream_index == m_VideoStream;
if (!frameDecoded) { if (!frameDecoded) {
av_free_packet(m_pPacket); av_packet_unref(m_pPacket);
} }
} }
} }
...@@ -283,15 +291,100 @@ bool MovieDecoder::getVideoPacket() ...@@ -283,15 +291,100 @@ bool MovieDecoder::getVideoPacket()
return frameDecoded; 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) void MovieDecoder::getScaledVideoFrame(int scaledSize, bool maintainAspectRatio, VideoFrame& videoFrame)
{ {
if (m_pFrame->interlaced_frame) { 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); m_pVideoCodecContext->width, m_pVideoCodecContext->height);
} }
int scaledWidth, scaledHeight; int scaledWidth, scaledHeight;
convertAndScaleFrame(PIX_FMT_RGB24, scaledSize, maintainAspectRatio, scaledWidth, scaledHeight); convertAndScaleFrame(AV_PIX_FMT_RGB24, scaledSize, maintainAspectRatio, scaledWidth, scaledHeight);
videoFrame.width = scaledWidth; videoFrame.width = scaledWidth;
videoFrame.height = scaledHeight; videoFrame.height = scaledHeight;
...@@ -302,7 +395,7 @@ void MovieDecoder::getScaledVideoFrame(int scaledSize, bool maintainAspectRatio, ...@@ -302,7 +395,7 @@ void MovieDecoder::getScaledVideoFrame(int scaledSize, bool maintainAspectRatio,
memcpy((&(videoFrame.frameData.front())), m_pFrame->data[0], videoFrame.lineSize * videoFrame.height); 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); calculateDimensions(scaledSize, maintainAspectRatio, scaledWidth, scaledHeight);
SwsContext* scaleContext = sws_getContext(m_pVideoCodecContext->width, m_pVideoCodecContext->height, SwsContext* scaleContext = sws_getContext(m_pVideoCodecContext->width, m_pVideoCodecContext->height,
...@@ -323,7 +416,7 @@ void MovieDecoder::convertAndScaleFrame(PixelFormat format, int scaledSize, bool ...@@ -323,7 +416,7 @@ void MovieDecoder::convertAndScaleFrame(PixelFormat format, int scaledSize, bool
convertedFrame->data, convertedFrame->linesize); convertedFrame->data, convertedFrame->linesize);
sws_freeContext(scaleContext); sws_freeContext(scaleContext);
av_free(m_pFrame); av_frame_free(&m_pFrame);
av_free(m_pFrameBuffer); av_free(m_pFrameBuffer);
m_pFrame = convertedFrame; m_pFrame = convertedFrame;
...@@ -355,9 +448,9 @@ void MovieDecoder::calculateDimensions(int squareSize, bool maintainAspectRatio, ...@@ -355,9 +448,9 @@ void MovieDecoder::calculateDimensions(int squareSize, bool maintainAspectRatio,
} }
} }
void MovieDecoder::createAVFrame(AVFrame** avFrame, quint8** frameBuffer, int width, int height, PixelFormat format) void MovieDecoder::createAVFrame(AVFrame** avFrame, quint8** frameBuffer, int width, int height, AVPixelFormat format)
{ {
*avFrame = avcodec_alloc_frame(); *avFrame = av_frame_alloc();
int numBytes = avpicture_get_size(format, width, height); int numBytes = avpicture_get_size(format, width, height);
*frameBuffer = reinterpret_cast<quint8*>(av_malloc(numBytes)); *frameBuffer = reinterpret_cast<quint8*>(av_malloc(numBytes));
......
...@@ -23,6 +23,9 @@ ...@@ -23,6 +23,9 @@
extern "C" { extern "C" {
#include <libavcodec/avcodec.h> #include <libavcodec/avcodec.h>
#include <libavformat/avformat.h> #include <libavformat/avformat.h>
#include <libavfilter/avfilter.h>
#include <libavfilter/buffersrc.h>
#include <libavfilter/buffersink.h>
} }
namespace ffmpegthumbnailer namespace ffmpegthumbnailer
...@@ -52,10 +55,14 @@ private: ...@@ -52,10 +55,14 @@ private:
bool decodeVideoPacket(); bool decodeVideoPacket();
bool getVideoPacket(); bool getVideoPacket();
void convertAndScaleFrame(PixelFormat format, int scaledSize, bool maintainAspectRatio, int& scaledWidth, int& scaledHeight); void convertAndScaleFrame(AVPixelFormat format, int scaledSize, bool maintainAspectRatio, int& scaledWidth, int& scaledHeight);
void createAVFrame(AVFrame** avFrame, quint8** frameBuffer, int width, int height, PixelFormat format); void createAVFrame(AVFrame** avFrame, quint8** frameBuffer, int width, int height, AVPixelFormat format);
void calculateDimensions(int squareSize, bool maintainAspectRatio, int& destWidth, int& destHeight); 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: private:
int m_VideoStream; int m_VideoStream;
AVFormatContext* m_pFormatContext; AVFormatContext* m_pFormatContext;
...@@ -68,6 +75,13 @@ private: ...@@ -68,6 +75,13 @@ private:
bool m_FormatContextWasGiven; bool m_FormatContextWasGiven;
bool m_AllowSeek; bool m_AllowSeek;
bool m_initialized; 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;
}; };
} }
......
...@@ -19,7 +19,7 @@ set(ffmpegthumbtest_SRCS ffmpegthumbtest.cpp ...@@ -19,7 +19,7 @@ set(ffmpegthumbtest_SRCS ffmpegthumbtest.cpp
add_executable(ffmpegthumbtest ${ffmpegthumbtest_SRCS} ) 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})
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment