vdr-plugin-softhddevice-drm-gles 1.5.9-20e15de
softhddevice.cpp
Go to the documentation of this file.
1
26#include <mutex>
27#include <variant>
28#include <libintl.h>
29
30extern "C" {
31#include <libavcodec/avcodec.h>
32}
33
34#include <vdr/dvbspu.h>
35#include <vdr/skins.h>
36
37#include "audio.h"
38#include "codec_audio.h"
39#include "config.h"
40#include "event.h"
41#include "grab.h"
42#include "jittertracker.h"
43#include "logger.h"
44#include "pes.h"
45#include "pipreceiver.h"
46#include "softhddevice.h"
47#include "softhdosd.h"
48#include "videorender.h"
49#include "videostream.h"
50
51/*****************************************************************************
52 * cSoftHdDevice class
53 ****************************************************************************/
54
63 : m_pSpuDecoder(new cDvbSpuDecoder()),
64 m_pConfig(config),
65 m_pipUseAlt(m_pConfig->ConfigPipUseAlt)
66{
67// LOGDEBUG("device: %s:", __FUNCTION__);
68}
69
76{
77 LOGDEBUG("device: %s:", __FUNCTION__);
78 delete m_pSpuDecoder;
79}
80
85{
86 LOGDEBUG("device: %s", __FUNCTION__);
88
89 return true;
90}
91
96{
97 LOGDEBUG("device: %s", __FUNCTION__);
99}
100
105{
106 LOGDEBUG("device: %s:", __FUNCTION__);
110}
111
118{
119 LOGDEBUG("device: %s: %d", __FUNCTION__, on);
120
121 if (on)
122 m_pOsdProvider = new cSoftOsdProvider(this); // no need to delete it, VDR does it
123
124 cDevice::MakePrimaryDevice(on);
125}
126
134{
135 LOGDEBUG("device: %s:", __FUNCTION__);
136 if (!IsPrimaryDevice())
137 return NULL;
138
139 return m_pSpuDecoder;
140}
141
146{
147 bool hasDecoder = !IsDetached();
148
149// LOGDEBUG("device: %s: %d", __FUNCTION__, hasDecoder);
150
151 return hasDecoder;
152}
153
158{
159 bool canReplay = !IsDetached();
160
161 LOGDEBUG("device: %s: %d", __FUNCTION__, canReplay);
162
163 return canReplay;
164}
165
177{
178 uint64_t startStateChange = cTimeMs::Now();
179 std::lock_guard<std::mutex> lock(m_mutex);
180
181 LOGDEBUG("device: received %s", EventToString(event));
182
183 if (m_state != DETACHED) {
186 }
187
188 bool needsResume = true;
189
190 auto invalid = [this, &event]() {
191 LOGWARNING("device: Invalid event '%s' in state '%s' received", EventToString(event), StateToString(m_state));
192 };
193
194 switch (m_state) {
195 case State::DETACHED:
196 std::visit(overload{
197 [&invalid](const PlayEvent&) { invalid(); },
198 [&invalid](const PauseEvent&) { invalid(); },
199 [&invalid](const StopEvent&) { invalid(); },
200 [&invalid](const TrickSpeedEvent&) { invalid(); },
201 [&invalid](const StillPictureEvent&) { invalid(); },
202 [](const DetachEvent&) { /* ignore */ },
203 [this](const AttachEvent&) {
204 if (!m_forceDetached)
205 SetState(STOP);
206 },
207 [&invalid](const BufferUnderrunEvent&) { invalid(); },
208 [&invalid](const BufferingThresholdReachedEvent&) { invalid(); },
209 [&invalid](const PipEvent&) { invalid(); },
210 [&invalid](const ScheduleResyncAtPtsMsEvent&) { invalid(); },
211 [&invalid](const ResyncEvent&) { invalid(); },
212 }, event);
213 needsResume = false;
214 break;
215 case State::STOP:
216 std::visit(overload{
217 [this](const PlayEvent&) {
222 },
223 [&invalid](const PauseEvent&) { invalid(); },
224 [&invalid](const StopEvent&) { invalid(); },
225 [&invalid](const TrickSpeedEvent&) { invalid(); },
226 [this](const StillPictureEvent& s) {
227 HandleStillPicture(s.data, s.size);
228 },
229 [this, &needsResume](const DetachEvent&) {
232 needsResume = false;
233 },
234 [&invalid](const AttachEvent&) { invalid(); },
235 [&invalid](const BufferUnderrunEvent&) { invalid(); },
236 [&invalid](const BufferingThresholdReachedEvent&) { invalid(); },
237 [this](const PipEvent& p) {
238 m_pPipHandler->HandleEvent(p.state);
239 },
240 [&invalid](const ScheduleResyncAtPtsMsEvent&) { invalid(); },
241 [&invalid](const ResyncEvent&) { invalid(); },
242 }, event);
243 break;
244 case State::BUFFERING:
245 std::visit(overload{
246 [this](const PlayEvent&) {
247 // ignore
248 },
249 [this](const PauseEvent&) {
250 // ignore
251 },
252 [this](const StopEvent&) {
253 SetState(STOP);
254 },
255 [this](const TrickSpeedEvent& t) {
256 // abort buffering and proceed with trick speed immediately, because trick speed shall be as fast and as demanded as possible
257 SetState(PLAY);
258 m_pRender->SetTrickSpeed(t.speed, t.active, t.forward);
260 },
261 [this](const StillPictureEvent& s) {
262 HandleStillPicture(s.data, s.size);
263 },
264 [this, &needsResume](const DetachEvent&) {
266 needsResume = false;
267 },
268 [&invalid](const AttachEvent&) { invalid(); },
269 [&invalid](const BufferUnderrunEvent&) { invalid(); },
270 [this](const BufferingThresholdReachedEvent&) {
271 bool receivedAudio = m_pAudio->HasPts();
272 bool receivedVideo = m_pVideoStream->HasInputPts();
273
274 if (receivedAudio && receivedVideo) {
276 int64_t firstAudioPtsMs = GetFirstAudioPtsMsToPlay();
277 int64_t firstVideoPtsMs = GetFirstVideoPtsMsToPlay();
278 // store the first PTSes beforehand, because dropping samples/frames will change the output of GetFirst*PtsMsToPlay()
279 m_pAudio->DropSamplesOlderThanPtsMs(firstAudioPtsMs);
280 m_pRender->SchedulePlaybackStartAtPtsMs(firstVideoPtsMs);
281 } else if (receivedAudio) {
282 LOGDEBUG("device: audio only detected");
285 } else if (receivedVideo) {
286 LOGDEBUG("device: video only detected");
289 } else
290 LOGFATAL("device: buffering threshold reached and no a/v available. This is a bug.");
291
292 SetState(PLAY);
293 },
294 [this](const PipEvent& p) {
295 m_pPipHandler->HandleEvent(p.state);
296 },
297 [this](const ScheduleResyncAtPtsMsEvent& s) {
298 SetState(PLAY);
300 },
301 [&invalid](const ResyncEvent&) { invalid(); },
302 }, event);
303 break;
304 case State::PLAY:
305 std::visit(overload{
306 [this](const PlayEvent&) {
307 // resume from pause
308 int audioBehindVideoByMs;
309 switch (m_playbackMode) {
310 case AUDIO_ONLY:
311 m_pAudio->SetPaused(false);
312 break;
313 case AUDIO_AND_VIDEO:
315 if (audioBehindVideoByMs > 0) {
316 m_pAudio->DropSamplesOlderThanPtsMs(m_pAudio->GetOutputPtsMs() + audioBehindVideoByMs);
317 m_pAudio->SetPaused(false);
318 } else
320
321 // fallthrough
322 case VIDEO_ONLY:
325 break;
326 case NONE:
327 LOGFATAL("device: play event in PLAY state with NONE playback mode. This is a bug.");
328 break;
329 }
330 },
331 [this](const PauseEvent&) {
333 m_pAudio->SetPaused(true);
334 },
335 [this](const StopEvent&) {
336 SetState(STOP);
337 },
338 [this](const TrickSpeedEvent& t) {
339 m_pRender->SetTrickSpeed(t.speed, t.active, t.forward);
341 },
342 [this](const StillPictureEvent& s) {
343 HandleStillPicture(s.data, s.size);
344 },
345 [this, &needsResume](const DetachEvent&) {
348 needsResume = false;
349 },
350 [&invalid](const AttachEvent&) { invalid(); },
351 [this](const BufferUnderrunEvent&) {
353 },
354 [&invalid](const BufferingThresholdReachedEvent&) {
355 // ignore
356 },
357 [this](const PipEvent& p) {
358 m_pPipHandler->HandleEvent(p.state);
359 },
360 [this](const ScheduleResyncAtPtsMsEvent& s) {
362 },
363 [this](const ResyncEvent&) {
365 },
366 }, event);
367 break;
369 std::visit(overload{
370 [this](const PlayEvent&) {
371 SetState(PLAY);
372 },
373 [this](const PauseEvent&) {
375 m_pAudio->SetPaused(true);
376 },
377 [this](const StopEvent&) {
378 SetState(STOP);
379 },
380 [this](const TrickSpeedEvent& t) {
381 // resume from pause, or change trick speed direction/speed
382 m_pRender->SetTrickSpeed(t.speed, t.active, t.forward);
384 },
385 [this](const StillPictureEvent& s) {
386 HandleStillPicture(s.data, s.size);
387 },
388 [this, &needsResume](const DetachEvent&) {
391 needsResume = false;
392 },
393 [&invalid](const AttachEvent&) { invalid(); },
394 [this](const BufferUnderrunEvent&) {
395 // ignore during trick speed. Fast forward/reverse as fast and as demanded as possible
396 },
397 [&invalid](const BufferingThresholdReachedEvent&) { invalid(); },
398 [this](const PipEvent& p) {
399 m_pPipHandler->HandleEvent(p.state);
400 },
401 [&invalid](const ScheduleResyncAtPtsMsEvent&) { invalid(); },
402 [&invalid](const ResyncEvent&) { invalid(); },
403 }, event);
404 break;
405 }
406
407 if (needsResume) {
410 }
411
412 uint64_t stopStateChange = cTimeMs::Now();
413 LOGDEBUG("device: state change done in %d ms", (int)(stopStateChange - startStateChange));
414}
415
425 switch (state) {
426 case BUFFERING:
427 // nothing
428 break;
429 case PLAY:
431 m_pAudio->SetPaused(false);
432
433 if (m_playbackMode != AUDIO_ONLY) {
437 }
438 break;
439 case TRICK_SPEED:
440 // The filter thread needs to be restarted for interlaced streams to be rendered without deinterlacer in trick speed mode. It is started lazily.
445 break;
446 case STOP:
447 ClearAudio();
448
451 m_pRender->Reset();
453
462
463 break;
464 case DETACHED:
465 delete m_pPipHandler;
466 m_pPipHandler = nullptr;
467
468 // resume the previously stopped threads
471
472 // now do the detach
474 delete m_pPipStream;
475
476 m_pRender->Exit(); // render must be stopped before videostream!
478 m_pAudio->Exit(); // audio must be stopped after renderer!
479#ifdef USE_GLES
480 m_pOsdProvider->StopOpenGlThread();
481#endif
482 delete m_pAudioDecoder; // includes a Close()
483 delete m_pVideoStream;
484 delete m_pGrab;
485 delete m_pRender;
486 delete m_pAudio;
487
488 break;
489 }
490}
491
501 switch (state) {
502 case PLAY:
505 m_pAudio->SetPaused(true);
506 break;
507 case BUFFERING:
509 break;
510 case TRICK_SPEED:
511 // The filter thread needs to be restarted for interlaced streams to be rendered with deinterlacer again. It is started lazily.
513 m_pRender->SetTrickSpeed(0, false, false);
520 break;
521 case STOP:
522 m_receivedAudio = false;
523 m_receivedVideo = false;
524 break;
525 case DETACHED:
526 m_pAudio = new cSoftHdAudio(this);
527 m_pRender = new cVideoRender(this);
531 m_pRender->Init(); // starts display thread
532 m_pVideoStream->StartDecoder(); // starts decoding thread
534 m_pPipStream->StartDecoder(); // starts decoding thread
535 m_pPipHandler = new cPipHandler(this);
536 // Audio is init lazily (includes starting thread)
537
538 break;
539 }
540}
541
548{
549 if (m_state != newState) {
550 LOGDEBUG("device: Preparing to leave state %s", StateToString(m_state));
552 LOGDEBUG("device: Changing state %s -> %s", StateToString(m_state), StateToString(newState));
553 m_state = newState;
555 LOGDEBUG("device: State changed to %s", StateToString(m_state));
556 }
557}
558
564bool cSoftHdDevice::SetPlayMode(ePlayMode play_mode)
565{
566 LOGDEBUG("device: %s: %d", __FUNCTION__, play_mode);
567
568 switch (play_mode) {
569 case pmNone:
571 break;
572 case pmAudioVideo:
573 case pmAudioOnly:
574 case pmAudioOnlyBlack:
575 case pmVideoOnly:
577 break;
578 default:
579 LOGERROR("device: %s: playmode not supported %d", play_mode);
580 return 0;
581 break;
582 }
583
584 return 1;
585}
586
592{
593 if (IsDetached())
594 return AV_NOPTS_VALUE;
595
596 switch (m_playbackMode) {
597 case NONE:
598 return AV_NOPTS_VALUE;
599 case AUDIO_AND_VIDEO:
600 case VIDEO_ONLY:
601 return m_pRender->GetVideoClock();
602 case AUDIO_ONLY:
604 }
605
606 abort();
607}
608
621void cSoftHdDevice::TrickSpeed(int speed, bool forward)
622{
623 LOGDEBUG("device: %s: %d %s", __FUNCTION__, speed, forward ? "forward" : "backward");
624
625 // This normalizes the VDR frame displaying count into a factor, representing how fast/slow the playback shall be.
626 // For example, a factor of 2.0 means twice as fast as normal, a factor of 0.5 means half as fast as normal (slow-mo).
627 // This is necessary because VDR sends only I-frames during trickspeed, but the distance between I-frames depends on the encoding parameters.
628 // Therefore, we send a normalized factor for the further components, which then calculate the necessary frame displaying count by considering the distance between I-frames.
629
630 double normalizedSpeed = 1;
631 static constexpr double MAX_SPEED = 3;
632
633 // these are arbitrary values, which feel just right
634 static constexpr double FAST_TRICKSPEED_FACTOR = 5; // the higher the factor, the faster the fast forward/reverse
635 static constexpr double SLOW_FORWARD_FACTOR = 2; // the higher the factor, the slower the slow-mo
636
637 // Fastest speed in reverse slow-mo is the original speed. Slower speeds are too slow, because of the already low frame rate.
638 static constexpr double SLOW_REVERSE_FACTOR = 1;
639
640 // speed of the trickspeed (VDR's magic frame displaying count)
641 switch (speed) {
642 case 6:
643 case 8:
644 case 63:
645 normalizedSpeed = 1; // slowest (both, in fast trickspeed and slow-mo)
646 break;
647 case 3:
648 case 4:
649 case 48:
650 normalizedSpeed = 2;
651 break;
652 case 1:
653 case 2:
654 case 24:
655 normalizedSpeed = 3; // fastest (both, in fast trickspeed and slow-mo)
656 break;
657 }
658
659 // figure out if VDR demands slow-mo or fast trickspeed
660 double tmp;
661 switch (speed) {
662 case 8:
663 case 4:
664 case 2:
665 case 63:
666 case 48:
667 case 24:
668 // slow-mo
669 tmp = (MAX_SPEED + 1) - normalizedSpeed;
670
671 if (forward)
672 tmp *= SLOW_FORWARD_FACTOR;
673 else
674 tmp *= SLOW_REVERSE_FACTOR;
675
676 normalizedSpeed = 1 / tmp;
677 break;
678 default:
679 // fast trickspeed
680 normalizedSpeed *= FAST_TRICKSPEED_FACTOR;
681 break;
682 }
683
684 OnEventReceived(TrickSpeedEvent{normalizedSpeed, speed != 0, forward});
685}
686
726
734{
735 cDevice::Play();
736
738}
739
744{
745 LOGDEBUG("device: %s:", __FUNCTION__);
746 cDevice::Freeze();
747
749}
750
757void cSoftHdDevice::StillPicture(const uchar *data, int size)
758{
759 LOGDEBUG("device: %s: %s %p %d", __FUNCTION__, data[0] == 0x47 ? "ts" : "pes", data, size);
760
761 if (data[0] == 0x47) { // ts sync byte
762 cDevice::StillPicture(data, size);
763 return;
764 }
765
767}
768
776void cSoftHdDevice::HandleStillPicture(const uchar *data, int size)
777{
780
781 // skip BufferUnderrunEvent{VIDEO} in renderer
783
784 const uchar *currentPacketStart = data;
785 while (currentPacketStart < data + size) {
786 cPesVideo pesPacket((const uint8_t*)currentPacketStart, size - (currentPacketStart - data));
787
788 if (pesPacket.IsValid())
789 PlayVideoInternal(m_pVideoStream, &m_videoReassemblyBuffer, currentPacketStart, pesPacket.GetPacketLength(), false);
790 else {
791 LOGWARNING("device: %s: invalid PES packet", __FUNCTION__);
792 break;
793 }
794
795 currentPacketStart += pesPacket.GetPacketLength();
796 }
797
799 m_pVideoStream->ResetInputPts(); // stillpicture shouldn't trigger having video data
801}
802
815bool cSoftHdDevice::Poll(__attribute__ ((unused)) cPoller & poller, int timeoutMs)
816{
817// LOGDEBUG("device: %s: timeout %d", __FUNCTION__, timeout_ms);
818 if (IsDetached())
819 return true;
820
822 return true;
823
824 usleep(timeoutMs * 1000);
825
826 return false;
827}
828
834bool cSoftHdDevice::Flush(int timeout)
835{
836 if (IsDetached())
837 return true;
838
839 LOGDEBUG("device: %s: timeout %d ms", __FUNCTION__, timeout);
841 if (timeout) { // let display thread work
842 usleep(timeout * 1000);
843 }
845 }
846
847 return true;
848}
849
856void cSoftHdDevice::SetVideoDisplayFormat(eVideoDisplayFormat videoDisplayFormat)
857{
858 LOGDEBUG("device: %s: %d", __FUNCTION__, videoDisplayFormat);
859
860 cDevice::SetVideoDisplayFormat(videoDisplayFormat);
861}
862
873void cSoftHdDevice::SetVideoFormat(bool videoFormat16_9)
874{
875 LOGDEBUG("device: %s: %d", __FUNCTION__, videoFormat16_9);
876
877 // FIXME: 4:3 / 16:9 video format not supported.
878 SetVideoDisplayFormat(eVideoDisplayFormat(Setup.VideoDisplayFormat));
879}
880
889void cSoftHdDevice::GetVideoSize(int &width, int &height, double &aspectRatio)
890{
891// LOGDEBUG("device: %s: %d x %d @ %f", __FUNCTION__, *width, *height, *aspectRatio);
892
893 if (IsDetached()) { // return default values according to vdr docs
894 width = 0;
895 height = 0;
896 aspectRatio = 1.0;
897 return;
898 }
899
900 m_pVideoStream->GetVideoSize(&width, &height, &aspectRatio);
901}
902
908void cSoftHdDevice::GetOsdSize(int &width, int &height, double &aspectRatio)
909{
910 if (IsDetached()) { // hardcode to 1920x1080 in detached state
911 width = 1920;
912 height = 1080;
913 aspectRatio = (double)width / (double)height;
914 return;
915 }
916
917 std::lock_guard<std::mutex> lock(m_sizeMutex);
918 width = m_screenWidth;
919 height = m_screenHeight;
920 aspectRatio = (double)width / (double)height;
921}
922
930void cSoftHdDevice::SetScreenSize(int width, int height, double refreshRateHz)
931{
932 std::lock_guard<std::mutex> lock(m_sizeMutex);
933 m_screenWidth = width;
934 m_screenHeight = height;
935 m_screenRefreshRateHz = refreshRateHz;
936}
937
944static void PrintStreamData(const uchar *payload)
945{
946 LOGDEBUG2(L_CODEC, "Stream: %02X%02X%02X | %02X | %02X%02X | %02X%02X%02X | %02X%02X%02X%02X %02X%02X%02X%02X %02X%02X%02X%02X %02X%02X%02X%02X",
947 payload[0],
948 payload[1],
949 payload[2],
950 payload[3],
951 payload[4],
952 payload[5],
953 payload[6],
954 payload[7],
955 payload[8],
956 payload[9],
957 payload[10],
958 payload[11],
959 payload[12],
960 payload[13],
961 payload[14],
962 payload[15],
963 payload[16],
964 payload[17],
965 payload[18],
966 payload[19],
967 payload[20],
968 payload[21],
969 payload[22],
970 payload[23],
971 payload[24]
972 );
973}
974
986int cSoftHdDevice::PlayAudio(const uchar *data, int size, uchar id)
987{
988// LOGDEBUG("device: %s: %p %p %d %d", __FUNCTION__, this, data, size, id);
989 if (IsDetached())
990 return size;
991
992 m_receivedAudio = true;
993
994 if (m_pAudio->IsBufferFull())
995 return 0;
996
997 cPesAudio pesPacket((const uint8_t*)data, size);
998
999 if (!pesPacket.IsValid()) {
1001
1002 return size;
1003 }
1004
1005 if (Transferring()) { // compensation is only necessary with live streams
1008 }
1009
1010 if (m_audioChannelID != id) {
1011 m_audioChannelID = id;
1014 LOGDEBUG("device: %s: new channel id 0x%02X", __FUNCTION__, m_audioChannelID);
1015 }
1016
1017 m_audioReassemblyBuffer.Push(pesPacket.GetPayload(), pesPacket.GetPayloadSize(), pesPacket.GetPts());
1018
1021
1022 AVPacket *avpkt;
1023 do {
1025
1026 if (avpkt) {
1027 if (m_pAudioDecoder->GetCodecId() == AV_CODEC_ID_NONE && m_audioReassemblyBuffer.GetCodec() != AV_CODEC_ID_NONE) {
1028 // The playback has just started
1031 }
1032
1033 m_pAudioDecoder->Decode(avpkt);
1034 AVPacket *copy = avpkt;
1035 av_packet_free(&copy);
1036 }
1037 } while (avpkt != nullptr);
1038
1039 return size;
1040}
1041
1042void cSoftHdDevice::SetAudioTrackDevice( __attribute__ ((unused)) eTrackType type)
1043{
1044 //LOGDEBUG("device: %s:", __FUNCTION__);
1045}
1046
1047void cSoftHdDevice::SetDigitalAudioDevice( __attribute__ ((unused)) bool on)
1048{
1049 //LOGDEBUG("device: %s: %s", __FUNCTION__, on ? "true" : "false");
1050}
1051
1052void cSoftHdDevice::SetAudioChannelDevice( __attribute__ ((unused))
1053 int audio_channel)
1054{
1055 //LOGDEBUG("device: %s: %d", __FUNCTION__, audio_channel);
1056}
1057
1059{
1060 //LOGDEBUG("device: %s:", __FUNCTION__);
1061 return 0;
1062}
1063
1070{
1071 if (IsDetached())
1072 return;
1073
1074 LOGDEBUG("device: %s: %d", __FUNCTION__, volume);
1075 m_pAudio->SetVolume((volume * 1000) / 255);
1076}
1077
1090int cSoftHdDevice::PlayVideo(const uchar *data, int size)
1091{
1092// LOGDEBUG("device: %s: %p %d", __FUNCTION__, data, size);
1093 if (IsDetached())
1094 return size;
1095
1096 m_receivedVideo = true;
1097
1098 return PlayVideoInternal(m_pVideoStream, &m_videoReassemblyBuffer, data, size, Transferring());
1099}
1100
1111int cSoftHdDevice::PlayPipVideo(const uchar *data, int size)
1112{
1113// LOGDEBUG("device: %s: %p %d", __FUNCTION__, data, size);
1114
1115 // This is a bit hacky:
1116 // Because we do no sync with the pip stream, we simply drop data
1117 // if the input buffer is full -> this prevents us from having a buffer overflow
1118 // caused by the pip stream.
1120 return size;
1121
1122 return PlayVideoInternal(m_pPipStream, &m_pipReassemblyBuffer, data, size, false);
1123}
1124
1134int cSoftHdDevice::PlayVideoInternal(cVideoStream *stream, cReassemblyBufferVideo *buffer, const uchar *data, int size, bool trackJitter)
1135{
1136 // LOGDEBUG("device: %s: %p %d", __FUNCTION__, data, size);
1137
1138 if (stream->IsInputBufferFull())
1139 return 0;
1140
1141 cPesVideo pesPacket((const uint8_t*)data, size);
1142
1143 if (!pesPacket.IsValid()) {
1144 buffer->Reset();
1145
1146 return size;
1147 }
1148
1149 if (trackJitter)
1151
1152 if (stream->GetCodecId() == AV_CODEC_ID_NONE) {
1153 // The playback has just started
1154 if (!pesPacket.HasPts() || !buffer->ParseCodecHeader(pesPacket.GetPayload(), pesPacket.GetPayloadSize())) {
1155 // received the middle of fragmented data, wait for the next PES packets with the start of a new frame
1156 return size;
1157 }
1158
1159 PrintStreamData(data);
1160 buffer->Push(pesPacket.GetPayload(), pesPacket.GetPayloadSize(), pesPacket.GetPts());
1161
1162 stream->Open(buffer->GetCodec());
1163 } else {
1164 int payloadOffset = 0;
1165 if (pesPacket.HasPts() && !buffer->IsEmpty()) {
1166 // received the first fragment of a new frame, finish the current reassembly buffer into an AVPacket
1167 stream->PushAvPacket(buffer->PopAvPacket());
1168
1169 // populate the cleared buffer with the next frame
1170 if (buffer->HasLeadingZero(pesPacket.GetPayload(), pesPacket.GetPayloadSize()))
1171 payloadOffset = 1; // H.264/HEVC streams may have a leading zero byte before the start code
1172 }
1173
1174 buffer->Push(pesPacket.GetPayload() + payloadOffset, pesPacket.GetPayloadSize() - payloadOffset, pesPacket.GetPts());
1175 }
1176
1177 return size;
1178}
1179
1189{
1190 if (m_state != BUFFERING)
1191 return false;
1192
1193 bool audioHasPts = m_pAudio->HasPts();
1194 bool videoHasInputPts = m_pVideoStream->HasInputPts();
1195 bool videoHasOutputPts = m_pRender->GetOutputPtsMs() != AV_NOPTS_VALUE;
1196
1197 // Assume audio only or video only if no PES fragment from the other stream has been received, while the buffering threshold of the other stream is reached.
1198 // Check for buffer fill level only if at least one PES packet was reassembled and pushed to the respective decoder.
1199 bool audioOnly = audioHasPts && !videoHasInputPts && m_receivedAudio && !m_receivedVideo;
1200 bool videoOnly = !audioHasPts && videoHasInputPts && !m_receivedAudio && m_receivedVideo;
1201
1203 (videoOnly && videoHasOutputPts && m_pVideoStream->GetInputPtsMs() - m_pRender->GetOutputPtsMs() > GetBufferFillLevelThresholdMs())) {
1204 LOGDEBUG("device: %s: Detected audio or video only", __FUNCTION__);
1205 return true;
1206 } else if (!audioHasPts || !videoHasInputPts || !videoHasOutputPts)
1207 return false; // Either no video or no audio received, yet. Or, video didn't make it to the output buffer, yet.
1208
1209 int64_t syncedAudioBufferFillLevelMs = m_pAudio->GetInputPtsMs() - GetFirstAudioPtsMsToPlay();
1210 int64_t syncedVideoBufferFillLevelMs = m_pVideoStream->GetInputPtsMs() - GetFirstVideoPtsMsToPlay();
1211
1212 bool reached = m_pRender->IsOutputBufferFull() && // video decoder output buffer (audio hardware output buffer is negligible)
1213 syncedVideoBufferFillLevelMs > GetBufferFillLevelThresholdMs() && // video decoder input buffer
1214 syncedAudioBufferFillLevelMs > GetBufferFillLevelThresholdMs(); // audio decoder output buffer
1215
1216 if (reached) {
1217 LOGDEBUG2(L_AV_SYNC, "First received PTS: %s (audio), %s (video) buffer fill levels: %ldms (audio) %ldms (video)",
1220 syncedAudioBufferFillLevelMs,
1221 syncedVideoBufferFillLevelMs);
1222 }
1223
1224 return reached;
1225}
1226
1240{
1241 int64_t ret = std::max(m_pRender->GetOutputPtsMs(), m_pAudio->GetOutputPtsMs());
1242
1245
1246 return ret;
1247}
1248
1253{
1254 int64_t ret = std::max(m_pRender->GetOutputPtsMs(), m_pAudio->GetOutputPtsMs());
1255
1258
1259 return ret;
1260}
1261
1271uchar *cSoftHdDevice::GrabImage(int &size, bool jpeg, int quality, int width, int height)
1272{
1273 if (IsDetached())
1274 return NULL;
1275
1276 if (m_pGrab->Active()) {
1277 LOGWARNING("device: %s: wait for the last grab to be finished - skip!", __FUNCTION__);
1278 return NULL;
1279 }
1280
1281 LOGDEBUG2(L_GRAB, "device: %s: %d, %d, %d, %dx%d", __FUNCTION__, size, jpeg, quality, width, height);
1282
1283 int screenWidth = 0;
1284 int screenHeight = 0;
1285 double aspectRatio = 0.0f;
1286 GetOsdSize(screenWidth, screenHeight, aspectRatio);
1287
1288 if (!m_pGrab->Start(jpeg, quality, width, height, screenWidth, screenHeight))
1289 return NULL;
1290
1291 size = m_pGrab->Size();
1292
1293 return m_pGrab->Image();
1294}
1295
1303cRect cSoftHdDevice::CanScaleVideo(const cRect & rect, __attribute__ ((unused)) int alignment)
1304{
1305 return rect;
1306}
1307
1316void cSoftHdDevice::ScaleVideo(const cRect & rect)
1317{
1318 if (IsDetached())
1319 return;
1320
1321 LOGDEBUG2(L_OSD, "device: %s: %dx%d%+d%+d",
1322 __FUNCTION__, rect.Width(), rect.Height(), rect.X(), rect.Y());
1323
1324 if (m_pRender)
1326}
1327
1332{
1333 return " -a device\taudio device (fe. alsa: hw:0,0)\n"
1334 " -p device\taudio device for pass-through (hw:0,1)\n"
1335 " -c channel\taudio mixer channel name (fe. PCM)\n"
1336 " -d resolution\tdisplay resolution (fe. 1920x1080@50)\n"
1337 " -D start in detached state\n"
1338 " -w workaround\tenable/disable workarounds\n"
1339#ifdef USE_GLES
1340 "\tdisable-ogl-osd disable openGL osd\n"
1341#endif
1342 "\tdisable-pip disable picture-in-picture\n"
1343 "\n";
1344}
1345
1352int cSoftHdDevice::ProcessArgs(int argc, char *argv[])
1353{
1354 //
1355 // Parse arguments.
1356 //
1357
1358 for (;;) {
1359#ifdef USE_GLES
1360 switch (getopt(argc, argv, "-a:c:p:d:Dw:")) {
1361#else
1362 switch (getopt(argc, argv, "-a:c:p:d:D")) {
1363#endif
1364 case 'a': // audio device for pcm
1366 continue;
1367 case 'c': // channel of audio mixer
1369 continue;
1370 case 'p': // pass-through audio device
1372 continue;
1373 case 'd': // set display output
1375 continue;
1376 case 'D': // start plugin in detached state
1377 m_forceDetached = true;
1378 continue;
1379 case 'w': // workarounds
1380 if (!strcasecmp("disable-pip", optarg)) {
1381 m_disablePip = true;
1382#ifdef USE_GLES
1383 } else if (!strcasecmp("disable-ogl-osd", optarg)) {
1384 SetDisableOglOsd();
1385#endif
1386 } else {
1387 fprintf(stderr, gettext("Workaround '%s' unsupported\n"),
1388 optarg);
1389 return 0;
1390 }
1391 continue;
1392 case EOF:
1393 break;
1394 case '-':
1395 fprintf(stderr, gettext("We need no long options\n"));
1396 return 0;
1397 case ':':
1398 fprintf(stderr, gettext("Missing argument for option '%c'\n"), optopt);
1399 return 0;
1400 default:
1401 fprintf(stderr, gettext("Unknown option '%c'\n"), optopt);
1402 return 0;
1403 }
1404 break;
1405 }
1406
1407 while (optind < argc) {
1408 fprintf(stderr, gettext("Unhandled argument '%s'\n"), argv[optind++]);
1409 }
1410
1411 return 1;
1412}
1413
1418{
1419 if (IsDetached())
1420 return;
1421
1423}
1424
1437void cSoftHdDevice::OsdDrawARGB(int xi, int yi, int height, int width, int pitch,
1438 const uint8_t * argb, int x, int y)
1439{
1440 if (IsDetached())
1441 return;
1442
1443 m_pRender->OsdDrawARGB(xi, yi, height, width, pitch, argb, x, y);
1444}
1445
1446#ifdef USE_GLES
1450int cSoftHdDevice::MaxSizeGPUImageCache(void)
1451{
1452 return m_pConfig->ConfigMaxSizeGPUImageCache;
1453};
1454
1458int cSoftHdDevice::OglOsdIsDisabled(void)
1459{
1460 return m_pConfig->ConfigDisableOglOsd;
1461};
1462
1466void cSoftHdDevice::SetDisableOglOsd(void)
1467{
1468 m_pConfig->ConfigDisableOglOsd = 1;
1469 if (m_pRender)
1470 m_pRender->DisableOglOsd();
1471}
1472
1476void cSoftHdDevice::SetEnableOglOsd(void)
1477{
1478 m_pConfig->ConfigDisableOglOsd = 0;
1479 if (m_pRender)
1480 m_pRender->EnableOglOsd();
1481}
1482
1483#endif
1484
1493
1502
1511
1526
1531{
1532 m_pAudio->SetPassthrough(mask);
1533 if (m_pAudioDecoder)
1535}
1536
1541{
1542 LOGDEBUG("%s:", __FUNCTION__);
1543 m_audioChannelID = -1;
1544}
1545
1553void cSoftHdDevice::GetStats(int *duped, int *dropped, int *counter)
1554{
1555 *duped = 0;
1556 *dropped = 0;
1557 *counter = 0;
1558 if (m_pRender) {
1559 m_pRender->GetStats(duped, dropped, counter);
1560 }
1561}
1562
1563/*****************************************************************************
1564 * media player functions
1565 ****************************************************************************/
1566
1574void cSoftHdDevice::SetAudioCodec(enum AVCodecID codecId, AVCodecParameters * par, AVRational timebase)
1575{
1576 m_pAudioDecoder->Open(codecId, par, timebase);
1577}
1578
1586void cSoftHdDevice::SetVideoCodec(enum AVCodecID codecId, AVCodecParameters * par, AVRational timebase)
1587{
1588 m_pVideoStream->Open(codecId, par, timebase);
1589}
1590
1600{
1601 m_pAudio->LazyInit();
1602
1603 if (m_pAudio->IsBufferFull()) {
1604// LOGERROR("device: %s: m_pAudio->GetFreeBytes() < AUDIO_MIN_BUFFER_FREE!", __FUNCTION__);
1605 return 0;
1606 }
1607 m_pAudioDecoder->Decode(pkt);
1608 return 1;
1609}
1610
1620{
1621 m_pAudio->LazyInit();
1622
1624 return 0;
1625 }
1626
1628
1629 return 1;
1630}
1631
1639{
1640 if (Replaying()) {
1641 LOGDEBUG("device: %s: Device is replaying, stop replay first", __FUNCTION__);
1642 StopReplay();
1643 }
1644
1645 if (IsPrimaryDevice(false)) {
1646 m_needsMakePrimary = true;
1647 MakePrimaryDevice(false);
1648 }
1649
1651}
1652
1660{
1661 m_forceDetached = false;
1662
1663 if (m_needsMakePrimary) {
1664 MakePrimaryDevice(true);
1665 m_needsMakePrimary = false;
1666 }
1667
1669}
1670
1675{
1676 std::lock_guard<std::mutex> lock(m_mutex);
1677 return m_state == State::DETACHED;
1678}
1679
1687
1705
1710{
1711 std::lock_guard<std::mutex> lock(m_mutex);
1712 return m_pPipHandler->IsEnabled();
1713}
1714
1724void cSoftHdDevice::PipChannelSwap(bool closePip) { m_pPipHandler->ChannelSwap(closePip); };
Audio and alsa module header file.
cAudioDecoder - Audio decoder class
Definition codec_audio.h:76
void FlushBuffers(void)
Flush the audio decoder.
void Decode(const AVPacket *)
Decode an audio packet.
AVCodecID GetCodecId() const
Definition codec_audio.h:85
void SetPassthrough(int)
Set audio pass-through mask.
void Open(AVCodecID, AVCodecParameters *=nullptr, AVRational={ .num=1,.den=90000 })
Open and initiate the audio decoder.
void Close(void)
Close the audio decoder.
void PacketReceived()
Called each time a packet is received.
void Reset()
Resets the jitter tracker.
cMainVideoStream - Main video stream class
Audio PES packet parser.
Definition pes.h:81
Video PES packet parser.
Definition pes.h:68
bool IsValid()
Check if the PES packet is valid.
Definition pes.cpp:244
int GetPayloadSize()
Get the size of the PES payload.
Definition pes.cpp:312
int GetPacketLength()
Get the total length of the PES packet.
Definition pes.cpp:334
const uint8_t * GetPayload()
Get a pointer to the PES payload data.
Definition pes.cpp:299
bool HasPts()
Check if the PES packet contains a Presentation Time Stamp (PTS)
Definition pes.cpp:270
int64_t GetPts()
Get the Presentation Time Stamp (PTS) from the PES header.
Definition pes.cpp:283
cPipHandler - class for pip
Definition pipreceiver.h:56
void ChannelChange(int)
Change the pip channel.
void SwapPosition(void)
Swap pip between normal and alternative position.
void Toggle(void)
Toggle picture-in-picture.
void HandleEvent(enum PipState)
Handle the pip event.
void Disable(void)
Stop picture-in-picture.
void ChannelSwap(bool)
Swap the pip channel with main live channel.
bool IsEnabled(void)
Definition pipreceiver.h:61
void Enable(void)
Start picture-in-picture.
void SetSize(void)
Set size and position for the pip window.
cPipVideoStream - Pip video stream class
AVPacket * PopAvPacket() override
Pop an audio AVPacket from the reassembly buffer.
Definition pes.cpp:448
Video stream reassembly buffer.
Definition pes.h:141
bool HasLeadingZero(const uint8_t *, int)
Check if video data has a leading zero byte before the start code.
Definition pes.cpp:431
bool ParseCodecHeader(const uint8_t *, int)
Parse video codec header to detect codec type.
Definition pes.cpp:398
AVPacket * PopAvPacket() override
Definition pes.h:144
virtual void Push(const uint8_t *data, int size, int64_t pts)
Definition pes.h:121
AVCodecID GetCodec()
Definition pes.h:126
void Reset()
Reset the reassembly buffer.
Definition pes.cpp:616
bool IsEmpty()
Definition pes.h:123
cSoftHdAudio - Audio class
Definition audio.h:51
void LazyInit(void)
Initialize audio output module.
Definition audio.cpp:1018
int64_t GetInputPtsMs(void)
Definition audio.h:71
int64_t GetHardwareOutputPtsTimebaseUnits(void)
Get the hardware output PTS in timebase units.
Definition audio.cpp:912
bool HasPts(void)
Definition audio.h:70
void SetVolume(int)
Set mixer volume (0-1000)
Definition audio.cpp:925
void DropSamplesOlderThanPtsMs(int64_t)
Drop samples older than the given PTS.
Definition audio.cpp:570
int64_t GetOutputPtsMs(void)
Get the output PTS of the ringbuffer.
Definition audio.cpp:867
void ClockDriftCompensation(void)
Calculate clock drift compensation.
Definition audio.cpp:1588
void Exit(void)
Cleanup audio output module.
Definition audio.cpp:1029
void SetPaused(bool)
Set audio playback paused state.
Definition audio.cpp:948
void SetPassthrough(int)
Set audio passthrough mask.
Definition audio.cpp:1004
bool IsBufferFull(void)
Definition audio.h:62
void FlushBuffers(void)
Flush audio buffers.
Definition audio.cpp:816
bool ConfigParseH264Dimensions
parse h264 stream for width and height for decoder init
Definition config.h:62
int ConfigVideoAudioDelayMs
config audio delay
Definition config.h:42
const char * ConfigDisplayResolution
display resolution (syntax: "1920x1080@50")
Definition config.h:81
int ConfigDecoderFallbackToSwNumPkts
maximum number of packets sent before fallback to sw decoder
Definition config.h:64
const char * ConfigAudioPCMDevice
audio PCM device
Definition config.h:78
bool ConfigDisableDeint
disable deinterlacer
Definition config.h:60
int ConfigAdditionalBufferLengthMs
config size ms of a/v buffer
Definition config.h:41
const char * ConfigAudioMixerChannel
audio mixer channel name
Definition config.h:80
bool ConfigDecoderNeedsIFrame
start h264 decoder only when an I-Frame arrives
Definition config.h:61
const char * ConfigAudioPassthroughDevice
audio passthrough device
Definition config.h:79
void SetState(State)
Sets the device into the given state.
void OsdDrawARGB(int, int, int, int, int, const uint8_t *, int, int)
Draw an OSD pixmap.
cReassemblyBufferVideo m_videoReassemblyBuffer
video pes reassembly buffer
void Stop(void)
Called by VDR when the plugin is stopped.
bool m_pipUseAlt
use alternative pip position
cReassemblyBufferVideo m_pipReassemblyBuffer
pip pes reassembly buffer
void PipChannelSwap(bool)
cVideoStream * m_pPipStream
pointer to pip video stream
void SetDecoderFallbackToSw(bool enable)
Force the decoder to fallback to software if the hardware decoder fails after the configured amount o...
void PipSwapPosition(void)
static constexpr int MIN_BUFFER_FILL_LEVEL_THRESHOLD_MS
min buffering threshold in ms
virtual void StillPicture(const uchar *, int)
Display the given I-frame as a still picture.
void PipSetSize(void)
cSoftOsdProvider * m_pOsdProvider
pointer to cSoftOsdProvider object
cVideoStream * m_pVideoStream
pointer to main video stream
cReassemblyBufferAudio m_audioReassemblyBuffer
audio pes reassembly buffer
std::atomic< bool > m_receivedAudio
flag if audio packets have been received
void SetRenderPipSize(void)
Wrapper functions for cVideoRender and cPipHandler.
cDvbSpuDecoder * m_pSpuDecoder
pointer to spu decoder
void OnEnteringState(State)
Actions to be performed when entering a state.
int Start(void)
Called by VDR when the plugin is started.
virtual void GetVideoSize(int &, int &, double &)
Get the video size.
int PlayAudioPkts(AVPacket *)
Play an audio packet.
virtual void GetOsdSize(int &, int &, double &)
Returns the width, height and aspect ratio the OSD.
void SetRenderPipActive(bool)
void GetStats(int *, int *, int *)
Get statistics from the renderer.
void ClearAudio(void)
Clear all audio data from the decoder and ringbuffer.
void ResetChannelId(void)
Reset the channel ID (restarts audio)
virtual bool CanReplay(void) const
Returns true if this device can currently start a replay session.
virtual void SetDigitalAudioDevice(bool)
std::mutex m_mutex
mutex to lock the state machine
virtual bool HasDecoder(void) const
Tells whether this device has an MPEG decoder.
virtual void Clear(void)
Clears all video and audio data from the device.
void OnEventReceived(const Event &)
Event handler for playback state transitions.
cPipHandler * m_pPipHandler
pointer to pip handler
void Detach(void)
Detach the device.
virtual int PlayVideo(const uchar *, int)
Play a video packet of the main videostream.
void ResetPipStream(void)
Resets pip stream and render pipeline.
double m_screenRefreshRateHz
std::atomic< State > m_state
current plugin state, normal plugin start sets detached state
void OnLeavingState(State)
Actions to be performed when leaving a state.
virtual bool SetPlayMode(ePlayMode)
Sets the device into the given play mode.
cAudioDecoder * m_pAudioDecoder
pointer to cAudioDecoder object
void SetAudioCodec(enum AVCodecID, AVCodecParameters *, AVRational)
Open an audio codec.
virtual void Play(void)
Sets the device into play mode (after a previous trick mode, or pause)
bool IsBufferingThresholdReached(void)
Check if the buffering threshold has been reached.
cVideoRender * m_pRender
pointer to cVideoRender object
virtual void SetAudioChannelDevice(int)
cSoftHdGrab * m_pGrab
pointer to grabber object
const char * CommandLineHelp(void)
Return command line help string.
cSoftHdDevice(cSoftHdConfig *)
cSoftHdDevice constructor
int PlayPipVideo(const uchar *, int)
Play a video packet of the pip videostream.
bool m_needsMakePrimary
cSoftHdAudio * m_pAudio
pointer to cSoftHdAudio object
cSoftHdConfig * m_pConfig
pointer to cSoftHdConfig object
virtual cRect CanScaleVideo(const cRect &, int taCenter)
Ask the output, if it can scale video.
bool m_disablePip
true, if pip was disabled by the user
virtual void SetVolumeDevice(int)
Sets the audio volume on this device (Volume = 0...255).
virtual int64_t GetSTC(void)
Gets the current System Time Counter, which can be used to synchronize audio, video and subtitles.
virtual bool Flush(int=0)
Flush the device output buffers.
bool IsDetached(void) const
Returns true, if the device is detached.
virtual void TrickSpeed(int, bool)
Sets the device into a mode where replay is done slower.
virtual int PlayAudio(const uchar *, int, uchar)
Play an audio packet.
void PipToggle(void)
bool PipIsEnabled(void)
Returns true, if pip is currently enabled.
std::mutex m_sizeMutex
mutex to lock screen size (which is accessed by different threads)
std::atomic< bool > m_receivedVideo
flag if video packets have been received
void SetDecoderNeedsIFrame(void)
Forces the h264 decoder to wait for an I-Frame to start.
int PlayVideoInternal(cVideoStream *, cReassemblyBufferVideo *, const uchar *, int, bool)
Play a video packet.
virtual int GetAudioChannelDevice(void)
int PlayVideoPkts(AVPacket *)
Play a video packet.
void SetScreenSize(int, int, double)
Set the screen size.
cJitterTracker m_audioJitterTracker
audio jitter tracker
int GetBufferFillLevelThresholdMs()
Returns the buffer fill level threshold in milliseconds.
void SetPassthrough(int)
Set the passthrough mask (called from setup menu or conf)
void HandleStillPicture(const uchar *data, int size)
The still picture data received from VDR can contain multiple PES packets.
virtual void SetVideoDisplayFormat(eVideoDisplayFormat)
Sets the video display format.
virtual void Freeze(void)
Puts the device into "freeze frame" mode.
void SetParseH264Dimensions(void)
Parse the h264 stream width and height before starting the decoder.
bool m_forceDetached
start the plugin in detached state
virtual ~cSoftHdDevice(void)
cSoftHdDevice destructor
int m_audioChannelID
current audio channel ID
void PipDisable(void)
virtual void SetVideoFormat(bool)
Set the video format.
virtual void MakePrimaryDevice(bool)
Informs a device that it will be the primary device.
void SetVideoCodec(enum AVCodecID, AVCodecParameters *, AVRational)
Open a video codec.
void PipEnable(void)
void SetDisableDeint(void)
Disables deinterlacer (called from setup menu or conf)
virtual uchar * GrabImage(int &, bool, int, int, int)
Grabs the currently visible screen image.
virtual cSpuDecoder * GetSpuDecoder(void)
Get the device SPU decoder.
cJitterTracker m_videoJitterTracker
video jitter tracker
virtual void SetAudioTrackDevice(eTrackType)
std::atomic< PlaybackMode > m_playbackMode
current playback mode
void OsdClose(void)
Close the OSD.
int64_t GetFirstAudioPtsMsToPlay()
Calculate the first audio PTS that should be played during synchronized playback.
virtual void ScaleVideo(const cRect &=cRect::Null)
Scale the currently shown video.
int64_t GetFirstVideoPtsMsToPlay()
int ProcessArgs(int, char *[])
Process the command line arguments.
void PipChannelChange(int)
virtual bool Poll(cPoller &, int=0)
Returns true if the device itself or any of the file handles in Poller is ready for further action.
void Attach(void)
Attach the device again.
cSoftHdGrab - Grabber class
Definition grab.h:82
bool Start(bool, int, int, int, int, int)
Start a grab in the video renderer.
Definition grab.cpp:332
uint8_t * Image(void)
Definition grab.h:88
bool Active(void)
Definition grab.h:86
int Size(void)
Definition grab.h:89
cSoftOsdProvider - SoftHdDevice plugin OSD provider class
Definition softhdosd.h:67
cVideoRender - Video render class
void PushPipFrame(AVFrame *)
bool IsOutputBufferFull(void)
Check, if the main render output buffer is full.
void ResetBufferReuseStrategy()
void OsdClear(void)
Clear the OSD (draw an empty/ transparent OSD)
void ScheduleResyncAtPtsMs(int64_t ptsMs)
void ClearDecoderToDisplayQueue(void)
Clear (empty) the decoder to display queue.
void Init(void)
Initialize the renderer.
void ResetDecodingStrategy()
void Exit(void)
Exit and cleanup the renderer.
void ResetPipBufferReuseStrategy()
void GetStats(int *, int *, int *)
Get some rendering statistics.
void DisplayBlackFrame(void)
void PushMainFrame(AVFrame *)
void SetVideoOutputPosition(const cRect &)
Set size and position of the video on the screen.
int64_t GetOutputPtsMs(void)
Get the output PTS in milliseconds.
void SetPipActive(bool on)
void DisplayThreadHalt(void)
void ClearPipDecoderToDisplayQueue(void)
Clear (empty) the decoder to display queue.
cQueue< cDrmBuffer > * GetPipOutputBuffer(void)
void SetStillpicture(bool active)
void SchedulePlaybackStartAtPtsMs(int64_t ptsMs)
int64_t GetVideoClock(void)
void OsdDrawARGB(int, int, int, int, int, const uint8_t *, int, int)
Draw an OSD ARGB image.
void SetScheduleAudioResume(bool resume)
void SetDisplayOneFrameThenPause(bool pause)
void SetPipSize(bool)
void SetPlaybackPaused(bool pause)
void DisplayThreadResume(void)
void ResetFrameCounter(void)
Send start condition to video thread.
void SetTrickSpeed(double, bool, bool)
Set the trickspeed parameters.
void ResetPipDecodingStrategy()
cQueue< cDrmBuffer > * GetMainOutputBuffer(void)
cVideoStream - Video stream class
Definition videostream.h:55
void GetVideoSize(int *, int *, double *)
Get video size and aspect ratio.
void SetDecoderFallbackToSwNumPkts(int numPackets)
Definition videostream.h:98
void Flush(void)
Flushes the video stream by finalizing any pending data.
void StartDecoder()
Start the decoder.
void DecodingThreadResume(void)
Definition videostream.h:86
void ClearVdrCoreToDecoderQueue(void)
Clears all video stream data, which is buffered to be decoded.
void ResetInputPts(void)
Definition videostream.h:80
void SetStartDecodingWithIFrame(bool enable)
Definition videostream.h:96
size_t GetAvPacketsFilled(void)
Definition videostream.h:73
void DisableDeint(bool disable)
Definition videostream.h:95
void CloseDecoder(void)
Close the decoder.
void Exit(void)
Exit video stream.
void CancelFilterThread(void)
Stop filter thread.
void DecodingThreadHalt(void)
Definition videostream.h:85
void FlushDecoder(void)
Flush the decoder.
void Open(AVCodecID, AVCodecParameters *=nullptr, AVRational={ .num=1,.den=90000 })
Open a video codec.
bool PushAvPacket(AVPacket *avpkt)
Pushes a pre-assembled AVPacket directly to the processing queue.
bool IsInputBufferFull(void)
Definition videostream.h:74
void ResetFilterThreadNeededCheck()
Definition videostream.h:90
int64_t GetInputPtsMs(void)
void SetParseH264Dimensions(bool enable)
Definition videostream.h:97
virtual void SetDeinterlacerDeactivated(bool deactivate)
Definition videostream.h:92
void ResetTrickSpeedFramesSentCounter(void)
Definition videostream.h:76
enum AVCodecID GetCodecId(void)
Definition videostream.h:75
bool HasInputPts(void)
Definition videostream.h:77
Audio decoder header file.
SoftHdDevice config header file.
State machine and event header file.
@ PIPSTOP
Definition event.h:31
std::variant< PlayEvent, PauseEvent, StopEvent, TrickSpeedEvent, StillPictureEvent, DetachEvent, AttachEvent, BufferUnderrunEvent, BufferingThresholdReachedEvent, PipEvent, ScheduleResyncAtPtsMsEvent, ResyncEvent > Event
Definition event.h:79
Grabber header file.
static void PrintStreamData(const uint8_t *data, int size)
Print raw stream data.
Tracks the jitter of incoming packets (currently only for logging purposes)
Logger class header file.
#define LOGDEBUG2
Definition logger.h:45
#define LOGDEBUG
Definition logger.h:44
#define LOGERROR
Definition logger.h:41
#define L_GRAB
Definition logger.h:66
#define L_AV_SYNC
Definition logger.h:54
#define L_CODEC
Definition logger.h:58
#define LOGWARNING
Definition logger.h:42
#define LOGFATAL
Logger macros.
Definition logger.h:40
#define L_OSD
Definition logger.h:56
#define AV_NOPTS_VALUE
Definition misc.h:69
static const char * Timestamp2String(int64_t ts, uint8_t divisor)
Workaround for av_err2str() not working with C++.
Definition misc.h:119
PES packet parser header.
Pip receiver header file.
static void PrintStreamData(const uchar *payload)
Print the start code, stream id, length, first three bytes (start code) of the payload,...
Device class header file.
@ AUDIO_AND_VIDEO
@ VIDEO_ONLY
@ AUDIO_ONLY
@ NONE
const char * EventToString(const Event &e)
State
@ PLAY
@ STOP
@ BUFFERING
@ TRICK_SPEED
@ DETACHED
const char * StateToString(State s)
Softhddevice osd header file.
Rendering class header file.
Videostream class header file.
#define VIDEO_PACKET_MAX
max number of video packets held in the buffer
Definition videostream.h:36