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
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  if (!Frame || (Scan != kScan_Interlaced && Scan != kScan_Intr2ndField))
74  {
75  Cleanup();
76  return;
77  }
78 
79  // Sanity check frame format
80  if (!format_is_yuv(Frame->codec))
81  {
82  Cleanup();
83  return;
84  }
85 
86  // check for software deinterlacing
87  bool doublerate = true;
88  bool topfieldfirst = Frame->interlaced_reversed ? !Frame->top_field_first : Frame->top_field_first;
89 
92  if (other)
93  {
94  Cleanup();
95  return;
96  }
97 
98  if (!deinterlacer)
99  {
100  doublerate = false;
101  deinterlacer = GetSingleRateOption(Frame, DEINT_CPU);
103  if (!deinterlacer || other)
104  {
105  Cleanup();
106  return;
107  }
108  }
109 
110  // libavfilter will not deinterlace NV12 frames. Allow shaders in this case.
111  // libswscale (for bob/onefield) is fine, as is our linearblend.
112  if ((deinterlacer == DEINT_HIGH) && format_is_nv12(Frame->codec))
113  {
114  Cleanup();
115  Frame->deinterlace_single = Frame->deinterlace_single | DEINT_SHADER;
116  Frame->deinterlace_double = Frame->deinterlace_double | DEINT_SHADER;
117  return;
118  }
119 
120  // certain material (telecined?) continually changes the field order. This
121  // cripples performance as the libavfiler deinterlacer is continually
122  // destroyed and recreated. Using 'auto' for the field order breaks user
123  // override of the interlacing order - so track switches in the field order
124  // and switch to auto if it is too frequent
125  bool fieldorderchanged = topfieldfirst != m_topFirst;
126  if (fieldorderchanged && deinterlacer != DEINT_HIGH)
127  {
128  fieldorderchanged = false;
129  m_topFirst = topfieldfirst;
130  }
131 
132  bool otherchanged = Frame->width != m_width || Frame->height != m_height ||
133  deinterlacer != m_deintType || doublerate != m_doubleRate ||
134  Frame->codec != m_inputType;
135 
136  if ((deinterlacer == DEINT_HIGH) && fieldorderchanged)
137  {
138  bool alreadyauto = m_autoFieldOrder;
139  bool change = m_lastFieldChange && (qAbs(m_lastFieldChange - Frame->frameCounter) < 10);
140  if (change && !m_autoFieldOrder)
141  {
142  m_autoFieldOrder = true;
143  LOG(VB_PLAYBACK, LOG_INFO, LOC + "Enabled 'auto' for field order");
144  }
145  else if (!change && m_autoFieldOrder)
146  {
147  m_autoFieldOrder = false;
148  LOG(VB_PLAYBACK, LOG_INFO, LOC + "Disabled 'auto' for field order");
149  }
150  if (alreadyauto && m_autoFieldOrder)
151  fieldorderchanged = false;
152  m_lastFieldChange = Frame->frameCounter;
153  }
154 
155  // Check for a change in input or deinterlacer
156  if (fieldorderchanged || otherchanged)
157  {
158  LOG(VB_GENERAL, LOG_INFO, LOC +
159  QString("Deinterlacer change: %1x%2 %3 dr:%4 tff:%5 -> %6x%7 %8 dr:%9 tff:%10")
161  .arg(m_doubleRate).arg(m_topFirst)
162  .arg(Frame->width).arg(Frame->height).arg(format_description(Frame->codec))
163  .arg(doublerate).arg(topfieldfirst));
164  if (!Initialise(Frame, deinterlacer, doublerate, topfieldfirst, Profile))
165  {
166  Cleanup();
167  return;
168  }
169  Force = true;
170  }
171  else if ((m_deintType == DEINT_HIGH) && (abs(Frame->frameCounter - m_discontinuityCounter) > 1))
172  {
173  if (!Initialise(Frame, deinterlacer, doublerate, topfieldfirst, Profile))
174  {
175  Cleanup();
176  return;
177  }
178  Force = true;
179  }
180 
181  m_discontinuityCounter = Frame->frameCounter;
182 
183  // Set in use deinterlacer for debugging
184  Frame->deinterlace_inuse = m_deintType | DEINT_CPU;
185  Frame->deinterlace_inuse2x = m_doubleRate;
186 
187  // onefield or bob
188  if (m_deintType == DEINT_BASIC)
189  {
190  OneField(Frame, Scan);
191  return;
192  }
193 
194  // linear blend
195  if (m_deintType == DEINT_MEDIUM)
196  {
197  Blend(Frame, Scan);
198  return;
199  }
200 
201  // We need a filter
202  if (!m_graph)
203  return;
204 
205  // Convert VideoFrame to AVFrame - no copy
207  {
208  LOG(VB_GENERAL, LOG_ERR, LOC + "Error converting frame");
209  return;
210  }
211 
212  m_frame->width = Frame->width;
213  m_frame->height = Frame->height;
214  m_frame->format = Frame->pix_fmt;
215  m_frame->pts = Frame->timecode;
216 
217  auto AddFrame = [](AVFilterContext* Source, AVFrame *AvFrame)
218  { return av_buffersrc_add_frame(Source, AvFrame); };
219 
220  // Add frame on first pass only
221  if (kScan_Interlaced == Scan)
222  {
223  if (AddFrame(m_source, m_frame) < 0)
224  {
225  LOG(VB_GENERAL, LOG_ERR, LOC + "Error adding frame");
226  return;
227  }
228  // yadif needs 2 frames to work with - add the frame again if we
229  // need a result now
230  if (Force)
231  AddFrame(m_source, m_frame);
232  }
233 
234  // Retrieve frame
235  int res = av_buffersink_get_frame(m_sink, m_frame);
236  if (res < 0)
237  {
238  if (res == AVERROR(EAGAIN))
239  return;
240  LOG(VB_GENERAL, LOG_ERR, LOC + "Error retrieving frame");
241  return;
242  }
243 
244  // Ensure AVFrame is in the expected format
245  if ((m_frame->format != m_inputFmt) || (Frame->pitches[0] < m_frame->linesize[0]) ||
246  (Frame->pitches[1] < m_frame->linesize[1]) || (Frame->pitches[2] < m_frame->linesize[2]))
247  {
248  LOG(VB_GENERAL, LOG_ERR, LOC + "Filter returned unexpected format");
249  return;
250  }
251 
252  // Copy AVFrame back to VideoFrame
253  uint count = planes(Frame->codec);
254  for (uint plane = 0; plane < count; ++plane)
255  copyplane(Frame->buf + Frame->offsets[plane], Frame->pitches[plane], m_frame->data[plane], m_frame->linesize[plane],
256  pitch_for_plane(m_inputType, m_frame->width, plane), height_for_plane(m_inputType, m_frame->height, plane));
257 
258  Frame->timecode = m_frame->pts;
259  Frame->already_deinterlaced = 1;
260 
261  // Free frame data
262  av_frame_unref(m_frame);
263 }
264 
266 {
267  if (m_graph || m_swsContext)
268  LOG(VB_PLAYBACK, LOG_INFO, LOC + "Removing CPU deinterlacer");
269 
270  avfilter_graph_free(&m_graph);
271  sws_freeContext(m_swsContext);
272  m_swsContext = nullptr;
274  m_autoFieldOrder = false;
275  m_lastFieldChange = 0;
276 
277  if (m_bobFrame)
278  {
279  LOG(VB_PLAYBACK, LOG_INFO, LOC + "Removing 'bob' cache frame");
281  delete m_bobFrame;
282  m_bobFrame = nullptr;
283  }
284 
286 }
287 
290  bool DoubleRate, bool TopFieldFirst, VideoDisplayProfile *Profile)
291 {
292  auto autofieldorder = m_autoFieldOrder;
293  auto lastfieldchange = m_lastFieldChange;
294  Cleanup();
295  m_source = nullptr;
296  m_sink = nullptr;
297 
298  if (!Frame)
299  return false;
300 
301  m_width = Frame->width;
302  m_height = Frame->height;
303  m_inputType = Frame->codec;
305  QString name = DeinterlacerName(Deinterlacer | DEINT_CPU, DoubleRate);
306 
307  // simple onefield/bob?
308  if (Deinterlacer == DEINT_BASIC || Deinterlacer == DEINT_MEDIUM)
309  {
310  m_deintType = Deinterlacer;
311  m_doubleRate = DoubleRate;
312  m_topFirst = TopFieldFirst;
313  if (Deinterlacer == DEINT_BASIC)
314  {
315  m_swsContext = sws_getCachedContext(m_swsContext, m_width, m_height >> 1, m_inputFmt,
316  m_width, m_height, m_inputFmt, SWS_FAST_BILINEAR,
317  nullptr, nullptr, nullptr);
318  if (m_swsContext == nullptr)
319  return false;
320  }
321  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Using deinterlacer '%1'").arg(name));
322  return true;
323  }
324 
325  // Sanity check the frame formats
327  {
328  LOG(VB_GENERAL, LOG_ERR, LOC + "Inconsistent frame formats");
329  return false;
330  }
331 
332  m_graph = avfilter_graph_alloc();
333  if (!m_graph)
334  return false;
335 
336  uint threads = 1;
337  if (Profile)
338  {
339  threads = Profile->GetMaxCPUs();
340  if (threads < 1 || threads > 8)
341  threads = 1;
342  }
343 
344  AVFilterInOut* inputs = nullptr;
345  AVFilterInOut* outputs = nullptr;
346 
347  QString deint = QString("yadif=mode=%1:parity=%2:threads=%3")
348  .arg(DoubleRate ? 1 : 0).arg(m_autoFieldOrder ? -1 : TopFieldFirst ? 0 : 1).arg(threads);
349 
350  QString graph = QString("buffer=video_size=%1x%2:pix_fmt=%3:time_base=1/1[in];[in]%4[out];[out] buffersink")
351  .arg(m_width).arg(m_height).arg(m_inputFmt).arg(deint);
352 
353  int res = avfilter_graph_parse2(m_graph, graph.toLatin1().constData(), &inputs, &outputs);
354  if (res >= 0 && !inputs && !outputs)
355  {
356  res = avfilter_graph_config(m_graph, nullptr);
357  if (res >= 0)
358  {
359  m_source = avfilter_graph_get_filter(m_graph, "Parsed_buffer_0");
360  m_sink = avfilter_graph_get_filter(m_graph, "Parsed_buffersink_2");
361 
362  if (m_source && m_sink)
363  {
364  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Created deinterlacer '%1' (%2 threads)")
365  .arg(name).arg(threads));
366  m_deintType = Deinterlacer;
367  m_doubleRate = DoubleRate;
368  m_topFirst = TopFieldFirst;
369  m_autoFieldOrder = autofieldorder;
370  m_lastFieldChange = lastfieldchange;
371  return true;
372  }
373  }
374  }
375 
376  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create avfilter");
378  avfilter_inout_free(&inputs);
379  avfilter_inout_free(&outputs);
380  return false;
381 }
382 
384 {
385  if (!Frame)
386  return false;
387 
388  if (!m_bobFrame)
389  {
390  m_bobFrame = new VideoFrame;
391  if (!m_bobFrame)
392  return false;
393  memset(m_bobFrame, 0, sizeof(VideoFrame));
394  LOG(VB_PLAYBACK, LOG_INFO, "Created new 'bob' cache frame");
395  }
396 
397  // copy Frame metadata, preserving any existing buffer allocation
398  unsigned char *buf = m_bobFrame->buf;
399  int size = m_bobFrame->size;
400  memcpy(m_bobFrame, Frame, sizeof(VideoFrame));
401  m_bobFrame->priv[0] = m_bobFrame->priv[1] = m_bobFrame->priv[2] = m_bobFrame->priv[3] = nullptr;
402  m_bobFrame->buf = buf;
403  m_bobFrame->size = size;
404 
405  if (!m_bobFrame->buf || (m_bobFrame->size != Frame->size))
406  {
408  m_bobFrame->buf = static_cast<unsigned char*>(av_malloc(static_cast<size_t>(Frame->size + 64)));
409  m_bobFrame->size = Frame->size;
410  }
411 
412  return m_bobFrame->buf != 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->buf, Frame->buf, static_cast<size_t>(m_bobFrame->size));
428 
429  // Convert VideoFrame to AVFrame - no copy
430  AVFrame dstframe;
432  (AVPictureFill(&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->width;
440  dstframe.height = Frame->height;
441  dstframe.format = Frame->pix_fmt;
442 
443  m_frame->width = m_bobFrame->width;
444  m_frame->format = m_bobFrame->pix_fmt;
445 
446  // Fake the frame height and stride to simulate a single field
447  m_frame->height = Frame->height >> 1;
448  m_frame->interlaced_frame = 0;
449  uint nbplanes = planes(m_inputType);
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->height)
462  {
463  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Error scaling frame: height %1 expected %2")
464  .arg(result).arg(Frame->height));
465  }
466  Frame->already_deinterlaced = 1;
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) * Pitch);
483  unsigned char *dest1 = Dst + (FirstRow * 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) * 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 HAVE_SSE2 || 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) * Pitch);
529  unsigned char *dest1 = Dst + (FirstRow * 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) * 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 HAVE_SSE2
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) * Pitch);
584  unsigned char *dest1 = Dst + (FirstRow * 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) * 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 HAVE_SSE2
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->height < 16 || Frame->width < 16)
634  return;
635 
636  bool second = false;
637  VideoFrame *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->buf, Frame->buf, static_cast<size_t>(m_bobFrame->size));
646  else
647  second = true;
648  src = m_bobFrame;
649  }
650 
651  bool hidepth = ColorDepth(src->codec) > 8;
652  bool top = second ? !m_topFirst : m_topFirst;
653  uint count = planes(src->codec);
654  for (uint plane = 0; plane < count; plane++)
655  {
656  int height = height_for_plane(src->codec, src->height, plane);
657  int firstrow = top ? 1 : 2;
658  bool height4 = (height % 4) == 0;
659  bool width4 = (src->pitches[plane] % 4) == 0;
660  // N.B. all frames allocated by MythTV should have 16 byte alignment
661  // for all planes
662 #if HAVE_SSE2 || HAVE_INTRINSICS_NEON
663  bool width16 = (src->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->buf + src->offsets[plane],
670  pitch_for_plane(src->codec, src->width, plane),
671  firstrow, height, src->pitches[plane],
672  Frame->buf + Frame->offsets[plane], Frame->pitches[plane],
673  second);
674  }
675  else
676  {
677  BlendSIMD16x4(src->buf + src->offsets[plane],
678  width_for_plane(src->codec, src->width, plane),
679  firstrow, height, src->pitches[plane],
680  Frame->buf + Frame->offsets[plane], Frame->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->buf + src->offsets[plane],
692  width_for_plane(src->codec, src->width, plane),
693  firstrow, height, src->pitches[plane],
694  Frame->buf + Frame->offsets[plane], Frame->pitches[plane],
695  second);
696  }
697  }
698  Frame->already_deinterlaced = 1;
699 }
int pitches[3]
Y, U, & V pitches.
Definition: mythframe.h:159
MythDeintType GetDoubleRateOption(const VideoFrame *Frame, MythDeintType Type, MythDeintType Override)
Definition: mythframe.cpp:854
unsigned char * buf
Definition: mythframe.h:139
void OneField(VideoFrame *Frame, FrameScanType Scan)
VideoFrameType codec
Definition: mythframe.h:138
void Blend(VideoFrame *Frame, FrameScanType Scan)
bool SetUpCache(VideoFrame *Frame)
struct AVFrame AVFrame
AVPixelFormat FrameTypeToPixelFormat(VideoFrameType type)
Convert VideoFrameType into FFmpeg's PixelFormat equivalent and vice-versa.
Definition: mythavutil.cpp:24
FrameScanType
Definition: videoouttypes.h:78
VideoFrameType PixelFormatToFrameType(AVPixelFormat fmt)
Definition: mythavutil.cpp:68
static int pitch_for_plane(VideoFrameType Type, int Width, uint Plane)
Definition: mythframe.h:342
VideoFrame * m_bobFrame
static uint planes(VideoFrameType Type)
Definition: mythframe.h:567
int ColorDepth(int Format)
Return the color depth for the given MythTV frame format.
Definition: mythframe.cpp:815
long long m_discontinuityCounter
MythDeintType
Definition: mythframe.h:120
QString DeinterlacerName(MythDeintType Deint, bool DoubleRate, VideoFrameType Format)
Return a user friendly description of the given deinterlacer.
Definition: mythavutil.cpp:114
static int height_for_plane(VideoFrameType Type, int Height, uint Plane)
Definition: mythframe.h:437
MythAVFrame m_frame
unsigned char * priv[4]
random empty storage
Definition: mythframe.h:151
AVFilterContext * m_source
int AVPictureFill(AVFrame *pic, const VideoFrame *frame, AVPixelFormat fmt)
AVPictureFill Initialise AVFrame pic with content from VideoFrame frame.
Definition: mythavutil.cpp:196
static bool s_haveSIMD
long long m_lastFieldChange
SwsContext * m_swsContext
static int format_is_yuv(VideoFrameType Type)
Definition: mythframe.h:114
int pix_fmt
Definition: mythframe.h:161
unsigned int uint
Definition: compat.h:140
void Filter(VideoFrame *Frame, FrameScanType Scan, VideoDisplayProfile *Profile, bool Force=false)
Deinterlace Frame if needed.
static int format_is_nv12(VideoFrameType Type)
Definition: mythframe.h:104
AVFilterContext * m_sink
void * av_malloc(unsigned int size)
static void copyplane(uint8_t *dst, int dst_pitch, const uint8_t *src, int src_pitch, int width, int height)
Definition: mythframe.h:537
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
static QString Source(const QNetworkRequest &request)
Definition: netstream.cpp:137
static void BlendC4x4(unsigned char *Src, int Width, int FirstRow, int LastRow, int Pitch, unsigned char *Dst, int DstPitch, bool Second)
uint GetMaxCPUs(void) const
int offsets[3]
Y, U, & V offsets.
Definition: mythframe.h:160
bool Initialise(VideoFrame *Frame, MythDeintType Deinterlacer, bool DoubleRate, bool TopFieldFirst, VideoDisplayProfile *Profile)
Initialise deinterlacing using the given MythDeintType.
int height
Definition: mythframe.h:142
AVFilterGraph * m_graph
MythDeintType m_deintType
const char * format_description(VideoFrameType Type)
Definition: mythframe.cpp:33
AVPixelFormat m_inputFmt
void av_free(void *ptr)
static int width_for_plane(VideoFrameType Type, int Width, uint Plane)
Definition: mythframe.h:392
MythDeintType GetSingleRateOption(const VideoFrame *Frame, MythDeintType Type, MythDeintType Override)
Definition: mythframe.cpp:841
static uint32_t avg(uint32_t A, uint32_t B)
#define LOC
VideoFrameType m_inputType