Skip to content

Commit 3dbc054

Browse files
committed
device: add option to start audio immediately at fast channel switch
1 parent b32c860 commit 3dbc054

8 files changed

Lines changed: 82 additions & 11 deletions

File tree

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,8 +204,9 @@ Setup: /etc/vdr/setup.conf
204204
Same as above, but now the display also chooses an interlaced mode for interlaced input (except for 576i) if available
205205

206206
softhddevice-drm-gles.VideoFastChannelSwitch = 0
207-
0 = enable fast channel switch: the first available frame is displayed as a still-picture as soon as possible until a/v is in sync
208-
1 = fast channel switch is disabled
207+
0 = fast channel switch is disabled
208+
1 = enable fast channel switch: video is presented immediately as a still-picture
209+
2 = enable fast channel switch: video is presented immediately as a still-picture and audio starts as soon as possible (slower than 1)
209210

210211
softhddevice-drm-gles.MaxSizeGPUImageCache = 128
211212
how many GPU memory should be used for image caching

config.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ class cSoftHdConfig {
5858
// Video
5959
int ConfigVideoEnableHDR = 0; ///< enable HDR
6060
int ConfigVideoDisplayMode = CONFIG_DISPLAY_MODE_DEFAULT; ///< display mode (enum ConfigDisplayMode)
61-
bool ConfigVideoFastChannelSwitch = false; ///< first video frame is presented as still-picture as soon as possible
61+
int ConfigVideoFastChannelSwitch = 0; ///< fast channel switch mode (0: disabled, 1: video, 2: video + audio)
6262

6363
// Audio
6464
bool ConfigAudioSoftvol = false; ///< config use software volume

po/de_DE.po

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,12 @@ msgstr "an Video angepasst (interlaced) %dx%d@%.2f%s"
362362
msgid "match video (interlaced)"
363363
msgstr "an Video anpassen (interlaced)"
364364

365+
msgid "video"
366+
msgstr "Video"
367+
368+
msgid "video and audio"
369+
msgstr "Video und Audio"
370+
365371
#, c-format
366372
msgid "channel switch done in %ldms (%ldms)"
367373
msgstr "Kanal gewechselt in %ldms (%ldms)"

softhddevice.cpp

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,11 @@ int cSoftHdDevice::PlayAudio(const uchar *data, int size, uchar id)
419419
if (IsBufferingThresholdReached())
420420
TriggerEvent(BufferingThresholdReachedEvent{});
421421

422+
// unpause audio, if the fast channel switch modes wants it to be started
423+
// the audio buffer reached the threshold and we are in live tv mode
424+
if (m_fastChannelSwitch == 2 && Transferring() && m_pAudio->IsPaused() && IsAudioBufferingThresholdReached())
425+
m_pAudio->SetPaused(false);
426+
422427
AVPacket *avpkt;
423428
do {
424429
if (!(avpkt = m_audioReassemblyBuffer.PopAvPacket()))
@@ -952,12 +957,16 @@ bool cSoftHdDevice::IsBufferingThresholdReached()
952957
int64_t syncedAudioBufferFillLevelMs = m_pAudio->GetInputPtsMs() - GetFirstAudioPtsMsToPlay();
953958
int64_t syncedVideoBufferFillLevelMs = m_pVideoStream->GetInputPtsMs() - GetFirstVideoPtsMsToPlay();
954959

960+
int audioBehindVideo = m_pRender->GetOutputPtsMs() - m_pAudio->GetOutputPtsMs() - GetVideoAudioDelayMs();
961+
bool audioReachedVideo = audioBehindVideo <= 0;
962+
955963
bool reached = m_pRender->IsOutputBufferFull() && // video decoder output buffer (audio hardware output buffer is negligible)
956964
syncedVideoBufferFillLevelMs > GetBufferFillLevelThresholdMs() && // video decoder input buffer
957-
syncedAudioBufferFillLevelMs > GetBufferFillLevelThresholdMs(); // audio decoder output buffer
965+
syncedAudioBufferFillLevelMs > GetBufferFillLevelThresholdMs() && // audio decoder output buffer
966+
(m_fastChannelSwitch == 2 ? audioReachedVideo : true); // if fast channel switch played audio already, wait for audio to come up
958967

959968
if (reached) {
960-
LOGDEBUG2(L_AV_SYNC, "First received PTS: %s (audio), %s (video) buffer fill levels: %ldms (audio) %ldms (video)",
969+
LOGDEBUG2(L_AV_SYNC, "buffering threshold reached - PTS: %s (audio), %s (video) - buffer fill levels: %ldms (audio) %ldms (video)",
961970
Timestamp2String(m_pAudio->GetOutputPtsMs(), 1),
962971
Timestamp2String(m_pRender->GetOutputPtsMs(), 1),
963972
syncedAudioBufferFillLevelMs,
@@ -967,6 +976,40 @@ bool cSoftHdDevice::IsBufferingThresholdReached()
967976
return reached;
968977
}
969978

979+
/**
980+
* Returns true, if audio buffer is filled enough to start audio playback
981+
*
982+
* @retval true if audio playback should start
983+
* @retval false if audio playback should not start
984+
*
985+
* @note Used for fast channel switch
986+
*/
987+
bool cSoftHdDevice::IsAudioBufferingThresholdReached()
988+
{
989+
if (m_pStateMachine->GetState() != BUFFERING)
990+
return false;
991+
992+
bool audioHasInputPts = m_pAudio->HasInputPts();
993+
bool videoHasInputPts = m_pVideoStream->HasInputPts();
994+
bool videoHasOutputPts = m_pRender->GetOutputPtsMs() != AV_NOPTS_VALUE;
995+
996+
// only start audio playback, if video is already there
997+
if (!audioHasInputPts || !videoHasInputPts || !videoHasOutputPts)
998+
return false;
999+
1000+
int64_t audioBufferFillLevelMs = m_pAudio->GetInputPtsMs() - m_pAudio->GetOutputPtsMs();
1001+
if (audioBufferFillLevelMs > GetBufferFillLevelThresholdMs()) {
1002+
LOGDEBUG2(L_AV_SYNC, "audio buffer reached threshold %dms - PTS: %s (audio), %s (video) - buffer fill levels: %ldms (audio)",
1003+
GetBufferFillLevelThresholdMs(),
1004+
Timestamp2String(m_pAudio->GetOutputPtsMs(), 1),
1005+
Timestamp2String(m_pRender->GetOutputPtsMs(), 1),
1006+
audioBufferFillLevelMs);
1007+
return true;
1008+
}
1009+
1010+
return false;
1011+
}
1012+
9701013
/*********************************************************************
9711014
* cSoftHdDevice public API - osd control
9721015
********************************************************************/
@@ -1819,11 +1862,14 @@ bool cSoftHdDevice::SchedulePlaybackStart(void)
18191862

18201863
if (receivedAudio && receivedVideo) {
18211864
m_playbackMode = AUDIO_AND_VIDEO;
1865+
// store the first PTSes beforehand, because dropping samples/frames will change the output of GetFirst*PtsMsToPlay()
18221866
int64_t firstAudioPtsMs = GetFirstAudioPtsMsToPlay();
18231867
int64_t firstVideoPtsMs = GetFirstVideoPtsMsToPlay();
18241868

1825-
// store the first PTSes beforehand, because dropping samples/frames will change the output of GetFirst*PtsMsToPlay()
1826-
m_pAudio->DropSamplesOlderThanPtsMs(firstAudioPtsMs);
1869+
// don't drop old audio, if we want to wait for it in fast channel switch mode including audio playback
1870+
if (m_fastChannelSwitch < 2 || !Transferring())
1871+
m_pAudio->DropSamplesOlderThanPtsMs(firstAudioPtsMs);
1872+
18271873
m_pRender->SchedulePlaybackStartAtPtsMs(firstVideoPtsMs);
18281874
} else if (receivedAudio) {
18291875
LOGDEBUG("device: audio only detected");

softhddevice.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,9 +147,10 @@ class cSoftHdDevice : public cDevice, public cStatus {
147147
void SetParseH264Dimensions(void);
148148
void SetDecoderFallbackToSw(bool);
149149
void SetEnableHdr(bool);
150-
void SetEnableFastChannelSwitch(bool enable) { m_fastChannelSwitch = enable; };
150+
void SetEnableFastChannelSwitch(int mode) { m_fastChannelSwitch = mode; };
151151
void SetDisplayMode(int);
152152
bool IsBufferingThresholdReached(void);
153+
bool IsAudioBufferingThresholdReached(void);
153154
bool IsVideoOnlyPlayback(void) { return m_playbackMode == VIDEO_ONLY; };
154155

155156
// Osd
@@ -257,7 +258,7 @@ class cSoftHdDevice : public cDevice, public cStatus {
257258
cJitterTracker m_videoJitterTracker{"video"}; ///< video jitter tracker
258259
std::chrono::steady_clock::time_point m_channelSwitchStartTime; ///< timestamp, when VDR triggered a channel switch
259260
std::chrono::steady_clock::time_point m_dataReceivedTime; ///< timestamp, when the first audio or video data after a channel switch arrives in Play*()
260-
bool m_fastChannelSwitch = false; ///< enable fast channel switch: display a video frame as still frame asap after stream start
261+
int m_fastChannelSwitch = 0; ///< 0: fast channel switch disabled, 1: video start immediately, 2: video and audio start immediately
261262

262263
std::atomic<PlaybackMode> m_playbackMode = NONE; ///< current playback mode
263264
int m_audioChannelID = -1; ///< current audio channel ID

softhdsetupmenu.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@ void cMenuSetupSoft::Create(void)
7777
if (m_cVideoMenu) {
7878
Add(new cMenuEditBoolItem(tr(" Enable HDR"), &m_cVideoEnableHDR, trVDR("no"), trVDR("yes")));
7979
Add(new cMenuEditStraItem(tr(" Display mode"), &m_cVideoDisplayMode, m_displayModePtrs.size(), m_displayModePtrs.data()));
80-
Add(new cMenuEditBoolItem(tr(" Enable fast channel switch"), &m_cVideoFastChannelSwitch, trVDR("no"), trVDR("yes")));
80+
81+
Add(new cMenuEditStraItem(tr(" Enable fast channel switch"), &m_cVideoFastChannelSwitch, m_fastChannelSwitchModePtrs.size(), m_fastChannelSwitchModePtrs.data()));
8182
}
8283

8384
//
@@ -301,6 +302,7 @@ cMenuSetupSoft::cMenuSetupSoft(cSoftHdDevice *device)
301302
// Video
302303
//
303304
BuildDisplayModeList();
305+
BuildFastChannelSwitchModeList();
304306

305307
m_cVideoMenu = 0;
306308
m_cVideoEnableHDR = m_pConfig->ConfigVideoEnableHDR;
@@ -437,6 +439,18 @@ void cMenuSetupSoft::BuildDisplayModeList(void)
437439
m_displayModePtrs.push_back(s.c_str());
438440
}
439441

442+
void cMenuSetupSoft::BuildFastChannelSwitchModeList(void)
443+
{
444+
m_fastChannelSwitchMode.clear();
445+
446+
m_fastChannelSwitchMode.push_back(trVDR("off"));
447+
m_fastChannelSwitchMode.push_back(tr("video"));
448+
m_fastChannelSwitchMode.push_back(tr("video and audio"));
449+
450+
for (auto &s : m_fastChannelSwitchMode)
451+
m_fastChannelSwitchModePtrs.push_back(s.c_str());
452+
}
453+
440454
/**
441455
* Store settings
442456
*/

softhdsetupmenu.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,10 +118,13 @@ class cMenuSetupSoft : public cMenuSetupPage {
118118

119119
std::vector<std::string> m_displayMode;
120120
std::vector<const char *> m_displayModePtrs;
121+
std::vector<std::string> m_fastChannelSwitchMode;
122+
std::vector<const char *> m_fastChannelSwitchModePtrs;
121123

122124
inline cOsdItem * CollapsedItem(const char *, int &, const char * = NULL);
123125
void Create(void);
124126
void BuildDisplayModeList(void);
127+
void BuildFastChannelSwitchModeList(void);
125128

126129
protected:
127130
virtual void Store(void);

videorender.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -786,7 +786,7 @@ bool cVideoRender::DisplayFrame(void)
786786
} else {
787787
if (m_pConfig->ConfigShowChannelSwitchDurationMessage)
788788
Skins.Message(mtInfo, cString::sprintf(tr("channel switch done in %ldms (%ldms)"), channelSwitchDurationMs, durationSinceFirstPacketMs));
789-
LOGDEBUG("in sync after channel switch in %dms, %dms after first packet was received", channelSwitchDurationMs, durationSinceFirstPacketMs);
789+
LOGDEBUG("playback start fired %dms after channel switch, %dms after first packet was received", channelSwitchDurationMs, durationSinceFirstPacketMs);
790790
}
791791
}
792792

0 commit comments

Comments
 (0)