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  auto deint = QString("yadif=mode=%1:parity=%2:threads=%3")
353  .arg(DoubleRate ? 1 : 0).arg(m_autoFieldOrder ? -1 : TopFieldFirst ? 0 : 1).arg(threads);
354 
355  auto graph = QString("buffer=video_size=%1x%2:pix_fmt=%3:time_base=1/1[in];[in]%4[out];[out] buffersink")
356  .arg(m_width).arg(m_height).arg(m_inputFmt).arg(deint);
357 
358  int res = avfilter_graph_parse2(m_graph, graph.toLatin1().constData(), &inputs, &outputs);
359  if (res >= 0 && !inputs && !outputs)
360  {
361  res = avfilter_graph_config(m_graph, nullptr);
362  if (res >= 0)
363  {
364  m_source = avfilter_graph_get_filter(m_graph, "Parsed_buffer_0");
365  m_sink = avfilter_graph_get_filter(m_graph, "Parsed_buffersink_2");
366 
367  if (m_source && m_sink)
368  {
369  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Created deinterlacer '%1' (%2 threads)")
370  .arg(name).arg(threads));
371  m_deintType = Deinterlacer;
372  m_doubleRate = DoubleRate;
373  m_topFirst = TopFieldFirst;
374  m_autoFieldOrder = autofieldorder;
375  m_lastFieldChange = lastfieldchange;
376  return true;
377  }
378  }
379  }
380 
381  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create avfilter");
383  avfilter_inout_free(&inputs);
384  avfilter_inout_free(&outputs);
385  return false;
386 }
387 
389 {
390  if (!Frame)
391  return false;
392 
393  if (m_bobFrame && !((m_bobFrame->m_bufferSize == Frame->m_bufferSize)) && (m_bobFrame->m_width == Frame->m_width) &&
394  (m_bobFrame->m_height == Frame->m_height) && (m_bobFrame->m_type == Frame->m_type))
395  {
396  delete m_bobFrame;
397  m_bobFrame = nullptr;
398  }
399 
400  if (!m_bobFrame)
401  {
403  Frame->m_bufferSize, Frame->m_width, Frame->m_height);
404  LOG(VB_PLAYBACK, LOG_INFO, "Created new 'bob' cache frame");
405  }
406 
407  return m_bobFrame && m_bobFrame->m_buffer != nullptr;
408 }
409 
411 {
412  if (!m_swsContext)
413  return;
414 
415  // we need a frame for caching - both to preserve the second field if
416  // needed and ensure we are not filtering in place (i.e. from src to src).
417  if (!SetUpCache(Frame))
418  return;
419 
420  // copy/cache on first pass
421  if (kScan_Interlaced == Scan)
422  memcpy(m_bobFrame->m_buffer, Frame->m_buffer, m_bobFrame->m_bufferSize);
423 
424  // Convert VideoFrame to AVFrame - no copy
425  AVFrame dstframe;
427  (MythAVUtil::FillAVFrame(&dstframe, Frame, m_inputFmt) < 1))
428  {
429  LOG(VB_GENERAL, LOG_ERR, LOC + "Error converting frame");
430  return;
431  }
432 
433  bool topfield = Scan == kScan_Interlaced ? m_topFirst : !m_topFirst;
434  dstframe.width = Frame->m_width;
435  dstframe.height = Frame->m_height;
436  dstframe.format = Frame->m_pixFmt;
437 
438  m_frame->width = m_bobFrame->m_width;
439  m_frame->format = m_bobFrame->m_pixFmt;
440 
441  // Fake the frame height and stride to simulate a single field
442  m_frame->height = Frame->m_height >> 1;
443  m_frame->interlaced_frame = 0;
445  for (uint i = 0; i < nbplanes; i++)
446  {
447  if (!topfield)
448  m_frame->data[i] = m_frame->data[i] + m_frame->linesize[i];
449  m_frame->linesize[i] = m_frame->linesize[i] << 1;
450  }
451 
452  // and scale to full height
453  int result = sws_scale(m_swsContext, m_frame->data, m_frame->linesize, 0, m_frame->height,
454  dstframe.data, dstframe.linesize);
455 
456  if (result != Frame->m_height)
457  {
458  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Error scaling frame: height %1 expected %2")
459  .arg(result).arg(Frame->m_height));
460  }
461  Frame->m_alreadyDeinterlaced = true;
462 }
463 
464 inline static uint32_t avg(uint32_t A, uint32_t B)
465 {
466  return (((A ^ B) & 0xFEFEFEFEUL) >> 1) + (A & B);
467 }
468 
469 // Optimised version with 4x4 alignment
470 static inline void BlendC4x4(unsigned char *Src, int Width, int FirstRow, int LastRow, int Pitch,
471  unsigned char *Dst, int DstPitch, bool Second)
472 {
473  int srcpitch = Pitch << 1;
474  int dstpitch = DstPitch << 1;
475  int maxrows = LastRow - 3;
476 
477  unsigned char *above = Src + ((FirstRow - 1) * static_cast<ptrdiff_t>(Pitch));
478  unsigned char *dest1 = Dst + (FirstRow * static_cast<ptrdiff_t>(DstPitch));
479  unsigned char *middle = above + srcpitch;
480  unsigned char *dest2 = dest1 + dstpitch;
481  unsigned char *below = middle + srcpitch;
482  unsigned char *dstcpy1 = Dst + ((FirstRow - 1) * static_cast<ptrdiff_t>(DstPitch));
483  unsigned char *dstcpy2 = dstcpy1 + dstpitch;
484 
485  srcpitch <<= 1;
486  dstpitch <<= 1;
487 
488  // 4 rows per pass
489  for (int row = FirstRow; row < maxrows; row += 4)
490  {
491  if (Second)
492  {
493  // On second pass, copy over the original, current field
494  memcpy(dstcpy1, above, static_cast<size_t>(DstPitch));
495  memcpy(dstcpy2, middle, static_cast<size_t>(DstPitch));
496  dstcpy1 += dstpitch;
497  dstcpy2 += dstpitch;
498  }
499  for (int col = 0; col < Width; col += 4)
500  {
501  *reinterpret_cast<uint32_t*>(&dest1[col]) =
502  avg(*reinterpret_cast<uint32_t*>(&above[col]), *reinterpret_cast<uint32_t*>(&middle[col]));
503  *reinterpret_cast<uint32_t*>(&dest2[col]) =
504  avg(*reinterpret_cast<uint32_t*>(&middle[col]), *reinterpret_cast<uint32_t*>(&below[col]));
505  }
506  above += srcpitch;
507  middle += srcpitch;
508  below += srcpitch;
509  dest1 += dstpitch;
510  dest2 += dstpitch;
511  }
512 }
513 
514 #if defined(Q_PROCESSOR_X86_64) || HAVE_INTRINSICS_NEON
515 // SIMD optimised version with 16x4 alignment
516 static inline void BlendSIMD16x4(unsigned char *Src, int Width, int FirstRow, int LastRow, int Pitch,
517  unsigned char *Dst, int DstPitch, bool Second)
518 {
519  int srcpitch = Pitch << 1;
520  int dstpitch = DstPitch << 1;
521  int maxrows = LastRow - 3;
522 
523  unsigned char *above = Src + ((FirstRow - 1) * static_cast<ptrdiff_t>(Pitch));
524  unsigned char *dest1 = Dst + (FirstRow * static_cast<ptrdiff_t>(DstPitch));
525  unsigned char *middle = above + srcpitch;
526  unsigned char *dest2 = dest1 + dstpitch;
527  unsigned char *below = middle + srcpitch;
528  unsigned char *dstcpy1 = Dst + ((FirstRow - 1) * static_cast<ptrdiff_t>(DstPitch));
529  unsigned char *dstcpy2 = dstcpy1 + dstpitch;
530 
531  srcpitch <<= 1;
532  dstpitch <<= 1;
533 
534  // 4 rows per pass
535  for (int row = FirstRow; row < maxrows; row += 4)
536  {
537  if (Second)
538  {
539  // On second pass, copy over the original, current field
540  memcpy(dstcpy1, above, static_cast<size_t>(DstPitch));
541  memcpy(dstcpy2, middle, static_cast<size_t>(DstPitch));
542  dstcpy1 += dstpitch;
543  dstcpy2 += dstpitch;
544  }
545  for (int col = 0; col < Width; col += 16)
546  {
547 #if defined(Q_PROCESSOR_X86_64)
548  __m128i mid = *reinterpret_cast<__m128i*>(&middle[col]);
549  *reinterpret_cast<__m128i*>(&dest1[col]) =
550  _mm_avg_epu8(*reinterpret_cast<__m128i*>(&above[col]), mid);
551  *reinterpret_cast<__m128i*>(&dest2[col]) =
552  _mm_avg_epu8(*reinterpret_cast<__m128i*>(&below[col]), mid);
553 #endif
554 #if HAVE_INTRINSICS_NEON
555  uint8x16_t mid = *reinterpret_cast<uint8x16_t*>(&middle[col]);
556  *reinterpret_cast<uint8x16_t*>(&dest1[col]) =
557  vrhaddq_u8(*reinterpret_cast<uint8x16_t*>(&above[col]), mid);
558  *reinterpret_cast<uint8x16_t*>(&dest2[col]) =
559  vrhaddq_u8(*reinterpret_cast<uint8x16_t*>(&below[col]), mid);
560 #endif
561  }
562  above += srcpitch;
563  middle += srcpitch;
564  below += srcpitch;
565  dest1 += dstpitch;
566  dest2 += dstpitch;
567  }
568 }
569 
570 // SIMD optimised version with 16x4 alignment for 10/12/16bit video
571 static inline void BlendSIMD8x4(unsigned char *Src, int Width, int FirstRow, int LastRow, int Pitch,
572  unsigned char *Dst, int DstPitch, bool Second)
573 {
574  int srcpitch = Pitch << 1;
575  int dstpitch = DstPitch << 1;
576  int maxrows = LastRow - 3;
577 
578  unsigned char *above = Src + ((FirstRow - 1) * static_cast<ptrdiff_t>(Pitch));
579  unsigned char *dest1 = Dst + (FirstRow * static_cast<ptrdiff_t>(DstPitch));
580  unsigned char *middle = above + srcpitch;
581  unsigned char *dest2 = dest1 + dstpitch;
582  unsigned char *below = middle + srcpitch;
583  unsigned char *dstcpy1 = Dst + ((FirstRow - 1) * static_cast<ptrdiff_t>(DstPitch));
584  unsigned char *dstcpy2 = dstcpy1 + dstpitch;
585 
586  srcpitch <<= 1;
587  dstpitch <<= 1;
588 
589  // 4 rows per pass
590  for (int row = FirstRow; row < maxrows; row += 4)
591  {
592  if (Second)
593  {
594  // On second pass, copy over the original, current field
595  memcpy(dstcpy1, above, static_cast<size_t>(DstPitch));
596  memcpy(dstcpy2, middle, static_cast<size_t>(DstPitch));
597  dstcpy1 += dstpitch;
598  dstcpy2 += dstpitch;
599  }
600  for (int col = 0; col < Width; col += 16)
601  {
602 #if defined(Q_PROCESSOR_X86_64)
603  __m128i mid = *reinterpret_cast<__m128i*>(&middle[col]);
604  *reinterpret_cast<__m128i*>(&dest1[col]) =
605  _mm_avg_epu16(*reinterpret_cast<__m128i*>(&above[col]), mid);
606  *reinterpret_cast<__m128i*>(&dest2[col]) =
607  _mm_avg_epu16(*reinterpret_cast<__m128i*>(&below[col]), mid);
608 #endif
609 #if HAVE_INTRINSICS_NEON
610  uint16x8_t mid = *reinterpret_cast<uint16x8_t*>(&middle[col]);
611  *reinterpret_cast<uint16x8_t*>(&dest1[col]) =
612  vrhaddq_u16(*reinterpret_cast<uint16x8_t*>(&above[col]), mid);
613  *reinterpret_cast<uint16x8_t*>(&dest2[col]) =
614  vrhaddq_u16(*reinterpret_cast<uint16x8_t*>(&below[col]), mid);
615 #endif
616  }
617  above += srcpitch;
618  middle += srcpitch;
619  below += srcpitch;
620  dest1 += dstpitch;
621  dest2 += dstpitch;
622  }
623 }
624 #endif
625 
627 {
628  if (Frame->m_height < 16 || Frame->m_width < 16)
629  return;
630 
631  bool second = false;
632  MythVideoFrame *src = Frame;
633 
634  if (m_doubleRate)
635  {
636  if (!SetUpCache(Frame))
637  return;
638  // copy/cache on first pass.
639  if (kScan_Interlaced == Scan)
640  memcpy(m_bobFrame->m_buffer, Frame->m_buffer, m_bobFrame->m_bufferSize);
641  else
642  second = true;
643  src = m_bobFrame;
644  }
645 
646  bool hidepth = MythVideoFrame::ColorDepth(src->m_type) > 8;
647  bool top = second ? !m_topFirst : m_topFirst;
649  for (uint plane = 0; plane < count; plane++)
650  {
651  int height = MythVideoFrame::GetHeightForPlane(src->m_type, src->m_height, plane);
652  int firstrow = top ? 1 : 2;
653  bool height4 = (height % 4) == 0;
654  bool width4 = (src->m_pitches[plane] % 4) == 0;
655  // N.B. all frames allocated by MythTV should have 16 byte alignment
656  // for all planes
657 #if defined(Q_PROCESSOR_X86_64) || HAVE_INTRINSICS_NEON
658  bool width16 = (src->m_pitches[plane] % 16) == 0;
659  // profiling SSE2 suggests it is usually 4x faster - as expected
660  if (s_haveSIMD && height4 && width16)
661  {
662  if (hidepth)
663  {
664  BlendSIMD8x4(src->m_buffer + src->m_offsets[plane],
666  firstrow, height, src->m_pitches[plane],
667  Frame->m_buffer + Frame->m_offsets[plane], Frame->m_pitches[plane],
668  second);
669  }
670  else
671  {
672  BlendSIMD16x4(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  }
679  else
680 #endif
681  // N.B. There is no 10bit support here - but it shouldn't be necessary
682  // as everything should be 16byte aligned and 10/12bit interlaced video
683  // is virtually unheard of.
684  if (width4 && height4 && !hidepth)
685  {
686  BlendC4x4(src->m_buffer + src->m_offsets[plane],
688  firstrow, height, src->m_pitches[plane],
689  Frame->m_buffer + Frame->m_offsets[plane], Frame->m_pitches[plane],
690  second);
691  }
692  }
693  Frame->m_alreadyDeinterlaced = true;
694 }
Source
static QString Source(const QNetworkRequest &request)
Definition: netstream.cpp:135
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: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:388
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:410
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:69
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:69
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
LOC
#define LOC
Definition: mythdeinterlacer.cpp:28
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
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:626
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:470
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:464
MythVideoFrame::FormatIsNV12
static bool FormatIsNV12(VideoFrameType Type)
Definition: mythframe.h:456
MythVideoProfile::GetMaxCPUs
uint GetMaxCPUs() const
Definition: mythvideoprofile.cpp:370
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