1

I can't seem to get my basic mp4 video streaming server to work on mobile IOS Safari/Chrome. It works fine on desktop chrome, but only shows the video player and controls with a black screen on IOS Safari.

I found some information talking about specifying mime types, byte ranges, and headers, but It seems like I have already done everything necessary?

What else do I need to do to get my mp4 video to stream to mobile IOS Safari?

Server:

const gridfsBucket = new mongoose.mongo.GridFSBucket(conn, {
      bucketName: `bucketName`,
    });

    const range = req.headers.range;

    if (!range) {
      res.status(400).send("Requires Range header");
    }
    
    const videoSize = video.length;
    const start = Number(range.replace(/\D/g, ""));
    const end = videoSize - 1;
    const contentLength = end - start + 1;
    
    const headers = {
      "Content-Range": `bytes ${start}-${end}/${videoSize}`,
      "Accept-Ranges": "bytes",
      "Content-Length": contentLength,
      "Content-Type": "video/mp4",
    };

    res.writeHead(206, headers);

    const downloadStream = gridfsBucket.openDownloadStream(
      ObjectId(_id),
      {
        start,
        end: videoSize,
      }
    );

    downloadStream.pipe(res);
  }

HTML5 Video:

<video controls muted playsInline>
  <source
    src={`/api/main/stream/video/${_id}`}
    type="video/mp4"
  />
</video>

IOS Safari:

Broken

twominds
  • 1,084
  • 5
  • 20
  • **(1)** Does _"...Works fine in Desktop"_ mean Safari browser running on a Apple desktop? **(2)** Without using **GridFS-Stream**, does the same MP4 file work okay in mobile iOS Safari? (put file on your website server and test). – VC.One Apr 11 '22 at 13:29
  • @VC.One It works on desktop chrome, but does not work on mobile IOS safari/chrome. I am not going to try that second thing you said because it has nothing to do with the question. – twominds Apr 11 '22 at 15:29
  • **(1)** _"It works on desktop Chrome"_ but why not confirm that it also works on desktop Safari? If you've never seen it work on **desktop Safari** don't be surprised if it also doesn't work on **mobile Safari**. **(2)** Okay no worries if not related to Question. My logic was since MP4 is **not a streaming** format (is designed for progressive downloads), so using ` – VC.One Apr 13 '22 at 14:00
  • @VC.One I was very specific when formulating this question. Deviation from the scope of this question will only result in time wasted. I am simply trying to stream a MP4 video using gridfs-stream to a mobile device using IOS safari. The question is simple, what specifically is the reason why it is not working according to my code? – twominds Apr 13 '22 at 18:34
  • _"I am simply trying to stream a MP4 video using gridfs-stream to a mobile device using IOS safari"_ I hear you but since **you're the only one with access to the stream** (no demo page for us to check) you'll have to do some tests... **(1)** Make sure the "pipe" methods is not blocked on iOS. The fastest test is a **progressive** download by providing a file URL (is a data **pointer**) to a ` – VC.One Apr 13 '22 at 23:22
  • ...That would be your first possible solution. Otherwise you might have to just buffer (store) the incoming bytes as chunks and then play them via **Media Source Extensions** **(2)** Make sure the codec(s) inside the MP4 are supported on the iOS device (is it H265 tested on older device? Is it VP9 codec recorded into MP4?). See how many [codecs that can be contained in an MP4](https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Video_codecs#common_codecs) – VC.One Apr 13 '22 at 23:32
  • _" The question is simple, what specifically is the reason why it is not working according to my code?"_ It works (on desktop Chrome) therefore nothing wrong with your code. You can see the complication is on iOS side. Either your data is incorrect (wrong codec) or iOS does not support byte streams on iOS. You can achieve same result by sending (from Grid-FS) the data as fragmented MP4 format. Then you can simply send frames (as incoming byte chunks) to the video decoder (using MSE). iOS supports MSE. You chose to stream so process the video like a stream of bytes and decode (correct) chunks – VC.One Apr 13 '22 at 23:41
  • During upload, I use FFMPEG to transcode all video files into MP4 using libx264 and libmp3lame. So we can be sure that the codec and container isn't the issue. I've seen many examples of people byte streaming mp4's to IOS safari using PHP, so I don't think that is the issue either. I feel like the solution to this issue isn't as complicated as we think. – twominds Apr 14 '22 at 00:51
  • **(1)** Why is **libmp3lame** involved in this? Most systems expect AAC audio inside MP4. In Chrome (PC) I used to get silent playback if my MP4 has MP3 audio (will check later if things have changed). See if giving iOS an MP4 with AAC will make it play the video. **(2)** _"During upload..."_ can you not just download one of these files and test in a video tag. A simple test of 2 video tags, one loading from Grid-FS and another tag loading same file copy from your own page server? Which one works? If none, then you know it's a codec issue. Only MediaSource playback allows mixing of a/v codecs – VC.One Apr 20 '22 at 18:05
  • @VC.One Ok, I will try that, I might update you later today because I got in a refactoring mode with my entire codebase. – twominds Apr 20 '22 at 18:11
  • @VC.One So I just tried using "aac" with "libx264" but it didn't work. I also tried using "libvpx-vp9" and "libopus" for webm, but that didn't work either. – twominds Apr 25 '22 at 01:20

0 Answers0