Mp4 video not playing on Safari on iOS, works on desktop

I’m trying to embed some short video-only MP4s in posts on Ghost 5.94, similar to how Ghost’s ActivityPub blog has been doing recently. Ghost’s videos play fine on Safari on my iPhone, but my own video does not.

I inspected the HTML used by Ghost’s ActivityPub blog vs my own, and both use the same attributes: loop, autoplay, muted playsinline. I’ll paste those both below.

So, I suspected maybe the issue was not with the HTML, but the video format itself. So I used ffprobe to review the details of my file vs a sample from Ghost’s ActivityPub blog that works.

Both are MP4 files using h264. Both contain a video stream and no audio stream. The one difference I see if that my file uses a “Constrained Baseline” profile, while Ghost’s file uses the “High” profile. But the “Constrained Baseline” profile is part of the WebRTC spec, which I expect that Safari supports.

I tried disabling looping. This caused the controls to appear as expected, but when “play” is pressed, nothing happenings.

Compare:

ffprobe output

For Ghost’s file:

Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'activitypub-demo-drawer-nav-2.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    encoder         : Lavf59.16.100
  Duration: 00:00:16.37, start: 0.000000, bitrate: 1357 kb/s
  Stream #0:0[0x1](und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, smpte170m/smpte170m/bt709, progressive), 1628x1080, 1354 kb/s, 60 fps, 60 tbr, 11520 tbn (default)
      Metadata:
        handler_name    : mp4-muxer-hdlr
        vendor_id       : [0][0][0][0]

For my file:

Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'fuzzel-fzf.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    encoder         : Lavf61.1.100
  Duration: 00:00:08.47, start: 0.000000, bitrate: 1275 kb/s
  Stream #0:0[0x1](und): Video: h264 (Constrained Baseline) (avc1 / 0x31637661), yuvj420p(pc, progressive), 2560x1440 [SAR 1:1 DAR 16:9], 1273 kb/s, 18.19 fps, 90k tbr, 90k tbn (default)
      Metadata:
        handler_name    : VideoHandler
        vendor_id       : [0][0][0][0]

The issue was resolved by re-encoding the file with ffmpeg’s default settings, like this:

 ffmpeg -i old.mp4 NEW.mp4

And here’s the result of analyzing the re-encoded file with ffprobe:

Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'fuzzel-fzf-NEW.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    encoder         : Lavf61.1.100
  Duration: 00:00:08.63, start: 0.000000, bitrate: 458 kb/s
  Stream #0:0[0x1](und): Video: h264 (High) (avc1 / 0x31637661), yuvj420p(pc, progressive), 2560x1440 [SAR 1:1 DAR 16:9], 455 kb/s, 18.19 fps, 18.19 tbr, 165k tbn (default)
      Metadata:
        handler_name    : VideoHandler
        vendor_id       : [0][0][0][0]
        encoder         : Lavc61.3.100 libx264

The primary difference I notice after re-encoding is that the profile was updated from “Constrained Baseline” to “High”.

The app that originally generated the problematic file was wf-recorder, a Linux CLI screen recorder. I’ll leave a note in their bug tracker.

1 Like