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