Chromecast 是否支持投射来自 Reddit 的视频? (HLS 和 Dash 视频)

Does the Chromecast support casting videos from Reddit? (HLS and Dash videos)

使用 URL http://192.168.xx.xx:8080/3hyw7hwoajn21/HLSPlaylist.m3u8 调用了代理 使用 URL http://192.168.xx.xx:8080/3hyw7hwoajn21/HLS_540_v4.m3u8 调用代理 使用 URL http://192.168.xx.xx:8080/3hyw7hwoajn21/HLS_AUDIO_160_K_v4.m3u8 调用代理 使用 URL http://192.168.xx.xx:8080/3hyw7hwoajn21/HLS_224_v4.m3u8

调用代理

这是一个 Reddit 视频示例:https://www.reddit.com/r/me_irl/comments/b3vrs4/me_irl

浏览the JSON,它有几个视频源选项:

"reddit_video": {
    "dash_url": "https://v.redd.it/3hyw7hwoajn21/DASHPlaylist.mpd",
    "duration": 76,
    "fallback_url": "https://v.redd.it/3hyw7hwoajn21/DASH_720?source=fallback",
    "height": 720,
    "hls_url": "https://v.redd.it/3hyw7hwoajn21/HLSPlaylist.m3u8",
    "is_gif": false,
    "scrubber_media_url": "https://v.redd.it/3hyw7hwoajn21/DASH_240",
    "transcoding_status": "completed",
    "width": 1280
}

虽然我似乎可以让其他 HLS/m3u8 视频与 Chromecast SDK 一起工作(例如 Google's own example HLS video),但我似乎无法让这些来源中的任何一个工作。

我试过了 https://v.redd.it/3hyw7hwoajn21/HLSPlaylist.m3u8 with the stream type set to both "live" or "buffered", I've tried the content type as "application/x-mpegURL", and I've tried the same for the dash URL https://v.redd.it/3hyw7hwoajn21/DASHPlaylist.mpd with content type "application/dash+xml" also to no avail. I found this question 这似乎表明有某种可能性?

我还注意到 DASH 文件有一个单独的视频和音频流 (https://v.redd.it/3hyw7hwoajn21/DASH_720 and https://v.redd.it/3hyw7hwoajn21/audio) 最坏的情况是有一种方法可以在 Chromecast 上播放视频流和单独的音频流?

Chromecast 不能播放这些视频类型吗?

更新

Jesse 和 aergistal 认为这与缺少 CORS headers 有关。我构建了一个自定义接收器应用程序以获得更好的调试日志,这确实是(第一个)问题; Chromecast 抱怨 CORS。

我使用 nginx 构建了一个添加所有 CORS headers 的本地反向代理,然后我将代理 URL 提供给 Chromecast,此 CORS 错误消失了。

然而,使用 HLS/m3u8 link 它仍然无法播放。现在它抱怨以下内容:

[cast.player.hls.PackedAudioParser] Neither ID3 nor ADTS header was found at 0

[cast.player.api.Host] error: cast.player.api.ErrorCode.NETWORK/315

[cast.receiver.MediaManager] Load metadata error: Error

完整日志:

这导致它仍然无法播放。有什么想法吗?

添加 CORS 问题允许 DASHPlaylist.mpd 变体加载(以前不会),这很好,但同时不是很好,因为反向代理需要您下载整个响应首先,DASH URL 只是一个完整的 MP4(而 HLS 是字节范围),这意味着反向代理必须先下载整个 DASH 视频才能显示它,与 HLS 相比,这需要很长时间。

因此,由于速度的原因,让 HLS 正常工作仍然是最佳选择,但是由于 Chromecast 上的播放问题,它注定无法正常工作吗?

结论

最合乎道德的答案是与 Reddit 合作,确保他们设置正确的 CORS header。 Google 文档中需要 CORS header。

模拟您的问题

使用此测试仪:

https://developer.jwplayer.com/tools/stream-tester/

它模拟了您在使用 Chromecast SDK 的代码中获得的一些相同体验。 Google 视频在没有 Playready DRM 设置的情况下播放,但 reddit 视频没有(在大多数浏览器中)。

MS EDGE 和 jwplayer

如果您 select Playready 并为 Playready url 添加任何内容,即使留空,它也适用于 M3U8。

Internet Explorer 和 jwplayer

Error, 232011 A manifest request was made without proper crossdomain credentials. Cannot load M3U8: Crossdomain access denied. This video cannot be played because of a technical error.

这表明 reddit 服务器上可能未启用 CORS。更多内容见下文。

Firefox 和 jwplayer

似乎没有任何东西适用于 jwplayer。

Chrome 和 jwplayer

不适用于 jwplayer。

Safari 和 jwplayer 播放器

您表示无需设置任何 DRM 设置即可运行。

iPhone/Apple电视

我试过了,m3u8 视频可以使用 AirPlay 直接从我的 phone 投射到 Apple TV (4K)。

模拟总结

所有 M3U8 视频都可以通过 Airplay 从 iPhone 流式传输到 AppleTV。它似乎适用于 Edge,也适用于 Safari,所以它可能仅适用于 Reddit 已接受通过 airplay 的 Apple 流媒体服务,但不接受 Chromecast。不太确定,但还能如何解释呢?如果有人能提供更多说明就更好了。

根本原因分析

请注意您分享的 google link 包括此 header:

Access-Control-Allow-Origin

它被设置为 *(又名。所有),这意味着服务器将与 Internet 上的任何域共享请求的资源。

https://tools.geekflare.com/report/cors-test/https://commondatastorage.googleapis.com/gtv-videos-bucket/CastVideos/hls/DesigningForGoogleCast.m3u8

reddit link 没有 header,这意味着 CORS 未启用以允许资源共享,这意味着它无法正常工作。

CORS 的描述 header https://www.codecademy.com/articles/what-is-cors

The Access-Control-Allow-Origin header allows servers to specify how their resources are shared with external domains. When a GET request is made to access a resource on Server A, Server A will respond with a value for the Access-Control-Allow-Origin header. Many times, this value will be *, meaning that Server A will share the requested resources with any domain on the Internet. Other times, the value of this header may be set to a particular domain (or list of domains), meaning that Server A will share its resources with that specific domain (or list of domains). The Access-Control-Allow-Origin header is critical to resource security.

有几个资源表明必须从服务器端启用 CORS:

https://whosebug.com/a/28360045/9105725

https://help.ooyala.com/video-platform/concepts/cors_enablement.html

甚至 Google 说这些 header 需要设置: https://developers.google.com/cast/docs/chrome_sender/advanced

CORS requirements For adaptive media streaming, Google Cast requires the presence of CORS headers, but even simple mp4 media streams require CORS if they include Tracks. If you want to enable Tracks for any media, you must enable CORS for both your track streams and your media streams. So, if you do not have CORS headers available for your simple mp4 media on your server, and you then add a simple subtitle track, you will not be able to stream your media unless you update your server to include the appropriate CORS header. In addition, you need to allow at least the following headers: Content-Type, Accept-Encoding, and Range. Note that the last two headers are additional headers that you may not have needed previously.

具有独立音轨的 HLS 解决方案


根据最新日志中的信息,所选片段格式与流中使用的实际格式不匹配。该流在 MPEG-TS 中使用 AAC,而 Cast SDK 尝试将其解析为打包音频。

Cast 问题跟踪器上的 reply 显示如果流被多路复用,HlsSegmentFormat 默认为 MPEG2_TS,否则 MPEG_AUDIO_ES

CAF 接收器的建议解决方案是拦截加载请求并使用 loadRequestData.media.hlsSegmentFormat = cast.framework.messages.HlsSegmentFormat.TS 覆盖段格式。稍微修改的示例:

<html>
<head>
</head>
<body>
  <cast-media-player id="player"></cast-media-player>
  <script type="text/javascript" src="//www.gstatic.com/cast/sdk/libs/caf_receiver/v3/cast_receiver_framework.js">
  </script>
  <script>
    const context = cast.framework.CastReceiverContext.getInstance();
    const playerManager = context.getPlayerManager();
    // intercept the LOAD request
    playerManager.setMessageInterceptor(
        cast.framework.messages.MessageType.LOAD, loadRequestData => {
            loadRequestData.media.hlsSegmentFormat = cast.framework.messages.HlsSegmentFormat.TS;
            return loadRequestData;
        });
    context.start();
  </script>
</body>
</html>

Original source

Yet another example


CORS 解决方案


Google Cast reference给你解决方案:

If you're having problems playing streams on a Cast device, it may be an issue with CORS. Use a publicly available CORS proxy server to test your streams

公开可用代理的问题在于,出于带宽考虑,它们会强制执行大小限制,因此请自行制作或使用 open-source。如果该应用程序在移动设备上运行,您还可以将其设为本地服务器。

当前流不受 DRM 保护。如果他们添加 CDN 身份验证或使用 DRM 保护流,这将变得更加复杂或完全不可能。


关于 CORS headers,您必须确保支持预检请求:客户端可能会先发送 OPTIONS 来检查 CORS 支持(包括允许的方法和 headers)。

您的流还必须支持 HTTP 范围请求,这意味着必须授权和公开适当的 headers。

来自 https://enable-cors.org 的预检请求配置示例:

Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET,POST,OPTIONS
Access-Control-Allow-Headers: DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range
Access-Control-Expose-Headers: Content-Length,Content-Range


您至少需要允许:GETOPTIONSContent-TypeRange headers,并公开 Content-LengthContent-Range.如果远程服务器提供,则删除重复项 headers。