MythTV master
mythvaapidrminterop.cpp
Go to the documentation of this file.
1// MythTV
4
6#include "fourcc.h"
8
9// FFmpeg
10extern "C" {
11#include "libavutil/hwcontext_drm.h"
12}
13
14// Std
15#include <unistd.h>
16
17#define LOC QString("VAAPIDRM: ")
18
20 : MythVAAPIInterop(Player, Context, Type),
21 MythEGLDMABUF(Context)
22{
23 QString device = gCoreContext->GetSetting("VAAPIDevice");
24 if (device.isEmpty())
25 device = "/dev/dri/renderD128";
26 m_drmFile.setFileName(device);
27 if (m_drmFile.open(QIODevice::ReadWrite))
28 {
29 m_vaDisplay = vaGetDisplayDRM(m_drmFile.handle());
30 if (!m_vaDisplay)
31 {
32 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create DRM VADisplay");
33 return;
34 }
35 }
36 else
37 {
38 LOG(VB_GENERAL, LOG_ERR, LOC + QString("Failed to open %1").arg(device));
39 return;
40 }
42
43 // DRM PRIME is preferred as it explicitly sets the fourcc's for each layer -
44 // so we don't have to guess. But it is not available with older libva and
45 // there are reports it does not work with some Radeon drivers
47 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Using %1 for interop")
48 .arg(m_usePrime ? "DRM PRIME" : "VAAPI handle"));
49}
50
52{
53#if CONFIG_DRM_VIDEO
54 delete m_drm;
55#endif
61 if (m_drmFile.isOpen())
62 m_drmFile.close();
63}
64
66{
68
69 if (!m_openglTextures.isEmpty() && m_openglContext->IsEGL())
70 {
71 int count = 0;
72 for (auto it = m_openglTextures.constBegin() ; it != m_openglTextures.constEnd(); ++it)
73 {
74 std::vector<MythVideoTextureOpenGL*> textures = it.value();
75 for (auto & texture : textures)
76 {
77 if (texture->m_data)
78 {
80 texture->m_data = nullptr;
81 count++;
82 }
83 }
84 }
85 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Deleted %1 EGL images in %2 groups")
86 .arg(count).arg(m_openglTextures.size()));
87 }
88
90}
91
93{
94 if (m_filterGraph)
95 {
96 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Deleting deinterlacer frame cache");
99 }
101}
102
104{
105 // remove the old, non-deinterlaced frame cache
106 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Deleting progressive frame cache");
109}
110
112{
113 while (!m_referenceFrames.isEmpty())
114 {
115 AVBufferRef* ref = m_referenceFrames.takeLast();
116 av_buffer_unref(&ref);
117 }
118}
119
121{
122 if (!Buffer)
123 return;
124
125 // don't retain twice for double rate
126 if (!m_referenceFrames.empty() &&
127 (static_cast<VASurfaceID>(reinterpret_cast<uintptr_t>(m_referenceFrames[0]->data)) ==
128 static_cast<VASurfaceID>(reinterpret_cast<uintptr_t>(Buffer->data))))
129 {
130 return;
131 }
132
133 m_referenceFrames.push_front(av_buffer_ref(Buffer));
134
135 // release old frames
136 while (m_referenceFrames.size() > 3)
137 {
138 AVBufferRef* ref = m_referenceFrames.takeLast();
139 av_buffer_unref(&ref);
140 }
141}
142
143std::vector<MythVideoTextureOpenGL*> MythVAAPIInteropDRM::GetReferenceFrames()
144{
145 std::vector<MythVideoTextureOpenGL*> result;
146 int size = m_referenceFrames.size();
147 if (size < 1)
148 return result;
149
150 auto next = static_cast<VASurfaceID>(reinterpret_cast<uintptr_t>(m_referenceFrames[0]->data));
151 auto current = static_cast<VASurfaceID>(reinterpret_cast<uintptr_t>(m_referenceFrames[size > 1 ? 1 : 0]->data));
152 auto last = static_cast<VASurfaceID>(reinterpret_cast<uintptr_t>(m_referenceFrames[size > 2 ? 2 : 0]->data));
153
154 if (!m_openglTextures.contains(next) || !m_openglTextures.contains(current) ||
155 !m_openglTextures.contains(last))
156 {
157 LOG(VB_GENERAL, LOG_ERR, LOC + "Reference frame error");
158 return result;
159 }
160
161 std::copy(m_openglTextures[last].cbegin(), m_openglTextures[last].cend(), std::back_inserter(result));
162 std::copy(m_openglTextures[current].cbegin(), m_openglTextures[current].cend(), std::back_inserter(result));
163 std::copy(m_openglTextures[next].cbegin(), m_openglTextures[next].cend(), std::back_inserter(result));
164 return result;
165}
166
167std::vector<MythVideoTextureOpenGL*>
169 MythVideoColourSpace* ColourSpace,
171 FrameScanType Scan)
172{
173 std::vector<MythVideoTextureOpenGL*> result;
174 if (!Frame)
175 return result;
176
177 VASurfaceID id = VerifySurface(Context, Frame);
178 if (!id || !m_vaDisplay)
179 return result;
180
181 // Update frame colourspace and initialise on first frame
182 if (ColourSpace)
183 {
184 if (m_openglTextures.isEmpty())
186 ColourSpace->UpdateColourSpace(Frame);
187 }
188
189 // Deinterlacing
190 bool needreferenceframes = false;
191 auto discontinuity = qAbs(Frame->m_frameCounter - m_discontinuityCounter) > 1;
192
193 if (is_interlaced(Scan))
194 {
195 // allow GLSL deinterlacers
196 Frame->m_deinterlaceAllowed = Frame->m_deinterlaceAllowed | DEINT_SHADER;
197
198 // is GLSL preferred - and if so do we need reference frames
199 bool glsldeint = false;
200
201 // we explicitly use a shader if preferred over driver. If CPU only
202 // is preferred, the default will be to use the driver instead and if that
203 // fails we fall back to GLSL
204 MythDeintType shader = Frame->GetDoubleRateOption(DEINT_SHADER);
205 MythDeintType driver = Frame->GetDoubleRateOption(DEINT_DRIVER);
206 if (m_filterError)
207 shader = Frame->GetDoubleRateOption(DEINT_SHADER | DEINT_CPU | DEINT_DRIVER, DEINT_ALL);
208 if (shader && !driver)
209 {
210 glsldeint = true;
211 needreferenceframes = shader == DEINT_HIGH;
212 Frame->m_deinterlaceDouble = Frame->m_deinterlaceDouble | DEINT_SHADER;
213 }
214 else if (!shader && !driver) // singlerate
215 {
216 shader = Frame->GetSingleRateOption(DEINT_SHADER);
217 driver = Frame->GetSingleRateOption(DEINT_DRIVER);
218 if (m_filterError)
219 shader = Frame->GetSingleRateOption(DEINT_SHADER | DEINT_CPU | DEINT_DRIVER, DEINT_ALL);
220 if (shader && !driver)
221 {
222 glsldeint = true;
223 needreferenceframes = shader == DEINT_HIGH;
224 Frame->m_deinterlaceSingle = Frame->m_deinterlaceSingle | DEINT_SHADER;
225 }
226 }
227
228 // driver deinterlacing
229 if (!glsldeint)
230 {
231 if (discontinuity)
233 id = Deinterlace(Frame, id, Scan);
234 }
235
236 // fallback to shaders if VAAPI deints fail
237 if (m_filterError)
238 Frame->m_deinterlaceAllowed = Frame->m_deinterlaceAllowed & ~DEINT_DRIVER;
239 }
240 else if (m_deinterlacer)
241 {
243 }
244
245 if (needreferenceframes)
246 {
247 if (discontinuity)
249 RotateReferenceFrames(reinterpret_cast<AVBufferRef*>(Frame->m_priv[0]));
250 }
251 else
252 {
254 }
255 m_discontinuityCounter = Frame->m_frameCounter;
256
257#if CONFIG_DRM_VIDEO
258 if (!m_drmTriedAndFailed)
259 if (HandleDRMVideo(ColourSpace, id, Frame))
260 return result;
261#endif
262
263 // return cached texture if available
264 if (m_openglTextures.contains(id))
265 {
266 if (needreferenceframes)
267 return GetReferenceFrames();
268 return m_openglTextures[id];
269 }
270
272 result = m_usePrime ? AcquirePrime(id, Context, Frame): AcquireVAAPI(id, Context, Frame);
273 m_openglTextures.insert(id, result);
274 if (needreferenceframes)
275 return GetReferenceFrames();
276 return result;
277}
278
279#ifndef DRM_FORMAT_R8
280#define MKTAG2(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | (static_cast<unsigned>(d) << 24))
281#define DRM_FORMAT_R8 MKTAG2('R', '8', ' ', ' ')
282#define DRM_FORMAT_GR88 MKTAG2('G', 'R', '8', '8')
283#define DRM_FORMAT_R16 MKTAG2('R', '1', '6', ' ')
284#define DRM_FORMAT_GR1616 MKTAG2('G', 'R', '3', '2')
285#endif
286
287std::vector<MythVideoTextureOpenGL*>
289 MythRenderOpenGL* Context,
291{
292 std::vector<MythVideoTextureOpenGL*> result;
293
294 VAImage vaimage;
295 memset(&vaimage, 0, sizeof(vaimage));
296 vaimage.buf = vaimage.image_id = VA_INVALID_ID;
297 INIT_ST;
298 va_status = vaDeriveImage(m_vaDisplay, Id, &vaimage);
299 CHECK_ST;
300 uint numplanes = vaimage.num_planes;
301
302 VABufferInfo vabufferinfo;
303 memset(&vabufferinfo, 0, sizeof(vabufferinfo));
304 vabufferinfo.mem_type = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME;
305 va_status = vaAcquireBufferHandle(m_vaDisplay, vaimage.buf, &vabufferinfo);
306 CHECK_ST;
307
308 VideoFrameType format = VATypeToMythType(vaimage.format.fourcc);
309 if (format == FMT_NONE)
310 {
311 LOG(VB_GENERAL, LOG_ERR, LOC + QString("Unsupported VA fourcc: %1")
312 .arg(fourcc_str(static_cast<int32_t>(vaimage.format.fourcc))));
313 }
314 else
315 {
316 if (numplanes != MythVideoFrame::GetNumPlanes(format))
317 {
318 LOG(VB_GENERAL, LOG_ERR, LOC + QString("Inconsistent plane count %1 != %2")
319 .arg(numplanes).arg(MythVideoFrame::GetNumPlanes(format)));
320 }
321 else
322 {
323 AVDRMFrameDescriptor drmdesc;
324 memset(&drmdesc, 0, sizeof(drmdesc));
325 drmdesc.nb_objects = 1;
326 drmdesc.nb_layers = static_cast<int>(numplanes);
327 drmdesc.objects[0].fd = static_cast<int>(vabufferinfo.handle);
328 drmdesc.objects[0].size = 0;
329 drmdesc.objects[0].format_modifier = 0;
330
331 for (uint i = 0; i < numplanes; ++i)
332 {
333 uint32_t fourcc = (format == FMT_P010) ? DRM_FORMAT_R16 : DRM_FORMAT_R8;
334 if (i > 0)
335 fourcc = (format == FMT_P010) ? DRM_FORMAT_GR1616 : DRM_FORMAT_GR88;
336 drmdesc.layers[i].nb_planes = 1;
337 drmdesc.layers[i].format = fourcc;
338 drmdesc.layers[i].planes[0].object_index = 0;
339 drmdesc.layers[i].planes[0].pitch = vaimage.pitches[i];
340 drmdesc.layers[i].planes[0].offset = vaimage.offsets[i];
341 }
342
343 result = CreateTextures(&drmdesc, Context, Frame, false);
344 }
345 }
346
347 va_status = vaReleaseBufferHandle(m_vaDisplay, vaimage.buf);
348 CHECK_ST;
349 va_status = vaDestroyImage(m_vaDisplay, vaimage.image_id);
350 CHECK_ST;
351
352 return result;
353}
354
356{
357 switch (Fourcc)
358 {
359 case VA_FOURCC_IYUV:
360 case VA_FOURCC_I420: return FMT_YV12;
361 case VA_FOURCC_NV12: return FMT_NV12;
362 case VA_FOURCC_YUY2:
363 case VA_FOURCC_UYVY: return FMT_YUY2;
364#if defined (VA_FOURCC_P010)
365 case VA_FOURCC_P010: return FMT_P010;
366#endif
367#if defined (VA_FOURCC_P016)
368 case VA_FOURCC_P016: return FMT_P016;
369#endif
370 case VA_FOURCC_ARGB: return FMT_ARGB32;
371 case VA_FOURCC_RGBA: return FMT_RGBA32;
372 }
373 return FMT_NONE;
374}
375
377{
378 return HaveDMABuf(Context);
379}
380
381#if VA_CHECK_VERSION(1, 1, 0)
382static inline void VADRMtoPRIME(VADRMPRIMESurfaceDescriptor* VaDRM, AVDRMFrameDescriptor* Prime)
383{
384 Prime->nb_objects = static_cast<int>(VaDRM->num_objects);
385 for (uint i = 0; i < VaDRM->num_objects; i++)
386 {
387 Prime->objects[i].fd = VaDRM->objects[i].fd;
388 Prime->objects[i].size = VaDRM->objects[i].size;
389 Prime->objects[i].format_modifier = VaDRM->objects[i].drm_format_modifier;
390 }
391 Prime->nb_layers = static_cast<int>(VaDRM->num_layers);
392 for (uint i = 0; i < VaDRM->num_layers; i++)
393 {
394 Prime->layers[i].format = VaDRM->layers[i].drm_format;
395 Prime->layers[i].nb_planes = static_cast<int>(VaDRM->layers[i].num_planes);
396 for (uint j = 0; j < VaDRM->layers[i].num_planes; j++)
397 {
398 Prime->layers[i].planes[j].object_index = static_cast<int>(VaDRM->layers[i].object_index[j]);
399 Prime->layers[i].planes[j].offset = VaDRM->layers[i].offset[j];
400 Prime->layers[i].planes[j].pitch = VaDRM->layers[i].pitch[j];
401 }
402 }
403}
404#endif
405
411std::vector<MythVideoTextureOpenGL*>
412MythVAAPIInteropDRM::AcquirePrime([[maybe_unused]] VASurfaceID Id,
413 [[maybe_unused]] MythRenderOpenGL* Context,
414 [[maybe_unused]] MythVideoFrame* Frame)
415{
416 std::vector<MythVideoTextureOpenGL*> result;
417
418#if VA_CHECK_VERSION(1, 1, 0)
419 if (!m_drmFrames.contains(Id))
420 m_drmFrames.insert(Id, GetDRMFrameDescriptor(Id));
421 if (!m_drmFrames.contains(Id))
422 return result;
423 result = CreateTextures(m_drmFrames[Id], Context, Frame, false);
424#endif
425 return result;
426}
427
428AVDRMFrameDescriptor* MythVAAPIInteropDRM::GetDRMFrameDescriptor([[maybe_unused]] VASurfaceID Id)
429{
430#if VA_CHECK_VERSION(1, 1, 0)
431 INIT_ST;
432 uint32_t exportflags = VA_EXPORT_SURFACE_SEPARATE_LAYERS | VA_EXPORT_SURFACE_READ_ONLY;
433 VADRMPRIMESurfaceDescriptor vadesc;
434 va_status = vaExportSurfaceHandle(m_vaDisplay, Id,
435 VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2,
436 exportflags, &vadesc);
437 CHECK_ST;
438
439 auto * drmdesc = reinterpret_cast<AVDRMFrameDescriptor*>(av_mallocz(sizeof(AVDRMFrameDescriptor)));
440 VADRMtoPRIME(&vadesc, drmdesc);
441 return drmdesc;
442#else
443 return nullptr;
444#endif
445}
446
448{
449 if (m_drmFrames.isEmpty())
450 return;
451
452 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Releasing %1 DRM descriptors").arg(m_drmFrames.size()));
453 for (auto * frame : std::as_const(m_drmFrames))
454 {
455 for (int i = 0; i < frame->nb_objects; i++)
456 close(frame->objects[i].fd);
457 av_freep(reinterpret_cast<void*>(&frame));
458 }
459 m_drmFrames.clear();
460}
461
463{
464#if VA_CHECK_VERSION(1, 1, 0)
465 static bool s_supported = false;
466 static bool s_checked = false;
467
468 if (s_checked)
469 return s_supported;
470 s_checked = true;
471
473
474 VASurfaceID surface = 0;
475
476 VASurfaceAttrib attribs = {};
477 attribs.flags = VA_SURFACE_ATTRIB_SETTABLE;
478 attribs.type = VASurfaceAttribPixelFormat;
479 attribs.value.type = VAGenericValueTypeInteger;
480 attribs.value.value.i = VA_FOURCC_NV12;
481
482 if (vaCreateSurfaces(m_vaDisplay, VA_RT_FORMAT_YUV420, 1920, 1080,
483 &surface, 1, &attribs, 1) == VA_STATUS_SUCCESS)
484 {
485 VADRMPRIMESurfaceDescriptor vadesc;
486 VAStatus status = vaExportSurfaceHandle(m_vaDisplay, surface, VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2,
487 VA_EXPORT_SURFACE_READ_ONLY | VA_EXPORT_SURFACE_SEPARATE_LAYERS,
488 &vadesc);
489 if (status == VA_STATUS_SUCCESS)
490 {
491 MythVideoFrame frame(FMT_DRMPRIME, nullptr, 0, 1920, 1080);
492 frame.m_swPixFmt = AV_PIX_FMT_NV12;
493 AVDRMFrameDescriptor drmdesc;
494 memset(&drmdesc, 0, sizeof(drmdesc));
495 VADRMtoPRIME(&vadesc, &drmdesc);
496 std::vector<MythVideoTextureOpenGL*> textures =
497 CreateTextures(&drmdesc, m_openglContext, &frame, false);
498
499 if (!textures.empty())
500 {
501 s_supported = true;
502 for (auto & texture : textures)
503 s_supported &= texture->m_data && (texture->m_textureId != 0U);
505 }
506 for (uint32_t i = 0; i < vadesc.num_objects; ++i)
507 close(vadesc.objects[i].fd);
508 }
509 vaDestroySurfaces(m_vaDisplay, &surface, 1);
510 }
511 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("VAAPI DRM PRIME interop is %1supported")
512 .arg(s_supported ? "" : "not "));
513 return s_supported;
514#else
515 return false;
516#endif
517}
518
519#if CONFIG_DRM_VIDEO
520bool MythVAAPIInteropDRM::HandleDRMVideo(MythVideoColourSpace* ColourSpace, VASurfaceID Id, MythVideoFrame* Frame)
521{
522 if (!((m_type == DRM_DRMPRIME) && m_usePrime && Id && Frame && ColourSpace))
523 return false;
524
525 if (!m_drm)
526 m_drm = new MythVideoDRM(ColourSpace);
527
528 if (m_drm)
529 {
530 if (m_drm->IsValid())
531 {
532 if (!m_drmFrames.contains(Id))
533 m_drmFrames.insert(Id, GetDRMFrameDescriptor(Id));
534 if (m_drm->RenderFrame(m_drmFrames[Id], Frame))
535 return true;
536 }
537
538 // RenderFrame may have decided we should give up
539 if (!m_drm->IsValid())
540 {
541 LOG(VB_GENERAL, LOG_INFO, LOC + "Disabling DRM video");
542 m_drmTriedAndFailed = true;
543 delete m_drm;
544 m_drm = nullptr;
545 }
546 }
547 return false;
548}
549#endif
QString GetSetting(const QString &key, const QString &defaultval="")
static void ClearDMATextures(MythRenderOpenGL *Context, std::vector< MythVideoTextureOpenGL * > &Textures)
static bool HaveDMABuf(MythRenderOpenGL *Context)
std::vector< MythVideoTextureOpenGL * > CreateTextures(AVDRMFrameDescriptor *Desc, MythRenderOpenGL *Context, MythVideoFrame *Frame, bool UseSeparate, FrameScanType Scan=kScan_Progressive)
void * GetEGLDisplay(void)
Definition: mythegl.cpp:78
bool IsEGL(void)
Definition: mythegl.cpp:31
void eglDestroyImageKHR(void *Disp, void *Image)
Definition: mythegl.cpp:158
uint64_t m_discontinuityCounter
InteropType m_type
virtual void DeleteTextures()
MythRenderOpenGL * m_openglContext
QHash< unsigned long long, std::vector< MythVideoTextureOpenGL * > > m_openglTextures
static VideoFrameType VATypeToMythType(uint32_t Fourcc)
void PostInitDeinterlacer() override
void RotateReferenceFrames(AVBufferRef *Buffer)
void DeleteTextures() override
static bool IsSupported(MythRenderOpenGL *Context)
QHash< unsigned long long, AVDRMFrameDescriptor * > m_drmFrames
AVDRMFrameDescriptor * GetDRMFrameDescriptor(VASurfaceID Id)
QVector< AVBufferRef * > m_referenceFrames
std::vector< MythVideoTextureOpenGL * > GetReferenceFrames()
std::vector< MythVideoTextureOpenGL * > AcquireVAAPI(VASurfaceID Id, MythRenderOpenGL *Context, MythVideoFrame *Frame)
MythVAAPIInteropDRM(MythPlayerUI *Player, MythRenderOpenGL *Context, InteropType Type)
void DestroyDeinterlacer() override
std::vector< MythVideoTextureOpenGL * > Acquire(MythRenderOpenGL *Context, MythVideoColourSpace *ColourSpace, MythVideoFrame *Frame, FrameScanType Scan) override
std::vector< MythVideoTextureOpenGL * > AcquirePrime(VASurfaceID Id, MythRenderOpenGL *Context, MythVideoFrame *Frame)
Export the given VideoFrame as a DRM PRIME descriptor.
virtual void DestroyDeinterlacer(void)
void InitaliseDisplay(void)
MythDeintType m_deinterlacer
AVFilterGraph * m_filterGraph
VASurfaceID VerifySurface(MythRenderOpenGL *Context, MythVideoFrame *Frame)
VASurfaceID Deinterlace(MythVideoFrame *Frame, VASurfaceID Current, FrameScanType Scan)
MythVideoColourSpace contains a QMatrix4x4 that can convert YCbCr data to RGB.
void SetSupportedAttributes(PictureAttributeSupported Supported)
Enable the given set of picture attributes.
bool UpdateColourSpace(const MythVideoFrame *Frame)
Set the current colourspace to use.
static uint GetNumPlanes(VideoFrameType Type)
Definition: mythframe.h:213
#define close
Definition: compat.h:39
static const char * fourcc_str(int i)
Definition: fourcc.h:26
unsigned int uint
Definition: freesurround.h:24
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
MythDeintType
Definition: mythframe.h:67
@ DEINT_HIGH
Definition: mythframe.h:71
@ DEINT_DRIVER
Definition: mythframe.h:74
@ DEINT_SHADER
Definition: mythframe.h:73
@ DEINT_ALL
Definition: mythframe.h:75
@ DEINT_CPU
Definition: mythframe.h:72
VideoFrameType
Definition: mythframe.h:20
@ FMT_RGBA32
Definition: mythframe.h:34
@ FMT_ARGB32
Definition: mythframe.h:33
@ FMT_YV12
Definition: mythframe.h:23
@ FMT_P016
Definition: mythframe.h:54
@ FMT_DRMPRIME
Definition: mythframe.h:63
@ FMT_NONE
Definition: mythframe.h:21
@ FMT_P010
Definition: mythframe.h:53
@ FMT_NV12
Definition: mythframe.h:52
@ FMT_YUY2
Definition: mythframe.h:50
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
#define LOC
#define DRM_FORMAT_R16
#define DRM_FORMAT_R8
#define DRM_FORMAT_GR88
#define DRM_FORMAT_GR1616
#define VA_FOURCC_I420
#define CHECK_ST
#define INIT_ST
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:15
MBASE_PUBLIC long long copy(QFile &dst, QFile &src, uint block_size=0)
Copies src file to dst file.
FrameScanType
Definition: videoouttypes.h:95
bool is_interlaced(FrameScanType Scan)
#define ALL_PICTURE_ATTRIBUTES