vdr-plugin-softhddevice-drm-gles 1.4.0
threads.cpp
Go to the documentation of this file.
1
28extern "C" {
29#include <libavcodec/avcodec.h>
30#include <libavfilter/buffersink.h>
31#include <libavfilter/buffersrc.h>
32#include <libavutil/opt.h>
33}
34
35#include "logger.h"
36#include "vdr/thread.h"
37#include "threads.h"
38#include "videorender.h"
39#include "audio.h"
40#include "videostream.h"
41#include "misc.h"
42
43/*****************************************************************************
44 * cDecodingThread class
45 *
46 * This thread decodes the video data
47 ****************************************************************************/
48cDecodingThread::cDecodingThread(cVideoStream *stream, const char *name) : cThread(name)
49{
50 m_pStream = stream;
51 Start();
52}
53
55{
56}
57
59{
60 LOGDEBUG("threads: decoding thread started");
61 while(Running()) {
62 m_mutex.lock();
63
65
66 m_mutex.unlock();
67
68 usleep(1000);
69 }
70 LOGDEBUG("threads: decoding thread stopped");
71}
72
74{
75 if (!Active())
76 return;
77
78 LOGDEBUG("threads: stopping decoding thread");
79 Cancel(2);
80}
81
82/*****************************************************************************
83 * cDisplayThread class
84 *
85 * This thread is responsible for displaying the video and osd
86 ****************************************************************************/
87cDisplayThread::cDisplayThread(cVideoRender *render) : cThread("softhd display")
88{
89 m_pRender = render;
90 Start();
91}
92
94{
95}
96
98{
99 LOGDEBUG("threads: display thread started");
100 while(Running()) {
101 m_mutex.lock();
102
103 bool scheduleImmediately = m_pRender->DisplayFrame();
104
105 m_mutex.unlock();
106
108
109 if (scheduleImmediately)
110 usleep(100); // yield thread. give control also to threads with lower priority.
111 else
112 usleep(1000);
113 }
114 LOGDEBUG("threads: display thread stopped");
115}
116
118{
119 if (!Active())
120 return;
121
122 LOGDEBUG("threads: stopping display thread");
123 Cancel(2);
124}
125
126/*****************************************************************************
127 * cAudioThread class
128 *
129 * This thread is decodes the audio data and moves it to hardware
130 ****************************************************************************/
131cAudioThread::cAudioThread(cSoftHdAudio *audio) : cThread("softhd audio")
132{
133 m_pAudio = audio;
134 Start();
135}
136
138{
139}
140
142{
143 LOGDEBUG("threads: audio thread started");
144 while (Running()) {
147
148 usleep(10000);
149 }
150 LOGDEBUG("threads: audio thread stopped");
151}
152
154{
155 if (!Active())
156 return;
157
158 LOGDEBUG("threads: stopping audio thread");
159 Cancel(2);
160}
161
162/*****************************************************************************
163 * cFilterThread class
164 *
165 * This thread handles video filters like deinterlacer or scale filter
166 ****************************************************************************/
167cFilterThread::cFilterThread(cVideoRender *videoRender, cQueue<cDrmBuffer> *drmBufferQueue, const char *name, std::function<void(AVFrame *)> frameOutput) : cThread(name)
168{
169 m_pRender = videoRender;
170 m_pDrmBufferQueue = drmBufferQueue;
171 m_frameOutput = frameOutput;
172}
173
175{
176}
177
185void cFilterThread::InitAndStart(const AVCodecContext *videoCtx, AVFrame *frame, bool enableDeinterlacer)
186{
187 int ret;
188 char args[512];
189 const char *filterDescr = NULL;
190 m_pFilterGraph = avfilter_graph_alloc();
191 if (!m_pFilterGraph)
192 LOGFATAL("filter thread: %s: Cannot alloc filter graph", __FUNCTION__);
193
195 m_filterBug = false;
196
197 const AVFilter *buffersrc = avfilter_get_by_name("buffer");
198 const AVFilter *buffersink = avfilter_get_by_name("buffersink");
199
200 // interlaced and non-trickspeed AV_PIX_FMT_DRM_PRIME (hardware decoded) -> hardware deinterlacer
201 // interlaced and non-trickspeed AV_PIX_FMT_YUV420P (software decoded) -> software deinterlacer
202 // progressive and trickspeed AV_PIX_FMT_YUV420P (software decoded) -> scale filter (for NV12 output)
203 // progressive and trickspeed AV_PIX_FMT_DRM_PRIME (hardware decoded) doesn't get to the FilterHandlerThread
204 if (enableDeinterlacer) {
205 if (frame->format == AV_PIX_FMT_DRM_PRIME) {
206 filterDescr = "deinterlace_v4l2m2m";
207 } else if (frame->format == AV_PIX_FMT_YUV420P) {
208 filterDescr = "bwdif=1:-1:0";
209 m_filterBug = true;
210 }
211 } else if (frame->format == AV_PIX_FMT_YUV420P) {
212 filterDescr = "scale";
213 } else
214 LOGFATAL("filter thread: %s: Unexpected pixel format: %d", __FUNCTION__, frame->format);
215#if LIBAVFILTER_VERSION_INT < AV_VERSION_INT(7,16,100)
216 avfilter_register_all();
217#endif
218
219 // if we have a 576i stream without a valid sample_aspect_ratio (0/1) force it to be 64/45
220 // wich "stretches" a 576i stream to 1920/1080 size
221 int sarNum = videoCtx->sample_aspect_ratio.num != 0 ? videoCtx->sample_aspect_ratio.num : (videoCtx->height == 576 ? 64 : 1);
222 int sarDen = videoCtx->sample_aspect_ratio.num != 0 ? videoCtx->sample_aspect_ratio.den : (videoCtx->height == 576 ? 45 : 1);
223
224 snprintf(args, sizeof(args), "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
225 videoCtx->width, videoCtx->height, frame->format,
226 videoCtx->pkt_timebase.num ? videoCtx->pkt_timebase.num : 1,
227 videoCtx->pkt_timebase.num ? videoCtx->pkt_timebase.den : 1,
228 sarNum,
229 sarDen);
230
231 LOGDEBUG2(L_CODEC, "filter thread: %s: filter=\"%s\" args=\"%s\"", __FUNCTION__, filterDescr, args);
232
233 ret = avfilter_graph_create_filter(&m_pBuffersrcCtx, buffersrc, "in", args, NULL, m_pFilterGraph);
234 if (ret < 0)
235 LOGFATAL("filter thread: %s: Cannot create buffer source (%d)", __FUNCTION__, ret);
236
237 AVBufferSrcParameters *par = av_buffersrc_parameters_alloc();
238 memset(par, 0, sizeof(*par));
239 par->format = AV_PIX_FMT_NONE;
240 par->hw_frames_ctx = frame->hw_frames_ctx;
241 ret = av_buffersrc_parameters_set(m_pBuffersrcCtx, par);
242 if (ret < 0)
243 LOGFATAL("filter thread: %s: Cannot av_buffersrc_parameters_set (%d)", __FUNCTION__, ret);
244
245 av_free(par);
246
247 ret = avfilter_graph_create_filter(&m_pBuffersinkCtx, buffersink, "out", NULL, NULL, m_pFilterGraph);
248 if (ret < 0)
249 LOGFATAL("filter thread: %s: Cannot create buffer sink (%d)", __FUNCTION__, ret);
250
251 if (frame->format != AV_PIX_FMT_DRM_PRIME) {
252 enum AVPixelFormat pixFmts[] = { AV_PIX_FMT_NV12, AV_PIX_FMT_NONE };
253 ret = av_opt_set_int_list(m_pBuffersinkCtx, "pix_fmts", pixFmts, AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN);
254 if (ret < 0)
255 LOGFATAL("filter thread: %s: Cannot set output pixel format (%d)", __FUNCTION__, ret);
256 }
257
258 AVFilterInOut *outputs = avfilter_inout_alloc();
259 AVFilterInOut *inputs = avfilter_inout_alloc();
260
261 outputs->name = av_strdup("in");
262 outputs->filter_ctx = m_pBuffersrcCtx;
263 outputs->pad_idx = 0;
264 outputs->next = NULL;
265
266 inputs->name = av_strdup("out");
267 inputs->filter_ctx = m_pBuffersinkCtx;
268 inputs->pad_idx = 0;
269 inputs->next = NULL;
270
271 ret = avfilter_graph_parse_ptr(m_pFilterGraph, filterDescr, &inputs, &outputs, NULL);
272 avfilter_inout_free(&inputs);
273 avfilter_inout_free(&outputs);
274
275 if (ret < 0) {
276 LOGFATAL("filter thread: %s: avfilter_graph_parse_ptr failed (%d)", __FUNCTION__, ret);
277 }
278
279 ret = avfilter_graph_config(m_pFilterGraph, NULL);
280 if (ret < 0)
281 LOGFATAL("filter thread: %s: avfilter_graph_config failed (%d)", __FUNCTION__, ret);
282
283 Start();
284}
285
287{
288 LOGDEBUG("threads: video filter thread started");
289
290 while (Running()) {
291 if (m_frames.IsEmpty()) {
292 usleep(1000);
293 continue;
294 }
295
296 AVFrame *frame = m_frames.Pop();
297
299 if (isInterlacedFrame(frame))
301
302 // add frame to filter
303 int ret;
304 if ((ret = av_buffersrc_add_frame_flags(m_pBuffersrcCtx, frame, AV_BUFFERSRC_FLAG_KEEP_REF)) < 0)
305 LOGWARNING("filter thread: %s: can't add_frame: %s", __FUNCTION__, av_err2str(ret));
306
307 av_frame_free(&frame);
308
309 // get filtered frames
310 while (Running()) {
311 AVFrame *filtFrame = av_frame_alloc();
312 if (!filtFrame)
313 LOGFATAL("filter thread: %s: can't allocate frame", __FUNCTION__);
314
315 ret = av_buffersink_get_frame(m_pBuffersinkCtx, filtFrame);
316
317 if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
318 av_frame_free(&filtFrame);
319 break;
320 } else if (ret < 0) {
321 LOGERROR("filter thread: %s: can't get filtered frame: %s", __FUNCTION__, av_err2str(ret));
322 av_frame_free(&filtFrame);
323 break;
324 }
325
326 while (Running() && m_pDrmBufferQueue->IsFull())
327 usleep(1000);
328
329 if (Running()) {
330 if (filtFrame->format == AV_PIX_FMT_NV12 && m_filterBug) // scale filter or sw deinterlacer, no prime data, always returns NV12
331 filtFrame->pts /= 2; // ffmpeg bug
332
333 m_frameOutput(filtFrame);
334 } else
335 av_frame_free(&filtFrame);
336 }
337 }
338 LOGDEBUG("threads: filter thread stopped");
339}
340
344void cFilterThread::PushFrame(AVFrame *frame)
345{
346 m_frames.Push(frame);
347}
348
350{
351 if (!Active())
352 return;
353
354 LOGDEBUG("threads: stopping filter thread");
355 Cancel(2);
356 m_filterBug = false;
358
359 while (!m_frames.IsEmpty()) {
360 AVFrame *frame = m_frames.Pop();
361 av_frame_free(&frame);
362 }
363
364 avfilter_graph_free(&m_pFilterGraph);
365}
Audio and alsa module header file.
cSoftHdAudio * m_pAudio
Definition: threads.h:90
cAudioThread(cSoftHdAudio *)
Definition: threads.cpp:131
void Stop(void)
Definition: threads.cpp:153
virtual ~cAudioThread(void)
Definition: threads.cpp:137
virtual void Action(void)
Definition: threads.cpp:141
std::mutex m_mutex
Definition: threads.h:48
cDecodingThread(cVideoStream *, const char *)
Definition: threads.cpp:48
void Stop(void)
Definition: threads.cpp:73
virtual void Action(void)
Definition: threads.cpp:58
cVideoStream * m_pStream
Definition: threads.h:49
virtual ~cDecodingThread(void)
Definition: threads.cpp:54
cVideoRender * m_pRender
Definition: threads.h:71
cDisplayThread(cVideoRender *)
Definition: threads.cpp:87
virtual void Action(void)
Definition: threads.cpp:97
std::mutex m_mutex
Definition: threads.h:70
virtual ~cDisplayThread(void)
Definition: threads.cpp:93
void Stop(void)
Definition: threads.cpp:117
void InitAndStart(const AVCodecContext *, AVFrame *, bool)
Init and start the video filter thread.
Definition: threads.cpp:185
void Action(void)
Definition: threads.cpp:286
void Stop(void)
Definition: threads.cpp:349
AVFilterContext * m_pBuffersinkCtx
Definition: threads.h:115
cVideoRender * m_pRender
Definition: threads.h:111
void PushFrame(AVFrame *)
Put a frame in the buffer to be filtered.
Definition: threads.cpp:344
cQueue< cDrmBuffer > * m_pDrmBufferQueue
pointer to renderer's DRM buffer queue
Definition: threads.h:120
AVFilterContext * m_pBuffersrcCtx
Definition: threads.h:114
bool m_filterBug
flag for a ffmpeg bug
Definition: threads.h:117
AVFilterGraph * m_pFilterGraph
Definition: threads.h:113
cFilterThread(cVideoRender *, cQueue< cDrmBuffer > *, const char *, std::function< void(AVFrame *)>)
Definition: threads.cpp:167
int m_numFramesToFilter
number of frames to be filtered
Definition: threads.h:121
std::function< void(AVFrame *)> m_frameOutput
function to output the frame
Definition: threads.h:119
virtual ~cFilterThread(void)
Definition: threads.cpp:174
cQueue< AVFrame > m_frames
queue for frames to be filtered
Definition: threads.h:118
T * Pop(void)
Pop an element from the back of the queue.
Definition: queue.h:64
bool IsEmpty(void)
Check if the queue is empty.
Definition: queue.h:106
bool IsFull(void)
Check if the queue is full.
Definition: queue.h:117
bool Push(T *element)
Push an element to the front of the queue.
Definition: queue.h:47
cSoftHdAudio - Audio class
Definition: audio.h:45
void ProcessEvents(void)
Process queued events and forward to event receiver.
Definition: audio.cpp:1585
bool CyclicCall(void)
Cyclic audio playback call.
Definition: audio.cpp:1118
cVideoRender - Video render class
Definition: videorender.h:122
void ProcessEvents(void)
Process queued events and forward to event receiver.
bool DisplayFrame()
Display the frame (video and/or osd)
cVideoStream - Video stream class
Definition: videostream.h:51
void DecodeInput(void)
Decodes a reassembled codec packet.
Logger class header file.
#define LOGDEBUG2
Definition: logger.h:50
#define LOGDEBUG
Definition: logger.h:49
#define LOGERROR
Definition: logger.h:46
#define L_CODEC
Definition: logger.h:63
#define LOGWARNING
Definition: logger.h:47
#define LOGFATAL
Logger macros.
Definition: logger.h:45
Misc function header file.
static bool isInterlacedFrame(AVFrame *frame)
Check, if this is an interlaced frame.
Definition: misc.h:47
Thread classes header file.
Rendering class header file.
Videostream class header file.