vdr-plugin-softhddevice-drm-gles 1.6.4-d0291bb
videofilter.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: AGPL-3.0-or-later
2
14extern "C" {
15#include <libavcodec/avcodec.h>
16#include <libavfilter/buffersink.h>
17#include <libavfilter/buffersrc.h>
18#include <libavutil/opt.h>
19}
20
21#include <vdr/thread.h>
22
23#include "logger.h"
24#include "misc.h"
25#include "videofilter.h"
26#include "videorender.h"
27
37 : cThread(name),
38 m_pRender(videoRender),
39 m_frameOutput(frameOutput),
40 m_pDrmBufferQueue(drmBufferQueue)
41{
42}
43
50{
51 int ret;
53
54#if LIBAVFILTER_BUILD >= AV_VERSION_INT(10, 6, 100)
55 ret = av_opt_set_array(m_pBuffersinkCtx, "pixel_formats",
57#else
60#endif
61
62 if (ret < 0)
63 LOGFATAL("video filter: %s: Cannot set output pixel format (%d)", __FUNCTION__, ret);
64}
65
74{
75 int ret;
76 char args[512];
77 const char *filterDescr = NULL;
79 if (!m_pFilterGraph)
80 LOGFATAL("video filter: %s: Cannot alloc filter graph", __FUNCTION__);
81
83 m_filterBug = false;
84
85 const AVFilter *buffersrc = avfilter_get_by_name("buffer");
86 const AVFilter *buffersink = avfilter_get_by_name("buffersink");
87
88#if LIBAVFILTER_VERSION_INT < AV_VERSION_INT(7,16,100)
90#endif
91
92 // interlaced and non-trickspeed AV_PIX_FMT_DRM_PRIME (hardware decoded) -> hardware deinterlacer
93 // interlaced and non-trickspeed AV_PIX_FMT_YUV420P (software decoded) -> software deinterlacer
94 // progressive and trickspeed AV_PIX_FMT_YUV420P (software decoded) -> scale filter (for NV12 output)
95 // progressive and trickspeed AV_PIX_FMT_DRM_PRIME (hardware decoded) doesn't get to the FilterHandlerThread
97 if (frame->format == AV_PIX_FMT_DRM_PRIME) {
98 filterDescr = "deinterlace_v4l2m2m";
99 } else if (frame->format == AV_PIX_FMT_YUV420P) {
100 filterDescr = "bwdif=1:-1:0";
101 m_filterBug = true;
102 }
103 } else if (frame->format == AV_PIX_FMT_YUV420P) {
104 filterDescr = "scale";
105 } else
106 LOGFATAL("video filter: %s: Unexpected pixel format: %d", __FUNCTION__, frame->format);
107
109 if (!m_pBuffersinkCtx)
110 LOGFATAL("video filter: %s: Cannot create buffer sink", __FUNCTION__);
111
112 // if we have a 576i stream without a valid sample_aspect_ratio (0/1) force it to be 64/45
113 // wich "stretches" a 576i stream to 1920/1080 size
114 // this was observed with h264 coded 576i vodafone DVB-C channels and some mpeg2 576i material
115 AVRational sar = videoCtx->sample_aspect_ratio;
116 if (videoCtx->sample_aspect_ratio.num == 0 && videoCtx->height == 576) {
117 sar = (AVRational){64, 45};
118 LOGDEBUG2(L_CODEC, "video filter: %s: Observed 576i material with a sar 0/1, stretch it with sar %d/%d", __FUNCTION__, sar.num, sar.den);
119 }
120
121 if (frame->format == AV_PIX_FMT_DRM_PRIME) {
123
125 if (!m_pBuffersrcCtx)
126 LOGFATAL("video filter: %s: Cannot create buffer src", __FUNCTION__);
127
129 memset(par, 0, sizeof(*par));
130
131 par->format = AV_PIX_FMT_DRM_PRIME;
132 par->hw_frames_ctx = frame->hw_frames_ctx;
133 par->time_base = videoCtx->pkt_timebase;
134 par->width = videoCtx->width;
135 par->height = videoCtx->height;
136 par->sample_aspect_ratio = sar;
137
138 LOGDEBUG2(L_CODEC, "video filter: %s: filter=\"%s\" fmt %d, hw ctx %p, tb %d/%d, wxh %dx%d, sar %d/%d",
140 par->format, par->hw_frames_ctx, par->time_base.num, par->time_base.den,
141 par->width, par->height, par->sample_aspect_ratio.num, par->sample_aspect_ratio.den);
142
144 if (ret < 0)
145 LOGFATAL("video filter: %s: Cannot av_buffersrc_parameters_set (%d)", __FUNCTION__, ret);
146
147 av_free(par);
148
150 if (ret < 0)
151 LOGFATAL("video filter: %s: Cannot initialize buffer src (%d)", __FUNCTION__, ret);
152 } else {
154
155 snprintf(args, sizeof(args), "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
156 videoCtx->width, videoCtx->height, frame->format,
157 videoCtx->pkt_timebase.num ? videoCtx->pkt_timebase.num : 1,
158 videoCtx->pkt_timebase.num ? videoCtx->pkt_timebase.den : 1,
159 sar.num, sar.den);
160
161 LOGDEBUG2(L_CODEC, "video filter: %s: filter=\"%s\" args=\"%s\"", __FUNCTION__, filterDescr, args);
162
164 if (ret < 0)
165 LOGFATAL("video filter: %s: Cannot create buffer src", __FUNCTION__);
166 }
167
169 if (ret < 0)
170 LOGFATAL("video filter: %s: Cannot initialize buffer sink (%d)", __FUNCTION__, ret);
171
174
175 outputs->name = av_strdup("in");
176 outputs->filter_ctx = m_pBuffersrcCtx;
177 outputs->pad_idx = 0;
178 outputs->next = NULL;
179
180 inputs->name = av_strdup("out");
181 inputs->filter_ctx = m_pBuffersinkCtx;
182 inputs->pad_idx = 0;
183 inputs->next = NULL;
184
186 if (ret < 0) {
187 LOGFATAL("video filter: %s: avfilter_graph_parse_ptr failed (%d)", __FUNCTION__, ret);
188 }
189
192
194 if (ret < 0)
195 LOGFATAL("video filter: %s: avfilter_graph_config failed (%d)", __FUNCTION__, ret);
196
197 Start();
198}
199
206{
207 LOGDEBUG("video filter: thread started");
208
209 while (Running()) {
210 if (m_frames.IsEmpty()) {
211 usleep(1000);
212 continue;
213 }
214
215 AVFrame *frame = m_frames.Pop();
216
218 if (isInterlacedFrame(frame))
220
221 // add frame to filter
222 int ret;
224 LOGWARNING("video filter: %s: can't add_frame: %s", __FUNCTION__, av_err2str(ret));
225
226 av_frame_free(&frame);
227
228 // get filtered frames
229 while (Running()) {
231 if (!filtFrame)
232 LOGFATAL("video filter: %s: can't allocate frame", __FUNCTION__);
233
235
236 if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
238 break;
239 } else if (ret < 0) {
240 LOGERROR("video filter: %s: can't get filtered frame: %s", __FUNCTION__, av_err2str(ret));
242 break;
243 }
244
245 while (Running() && m_pDrmBufferQueue->IsFull())
246 usleep(1000);
247
248 if (Running()) {
249 if (filtFrame->format == AV_PIX_FMT_NV12 && m_filterBug) // scale filter or sw deinterlacer, no prime data, always returns NV12
250 filtFrame->pts /= 2; // ffmpeg bug
251
253 } else
255 }
256 }
257 LOGDEBUG("video filter: thread stopped");
258}
259
264{
265 m_frames.Push(frame);
266}
267
272{
273 if (!Active())
274 return;
275
276 LOGDEBUG("video filter: stopping thread");
277 Cancel(2);
278 m_filterBug = false;
280
281 while (!m_frames.IsEmpty()) {
282 AVFrame *frame = m_frames.Pop();
283 av_frame_free(&frame);
284 }
285
287}
T * Pop(void)
Pop an element from the back of the queue.
Definition queue.h:57
bool IsEmpty(void)
Check if the queue is empty.
Definition queue.h:99
bool IsFull(void)
Check if the queue is full.
Definition queue.h:110
bool Push(T *element)
Push an element to the front of the queue.
Definition queue.h:40
cQueue< cDrmBuffer > * m_pDrmBufferQueue
pointer to renderer's DRM buffer queue
Definition videofilter.h:60
void SetFilterOutputPixFormat(AVPixelFormat)
Setup the filter output pixel format.
cVideoFilter(cVideoRender *, cQueue< cDrmBuffer > *, const char *, std::function< void(AVFrame *)>)
Initiate Filter.
int m_numFramesToFilter
number of frames to be filtered
Definition videofilter.h:61
AVFilterGraph * m_pFilterGraph
filter graph
Definition videofilter.h:53
cQueue< AVFrame > m_frames
queue for frames to be filtered
Definition videofilter.h:58
void InitAndStart(const AVCodecContext *, AVFrame *, bool)
Init and start the video filter thread.
void Stop(void)
Stops the filter thread and does a cleanup.
void Action(void)
Main filter thread loop.
AVFilterContext * m_pBuffersinkCtx
buffer sink context
Definition videofilter.h:55
std::function< void(AVFrame *)> m_frameOutput
function to output the frame
Definition videofilter.h:59
bool m_filterBug
flag for a ffmpeg bug
Definition videofilter.h:57
AVFilterContext * m_pBuffersrcCtx
buffer src context
Definition videofilter.h:54
void PushFrame(AVFrame *)
Puts a frame in the buffer to be filtered.
Video Renderer.
#define LOGDEBUG2
log to LOG_DEBUG and add a prefix
Definition logger.h:47
#define LOGDEBUG
log to LOG_DEBUG
Definition logger.h:45
#define LOGERROR
log to LOG_ERR
Definition logger.h:39
#define LOGWARNING
log to LOG_WARN
Definition logger.h:41
#define LOGFATAL
log to LOG_ERR and abort
Definition logger.h:37
static bool isInterlacedFrame(AVFrame *frame)
Check, if this is an interlaced frame.
Definition misc.h:86
#define av_err2str(err)
Definition misc.h:112
@ L_CODEC
codec logs
Definition logger.h:61
Logger Header File.
Misc Functions.
Deinterlace and Scaling Filters Header File.
Video Renderer (Display) Header File.