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