Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement subtitle 24/25fps frame rate correction #23206

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions addons/resource.language.en_gb/resources/strings.po
Original file line number Diff line number Diff line change
Expand Up @@ -23789,6 +23789,12 @@ msgctxt "#39201"
msgid "HDR10+"
msgstr ""

#: xbmc/dialogs/GUIDialogSubtitles.cpp
msgctxt "#39202"
msgid "Fix 24/25 fps mismatch"
msgstr ""


# 40000 to 40800 are reserved for Video Versions feature

#. Generic video versions label (plural)
Expand Down
18 changes: 17 additions & 1 deletion xbmc/application/ApplicationPlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -737,6 +737,21 @@ void CApplicationPlayer::SetSubTitleDelay(float fValue)
player->SetSubTitleDelay(fValue);
}

void CApplicationPlayer::SetSubtitleCompensateFPS(bool bValue)
{
std::shared_ptr<IPlayer> player = GetInternal();
if (player)
player->SetSubtitleCompensateFPS(bValue);
}

bool CApplicationPlayer::GetSubtitleCompensateFPS() const
{
std::shared_ptr<const IPlayer> player = GetInternal();
if (player)
return player->GetSubtitleCompensateFPS();
return false;
}

void CApplicationPlayer::SetAVDelay(float fValue)
{
std::shared_ptr<IPlayer> player = GetInternal();
Expand Down Expand Up @@ -765,7 +780,8 @@ void CApplicationPlayer::GetAudioCapabilities(std::vector<int>& audioCaps) const
player->GetAudioCapabilities(audioCaps);
}

void CApplicationPlayer::GetSubtitleCapabilities(std::vector<int>& subCaps) const
void CApplicationPlayer::GetSubtitleCapabilities(
std::vector<IPlayerSubtitleCapabilities>& subCaps) const
{
const std::shared_ptr<const IPlayer> player = GetInternal();
if (player)
Expand Down
4 changes: 3 additions & 1 deletion xbmc/application/ApplicationPlayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,9 @@ class CApplicationPlayer : public IApplicationComponent
std::string GetPlayerState();
PLAYLIST::Id GetPreferredPlaylist() const;
int GetSubtitleDelay() const;
bool GetSubtitleCompensateFPS() const;
int GetSubtitle();
void GetSubtitleCapabilities(std::vector<int>& subCaps) const;
void GetSubtitleCapabilities(std::vector<IPlayerSubtitleCapabilities>& subCaps) const;
int GetSubtitleCount() const;
void GetSubtitleStreamInfo(int index, SubtitleStreamInfo& info) const;
bool GetSubtitleVisible() const;
Expand Down Expand Up @@ -152,6 +153,7 @@ class CApplicationPlayer : public IApplicationComponent
bool SetPlayerState(const std::string& state);
void SetSubtitle(int iStream);
void SetSubTitleDelay(float fValue = 0.0f);
void SetSubtitleCompensateFPS(bool bDoCompensate = false);
void SetSubtitleVisible(bool bVisible);

/*!
Expand Down
7 changes: 5 additions & 2 deletions xbmc/cores/IPlayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ enum IPlayerSubtitleCapabilities
IPC_SUBS_ALL,
IPC_SUBS_SELECT,
IPC_SUBS_EXTERNAL,
IPC_SUBS_OFFSET
IPC_SUBS_OFFSET,
IPC_SUBS_STRETCH
};

enum ERENDERFEATURE
Expand Down Expand Up @@ -117,6 +118,8 @@ class IPlayer

virtual void SetSubTitleDelay(float fValue = 0.0f) {}
virtual float GetSubTitleDelay() { return 0.0f; }
virtual void SetSubtitleCompensateFPS(bool bValue = false) {}
virtual bool GetSubtitleCompensateFPS() const { return false; }
virtual int GetSubtitleCount() const { return 0; }
virtual int GetSubtitle() { return -1; }
virtual void GetSubtitleStreamInfo(int index, SubtitleStreamInfo& info) const {}
Expand Down Expand Up @@ -217,7 +220,7 @@ class IPlayer
/*!
\brief define the subtitle capabilities of the player
*/
virtual void GetSubtitleCapabilities(std::vector<int>& subCaps) const
virtual void GetSubtitleCapabilities(std::vector<IPlayerSubtitleCapabilities>& subCaps) const
{
subCaps.assign(1, IPC_SUBS_ALL);
}
Expand Down
2 changes: 2 additions & 0 deletions xbmc/cores/VideoPlayer/IVideoPlayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ class IDVDStreamPlayerVideo : public IDVDStreamPlayer
virtual bool IsSubtitleEnabled() = 0;
virtual double GetSubtitleDelay() = 0;
virtual void SetSubtitleDelay(double delay) = 0;
virtual bool GetSubtitleCompensateFPS() const = 0;
virtual void SetSubtitleCompensateFPS(bool bDoCompensate) = 0;
bool IsStalled() const override = 0;
virtual bool IsRewindStalled() const { return false; }
virtual double GetCurrentPts() = 0;
Expand Down
11 changes: 11 additions & 0 deletions xbmc/cores/VideoPlayer/VideoPlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3347,6 +3347,17 @@ float CVideoPlayer::GetSubTitleDelay()
return (float) -m_VideoPlayerVideo->GetSubtitleDelay() / DVD_TIME_BASE;
}

void CVideoPlayer::SetSubtitleCompensateFPS(bool bDoCompensate)
{
m_processInfo->GetVideoSettingsLocked().SetSubtitleCompensateFPS(bDoCompensate);
m_VideoPlayerVideo->SetSubtitleCompensateFPS(bDoCompensate);
}

bool CVideoPlayer::GetSubtitleCompensateFPS() const
{
return m_VideoPlayerVideo->GetSubtitleCompensateFPS();
}

bool CVideoPlayer::GetSubtitleVisible() const
{
if (m_pInputStream && m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD))
Expand Down
2 changes: 2 additions & 0 deletions xbmc/cores/VideoPlayer/VideoPlayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,8 @@ class CVideoPlayer : public IPlayer, public CThread, public IVideoPlayer,

void SetSubTitleDelay(float fValue = 0.0f) override;
float GetSubTitleDelay() override;
void SetSubtitleCompensateFPS(bool bValue) override;
bool GetSubtitleCompensateFPS() const override;
int GetSubtitleCount() const override;
int GetSubtitle() override;
void GetSubtitleStreamInfo(int index, SubtitleStreamInfo& info) const override;
Expand Down
24 changes: 21 additions & 3 deletions xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ CVideoPlayerVideo::CVideoPlayerVideo(CDVDClock* pClock
m_paused = false;
m_syncState = IDVDStreamPlayer::SYNC_STARTING;
m_iSubtitleDelay = 0;
m_subtitleCompensateFPS = 0.0;
m_iLateFrames = 0;
m_iDroppedRequest = 0;
m_fForcedAspectRatio = 0;
Expand Down Expand Up @@ -802,9 +803,26 @@ void CVideoPlayerVideo::Flush(bool sync)

void CVideoPlayerVideo::ProcessOverlays(const VideoPicture* pSource, double pts)
{
double pts1 = pts;
if (m_subtitleCompensateFPS)
{
double stFrameRate = m_fFrameRate;
while (stFrameRate > 44.0)
stFrameRate /= 2.0;
if ((stFrameRate > 24.9 && stFrameRate < 25.1) || (stFrameRate > 49.9 && stFrameRate < 50.1))
// 25fps material, 24fps subtitles
// use 23.976 since it's waay more common
// in the ultra-rare cases of true 24.0 fps, it's still only a 86 frames
// = ~ 3.6 seconds difference per hour, something I feel one could deal
// with using the subtitle offset feature if need be.
pts1 = pts * (stFrameRate / 23.976);
else // 24 fps material, compensate 25fps subtitles
pts1 = pts * (stFrameRate / 25.0);
}

// remove any overlays that are out of time
if (m_syncState == IDVDStreamPlayer::SYNC_INSYNC)
m_pOverlayContainer->CleanUp(pts - m_iSubtitleDelay);
m_pOverlayContainer->CleanUp(pts1 - m_iSubtitleDelay);

VecOverlays overlays;

Expand All @@ -822,7 +840,7 @@ void CVideoPlayerVideo::ProcessOverlays(const VideoPicture* pSource, double pts)
if(!pOverlay->bForced && !m_bRenderSubs)
continue;

double pts2 = pOverlay->bForced ? pts : pts - m_iSubtitleDelay;
double pts2 = pOverlay->bForced ? pts1 : pts1 - m_iSubtitleDelay;

if((pOverlay->iPTSStartTime <= pts2 && (pOverlay->iPTSStopTime > pts2 || pOverlay->iPTSStopTime == 0LL)))
{
Expand All @@ -837,7 +855,7 @@ void CVideoPlayerVideo::ProcessOverlays(const VideoPicture* pSource, double pts)

for(it = overlays.begin(); it != overlays.end(); ++it)
{
double pts2 = (*it)->bForced ? pts : pts - m_iSubtitleDelay;
double pts2 = (*it)->bForced ? pts1 : pts1 - m_iSubtitleDelay;
m_renderManager.AddOverlay(*it, pts2);
}
}
Expand Down
6 changes: 6 additions & 0 deletions xbmc/cores/VideoPlayer/VideoPlayerVideo.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ class CVideoPlayerVideo : public CThread, public IDVDStreamPlayerVideo
bool IsSubtitleEnabled() override { return m_bRenderSubs; }
double GetSubtitleDelay() override { return m_iSubtitleDelay; }
void SetSubtitleDelay(double delay) override { m_iSubtitleDelay = delay; }
bool GetSubtitleCompensateFPS() const override { return m_subtitleCompensateFPS; }
void SetSubtitleCompensateFPS(bool bDoCompensate) override
{
m_subtitleCompensateFPS = bDoCompensate;
}
bool IsStalled() const override { return m_stalled; }
bool IsRewindStalled() const override { return m_rewindStalled; }
double GetCurrentPts() override;
Expand Down Expand Up @@ -105,6 +110,7 @@ class CVideoPlayerVideo : public CThread, public IDVDStreamPlayerVideo
int CalcDropRequirement(double pts);

double m_iSubtitleDelay;
bool m_subtitleCompensateFPS;

int m_iLateFrames;
int m_iDroppedFrames;
Expand Down
9 changes: 9 additions & 0 deletions xbmc/cores/VideoSettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ CVideoSettings::CVideoSettings()
m_AudioStream = -1;
m_SubtitleStream = -1;
m_SubtitleDelay = 0.0f;
m_subtitleCompensateFPS = false;
m_subtitleVerticalPosition = 0;
m_subtitleVerticalPositionSave = false;
m_SubtitleOn = true;
Expand Down Expand Up @@ -57,6 +58,8 @@ bool CVideoSettings::operator!=(const CVideoSettings &right) const
if (m_AudioStream != right.m_AudioStream) return true;
if (m_SubtitleStream != right.m_SubtitleStream) return true;
if (m_SubtitleDelay != right.m_SubtitleDelay) return true;
if (m_subtitleCompensateFPS != right.m_subtitleCompensateFPS)
return true;
if (m_subtitleVerticalPosition != right.m_subtitleVerticalPosition)
return true;
if (m_subtitleVerticalPositionSave != right.m_subtitleVerticalPositionSave)
Expand Down Expand Up @@ -125,6 +128,12 @@ void CVideoSettingsLocked::SetSubtitleDelay(float delay)
m_videoSettings.m_SubtitleDelay = delay;
}

void CVideoSettingsLocked::SetSubtitleCompensateFPS(bool doCompensate)
{
std::unique_lock<CCriticalSection> lock(m_critSection);
m_videoSettings.m_subtitleCompensateFPS = doCompensate;
}

void CVideoSettingsLocked::SetSubtitleVerticalPosition(int value, bool save)
{
std::unique_lock<CCriticalSection> lock(m_critSection);
Expand Down
2 changes: 2 additions & 0 deletions xbmc/cores/VideoSettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ class CVideoSettings
float m_VolumeAmplification;
int m_SubtitleStream;
float m_SubtitleDelay;
double m_subtitleCompensateFPS;
int m_subtitleVerticalPosition{0};
bool m_subtitleVerticalPositionSave{false};
bool m_SubtitleOn;
Expand Down Expand Up @@ -246,6 +247,7 @@ class CVideoSettingsLocked
void SetVideoStream(int stream);
void SetAudioDelay(float delay);
void SetSubtitleDelay(float delay);
void SetSubtitleCompensateFPS(bool doCompensate);

/*!
* \brief Set the subtitle vertical position,
Expand Down
13 changes: 13 additions & 0 deletions xbmc/video/dialogs/GUIDialogSubtitleSettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@

#define SETTING_SUBTITLE_ENABLE "subtitles.enable"
#define SETTING_SUBTITLE_DELAY "subtitles.delay"
#define SETTING_SUBTITLE_FPS "subtitles.fps"
#define SETTING_SUBTITLE_STREAM "subtitles.stream"
#define SETTING_SUBTITLE_BROWSER "subtitles.browser"
#define SETTING_SUBTITLE_SEARCH "subtitles.search"
Expand Down Expand Up @@ -111,6 +112,11 @@ void CGUIDialogSubtitleSettings::OnSettingChanged(const std::shared_ptr<const CS
float value = static_cast<float>(std::static_pointer_cast<const CSettingNumber>(setting)->GetValue());
appPlayer->SetSubTitleDelay(value);
}
else if (settingId == SETTING_SUBTITLE_FPS)
{
bool value = std::static_pointer_cast<const CSettingBool>(setting)->GetValue();
appPlayer->SetSubtitleCompensateFPS(value);
}
else if (settingId == SETTING_SUBTITLE_STREAM)
{
m_subtitleStream = std::static_pointer_cast<const CSettingInt>(setting)->GetValue();
Expand Down Expand Up @@ -303,6 +309,13 @@ void CGUIDialogSubtitleSettings::InitializeSettings()
std::static_pointer_cast<CSettingControlSlider>(settingSubtitleDelay->GetControl())->SetFormatter(SettingFormatterDelay);
}

if (SupportsSubtitleFeature(IPC_SUBS_STRETCH))
{
m_subtitleCompensateFPS = appPlayer->GetSubtitleCompensateFPS();
AddToggle(groupSubtitles, SETTING_SUBTITLE_FPS, 39202, SettingLevel::Basic,
m_subtitleCompensateFPS);
}

// subtitle stream setting
if (SupportsSubtitleFeature(IPC_SUBS_SELECT))
AddSubtitleStreams(groupSubtitles, SETTING_SUBTITLE_STREAM);
Expand Down
4 changes: 3 additions & 1 deletion xbmc/video/dialogs/GUIDialogSubtitleSettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#pragma once

#include "cores/IPlayer.h"
#include "cores/VideoPlayer/Interface/StreamInfo.h"
#include "settings/dialogs/GUIDialogSettingsManualBase.h"

Expand Down Expand Up @@ -51,9 +52,10 @@ class CGUIDialogSubtitleSettings : public CGUIDialogSettingsManualBase

int m_subtitleStream;
bool m_subtitleVisible;
bool m_subtitleCompensateFPS;
std::shared_ptr<CSettingInt> m_subtitleStreamSetting;

std::vector<int> m_subtitleCapabilities;
std::vector<IPlayerSubtitleCapabilities> m_subtitleCapabilities;
static std::string FormatFlags(StreamFlags flags);

static void SubtitleStreamsOptionFiller(const std::shared_ptr<const CSetting>& setting,
Expand Down