HTML5视频标签无法在iOS上使用(iPhone)

发布于 2025-01-24 17:20:53 字数 3297 浏览 1 评论 0原文

上下文

我正在尝试在Edge浏览器中播放视频。 项目框架是
.NET 6 MVCvue客户端
.NET 6 WebAPI服务器端

客户的VUE组件将与范围标头(1MB)一起发送请求,以请求零碎的MP4,并使用媒体源扩展(MSE)将arraybuffer附加到bloburl,指向video.src

这样的

var mediaSource = new MediaSource;
mediaSource.addEventListener('sourceopen', sourceOpen);
video.src = URL.createObjectURL(mediaSource);

这种情况在Window的边缘效果很好,,但 iPhone 上没有起作用(iPhone SE 的Edge浏览器测试)
视频标签不起作用,只显示一个空白页。
图片来自iPhone SE(边缘版本100.0.1185.50)

在Window的边缘版本100.0.1185.50
上正常工作 来自窗口10的图像

我尝试过的尝试解决方案

,我尝试添加playsInline prop prop prop prop op toide tag和 html5视频标签在Safari,iPhone和iPad中不起作用,但仍然没有起作用。

代码段

vue组件的方法是bellow的:

    /*
         * check the videoId is equal to course or not.
         * if not, fetch new video stream, and create blob url to this.videoUrl
         */
        async displayVideo() {
          if (this.videoId != this.course) {
            //common.loader.show("#255AC4", 1.5, "Loading...");
            this.videoId = this.course;
    
            let video = document.querySelector("video");
            let assetURL = FrontEndUrl + `/Stream/${this.videoId}`;
            let mimeCodec = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"';
            let sourceBuffer;
            let chunkSize;
            let contentRange;
            let loop;
            let index;
    
            const token = common.cookieManager.getCookieValue(`signin`);
    
            if ('MediaSource' in window && MediaSource.isTypeSupported(mimeCodec)) {
              let mediaSource = new MediaSource;
              mediaSource.addEventListener('sourceopen', sourceOpen);
              video.src = URL.createObjectURL(mediaSource);
            } else {
              console.error('Unsupported MIME type or codec: ', mimeCodec);
            }
    
            function sourceOpen() {
              // chunkSize set to 1MB
              chunkSize = 1024 * 1024 * 1;
    
              // index set to 1 because the fetchNextSegment start from second fragment
              index = 1;
    
              // 取出 mediaSource 並且把sourceBuffer加上 updateend event
              let mediaSoruce = this;
              sourceBuffer = mediaSoruce.addSourceBuffer(mimeCodec);
              sourceBuffer.addEventListener("updateend", fetchNextSegment);
    
              fetchArrayBuffer(assetURL, chunkSize * 0, appendBuffer);
    
              // 
              

Context

I am trying to play a video in edge browser.
The project framework is
.NET 6 MVC and VUE for client side
.NET 6 WebApi for server side

the client's Vue component will send request with range header (1MB) to request fragmented MP4, and use media Source extension(MSE) to append arrayBuffer to the blobUrl that point to video.src.

like this

var mediaSource = new MediaSource;
mediaSource.addEventListener('sourceopen', sourceOpen);
video.src = URL.createObjectURL(mediaSource);

This works fine in window's EDGE, BUT didn't work on iPhone (tested by iPhone SE's edge browser)
the video tag didn't work, it only show a blank page.
image from iPhone SE (EDGE Version 100.0.1185.50)
enter image description here

Works fine on window's EDGE Version 100.0.1185.50
image from window 10
enter image description here

Tried Solution

I had tried add playsinline prop to video tag and other solutions in HTML5 Video tag not working in Safari , iPhone and iPad, but still didn't work.

Code Snippet

The Vue Component's method is as bellow:

    /*
         * check the videoId is equal to course or not.
         * if not, fetch new video stream, and create blob url to this.videoUrl
         */
        async displayVideo() {
          if (this.videoId != this.course) {
            //common.loader.show("#255AC4", 1.5, "Loading...");
            this.videoId = this.course;
    
            let video = document.querySelector("video");
            let assetURL = FrontEndUrl + `/Stream/${this.videoId}`;
            let mimeCodec = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"';
            let sourceBuffer;
            let chunkSize;
            let contentRange;
            let loop;
            let index;
    
            const token = common.cookieManager.getCookieValue(`signin`);
    
            if ('MediaSource' in window && MediaSource.isTypeSupported(mimeCodec)) {
              let mediaSource = new MediaSource;
              mediaSource.addEventListener('sourceopen', sourceOpen);
              video.src = URL.createObjectURL(mediaSource);
            } else {
              console.error('Unsupported MIME type or codec: ', mimeCodec);
            }
    
            function sourceOpen() {
              // chunkSize set to 1MB
              chunkSize = 1024 * 1024 * 1;
    
              // index set to 1 because the fetchNextSegment start from second fragment
              index = 1;
    
              // 取出 mediaSource 並且把sourceBuffer加上 updateend event
              let mediaSoruce = this;
              sourceBuffer = mediaSoruce.addSourceBuffer(mimeCodec);
              sourceBuffer.addEventListener("updateend", fetchNextSegment);
    
              fetchArrayBuffer(assetURL, chunkSize * 0, appendBuffer);
    
              // ???? 這裡會報一個 DOM interact 的 錯誤
              //video.play();
            }
    
            function fetchNextSegment() {
              if (index > loop) {
                sourceBuffer.removeEventListener("updateend", fetchNextSegment);
                return;
              }
    
              fetchArrayBuffer(assetURL, chunkSize * index, appendBuffer);
    
              index++;
            }
    
            function fetchArrayBuffer(url, range, appendBuffer) {
              fetch(url, {
                headers: {
                  "Range": `bytes=${range}-`,
                  "Authorization": `Bearer ${token}`,
                }
              })
                .then(response => {
                  if (!loop) {
                    contentRange = response.headers.get("x-content-range-total");
                    loop = Math.floor(contentRange / chunkSize);
                  }
    
                  return response.arrayBuffer();
                })
                .then(data => { appendBuffer(data) });
            }
    
            function appendBuffer(videoChunk) {
              if (videoChunk) {
                sourceBuffer.appendBuffer(videoChunk);
              }
            }
    
            // ???? 這是原本舊的方式,此方式無法附上 JWT token
            // this.videoUrl = await this.fetchVideoStream(this.videoId); //FrontEndUrl + `/Stream/${this.videoId}`;
    
            //common.loader.close();
          }
        },

And My Vue's template

    <p-card>
              <template #header>
              </template>
              <template #title>
                  <h2>課程名: {{courseName}}</h2>
              </template>
              <template #subtitle>
              </template>
              <template #content>
              <video id="video" style="width: 100%; height: auto; overflow: hidden;" :key="videoUrl" v-on:loadeddata="setCurrentTime" v-on:playing="playing" v-on:pause="pause" controls autoplay playsinline>
              </video>
              </template>
              <template #footer>
              版權所有.轉載必究
              </template>
              </p-card>

I also had logs in machine, but the logs was normal.

Does anyone know why it can's work on the iOS's EDGE? Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

别把无礼当个性 2025-01-31 17:20:53

摘要

我可以使用mse 中,发现原因是iPhone的 ios确实不支持MSE (媒体源扩展)。所以MSE不起作用。

来自我可以使用MSE
的图像

解决方案

iPhone的iOS支持 hls> hls> hls “ https://developer.apple.com/streaming/examples/” rel =“ nofollow noreferrer”> apple dev docs ),因此您需要将MP4转换为 hls 格式。 (可以使用 bento4 hls

Summary

After checked at Can I use MSE, found the reason is the IOS of iPhone does not support MSE (Media Source Extension). So the MSE didn't work.

an image from Can I use MSE
enter image description here

Solution

The iPhone's iOS support HLS originally (apple dev docs), so you need to convert the MP4 to HLS format.(can use bento4 HLS)
???? MP4 format must be fMP4 format

After converted, the HLS format output directory will look like this
enter image description here

The filename extension should be .m3u8, and the master.m3u8 is a doument that describe the video's all information.

Then let the video tag's src attribute point to the HLS resource's URL(master.m3u8).
like this sample code

<video src="https://XXX/master.m3u8">
</video>

Also can use the videoJS library, the srcObject's type is "application/x-mpegURL"

   var player = videojs("videoId");
   if (this.iOS()) {
        // ⚠ 驗證會失敗 還不清楚原因,有確定後端 驗證 是正常的
        //const token = common.cookieManager.getCookieValue(`signin`);
        url = FrontEndUrl + `/Media/Video/${this.videoId}/master.m3u8`;
        srcObject = { src: url, type: "application/x-mpegURL" }
      }

      try {
        player.src(srcObject);
        player.play();
      } catch (e) {
        alert(e.message);
        console.log(e);
      }

a simple HLS demo on github page
But this demo use the hls.js not video.js

<iframe width="auto" src="https://s780609.github.io/hlsJsDemo/">
</iframe>

Reference of bento4

Convert to HLS format command example
???? -f: force to replace the old file
     -o: output directory

mp4hls -f -o [output directory] [source mp4 file]
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文