Skip to content

fix: video player playback rate#8407

Merged
FreeTubeBot merged 3 commits intoFreeTubeApp:developmentfrom
lukasstorck:fix/video-player-playback-rate
Jan 17, 2026
Merged

fix: video player playback rate#8407
FreeTubeBot merged 3 commits intoFreeTubeApp:developmentfrom
lukasstorck:fix/video-player-playback-rate

Conversation

@lukasstorck
Copy link
Contributor

@lukasstorck lukasstorck commented Dec 11, 2025

Pull Request Type

  • Bugfix
  • Feature Implementation
  • Documentation
  • Other

Related issue

closes #8226

Description

Fixes a bug with the playback rate jumping to a wrong value (bug described in issue #8226).

Bug details

When loading the video player the playback rate is set based on a prop, which keeps track of the playback rate of a session. So, when playing the next video in a playlist or selecting a video from the next videos section, this correctly allows for keeping the same playback rate. While the current playback rate is set correctly, it is also used to set the default playback rate:

// ft-shaka-video-player.js line 2576-2577
videoElement.playbackRate = props.currentPlaybackRate
videoElement.defaultPlaybackRate = props.currentPlaybackRate

Now, when we set the playback rate back to the actual default playback rate, we correctly stop the trick play mode, but this makes the video player use the default playback rate of the video element, which is wrong from the snippet above, and propagate the value through an event update (update value in UI).

// ft-shaka-video-player.js line 1955-1970
function changePlayBackRate(step) {
  const newPlaybackRateString = (player.getPlaybackRate() + step).toFixed(2)
  const newPlaybackRate = parseFloat(newPlaybackRateString)

  // The following error is thrown if you go below 0.07:
  // The provided playback rate (0.05) is not in the supported playback range.
  if (newPlaybackRate > 0.07 && newPlaybackRate <= maxVideoPlaybackRate.value) {
    if (newPlaybackRate === defaultPlaybackRate.value) {
      player.cancelTrickPlay()
    } else {
      player.trickPlay(newPlaybackRate, false)
    }

    showValueChange(`${newPlaybackRateString}x`)
  }
}

So we can fix this first bug by correctly providing the default playback rate, but this introduces a second bug where after loading the video player, the current playback rate is always reset to the default playback rate. This is because the current playback rate value of the video element is reset to the default value set when the video element is attached to the local player.

// ft-shaka-video-player.js line 2576-2590
videoElement.playbackRate = props.currentPlaybackRate
videoElement.defaultPlaybackRate = props.currentPlaybackRate

const localPlayer = new shaka.Player()

ui = new shaka.ui.Overlay(
  localPlayer,
  container.value,
  videoElement,
  vrCanvas.value
)

await localPlayer.attach(videoElement)  // videoElement.playbackRate is reset to default value

I assume this is the reason, why the default playback rate of the video element was set to the current playback rate and not the actual default playback rate.

Fixes

  • set the default playback rate value of the video element (videoElement.defaultPlaybackRate) based on global default playback rate (defaultPlaybackRate.value) instead of the current playback rate (props.currentPlaybackRate)
  • set the playback rate and default playback rate on the video element after calling .attach() to avoid the playback rate to be overridden
    • an alternative solution would be to figure out why shaka player resets the value and maybe fix it there

Testing

  1. open a video
  2. set a non-default playback rate
  3. select a new video
    • either via "Up next" section
    • or via a playlist
  4. set playback rate back to the default playback rate (not via the UI button)
    • either via ctrl+mouse scroll
    • or via hotkeys P or O
  5. when reaching the default playback rate, is now should not jump to the playback rate of the previous video, but correctly stay at the default playback rate

Desktop

  • OS: Ubuntu
  • OS Version: 24.04.2 LTS
  • FreeTube version: v0.23.12 Beta

Additional context

The reason why await localPlayer.attach(videoElement) resets the playback rate to the default value of the video element is, that the source of the HTMLMediaElement is changed, which resets the playback rate to the set default value.
Excerpts from the code of the shaka video player:

// lib/player.js
async attach(mediaElement, initializeMediaSource = true) {
  // ...
  this.video_ = mediaElement;
  // ...
  await this.initializeMediaSourceEngineInner_();  // <-- calls
}

// ...

async initializeMediaSourceEngineInner_() {
  // ...
  const mediaSourceEngine = this.createMediaSourceEngine(  // <-- calls
    this.video_,
    // ...
  )
  // ...
}

// ...

createMediaSourceEngine(mediaElement, textDisplayer, playerInterface,
                        lcevcDec, config) {
  return new shaka.media.MediaSourceEngine(  // <-- calls
    mediaElement,
    textDisplayer,
    playerInterface,
    config,
    lcevcDec);
  }
// lib/media/media_source_engine.js
shaka.media.MediaSourceEngine = class {
  constructor(video, textDisplayer, playerInterface, config, lcevcDec) {
    // ...
    this.mediaSource_ = this.createMediaSource(this.mediaSourceOpen_);  // <-- calls
    // ...
  }
  
  createMediaSource(p) {
    // ...
    // Store the object URL for releasing it later.
    this.url_ = shaka.media.MediaSourceEngine.createObjectURL(mediaSource);
    if (this.config_.useSourceElements) {
      this.video_.removeAttribute('src');
      if (this.source_) {
        this.video_.removeChild(this.source_);
      }
      if (this.secondarySource_) {
        this.video_.removeChild(this.secondarySource_);
      }
      this.source_ = shaka.util.Dom.createSourceElement(this.url_);
      this.video_.appendChild(this.source_);  // source replace here
      if (this.secondarySource_) {
        this.video_.appendChild(this.secondarySource_);
      }
      this.video_.load();
    } else {
      this.video_.src = this.url_;  // or source attribute replaced here
    }
  }
}

This is therefore not directly the fault of the shaka player, but based on the HTMLMediaElement. This can also be tested with this example:

const video = document.createElement("video");
video.playbackRate = 2;
video.src = "media/video.mp4"; // some valid url
video.playbackRate; // now reset to 1

Alternatively to the second commit, this could be fixed in the shaka player by storing the playback rate before setting a new (or first) source. But the fix would work either way.

@lukasstorck lukasstorck marked this pull request as ready for review December 11, 2025 17:44
@FreeTubeBot FreeTubeBot enabled auto-merge (squash) December 11, 2025 17:44
@github-actions github-actions bot added the PR: waiting for review For PRs that are complete, tested, and ready for review label Dec 11, 2025
@lukasstorck lukasstorck changed the title fix/video player playback rate fix: video player playback rate Dec 11, 2025
@github-actions
Copy link
Contributor

This PR is stale because it has been open 14 days with no activity. Remove stale label or comment or this will be closed in 14 days.

@FreeTubeBot FreeTubeBot merged commit b06c902 into FreeTubeApp:development Jan 17, 2026
5 checks passed
@github-actions github-actions bot removed the PR: waiting for review For PRs that are complete, tested, and ready for review label Jan 17, 2026
@lukasstorck lukasstorck deleted the fix/video-player-playback-rate branch January 17, 2026 12:37
PikachuEXE added a commit to PikachuEXE/FreeTube that referenced this pull request Jan 19, 2026
* development: (55 commits)
  Translated using Weblate (Chinese (Simplified Han script))
  Translated using Weblate (Czech)
  Translated using Weblate (Russian)
  Translated using Weblate (Polish)
  Translated using Weblate (Kurdish (Central))
  Translated using Weblate (French)
  Use GITHUB_TOKEN instead of dedicated PUSH_TOKEN in auto-merge workflow (FreeTubeApp#8541)
  Local API: Implement SABR for VODs (FreeTubeApp#8047)
  Bump package version from 0.23.12 to 0.23.13 (FreeTubeApp#8531)
  Update CodeQL workflow to match the latest template (FreeTubeApp#8533)
  fix: video player playback rate (FreeTubeApp#8407)
  Decipher live DASH manifest URL (FreeTubeApp#8530)
  Add a show all windows button to the tray menu (FreeTubeApp#8494)
  Disable automatically running the flatpak workflow (FreeTubeApp#8507)
  fix using shift on watch page (FreeTubeApp#8491)
  Translated using Weblate (Hebrew)
  Translated using Weblate (Hebrew)
  Fix WAPT link in README (FreeTubeApp#8529)
  Fix typo in auto-merge workflow (FreeTubeApp#8518)
  Added translation using Weblate (Uzbek)
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Playback speed incorrectly increases if keyboard shortcuts are being used

5 participants