videojs / http-streaming

HLS, DASH, and future HTTP streaming protocols library for video.js
https://videojs-http-streaming.netlify.app/
Other
2.49k stars 421 forks source link

Byte Range requests are not working at all #1441

Closed ghost closed 10 months ago

ghost commented 11 months ago

For some reason byte range requests aren't working at all, VideoJS does simply not attach the Range header to the http request, where other player working perfectly fine with my streaming backend, I tested my config below using various players e.g. the bitmovin player works fine with my setup.

This is how my nginx location looks like:

location /hls {
           proxy_pass http://data_backend/vod;
           proxy_set_header Authorization '';
           add_header Cache-Control "private, no-transform, max-age=7200";
           add_header 'access-control-allow-credentials' 'true';
           add_header 'access-control-allow-origin' $allow_origin;
           # Trick preflight option requests of media players like VideoJS
           if ($request_method = OPTIONS) {
               add_header 'access-control-allow-credentials' 'true';
               add_header 'access-control-allow-headers' 'server,x-goog-meta-frames,content-length,content-type,x-requested-with,if-modified-since,if-none-match,authorization,accept,accept-encoding,accept-language,access-control-request-headers,access-control-request-method,cache-control,connection,dnt,host,pragma,sec-fetch-dest,sec-fetch-mode,sec-fetch-site,sec-gpc,te,user-agent';
               add_header 'access-control-allow-origin' $allow_origin;
               add_header 'content-length' 0;
               return 204;
               }

           # For byte-Range requests
           if ($request_method = GET) {
            proxy_set_header Range $http_range;
            add_header 'Access-Control-Allow-Origin' $allow_origin;
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
            add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
            add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
            }

           if ($invalid_referer){
              return 403;
           }

           if ($request_method !~ ^(GET|HEAD|OPTIONS)$ ){
              return 405;
           }
        }

Can please somebody explain to my what the problem is here? This is definitely a VideoJS problem, and not a problem on server side from my end.

This is how my playlist is structured:

#EXTM3U
#EXT-X-VERSION:7
#EXT-X-PLAYLIST-TYPE VOD

#EXT-X-STREAM-INF:BANDWIDTH=281600,CODECS="mp4a.40.2"
a-aac-mp4a.40.2_256000/master.m3u8

And this is the actually referenced playlist of the Track:

#EXTM3U
#EXT-X-VERSION:7
#EXT-X-TARGETDURATION:4
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-MAP:URI="file.m4s",BYTERANGE="761@0"
#EXTINF:4.017052,
#EXT-X-BYTERANGE:129719@761
file.m4s
#EXTINF:3.993832,
#EXT-X-BYTERANGE:128476@130480
file.m4s
#EXTINF:3.993832,
#EXT-X-BYTERANGE:129024@258956
file.m4s
#EXTINF:4.017052,
#EXT-X-BYTERANGE:129002@387980
file.m4s
#EXTINF:3.993832,
#EXT-X-BYTERANGE:128620@516982
file.m4s
#EXTINF:3.993832,
#EXT-X-BYTERANGE:128658@645602
file.m4s
#EXTINF:3.993832,
#EXT-X-BYTERANGE:128679@774260
file.m4s
#EXTINF:4.017052,
#EXT-X-BYTERANGE:129633@902939
file.m4s
#EXTINF:3.993832,
#EXT-X-BYTERANGE:128594@1032572
file.m4s
#EXTINF:3.993832,
#EXT-X-BYTERANGE:128531@1161166
file.m4s
#EXTINF:3.993832,
#EXT-X-BYTERANGE:128952@1289697
file.m4s
#EXTINF:4.017052,
#EXT-X-BYTERANGE:129014@1418649
file.m4s
#EXTINF:3.993832,
#EXT-X-BYTERANGE:128616@1547663
file.m4s
#EXTINF:3.993832,
#EXT-X-BYTERANGE:128753@1676279
file.m4s
#EXTINF:3.993832,
#EXT-X-BYTERANGE:128640@1805032
file.m4s
#EXTINF:4.017052,
#EXT-X-BYTERANGE:129729@1933672
file.m4s
#EXTINF:3.993832,
#EXT-X-BYTERANGE:128276@2063401
file.m4s
#EXTINF:3.993832,
#EXT-X-BYTERANGE:128627@2191677
file.m4s
#EXTINF:4.017052,
#EXT-X-BYTERANGE:129541@2320304
file.m4s
#EXTINF:3.993832,
#EXT-X-BYTERANGE:128535@2449845
file.m4s
#EXTINF:3.993832,
#EXT-X-BYTERANGE:128885@2578380
file.m4s
#EXTINF:3.993832,
#EXT-X-BYTERANGE:128706@2707265
file.m4s
#EXTINF:4.017052,
#EXT-X-BYTERANGE:129112@2835971
file.m4s
#EXTINF:3.993832,
#EXT-X-BYTERANGE:128891@2965083
file.m4s
#EXTINF:3.993832,
#EXT-X-BYTERANGE:128396@3093974
file.m4s
#EXTINF:3.993832,
#EXT-X-BYTERANGE:128729@3222370
file.m4s
#EXTINF:4.017052,
#EXT-X-BYTERANGE:129493@3351099
file.m4s
#EXTINF:3.993832,
#EXT-X-BYTERANGE:128478@3480592
file.m4s
#EXTINF:3.993832,
#EXT-X-BYTERANGE:128671@3609070
file.m4s
#EXTINF:3.993832,
#EXT-X-BYTERANGE:128690@3737741
file.m4s
#EXTINF:4.017052,
#EXT-X-BYTERANGE:129366@3866431
file.m4s
#EXTINF:3.993832,
#EXT-X-BYTERANGE:128814@3995797
file.m4s
#EXTINF:3.993832,
#EXT-X-BYTERANGE:128440@4124611
file.m4s
#EXTINF:4.017052,
#EXT-X-BYTERANGE:129396@4253051
file.m4s
#EXTINF:3.993832,
#EXT-X-BYTERANGE:129007@4382447
file.m4s
#EXTINF:3.993832,
#EXT-X-BYTERANGE:128293@4511454
file.m4s
#EXTINF:3.993832,
#EXT-X-BYTERANGE:128687@4639747
file.m4s
#EXTINF:4.017052,
#EXT-X-BYTERANGE:129401@4768434
file.m4s
#EXTINF:3.993832,
#EXT-X-BYTERANGE:128664@4897835
file.m4s
#EXTINF:3.993832,
#EXT-X-BYTERANGE:128691@5026499
file.m4s
#EXTINF:3.993832,
#EXT-X-BYTERANGE:128677@5155190
file.m4s
#EXTINF:4.017052,
#EXT-X-BYTERANGE:129341@5283867
file.m4s
#EXTINF:3.993832,
#EXT-X-BYTERANGE:128694@5413208
file.m4s
#EXTINF:3.993832,
#EXT-X-BYTERANGE:128492@5541902
file.m4s
#EXTINF:0.863107,
#EXT-X-BYTERANGE:28659@5670394
file.m4s
#EXT-X-ENDLIST

But VideoJS does not use rage header in its request using this playlist setup. The only thing that is working for me is using independent segments, which is kinda annoying ...

Is somebody using HLS streaming with byte range requests and got it working ?

dzianis-dashkevich commented 11 months ago

Is somebody using HLS streaming with byte range requests and got it working ?

A default example on the VHS demo page is a byte-range example

https://videojs-http-streaming.netlify.app/

Here is the code where vhs attaches range headers if byte-range is presented: https://github.com/videojs/http-streaming/blob/719b7f44d9608de9774aa8f0f56679fd9342501c/src/media-segment-request.js#L1027

and here is the actual code of the function: https://github.com/videojs/http-streaming/blob/719b7f44d9608de9774aa8f0f56679fd9342501c/src/xhr.js#L176

video-archivist-bot commented 11 months ago

Hey! We've detected some video files in a comment on this issue. If you'd like to permanently archive these videos and tie them to this project, a maintainer of the project can reply to this issue with the following commands:

ghost commented 11 months ago

@dzianis-dashkevich I noticed that this is a transport stream (.ts file), but I'm using fragmented mp4 (fmp4/m4s), could this be the issue here? I also noticed that there is not #EXT-X-VERSION Tag or #EXT-X-PLAYLIST-TYPE at the Playlist you mentioned. Can you maybe explain a bit more what the issue is here with my playlist setup? I don't fully understand what triggers the byte range requests using VideoJS.

Please also see:

https://github.com/videojs/http-streaming/blob/719b7f44d9608de9774aa8f0f56679fd9342501c/docs/supported-features.md?plain=1#L99

### HLS Missing Features
->

* Use of [EXT-X-MAP] with [TS] segments
  * [EXT-X-MAP] is currently supported for [MP4] segments, but not yet for TS

So is this now missing or not? The statement is kinda strange as it's part of the missing features section.

Thanks in advance!

dzianis-dashkevich commented 11 months ago

I noticed that this is a transport stream (.ts file), but I'm using fragmented mp4 (fmp4/m4s), could this be the issue here?

It should not be a problem.

I also noticed that there is not #EXT-X-VERSION Tag or #EXT-X-PLAYLIST-TYPE at the Playlist you mentioned.

It should not be a problem as well.

I don't fully understand what triggers the byte range requests using VideoJS

If the m3u8 parser returns a byte range for each segment, VHS should append range headers.

Can you maybe explain a bit more what the issue is here with my playlist setup?

I don't know what might be wrong with your audio-only playlist setup... You can deploy your playlist and provide a publicly available URL to test it on the VHS demo page.

So is this now missing or not? The statement is kinda strange as it's part of the missing features section.

This is probably outdated since vhs supports an initialization section for CMAF streams

you can check this example on the VHS demo page: https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8

video-archivist-bot commented 11 months ago

Hey! We've detected some video files in a comment on this issue. If you'd like to permanently archive these videos and tie them to this project, a maintainer of the project can reply to this issue with the following commands:

ghost commented 11 months ago

Please give me some time, I will provide the data ASAP, thanks so far.

ghost commented 10 months ago

@dzianis-dashkevich You were indeed right, the HLS stream plays well using https://videojs-http-streaming.netlify.app, but I don't understand why it's not working with my setup here ... :( I'm using Angular together with VideoJS 7 and also the latest version of VHS (3.7.0). Is there anything special I have to activate with the player options ???

this.videoJsConfigObj = {
      autoSetup: true,
      fill: false,
      controlBar: {
        volumePanel: {
          inline: false
        },
        fullscreenToggle: false,
      },
      autoplay: true,
      disablePictureInPicture: true,
      controls: true,
      inactivityTimeout: 0,
      fluid: true,
      audioOnlyMode: true,
      preferFullWindow: false,
      preload: 'metadata',
      techOrder: ['html5'],
      html5: {
        nativeControlsForTouch: true,
        nativeAudioTracks: true,
        nativeVideoTracks: true,
        nativeTextTracks: true,
        preloadTextTracks: false,
        vhs: {
          withCredentials: true,
          overrideNative: false,
          bandwidth: 1411000,
          handlePartialData: true,
          maxPlaylistRetries: 10,
          fastQualityChange: true,
          enableLowInitialPlaylist: false,
          limitRenditionByPlayerDimensions: true,
          useDevicePixelRatio: true,
          experimentalBufferBasedABR: false,
          handleManifestRedirects: true,
          useNetworkInformationApi: false,
          cacheEncryptionKeys: true,
          manualCleanup: true,
        },
      }
    }
  }

At the package.json of my Angular application I have:


"@types/video.js": "^7.3.55",
"@videojs/http-streaming": "^3.7.0",
"video.js": "^7.21.5",

Thanks in advance

ghost commented 10 months ago

I found the offending line ... Which is kinda strange ...

I have the following at my VideoJS config:

videojs.Vhs.xhr.beforeRequest = (options: any) => {
      options.headers = { Authorization: this.file_response.access_token }; ### < This appear to be evil here
      options.withCredentials = true;

If I disable the JWT authorization against my media files and also remove options.headers = { Authorization: this.file_response.access_token };

I have no problems at all playing the Media ... Any Idea? Actually I would expect that I can also send the JWT with every byte range request

ghost commented 10 months ago

To get byte-range requests working with an additional Authorization Header you should not overwrite the already existing headers as I did before, Instead we need to trick a bit around the request logic and simply append the Authorization like this:

videojs.Vhs.xhr.beforeRequest = (options: any) => {
      if (!options.headers) {
        options.headers = {}; // Ensure the headers object exists
      }

      // Add the Authorization header without overwriting existing headers
      options.headers['Authorization'] = this.file_response.access_token;

      return options;
    };

Maybe it help somebody else ...

@dzianis-dashkevich Thanks again for your interest in with problem