'MP4 Video - Safari -> Cloudflare -> nginx -> Rails = No Play

I've seen quite a number of similar questions and issues regarding this, and I've come to the conclusion that it's a problem with Safari requiring a 206 response, rather than 200.

It's currently Cloudflare returning a 200, rather than a 206, but I'm not entirely certain I have everything set up properly elsewhere, either.

This is my Rails controller method that serves the videos:

def videos file_name = params.fetch(:filename, '') file_path = "#{Rails.root}/app/assets/videos/#{file_name}.#{params.fetch(:extension, '')}" raise ActionController::RoutingError, 'Not Found' unless file_name.index('/').nil? && File.exist?(file_path) send_file(file_path, type: 'video/mp4', disposition: 'inline', status: (request.headers['Range'].present? ? 206 : 200)) end

Basically it checks to see if there are any /'s in the file name (to avoid any security issues... all videos being served in this fashion are in the same folder on the server), and ensure the file exists, then uses send_file to deliver it, and if the 'Range' header is present, returns the 206 status, otherwise 200.

I think this is correct... and the nginx config is very simple, basically just passing through to puma, but I'm not at all clear that it matters, as the 'Range' header doesn't seem to be making it through Cloudflare to my server, regardless (I dumped headers and didn't see anything about 'Range').

The encoding is right, the content/mime type is right, it works fine on Chrome & Firefox, everything seems great except it just doesn't play in Safari.

I've spent a good part of today trying to figure this out and I've tried a ton of different things, but I simply have no further ideas.

How do I make this stupid thing work on Safari?



Solution 1:[1]

This curiously specific title was exactly my situation. I confirmed the issue per Apple's guide, listed below, and verified I was downloading the whole file, and after the fix only the first chunk.

curl --range 0-99 http://example.com/test.mov -o /dev/null

I resolved my Safari .mp4 playback by changing my gzip compression settings in my nginx.conf, to remove gzip compression of .mp4 files.

Here's the block in nginx for reference. (Note: depending on how your app is configured, you may need to change the location line to location ~ \.mp4$ {

location ~ ^/(assets|system|videos)/  {
   expires max;
   add_header Cache-Control public;
   add_header ETag "";
   gzip on;
   gzip_http_version 1.1;
   gzip_vary on;
   gzip_comp_level 6;
   gzip_proxied any;

   # Reference configuration
   #gzip_types text/plain text/html text/css application/json application/javascript application/x-javascript text/javascript video/mp4 application/mp4 image/jpeg image/png image/svg+xml application/x-font-ttf application/x-font-truetype application/font-woff application/font-woff2 application/vnd.ms-fontobject;

   # Kelton trying to fix cloudflare by removing the mp4 settings
   gzip_types text/plain text/html text/css application/json application/javascript application/x-javascript text/javascript image/jpeg image/png image/svg+xml application/application/x-font-ttf application/x-font-truetype application/font-woff application/font-woff2 application/vnd.ms-fontobject;
}

Link to Apple documentation reference: https://developer.apple.com/library/archive/documentation/AppleApplications/Reference/SafariWebContent/CreatingVideoforSafarioniPhone/CreatingVideoforSafarioniPhone.html#//apple_ref/doc/uid/TP40006514-SW6

Solution 2:[2]

Before you start changing your nginx config, you might want to check if your mp4 is using a codec supported by all of the major browser vendors.

Case in point: I was creating a background video for a WordPress site using this ffmpeg command:

ffmpeg -i input.mov -vcodec libx265 -crf 32 -an output.mp4

When I uploaded it, WordPress gave me this error and the video would not play:

Media error: Format(s) not supported or source(s) not found

I incorrectly assumed it was an issue with Cloudflare or nginx. The problem is, at least at this point in time, only Microsoft Edge (version 16 and later) and Safari (version 11 and later) support H.265. I should have used H.264:

ffmpeg -i input.mov -vcodec libx264 -crf 32 -an output.mp4

I reuploaded the video and it worked fine.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Tyler