2 #include "libmythbase/mythconfig.h"
13 #include "libavfilter/buffersrc.h"
14 #include "libavfilter/buffersink.h"
15 #include "libavutil/cpu.h"
20 #ifdef Q_PROCESSOR_X86_64
21 # include <emmintrin.h>
22 static const bool s_haveSIMD =
true;
23 #elif HAVE_INTRINSICS_NEON
24 # include <arm_neon.h>
25 static const bool s_haveSIMD = av_get_cpu_flags() & AV_CPU_FLAG_NEON;
28 #define LOC QString("MythDeint: ")
79 if (
Frame->m_alreadyDeinterlaced)
90 bool doublerate =
true;
91 bool topfieldfirst =
Frame->m_interlacedReverse ? !
Frame->m_topFieldFirst :
Frame->m_topFieldFirst;
106 if (!deinterlacer || other)
128 bool fieldorderchanged = topfieldfirst !=
m_topFirst;
129 if (fieldorderchanged && deinterlacer !=
DEINT_HIGH)
131 fieldorderchanged =
false;
139 if ((deinterlacer ==
DEINT_HIGH) && fieldorderchanged)
146 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Enabled 'auto' for field order");
151 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Disabled 'auto' for field order");
154 fieldorderchanged =
false;
159 if (fieldorderchanged || otherchanged)
161 LOG(VB_GENERAL, LOG_INFO,
LOC +
162 QString(
"Deinterlacer change: %1x%2 %3 dr:%4 tff:%5 -> %6x%7 %8 dr:%9 tff:%10")
167 .arg(doublerate).arg(topfieldfirst));
168 if (!
Initialise(
Frame, deinterlacer, doublerate, topfieldfirst, Profile))
177 if (!
Initialise(
Frame, deinterlacer, doublerate, topfieldfirst, Profile))
212 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Error converting frame");
221 auto AddFrame = [](AVFilterContext*
Source,
AVFrame* AvFrame)
222 {
return av_buffersrc_add_frame(
Source, AvFrame); };
229 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Error adding frame");
242 if (res == AVERROR(EAGAIN))
244 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Error retrieving frame");
252 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Filter returned unexpected format");
258 for (
uint plane = 0; plane < count; ++plane)
266 Frame->m_timecode = std::chrono::milliseconds(
m_frame->pts);
267 Frame->m_alreadyDeinterlaced =
true;
276 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Removing CPU deinterlacer");
287 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Removing 'bob' cache frame");
324 nullptr,
nullptr,
nullptr);
328 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Using deinterlacer '%1'").arg(name));
335 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Inconsistent frame formats");
339 m_graph = avfilter_graph_alloc();
346 threads =
std::clamp(Profile->
GetMaxCPUs(), 1U, std::max(8U, std::thread::hardware_concurrency()));
349 AVFilterInOut* inputs =
nullptr;
350 AVFilterInOut* outputs =
nullptr;
355 else if (TopFieldFirst)
357 auto deint = QString(
"yadif=mode=%1:parity=%2:threads=%3")
358 .arg(DoubleRate ? 1 : 0).arg(parity).arg(threads);
360 auto graph = QString(
"buffer=video_size=%1x%2:pix_fmt=%3:time_base=1/1[in];[in]%4[out];[out] buffersink")
363 int res = avfilter_graph_parse2(
m_graph, graph.toLatin1().constData(), &inputs, &outputs);
364 if (res >= 0 && !inputs && !outputs)
366 res = avfilter_graph_config(
m_graph,
nullptr);
370 m_sink = avfilter_graph_get_filter(
m_graph,
"Parsed_buffersink_2");
374 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Created deinterlacer '%1' (%2 threads)")
375 .arg(name).arg(threads));
386 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to create avfilter");
388 avfilter_inout_free(&inputs);
389 avfilter_inout_free(&outputs);
409 LOG(VB_PLAYBACK, LOG_INFO,
"Created new 'bob' cache frame");
434 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Error converting frame");
439 dstframe.width =
Frame->m_width;
440 dstframe.height =
Frame->m_height;
441 dstframe.format =
Frame->m_pixFmt;
450 for (
uint i = 0; i < nbplanes; i++)
459 dstframe.data, dstframe.linesize);
461 if (result !=
Frame->m_height)
463 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Error scaling frame: height %1 expected %2")
464 .arg(result).arg(
Frame->m_height));
466 Frame->m_alreadyDeinterlaced =
true;
469 inline static uint32_t
avg(uint32_t A, uint32_t B)
471 return (((A ^ B) & 0xFEFEFEFEUL) >> 1) + (A & B);
475 static inline void BlendC4x4(
unsigned char *Src,
int Width,
int FirstRow,
int LastRow,
int Pitch,
476 unsigned char *Dst,
int DstPitch,
bool Second)
478 int srcpitch = Pitch << 1;
479 int dstpitch = DstPitch << 1;
480 int maxrows = LastRow - 3;
482 unsigned char *above = Src + ((FirstRow - 1) *
static_cast<ptrdiff_t
>(Pitch));
483 unsigned char *dest1 = Dst + (FirstRow *
static_cast<ptrdiff_t
>(DstPitch));
484 unsigned char *middle = above + srcpitch;
485 unsigned char *dest2 = dest1 + dstpitch;
486 unsigned char *below = middle + srcpitch;
487 unsigned char *dstcpy1 = Dst + ((FirstRow - 1) *
static_cast<ptrdiff_t
>(DstPitch));
488 unsigned char *dstcpy2 = dstcpy1 + dstpitch;
494 for (
int row = FirstRow; row < maxrows; row += 4)
499 memcpy(dstcpy1, above,
static_cast<size_t>(DstPitch));
500 memcpy(dstcpy2, middle,
static_cast<size_t>(DstPitch));
504 for (
int col = 0; col < Width; col += 4)
506 *
reinterpret_cast<uint32_t*
>(&dest1[col]) =
507 avg(*
reinterpret_cast<uint32_t*
>(&above[col]), *
reinterpret_cast<uint32_t*
>(&middle[col]));
508 *
reinterpret_cast<uint32_t*
>(&dest2[col]) =
509 avg(*
reinterpret_cast<uint32_t*
>(&middle[col]), *
reinterpret_cast<uint32_t*
>(&below[col]));
519 #if defined(Q_PROCESSOR_X86_64) || HAVE_INTRINSICS_NEON
521 static inline void BlendSIMD16x4(
unsigned char *Src,
int Width,
int FirstRow,
int LastRow,
int Pitch,
522 unsigned char *Dst,
int DstPitch,
bool Second)
524 int srcpitch = Pitch << 1;
525 int dstpitch = DstPitch << 1;
526 int maxrows = LastRow - 3;
528 unsigned char *above = Src + ((FirstRow - 1) *
static_cast<ptrdiff_t
>(Pitch));
529 unsigned char *dest1 = Dst + (FirstRow *
static_cast<ptrdiff_t
>(DstPitch));
530 unsigned char *middle = above + srcpitch;
531 unsigned char *dest2 = dest1 + dstpitch;
532 unsigned char *below = middle + srcpitch;
533 unsigned char *dstcpy1 = Dst + ((FirstRow - 1) *
static_cast<ptrdiff_t
>(DstPitch));
534 unsigned char *dstcpy2 = dstcpy1 + dstpitch;
540 for (
int row = FirstRow; row < maxrows; row += 4)
545 memcpy(dstcpy1, above,
static_cast<size_t>(DstPitch));
546 memcpy(dstcpy2, middle,
static_cast<size_t>(DstPitch));
550 for (
int col = 0; col < Width; col += 16)
552 #if defined(Q_PROCESSOR_X86_64)
553 __m128i mid = *
reinterpret_cast<__m128i*
>(&middle[col]);
554 *
reinterpret_cast<__m128i*
>(&dest1[col]) =
555 _mm_avg_epu8(*
reinterpret_cast<__m128i*
>(&above[col]), mid);
556 *
reinterpret_cast<__m128i*
>(&dest2[col]) =
557 _mm_avg_epu8(*
reinterpret_cast<__m128i*
>(&below[col]), mid);
559 #if HAVE_INTRINSICS_NEON
560 uint8x16_t mid = *
reinterpret_cast<uint8x16_t*
>(&middle[col]);
561 *
reinterpret_cast<uint8x16_t*
>(&dest1[col]) =
562 vrhaddq_u8(*
reinterpret_cast<uint8x16_t*
>(&above[col]), mid);
563 *
reinterpret_cast<uint8x16_t*
>(&dest2[col]) =
564 vrhaddq_u8(*
reinterpret_cast<uint8x16_t*
>(&below[col]), mid);
576 static inline void BlendSIMD8x4(
unsigned char *Src,
int Width,
int FirstRow,
int LastRow,
int Pitch,
577 unsigned char *Dst,
int DstPitch,
bool Second)
579 int srcpitch = Pitch << 1;
580 int dstpitch = DstPitch << 1;
581 int maxrows = LastRow - 3;
583 unsigned char *above = Src + ((FirstRow - 1) *
static_cast<ptrdiff_t
>(Pitch));
584 unsigned char *dest1 = Dst + (FirstRow *
static_cast<ptrdiff_t
>(DstPitch));
585 unsigned char *middle = above + srcpitch;
586 unsigned char *dest2 = dest1 + dstpitch;
587 unsigned char *below = middle + srcpitch;
588 unsigned char *dstcpy1 = Dst + ((FirstRow - 1) *
static_cast<ptrdiff_t
>(DstPitch));
589 unsigned char *dstcpy2 = dstcpy1 + dstpitch;
595 for (
int row = FirstRow; row < maxrows; row += 4)
600 memcpy(dstcpy1, above,
static_cast<size_t>(DstPitch));
601 memcpy(dstcpy2, middle,
static_cast<size_t>(DstPitch));
605 for (
int col = 0; col < Width; col += 16)
607 #if defined(Q_PROCESSOR_X86_64)
608 __m128i mid = *
reinterpret_cast<__m128i*
>(&middle[col]);
609 *
reinterpret_cast<__m128i*
>(&dest1[col]) =
610 _mm_avg_epu16(*
reinterpret_cast<__m128i*
>(&above[col]), mid);
611 *
reinterpret_cast<__m128i*
>(&dest2[col]) =
612 _mm_avg_epu16(*
reinterpret_cast<__m128i*
>(&below[col]), mid);
614 #if HAVE_INTRINSICS_NEON
615 uint16x8_t mid = *
reinterpret_cast<uint16x8_t*
>(&middle[col]);
616 *
reinterpret_cast<uint16x8_t*
>(&dest1[col]) =
617 vrhaddq_u16(*
reinterpret_cast<uint16x8_t*
>(&above[col]), mid);
618 *
reinterpret_cast<uint16x8_t*
>(&dest2[col]) =
619 vrhaddq_u16(*
reinterpret_cast<uint16x8_t*
>(&below[col]), mid);
633 if (
Frame->m_height < 16 ||
Frame->m_width < 16)
654 for (
uint plane = 0; plane < count; plane++)
657 int firstrow = top ? 1 : 2;
658 bool height4 = (height % 4) == 0;
659 bool width4 = (src->
m_pitches[plane] % 4) == 0;
662 #if defined(Q_PROCESSOR_X86_64) || HAVE_INTRINSICS_NEON
663 bool width16 = (src->
m_pitches[plane] % 16) == 0;
665 if (s_haveSIMD && height4 && width16)
689 if (width4 && height4 && !hidepth)
698 Frame->m_alreadyDeinterlaced =
true;