tauri-apps / tauri

Build smaller, faster, and more secure desktop and mobile applications with a web frontend.
https://tauri.app
Apache License 2.0
85.45k stars 2.58k forks source link

[bug] MacOS Problem with playing video from resources in the format webm. #5605

Open Bukmopbl4 opened 2 years ago

Bukmopbl4 commented 2 years ago

Describe the bug

I noticed an unpleasant bug when loading video from resources in the format webm. The video takes a super long time to load thousands of requests byte by byte. Bytes range is abnormal like "Range: bytes=1010843-1010843". In Dev and Prod. Same Video in mp4 format is loaded with correct chunks and playing normally.

I used resolveResource and convertFileSrc.

https://user-images.githubusercontent.com/19820469/201137488-af07be82-e658-4b47-94aa-c9de33cf36bd.mp4

Reproduction

No response

Expected behavior

No response

Platform and versions

Environment › OS: Mac OS 13.0.0 X64 › Node.js: 16.17.1 › npm: 8.15.0 › pnpm: Not installed! › yarn: Not installed! › rustup: 1.25.1 › rustc: 1.64.0 › cargo: 1.64.0 › Rust toolchain: stable-x86_64-apple-darwin

Packages WARNING: no lock files found, defaulting to npm › @tauri-apps/cli [NPM]: 1.2.0 › @tauri-apps/api [NPM]: Not installed! › tauri [RUST]: 1.2.0, › tauri-build [RUST]: 1.2.0, › tao [RUST]: 0.15.2, › wry [RUST]: 0.22.0,

App › build-type: bundle › CSP: unset › distDir: ../src › devPath: ../src package.json not found

App directory structure ├─ src-tauri ├─ .git ├─ .vscode └─ src

Stack trace

No response

Additional context

No response

Bukmopbl4 commented 2 years ago

I think this is exclusively a problem of the custom protocol, since on local server http://127.0.0.1:1430/ it works without problems.

amrbashir commented 2 years ago

Seems to work fine on Windows, so I will mark this as a macOS issue.

when you are using a dev-server, is the range headers also weird?

Bukmopbl4 commented 2 years ago

when you are using a dev-server, is the range headers also weird?

image

I have a same problem on DEV

Bukmopbl4 commented 2 years ago

I tried to play the video as date link in base64 and it works with anything, but it doesn't work with webm format. Feeling that this is a problem specifically with playback in the format webm vp9 codec

Bukmopbl4 commented 2 years ago

Seems to work fine on Windows

On Windows, the video webm is played as needed from assets in any form and with transparency.

Bukmopbl4 commented 2 years ago

but if I use external link it loads with 2 requests and i can play video.

image

there is some problem if it is a video tag on the local page.

amrbashir commented 2 years ago

when you are using a dev-server, is the range headers also weird?

image

I have a same problem on DEV

I meant serving the file through a localhost server not through asset protocol

Bukmopbl4 commented 2 years ago
image

it works on DEV through a localhost server but without alpha-channel support like on Windows

Owez commented 1 year ago

Looks like im having the same issue at the moment, im serving webm files from an api to my app and it has really strange results (everything here is webm, for some reason only one video plays. these all work fine in firefox whilst using the dev server):

https://user-images.githubusercontent.com/30081702/221376074-0c055482-fb66-4b8c-a005-fedd8c766f8f.mov

@Bukmopbl4 Did you find a fix for your issue in the end?

Owez commented 1 year ago

I can confirm that its just the webm container format and nothing to do with the videos themselves. If you convert all input videos into mp4 (e.g., using ffmpeg) they work perfectly fine when streaming from a server. This is a decent workaround for now because copying the containers is relatively quick and won't destroy video quality.

My core library is in Python and luckily I already have a converter for input videos, so I just adapted it for mp4 files. Doing a simple container codac copying (like this) is all that's needed. Example converter here:

https://github.com/Owez/yark/blob/f67232073c2560a623b434b64734cf168d766a95/yark/yark/archiver/converter.py#L10

Bukmopbl4 commented 1 year ago

I can confirm that its just the webm container format and nothing to do with the videos themselves. If you convert all input videos into mp4 (e.g., using ffmpeg) they work perfectly fine when streaming from a server. This is a decent workaround for now because copying the containers is relatively quick and won't destroy video quality.

My core library is in Python and luckily I already have a converter for input videos, so I just adapted it for mp4 files. Doing a simple container codac copying (like this) is all that's needed. Example converter here:

https://github.com/Owez/yark/blob/f67232073c2560a623b434b64734cf168d766a95/yark/yark/archiver/converter.py#L10

mp4 does not have transparency support. webm (vp9) is required.

stavros-k commented 2 days ago

I've got the opposite issue webm works, mp4 does not. And yes it seems to be the custom protocol. Same issue is experienced in go-wails

      <video
        src="/bg-video.webm"
        autoPlay
        loop
        muted
        playsInline
        className="bg-video"
      />

      <video
        src="/bg-video.mp4"
        autoPlay
        loop
        muted
        playsInline
        className="bg-video"
      />
image image
Bukmopbl4 commented 2 days ago

I no longer remember how I solved this issue for that old project. It's not a fact that it's still relevant for version 2. I can suggest specifying which codec you need for the video tag, as that might make a difference. In my current projects, I don't use a custom protocol anymore; instead, I implemented a solution using Warp. Moreover, I don't just work with files individually—I use a single data file with encryption that contains all my resources at once. Through Warp, I serve them according to the metadata offsets within this file. It turned out great and works perfectly with any type of file.

stavros-k commented 1 day ago

You mean you spin an "embedded" http server? How can you ensure the port is going to be free? Do you bind a random one and then pass it up to the frontend?

Well that should work, but I believe Apple (which looks like its on their side) should fix this issue. Why would someone do 1. such small range requests, the overhead is huge. 2. Repeat the file fetch unlimited times. It seems that this bug is at least 2 years old. :(

I don't even care about macos, the app I'm making is very specific and will run on windows (which works fine!) I just do dev on mac, and noticed it. Commented to add that is experienced on another framework (Wails) as well. And therefore is most likely Apple's issue and not tauri's

Bukmopbl4 commented 1 day ago

You mean you spin an "embedded" http server? How can you ensure the port is going to be free? Do you bind a random one and then pass it up to the frontend?

Well that should work, but I believe Apple (which looks like its on their side) should fix this issue. Why would someone do 1. such small range requests, the overhead is huge. 2. Repeat the file fetch unlimited times. It seems that this bug is at least 2 years old. :(

I don't even care about macos, the app I'm making is very specific and will run on windows (which works fine!) I just do dev on mac, and noticed it. Commented to add that is experienced on another framework (Wails) as well. And therefore is most likely Apple's issue and not tauri's

In my case, I seamlessly switched to a local Warp server instead of a custom protocol, and it actually turned out better than I expected. I didn’t bother with the port because I’m writing specific applications for specific needs where being universal in terms of port selection isn’t necessary, but I also don’t see it as a problem. I haven’t looked into how this issue stands in version 2 for a while. I’ll need to set aside some time to check it. Have you tried specifying a codec for the video tag?

Bukmopbl4 commented 1 day ago

I tested it on Tauri version 2. The issue persists for the release version using the tauri: protocol. WebM works flawlessly, but MP4 plays while causing the network to transfer gigabytes, even though the video is only 5 MB. It's creating some sort of chaos with ranges. This happens on macOS.

Bukmopbl4 commented 1 day ago

Try not to set the src directly. Instead, on page load, perform a fetch request for the video, place the bytes into a blob:, and then assign it to the video tag. In this case, the video plays correctly, and 206 Partial Content responses seem to work properly without generating gigabytes of traffic.

stavros-k commented 1 day ago

Unfortunately this is not working

import { useEffect, useState } from "react";

export const BackgroundVideo = () => {
  const [url, setUrl] = useState<string | null>(null);

  useEffect(() => {
    const fetchVideo = async () => {
      try {
        const response = await fetch("/videos/bg-video.mp4");
        const blob = await response.blob();
        const objectUrl = URL.createObjectURL(blob);
        setUrl(objectUrl);

        return () => {
          URL.revokeObjectURL(objectUrl);
        };
      } catch (error) {
        console.error("Error loading background video:", error);
      }
    };

    fetchVideo();
  }, []);

  if (!url) {
    return <div className="absolute inset-0 w-full h-full bg-amber-50 z-0" />;
  }

  return (
    <div className="absolute inset-0 w-full h-full bg-amber-50 z-0">
      <video
        src={url}
        loop
        muted
        autoPlay
        playsInline
        className="w-full h-full object-cover"
      />
    </div>
  );
};

export default BackgroundVideo;

If I console log fetching, it indeed only runs once.

On the asset server I can see it fetches it once. But network tab on inspector says otherwise

image

Yes this test was under different framework (wails), I'll test with tauri in a few. Sure enough same on tauri

image