]>
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 | ||
100 | @@ -592,10 +597,10 @@ | |
101 | // Convert audio | |
102 | tvhtrace("transcode", "%04X: converting audio", shortid(t)); | |
103 | ||
104 | - tvhtrace("transcode", "%04X: IN : channels=%d, layout=%" PRIi64 ", rate=%d, fmt=%d, bitrate=%d", | |
105 | + tvhtrace("transcode", "%04X: IN : channels=%d, layout=%" PRIi64 ", rate=%d, fmt=%d, bitrate=%ld", | |
106 | shortid(t), ictx->channels, ictx->channel_layout, ictx->sample_rate, | |
107 | ictx->sample_fmt, ictx->bit_rate); | |
108 | - tvhtrace("transcode", "%04X: OUT: channels=%d, layout=%" PRIi64 ", rate=%d, fmt=%d, bitrate=%d", | |
109 | + tvhtrace("transcode", "%04X: OUT: channels=%d, layout=%" PRIi64 ", rate=%d, fmt=%d, bitrate=%ld", | |
110 | shortid(t), octx->channels, octx->channel_layout, octx->sample_rate, | |
111 | octx->sample_fmt, octx->bit_rate); | |
112 | ||
113 | @@ -952,6 +957,114 @@ | |
114 | ||
115 | } | |
116 | ||
117 | +/* create a simple deinterlacer-scaler video filter chain */ | |
118 | +static int | |
119 | +create_video_filter(video_stream_t *vs, transcoder_t *t, | |
120 | + AVCodecContext *ictx, AVCodecContext *octx) | |
121 | +{ | |
122 | + AVFilterInOut *flt_inputs, *flt_outputs; | |
123 | + AVFilter *flt_bufsrc, *flt_bufsink; | |
124 | + char opt[128]; | |
125 | + int err; | |
126 | + | |
127 | + err = 1; | |
128 | + flt_inputs = flt_outputs = NULL; | |
129 | + flt_bufsrc = flt_bufsink = NULL; | |
130 | + | |
131 | + if (vs->flt_graph) | |
132 | + avfilter_graph_free(&vs->flt_graph); | |
133 | + | |
134 | + vs->flt_graph = avfilter_graph_alloc(); | |
135 | + if (!vs->flt_graph) | |
136 | + return err; | |
137 | + | |
138 | + flt_inputs = avfilter_inout_alloc(); | |
139 | + if (!flt_inputs) | |
140 | + goto out_err; | |
141 | + | |
142 | + flt_outputs = avfilter_inout_alloc(); | |
143 | + if (!flt_outputs) | |
144 | + goto out_err; | |
145 | + | |
146 | + flt_bufsrc = avfilter_get_by_name("buffer"); | |
147 | + flt_bufsink = avfilter_get_by_name("buffersink"); | |
148 | + if (!flt_bufsrc || !flt_bufsink) { | |
149 | + tvherror("transcode", "%04X: libav default buffers unknown", shortid(t)); | |
150 | + goto out_err; | |
151 | + } | |
152 | + | |
153 | + memset(opt, 0, sizeof(opt)); | |
154 | + snprintf(opt, sizeof(opt), "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d", | |
155 | + ictx->width, | |
156 | + ictx->height, | |
157 | + ictx->pix_fmt, | |
158 | + ictx->time_base.num, | |
159 | + ictx->time_base.den, | |
160 | + ictx->sample_aspect_ratio.num, | |
161 | + ictx->sample_aspect_ratio.den); | |
162 | + | |
163 | + err = avfilter_graph_create_filter(&vs->flt_bufsrcctx, flt_bufsrc, "in", | |
164 | + opt, NULL, vs->flt_graph); | |
165 | + if (err < 0) { | |
166 | + tvherror("transcode", "%04X: fltchain IN init error", shortid(t)); | |
167 | + goto out_err; | |
168 | + } | |
169 | + | |
170 | + err = avfilter_graph_create_filter(&vs->flt_bufsinkctx, flt_bufsink, | |
171 | + "out", NULL, NULL, vs->flt_graph); | |
172 | + if (err < 0) { | |
173 | + tvherror("transcode", "%04X: fltchain OUT init error", shortid(t)); | |
174 | + goto out_err; | |
175 | + } | |
176 | + | |
177 | + flt_outputs->name = av_strdup("in"); | |
178 | + flt_outputs->filter_ctx = vs->flt_bufsrcctx; | |
179 | + flt_outputs->pad_idx = 0; | |
180 | + flt_outputs->next = NULL; | |
181 | + flt_inputs->name = av_strdup("out"); | |
182 | + flt_inputs->filter_ctx = vs->flt_bufsinkctx; | |
183 | + flt_inputs->pad_idx = 0; | |
184 | + flt_inputs->next = NULL; | |
185 | + | |
186 | + /* add filters: yadif to deinterlace and a scaler */ | |
187 | + memset(opt, 0, sizeof(opt)); | |
188 | + snprintf(opt, sizeof(opt), "yadif,scale=%dx%d", | |
189 | + octx->width, | |
190 | + octx->height); | |
191 | + err = avfilter_graph_parse_ptr(vs->flt_graph, | |
192 | + opt, | |
193 | + &flt_inputs, | |
194 | + &flt_outputs, | |
195 | + NULL); | |
196 | + if (err < 0) { | |
197 | + tvherror("transcode", "%04X: failed to init filter chain", shortid(t)); | |
198 | + goto out_err; | |
199 | + } | |
200 | + | |
201 | + err = avfilter_graph_config(vs->flt_graph, NULL); | |
202 | + if (err < 0) { | |
203 | + tvherror("transcode", "%04X: failed to config filter chain", shortid(t)); | |
204 | + goto out_err; | |
205 | + } | |
206 | + | |
207 | + avfilter_inout_free(&flt_inputs); | |
208 | + avfilter_inout_free(&flt_outputs); | |
209 | + | |
210 | + return 0; /* all OK */ | |
211 | + | |
212 | +out_err: | |
213 | + if (flt_inputs) | |
214 | + avfilter_inout_free(&flt_inputs); | |
215 | + if (flt_outputs) | |
216 | + avfilter_inout_free(&flt_outputs); | |
217 | + if (vs->flt_graph) { | |
218 | + avfilter_graph_free(&vs->flt_graph); | |
219 | + vs->flt_graph = NULL; | |
220 | + } | |
221 | + | |
222 | + return err; | |
223 | +} | |
224 | + | |
225 | /** | |
226 | * | |
227 | */ | |
228 | @@ -962,9 +1075,7 @@ | |
229 | AVCodecContext *ictx, *octx; | |
230 | AVDictionary *opts; | |
231 | AVPacket packet, packet2; | |
232 | - AVPicture deint_pic; | |
233 | - uint8_t *buf, *deint; | |
234 | - int length, len, ret, got_picture, got_output, got_ref; | |
235 | + int length, ret, got_picture, got_output, got_ref; | |
236 | video_stream_t *vs = (video_stream_t*)ts; | |
237 | streaming_message_t *sm; | |
238 | th_pkt_t *pkt2; | |
239 | @@ -980,7 +1091,6 @@ | |
240 | icodec = vs->vid_icodec; | |
241 | ocodec = vs->vid_ocodec; | |
242 | ||
243 | - buf = deint = NULL; | |
244 | opts = NULL; | |
245 | ||
246 | got_ref = 0; | |
247 | @@ -1061,7 +1171,7 @@ | |
248 | switch (ts->ts_type) { | |
249 | case SCT_MPEG2VIDEO: | |
250 | octx->codec_id = AV_CODEC_ID_MPEG2VIDEO; | |
251 | - octx->pix_fmt = PIX_FMT_YUV420P; | |
252 | + octx->pix_fmt = AV_PIX_FMT_YUV420P; | |
253 | octx->flags |= CODEC_FLAG_GLOBAL_HEADER; | |
254 | ||
255 | // Default settings for quantizer. Best quality unless changed by the streaming profile. | |
256 | @@ -1089,7 +1199,7 @@ | |
257 | ||
258 | case SCT_VP8: | |
259 | octx->codec_id = AV_CODEC_ID_VP8; | |
260 | - octx->pix_fmt = PIX_FMT_YUV420P; | |
261 | + octx->pix_fmt = AV_PIX_FMT_YUV420P; | |
262 | ||
263 | av_dict_set(&opts, "quality", "realtime", 0); | |
264 | ||
265 | @@ -1120,7 +1230,7 @@ | |
266 | ||
267 | case SCT_H264: | |
268 | octx->codec_id = AV_CODEC_ID_H264; | |
269 | - octx->pix_fmt = PIX_FMT_YUV420P; | |
270 | + octx->pix_fmt = AV_PIX_FMT_YUV420P; | |
271 | octx->flags |= CODEC_FLAG_GLOBAL_HEADER; | |
272 | ||
273 | // Qscale difference between I-frames and P-frames. | |
274 | @@ -1177,79 +1287,53 @@ | |
275 | transcoder_stream_invalidate(ts); | |
276 | goto cleanup; | |
277 | } | |
278 | - } | |
279 | ||
280 | - len = avpicture_get_size(ictx->pix_fmt, ictx->width, ictx->height); | |
281 | - deint = av_malloc(len); | |
282 | - | |
283 | - avpicture_fill(&deint_pic, | |
284 | - deint, | |
285 | - ictx->pix_fmt, | |
286 | - ictx->width, | |
287 | - ictx->height); | |
288 | - | |
289 | - if (avpicture_deinterlace(&deint_pic, | |
290 | - (AVPicture *)vs->vid_dec_frame, | |
291 | - ictx->pix_fmt, | |
292 | - ictx->width, | |
293 | - ictx->height) < 0) { | |
294 | - tvherror("transcode", "%04X: Cannot deinterlace frame", shortid(t)); | |
295 | - transcoder_stream_invalidate(ts); | |
296 | - goto cleanup; | |
297 | + if (create_video_filter(vs, t, ictx, octx)) { | |
298 | + tvherror("transcode", "%04X: Video filter creation failed", | |
299 | + shortid(t)); | |
300 | + transcoder_stream_invalidate(ts); | |
301 | + goto cleanup; | |
302 | + } | |
303 | } | |
304 | ||
305 | - len = avpicture_get_size(octx->pix_fmt, octx->width, octx->height); | |
306 | - buf = av_malloc(len + FF_INPUT_BUFFER_PADDING_SIZE); | |
307 | - memset(buf, 0, len); | |
308 | - | |
309 | - avpicture_fill((AVPicture *)vs->vid_enc_frame, | |
310 | - buf, | |
311 | - octx->pix_fmt, | |
312 | - octx->width, | |
313 | - octx->height); | |
314 | - | |
315 | - vs->vid_scaler = sws_getCachedContext(vs->vid_scaler, | |
316 | - ictx->width, | |
317 | - ictx->height, | |
318 | - ictx->pix_fmt, | |
319 | - octx->width, | |
320 | - octx->height, | |
321 | - octx->pix_fmt, | |
322 | - 1, | |
323 | - NULL, | |
324 | - NULL, | |
325 | - NULL); | |
326 | - | |
327 | - if (sws_scale(vs->vid_scaler, | |
328 | - (const uint8_t * const*)deint_pic.data, | |
329 | - deint_pic.linesize, | |
330 | - 0, | |
331 | - ictx->height, | |
332 | - vs->vid_enc_frame->data, | |
333 | - vs->vid_enc_frame->linesize) < 0) { | |
334 | - tvherror("transcode", "%04X: Cannot scale frame", shortid(t)); | |
335 | + /* push decoded frame into filter chain */ | |
336 | + if (av_buffersrc_add_frame(vs->flt_bufsrcctx, vs->vid_dec_frame) < 0) { | |
337 | + tvherror("transcode", "%04X: filter input error", shortid(t)); | |
338 | transcoder_stream_invalidate(ts); | |
339 | goto cleanup; | |
340 | } | |
341 | ||
342 | - vs->vid_enc_frame->format = octx->pix_fmt; | |
343 | - vs->vid_enc_frame->width = octx->width; | |
344 | - vs->vid_enc_frame->height = octx->height; | |
345 | - | |
346 | - vs->vid_enc_frame->pkt_pts = vs->vid_dec_frame->pkt_pts; | |
347 | - vs->vid_enc_frame->pkt_dts = vs->vid_dec_frame->pkt_dts; | |
348 | - | |
349 | - if (vs->vid_dec_frame->reordered_opaque != AV_NOPTS_VALUE) | |
350 | - vs->vid_enc_frame->pts = vs->vid_dec_frame->reordered_opaque; | |
351 | - | |
352 | - else if (ictx->coded_frame && ictx->coded_frame->pts != AV_NOPTS_VALUE) | |
353 | - vs->vid_enc_frame->pts = vs->vid_dec_frame->pts; | |
354 | - | |
355 | - ret = avcodec_encode_video2(octx, &packet2, vs->vid_enc_frame, &got_output); | |
356 | - if (ret < 0) { | |
357 | - tvherror("transcode", "%04X: Error encoding frame", shortid(t)); | |
358 | - transcoder_stream_invalidate(ts); | |
359 | - goto cleanup; | |
360 | + /* and pull out a filtered frame */ | |
361 | + while (1) { | |
362 | + ret = av_buffersink_get_frame(vs->flt_bufsinkctx, vs->vid_enc_frame); | |
363 | + if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) | |
364 | + break; | |
365 | + if (ret < 0) { | |
366 | + tvherror("transcode", "%04X: filter output error", shortid(t)); | |
367 | + transcoder_stream_invalidate(ts); | |
368 | + goto cleanup; | |
369 | + } | |
370 | + | |
371 | + vs->vid_enc_frame->format = octx->pix_fmt; | |
372 | + vs->vid_enc_frame->width = octx->width; | |
373 | + vs->vid_enc_frame->height = octx->height; | |
374 | + | |
375 | + vs->vid_enc_frame->pkt_pts = vs->vid_dec_frame->pkt_pts; | |
376 | + vs->vid_enc_frame->pkt_dts = vs->vid_dec_frame->pkt_dts; | |
377 | + | |
378 | + if (vs->vid_dec_frame->reordered_opaque != AV_NOPTS_VALUE) | |
379 | + vs->vid_enc_frame->pts = vs->vid_dec_frame->reordered_opaque; | |
380 | + | |
381 | + else if (ictx->coded_frame && ictx->coded_frame->pts != AV_NOPTS_VALUE) | |
382 | + vs->vid_enc_frame->pts = vs->vid_dec_frame->pts; | |
383 | + | |
384 | + ret = avcodec_encode_video2(octx, &packet2, vs->vid_enc_frame, &got_output); | |
385 | + if (ret < 0) { | |
386 | + tvherror("transcode", "%04X: Error encoding frame", shortid(t)); | |
387 | + transcoder_stream_invalidate(ts); | |
388 | + goto cleanup; | |
389 | + } | |
390 | + av_frame_unref(vs->vid_enc_frame); | |
391 | } | |
392 | ||
393 | if (got_output) | |
394 | @@ -1263,12 +1347,6 @@ | |
395 | ||
396 | av_free_packet(&packet); | |
397 | ||
398 | - if(buf) | |
399 | - av_free(buf); | |
400 | - | |
401 | - if(deint) | |
402 | - av_free(deint); | |
403 | - | |
404 | if(opts) | |
405 | av_dict_free(&opts); | |
406 | ||
407 | @@ -1548,15 +1626,17 @@ | |
408 | if(vs->vid_dec_frame) | |
409 | av_free(vs->vid_dec_frame); | |
410 | ||
411 | - if(vs->vid_scaler) | |
412 | - sws_freeContext(vs->vid_scaler); | |
413 | - | |
414 | if(vs->vid_enc_frame) | |
415 | av_free(vs->vid_enc_frame); | |
416 | ||
417 | if (vs->vid_first_pkt) | |
418 | pkt_ref_dec(vs->vid_first_pkt); | |
419 | ||
420 | + if (vs->flt_graph) { | |
421 | + avfilter_graph_free(&vs->flt_graph); | |
422 | + vs->flt_graph = NULL; | |
423 | + } | |
424 | + | |
425 | free(ts); | |
426 | } | |
427 | ||
428 | @@ -1603,11 +1683,13 @@ | |
429 | vs->vid_ictx->thread_count = | |
430 | vs->vid_octx->thread_count = transcoder_thread_count(t, sct); | |
431 | ||
432 | - vs->vid_dec_frame = avcodec_alloc_frame(); | |
433 | - vs->vid_enc_frame = avcodec_alloc_frame(); | |
434 | + vs->vid_dec_frame = av_frame_alloc(); | |
435 | + vs->vid_enc_frame = av_frame_alloc(); | |
436 | + | |
437 | + av_frame_unref(vs->vid_dec_frame); | |
438 | + av_frame_unref(vs->vid_enc_frame); | |
439 | ||
440 | - avcodec_get_frame_defaults(vs->vid_dec_frame); | |
441 | - avcodec_get_frame_defaults(vs->vid_enc_frame); | |
442 | + vs->flt_graph = NULL; /* allocated in packet processor */ | |
443 | ||
444 | LIST_INSERT_HEAD(&t->t_stream_list, (transcoder_stream_t*)vs, ts_link); | |
445 |