Page MenuHomePhabricator

Chrome does not play some videos with type "video/quicktime", but does play them with type "video/mp4"
Closed, ResolvedPublic

Description

See PHI633. An install reports that a video embeds and plays correctly in Safari, but not in Chrome.

To reproduce this issue, download this video:

Now, create two HTML files:

bad.html
<video controls>
  <source src="movie.mov" type="video/quicktime">
</video>
good.html
<video controls>
  <source src="movie.mov" type="video/mp4">
</video>

Open both HTML files in Chrome.

  • The good.html file embeds and plays the video.
  • The bad.html file does not play the video.

The MIME type of this file, as determined by file, is correct:

$ file --mime-type movie.mov 
movie.mov: video/quicktime

Chrome can clearly play the file and just chooses not to.

Event Timeline

epriestley triaged this task as Normal priority.May 3 2018, 3:31 PM
epriestley created this task.

One easy approach we could take is just:

// Trick Chrome into playing certain videos.
if ($type === 'video/quicktime') {
  $type = 'video/mp4';
}

But there's no easy way to tell how much collateral damage this might cause (does it cause other browsers to not play these videos, or other videos?), and the cure might be worse than the disease.

I'm also not sure how to detect that a given file is an MP4 video file, or if this video file even is MP4 -- Quicktime Player reports it as "H.264" but I think all video files are basically 30-40 levels of container formats wrapped in one another and that this may be a H.264-encoded video stream inside an MP4 container inside a Quicktime container -- or may not be. I suspect ffmpeg or similar has some command like ffmpeg --explain-what-this-is movie.mov but I'd prefer not to require installs to install ffmpeg (although maybe this isn't the end of the world).

Also ffmpeg is super illegal thought crime full of forbidden and completely unlicensed prime numbers or something, maybe?

Basically, I'm currently pretty far out of my depth on understanding video container/codec formats and the tools available to interact with them, so I have very low confidence that I can predict how much damage various changes will cause.

Next steps are probably:

  • Learn how video file formats actually work.
  • Identify exactly what's going on with that file.
  • Look at available tools for inspecting the contents of video files.

Hopefully that yields a greater understanding and more confidence in an approach.


I made some effort to Google this and found a bit of evidence of users running into a similar situation and using the workaround above (e.g., see here) but nothing in the way of concrete guidance.

Another place to look might be other software which embeds user-uploaded video, but I'm not sure offhand which pieces of software would be good to look at. I think, e.g., most blogs nowadays just work by uploading to YouTube (which can transcode into multiple formats and do other sophisticated things) and embedding the video from YouTube.

mediainfo is the tool for this, but is really overkill for programmatic use.

General
Complete name                            : movie.mov
Format                                   : MPEG-4
Format profile                           : QuickTime
Codec ID                                 : qt   0000.00 (qt  )
File size                                : 639 KiB
Duration                                 : 6 s 405 ms
Overall bit rate                         : 817 kb/s
Recorded date                            : 2016-06-07T14:12:11-0700
Encoded date                             : UTC 2016-06-07 21:17:38
Tagged date                              : UTC 2016-06-07 21:17:41
Writing application                      : 7.1.2
Writing library                          : Apple QuickTime
Make                                     : Apple
Model                                    : iPhone 4
com.apple.quicktime.make                 : Apple
com.apple.quicktime.creationdate         : 2016-06-07T14:12:11-0700
com.apple.quicktime.software             : 7.1.2
com.apple.quicktime.model                : iPhone 4

Video
ID                                       : 2
Format                                   : AVC
Format/Info                              : Advanced Video Codec
Format profile                           : Baseline@L3
Format settings, CABAC                   : No
Format settings, RefFrames               : 1 frame
Format settings, GOP                     : M=1, N=30
Codec ID                                 : avc1
Codec ID/Info                            : Advanced Video Coding
Duration                                 : 6 s 405 ms
Bit rate                                 : 747 kb/s
Width                                    : 568 pixels
Height                                   : 320 pixels
Display aspect ratio                     : 16:9
Frame rate mode                          : Variable
Frame rate                               : 29.970 (29970/1000) FPS
Minimum frame rate                       : 28.571 FPS
Maximum frame rate                       : 30.000 FPS
Color space                              : YUV
Chroma subsampling                       : 4:2:0
Bit depth                                : 8 bits
Scan type                                : Progressive
Bits/(Pixel*Frame)                       : 0.137
Stream size                              : 584 KiB (91%)
Title                                    : Core Media Video
Encoded date                             : UTC 2016-06-07 21:17:38
Tagged date                              : UTC 2016-06-07 21:17:41
Color range                              : Limited
Color primaries                          : BT.709
Transfer characteristics                 : BT.709
Matrix coefficients                      : BT.709

Audio
ID                                       : 1
Format                                   : AAC
Format/Info                              : Advanced Audio Codec
Format profile                           : LC
Codec ID                                 : 40
Duration                                 : 6 s 383 ms
Source duration                          : 6 s 432 ms
Bit rate mode                            : Constant
Bit rate                                 : 64.0 kb/s
Channel(s)                               : 1 channel
Channel positions                        : Front: C
Sampling rate                            : 44.1 kHz
Frame rate                               : 43.066 FPS (1024 SPF)
Compression mode                         : Lossy
Stream size                              : 49.9 KiB (8%)
Source stream size                       : 50.1 KiB (8%)
Title                                    : Core Media Audio
Encoded date                             : UTC 2016-06-07 21:17:38
Tagged date                              : UTC 2016-06-07 21:17:41

This is almost certainly a Chrome bug, because the file is really a QTFF container - so Chrome has code to parse and play it in the MP4 pipeline (it is very, very similar to the MP4 container), but is missing the mime type registration to hook it up to the MP4 pipeline. You're almost certainly safe just faking it to video/mp4 though.

Thanks! I wouldn't mind parsing that but I'm hesitant to ask installs to install it -- but it's helpful in understanding that I'm not completely crazy here and that there's at least some basis for "video/mp4" being a quasi-legitimate way to label the video file.

I did dig up this this similar issue in Drupal:

https://www.drupal.org/project/drupal/issues/2940065

That notes that removing the type attribute works. I can reproduce this locally: either type="video/mp4" or <no type attribute> work, only type="video/quicktime" poisons the tag.

The Drupal issue seems to have been resolved wrong: I think the resolver maybe didn't catch that omitting type works, so the justification that "there is no cross-browser support for MOV" isn't relevant in this particular case, since Chrome can clearly play the file.

Since you obviously know more about this than I do and are comfortable with the video/mp4 approach, and omitting type entirely works, I'm inclined to try this:

hybrid.html
<video controls>
  <source src="movie.mov" type="video/quicktime">
  <source src="movie.mov">
</video>

That is, emit one <source /> with the real type, and then one "wildcard" <source /> with no type. The W3C validator seems OK with this, and Safari, Chrome, and Firefox also seem to do okay with it.

This feels a little more robust to me as a "trick Chrome into recovering" patch, since we don't have to actually lie about the content type. The markup we'd emit is super ambiguous, but it "feels" like the intent is preserved a little better and more likely that adding an extra <source /> tag won't break anything compared to lying about the content type.

I'm going to give that a try and see what it breaks.

I can imagine that two <source /> tags might, in some bizarre world, cause browsers to download the file twice when you click "Play", if they're super confused about how to process videos, don't notice that the URLs are the same, and don't hit any caching. But that's a pretty minor bad effect, and I didn't immediately see any kind of bad behavior locally.

My knowledge is centred around broadcast video / IPTV (UDP multicast) rather than HTML5 video, but that seems fairly reasonable. I don't think anything should try and download the file twice unless it is a complete clownshoes implementation that probably has multiple other serious bugs wasting bandwidth. I think the worst case with no type that might be hit here is that the browser could decide to download the entire file on load to figure out the format and duration, rather than starting with byte-range requests, but this is easy to test and unlikely (I'd expect any sane one to always request chunks).

Some research suggests that a) with only 1 real file and b) any of them having no type, it might make most sense to just leave off type completely (and only have one source) - it isn't doing anything useful for the browser because the standard behaviour just says to skip any with known-incompatible types. So every browser should either get the first
one with the real type, or fallback to the wildcard. I do not think any decisions are meant to be made based on the provided type other than do or do not try and play it inline, the real work is all done based on the actual bytes received - which is why giving the wrong (but compatible type) works.

I like that reasoning a lot better than mine, and simply omitting type appears to produce the correct behavior in every browser, at least for this file. I'll try that instead, and we can revisit this after we write a video transcoder in PHP and can offer files in multiple formats.