MythTV master
videobuffers.cpp
Go to the documentation of this file.
1// Copyright (c) 2005, Daniel Thor Kristjansson
2// based on earlier work in MythTV's videout_xvmc.cpp
3
4// Std
5#include <chrono>
6#include <thread>
7
8// MythTV
10#include "libmythbase/mythconfig.h"
12
13#include "fourcc.h"
14#include "mythcodecid.h"
15#include "videobuffers.h"
16
17// FFmpeg
18extern "C" {
19#include "libavcodec/avcodec.h"
20}
21
22static constexpr uint16_t TRY_LOCK_SPINS { 2000 };
23static constexpr uint16_t TRY_LOCK_SPINS_BEFORE_WARNING { 9999 };
24static constexpr std::chrono::milliseconds TRY_LOCK_SPIN_WAIT { 1ms };
25
27
37static inline void ReleaseDecoderResources(MythVideoFrame *Frame, std::vector<AVBufferRef *> &Discards)
38{
40 {
41 auto* ref = reinterpret_cast<AVBufferRef*>(Frame->m_priv[0]);
42 if (ref != nullptr)
43 Discards.push_back(ref);
44 Frame->m_buffer = Frame->m_priv[0] = nullptr;
45
47 {
48 ref = reinterpret_cast<AVBufferRef*>(Frame->m_priv[1]);
49 if (ref != nullptr)
50 Discards.push_back(ref);
51 Frame->m_priv[1] = nullptr;
52 }
53 }
54}
55
56static inline void DoDiscard(const std::vector<AVBufferRef *> &Discards)
57{
58 for (auto * it : Discards)
59 av_buffer_unref(&it);
60}
61
135uint VideoBuffers::GetNumBuffers(int PixelFormat, int MaxReferenceFrames, bool Decoder /*=false*/)
136{
137 uint refs = static_cast<uint>(MaxReferenceFrames);
138 switch (PixelFormat)
139 {
140 case FMT_DXVA2: return 30;
141 // It is currrently unclear whether VTB just happy with a smaller buffer size
142 // or needs reference frames plus headroom - use the latter for now.
143 case FMT_VTB: return refs + 8;
144 // Max 16 ref frames, 12 headroom and allocate 2 extra in the VAAPI frames
145 // context for additional references held by the VPP deinterlacer (i.e.
146 // prevent buffer starvation in the decoder)
147 // This covers the 'worst case' samples.
148 case FMT_VAAPI: return Decoder ? (refs + 14) : (refs + 12);
149 case FMT_VDPAU: return refs + 12;
150 // Copyback of hardware frames. These decoders are buffering internally
151 // already - so no need for a large presentation buffer
152 case FMT_NONE: return 8; // NOLINT(bugprone-branch-clone)
153 // As for copyback, these decoders buffer internally
154 case FMT_NVDEC: return 8;
155 case FMT_MEDIACODEC: return 8;
156 case FMT_MMAL: return 8;
157 // the default number of output buffers in FFmpeg v4l2_m2m.h is 6
158 case FMT_DRMPRIME: return 6;
159 // Standard software decode
160 case FMT_YV12: return refs + 14;
161 default: break;
162 }
163 return 30;
164}
165
175void VideoBuffers::Init(uint NumDecode, uint NeedFree,
176 uint NeedPrebufferNormal, uint NeedPrebufferSmall)
177{
178 QMutexLocker locker(&m_globalLock);
179
180 Reset();
181
182 // make a big reservation, so that things that depend on
183 // pointer to VideoFrames work even after a few push_backs
184 m_buffers.reserve(std::max(NumDecode, 128U));
185 m_buffers.resize(NumDecode);
186 for (uint i = 0; i < NumDecode; i++)
187 m_vbufferMap[At(i)] = i;
188
189 m_needFreeFrames = NeedFree;
190 m_needPrebufferFrames = NeedPrebufferNormal;
191 m_needPrebufferFramesNormal = NeedPrebufferNormal;
192 m_needPrebufferFramesSmall = NeedPrebufferSmall;
193
194 for (uint i = 0; i < NumDecode; i++)
197}
198
200 MythCodecID CodecID)
201{
202 QMutexLocker locker(&m_globalLock);
203 for (auto & buffer : m_buffers)
204 SetDeinterlacingFlags(buffer, Single, Double, CodecID);
205}
206
215 MythDeintType Double, MythCodecID CodecID)
216{
217 static const MythDeintType kDriver = DEINT_ALL & ~(DEINT_CPU | DEINT_SHADER);
218 static const MythDeintType kShader = DEINT_ALL & ~(DEINT_CPU | DEINT_DRIVER);
219 static const MythDeintType kSoftware = DEINT_ALL & ~(DEINT_SHADER | DEINT_DRIVER);
220 Frame.m_deinterlaceSingle = Single;
221 Frame.m_deinterlaceDouble = Double;
222
223 if (codec_is_copyback(CodecID))
224 {
225 if (codec_is_vaapi_dec(CodecID) || codec_is_nvdec_dec(CodecID))
226 Frame.m_deinterlaceAllowed = kSoftware | kShader | kDriver;
227 else // VideoToolBox, MediaCodec and VDPAU copyback
228 Frame.m_deinterlaceAllowed = kSoftware | kShader;
229 }
230 else if (FMT_DRMPRIME == Frame.m_type)
231 { // NOLINT(bugprone-branch-clone)
232 Frame.m_deinterlaceAllowed = kShader; // No driver deint - if RGBA frames are returned, shaders will be disabled
233 }
234 else if (FMT_MMAL == Frame.m_type)
235 {
236 Frame.m_deinterlaceAllowed = kShader; // No driver deint yet (TODO) and YUV frames returned
237 }
238 else if (FMT_VTB == Frame.m_type)
239 {
240 Frame.m_deinterlaceAllowed = kShader; // No driver deint and YUV frames returned
241 }
242 else if (FMT_NVDEC == Frame.m_type)
243 {
244 Frame.m_deinterlaceAllowed = kShader | kDriver; // YUV frames and decoder deint
245 }
246 else if (FMT_VDPAU == Frame.m_type)
247 { // NOLINT(bugprone-branch-clone)
248 Frame.m_deinterlaceAllowed = kDriver; // No YUV frames for shaders
249 }
250 else if (FMT_VAAPI == Frame.m_type)
251 {
252 Frame.m_deinterlaceAllowed = kDriver; // DRM will allow shader if no VPP
253 }
254 else
255 {
256 Frame.m_deinterlaceAllowed = kSoftware | kShader;
257 }
258}
259
265{
266 QMutexLocker locker(&m_globalLock);
267 m_available.clear();
268 m_used.clear();
269 m_limbo.clear();
270 m_finished.clear();
271 m_decode.clear();
272 m_pause.clear();
273 m_displayed.clear();
274 m_vbufferMap.clear();
275}
276
282{
283 QMutexLocker locker(&m_globalLock);
285}
286
288{
289 QMutexLocker locker(&m_globalLock);
290 MythVideoFrame *frame = nullptr;
291
292 // Try to get a frame not being used by the decoder
293 for (size_t i = 0; i < m_available.size(); i++)
294 {
295 frame = m_available.dequeue();
296 if (m_decode.contains(frame))
297 m_available.enqueue(frame);
298 else
299 break;
300 }
301
302 while (frame && m_used.contains(frame))
303 {
304 LOG(VB_PLAYBACK, LOG_NOTICE,
305 QString("GetNextFreeFrame() served a busy frame %1. Dropping. %2")
306 .arg(DebugString(frame, true), GetStatus()));
307 frame = m_available.dequeue();
308 }
309
310 if (frame)
311 SafeEnqueue(EnqueueTo, frame);
312 return frame;
313}
314
320{
321 for (uint tries = 1; true; tries++)
322 {
324 if (frame)
325 return frame;
326
327 if (tries >= TRY_LOCK_SPINS)
328 {
329 LOG(VB_GENERAL, LOG_ERR, QString("GetNextFreeFrame: "
330 "available:%1 used:%2 limbo:%3 pause:%4 displayed:%5 decode:%6 finished:%7")
331 .arg(m_available.size()).arg(m_used.size()).arg(m_limbo.size())
332 .arg(m_pause.size()).arg(m_displayed.size()).arg(m_decode.size())
333 .arg(m_finished.size()));
334 LOG(VB_GENERAL, LOG_ERR,
335 QString("GetNextFreeFrame() unable to "
336 "lock frame %1 times. Discarding Frames.")
337 .arg(TRY_LOCK_SPINS));
338 DiscardFrames(true);
339 continue;
340 }
341
342 if (tries && !(tries % TRY_LOCK_SPINS_BEFORE_WARNING))
343 {
344 LOG(VB_PLAYBACK, LOG_NOTICE,
345 QString("GetNextFreeFrame() TryLock has "
346 "spun %1 times, this is a lot.").arg(tries));
347 }
348 std::this_thread::sleep_for(TRY_LOCK_SPIN_WAIT);
349 }
350
351 return nullptr;
352}
353
361{
362 QMutexLocker locker(&m_globalLock);
363
366 //non directrendering frames are ffmpeg handled
367 if (Frame->m_directRendering)
370}
371
378{
379 std::vector<AVBufferRef*> discards;
380
381 m_globalLock.lock();
382
385
386 // if decoder didn't release frame and the buffer is getting released by
387 // the decoder assume that the frame is lost and return to available
388 if (!m_decode.contains(Frame))
389 {
392 }
393
394 // remove from decode queue since the decoder is finished
395 while (m_decode.contains(Frame))
397
398 m_globalLock.unlock();
399
400 DoDiscard(discards);
401}
402
408{
409 QMutexLocker locker(&m_globalLock);
411}
412
418{
419 std::vector<AVBufferRef*> discards;
420
421 m_globalLock.lock();
422
425
427
428 // check if any finished frames are no longer used by decoder and return to available
430 for (auto & it : ula)
431 {
432 if (!m_decode.contains(it))
433 {
435 ReleaseDecoderResources(it, discards);
437 }
438 }
439
440 m_globalLock.unlock();
441
442 DoDiscard(discards);
443}
444
451{
452 std::vector<AVBufferRef*> discards;
453 m_globalLock.lock();
456 m_globalLock.unlock();
457 DoDiscard(discards);
458}
459
461{
462 std::vector<AVBufferRef*> discards;
463
464 m_globalLock.lock();
465 while (Size(kVideoBuffer_pause))
466 {
468 ReleaseDecoderResources(frame, discards);
470 }
471 m_globalLock.unlock();
472
473 DoDiscard(discards);
474}
475
482bool VideoBuffers::DiscardAndRecreate(MythCodecID CodecID, QSize VideoDim, int References)
483{
484 bool result = false;
485 std::vector<AVBufferRef*> refs;
486
487 m_globalLock.lock();
488 LOG(VB_PLAYBACK, LOG_INFO, QString("DiscardAndRecreate: %1").arg(GetStatus()));
489
490 // Remove pause frames (cutdown version of DiscardPauseFrames)
491 while (Size(kVideoBuffer_pause))
492 {
494 ReleaseDecoderResources(frame, refs);
496 }
497
498 // See DiscardFrames
500 ula.insert(ula.end(), m_limbo.begin(), m_limbo.end());
501 ula.insert(ula.end(), m_available.begin(), m_available.end());
502 ula.insert(ula.end(), m_finished.begin(), m_finished.end());
503
504 frame_queue_t discards(m_used);
505 discards.insert(discards.end(), m_limbo.begin(), m_limbo.end());
506 discards.insert(discards.end(), m_finished.begin(), m_finished.end());
507 for (auto & discard : discards)
508 {
509 ReleaseDecoderResources(discard, refs);
511 }
512
514 {
515 for (uint i = 0; i < Size(); i++)
516 {
517 if (!m_available.contains(At(i)) && !m_pause.contains(At(i)) &&
519 {
520 LOG(VB_GENERAL, LOG_INFO,
521 QString("VideoBuffers::DiscardFrames(): %1 (%2) not "
522 "in available, pause, or displayed %3")
523 .arg(DebugString(At(i), true)).arg(reinterpret_cast<long long>(At(i)))
524 .arg(GetStatus()));
525 ReleaseDecoderResources(At(i), refs);
527 }
528 }
529 }
530
531 for (auto & it : m_decode)
533 for (auto & it : m_decode)
535 m_decode.clear();
536
537 Reset();
538
539 // Recreate - see MythVideoOutputOpenGL::CreateBuffers
540 if (codec_is_copyback(CodecID))
541 {
543 result = CreateBuffers(FMT_YV12, VideoDim.width(), VideoDim.height(), m_renderFormats);
544 }
545 else if (codec_is_mediacodec(CodecID))
546 {
547 result = CreateBuffers(FMT_MEDIACODEC, m_renderFormats, VideoDim, 1, 2, 2);
548 }
549 else if (codec_is_vaapi(CodecID))
550 {
551 result = CreateBuffers(FMT_VAAPI, m_renderFormats, VideoDim, 2, 1, 4, References);
552 }
553 else if (codec_is_vtb(CodecID))
554 {
555 result = CreateBuffers(FMT_VTB, m_renderFormats, VideoDim, 1, 4, 2);
556 }
557 else if (codec_is_vdpau(CodecID))
558 {
559 result = CreateBuffers(FMT_VDPAU, m_renderFormats, VideoDim, 2, 1, 4, References);
560 }
561 else if (codec_is_nvdec(CodecID))
562 {
563 result = CreateBuffers(FMT_NVDEC, m_renderFormats, VideoDim, 2, 1, 4);
564 }
565 else if (codec_is_mmal(CodecID))
566 {
567 result = CreateBuffers(FMT_MMAL, m_renderFormats, VideoDim, 2, 1, 4);
568 }
569 else if (codec_is_v4l2(CodecID) || codec_is_drmprime(CodecID))
570 {
571 result = CreateBuffers(FMT_DRMPRIME, m_renderFormats, VideoDim, 2, 1, 4);
572 }
573 else
574 {
575 result = CreateBuffers(FMT_YV12, m_renderFormats, VideoDim, 1, 8, 4, References);
576 }
577
578 LOG(VB_PLAYBACK, LOG_INFO, QString("DiscardAndRecreate: %1").arg(GetStatus()));
579 m_globalLock.unlock();
580
581 // and finally release references now that the lock is released
582 DoDiscard(refs);
583 return result;
584}
585
587{
588 QMutexLocker locker(&m_globalLock);
589 frame_queue_t *queue = nullptr;
590 if (Type == kVideoBuffer_avail)
591 queue = &m_available;
592 else if (Type == kVideoBuffer_used)
593 queue = &m_used;
594 else if (Type == kVideoBuffer_displayed)
595 queue = &m_displayed;
596 else if (Type == kVideoBuffer_limbo)
597 queue = &m_limbo;
598 else if (Type == kVideoBuffer_pause)
599 queue = &m_pause;
600 else if (Type == kVideoBuffer_decode)
601 queue = &m_decode;
602 else if (Type == kVideoBuffer_finished)
603 queue = &m_finished;
604 return queue;
605}
606
608{
609 QMutexLocker locker(&m_globalLock);
610 const frame_queue_t *queue = nullptr;
611 if (Type == kVideoBuffer_avail)
612 queue = &m_available;
613 else if (Type == kVideoBuffer_used)
614 queue = &m_used;
615 else if (Type == kVideoBuffer_displayed)
616 queue = &m_displayed;
617 else if (Type == kVideoBuffer_limbo)
618 queue = &m_limbo;
619 else if (Type == kVideoBuffer_pause)
620 queue = &m_pause;
621 else if (Type == kVideoBuffer_decode)
622 queue = &m_decode;
623 else if (Type == kVideoBuffer_finished)
624 queue = &m_finished;
625 return queue;
626}
627
629{
630 return &m_buffers[FrameNum];
631}
632
634{
635 return &m_buffers[FrameNum];
636}
637
639{
640 QMutexLocker locker(&m_globalLock);
641 frame_queue_t *queue = Queue(Type);
642 if (!queue)
643 return nullptr;
644 return queue->dequeue();
645}
646
648{
649 QMutexLocker locker(&m_globalLock);
650 frame_queue_t *queue = Queue(Type);
651 if (!queue)
652 return nullptr;
653 if (!queue->empty())
654 return queue->head();
655 return nullptr;
656}
657
659{
660 QMutexLocker locker(&m_globalLock);
661 frame_queue_t *queue = Queue(Type);
662 if (!queue)
663 return nullptr;
664 if (!queue->empty())
665 return queue->tail();
666 return nullptr;
667}
668
670{
671 if (!Frame)
672 return;
673 frame_queue_t *queue = Queue(Type);
674 if (!queue)
675 return;
676 m_globalLock.lock();
677 queue->remove(Frame);
678 queue->enqueue(Frame);
679 if (Type == kVideoBuffer_pause)
680 Frame->m_pauseFrame = true;
681 m_globalLock.unlock();
682}
683
685{
686 if (!Frame)
687 return;
688
689 QMutexLocker locker(&m_globalLock);
692 if ((Type & kVideoBuffer_used) == kVideoBuffer_used)
704}
705
707{
708 if (!Frame)
709 return;
710 QMutexLocker locker(&m_globalLock);
712 Enqueue(Type, Frame);
713}
714
721{
722 m_globalLock.lock();
723 frame_queue_t *queue = Queue(Type);
724 if (queue)
725 return queue->begin();
726 return m_available.begin();
727}
728
730{
731 m_globalLock.unlock();
732}
733
735{
736 QMutexLocker locker(&m_globalLock);
737 frame_queue_t *queue = Queue(Type);
738 return (queue ? queue->end() : m_available.end());
739}
740
742{
743 QMutexLocker locker(&m_globalLock);
744 const frame_queue_t *queue = Queue(Type);
745 if (queue)
746 return queue->size();
747 return 0;
748}
749
751{
752 QMutexLocker locker(&m_globalLock);
753 const frame_queue_t *queue = Queue(Type);
754 if (queue)
755 return queue->contains(Frame);
756 return false;
757}
758
760{
761 return At(m_vpos);
762}
763
765{
766 return At(m_rpos);
767}
768
770{
771 return Size(kVideoBuffer_used);
772}
773
775{
776 return Size(kVideoBuffer_avail);
777}
778
780{
782}
783
785{
787}
788
790{
791 return At(m_vpos);
792}
793
795{
796 return At(m_rpos);
797}
798
800{
801 return m_buffers.size();
802}
803
808void VideoBuffers::DiscardFrames(bool NextFrameIsKeyFrame)
809{
810 std::vector<AVBufferRef*> refs;
811 m_globalLock.lock();
812 LOG(VB_PLAYBACK, LOG_INFO, QString("VideoBuffers::DiscardFrames(%1): %2")
813 .arg(NextFrameIsKeyFrame).arg(GetStatus()));
814
815 if (!NextFrameIsKeyFrame)
816 {
818 for (auto & it : ula)
819 {
820 ReleaseDecoderResources(it, refs);
822 }
823 LOG(VB_PLAYBACK, LOG_INFO,
824 QString("VideoBuffers::DiscardFrames(%1): %2 -- done")
825 .arg(NextFrameIsKeyFrame).arg(GetStatus()));
826 m_globalLock.unlock();
827 DoDiscard(refs);
828 return;
829 }
830
831 // Remove inheritence of all frames not in displayed or pause
833 ula.insert(ula.end(), m_limbo.begin(), m_limbo.end());
834 ula.insert(ula.end(), m_available.begin(), m_available.end());
835 ula.insert(ula.end(), m_finished.begin(), m_finished.end());
837
838 // Discard frames
839 frame_queue_t discards(m_used);
840 discards.insert(discards.end(), m_limbo.begin(), m_limbo.end());
841 discards.insert(discards.end(), m_finished.begin(), m_finished.end());
842 for (it = discards.begin(); it != discards.end(); ++it)
843 {
844 ReleaseDecoderResources(*it, refs);
846 }
847
848 // Verify that things are kosher
850 {
851 for (uint i = 0; i < Size(); i++)
852 {
853 if (!m_available.contains(At(i)) && !m_pause.contains(At(i)) &&
855 {
856 // This message is DEBUG because it does occur
857 // after Reset is called.
858 // That happens when failing over from OpenGL
859 // to another method, if QT painter is selected.
860 LOG(VB_GENERAL, LOG_DEBUG,
861 QString("VideoBuffers::DiscardFrames(): %1 (%2) not "
862 "in available, pause, or displayed %3")
863 .arg(DebugString(At(i), true)).arg((long long)At(i))
864 .arg(GetStatus()));
865 ReleaseDecoderResources(At(i), refs);
867 }
868 }
869 }
870
871 // Make sure frames used by decoder are last...
872 // This is for libmpeg2 which still uses the frames after a reset.
873 for (it = m_decode.begin(); it != m_decode.end(); ++it)
875 for (it = m_decode.begin(); it != m_decode.end(); ++it)
876 m_available.enqueue(*it);
877 m_decode.clear();
878
879 LOG(VB_PLAYBACK, LOG_INFO,
880 QString("VideoBuffers::DiscardFrames(%1): %2 -- done")
881 .arg(NextFrameIsKeyFrame).arg(GetStatus()));
882
883 m_globalLock.unlock();
884 DoDiscard(refs);
885}
886
896{
897 std::vector<AVBufferRef*> discards;
898 {
899 QMutexLocker locker(&m_globalLock);
900
901 for (uint i = 0; i < Size(); i++)
902 At(i)->m_timecode = 0ms;
903
904 for (uint i = 0; (i < Size()) && (m_used.count() > 1); i++)
905 {
906 MythVideoFrame *buffer = At(i);
907 if (m_used.contains(buffer) && !m_decode.contains(buffer))
908 {
909 m_used.remove(buffer);
910 m_available.enqueue(buffer);
911 ReleaseDecoderResources(buffer, discards);
912 }
913 }
914
915 if (m_used.count() > 0)
916 {
917 for (uint i = 0; i < Size(); i++)
918 {
919 MythVideoFrame *buffer = At(i);
920 if (m_used.contains(buffer) && !m_decode.contains(buffer))
921 {
922 m_used.remove(buffer);
923 m_available.enqueue(buffer);
924 ReleaseDecoderResources(buffer, discards);
925 m_vpos = m_vbufferMap[buffer];
926 m_rpos = m_vpos;
927 break;
928 }
929 }
930 }
931 else
932 {
933 m_vpos = m_rpos = 0;
934 }
935 }
936
937 DoDiscard(discards);
938}
939
940bool VideoBuffers::CreateBuffers(VideoFrameType Type, const VideoFrameTypes* RenderFormats, QSize Size,
941 uint NeedFree, uint NeedprebufferNormal,
942 uint NeedPrebufferSmall, int MaxReferenceFrames)
943{
944 m_renderFormats = RenderFormats;
945 Init(GetNumBuffers(Type, MaxReferenceFrames), NeedFree, NeedprebufferNormal, NeedPrebufferSmall);
946 return CreateBuffers(Type, Size.width(), Size.height(), m_renderFormats);
947}
948
949bool VideoBuffers::CreateBuffers(VideoFrameType Type, int Width, int Height, const VideoFrameTypes* RenderFormats)
950{
951 bool success = true;
952 m_renderFormats = RenderFormats;
953
954 // Hardware buffers with no allocated memory
956 {
957 for (uint i = 0; i < Size(); i++)
958 m_buffers[i].Init(Type, Width, Height, m_renderFormats);
959 LOG(VB_PLAYBACK, LOG_INFO, QString("Created %1 empty %2 (%3x%4) video buffers")
960 .arg(Size()).arg(MythVideoFrame::FormatDescription(Type)).arg(Width).arg(Height));
961 return true;
962 }
963
964 // Software buffers
965 for (uint i = 0; i < Size(); i++)
966 {
967 m_buffers[i].Init(Type, Width, Height, m_renderFormats);
968 m_buffers[i].ClearBufferToBlank();
969 success &= m_buffers[i].m_dummy || (m_buffers[i].m_buffer != nullptr);
970 }
971
972 // workaround null buffers for audio only (remove when these buffers aren't used)
973 if (!success && (Width < 1 || Height < 1))
974 success = true;
975
976 LOG(VB_PLAYBACK, LOG_INFO, QString("Created %1 %2 (%3x%4) video buffers")
977 .arg(Size()).arg(MythVideoFrame::FormatDescription(Type)).arg(Width).arg(Height));
978 return success;
979}
980
982 int Width, int Height)
983{
984 if (!Frame)
985 return false;
986
988 {
989 LOG(VB_GENERAL, LOG_ERR, "Cannot re-initialise a hardware buffer");
990 return false;
991 }
992
993 VideoFrameType old = Frame->m_type;
994 const auto * formats = Frame->m_renderFormats;
995 LOG(VB_PLAYBACK, LOG_INFO, QString("Reallocating frame %1 %2x%3->%4 %5x%6")
996 .arg(MythVideoFrame::FormatDescription(old)).arg(Frame->m_width).arg(Frame->m_height)
997 .arg(MythVideoFrame::FormatDescription(Type)).arg(Width).arg(Height));
998
999 MythDeintType singler = Frame->m_deinterlaceSingle;
1000 MythDeintType doubler = Frame->m_deinterlaceDouble;
1001 Frame->Init(Type, Width, Height, formats);
1002 Frame->ClearBufferToBlank();
1003
1004 // retain deinterlacer settings and update restrictions based on new frame type
1005 SetDeinterlacingFlags(*Frame, singler, doubler, CodecID);
1006 return true;
1007}
1008
1009static unsigned long long to_bitmap(const frame_queue_t& Queue, int Num);
1010
1012{
1013 if (Num == 0)
1014 Num = Size();
1015
1016 QString str("");
1017 if (m_globalLock.tryLock())
1018 {
1019 int count = Size();
1020 unsigned long long a = to_bitmap(m_available, count);
1021 unsigned long long u = to_bitmap(m_used, count);
1022 unsigned long long d = to_bitmap(m_displayed, count);
1023 unsigned long long l = to_bitmap(m_limbo, count);
1024 unsigned long long p = to_bitmap(m_pause, count);
1025 unsigned long long f = to_bitmap(m_finished, count);
1026 unsigned long long x = to_bitmap(m_decode, count);
1027 for (uint i = 0; i < Num; i++)
1028 {
1029 unsigned long long mask = 1ULL << i;
1030 QString tmp("");
1031 if (a & mask)
1032 tmp += (x & mask) ? "a" : "A";
1033 if (u & mask)
1034 tmp += (x & mask) ? "u" : "U";
1035 if (d & mask)
1036 tmp += (x & mask) ? "d" : "D";
1037 if (l & mask)
1038 tmp += (x & mask) ? "l" : "L";
1039 if (p & mask)
1040 tmp += (x & mask) ? "p" : "P";
1041 if (f & mask)
1042 tmp += (x & mask) ? "f" : "F";
1043 if (0 == tmp.length())
1044 str += " ";
1045 else if (1 == tmp.length())
1046 str += tmp;
1047 else
1048 str += "(" + tmp + ")";
1049 }
1050 m_globalLock.unlock();
1051 }
1052 else
1053 {
1054 for (uint i = 0; i < Num; i++)
1055 str += " ";
1056 }
1057 return str;
1058}
1059
1060/*******************************
1061 ** Debugging functions below **
1062 *******************************/
1063
1064static constexpr size_t DBG_STR_ARR_SIZE { 40 };
1065const std::array<const QString,DBG_STR_ARR_SIZE> dbg_str_arr
1066{
1067 "A ", " B ", " C ", " D ",
1068 " E ", " F ", " G ", " H", // 8
1069 "a ", " b ", " c ", " d ",
1070 " e ", " f ", " g ", " h", // 16
1071 "0 ", " 1 ", " 2 ", " 3 ",
1072 " 4 ", " 5 ", " 6 ", " 7", // 24
1073 "I ", " J ", " K ", " L ",
1074 " M ", " N ", " O ", " P", // 32
1075 "i ", " j ", " k ", " l ",
1076 " m ", " n ", " o ", " p", // 40
1077};
1078const std::array<const QString,DBG_STR_ARR_SIZE> dbg_str_arr_short
1079{
1080 "A","B","C","D","E","F","G","H", // 8
1081 "a","b","c","d","e","f","g","h", // 16
1082 "0","1","2","3","4","5","6","7", // 24
1083 "I","J","K","L","M","N","O","P", // 32
1084 "i","j","k","l","m","n","o","p", // 40
1085};
1086
1087std::map<const MythVideoFrame *, int> dbg_str;
1088
1090{
1091 auto it = dbg_str.find(Frame);
1092 if (it == dbg_str.end())
1093 return dbg_str[Frame] = next_dbg_str++;
1094 return it->second;
1095}
1096
1097const QString& DebugString(const MythVideoFrame *Frame, bool Short)
1098{
1099 if (Short)
1102}
1103
1104const QString& DebugString(uint FrameNum, bool Short)
1105{
1106 return ((Short) ? dbg_str_arr_short : dbg_str_arr)[FrameNum];
1107}
1108
1109static unsigned long long to_bitmap(const frame_queue_t& Queue, int Num)
1110{
1111 unsigned long long bitmap = 0;
1112 for (auto *it : Queue)
1113 {
1114 int shift = DebugNum(it) % Num;
1115 bitmap |= 1ULL << shift;
1116 }
1117 return bitmap;
1118}
T head()
Returns item at head of list. O(1).
Definition: mythdeque.h:82
size_type count() const
Returns size of list. O(1).
Definition: mythdeque.h:79
T dequeue()
Removes item from front of list and returns a copy. O(1).
Definition: mythdeque.h:31
void remove(T const item)
Removes any item from list. O(n).
Definition: mythdeque.h:66
void enqueue(const T &d)
Adds item to the back of the list. O(1).
Definition: mythdeque.h:41
bool contains(T const &item) const
Returns true if item is in list. O(n).
Definition: mythdeque.h:75
typename std::deque< MythVideoFrame * >::iterator iterator
Definition: mythdeque.h:43
T tail()
Returns item at tail of list. O(1).
Definition: mythdeque.h:91
static QString FormatDescription(VideoFrameType Type)
Definition: mythframe.cpp:368
static bool HardwareFramesFormat(VideoFrameType Type)
Definition: mythframe.h:432
std::chrono::milliseconds m_timecode
Definition: mythframe.h:130
static bool HardwareFormat(VideoFrameType Type)
Definition: mythframe.h:424
uint m_needPrebufferFramesSmall
Definition: videobuffers.h:117
void SetPrebuffering(bool Normal)
Sets prebuffering state to normal, or small.
QRecursiveMutex m_globalLock
Definition: videobuffers.h:120
MythVideoFrame * GetNextFreeFrame(BufferType EnqueueTo=kVideoBuffer_limbo)
Gets a frame from available buffers list.
static uint GetNumBuffers(int PixelFormat, int MaxReferenceFrames=16, bool Decoder=false)
void SafeEnqueue(BufferType Type, MythVideoFrame *Frame)
frame_queue_t m_finished
Definition: videobuffers.h:109
frame_queue_t::iterator BeginLock(BufferType Type)
Lock the video buffers.
MythVideoFrame * Tail(BufferType Type)
bool EnoughFreeFrames(void) const
frame_queue_t * Queue(BufferType Type)
frame_queue_t m_pause
Definition: videobuffers.h:106
MythVideoFrame * At(uint FrameNum)
uint Size(void) const
QString GetStatus(uint Num=0) const
uint m_needFreeFrames
Definition: videobuffers.h:114
frame_vector_t m_buffers
Definition: videobuffers.h:111
frame_queue_t m_displayed
Definition: videobuffers.h:107
MythVideoFrame * GetLastShownFrame(void)
MythVideoFrame * GetLastDecodedFrame(void)
void SetDeinterlacing(MythDeintType Single, MythDeintType Double, MythCodecID CodecID)
frame_queue_t m_available
Definition: videobuffers.h:103
static void SetDeinterlacingFlags(MythVideoFrame &Frame, MythDeintType Single, MythDeintType Double, MythCodecID CodecID)
Set the appropriate flags for single and double rate deinterlacing.
bool CreateBuffers(VideoFrameType Type, const VideoFrameTypes *RenderFormats, QSize Size, uint NeedFree, uint NeedprebufferNormal, uint NeedPrebufferSmall, int MaxReferenceFrames=16)
uint ValidVideoFrames(void) const
bool EnoughDecodedFrames(void) const
void Reset(void)
Resets the class so that Init may be called again.
bool Contains(BufferType Type, MythVideoFrame *Frame) const
void Remove(BufferType Type, MythVideoFrame *Frame)
frame_queue_t m_limbo
Definition: videobuffers.h:105
void DiscardPauseFrames(void)
void DoneDisplayingFrame(MythVideoFrame *Frame)
Removes frame from used queue and adds it to the available list.
const VideoFrameTypes * m_renderFormats
Definition: videobuffers.h:112
MythVideoFrame * Dequeue(BufferType Type)
MythVideoFrame * GetNextFreeFrameInternal(BufferType EnqueueTo)
void Enqueue(BufferType Type, MythVideoFrame *Frame)
frame_queue_t m_decode
Definition: videobuffers.h:108
static bool ReinitBuffer(MythVideoFrame *Frame, VideoFrameType Type, MythCodecID CodecID, int Width, int Height)
frame_queue_t m_used
Definition: videobuffers.h:104
frame_queue_t::iterator End(BufferType Type)
void DiscardFrames(bool NextFrameIsKeyFrame)
Mark all used frames as ready to be reused, this is for seek.
void ReleaseFrame(MythVideoFrame *Frame)
Frame is ready to be for filtering or OSD application.
void Init(uint NumDecode, uint NeedFree, uint NeedprebufferNormal, uint NeedPrebufferSmall)
Creates buffers and sets various buffer management parameters.
void ClearAfterSeek(void)
Clear used frames after seeking.
vbuffer_map_t m_vbufferMap
Definition: videobuffers.h:110
void DiscardFrame(MythVideoFrame *Frame)
Frame is ready to be reused by decoder.
bool DiscardAndRecreate(MythCodecID CodecID, QSize VideoDim, int References)
Discard all buffers and recreate.
uint FreeVideoFrames(void) const
void StartDisplayingFrame(void)
Sets rpos to index of videoframe at head of used queue.
uint m_needPrebufferFramesNormal
Definition: videobuffers.h:116
MythVideoFrame * Head(BufferType Type)
void DeLimboFrame(MythVideoFrame *Frame)
If the frame is still in the limbo state it is added to the available queue.
uint m_needPrebufferFrames
Definition: videobuffers.h:115
unsigned int uint
Definition: freesurround.h:24
static guint32 * tmp
Definition: goom_core.cpp:26
static const iso6937table * d
unsigned short uint16_t
Definition: iso6937tables.h:3
MythCodecID
Definition: mythcodecid.h:14
@ kCodec_NONE
Definition: mythcodecid.h:17
static bool codec_is_vdpau(MythCodecID id)
Definition: mythcodecid.h:304
static bool codec_is_mediacodec(MythCodecID id)
Definition: mythcodecid.h:337
static bool codec_is_drmprime(MythCodecID id)
Definition: mythcodecid.h:301
static bool codec_is_mmal(MythCodecID id)
Definition: mythcodecid.h:363
static bool codec_is_nvdec(MythCodecID id)
Definition: mythcodecid.h:344
static bool codec_is_vtb(MythCodecID id)
Definition: mythcodecid.h:351
static bool codec_is_v4l2(MythCodecID id)
Definition: mythcodecid.h:358
static bool codec_is_copyback(MythCodecID id)
Definition: mythcodecid.h:368
static bool codec_is_nvdec_dec(MythCodecID id)
Definition: mythcodecid.h:347
static bool codec_is_vaapi(MythCodecID id)
Definition: mythcodecid.h:321
static bool codec_is_vaapi_dec(MythCodecID id)
Definition: mythcodecid.h:324
MythDeintType
Definition: mythframe.h:67
@ DEINT_DRIVER
Definition: mythframe.h:74
@ DEINT_NONE
Definition: mythframe.h:68
@ DEINT_SHADER
Definition: mythframe.h:73
@ DEINT_ALL
Definition: mythframe.h:75
@ DEINT_CPU
Definition: mythframe.h:72
std::vector< VideoFrameType > VideoFrameTypes
Definition: mythframe.h:82
VideoFrameType
Definition: mythframe.h:20
@ FMT_VAAPI
Definition: mythframe.h:57
@ FMT_VTB
Definition: mythframe.h:61
@ FMT_YV12
Definition: mythframe.h:23
@ FMT_DRMPRIME
Definition: mythframe.h:63
@ FMT_VDPAU
Definition: mythframe.h:56
@ FMT_NONE
Definition: mythframe.h:21
@ FMT_NVDEC
Definition: mythframe.h:62
@ FMT_MMAL
Definition: mythframe.h:59
@ FMT_DXVA2
Definition: mythframe.h:58
@ FMT_MEDIACODEC
Definition: mythframe.h:60
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
const std::array< const std::string, 8 > formats
Definition: vbilut.cpp:189
static unsigned long long to_bitmap(const frame_queue_t &Queue, int Num)
static constexpr std::chrono::milliseconds TRY_LOCK_SPIN_WAIT
static constexpr size_t DBG_STR_ARR_SIZE
static int DebugNum(const MythVideoFrame *Frame)
std::map< const MythVideoFrame *, int > dbg_str
const std::array< const QString, DBG_STR_ARR_SIZE > dbg_str_arr
static constexpr uint16_t TRY_LOCK_SPINS_BEFORE_WARNING
static void DoDiscard(const std::vector< AVBufferRef * > &Discards)
int next_dbg_str
static void ReleaseDecoderResources(MythVideoFrame *Frame, std::vector< AVBufferRef * > &Discards)
Store AVBufferRef's for later disposal.
static constexpr uint16_t TRY_LOCK_SPINS
const std::array< const QString, DBG_STR_ARR_SIZE > dbg_str_arr_short
const QString & DebugString(const MythVideoFrame *Frame, bool Short)
BufferType
Definition: videobuffers.h:27
@ kVideoBuffer_decode
Definition: videobuffers.h:34
@ kVideoBuffer_finished
Definition: videobuffers.h:33
@ kVideoBuffer_limbo
Definition: videobuffers.h:29
@ kVideoBuffer_all
Definition: videobuffers.h:35
@ kVideoBuffer_displayed
Definition: videobuffers.h:32
@ kVideoBuffer_used
Definition: videobuffers.h:30
@ kVideoBuffer_avail
Definition: videobuffers.h:28
@ kVideoBuffer_pause
Definition: videobuffers.h:31