]>
Commit | Line | Data |
---|---|---|
1b264c50 JR |
1 | diff -ur tvheadend-4.0.8.orig/configure tvheadend-4.0.8/configure |
2 | --- tvheadend-4.0.8.orig/configure 2015-12-16 18:33:33.000000000 +0100 | |
3 | +++ tvheadend-4.0.8/configure 2016-04-16 19:41:41.685840403 +0200 | |
4 | @@ -395,7 +395,7 @@ | |
5 | has_libav=false | |
6 | fi | |
7 | ||
8 | - if $has_libav && ! check_pkg libswscale ">=2.3.100"; then | |
9 | + if $has_libav && ! check_pkg libavfilter ">=4.0.0"; then | |
10 | has_libav=false | |
11 | fi | |
12 | ||
13 | @@ -421,7 +421,7 @@ | |
14 | has_libav=false | |
15 | fi | |
16 | ||
17 | - if $has_libav && ! check_pkg libswscale ">=2.1.2"; then | |
18 | + if $has_libav && ! check_pkg libavfilter ">=4.0.0"; then | |
19 | has_libav=false | |
20 | fi | |
21 | ||
22 | diff -ur tvheadend-4.0.8.orig/Makefile tvheadend-4.0.8/Makefile | |
23 | --- tvheadend-4.0.8.orig/Makefile 2015-12-16 18:33:33.000000000 +0100 | |
24 | +++ tvheadend-4.0.8/Makefile 2016-04-16 19:41:41.685840403 +0200 | |
25 | @@ -60,7 +60,7 @@ | |
26 | LDFLAGS_FFDIR = ${ROOTDIR}/libav_static/build/ffmpeg/lib | |
27 | LDFLAGS += ${LDFLAGS_FFDIR}/libavresample.a | |
28 | LDFLAGS += ${LDFLAGS_FFDIR}/libswresample.a | |
29 | -LDFLAGS += ${LDFLAGS_FFDIR}/libswscale.a | |
30 | +LDFLAGS += ${LDFLAGS_FFDIR}/libavfilter.a | |
31 | LDFLAGS += ${LDFLAGS_FFDIR}/libavutil.a | |
32 | LDFLAGS += ${LDFLAGS_FFDIR}/libavformat.a | |
33 | LDFLAGS += ${LDFLAGS_FFDIR}/libavcodec.a | |
34 | diff -ur tvheadend-4.0.8.orig/Makefile.ffmpeg tvheadend-4.0.8/Makefile.ffmpeg | |
35 | --- tvheadend-4.0.8.orig/Makefile.ffmpeg 2015-12-16 18:33:33.000000000 +0100 | |
36 | +++ tvheadend-4.0.8/Makefile.ffmpeg 2016-04-16 19:41:41.685840403 +0200 | |
37 | @@ -60,7 +60,7 @@ | |
38 | FFMPEG_SHA1 = 65470c9b967485f72f81758a7bad44cf7a1763db | |
39 | ||
40 | EXTLIBS = libx264 libvorbis libvpx | |
41 | -COMPONENTS = avutil avformat avcodec swresample swscale avresample | |
42 | +COMPONENTS = avutil avformat avcodec swresample avfilter avresample | |
43 | PROTOCOLS = file | |
44 | DECODERS = mpeg2video mp2 ac3 eac3 h264 h264_vdpau aac aac_latm vorbis libvorbis | |
45 | ENCODERS = mpeg2video mp2 libx264 libvpx_vp8 libvpx_vp9 aac libaacplus vorbis libvorbis | |
46 | diff -ur tvheadend-4.0.8.orig/src/libav.c tvheadend-4.0.8/src/libav.c | |
47 | --- tvheadend-4.0.8.orig/src/libav.c 2015-12-16 18:33:33.000000000 +0100 | |
48 | +++ tvheadend-4.0.8/src/libav.c 2016-04-16 19:44:03.666521276 +0200 | |
49 | @@ -186,4 +186,5 @@ | |
50 | av_log_set_callback(libav_log_callback); | |
51 | av_log_set_level(AV_LOG_VERBOSE); | |
52 | av_register_all(); | |
53 | + avfilter_register_all(); | |
54 | } | |
55 | diff -ur tvheadend-4.0.8.orig/src/libav.h tvheadend-4.0.8/src/libav.h | |
56 | --- tvheadend-4.0.8.orig/src/libav.h 2015-12-16 18:33:33.000000000 +0100 | |
57 | +++ tvheadend-4.0.8/src/libav.h 2016-04-16 19:41:41.685840403 +0200 | |
58 | @@ -21,6 +21,7 @@ | |
59 | ||
60 | ||
61 | #include <libavformat/avformat.h> | |
62 | +#include <libavfilter/avfilter.h> | |
63 | #include "tvheadend.h" | |
64 | ||
65 | /* | |
66 | diff -ur tvheadend-4.0.8.orig/src/plumbing/transcoding.c tvheadend-4.0.8/src/plumbing/transcoding.c | |
67 | --- tvheadend-4.0.8.orig/src/plumbing/transcoding.c 2015-12-16 18:33:33.000000000 +0100 | |
68 | +++ tvheadend-4.0.8/src/plumbing/transcoding.c 2016-04-16 19:53:13.907273675 +0200 | |
69 | @@ -19,12 +19,14 @@ | |
70 | #include <unistd.h> | |
71 | #include <libavformat/avformat.h> | |
72 | #include <libavcodec/avcodec.h> | |
73 | -#include <libswscale/swscale.h> | |
74 | +#include <libavfilter/avfiltergraph.h> | |
75 | +#include <libavfilter/buffersink.h> | |
76 | +#include <libavfilter/buffersrc.h> | |
77 | +#include <libavutil/opt.h> | |
78 | #include <libavresample/avresample.h> | |
79 | #include <libavutil/opt.h> | |
80 | #include <libavutil/audio_fifo.h> | |
81 | #include <libavutil/dict.h> | |
82 | -#include <libavutil/audioconvert.h> | |
83 | ||
84 | #if LIBAVUTIL_VERSION_MICRO >= 100 /* FFMPEG */ | |
85 | #define USING_FFMPEG 1 | |
86 | @@ -91,9 +93,12 @@ | |
87 | AVCodec *vid_ocodec; | |
88 | ||
89 | AVFrame *vid_dec_frame; | |
90 | - struct SwsContext *vid_scaler; | |
91 | AVFrame *vid_enc_frame; | |
92 | ||
93 | + AVFilterGraph *flt_graph; | |
94 | + AVFilterContext *flt_bufsrcctx; | |
95 | + AVFilterContext *flt_bufsinkctx; | |
96 | + | |
97 | int16_t vid_width; | |
98 | int16_t vid_height; | |
99 | ||
1b264c50 JR |
100 | @@ -952,6 +957,114 @@ |
101 | ||
102 | } | |
103 | ||
104 | +/* create a simple deinterlacer-scaler video filter chain */ | |
105 | +static int | |
106 | +create_video_filter(video_stream_t *vs, transcoder_t *t, | |
107 | + AVCodecContext *ictx, AVCodecContext *octx) | |
108 | +{ | |
109 | + AVFilterInOut *flt_inputs, *flt_outputs; | |
110 | + AVFilter *flt_bufsrc, *flt_bufsink; | |
111 | + char opt[128]; | |
112 | + int err; | |
113 | + | |
114 | + err = 1; | |
115 | + flt_inputs = flt_outputs = NULL; | |
116 | + flt_bufsrc = flt_bufsink = NULL; | |
117 | + | |
118 | + if (vs->flt_graph) | |
119 | + avfilter_graph_free(&vs->flt_graph); | |
120 | + | |
121 | + vs->flt_graph = avfilter_graph_alloc(); | |
122 | + if (!vs->flt_graph) | |
123 | + return err; | |
124 | + | |
125 | + flt_inputs = avfilter_inout_alloc(); | |
126 | + if (!flt_inputs) | |
127 | + goto out_err; | |
128 | + | |
129 | + flt_outputs = avfilter_inout_alloc(); | |
130 | + if (!flt_outputs) | |
131 | + goto out_err; | |
132 | + | |
133 | + flt_bufsrc = avfilter_get_by_name("buffer"); | |
134 | + flt_bufsink = avfilter_get_by_name("buffersink"); | |
135 | + if (!flt_bufsrc || !flt_bufsink) { | |
136 | + tvherror("transcode", "%04X: libav default buffers unknown", shortid(t)); | |
137 | + goto out_err; | |
138 | + } | |
139 | + | |
140 | + memset(opt, 0, sizeof(opt)); | |
141 | + snprintf(opt, sizeof(opt), "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d", | |
142 | + ictx->width, | |
143 | + ictx->height, | |
144 | + ictx->pix_fmt, | |
145 | + ictx->time_base.num, | |
146 | + ictx->time_base.den, | |
147 | + ictx->sample_aspect_ratio.num, | |
148 | + ictx->sample_aspect_ratio.den); | |
149 | + | |
150 | + err = avfilter_graph_create_filter(&vs->flt_bufsrcctx, flt_bufsrc, "in", | |
151 | + opt, NULL, vs->flt_graph); | |
152 | + if (err < 0) { | |
153 | + tvherror("transcode", "%04X: fltchain IN init error", shortid(t)); | |
154 | + goto out_err; | |
155 | + } | |
156 | + | |
157 | + err = avfilter_graph_create_filter(&vs->flt_bufsinkctx, flt_bufsink, | |
158 | + "out", NULL, NULL, vs->flt_graph); | |
159 | + if (err < 0) { | |
160 | + tvherror("transcode", "%04X: fltchain OUT init error", shortid(t)); | |
161 | + goto out_err; | |
162 | + } | |
163 | + | |
164 | + flt_outputs->name = av_strdup("in"); | |
165 | + flt_outputs->filter_ctx = vs->flt_bufsrcctx; | |
166 | + flt_outputs->pad_idx = 0; | |
167 | + flt_outputs->next = NULL; | |
168 | + flt_inputs->name = av_strdup("out"); | |
169 | + flt_inputs->filter_ctx = vs->flt_bufsinkctx; | |
170 | + flt_inputs->pad_idx = 0; | |
171 | + flt_inputs->next = NULL; | |
172 | + | |
173 | + /* add filters: yadif to deinterlace and a scaler */ | |
174 | + memset(opt, 0, sizeof(opt)); | |
175 | + snprintf(opt, sizeof(opt), "yadif,scale=%dx%d", | |
176 | + octx->width, | |
177 | + octx->height); | |
178 | + err = avfilter_graph_parse_ptr(vs->flt_graph, | |
179 | + opt, | |
180 | + &flt_inputs, | |
181 | + &flt_outputs, | |
182 | + NULL); | |
183 | + if (err < 0) { | |
184 | + tvherror("transcode", "%04X: failed to init filter chain", shortid(t)); | |
185 | + goto out_err; | |
186 | + } | |
187 | + | |
188 | + err = avfilter_graph_config(vs->flt_graph, NULL); | |
189 | + if (err < 0) { | |
190 | + tvherror("transcode", "%04X: failed to config filter chain", shortid(t)); | |
191 | + goto out_err; | |
192 | + } | |
193 | + | |
194 | + avfilter_inout_free(&flt_inputs); | |
195 | + avfilter_inout_free(&flt_outputs); | |
196 | + | |
197 | + return 0; /* all OK */ | |
198 | + | |
199 | +out_err: | |
200 | + if (flt_inputs) | |
201 | + avfilter_inout_free(&flt_inputs); | |
202 | + if (flt_outputs) | |
203 | + avfilter_inout_free(&flt_outputs); | |
204 | + if (vs->flt_graph) { | |
205 | + avfilter_graph_free(&vs->flt_graph); | |
206 | + vs->flt_graph = NULL; | |
207 | + } | |
208 | + | |
209 | + return err; | |
210 | +} | |
211 | + | |
212 | /** | |
213 | * | |
214 | */ | |
215 | @@ -962,9 +1075,7 @@ | |
216 | AVCodecContext *ictx, *octx; | |
217 | AVDictionary *opts; | |
218 | AVPacket packet, packet2; | |
219 | - AVPicture deint_pic; | |
220 | - uint8_t *buf, *deint; | |
221 | - int length, len, ret, got_picture, got_output, got_ref; | |
222 | + int length, ret, got_picture, got_output, got_ref; | |
223 | video_stream_t *vs = (video_stream_t*)ts; | |
224 | streaming_message_t *sm; | |
225 | th_pkt_t *pkt2; | |
226 | @@ -980,7 +1091,6 @@ | |
227 | icodec = vs->vid_icodec; | |
228 | ocodec = vs->vid_ocodec; | |
229 | ||
230 | - buf = deint = NULL; | |
231 | opts = NULL; | |
232 | ||
233 | got_ref = 0; | |
234 | @@ -1061,7 +1171,7 @@ | |
235 | switch (ts->ts_type) { | |
236 | case SCT_MPEG2VIDEO: | |
237 | octx->codec_id = AV_CODEC_ID_MPEG2VIDEO; | |
238 | - octx->pix_fmt = PIX_FMT_YUV420P; | |
239 | + octx->pix_fmt = AV_PIX_FMT_YUV420P; | |
240 | octx->flags |= CODEC_FLAG_GLOBAL_HEADER; | |
241 | ||
242 | // Default settings for quantizer. Best quality unless changed by the streaming profile. | |
243 | @@ -1089,7 +1199,7 @@ | |
244 | ||
245 | case SCT_VP8: | |
246 | octx->codec_id = AV_CODEC_ID_VP8; | |
247 | - octx->pix_fmt = PIX_FMT_YUV420P; | |
248 | + octx->pix_fmt = AV_PIX_FMT_YUV420P; | |
249 | ||
250 | av_dict_set(&opts, "quality", "realtime", 0); | |
251 | ||
252 | @@ -1120,7 +1230,7 @@ | |
253 | ||
254 | case SCT_H264: | |
255 | octx->codec_id = AV_CODEC_ID_H264; | |
256 | - octx->pix_fmt = PIX_FMT_YUV420P; | |
257 | + octx->pix_fmt = AV_PIX_FMT_YUV420P; | |
258 | octx->flags |= CODEC_FLAG_GLOBAL_HEADER; | |
259 | ||
260 | // Qscale difference between I-frames and P-frames. | |
261 | @@ -1177,79 +1287,53 @@ | |
262 | transcoder_stream_invalidate(ts); | |
263 | goto cleanup; | |
264 | } | |
265 | - } | |
266 | ||
267 | - len = avpicture_get_size(ictx->pix_fmt, ictx->width, ictx->height); | |
268 | - deint = av_malloc(len); | |
269 | - | |
270 | - avpicture_fill(&deint_pic, | |
271 | - deint, | |
272 | - ictx->pix_fmt, | |
273 | - ictx->width, | |
274 | - ictx->height); | |
275 | - | |
276 | - if (avpicture_deinterlace(&deint_pic, | |
277 | - (AVPicture *)vs->vid_dec_frame, | |
278 | - ictx->pix_fmt, | |
279 | - ictx->width, | |
280 | - ictx->height) < 0) { | |
281 | - tvherror("transcode", "%04X: Cannot deinterlace frame", shortid(t)); | |
282 | - transcoder_stream_invalidate(ts); | |
283 | - goto cleanup; | |
284 | + if (create_video_filter(vs, t, ictx, octx)) { | |
285 | + tvherror("transcode", "%04X: Video filter creation failed", | |
286 | + shortid(t)); | |
287 | + transcoder_stream_invalidate(ts); | |
288 | + goto cleanup; | |
289 | + } | |
290 | } | |
291 | ||
292 | - len = avpicture_get_size(octx->pix_fmt, octx->width, octx->height); | |
293 | - buf = av_malloc(len + FF_INPUT_BUFFER_PADDING_SIZE); | |
294 | - memset(buf, 0, len); | |
295 | - | |
296 | - avpicture_fill((AVPicture *)vs->vid_enc_frame, | |
297 | - buf, | |
298 | - octx->pix_fmt, | |
299 | - octx->width, | |
300 | - octx->height); | |
301 | - | |
302 | - vs->vid_scaler = sws_getCachedContext(vs->vid_scaler, | |
303 | - ictx->width, | |
304 | - ictx->height, | |
305 | - ictx->pix_fmt, | |
306 | - octx->width, | |
307 | - octx->height, | |
308 | - octx->pix_fmt, | |
309 | - 1, | |
310 | - NULL, | |
311 | - NULL, | |
312 | - NULL); | |
313 | - | |
314 | - if (sws_scale(vs->vid_scaler, | |
315 | - (const uint8_t * const*)deint_pic.data, | |
316 | - deint_pic.linesize, | |
317 | - 0, | |
318 | - ictx->height, | |
319 | - vs->vid_enc_frame->data, | |
320 | - vs->vid_enc_frame->linesize) < 0) { | |
321 | - tvherror("transcode", "%04X: Cannot scale frame", shortid(t)); | |
322 | + /* push decoded frame into filter chain */ | |
323 | + if (av_buffersrc_add_frame(vs->flt_bufsrcctx, vs->vid_dec_frame) < 0) { | |
324 | + tvherror("transcode", "%04X: filter input error", shortid(t)); | |
325 | transcoder_stream_invalidate(ts); | |
326 | goto cleanup; | |
327 | } | |
328 | ||
329 | - vs->vid_enc_frame->format = octx->pix_fmt; | |
330 | - vs->vid_enc_frame->width = octx->width; | |
331 | - vs->vid_enc_frame->height = octx->height; | |
332 | - | |
333 | - vs->vid_enc_frame->pkt_pts = vs->vid_dec_frame->pkt_pts; | |
334 | - vs->vid_enc_frame->pkt_dts = vs->vid_dec_frame->pkt_dts; | |
335 | - | |
336 | - if (vs->vid_dec_frame->reordered_opaque != AV_NOPTS_VALUE) | |
337 | - vs->vid_enc_frame->pts = vs->vid_dec_frame->reordered_opaque; | |
338 | - | |
339 | - else if (ictx->coded_frame && ictx->coded_frame->pts != AV_NOPTS_VALUE) | |
340 | - vs->vid_enc_frame->pts = vs->vid_dec_frame->pts; | |
341 | - | |
342 | - ret = avcodec_encode_video2(octx, &packet2, vs->vid_enc_frame, &got_output); | |
343 | - if (ret < 0) { | |
344 | - tvherror("transcode", "%04X: Error encoding frame", shortid(t)); | |
345 | - transcoder_stream_invalidate(ts); | |
346 | - goto cleanup; | |
347 | + /* and pull out a filtered frame */ | |
348 | + while (1) { | |
349 | + ret = av_buffersink_get_frame(vs->flt_bufsinkctx, vs->vid_enc_frame); | |
350 | + if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) | |
351 | + break; | |
352 | + if (ret < 0) { | |
353 | + tvherror("transcode", "%04X: filter output error", shortid(t)); | |
354 | + transcoder_stream_invalidate(ts); | |
355 | + goto cleanup; | |
356 | + } | |
357 | + | |
358 | + vs->vid_enc_frame->format = octx->pix_fmt; | |
359 | + vs->vid_enc_frame->width = octx->width; | |
360 | + vs->vid_enc_frame->height = octx->height; | |
361 | + | |
362 | + vs->vid_enc_frame->pkt_pts = vs->vid_dec_frame->pkt_pts; | |
363 | + vs->vid_enc_frame->pkt_dts = vs->vid_dec_frame->pkt_dts; | |
364 | + | |
365 | + if (vs->vid_dec_frame->reordered_opaque != AV_NOPTS_VALUE) | |
366 | + vs->vid_enc_frame->pts = vs->vid_dec_frame->reordered_opaque; | |
367 | + | |
368 | + else if (ictx->coded_frame && ictx->coded_frame->pts != AV_NOPTS_VALUE) | |
369 | + vs->vid_enc_frame->pts = vs->vid_dec_frame->pts; | |
370 | + | |
371 | + ret = avcodec_encode_video2(octx, &packet2, vs->vid_enc_frame, &got_output); | |
372 | + if (ret < 0) { | |
373 | + tvherror("transcode", "%04X: Error encoding frame", shortid(t)); | |
374 | + transcoder_stream_invalidate(ts); | |
375 | + goto cleanup; | |
376 | + } | |
377 | + av_frame_unref(vs->vid_enc_frame); | |
378 | } | |
379 | ||
380 | if (got_output) | |
381 | @@ -1263,12 +1347,6 @@ | |
382 | ||
383 | av_free_packet(&packet); | |
384 | ||
385 | - if(buf) | |
386 | - av_free(buf); | |
387 | - | |
388 | - if(deint) | |
389 | - av_free(deint); | |
390 | - | |
391 | if(opts) | |
392 | av_dict_free(&opts); | |
393 | ||
394 | @@ -1548,15 +1626,17 @@ | |
395 | if(vs->vid_dec_frame) | |
396 | av_free(vs->vid_dec_frame); | |
397 | ||
398 | - if(vs->vid_scaler) | |
399 | - sws_freeContext(vs->vid_scaler); | |
400 | - | |
401 | if(vs->vid_enc_frame) | |
402 | av_free(vs->vid_enc_frame); | |
403 | ||
404 | if (vs->vid_first_pkt) | |
405 | pkt_ref_dec(vs->vid_first_pkt); | |
406 | ||
407 | + if (vs->flt_graph) { | |
408 | + avfilter_graph_free(&vs->flt_graph); | |
409 | + vs->flt_graph = NULL; | |
410 | + } | |
411 | + | |
412 | free(ts); | |
413 | } | |
414 | ||
415 | @@ -1603,11 +1683,13 @@ | |
416 | vs->vid_ictx->thread_count = | |
417 | vs->vid_octx->thread_count = transcoder_thread_count(t, sct); | |
418 | ||
419 | - vs->vid_dec_frame = avcodec_alloc_frame(); | |
420 | - vs->vid_enc_frame = avcodec_alloc_frame(); | |
421 | + vs->vid_dec_frame = av_frame_alloc(); | |
422 | + vs->vid_enc_frame = av_frame_alloc(); | |
423 | + | |
424 | + av_frame_unref(vs->vid_dec_frame); | |
425 | + av_frame_unref(vs->vid_enc_frame); | |
426 | ||
427 | - avcodec_get_frame_defaults(vs->vid_dec_frame); | |
428 | - avcodec_get_frame_defaults(vs->vid_enc_frame); | |
429 | + vs->flt_graph = NULL; /* allocated in packet processor */ | |
430 | ||
431 | LIST_INSERT_HEAD(&t->t_stream_list, (transcoder_stream_t*)vs, ts_link); | |
432 |