diff --git a/i18n/en.json b/i18n/en.json
index 8e8913263c..dcfa0dc17f 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -1540,6 +1540,9 @@
   "play_memories": "Play memories",
   "play_motion_photo": "Play Motion Photo",
   "play_or_pause_video": "Play or pause video",
+  "play_original_video": "Play original video",
+  "play_original_video_setting_description": "Prefer playback of original videos rather than transcoded videos. If original asset is not compatible it may not playback correctly.",
+  "play_transcoded_video": "Play transcoded video",
   "please_auth_to_access": "Please authenticate to access",
   "port": "Port",
   "preferences_settings_subtitle": "Manage the app's preferences",
diff --git a/web/src/lib/components/asset-viewer/asset-viewer-nav-bar.svelte b/web/src/lib/components/asset-viewer/asset-viewer-nav-bar.svelte
index d61af04db6..4a792d7945 100644
--- a/web/src/lib/components/asset-viewer/asset-viewer-nav-bar.svelte
+++ b/web/src/lib/components/asset-viewer/asset-viewer-nav-bar.svelte
@@ -56,6 +56,7 @@
     mdiMagnifyPlusOutline,
     mdiPresentationPlay,
     mdiUpload,
+    mdiVideoOutline,
   } from '@mdi/js';
   import type { Snippet } from 'svelte';
   import { t } from 'svelte-i18n';
@@ -78,6 +79,8 @@
     // export let showEditorHandler: () => void;
     onClose: () => void;
     motionPhoto?: Snippet;
+    playOriginalVideo: boolean;
+    setPlayOriginalVideo: (value: boolean) => void;
   }
 
   let {
@@ -97,6 +100,8 @@
     onShowDetail,
     onClose,
     motionPhoto,
+    playOriginalVideo = false,
+    setPlayOriginalVideo,
   }: Props = $props();
 
   const sharedLink = getSharedLink();
@@ -245,6 +250,15 @@
           {#if !asset.isTrashed}
             
           {/if}
+
+          {#if asset.type === AssetTypeEnum.Video}
+             setPlayOriginalVideo(!playOriginalVideo)}
+              text={playOriginalVideo ? $t('play_transcoded_video') : $t('play_original_video')}
+            />
+          {/if}
+
           
            void 0);
+  let playOriginalVideo = $state($alwaysLoadOriginalVideo);
+
+  const setPlayOriginalVideo = (value: boolean) => {
+    playOriginalVideo = value;
+  };
 
   const refreshStack = async () => {
     if (authManager.isSharedLink) {
@@ -410,6 +415,8 @@
         onPlaySlideshow={() => ($slideshowState = SlideshowState.PlaySlideshow)}
         onShowDetail={toggleDetailPanel}
         onClose={closeViewer}
+        {playOriginalVideo}
+        {setPlayOriginalVideo}
       >
         {#snippet motionPhoto()}
            navigateAsset()}
             onVideoStarted={handleVideoStarted}
+            {playOriginalVideo}
           />
         {/if}
       {/key}
@@ -480,6 +488,7 @@
               onPreviousAsset={() => navigateAsset('previous')}
               onNextAsset={() => navigateAsset('next')}
               onVideoEnded={() => (shouldPlayMotionPhoto = false)}
+              {playOriginalVideo}
             />
           {:else if asset.exifInfo?.projectionType === ProjectionType.EQUIRECTANGULAR || (asset.originalPath && asset.originalPath
                 .toLowerCase()
@@ -510,6 +519,7 @@
             onClose={closeViewer}
             onVideoEnded={() => navigateAsset()}
             onVideoStarted={handleVideoStarted}
+            {playOriginalVideo}
           />
         {/if}
         {#if $slideshowState === SlideshowState.None && isShared && ((album && album.isActivityEnabled) || activityManager.commentCount > 0) && !activityManager.isLoading}
diff --git a/web/src/lib/components/asset-viewer/video-native-viewer.svelte b/web/src/lib/components/asset-viewer/video-native-viewer.svelte
index fd3bc1c44f..2ccfb59243 100644
--- a/web/src/lib/components/asset-viewer/video-native-viewer.svelte
+++ b/web/src/lib/components/asset-viewer/video-native-viewer.svelte
@@ -10,7 +10,7 @@
     videoViewerMuted,
     videoViewerVolume,
   } from '$lib/stores/preferences.store';
-  import { getAssetPlaybackUrl, getAssetThumbnailUrl } from '$lib/utils';
+  import { getAssetOriginalUrl, getAssetPlaybackUrl, getAssetThumbnailUrl } from '$lib/utils';
   import { AssetMediaSize } from '@immich/sdk';
   import { LoadingSpinner } from '@immich/ui';
   import { onDestroy, onMount } from 'svelte';
@@ -21,6 +21,7 @@
     assetId: string;
     loopVideo: boolean;
     cacheKey: string | null;
+    playOriginalVideo: boolean;
     onPreviousAsset?: () => void;
     onNextAsset?: () => void;
     onVideoEnded?: () => void;
@@ -32,6 +33,7 @@
     assetId,
     loopVideo,
     cacheKey,
+    playOriginalVideo,
     onPreviousAsset = () => {},
     onNextAsset = () => {},
     onVideoEnded = () => {},
@@ -48,7 +50,12 @@
   onMount(() => {
     // Show video after mount to ensure fading in.
     showVideo = true;
-    assetFileUrl = getAssetPlaybackUrl({ id: assetId, cacheKey });
+  });
+
+  $effect(() => {
+    assetFileUrl = playOriginalVideo
+      ? getAssetOriginalUrl({ id: assetId, cacheKey })
+      : getAssetPlaybackUrl({ id: assetId, cacheKey });
     if (videoPlayer) {
       videoPlayer.load();
     }
diff --git a/web/src/lib/components/asset-viewer/video-wrapper-viewer.svelte b/web/src/lib/components/asset-viewer/video-wrapper-viewer.svelte
index a5a94d85d4..748886d901 100644
--- a/web/src/lib/components/asset-viewer/video-wrapper-viewer.svelte
+++ b/web/src/lib/components/asset-viewer/video-wrapper-viewer.svelte
@@ -1,13 +1,14 @@