1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
|
Fix build with ffmpeg>=2.9
Obtained from: https://git.reviewboard.kde.org/r/126992
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 48eed64d76f0542327c8dbce9644e5cc898c8cbc..3c761fa584497e6aba9065e195533b1bf8498648 100644
--- CMakeLists.txt
+++ CMakeLists.txt
@@ -27,7 +27,7 @@ set( ffmpegthumbs_PART_SRCS
kde4_add_plugin(ffmpegthumbs ${ffmpegthumbs_PART_SRCS})
-target_link_libraries(ffmpegthumbs ${KDE4_KIO_LIBS} ${AVUTIL_LIBRARIES} ${AVFORMAT_LIBRARIES} ${AVCODEC_LIBRARIES} ${SWSCALE_LIBRARIES} )
+target_link_libraries(ffmpegthumbs ${KDE4_KIO_LIBS} ${AVUTIL_LIBRARIES} ${AVFILTER_LIBRARIES} ${AVFORMAT_LIBRARIES} ${AVCODEC_LIBRARIES} ${SWSCALE_LIBRARIES} )
install(TARGETS ffmpegthumbs DESTINATION ${PLUGIN_INSTALL_DIR})
diff --git a/cmake/FindFFmpeg.cmake b/cmake/FindFFmpeg.cmake
index 27c6b16de7cfd7514a9a2c273dcd242670248613..915ab5f9f9618c460560342b564963e701a5efd8 100644
--- cmake/FindFFmpeg.cmake
+++ cmake/FindFFmpeg.cmake
@@ -99,6 +99,7 @@ if (NOT FFMPEG_LIBRARIES)
# 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)
diff --git a/ffmpegthumbnailer/moviedecoder.h b/ffmpegthumbnailer/moviedecoder.h
index 288892685b6ae6946f158deacab1eeded5745cb6..b4a76b81724dd5956eb2be61ab7470b2ed351a4c 100644
--- ffmpegthumbnailer/moviedecoder.h
+++ ffmpegthumbnailer/moviedecoder.h
@@ -23,6 +23,9 @@
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
+#include <libavfilter/avfilter.h>
+#include <libavfilter/buffersrc.h>
+#include <libavfilter/buffersink.h>
}
namespace ffmpegthumbnailer
@@ -52,10 +55,14 @@ private:
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 delete_filter_graph();
+ int init_filter_graph(enum AVPixelFormat pixfmt, int width, int height);
+ int process_filter_graph(AVPicture *dst, const AVPicture *src, enum AVPixelFormat pixfmt, int width, int height);
+
private:
int m_VideoStream;
AVFormatContext* m_pFormatContext;
@@ -68,6 +75,13 @@ private:
bool m_FormatContextWasGiven;
bool m_AllowSeek;
bool m_initialized;
+ AVFilterContext* m_buffersink_ctx;
+ AVFilterContext* m_buffersrc_ctx;
+ AVFilterGraph* m_filter_graph;
+ AVFrame* m_filter_frame;
+ int m_last_width;
+ int m_last_height;
+ enum AVPixelFormat m_last_pixfmt;
};
}
diff --git a/ffmpegthumbnailer/moviedecoder.cpp b/ffmpegthumbnailer/moviedecoder.cpp
index c8ae6d1acd2876cabb5c0594b52f676486be707e..59ae79480575f2394d1f1b7d6dceb5daa7d6e4b7 100644
--- ffmpegthumbnailer/moviedecoder.cpp
+++ ffmpegthumbnailer/moviedecoder.cpp
@@ -51,6 +51,9 @@ MovieDecoder::~MovieDecoder()
void MovieDecoder::initialize(const QString& filename)
{
+ m_last_width = -1;
+ m_last_height = -1;
+ m_last_pixfmt = AV_PIX_FMT_NONE;
av_register_all();
avcodec_register_all();
@@ -67,7 +70,7 @@ void MovieDecoder::initialize(const QString& filename)
}
initializeVideo();
- m_pFrame = avcodec_alloc_frame();
+ m_pFrame = av_frame_alloc();
if (m_pFrame) {
m_initialized=true;
@@ -82,6 +85,7 @@ bool MovieDecoder::getInitialized()
void MovieDecoder::destroy()
{
+ delete_filter_graph();
if (m_pVideoCodecContext) {
avcodec_close(m_pVideoCodecContext);
m_pVideoCodecContext = NULL;
@@ -99,7 +103,7 @@ void MovieDecoder::destroy()
}
if (m_pFrame) {
- av_free(m_pFrame);
+ av_frame_free(&m_pFrame);
m_pFrame = NULL;
}
@@ -239,7 +243,7 @@ bool MovieDecoder::decodeVideoPacket()
return false;
}
- avcodec_get_frame_defaults(m_pFrame);
+ av_frame_unref(m_pFrame);
int frameFinished = 0;
@@ -283,15 +287,83 @@ bool MovieDecoder::getVideoPacket()
return frameDecoded;
}
+void MovieDecoder::delete_filter_graph() {
+ if (m_filter_graph) {
+ av_frame_free(&m_filter_frame);
+ avfilter_graph_free(&m_filter_graph);
+ }
+}
+
+int MovieDecoder::init_filter_graph(enum AVPixelFormat pixfmt, int width, int height) {
+ AVFilterInOut *inputs = NULL, *outputs = NULL;
+ char args[512];
+ int res;
+
+ delete_filter_graph();
+ m_filter_graph = avfilter_graph_alloc();
+ snprintf(args, sizeof(args),
+ "buffer=video_size=%dx%d:pix_fmt=%d:time_base=1/1:pixel_aspect=0/1[in];"
+ "[in]yadif[out];"
+ "[out]buffersink",
+ width, height, pixfmt);
+ res = avfilter_graph_parse2(m_filter_graph, args, &inputs, &outputs);
+ if (res < 0)
+ return res;
+ if(inputs || outputs)
+ return -1;
+ res = avfilter_graph_config(m_filter_graph, NULL);
+ if (res < 0)
+ return res;
+
+ m_buffersrc_ctx = avfilter_graph_get_filter(m_filter_graph, "Parsed_buffer_0");
+ m_buffersink_ctx = avfilter_graph_get_filter(m_filter_graph, "Parsed_buffersink_2");
+ if (!m_buffersrc_ctx || !m_buffersink_ctx)
+ return -1;
+ m_filter_frame = av_frame_alloc();
+ m_last_width = width;
+ m_last_height = height;
+ m_last_pixfmt = pixfmt;
+
+ return 0;
+}
+
+int MovieDecoder::process_filter_graph(AVPicture *dst, const AVPicture *src,
+ enum AVPixelFormat pixfmt, int width, int height) {
+ int res;
+
+ if (!m_filter_graph || width != m_last_width ||
+ height != m_last_height || pixfmt != m_last_pixfmt) {
+ res = init_filter_graph(pixfmt, width, height);
+ if (res < 0)
+ return res;
+ }
+
+ memcpy(m_filter_frame->data, src->data, sizeof(src->data));
+ memcpy(m_filter_frame->linesize, src->linesize, sizeof(src->linesize));
+ m_filter_frame->width = width;
+ m_filter_frame->height = height;
+ m_filter_frame->format = pixfmt;
+ res = av_buffersrc_add_frame(m_buffersrc_ctx, m_filter_frame);
+ if (res < 0)
+ return res;
+ res = av_buffersink_get_frame(m_buffersink_ctx, m_filter_frame);
+ if (res < 0)
+ return res;
+ av_picture_copy(dst, (const AVPicture *) m_filter_frame, pixfmt, width, height);
+ av_frame_unref(m_filter_frame);
+
+ return 0;
+}
+
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,
+ process_filter_graph((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 +374,7 @@ void MovieDecoder::getScaledVideoFrame(int scaledSize, bool maintainAspectRatio,
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 +395,7 @@ void MovieDecoder::convertAndScaleFrame(PixelFormat format, int scaledSize, bool
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 +427,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);
*frameBuffer = reinterpret_cast<quint8*>(av_malloc(numBytes));
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 1728fcdd14b699b8f4d7e9a9ffcd8ddc11f495c6..b46169a6274af3e75bd303434a6ce82c928875a0 100644
--- tests/CMakeLists.txt
+++ tests/CMakeLists.txt
@@ -19,7 +19,7 @@ set(ffmpegthumbtest_SRCS ffmpegthumbtest.cpp
kde4_add_executable(ffmpegthumbtest ${ffmpegthumbtest_SRCS} )
-target_link_libraries(ffmpegthumbtest ${KDE4_KDECORE_LIBS} ${KDE4_KIO_LIBS} ${AVUTIL_LIBRARIES} ${AVFORMAT_LIBRARIES} ${AVCODEC_LIBRARIES} ${SWSCALE_LIBRARIES})
+target_link_libraries(ffmpegthumbtest ${KDE4_KDECORE_LIBS} ${KDE4_KIO_LIBS} ${AVUTIL_LIBRARIES} ${AVFILTER_LIBRARIES} ${AVFORMAT_LIBRARIES} ${AVCODEC_LIBRARIES} ${SWSCALE_LIBRARIES})
|