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 "mythdeinterlacer.h"
6 
7 extern "C" {
8 #include "libavfilter/buffersrc.h"
9 #include "libavfilter/buffersink.h"
10 }
11 
12 #if (HAVE_SSE2 && ARCH_X86_64)
13 #include "libavutil/x86/cpu.h"
14 #include <emmintrin.h>
15 bool MythDeinterlacer::s_haveSIMD = av_get_cpu_flags() & AV_CPU_FLAG_SSE2;
16 #elif HAVE_INTRINSICS_NEON
17 #if ARCH_AARCH64
18 #include "libavutil/aarch64/cpu.h"
19 #elif ARCH_ARM
20 #include "libavutil/arm/cpu.h"
21 #endif
22 #include <arm_neon.h>
23 bool MythDeinterlacer::s_haveSIMD = have_neon(av_get_cpu_flags());
24 #else
25 bool MythDeinterlacer::s_haveSIMD = false;
26 #endif
27 
28 #define LOC QString("MythDeint: ")
29 
48 {
49  Cleanup();
50 }
51 
70  VideoDisplayProfile *Profile, bool Force)
71 {
72  // nothing to see here
73 
74  if (!Frame || !is_interlaced(Scan))
75  {
76  Cleanup();
77  return;
78  }
79 
80  if (Frame->already_deinterlaced)
81  return;
82 
83  // Sanity check frame format
84  if (!format_is_yuv(Frame->codec))
85  {
86  Cleanup();
87  return;
88  }
89 
90  // check for software deinterlacing
91  bool doublerate = true;
92  bool topfieldfirst = Frame->interlaced_reversed ? !Frame->top_field_first : Frame->top_field_first;
93 
96  if (other)
97  {
98  Cleanup();
99  return;
100  }
101 
102  if (!deinterlacer)
103  {
104  doublerate = false;
105  deinterlacer = GetSingleRateOption(Frame, DEINT_CPU);
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) && format_is_nv12(Frame->codec))
117  {
118  Cleanup();
119  Frame->deinterlace_single = Frame->deinterlace_single | DEINT_SHADER;
120  Frame->deinterlace_double = Frame->deinterlace_double | 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->width != m_width || Frame->height != m_height ||
137  deinterlacer != m_deintType || doublerate != m_doubleRate ||
138  Frame->codec != m_inputType;
139 
140  if ((deinterlacer == DEINT_HIGH) && fieldorderchanged)
141  {
142  bool alreadyauto = m_autoFieldOrder;
143  bool change = m_lastFieldChange && (qAbs(m_lastFieldChange - Frame->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->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")
166  .arg(Frame->width).arg(Frame->height).arg(format_description(Frame->codec))
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) && (abs(Frame->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->frameCounter;
186 
187  // Set in use deinterlacer for debugging
188  Frame->deinterlace_inuse = m_deintType | DEINT_CPU;
189  Frame->deinterlace_inuse2x = 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->width;
217  m_frame->height = Frame->height;
218  m_frame->format = Frame->pix_fmt;
219  m_frame->pts = Frame->timecode;
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->pitches[0] < m_frame->linesize[0]) ||
250  (Frame->pitches[1] < m_frame->linesize[1]) || (Frame->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 = planes(Frame->codec);
258  for (uint plane = 0; plane < count; ++plane)
259  copyplane(Frame->buf + Frame->offsets[plane], Frame->pitches[plane], m_frame->data[plane], m_frame->linesize[plane],
260  pitch_for_plane(m_inputType, m_frame->width, plane), height_for_plane(m_inputType, m_frame->height, plane));
261 
262  Frame->timecode = m_frame->pts;
263  Frame->already_deinterlaced = true;
264 
265  // Free frame data
266  av_frame_unref(m_frame);
267 }
268 
270 {
271  if (m_graph || m_swsContext)
272  LOG(VB_PLAYBACK, LOG_INFO, LOC + "Removing CPU deinterlacer");
273 
274  avfilter_graph_free(&m_graph);
275  sws_freeContext(m_swsContext);
276  m_swsContext = nullptr;
278  m_autoFieldOrder = false;
279  m_lastFieldChange = 0;
280 
281  if (m_bobFrame)
282  {
283  LOG(VB_PLAYBACK, LOG_INFO, LOC + "Removing 'bob' cache frame");
285  delete m_bobFrame;
286  m_bobFrame = nullptr;
287  }
288 
290 }
291 
294  bool DoubleRate, bool TopFieldFirst, VideoDisplayProfile *Profile)
295 {
296  auto autofieldorder = m_autoFieldOrder;
297  auto lastfieldchange = m_lastFieldChange;
298  Cleanup();
299  m_source = nullptr;
300  m_sink = nullptr;
301 
302  if (!Frame)
303  return false;
304 
305  m_width = Frame->width;
306  m_height = Frame->height;
307  m_inputType = Frame->codec;
309  QString name = DeinterlacerName(Deinterlacer | DEINT_CPU, DoubleRate);
310 
311  // simple onefield/bob?
312  if (Deinterlacer == DEINT_BASIC || Deinterlacer == DEINT_MEDIUM)
313  {
314  m_deintType = Deinterlacer;
315  m_doubleRate = DoubleRate;
316  m_topFirst = TopFieldFirst;
317  if (Deinterlacer == DEINT_BASIC)
318  {
319  m_swsContext = sws_getCachedContext(m_swsContext, m_width, m_height >> 1, m_inputFmt,
320  m_width, m_height, m_inputFmt, SWS_FAST_BILINEAR,
321  nullptr, nullptr, nullptr);
322  if (m_swsContext == nullptr)
323  return false;
324  }
325  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Using deinterlacer '%1'").arg(name));
326  return true;
327  }
328 
329  // Sanity check the frame formats
331  {
332  LOG(VB_GENERAL, LOG_ERR, LOC + "Inconsistent frame formats");
333  return false;
334  }
335 
336  m_graph = avfilter_graph_alloc();
337  if (!m_graph)
338  return false;
339 
340  uint threads = 1;
341  if (Profile)
342  {
343  threads = Profile->GetMaxCPUs();
344  if (threads < 1 || threads > 8)
345  threads = 1;
346  }
347 
348  AVFilterInOut* inputs = nullptr;
349  AVFilterInOut* outputs = nullptr;
350 
351  QString deint = QString("yadif=mode=%1:parity=%2:threads=%3")
352  .arg(DoubleRate ? 1 : 0).arg(m_autoFieldOrder ? -1 : TopFieldFirst ? 0 : 1).arg(threads);
353 
354  QString graph = QString("buffer=video_size=%1x%2:pix_fmt=%3:time_base=1/1[in];[in]%4[out];[out] buffersink")
355  .arg(m_width).arg(m_height).arg(m_inputFmt).arg(deint);
356 
357  int res = avfilter_graph_parse2(m_graph, graph.toLatin1().constData(), &inputs, &outputs);
358  if (res >= 0 && !inputs && !outputs)
359  {
360  res = avfilter_graph_config(m_graph, nullptr);
361  if (res >= 0)
362  {
363  m_source = avfilter_graph_get_filter(m_graph, "Parsed_buffer_0");
364  m_sink = avfilter_graph_get_filter(m_graph, "Parsed_buffersink_2");
365 
366  if (m_source && m_sink)
367  {
368  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Created deinterlacer '%1' (%2 threads)")
369  .arg(name).arg(threads));
370  m_deintType = Deinterlacer;
371  m_doubleRate = DoubleRate;
372  m_topFirst = TopFieldFirst;
373  m_autoFieldOrder = autofieldorder;
374  m_lastFieldChange = lastfieldchange;
375  return true;
376  }
377  }
378  }
379 
380  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create avfilter");
382  avfilter_inout_free(&inputs);
383  avfilter_inout_free(&outputs);
384  return false;
385 }
386 
388 {
389  if (!Frame)
390  return false;
391 
392  if (!m_bobFrame)
393  {
394  m_bobFrame = new VideoFrame;
395  if (!m_bobFrame)
396  return false;
397  memset(m_bobFrame, 0, sizeof(VideoFrame));
398  LOG(VB_PLAYBACK, LOG_INFO, "Created new 'bob' cache frame");
399  }
400 
401  // copy Frame metadata, preserving any existing buffer allocation
402  unsigned char *buf = m_bobFrame->buf;
403  int size = m_bobFrame->size;
404  memcpy(m_bobFrame, Frame, sizeof(VideoFrame));
405  m_bobFrame->priv[0] = m_bobFrame->priv[1] = m_bobFrame->priv[2] = m_bobFrame->priv[3] = nullptr;
406  m_bobFrame->buf = buf;
407  m_bobFrame->size = size;
408 
409  if (!m_bobFrame->buf || (m_bobFrame->size != Frame->size))
410  {
412  m_bobFrame->buf = static_cast<unsigned char*>(av_malloc(static_cast<size_t>(Frame->size + 64)));
413  m_bobFrame->size = Frame->size;
414  }
415 
416  return m_bobFrame->buf != nullptr;
417 }
418 
420 {
421  if (!m_swsContext)
422  return;
423 
424  // we need a frame for caching - both to preserve the second field if
425  // needed and ensure we are not filtering in place (i.e. from src to src).
426  if (!SetUpCache(Frame))
427  return;
428 
429  // copy/cache on first pass
430  if (kScan_Interlaced == Scan)
431  memcpy(m_bobFrame->buf, Frame->buf, static_cast<size_t>(m_bobFrame->size));
432 
433  // Convert VideoFrame to AVFrame - no copy
434  AVFrame dstframe;
436  (AVPictureFill(&dstframe, Frame, m_inputFmt) < 1))
437  {
438  LOG(VB_GENERAL, LOG_ERR, LOC + "Error converting frame");
439  return;
440  }
441 
442  bool topfield = Scan == kScan_Interlaced ? m_topFirst : !m_topFirst;
443  dstframe.width = Frame->width;
444  dstframe.height = Frame->height;
445  dstframe.format = Frame->pix_fmt;
446 
447  m_frame->width = m_bobFrame->width;
448  m_frame->format = m_bobFrame->pix_fmt;
449 
450  // Fake the frame height and stride to simulate a single field
451  m_frame->height = Frame->height >> 1;
452  m_frame->interlaced_frame = 0;
453  uint nbplanes = planes(m_inputType);
454  for (uint i = 0; i < nbplanes; i++)
455  {
456  if (!topfield)
457  m_frame->data[i] = m_frame->data[i] + m_frame->linesize[i];
458  m_frame->linesize[i] = m_frame->linesize[i] << 1;
459  }
460 
461  // and scale to full height
462  int result = sws_scale(m_swsContext, m_frame->data, m_frame->linesize, 0, m_frame->height,
463  dstframe.data, dstframe.linesize);
464 
465  if (result != Frame->height)
466  {
467  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Error scaling frame: height %1 expected %2")
468  .arg(result).arg(Frame->height));
469  }
470  Frame->already_deinterlaced = true;
471 }
472 
473 inline static uint32_t avg(uint32_t A, uint32_t B)
474 {
475  return (((A ^ B) & 0xFEFEFEFEUL) >> 1) + (A & B);
476 }
477 
478 // Optimised version with 4x4 alignment
479 static inline void BlendC4x4(unsigned char *Src, int Width, int FirstRow, int LastRow, int Pitch,
480  unsigned char *Dst, int DstPitch, bool Second)
481 {
482  int srcpitch = Pitch << 1;
483  int dstpitch = DstPitch << 1;
484  int maxrows = LastRow - 3;
485 
486  unsigned char *above = Src + ((FirstRow - 1) * Pitch);
487  unsigned char *dest1 = Dst + (FirstRow * DstPitch);
488  unsigned char *middle = above + srcpitch;
489  unsigned char *dest2 = dest1 + dstpitch;
490  unsigned char *below = middle + srcpitch;
491  unsigned char *dstcpy1 = Dst + ((FirstRow - 1) * DstPitch);
492  unsigned char *dstcpy2 = dstcpy1 + dstpitch;
493 
494  srcpitch <<= 1;
495  dstpitch <<= 1;
496 
497  // 4 rows per pass
498  for (int row = FirstRow; row < maxrows; row += 4)
499  {
500  if (Second)
501  {
502  // On second pass, copy over the original, current field
503  memcpy(dstcpy1, above, static_cast<size_t>(DstPitch));
504  memcpy(dstcpy2, middle, static_cast<size_t>(DstPitch));
505  dstcpy1 += dstpitch;
506  dstcpy2 += dstpitch;
507  }
508  for (int col = 0; col < Width; col += 4)
509  {
510  *reinterpret_cast<uint32_t*>(&dest1[col]) =
511  avg(*reinterpret_cast<uint32_t*>(&above[col]), *reinterpret_cast<uint32_t*>(&middle[col]));
512  *reinterpret_cast<uint32_t*>(&dest2[col]) =
513  avg(*reinterpret_cast<uint32_t*>(&middle[col]), *reinterpret_cast<uint32_t*>(&below[col]));
514  }
515  above += srcpitch;
516  middle += srcpitch;
517  below += srcpitch;
518  dest1 += dstpitch;
519  dest2 += dstpitch;
520  }
521 }
522 
523 #if (HAVE_SSE2 && ARCH_X86_64) || HAVE_INTRINSICS_NEON
524 // SIMD optimised version with 16x4 alignment
525 static inline void BlendSIMD16x4(unsigned char *Src, int Width, int FirstRow, int LastRow, int Pitch,
526  unsigned char *Dst, int DstPitch, bool Second)
527 {
528  int srcpitch = Pitch << 1;
529  int dstpitch = DstPitch << 1;
530  int maxrows = LastRow - 3;
531 
532  unsigned char *above = Src + ((FirstRow - 1) * Pitch);
533  unsigned char *dest1 = Dst + (FirstRow * DstPitch);
534  unsigned char *middle = above + srcpitch;
535  unsigned char *dest2 = dest1 + dstpitch;
536  unsigned char *below = middle + srcpitch;
537  unsigned char *dstcpy1 = Dst + ((FirstRow - 1) * DstPitch);
538  unsigned char *dstcpy2 = dstcpy1 + dstpitch;
539 
540  srcpitch <<= 1;
541  dstpitch <<= 1;
542 
543  // 4 rows per pass
544  for (int row = FirstRow; row < maxrows; row += 4)
545  {
546  if (Second)
547  {
548  // On second pass, copy over the original, current field
549  memcpy(dstcpy1, above, static_cast<size_t>(DstPitch));
550  memcpy(dstcpy2, middle, static_cast<size_t>(DstPitch));
551  dstcpy1 += dstpitch;
552  dstcpy2 += dstpitch;
553  }
554  for (int col = 0; col < Width; col += 16)
555  {
556 #if (HAVE_SSE2 && ARCH_X86_64)
557  __m128i mid = *reinterpret_cast<__m128i*>(&middle[col]);
558  *reinterpret_cast<__m128i*>(&dest1[col]) =
559  _mm_avg_epu8(*reinterpret_cast<__m128i*>(&above[col]), mid);
560  *reinterpret_cast<__m128i*>(&dest2[col]) =
561  _mm_avg_epu8(*reinterpret_cast<__m128i*>(&below[col]), mid);
562 #endif
563 #if HAVE_INTRINSICS_NEON
564  uint8x16_t mid = *reinterpret_cast<uint8x16_t*>(&middle[col]);
565  *reinterpret_cast<uint8x16_t*>(&dest1[col]) =
566  vrhaddq_u8(*reinterpret_cast<uint8x16_t*>(&above[col]), mid);
567  *reinterpret_cast<uint8x16_t*>(&dest2[col]) =
568  vrhaddq_u8(*reinterpret_cast<uint8x16_t*>(&below[col]), mid);
569 #endif
570  }
571  above += srcpitch;
572  middle += srcpitch;
573  below += srcpitch;
574  dest1 += dstpitch;
575  dest2 += dstpitch;
576  }
577 }
578 
579 // SIMD optimised version with 16x4 alignment for 10/12/16bit video
580 static inline void BlendSIMD8x4(unsigned char *Src, int Width, int FirstRow, int LastRow, int Pitch,
581  unsigned char *Dst, int DstPitch, bool Second)
582 {
583  int srcpitch = Pitch << 1;
584  int dstpitch = DstPitch << 1;
585  int maxrows = LastRow - 3;
586 
587  unsigned char *above = Src + ((FirstRow - 1) * Pitch);
588  unsigned char *dest1 = Dst + (FirstRow * DstPitch);
589  unsigned char *middle = above + srcpitch;
590  unsigned char *dest2 = dest1 + dstpitch;
591  unsigned char *below = middle + srcpitch;
592  unsigned char *dstcpy1 = Dst + ((FirstRow - 1) * DstPitch);
593  unsigned char *dstcpy2 = dstcpy1 + dstpitch;
594 
595  srcpitch <<= 1;
596  dstpitch <<= 1;
597 
598  // 4 rows per pass
599  for (int row = FirstRow; row < maxrows; row += 4)
600  {
601  if (Second)
602  {
603  // On second pass, copy over the original, current field
604  memcpy(dstcpy1, above, static_cast<size_t>(DstPitch));
605  memcpy(dstcpy2, middle, static_cast<size_t>(DstPitch));
606  dstcpy1 += dstpitch;
607  dstcpy2 += dstpitch;
608  }
609  for (int col = 0; col < Width; col += 16)
610  {
611 #if (HAVE_SSE2 && ARCH_X86_64)
612  __m128i mid = *reinterpret_cast<__m128i*>(&middle[col]);
613  *reinterpret_cast<__m128i*>(&dest1[col]) =
614  _mm_avg_epu16(*reinterpret_cast<__m128i*>(&above[col]), mid);
615  *reinterpret_cast<__m128i*>(&dest2[col]) =
616  _mm_avg_epu16(*reinterpret_cast<__m128i*>(&below[col]), mid);
617 #endif
618 #if HAVE_INTRINSICS_NEON
619  uint16x8_t mid = *reinterpret_cast<uint16x8_t*>(&middle[col]);
620  *reinterpret_cast<uint16x8_t*>(&dest1[col]) =
621  vrhaddq_u16(*reinterpret_cast<uint16x8_t*>(&above[col]), mid);
622  *reinterpret_cast<uint16x8_t*>(&dest2[col]) =
623  vrhaddq_u16(*reinterpret_cast<uint16x8_t*>(&below[col]), mid);
624 #endif
625  }
626  above += srcpitch;
627  middle += srcpitch;
628  below += srcpitch;
629  dest1 += dstpitch;
630  dest2 += dstpitch;
631  }
632 }
633 #endif
634 
636 {
637  if (Frame->height < 16 || Frame->width < 16)
638  return;
639 
640  bool second = false;
641  VideoFrame *src = Frame;
642 
643  if (m_doubleRate)
644  {
645  if (!SetUpCache(Frame))
646  return;
647  // copy/cache on first pass.
648  if (kScan_Interlaced == Scan)
649  memcpy(m_bobFrame->buf, Frame->buf, static_cast<size_t>(m_bobFrame->size));
650  else
651  second = true;
652  src = m_bobFrame;
653  }
654 
655  bool hidepth = ColorDepth(src->codec) > 8;
656  bool top = second ? !m_topFirst : m_topFirst;
657  uint count = planes(src->codec);
658  for (uint plane = 0; plane < count; plane++)
659  {
660  int height = height_for_plane(src->codec, src->height, plane);
661  int firstrow = top ? 1 : 2;
662  bool height4 = (height % 4) == 0;
663  bool width4 = (src->pitches[plane] % 4) == 0;
664  // N.B. all frames allocated by MythTV should have 16 byte alignment
665  // for all planes
666 #if (HAVE_SSE2 && ARCH_X86_64) || HAVE_INTRINSICS_NEON
667  bool width16 = (src->pitches[plane] % 16) == 0;
668  // profiling SSE2 suggests it is usually 4x faster - as expected
669  if (s_haveSIMD && height4 && width16)
670  {
671  if (hidepth)
672  {
673  BlendSIMD8x4(src->buf + src->offsets[plane],
674  pitch_for_plane(src->codec, src->width, plane),
675  firstrow, height, src->pitches[plane],
676  Frame->buf + Frame->offsets[plane], Frame->pitches[plane],
677  second);
678  }
679  else
680  {
681  BlendSIMD16x4(src->buf + src->offsets[plane],
682  width_for_plane(src->codec, src->width, plane),
683  firstrow, height, src->pitches[plane],
684  Frame->buf + Frame->offsets[plane], Frame->pitches[plane],
685  second);
686  }
687  }
688  else
689 #endif
690  // N.B. There is no 10bit support here - but it shouldn't be necessary
691  // as everything should be 16byte aligned and 10/12bit interlaced video
692  // is virtually unheard of.
693  if (width4 && height4 && !hidepth)
694  {
695  BlendC4x4(src->buf + src->offsets[plane],
696  width_for_plane(src->codec, src->width, plane),
697  firstrow, height, src->pitches[plane],
698  Frame->buf + Frame->offsets[plane], Frame->pitches[plane],
699  second);
700  }
701  }
702  Frame->already_deinterlaced = true;
703 }
Source
static QString Source(const QNetworkRequest &request)
Definition: netstream.cpp:137
GetSingleRateOption
MythDeintType GetSingleRateOption(const VideoFrame *Frame, MythDeintType Type, MythDeintType Override)
Definition: mythframe.cpp:834
MythDeinterlacer::Filter
void Filter(VideoFrame *Frame, FrameScanType Scan, VideoDisplayProfile *Profile, bool Force=false)
Deinterlace Frame if needed.
Definition: mythdeinterlacer.cpp:69
MythDeinterlacer::m_frame
MythAVFrame m_frame
Definition: mythdeinterlacer.h:42
DEINT_MEDIUM
@ DEINT_MEDIUM
Definition: mythframe.h:125
MythDeinterlacer::m_swsContext
SwsContext * m_swsContext
Definition: mythdeinterlacer.h:47
VideoFrame::pitches
int pitches[3]
Y, U, & V pitches.
Definition: mythframe.h:161
DEINT_SHADER
@ DEINT_SHADER
Definition: mythframe.h:128
MythDeinterlacer::m_lastFieldChange
long long m_lastFieldChange
Definition: mythdeinterlacer.h:50
MythDeinterlacer::m_graph
AVFilterGraph * m_graph
Definition: mythdeinterlacer.h:43
MythDeinterlacer::m_width
int m_width
Definition: mythdeinterlacer.h:37
Frame
Definition: zmdefines.h:93
DEINT_NONE
@ DEINT_NONE
Definition: mythframe.h:123
arg
arg(title).arg(filename).arg(doDelete))
PixelFormatToFrameType
VideoFrameType PixelFormatToFrameType(AVPixelFormat fmt)
Definition: mythavutil.cpp:69
FrameScanType
FrameScanType
Definition: videoouttypes.h:78
GetDoubleRateOption
MythDeintType GetDoubleRateOption(const VideoFrame *Frame, MythDeintType Type, MythDeintType Override)
Definition: mythframe.cpp:847
VideoFrame::buf
unsigned char * buf
Definition: mythframe.h:140
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
VideoFrame
Definition: mythframe.h:137
MythDeinterlacer::m_deintType
MythDeintType m_deintType
Definition: mythdeinterlacer.h:39
pitch_for_plane
static int pitch_for_plane(VideoFrameType Type, int Width, uint Plane)
Definition: mythframe.h:345
MythDeinterlacer::Initialise
bool Initialise(VideoFrame *Frame, MythDeintType Deinterlacer, bool DoubleRate, bool TopFieldFirst, VideoDisplayProfile *Profile)
Initialise deinterlacing using the given MythDeintType.
Definition: mythdeinterlacer.cpp:293
mythdeinterlacer.h
VideoFrame::codec
VideoFrameType codec
Definition: mythframe.h:139
DEINT_CPU
@ DEINT_CPU
Definition: mythframe.h:127
AVFrame
struct AVFrame AVFrame
Definition: BorderDetector.h:15
MythDeinterlacer::m_inputFmt
AVPixelFormat m_inputFmt
Definition: mythdeinterlacer.h:36
DeinterlacerName
QString DeinterlacerName(MythDeintType Deint, bool DoubleRate, VideoFrameType Format)
Return a user friendly description of the given deinterlacer.
Definition: mythavutil.cpp:115
mythlogging.h
Source
Definition: channelsettings.cpp:68
MythDeinterlacer::m_autoFieldOrder
bool m_autoFieldOrder
Definition: mythdeinterlacer.h:49
VideoDisplayProfile::GetMaxCPUs
uint GetMaxCPUs(void) const
Definition: videodisplayprofile.cpp:414
copyplane
static void copyplane(uint8_t *dst, int dst_pitch, const uint8_t *src, int src_pitch, int width, int height)
Definition: mythframe.h:540
MythDeinterlacer::m_height
int m_height
Definition: mythdeinterlacer.h:38
format_is_yuv
static bool format_is_yuv(VideoFrameType Type)
Definition: mythframe.h:115
format_is_nv12
static bool format_is_nv12(VideoFrameType Type)
Definition: mythframe.h:105
av_free
void av_free(void *ptr)
VideoFrame::priv
unsigned char * priv[4]
random empty storage
Definition: mythframe.h:152
uint
unsigned int uint
Definition: compat.h:140
VideoFrame::pix_fmt
int pix_fmt
Definition: mythframe.h:163
LOC
#define LOC
Definition: mythdeinterlacer.cpp:28
MythDeinterlacer::OneField
void OneField(VideoFrame *Frame, FrameScanType Scan)
Definition: mythdeinterlacer.cpp:419
MythDeinterlacer::Cleanup
void Cleanup(void)
Definition: mythdeinterlacer.cpp:269
MythDeinterlacer::m_inputType
VideoFrameType m_inputType
Definition: mythdeinterlacer.h:35
MythDeinterlacer::Blend
void Blend(VideoFrame *Frame, FrameScanType Scan)
Definition: mythdeinterlacer.cpp:635
VideoDisplayProfile
Definition: videodisplayprofile.h:69
MythDeintType
MythDeintType
Definition: mythframe.h:121
VideoFrame::offsets
int offsets[3]
Y, U, & V offsets.
Definition: mythframe.h:162
ColorDepth
int ColorDepth(int Format)
Return the color depth for the given MythTV frame format.
Definition: mythframe.cpp:808
AVPictureFill
int AVPictureFill(AVFrame *pic, const VideoFrame *frame, AVPixelFormat fmt)
AVPictureFill Initialise AVFrame pic with content from VideoFrame frame.
Definition: mythavutil.cpp:197
planes
static uint planes(VideoFrameType Type)
Definition: mythframe.h:570
width_for_plane
static int width_for_plane(VideoFrameType Type, int Width, uint Plane)
Definition: mythframe.h:395
kScan_Interlaced
@ kScan_Interlaced
Definition: videoouttypes.h:82
MythDeinterlacer::SetUpCache
bool SetUpCache(VideoFrame *Frame)
Definition: mythdeinterlacer.cpp:387
DEINT_HIGH
@ DEINT_HIGH
Definition: mythframe.h:126
MythDeinterlacer::m_discontinuityCounter
long long m_discontinuityCounter
Definition: mythdeinterlacer.h:48
mythavutil.h
height_for_plane
static int height_for_plane(VideoFrameType Type, int Height, uint Plane)
Definition: mythframe.h:440
MythDeinterlacer::s_haveSIMD
static bool s_haveSIMD
Definition: mythdeinterlacer.h:51
VideoFrame::height
int height
Definition: mythframe.h:143
av_malloc
void * av_malloc(unsigned int size)
MythDeinterlacer::~MythDeinterlacer
~MythDeinterlacer()
Definition: mythdeinterlacer.cpp:47
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:479
MythDeinterlacer::m_source
AVFilterContext * m_source
Definition: mythdeinterlacer.h:44
DEINT_BASIC
@ DEINT_BASIC
Definition: mythframe.h:124
MythDeinterlacer::m_topFirst
bool m_topFirst
Definition: mythdeinterlacer.h:41
VideoFrame::size
int size
Definition: mythframe.h:147
MythDeinterlacer::m_bobFrame
VideoFrame * m_bobFrame
Definition: mythdeinterlacer.h:46
format_description
const char * format_description(VideoFrameType Type)
Definition: mythframe.cpp:33
is_interlaced
bool is_interlaced(FrameScanType Scan)
Definition: videoouttypes.h:174
avg
static uint32_t avg(uint32_t A, uint32_t B)
Definition: mythdeinterlacer.cpp:473
MythDeinterlacer::m_sink
AVFilterContext * m_sink
Definition: mythdeinterlacer.h:45
VideoFrame::width
int width
Definition: mythframe.h:142
FrameTypeToPixelFormat
AVPixelFormat FrameTypeToPixelFormat(VideoFrameType type)
Convert VideoFrameType into FFmpeg's PixelFormat equivalent and vice-versa.
Definition: mythavutil.cpp:25
MythDeinterlacer::m_doubleRate
bool m_doubleRate
Definition: mythdeinterlacer.h:40