diff --git a/resources/celerity/map.php b/resources/celerity/map.php
--- a/resources/celerity/map.php
+++ b/resources/celerity/map.php
@@ -7,7 +7,7 @@
  */
 return array(
   'names' => array(
-    'core.pkg.css' => 'b9927580',
+    'core.pkg.css' => '0e3b60db',
     'core.pkg.js' => '3f15fa62',
     'darkconsole.pkg.js' => 'e7393ebb',
     'differential.pkg.css' => 'f3fb8324',
@@ -104,7 +104,7 @@
     'rsrc/css/application/tokens/tokens.css' => '3d0f239e',
     'rsrc/css/application/uiexample/example.css' => '528b19de',
     'rsrc/css/core/core.css' => 'd0801452',
-    'rsrc/css/core/remarkup.css' => '787105d6',
+    'rsrc/css/core/remarkup.css' => '845a390d',
     'rsrc/css/core/syntax.css' => '9fc496d5',
     'rsrc/css/core/z-index.css' => '5b6fcf3f',
     'rsrc/css/diviner/diviner-shared.css' => 'aa3656aa',
@@ -149,7 +149,7 @@
     'rsrc/css/phui/phui-pager.css' => 'bea33d23',
     'rsrc/css/phui/phui-pinboard-view.css' => '2495140e',
     'rsrc/css/phui/phui-profile-menu.css' => 'c8557f33',
-    'rsrc/css/phui/phui-property-list-view.css' => '1d42ee7c',
+    'rsrc/css/phui/phui-property-list-view.css' => '6458f614',
     'rsrc/css/phui/phui-remarkup-preview.css' => '1a8f2591',
     'rsrc/css/phui/phui-segment-bar-view.css' => '46342871',
     'rsrc/css/phui/phui-spacing.css' => '042804d6',
@@ -784,7 +784,7 @@
     'phabricator-object-selector-css' => '85ee8ce6',
     'phabricator-phtize' => 'd254d646',
     'phabricator-prefab' => 'e67df814',
-    'phabricator-remarkup-css' => '787105d6',
+    'phabricator-remarkup-css' => '845a390d',
     'phabricator-search-results-css' => '7dea472c',
     'phabricator-shaped-request' => '7cbe244b',
     'phabricator-side-menu-view-css' => 'dd849797',
@@ -851,7 +851,7 @@
     'phui-pager-css' => 'bea33d23',
     'phui-pinboard-view-css' => '2495140e',
     'phui-profile-menu-css' => 'c8557f33',
-    'phui-property-list-view-css' => '1d42ee7c',
+    'phui-property-list-view-css' => '6458f614',
     'phui-remarkup-preview-css' => '1a8f2591',
     'phui-segment-bar-view-css' => '46342871',
     'phui-spacing-css' => '042804d6',
diff --git a/src/applications/files/config/PhabricatorFilesConfigOptions.php b/src/applications/files/config/PhabricatorFilesConfigOptions.php
--- a/src/applications/files/config/PhabricatorFilesConfigOptions.php
+++ b/src/applications/files/config/PhabricatorFilesConfigOptions.php
@@ -34,9 +34,16 @@
       'image/x-icon'              => 'image/x-icon',
       'image/vnd.microsoft.icon'  => 'image/x-icon',
 
-      'audio/x-wav'     => 'audio/x-wav',
+      // This is a generic type for both OGG video and OGG audio.
       'application/ogg' => 'application/ogg',
-      'audio/mpeg'      => 'audio/mpeg',
+
+      'audio/x-wav' => 'audio/x-wav',
+      'audio/mpeg' => 'audio/mpeg',
+      'audio/ogg' => 'audio/ogg',
+
+      'video/mp4' => 'video/mp4',
+      'video/ogg' => 'video/ogg',
+      'video/webm' => 'video/webm',
     );
 
     $image_default = array(
@@ -49,10 +56,29 @@
       'image/vnd.microsoft.icon'  => true,
     );
 
+
+    // The "application/ogg" type is listed as both an audio and video type,
+    // because it may contain either type of content.
+
     $audio_default = array(
-      'audio/x-wav'     => true,
+      'audio/x-wav' => true,
+      'audio/mpeg' => true,
+      'audio/ogg' => true,
+
+      // These are video or ambiguous types, but can be forced to render as
+      // audio with `media=audio`, which seems to work properly in browsers.
+      // (For example, you can embed a music video as audio if you just want
+      // to set the mood for your task without distracting viewers.)
+      'video/mp4' => true,
+      'video/ogg' => true,
+      'application/ogg' => true,
+    );
+
+    $video_default = array(
+      'video/mp4' => true,
+      'video/ogg' => true,
+      'video/webm' => true,
       'application/ogg' => true,
-      'audio/mpeg'      => true,
     );
 
     // largely lifted from http://en.wikipedia.org/wiki/Internet_media_type
@@ -70,6 +96,7 @@
       // movie file icon
       'video/mpeg' => 'fa-file-movie-o',
       'video/mp4' => 'fa-file-movie-o',
+      'application/ogg' => 'fa-file-movie-o',
       'video/ogg' => 'fa-file-movie-o',
       'video/quicktime' => 'fa-file-movie-o',
       'video/webm' => 'fa-file-movie-o',
@@ -122,8 +149,14 @@
         ->setSummary(pht('Configure which MIME types are audio.'))
         ->setDescription(
           pht(
-            'List of MIME types which can be used to render an `%s` tag.',
+            'List of MIME types which can be rendered with an `%s` tag.',
             '<audio />')),
+      $this->newOption('files.video-mime-types', 'set', $video_default)
+        ->setSummary(pht('Configure which MIME types are video.'))
+        ->setDescription(
+          pht(
+            'List of MIME types which can be rendered with a `%s` tag.',
+            '<video />')),
       $this->newOption('files.icon-mime-types', 'wild', $icon_default)
         ->setLocked(true)
         ->setSummary(pht('Configure which MIME types map to which icons.'))
diff --git a/src/applications/files/controller/PhabricatorFileInfoController.php b/src/applications/files/controller/PhabricatorFileInfoController.php
--- a/src/applications/files/controller/PhabricatorFileInfoController.php
+++ b/src/applications/files/controller/PhabricatorFileInfoController.php
@@ -230,23 +230,34 @@
       $cache_string = pht('Not Applicable');
     }
 
-    $finfo->addProperty(pht('Viewable Image'), $image_string);
-    $finfo->addProperty(pht('Cacheable'), $cache_string);
+    $types = array();
+    if ($file->isViewableImage()) {
+      $types[] = pht('Image');
+    }
 
-    $builtin = $file->getBuiltinName();
-    if ($builtin === null) {
-      $builtin_string = pht('No');
-    } else {
-      $builtin_string = $builtin;
+    if ($file->isVideo()) {
+      $types[] = pht('Video');
+    }
+
+    if ($file->isAudio()) {
+      $types[] = pht('Audio');
     }
 
-    $finfo->addProperty(pht('Builtin'), $builtin_string);
+    if ($file->getCanCDN()) {
+      $types[] = pht('Can CDN');
+    }
+
+    $builtin = $file->getBuiltinName();
+    if ($builtin !== null) {
+      $types[] = pht('Builtin ("%s")', $builtin);
+    }
 
-    $is_profile = $file->getIsProfileImage()
-      ? pht('Yes')
-      : pht('No');
+    if ($file->getIsProfileImage()) {
+      $types[] = pht('Profile');
+    }
 
-    $finfo->addProperty(pht('Profile'), $is_profile);
+    $types = implode(', ', $types);
+    $finfo->addProperty(pht('Attributes'), $types);
 
     $storage_properties = new PHUIPropertyListView();
     $box->addPropertyList($storage_properties, pht('Storage'));
@@ -293,6 +304,23 @@
         ->addImageContent($linked_image);
 
       $box->addPropertyList($media);
+    } else if ($file->isVideo()) {
+      $video = phutil_tag(
+        'video',
+        array(
+          'controls' => 'controls',
+          'class' => 'phui-property-list-video',
+        ),
+        phutil_tag(
+          'source',
+          array(
+            'src' => $file->getViewURI(),
+            'type' => $file->getMimeType(),
+          )));
+      $media = id(new PHUIPropertyListView())
+        ->addImageContent($video);
+
+      $box->addPropertyList($media);
     } else if ($file->isAudio()) {
       $audio = phutil_tag(
         'audio',
diff --git a/src/applications/files/markup/PhabricatorEmbedFileRemarkupRule.php b/src/applications/files/markup/PhabricatorEmbedFileRemarkupRule.php
--- a/src/applications/files/markup/PhabricatorEmbedFileRemarkupRule.php
+++ b/src/applications/files/markup/PhabricatorEmbedFileRemarkupRule.php
@@ -43,12 +43,27 @@
 
     $is_viewable_image = $object->isViewableImage();
     $is_audio = $object->isAudio();
+    $is_video = $object->isVideo();
     $force_link = ($options['layout'] == 'link');
 
-    $options['viewable'] = ($is_viewable_image || $is_audio);
+    // If a file is both audio and video, as with "application/ogg" by default,
+    // render it as video but allow the user to specify `media=audio` if they
+    // want to force it to render as audio.
+    if ($is_audio && $is_video) {
+      $media = $options['media'];
+      if ($media == 'audio') {
+        $is_video = false;
+      } else {
+        $is_audio = false;
+      }
+    }
+
+    $options['viewable'] = ($is_viewable_image || $is_audio || $is_video);
 
     if ($is_viewable_image && !$force_link) {
       return $this->renderImageFile($object, $handle, $options);
+    } else if ($is_video && !$force_link) {
+      return $this->renderVideoFile($object, $handle, $options);
     } else if ($is_audio && !$force_link) {
       return $this->renderAudioFile($object, $handle, $options);
     } else {
@@ -58,12 +73,15 @@
 
   private function getFileOptions($option_string) {
     $options = array(
-      'size'    => null,
-      'layout'  => 'left',
-      'float'   => false,
-      'width'   => null,
-      'height'  => null,
+      'size' => null,
+      'layout' => 'left',
+      'float' => false,
+      'width' => null,
+      'height' => null,
       'alt' => null,
+      'media' => null,
+      'autoplay' => null,
+      'loop' => null,
     );
 
     if ($option_string) {
@@ -201,22 +219,47 @@
     PhabricatorFile $file,
     PhabricatorObjectHandle $handle,
     array $options) {
+    return $this->renderMediaFile('audio', $file, $handle, $options);
+  }
+
+  private function renderVideoFile(
+    PhabricatorFile $file,
+    PhabricatorObjectHandle $handle,
+    array $options) {
+    return $this->renderMediaFile('video', $file, $handle, $options);
+  }
+
+  private function renderMediaFile(
+    $tag,
+    PhabricatorFile $file,
+    PhabricatorObjectHandle $handle,
+    array $options) {
+
+    $is_video = ($tag == 'video');
 
     if (idx($options, 'autoplay')) {
       $preload = 'auto';
       $autoplay = 'autoplay';
     } else {
-      $preload = 'none';
+      // If we don't preload video, the user can't see the first frame and
+      // has no clue what they're looking at, so always preload.
+      if ($is_video) {
+        $preload = 'auto';
+      } else {
+        $preload = 'none';
+      }
       $autoplay = null;
     }
 
     return $this->newTag(
-      'audio',
+      $tag,
       array(
         'controls' => 'controls',
         'preload' => $preload,
         'autoplay' => $autoplay,
         'loop' => idx($options, 'loop') ? 'loop' : null,
+        'alt' => $options['alt'],
+        'class' => 'phabricator-media',
       ),
       $this->newTag(
         'source',
diff --git a/src/applications/files/storage/PhabricatorFile.php b/src/applications/files/storage/PhabricatorFile.php
--- a/src/applications/files/storage/PhabricatorFile.php
+++ b/src/applications/files/storage/PhabricatorFile.php
@@ -58,6 +58,11 @@
   private $originalFile = self::ATTACHABLE;
   private $transforms = self::ATTACHABLE;
 
+  public function getMimeType() {
+    $type = parent::getMimeType();
+    return $type;
+  }
+
   public static function initializeNewFile() {
     $app = id(new PhabricatorApplicationQuery())
       ->setViewer(PhabricatorUser::getOmnipotentUser())
@@ -802,6 +807,16 @@
     return idx($mime_map, $mime_type);
   }
 
+  public function isVideo() {
+    if (!$this->isViewableInBrowser()) {
+      return false;
+    }
+
+    $mime_map = PhabricatorEnv::getEnvConfig('files.video-mime-types');
+    $mime_type = $this->getMimeType();
+    return idx($mime_map, $mime_type);
+  }
+
   public function isTransformableImage() {
     // NOTE: The way the 'gd' extension works in PHP is that you can install it
     // with support for only some file types, so it might be able to handle
diff --git a/src/docs/user/userguide/remarkup.diviner b/src/docs/user/userguide/remarkup.diviner
--- a/src/docs/user/userguide/remarkup.diviner
+++ b/src/docs/user/userguide/remarkup.diviner
@@ -410,18 +410,29 @@
 
   {F123, layout=left, float, size=full, alt="a duckling"}
 
-Valid options are:
+Valid options for all files are:
 
   - **layout** left (default), center, right, inline, link (render a link
     instead of a thumbnail for images)
+  - **name** with `layout=link` or for non-images, use this name for the link
+    text
+  - **alt** Provide alternate text for assistive technologies.
+
+Image files support these options:
+
   - **float** If layout is set to left or right, the image will be floated so
     text wraps around it.
   - **size** thumb (default), full
-  - **name** with `layout=link` or for non-images, use this name for the link
-    text
   - **width** Scale image to a specific width.
   - **height** Scale image to a specific height.
-  - **alt** Provide alternate text for assistive technologies.
+
+Audio and video files support these options:
+
+  - **media**: Specify the media type as `audio` or `video`. This allows you
+    to disambiguate how file format which may contain either audio or video
+    should be rendered.
+  - **loop**: Loop this media.
+  - **autoplay**: Automatically begin playing this media.
 
 == Embedding Countdowns
 
diff --git a/webroot/rsrc/css/core/remarkup.css b/webroot/rsrc/css/core/remarkup.css
--- a/webroot/rsrc/css/core/remarkup.css
+++ b/webroot/rsrc/css/core/remarkup.css
@@ -218,6 +218,17 @@
   width: 50%;
 }
 
+video.phabricator-media {
+  background: {$greybackground};
+}
+
+.phabricator-remarkup video {
+  display: block;
+  margin: 0 auto;
+  min-width: 240px;
+  width: 90%;
+}
+
 .phabricator-remarkup-mention-exists {
   font-weight: bold;
   background: #e6f3ff;
diff --git a/webroot/rsrc/css/phui/phui-property-list-view.css b/webroot/rsrc/css/phui/phui-property-list-view.css
--- a/webroot/rsrc/css/phui/phui-property-list-view.css
+++ b/webroot/rsrc/css/phui/phui-property-list-view.css
@@ -160,6 +160,13 @@
   min-width: 240px;
 }
 
+.phui-property-list-video {
+  display: block;
+  margin: 0 auto;
+  width: 90%;
+  min-width: 240px;
+}
+
 /* When tags appear in property lists, give them a little more vertical
    spacing. */
 .phui-property-list-view .phui-tag-view {