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
11
12#include "fourcc.h"
13#include "mythcodecid.h"
14#include "videobuffers.h"
15
16// FFmpeg
17extern "C" {
18#include "libavcodec/avcodec.h"
19}
20
21static constexpr uint16_t TRY_LOCK_SPINS { 2000 };
22static constexpr uint16_t TRY_LOCK_SPINS_BEFORE_WARNING { 9999 };
23static constexpr std::chrono::milliseconds TRY_LOCK_SPIN_WAIT { 1ms };
24
26
36static inline void ReleaseDecoderResources(MythVideoFrame *Frame, std::vector<AVBufferRef *> &Discards)
37{
39 {
40 auto* ref = reinterpret_cast<AVBufferRef*>(Frame->m_priv[0]);
41 if (ref != nullptr)
42 Discards.push_back(ref);
43 Frame->m_buffer = Frame->m_priv[0] = nullptr;
44
46 {
47 ref = reinterpret_cast<AVBufferRef*>(Frame->m_priv[1]);
48 if (ref != nullptr)
49 Discards.push_back(ref);
50 Frame->m_priv[1] = nullptr;
51 }
52 }
53}
54
55static inline void DoDiscard(const std::vector<AVBufferRef *> &Discards)
56{
57 for (auto * it : Discards)
58 av_buffer_unref(&it);
59}
60
134uint VideoBuffers::GetNumBuffers(int PixelFormat, int MaxReferenceFrames, bool Decoder /*=false*/)
135{
136 uint refs = static_cast<uint>(MaxReferenceFrames);
137 switch (PixelFormat)
138 {
139 case FMT_DXVA2: return 30;
140 // It is currrently unclear whether VTB just happy with a smaller buffer size
141 // or needs reference frames plus headroom - use the latter for now.
142 case FMT_VTB: return refs + 8;
143 // Max 16 ref frames, 12 headroom and allocate 2 extra in the VAAPI frames
144 // context for additional references held by the VPP deinterlacer (i.e.
145 // prevent buffer starvation in the decoder)
146 // This covers the 'worst case' samples.
147 case FMT_VAAPI: return Decoder ? (refs + 14) : (refs + 12);
148 case FMT_VDPAU: return refs + 12;
149 // Copyback of hardware frames. These decoders are buffering internally
150 // already - so no need for a large presentation buffer
151 case FMT_NONE: return 8; // NOLINT(bugprone-branch-clone)
152 // As for copyback, these decoders buffer internally
153 case FMT_NVDEC: return 8;
154 case FMT_MEDIACODEC: return 8;
155 case FMT_MMAL: return 8;
156 // the default number of output buffers in FFmpeg v4l2_m2m.h is 6
157 case FMT_DRMPRIME: return 6;
158 // Standard software decode
159 case FMT_YV12: return refs + 14;
160 default: break;
161 }
162 return 30;
163}
164
174void VideoBuffers::Init(uint NumDecode, uint NeedFree,
175 uint NeedPrebufferNormal, uint NeedPrebufferSmall)
176{
177 QMutexLocker locker(&m_globalLock);
178
179 Reset();
180
181 // make a big reservation, so that things that depend on
182 // pointer to VideoFrames work even after a few push_backs
183 m_buffers.reserve(std::max(NumDecode, 128U));
184 m_buffers.resize(NumDecode);
185 for (uint i = 0; i < NumDecode; i++)
186 m_vbufferMap[At(i)] = i;
187
188 m_needFreeFrames = NeedFree;
189 m_needPrebufferFrames = NeedPrebufferNormal;
190 m_needPrebufferFramesNormal = NeedPrebufferNormal;
191 m_needPrebufferFramesSmall = NeedPrebufferSmall;
192
193 for (uint i = 0; i < NumDecode; i++)
196}
197
199 MythCodecID CodecID)
200{
201 QMutexLocker locker(&m_globalLock);
202 for (auto & buffer : m_buffers)
203 SetDeinterlacingFlags(buffer, Single, Double, CodecID);
204}
205
214 MythDeintType Double, MythCodecID CodecID)
215{
216 static const MythDeintType kDriver = DEINT_ALL & ~(DEINT_CPU | DEINT_SHADER);
217 static const MythDeintType kShader = DEINT_ALL & ~(DEINT_CPU | DEINT_DRIVER);
218 static const MythDeintType kSoftware = DEINT_ALL & ~(DEINT_SHADER | DEINT_DRIVER);
219 Frame.m_deinterlaceSingle = Single;
220 Frame.m_deinterlaceDouble = Double;
221
222 if (codec_is_copyback(CodecID))
223 {
224 if (codec_is_vaapi_dec(CodecID) || codec_is_nvdec_dec(CodecID))
225 Frame.m_deinterlaceAllowed = kSoftware | kShader | kDriver;
226 else // VideoToolBox, MediaCodec and VDPAU copyback
227 Frame.m_deinterlaceAllowed = kSoftware | kShader;
228 }
229 else if (FMT_DRMPRIME == Frame.m_type)
230 { // NOLINT(bugprone-branch-clone)
231 Frame.m_deinterlaceAllowed = kShader; // No driver deint - if RGBA frames are returned, shaders will be disabled
232 }
233 else if (FMT_MMAL == Frame.m_type)
234 {
235 Frame.m_deinterlaceAllowed = kShader; // No driver deint yet (TODO) and YUV frames returned
236 }
237 else if (FMT_VTB == Frame.m_type)
238 {
239 Frame.m_deinterlaceAllowed = kShader; // No driver deint and YUV frames returned
240 }
241 else if (FMT_NVDEC == Frame.m_type)
242 {
243 Frame.m_deinterlaceAllowed = kShader | kDriver; // YUV frames and decoder deint
244 }
245 else if (FMT_VDPAU == Frame.m_type)
246 { // NOLINT(bugprone-branch-clone)
247 Frame.m_deinterlaceAllowed = kDriver; // No YUV frames for shaders
248 }
249 else if (FMT_VAAPI == Frame.m_type)
250 {
251 Frame.m_deinterlaceAllowed = kDriver; // DRM will allow shader if no VPP
252 }
253 else
254 {
255 Frame.m_deinterlaceAllowed = kSoftware | kShader;
256 }
257}
258
264{
265 QMutexLocker locker(&m_globalLock);
266 m_available.clear();
267 m_used.clear();
268 m_limbo.clear();
269 m_finished.clear();
270 m_decode.clear();
271 m_pause.clear();
272 m_displayed.clear();
273 m_vbufferMap.clear();
274}
275
281{
282 QMutexLocker locker(&m_globalLock);
284}
285
287{
288 QMutexLocker locker(&m_globalLock);
289 MythVideoFrame *frame = nullptr;
290
291 // Try to get a frame not being used by the decoder
292 for (size_t i = 0; i < m_available.size(); i++)
293 {
294 frame = m_available.dequeue();
295 if (m_decode.contains(frame))
296 m_available.enqueue(frame);
297 else
298 break;
299 }
300
301 while (frame && m_used.contains(frame))
302 {
303 LOG(VB_PLAYBACK, LOG_NOTICE,
304 QString("GetNextFreeFrame() served a busy frame %1. Dropping. %2")
305 .arg(DebugString(frame, true), GetStatus()));
306 frame = m_available.dequeue();
307 }
308
309 if (frame)
310 SafeEnqueue(EnqueueTo, frame);
311 return frame;
312}
313
319{
320 for (uint tries = 1; true; tries++)
321 {
323 if (frame)
324 return frame;
325
326 if (tries >= TRY_LOCK_SPINS)
327 {
328 LOG(VB_GENERAL, LOG_ERR, QString("GetNextFreeFrame: "
329 "available:%1 used:%2 limbo:%3 pause:%4 displayed:%5 decode:%6 finished:%7")
330 .arg(m_available.size()).arg(m_used.size()).arg(m_limbo.size())
331 .arg(m_pause.size()).arg(m_displayed.size()).arg(m_decode.size())
332 .arg(m_finished.size()));
333 LOG(VB_GENERAL, LOG_ERR,
334 QString("GetNextFreeFrame() unable to "
335 "lock frame %1 times. Discarding Frames.")
336 .arg(TRY_LOCK_SPINS));
337 DiscardFrames(true);
338 continue;
339 }
340
341 if (tries && !(tries % TRY_LOCK_SPINS_BEFORE_WARNING))
342 {
343 LOG(VB_PLAYBACK, LOG_NOTICE,
344 QString("GetNextFreeFrame() TryLock has "
345 "spun %1 times, this is a lot.").arg(tries));
346 }
347 std::this_thread::sleep_for(TRY_LOCK_SPIN_WAIT);
348 }
349
350 return nullptr;
351}
352
360{
361 QMutexLocker locker(&m_globalLock);
362
365 //non directrendering frames are ffmpeg handled
366 if (Frame->m_directRendering)
369}
370
377{
378 std::vector<AVBufferRef*> discards;
379
380 m_globalLock.lock();
381
384
385 // if decoder didn't release frame and the buffer is getting released by
386 // the decoder assume that the frame is lost and return to available
387 if (!m_decode.contains(Frame))
388 {
391 }
392
393 // remove from decode queue since the decoder is finished
394 while (m_decode.contains(Frame))
396
397 m_globalLock.unlock();
398
399 DoDiscard(discards);
400}
401
407{
408 QMutexLocker locker(&m_globalLock);
410}
411
417{
418 std::vector<AVBufferRef*> discards;
419
420 m_globalLock.lock();
421
424
426
427 // check if any finished frames are no longer used by decoder and return to available
429 for (auto & it : ula)
430 {
431 if (!m_decode.contains(it))
432 {
434 ReleaseDecoderResources(it, discards);
436 }
437 }
438
439 m_globalLock.unlock();
440
441 DoDiscard(discards);
442}
443
450{
451 std::vector<AVBufferRef*> discards;
452 m_globalLock.lock();
455 m_globalLock.unlock();
456 DoDiscard(discards);
457}
458
460{
461 std::vector<AVBufferRef*> discards;
462
463 m_globalLock.lock();
464 while (Size(kVideoBuffer_pause))
465 {
467 ReleaseDecoderResources(frame, discards);
469 }
470 m_globalLock.unlock();
471
472 DoDiscard(discards);
473}
474
481bool VideoBuffers::DiscardAndRecreate(MythCodecID CodecID, QSize VideoDim, int References)
482{
483 bool result = false;
484 std::vector<AVBufferRef*> refs;
485
486 m_globalLock.lock();
487 LOG(VB_PLAYBACK, LOG_INFO, QString("DiscardAndRecreate: %1").arg(GetStatus()));
488
489 // Remove pause frames (cutdown version of DiscardPauseFrames)
490 while (Size(kVideoBuffer_pause))
491 {
493 ReleaseDecoderResources(frame, refs);
495 }
496
497 // See DiscardFrames
499 ula.insert(ula.end(), m_limbo.begin(), m_limbo.end());
500 ula.insert(ula.end(), m_available.begin(), m_available.end());
501 ula.insert(ula.end(), m_finished.begin(), m_finished.end());
502
503 frame_queue_t discards(m_used);
504 discards.insert(discards.end(), m_limbo.begin(), m_limbo.end());
505 discards.insert(discards.end(), m_finished.begin(), m_finished.end());
506 for (auto & discard : discards)
507 {
508 ReleaseDecoderResources(discard, refs);
510 }
511
513 {
514 for (uint i = 0; i < Size(); i++)
515 {
516 if (!m_available.contains(At(i)) && !m_pause.contains(At(i)) &&
518 {
519 LOG(VB_GENERAL, LOG_INFO,
520 QString("VideoBuffers::DiscardFrames(): %1 (%2) not "
521 "in available, pause, or displayed %3")
522 .arg(DebugString(At(i), true)).arg(reinterpret_cast<long long>(At(i)))
523 .arg(GetStatus()));
524 ReleaseDecoderResources(At(i), refs);
526 }
527 }
528 }
529
530 for (auto & it : m_decode)
532 for (auto & it : m_decode)
534 m_decode.clear();
535
536 Reset();
537
538 // Recreate - see MythVideoOutputOpenGL::CreateBuffers
539 if (codec_is_copyback(CodecID))
540 {
542 result = CreateBuffers(FMT_YV12, VideoDim.width(), VideoDim.height(), m_renderFormats);
543 }
544 else if (codec_is_mediacodec(CodecID))
545 {
546 result = CreateBuffers(FMT_MEDIACODEC, m_renderFormats, VideoDim, 1, 2, 2);
547 }
548 else if (codec_is_vaapi(CodecID))
549 {
550 result = CreateBuffers(FMT_VAAPI, m_renderFormats, VideoDim, 2, 1, 4, References);
551 }
552 else if (codec_is_vtb(CodecID))
553 {
554 result = CreateBuffers(FMT_VTB, m_renderFormats, VideoDim, 1, 4, 2);
555 }
556 else if (codec_is_vdpau(CodecID))
557 {
558 result = CreateBuffers(FMT_VDPAU, m_renderFormats, VideoDim, 2, 1, 4, References);
559 }
560 else if (codec_is_nvdec(CodecID))
561 {
562 result = CreateBuffers(FMT_NVDEC, m_renderFormats, VideoDim, 2, 1, 4);
563 }
564 else if (codec_is_mmal(CodecID))
565 {
566 result = CreateBuffers(FMT_MMAL, m_renderFormats, VideoDim, 2, 1, 4);
567 }
568 else if (codec_is_v4l2(CodecID) || codec_is_drmprime(CodecID))
569 {
570 result = CreateBuffers(FMT_DRMPRIME, m_renderFormats, VideoDim, 2, 1, 4);
571 }
572 else
573 {
574 result = CreateBuffers(FMT_YV12, m_renderFormats, VideoDim, 1, 8, 4, References);
575 }
576
577 LOG(VB_PLAYBACK, LOG_INFO, QString("DiscardAndRecreate: %1").arg(GetStatus()));
578 m_globalLock.unlock();
579
580 // and finally release references now that the lock is released
581 DoDiscard(refs);
582 return result;
583}
584
586{
587 QMutexLocker locker(&m_globalLock);
588 frame_queue_t *queue = nullptr;
589 if (Type == kVideoBuffer_avail)
590 queue = &m_available;
591 else if (Type == kVideoBuffer_used)
592 queue = &m_used;
593 else if (Type == kVideoBuffer_displayed)
594 queue = &m_displayed;
595 else if (Type == kVideoBuffer_limbo)
596 queue = &m_limbo;
597 else if (Type == kVideoBuffer_pause)
598 queue = &m_pause;
599 else if (Type == kVideoBuffer_decode)
600 queue = &m_decode;
601 else if (Type == kVideoBuffer_finished)
602 queue = &m_finished;
603 return queue;
604}
605
607{
608 QMutexLocker locker(&m_globalLock);
609 const frame_queue_t *queue = nullptr;
610 if (Type == kVideoBuffer_avail)
611 queue = &m_available;
612 else if (Type == kVideoBuffer_used)
613 queue = &m_used;
614 else if (Type == kVideoBuffer_displayed)
615 queue = &m_displayed;
616 else if (Type == kVideoBuffer_limbo)
617 queue = &m_limbo;
618 else if (Type == kVideoBuffer_pause)
619 queue = &m_pause;
620 else if (Type == kVideoBuffer_decode)
621 queue = &m_decode;
622 else if (Type == kVideoBuffer_finished)
623 queue = &m_finished;
624 return queue;
625}
626
628{
629 return &m_buffers[FrameNum];
630}
631
633{
634 return &m_buffers[FrameNum];
635}
636
638{
639 QMutexLocker locker(&m_globalLock);
640 frame_queue_t *queue = Queue(Type);
641 if (!queue)
642 return nullptr;
643 return queue->dequeue();
644}
645
647{
648 QMutexLocker locker(&m_globalLock);
649 frame_queue_t *queue = Queue(Type);
650 if (!queue)
651 return nullptr;
652 if (!queue->empty())
653 return queue->head();
654 return nullptr;
655}
656
658{
659 QMutexLocker locker(&m_globalLock);
660 frame_queue_t *queue = Queue(Type);
661 if (!queue)
662 return nullptr;
663 if (!queue->empty())
664 return queue->tail();
665 return nullptr;
666}
667
669{
670 if (!Frame)
671 return;
672 frame_queue_t *queue = Queue(Type);
673 if (!queue)
674 return;
675 m_globalLock.lock();
676 queue->remove(Frame);
677 queue->enqueue(Frame);
678 if (Type == kVideoBuffer_pause)
679 Frame->m_pauseFrame = true;
680 m_globalLock.unlock();
681}
682
684{
685 if (!Frame)
686 return;
687
688 QMutexLocker locker(&m_globalLock);
691 if ((Type & kVideoBuffer_used) == kVideoBuffer_used)
703}
704
706{
707 if (!Frame)
708 return;
709 QMutexLocker locker(&m_globalLock);
711 Enqueue(Type, Frame);
712}
713
720{
721 m_globalLock.lock();
722 frame_queue_t *queue = Queue(Type);
723 if (queue)
724 return queue->begin();
725 return m_available.begin();
726}
727
729{
730 m_globalLock.unlock();
731}
732
734{
735 QMutexLocker locker(&m_globalLock);
736 frame_queue_t *queue = Queue(Type);
737 return (queue ? queue->end() : m_available.end());
738}
739
741{
742 QMutexLocker locker(&m_globalLock);
743 const frame_queue_t *queue = Queue(Type);
744 if (queue)
745 return queue->size();
746 return 0;
747}
748
750{
751 QMutexLocker locker(&m_globalLock);
752 const frame_queue_t *queue = Queue(Type);
753 if (queue)
754 return queue->contains(Frame);
755 return false;
756}
757
759{
760 return At(m_vpos);
761}
762
764{
765 return At(m_rpos);
766}
767
769{
770 return Size(kVideoBuffer_used);
771}
772
774{
775 return Size(kVideoBuffer_avail);
776}
777
779{
781}
782
784{
786}
787
789{
790 return At(m_vpos);
791}
792
794{
795 return At(m_rpos);
796}
797
799{
800 return m_buffers.size();
801}
802
807void VideoBuffers::DiscardFrames(bool NextFrameIsKeyFrame)
808{
809 std::vector<AVBufferRef*> refs;
810 m_globalLock.lock();
811 LOG(VB_PLAYBACK, LOG_INFO, QString("VideoBuffers::DiscardFrames(%1): %2")
812 .arg(NextFrameIsKeyFrame).arg(GetStatus()));
813
814 if (!NextFrameIsKeyFrame)
815 {
817 for (auto & it : ula)
818 {
819 ReleaseDecoderResources(it, refs);
821 }
822 LOG(VB_PLAYBACK, LOG_INFO,
823 QString("VideoBuffers::DiscardFrames(%1): %2 -- done")
824 .arg(NextFrameIsKeyFrame).arg(GetStatus()));
825 m_globalLock.unlock();
826 DoDiscard(refs);
827 return;
828 }
829
830 // Remove inheritence of all frames not in displayed or pause
832 ula.insert(ula.end(), m_limbo.begin(), m_limbo.end());
833 ula.insert(ula.end(), m_available.begin(), m_available.end());
834 ula.insert(ula.end(), m_finished.begin(), m_finished.end());
836
837 // Discard frames
838 frame_queue_t discards(m_used);
839 discards.insert(discards.end(), m_limbo.begin(), m_limbo.end());
840 discards.insert(discards.end(), m_finished.begin(), m_finished.end());
841 for (it = discards.begin(); it != discards.end(); ++it)
842 {
843 ReleaseDecoderResources(*it, refs);
845 }
846
847 // Verify that things are kosher
849 {
850 for (uint i = 0; i < Size(); i++)
851 {
852 if (!m_available.contains(At(i)) && !m_pause.contains(At(i)) &&
854 {
855 // This message is DEBUG because it does occur
856 // after Reset is called.
857 // That happens when failing over from OpenGL
858 // to another method, if QT painter is selected.
859 LOG(VB_GENERAL, LOG_DEBUG,
860 QString("VideoBuffers::DiscardFrames(): %1 (%2) not "
861 "in available, pause, or displayed %3")
862 .arg(DebugString(At(i), true)).arg((long long)At(i))
863 .arg(GetStatus()));
864 ReleaseDecoderResources(At(i), refs);
866 }
867 }
868 }
869
870 // Make sure frames used by decoder are last...
871 // This is for libmpeg2 which still uses the frames after a reset.
872 for (it = m_decode.begin(); it != m_decode.end(); ++it)
874 for (it = m_decode.begin(); it != m_decode.end(); ++it)
875 m_available.enqueue(*it);
876 m_decode.clear();
877
878 LOG(VB_PLAYBACK, LOG_INFO,
879 QString("VideoBuffers::DiscardFrames(%1): %2 -- done")
880 .arg(NextFrameIsKeyFrame).arg(GetStatus()));
881
882 m_globalLock.unlock();
883 DoDiscard(refs);
884}
885
895{
896 std::vector<AVBufferRef*> discards;
897 {
898 QMutexLocker locker(&m_globalLock);
899
900 for (uint i = 0; i < Size(); i++)
901 At(i)->m_timecode = 0ms;
902
903 for (uint i = 0; (i < Size()) && (m_used.count() > 1); i++)
904 {
905 MythVideoFrame *buffer = At(i);
906 if (m_used.contains(buffer) && !m_decode.contains(buffer))
907 {
908 m_used.remove(buffer);
909 m_available.enqueue(buffer);
910 ReleaseDecoderResources(buffer, discards);
911 }
912 }
913
914 if (m_used.count() > 0)
915 {
916 for (uint i = 0; i < Size(); i++)
917 {
918 MythVideoFrame *buffer = At(i);
919 if (m_used.contains(buffer) && !m_decode.contains(buffer))
920 {
921 m_used.remove(buffer);
922 m_available.enqueue(buffer);
923 ReleaseDecoderResources(buffer, discards);
924 m_vpos = m_vbufferMap[buffer];
925 m_rpos = m_vpos;
926 break;
927 }
928 }
929 }
930 else
931 {
932 m_vpos = m_rpos = 0;
933 }
934 }
935
936 DoDiscard(discards);
937}
938
939bool VideoBuffers::CreateBuffers(VideoFrameType Type, const VideoFrameTypes* RenderFormats, QSize Size,
940 uint NeedFree, uint NeedprebufferNormal,
941 uint NeedPrebufferSmall, int MaxReferenceFrames)
942{
943 m_renderFormats = RenderFormats;
944 Init(GetNumBuffers(Type, MaxReferenceFrames), NeedFree, NeedprebufferNormal, NeedPrebufferSmall);
945 return CreateBuffers(Type, Size.width(), Size.height(), m_renderFormats);
946}
947
948bool VideoBuffers::CreateBuffers(VideoFrameType Type, int Width, int Height, const VideoFrameTypes* RenderFormats)
949{
950 bool success = true;
951 m_renderFormats = RenderFormats;
952
953 // Hardware buffers with no allocated memory
955 {
956 for (uint i = 0; i < Size(); i++)
957 m_buffers[i].Init(Type, Width, Height, m_renderFormats);
958 LOG(VB_PLAYBACK, LOG_INFO, QString("Created %1 empty %2 (%3x%4) video buffers")
959 .arg(Size()).arg(MythVideoFrame::FormatDescription(Type)).arg(Width).arg(Height));
960 return true;
961 }
962
963 // Software buffers
964 for (uint i = 0; i < Size(); i++)
965 {
966 m_buffers[i].Init(Type, Width, Height, m_renderFormats);
967 m_buffers[i].ClearBufferToBlank();
968 success &= m_buffers[i].m_dummy || (m_buffers[i].m_buffer != nullptr);
969 }
970
971 // workaround null buffers for audio only (remove when these buffers aren't used)
972 if (!success && (Width < 1 || Height < 1))
973 success = true;
974
975 LOG(VB_PLAYBACK, LOG_INFO, QString("Created %1 %2 (%3x%4) video buffers")
976 .arg(Size()).arg(MythVideoFrame::FormatDescription(Type)).arg(Width).arg(Height));
977 return success;
978}
979
981 int Width, int Height)
982{
983 if (!Frame)
984 return false;
985
987 {
988 LOG(VB_GENERAL, LOG_ERR, "Cannot re-initialise a hardware buffer");
989 return false;
990 }
991
992 VideoFrameType old = Frame->m_type;
993 const auto * formats = Frame->m_renderFormats;
994 LOG(VB_PLAYBACK, LOG_INFO, QString("Reallocating frame %1 %2x%3->%4 %5x%6")
995 .arg(MythVideoFrame::FormatDescription(old)).arg(Frame->m_width).arg(Frame->m_height)
996 .arg(MythVideoFrame::FormatDescription(Type)).arg(Width).arg(Height));
997
998 MythDeintType singler = Frame->m_deinterlaceSingle;
999 MythDeintType doubler = Frame->m_deinterlaceDouble;
1000 Frame->Init(Type, Width, Height, formats);
1001 Frame->ClearBufferToBlank();
1002
1003 // retain deinterlacer settings and update restrictions based on new frame type
1004 SetDeinterlacingFlags(*Frame, singler, doubler, CodecID);
1005 return true;
1006}
1007
1008static unsigned long long to_bitmap(const frame_queue_t& Queue, int Num);
1009
1011{
1012 if (Num == 0)
1013 Num = Size();
1014
1015 QString str("");
1016 if (m_globalLock.tryLock())
1017 {
1018 int count = Size();
1019 unsigned long long a = to_bitmap(m_available, count);
1020 unsigned long long u = to_bitmap(m_used, count);
1021 unsigned long long d = to_bitmap(m_displayed, count);
1022 unsigned long long l = to_bitmap(m_limbo, count);
1023 unsigned long long p = to_bitmap(m_pause, count);
1024 unsigned long long f = to_bitmap(m_finished, count);
1025 unsigned long long x = to_bitmap(m_decode, count);
1026 for (uint i = 0; i < Num; i++)
1027 {
1028 unsigned long long mask = 1ULL << i;
1029 QString tmp("");
1030 if (a & mask)
1031 tmp += (x & mask) ? "a" : "A";
1032 if (u & mask)
1033 tmp += (x & mask) ? "u" : "U";
1034 if (d & mask)
1035 tmp += (x & mask) ? "d" : "D";
1036 if (l & mask)
1037 tmp += (x & mask) ? "l" : "L";
1038 if (p & mask)
1039 tmp += (x & mask) ? "p" : "P";
1040 if (f & mask)
1041 tmp += (x & mask) ? "f" : "F";
1042 if (0 == tmp.length())
1043 str += " ";
1044 else if (1 == tmp.length())
1045 str += tmp;
1046 else
1047 str += "(" + tmp + ")";
1048 }
1049 m_globalLock.unlock();
1050 }
1051 else
1052 {
1053 for (uint i = 0; i < Num; i++)
1054 str += " ";
1055 }
1056 return str;
1057}
1058
1059/*******************************
1060 ** Debugging functions below **
1061 *******************************/
1062
1063static constexpr size_t DBG_STR_ARR_SIZE { 40 };
1064const std::array<const QString,DBG_STR_ARR_SIZE> dbg_str_arr
1065{
1066 "A ", " B ", " C ", " D ",
1067 " E ", " F ", " G ", " H", // 8
1068 "a ", " b ", " c ", " d ",
1069 " e ", " f ", " g ", " h", // 16
1070 "0 ", " 1 ", " 2 ", " 3 ",
1071 " 4 ", " 5 ", " 6 ", " 7", // 24
1072 "I ", " J ", " K ", " L ",
1073 " M ", " N ", " O ", " P", // 32
1074 "i ", " j ", " k ", " l ",
1075 " m ", " n ", " o ", " p", // 40
1076};
1077const std::array<const QString,DBG_STR_ARR_SIZE> dbg_str_arr_short
1078{
1079 "A","B","C","D","E","F","G","H", // 8
1080 "a","b","c","d","e","f","g","h", // 16
1081 "0","1","2","3","4","5","6","7", // 24
1082 "I","J","K","L","M","N","O","P", // 32
1083 "i","j","k","l","m","n","o","p", // 40
1084};
1085
1086std::map<const MythVideoFrame *, int> dbg_str;
1087
1089{
1090 auto it = dbg_str.find(Frame);
1091 if (it == dbg_str.end())
1092 return dbg_str[Frame] = next_dbg_str++;
1093 return it->second;
1094}
1095
1096const QString& DebugString(const MythVideoFrame *Frame, bool Short)
1097{
1098 if (Short)
1101}
1102
1103const QString& DebugString(uint FrameNum, bool Short)
1104{
1105 return ((Short) ? dbg_str_arr_short : dbg_str_arr)[FrameNum];
1106}
1107
1108static unsigned long long to_bitmap(const frame_queue_t& Queue, int Num)
1109{
1110 unsigned long long bitmap = 0;
1111 for (auto *it : Queue)
1112 {
1113 int shift = DebugNum(it) % Num;
1114 bitmap |= 1ULL << shift;
1115 }
1116 return bitmap;
1117}
static const std::array< const std::string, 8 > formats
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: compat.h:60
static uint32_t * tmp
Definition: goom_core.cpp:28
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
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