MythTV master
mythdeinterlacer.cpp
Go to the documentation of this file.
1// MythTV
2#include "libmythbase/mythconfig.h"
4
5#include "mythavutil.h"
6#include "mythdeinterlacer.h"
7#include "mythvideoprofile.h"
8
9#include <algorithm>
10#include <thread>
11
12extern "C" {
13#include "libavfilter/buffersrc.h"
14#include "libavfilter/buffersink.h"
15#include "libavutil/cpu.h"
16}
17
18#include <QtGlobal>
19#if QT_VERSION >= QT_VERSION_CHECK(6,5,0)
20#include <QtProcessorDetection>
21#endif
22
23#ifdef Q_PROCESSOR_X86_64
24# include <emmintrin.h>
25static const bool s_haveSIMD = true;
26#elif HAVE_INTRINSICS_NEON
27# include <arm_neon.h>
28static const bool s_haveSIMD = av_get_cpu_flags() & AV_CPU_FLAG_NEON;
29#endif
30
31#define LOC QString("MythDeint: ")
32
51{
52 Cleanup();
53}
54
73 MythVideoProfile *Profile, bool Force)
74{
75 // nothing to see here
76 if (!Frame || !is_interlaced(Scan))
77 {
78 Cleanup();
79 return;
80 }
81
82 if (Frame->m_alreadyDeinterlaced)
83 return;
84
85 // Sanity check frame format
86 if (!MythVideoFrame::YUVFormat(Frame->m_type))
87 {
88 Cleanup();
89 return;
90 }
91
92 // check for software deinterlacing
93 bool doublerate = true;
94 bool topfieldfirst = Frame->m_interlacedReverse ? !Frame->m_topFieldFirst : Frame->m_topFieldFirst;
95
96 auto deinterlacer = Frame->GetDoubleRateOption(DEINT_CPU);
97 auto other = Frame->GetDoubleRateOption(DEINT_SHADER);
98 if (other)
99 {
100 Cleanup();
101 return;
102 }
103
104 if (!deinterlacer)
105 {
106 doublerate = false;
107 deinterlacer = Frame->GetSingleRateOption(DEINT_CPU);
108 other = Frame->GetSingleRateOption(DEINT_SHADER);
109 if (!deinterlacer || other)
110 {
111 Cleanup();
112 return;
113 }
114 }
115
116 // libavfilter will not deinterlace NV12 frames. Allow shaders in this case.
117 // libswscale (for bob/onefield) is fine, as is our linearblend.
118 if ((deinterlacer == DEINT_HIGH) && MythVideoFrame::FormatIsNV12(Frame->m_type))
119 {
120 Cleanup();
121 Frame->m_deinterlaceSingle = Frame->m_deinterlaceSingle | DEINT_SHADER;
122 Frame->m_deinterlaceDouble = Frame->m_deinterlaceDouble | DEINT_SHADER;
123 return;
124 }
125
126 // certain material (telecined?) continually changes the field order. This
127 // cripples performance as the libavfiler deinterlacer is continually
128 // destroyed and recreated. Using 'auto' for the field order breaks user
129 // override of the interlacing order - so track switches in the field order
130 // and switch to auto if it is too frequent
131 bool fieldorderchanged = topfieldfirst != m_topFirst;
132 if (fieldorderchanged && deinterlacer != DEINT_HIGH)
133 {
134 fieldorderchanged = false;
135 m_topFirst = topfieldfirst;
136 }
137
138 bool otherchanged = Frame->m_width != m_width || Frame->m_height != m_height ||
139 deinterlacer != m_deintType || doublerate != m_doubleRate ||
140 Frame->m_type != m_inputType;
141
142 if ((deinterlacer == DEINT_HIGH) && fieldorderchanged)
143 {
144 bool alreadyauto = m_autoFieldOrder;
145 bool change = m_lastFieldChange && (qAbs(m_lastFieldChange - Frame->m_frameCounter) < 10);
146 if (change && !m_autoFieldOrder)
147 {
148 m_autoFieldOrder = true;
149 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Enabled 'auto' for field order");
150 }
151 else if (!change && m_autoFieldOrder)
152 {
153 m_autoFieldOrder = false;
154 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Disabled 'auto' for field order");
155 }
156 if (alreadyauto && m_autoFieldOrder)
157 fieldorderchanged = false;
158 m_lastFieldChange = Frame->m_frameCounter;
159 }
160
161 // Check for a change in input or deinterlacer
162 if (fieldorderchanged || otherchanged)
163 {
164 LOG(VB_GENERAL, LOG_INFO, LOC +
165 QString("Deinterlacer change: %1x%2 %3 dr:%4 tff:%5 -> %6x%7 %8 dr:%9 tff:%10")
167 .arg(m_doubleRate).arg(m_topFirst)
168 .arg(Frame->m_width).arg(Frame->m_height)
170 .arg(doublerate).arg(topfieldfirst));
171 if (!Initialise(Frame, deinterlacer, doublerate, topfieldfirst, Profile))
172 {
173 Cleanup();
174 return;
175 }
176 Force = true;
177 }
178 else if ((m_deintType == DEINT_HIGH) && (qAbs(Frame->m_frameCounter - m_discontinuityCounter) > 1))
179 {
180 if (!Initialise(Frame, deinterlacer, doublerate, topfieldfirst, Profile))
181 {
182 Cleanup();
183 return;
184 }
185 Force = true;
186 }
187
188 m_discontinuityCounter = Frame->m_frameCounter;
189
190 // Set in use deinterlacer for debugging
191 Frame->m_deinterlaceInuse = m_deintType | DEINT_CPU;
192 Frame->m_deinterlaceInuse2x = m_doubleRate;
193
194 // onefield or bob
196 {
197 OneField(Frame, Scan);
198 return;
199 }
200
201 // linear blend
203 {
204 Blend(Frame, Scan);
205 return;
206 }
207
208 // We need a filter
209 if (!m_graph)
210 return;
211
212 // Convert VideoFrame to AVFrame - no copy
214 {
215 LOG(VB_GENERAL, LOG_ERR, LOC + "Error converting frame");
216 return;
217 }
218
219 m_frame->width = Frame->m_width;
220 m_frame->height = Frame->m_height;
221 m_frame->format = Frame->m_pixFmt;
222 m_frame->pts = Frame->m_timecode.count();
223
224 auto AddFrame = [](AVFilterContext* Source, AVFrame* AvFrame)
225 { return av_buffersrc_add_frame(Source, AvFrame); };
226
227 // Add frame on first pass only
228 if (kScan_Interlaced == Scan)
229 {
230 if (AddFrame(m_source, m_frame) < 0)
231 {
232 LOG(VB_GENERAL, LOG_ERR, LOC + "Error adding frame");
233 return;
234 }
235 // yadif needs 2 frames to work with - add the frame again if we
236 // need a result now
237 if (Force)
238 AddFrame(m_source, m_frame);
239 }
240
241 // Retrieve frame
242 int res = av_buffersink_get_frame(m_sink, m_frame);
243 if (res < 0)
244 {
245 if (res == AVERROR(EAGAIN))
246 return;
247 LOG(VB_GENERAL, LOG_ERR, LOC + "Error retrieving frame");
248 return;
249 }
250
251 // Ensure AVFrame is in the expected format
252 if ((m_frame->format != m_inputFmt) || (Frame->m_pitches[0] < m_frame->linesize[0]) ||
253 (Frame->m_pitches[1] < m_frame->linesize[1]) || (Frame->m_pitches[2] < m_frame->linesize[2]))
254 {
255 LOG(VB_GENERAL, LOG_ERR, LOC + "Filter returned unexpected format");
256 return;
257 }
258
259 // Copy AVFrame back to VideoFrame
260 uint count = MythVideoFrame::GetNumPlanes(Frame->m_type);
261 for (uint plane = 0; plane < count; ++plane)
262 {
263 MythVideoFrame::CopyPlane(Frame->m_buffer + Frame->m_offsets[plane], Frame->m_pitches[plane],
264 m_frame->data[plane], m_frame->linesize[plane],
267 }
268
269 Frame->m_timecode = std::chrono::milliseconds(m_frame->pts);
270 Frame->m_alreadyDeinterlaced = true;
271
272 // Free frame data
273 av_frame_unref(m_frame);
274}
275
277{
278 if (m_graph || m_swsContext)
279 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Removing CPU deinterlacer");
280
281 avfilter_graph_free(&m_graph);
282 sws_freeContext(m_swsContext);
283 m_swsContext = nullptr;
285 m_autoFieldOrder = false;
287
288 if (m_bobFrame)
289 {
290 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Removing 'bob' cache frame");
291 delete m_bobFrame;
292 m_bobFrame = nullptr;
293 }
294
296}
297
300 bool DoubleRate, bool TopFieldFirst, MythVideoProfile *Profile)
301{
302 auto autofieldorder = m_autoFieldOrder;
303 auto lastfieldchange = m_lastFieldChange;
304 Cleanup();
305 m_source = nullptr;
306 m_sink = nullptr;
307
308 if (!Frame)
309 return false;
310
311 m_width = Frame->m_width;
312 m_height = Frame->m_height;
313 m_inputType = Frame->m_type;
315 auto name = MythVideoFrame::DeinterlacerName(Deinterlacer | DEINT_CPU, DoubleRate);
316
317 // simple onefield/bob?
318 if (Deinterlacer == DEINT_BASIC || Deinterlacer == DEINT_MEDIUM)
319 {
320 m_deintType = Deinterlacer;
321 m_doubleRate = DoubleRate;
322 m_topFirst = TopFieldFirst;
323 if (Deinterlacer == DEINT_BASIC)
324 {
325 m_swsContext = sws_getCachedContext(m_swsContext, m_width, m_height >> 1, m_inputFmt,
326 m_width, m_height, m_inputFmt, SWS_FAST_BILINEAR,
327 nullptr, nullptr, nullptr);
328 if (m_swsContext == nullptr)
329 return false;
330 }
331 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Using deinterlacer '%1'").arg(name));
332 return true;
333 }
334
335 // Sanity check the frame formats
337 {
338 LOG(VB_GENERAL, LOG_ERR, LOC + "Inconsistent frame formats");
339 return false;
340 }
341
342 m_graph = avfilter_graph_alloc();
343 if (!m_graph)
344 return false;
345
346 uint threads = 1;
347 if (Profile)
348 {
349 threads = std::clamp(Profile->GetMaxCPUs(), 1U, std::max(8U, std::thread::hardware_concurrency()));
350 }
351
352 AVFilterInOut* inputs = nullptr;
353 AVFilterInOut* outputs = nullptr;
354
355 int parity {1};
357 parity = -1;
358 else if (TopFieldFirst)
359 parity = 0;
360 auto deint = QString("yadif=mode=%1:parity=%2:threads=%3")
361 .arg(DoubleRate ? 1 : 0).arg(parity).arg(threads);
362
363 auto graph = QString("buffer=video_size=%1x%2:pix_fmt=%3:time_base=1/1[in];[in]%4[out];[out] buffersink")
364 .arg(m_width).arg(m_height).arg(m_inputFmt).arg(deint);
365
366 int res = avfilter_graph_parse2(m_graph, graph.toLatin1().constData(), &inputs, &outputs);
367 if (res >= 0 && !inputs && !outputs)
368 {
369 res = avfilter_graph_config(m_graph, nullptr);
370 if (res >= 0)
371 {
372 m_source = avfilter_graph_get_filter(m_graph, "Parsed_buffer_0");
373 m_sink = avfilter_graph_get_filter(m_graph, "Parsed_buffersink_2");
374
375 if (m_source && m_sink)
376 {
377 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Created deinterlacer '%1' (%2 threads)")
378 .arg(name).arg(threads));
379 m_deintType = Deinterlacer;
380 m_doubleRate = DoubleRate;
381 m_topFirst = TopFieldFirst;
382 m_autoFieldOrder = autofieldorder;
383 m_lastFieldChange = lastfieldchange;
384 return true;
385 }
386 }
387 }
388
389 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create avfilter");
391 avfilter_inout_free(&inputs);
392 avfilter_inout_free(&outputs);
393 return false;
394}
395
397{
398 if (!Frame)
399 return false;
400
401 if (m_bobFrame && !(m_bobFrame->m_bufferSize == Frame->m_bufferSize) && (m_bobFrame->m_width == Frame->m_width) &&
402 (m_bobFrame->m_height == Frame->m_height) && (m_bobFrame->m_type == Frame->m_type))
403 {
404 delete m_bobFrame;
405 m_bobFrame = nullptr;
406 }
407
408 if (!m_bobFrame)
409 {
411 Frame->m_bufferSize, Frame->m_width, Frame->m_height);
412 LOG(VB_PLAYBACK, LOG_INFO, "Created new 'bob' cache frame");
413 }
414
415 return m_bobFrame && m_bobFrame->m_buffer != nullptr;
416}
417
419{
420 if (!m_swsContext)
421 return;
422
423 // we need a frame for caching - both to preserve the second field if
424 // needed and ensure we are not filtering in place (i.e. from src to src).
425 if (!SetUpCache(Frame))
426 return;
427
428 // copy/cache on first pass
429 if (kScan_Interlaced == Scan)
430 memcpy(m_bobFrame->m_buffer, Frame->m_buffer, m_bobFrame->m_bufferSize);
431
432 // Convert VideoFrame to AVFrame - no copy
433 AVFrame dstframe;
435 (MythAVUtil::FillAVFrame(&dstframe, Frame, m_inputFmt) < 1))
436 {
437 LOG(VB_GENERAL, LOG_ERR, LOC + "Error converting frame");
438 return;
439 }
440
441 bool topfield = Scan == kScan_Interlaced ? m_topFirst : !m_topFirst;
442 dstframe.width = Frame->m_width;
443 dstframe.height = Frame->m_height;
444 dstframe.format = Frame->m_pixFmt;
445
446 m_frame->width = m_bobFrame->m_width;
447 m_frame->format = m_bobFrame->m_pixFmt;
448
449 // Fake the frame height and stride to simulate a single field
450 m_frame->height = Frame->m_height >> 1;
451 m_frame->flags &= ~AV_FRAME_FLAG_INTERLACED;
453 for (uint i = 0; i < nbplanes; i++)
454 {
455 if (!topfield)
456 m_frame->data[i] = m_frame->data[i] + m_frame->linesize[i];
457 m_frame->linesize[i] = m_frame->linesize[i] << 1;
458 }
459
460 // and scale to full height
461 int result = sws_scale(m_swsContext, m_frame->data, m_frame->linesize, 0, m_frame->height,
462 dstframe.data, dstframe.linesize);
463
464 if (result != Frame->m_height)
465 {
466 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Error scaling frame: height %1 expected %2")
467 .arg(result).arg(Frame->m_height));
468 }
469 Frame->m_alreadyDeinterlaced = true;
470}
471
472inline static uint32_t avg(uint32_t A, uint32_t B)
473{
474 return (((A ^ B) & 0xFEFEFEFEUL) >> 1) + (A & B);
475}
476
477// Optimised version with 4x4 alignment
478static inline void BlendC4x4(unsigned char *Src, int Width, int FirstRow, int LastRow, int Pitch,
479 unsigned char *Dst, int DstPitch, bool Second)
480{
481 int srcpitch = Pitch << 1;
482 int dstpitch = DstPitch << 1;
483 int maxrows = LastRow - 3;
484
485 unsigned char *above = Src + ((FirstRow - 1) * static_cast<ptrdiff_t>(Pitch));
486 unsigned char *dest1 = Dst + (FirstRow * static_cast<ptrdiff_t>(DstPitch));
487 unsigned char *middle = above + srcpitch;
488 unsigned char *dest2 = dest1 + dstpitch;
489 unsigned char *below = middle + srcpitch;
490 unsigned char *dstcpy1 = Dst + ((FirstRow - 1) * static_cast<ptrdiff_t>(DstPitch));
491 unsigned char *dstcpy2 = dstcpy1 + dstpitch;
492
493 srcpitch <<= 1;
494 dstpitch <<= 1;
495
496 // 4 rows per pass
497 for (int row = FirstRow; row < maxrows; row += 4)
498 {
499 if (Second)
500 {
501 // On second pass, copy over the original, current field
502 memcpy(dstcpy1, above, static_cast<size_t>(DstPitch));
503 memcpy(dstcpy2, middle, static_cast<size_t>(DstPitch));
504 dstcpy1 += dstpitch;
505 dstcpy2 += dstpitch;
506 }
507 for (int col = 0; col < Width; col += 4)
508 {
509 *reinterpret_cast<uint32_t*>(&dest1[col]) =
510 avg(*reinterpret_cast<uint32_t*>(&above[col]), *reinterpret_cast<uint32_t*>(&middle[col]));
511 *reinterpret_cast<uint32_t*>(&dest2[col]) =
512 avg(*reinterpret_cast<uint32_t*>(&middle[col]), *reinterpret_cast<uint32_t*>(&below[col]));
513 }
514 above += srcpitch;
515 middle += srcpitch;
516 below += srcpitch;
517 dest1 += dstpitch;
518 dest2 += dstpitch;
519 }
520}
521
522#if defined(Q_PROCESSOR_X86_64) || HAVE_INTRINSICS_NEON
523// SIMD optimised version with 16x4 alignment
524static inline void BlendSIMD16x4(unsigned char *Src, int Width, int FirstRow, int LastRow, int Pitch,
525 unsigned char *Dst, int DstPitch, bool Second)
526{
527 int srcpitch = Pitch << 1;
528 int dstpitch = DstPitch << 1;
529 int maxrows = LastRow - 3;
530
531 unsigned char *above = Src + ((FirstRow - 1) * static_cast<ptrdiff_t>(Pitch));
532 unsigned char *dest1 = Dst + (FirstRow * static_cast<ptrdiff_t>(DstPitch));
533 unsigned char *middle = above + srcpitch;
534 unsigned char *dest2 = dest1 + dstpitch;
535 unsigned char *below = middle + srcpitch;
536 unsigned char *dstcpy1 = Dst + ((FirstRow - 1) * static_cast<ptrdiff_t>(DstPitch));
537 unsigned char *dstcpy2 = dstcpy1 + dstpitch;
538
539 srcpitch <<= 1;
540 dstpitch <<= 1;
541
542 // 4 rows per pass
543 for (int row = FirstRow; row < maxrows; row += 4)
544 {
545 if (Second)
546 {
547 // On second pass, copy over the original, current field
548 memcpy(dstcpy1, above, static_cast<size_t>(DstPitch));
549 memcpy(dstcpy2, middle, static_cast<size_t>(DstPitch));
550 dstcpy1 += dstpitch;
551 dstcpy2 += dstpitch;
552 }
553 for (int col = 0; col < Width; col += 16)
554 {
555#ifdef Q_PROCESSOR_X86_64
556 __m128i mid = *reinterpret_cast<__m128i*>(&middle[col]);
557 *reinterpret_cast<__m128i*>(&dest1[col]) =
558 _mm_avg_epu8(*reinterpret_cast<__m128i*>(&above[col]), mid);
559 *reinterpret_cast<__m128i*>(&dest2[col]) =
560 _mm_avg_epu8(*reinterpret_cast<__m128i*>(&below[col]), mid);
561#endif
562#if HAVE_INTRINSICS_NEON
563 uint8x16_t mid = *reinterpret_cast<uint8x16_t*>(&middle[col]);
564 *reinterpret_cast<uint8x16_t*>(&dest1[col]) =
565 vrhaddq_u8(*reinterpret_cast<uint8x16_t*>(&above[col]), mid);
566 *reinterpret_cast<uint8x16_t*>(&dest2[col]) =
567 vrhaddq_u8(*reinterpret_cast<uint8x16_t*>(&below[col]), mid);
568#endif
569 }
570 above += srcpitch;
571 middle += srcpitch;
572 below += srcpitch;
573 dest1 += dstpitch;
574 dest2 += dstpitch;
575 }
576}
577
578// SIMD optimised version with 16x4 alignment for 10/12/16bit video
579static inline void BlendSIMD8x4(unsigned char *Src, int Width, int FirstRow, int LastRow, int Pitch,
580 unsigned char *Dst, int DstPitch, bool Second)
581{
582 int srcpitch = Pitch << 1;
583 int dstpitch = DstPitch << 1;
584 int maxrows = LastRow - 3;
585
586 unsigned char *above = Src + ((FirstRow - 1) * static_cast<ptrdiff_t>(Pitch));
587 unsigned char *dest1 = Dst + (FirstRow * static_cast<ptrdiff_t>(DstPitch));
588 unsigned char *middle = above + srcpitch;
589 unsigned char *dest2 = dest1 + dstpitch;
590 unsigned char *below = middle + srcpitch;
591 unsigned char *dstcpy1 = Dst + ((FirstRow - 1) * static_cast<ptrdiff_t>(DstPitch));
592 unsigned char *dstcpy2 = dstcpy1 + dstpitch;
593
594 srcpitch <<= 1;
595 dstpitch <<= 1;
596
597 // 4 rows per pass
598 for (int row = FirstRow; row < maxrows; row += 4)
599 {
600 if (Second)
601 {
602 // On second pass, copy over the original, current field
603 memcpy(dstcpy1, above, static_cast<size_t>(DstPitch));
604 memcpy(dstcpy2, middle, static_cast<size_t>(DstPitch));
605 dstcpy1 += dstpitch;
606 dstcpy2 += dstpitch;
607 }
608 for (int col = 0; col < Width; col += 16)
609 {
610#ifdef Q_PROCESSOR_X86_64
611 __m128i mid = *reinterpret_cast<__m128i*>(&middle[col]);
612 *reinterpret_cast<__m128i*>(&dest1[col]) =
613 _mm_avg_epu16(*reinterpret_cast<__m128i*>(&above[col]), mid);
614 *reinterpret_cast<__m128i*>(&dest2[col]) =
615 _mm_avg_epu16(*reinterpret_cast<__m128i*>(&below[col]), mid);
616#endif
617#if HAVE_INTRINSICS_NEON
618 uint16x8_t mid = *reinterpret_cast<uint16x8_t*>(&middle[col]);
619 *reinterpret_cast<uint16x8_t*>(&dest1[col]) =
620 vrhaddq_u16(*reinterpret_cast<uint16x8_t*>(&above[col]), mid);
621 *reinterpret_cast<uint16x8_t*>(&dest2[col]) =
622 vrhaddq_u16(*reinterpret_cast<uint16x8_t*>(&below[col]), mid);
623#endif
624 }
625 above += srcpitch;
626 middle += srcpitch;
627 below += srcpitch;
628 dest1 += dstpitch;
629 dest2 += dstpitch;
630 }
631}
632#endif
633
635{
636 if (Frame->m_height < 16 || Frame->m_width < 16)
637 return;
638
639 bool second = false;
640 MythVideoFrame *src = Frame;
641
642 if (m_doubleRate)
643 {
644 if (!SetUpCache(Frame))
645 return;
646 // copy/cache on first pass.
647 if (kScan_Interlaced == Scan)
648 memcpy(m_bobFrame->m_buffer, Frame->m_buffer, m_bobFrame->m_bufferSize);
649 else
650 second = true;
651 src = m_bobFrame;
652 }
653
654 bool hidepth = MythVideoFrame::ColorDepth(src->m_type) > 8;
655 bool top = second ? !m_topFirst : m_topFirst;
657 for (uint plane = 0; plane < count; plane++)
658 {
659 int height = MythVideoFrame::GetHeightForPlane(src->m_type, src->m_height, plane);
660 int firstrow = top ? 1 : 2;
661 bool height4 = (height % 4) == 0;
662 bool width4 = (src->m_pitches[plane] % 4) == 0;
663 // N.B. all frames allocated by MythTV should have 16 byte alignment
664 // for all planes
665#if defined(Q_PROCESSOR_X86_64) || HAVE_INTRINSICS_NEON
666 bool width16 = (src->m_pitches[plane] % 16) == 0;
667 // profiling SSE2 suggests it is usually 4x faster - as expected
668 if (s_haveSIMD && height4 && width16)
669 {
670 if (hidepth)
671 {
672 BlendSIMD8x4(src->m_buffer + src->m_offsets[plane],
674 firstrow, height, src->m_pitches[plane],
675 Frame->m_buffer + Frame->m_offsets[plane], Frame->m_pitches[plane],
676 second);
677 }
678 else
679 {
680 BlendSIMD16x4(src->m_buffer + src->m_offsets[plane],
682 firstrow, height, src->m_pitches[plane],
683 Frame->m_buffer + Frame->m_offsets[plane], Frame->m_pitches[plane],
684 second);
685 }
686 }
687 else
688#endif
689 // N.B. There is no 10bit support here - but it shouldn't be necessary
690 // as everything should be 16byte aligned and 10/12bit interlaced video
691 // is virtually unheard of.
692 if (width4 && height4 && !hidepth)
693 {
694 BlendC4x4(src->m_buffer + src->m_offsets[plane],
696 firstrow, height, src->m_pitches[plane],
697 Frame->m_buffer + Frame->m_offsets[plane], Frame->m_pitches[plane],
698 second);
699 }
700 }
701 Frame->m_alreadyDeinterlaced = true;
702}
AVFrame AVFrame
static VideoFrameType PixelFormatToFrameType(AVPixelFormat Fmt)
Definition: mythavutil.cpp:75
static int FillAVFrame(AVFrame *Frame, const MythVideoFrame *From, AVPixelFormat Fmt=AV_PIX_FMT_NONE)
Initialise AVFrame with content from MythVideoFrame.
Definition: mythavutil.cpp:202
static AVPixelFormat FrameTypeToPixelFormat(VideoFrameType Type)
Definition: mythavutil.cpp:31
void OneField(MythVideoFrame *Frame, FrameScanType Scan)
bool Initialise(MythVideoFrame *Frame, MythDeintType Deinterlacer, bool DoubleRate, bool TopFieldFirst, MythVideoProfile *Profile)
Initialise deinterlacing using the given MythDeintType.
AVPixelFormat m_inputFmt
void Filter(MythVideoFrame *Frame, FrameScanType Scan, MythVideoProfile *Profile, bool Force=false)
Deinterlace Frame if needed.
VideoFrameType m_inputType
AVFilterGraph * m_graph
MythDeintType m_deintType
uint64_t m_lastFieldChange
AVFilterContext * m_sink
void Blend(MythVideoFrame *Frame, FrameScanType Scan)
uint64_t m_discontinuityCounter
AVFilterContext * m_source
MythVideoFrame * m_bobFrame
bool SetUpCache(MythVideoFrame *Frame)
SwsContext * m_swsContext
MythAVFrame m_frame
VideoFrameType m_type
Definition: mythframe.h:118
static uint GetNumPlanes(VideoFrameType Type)
Definition: mythframe.h:213
static int GetPitchForPlane(VideoFrameType Type, int Width, uint Plane)
Definition: mythframe.h:303
static QString DeinterlacerName(MythDeintType Deint, bool DoubleRate, VideoFrameType Format=FMT_NONE)
Definition: mythframe.cpp:466
static bool FormatIsNV12(VideoFrameType Type)
Definition: mythframe.h:455
static QString FormatDescription(VideoFrameType Type)
Definition: mythframe.cpp:372
size_t m_bufferSize
Definition: mythframe.h:123
static int GetHeightForPlane(VideoFrameType Type, int Height, uint Plane)
Definition: mythframe.h:257
FramePitches m_pitches
Definition: mythframe.h:141
uint8_t * m_buffer
Definition: mythframe.h:119
static uint8_t * GetAlignedBuffer(size_t Size)
Definition: mythframe.cpp:434
static bool YUVFormat(VideoFrameType Type)
Definition: mythframe.h:465
static void CopyPlane(uint8_t *To, int ToPitch, const uint8_t *From, int FromPitch, int PlaneWidth, int PlaneHeight)
Definition: mythframe.cpp:192
static int ColorDepth(int Format)
Definition: mythframe.h:398
static int GetWidthForPlane(VideoFrameType Type, int Width, uint Plane)
Definition: mythframe.h:353
FrameOffsets m_offsets
Definition: mythframe.h:142
uint GetMaxCPUs() const
unsigned int uint
Definition: compat.h:60
#define LOC
static void BlendC4x4(unsigned char *Src, int Width, int FirstRow, int LastRow, int Pitch, unsigned char *Dst, int DstPitch, bool Second)
static uint32_t avg(uint32_t A, uint32_t B)
MythDeintType
Definition: mythframe.h:67
@ DEINT_HIGH
Definition: mythframe.h:71
@ DEINT_MEDIUM
Definition: mythframe.h:70
@ DEINT_BASIC
Definition: mythframe.h:69
@ DEINT_NONE
Definition: mythframe.h:68
@ DEINT_SHADER
Definition: mythframe.h:73
@ DEINT_CPU
Definition: mythframe.h:72
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
static QString Source(const QNetworkRequest &request)
Definition: netstream.cpp:139
static eu8 clamp(eu8 value, eu8 low, eu8 high)
Definition: pxsup2dast.c:204
FrameScanType
Definition: videoouttypes.h:95
@ kScan_Interlaced
Definition: videoouttypes.h:98
bool is_interlaced(FrameScanType Scan)