diff --git src/wp-admin/includes/image-edit.php src/wp-admin/includes/image-edit.php
index 9641c70..2ca847c 100644
--- src/wp-admin/includes/image-edit.php
+++ src/wp-admin/includes/image-edit.php
@@ -636,6 +636,8 @@ function wp_restore_image($post_id) {
  * @return \stdClass
  */
 function wp_save_image( $post_id ) {
+	global $_wp_additional_image_sizes;
+
 	$return = new stdClass;
 	$success = $delete = $scaled = $nocrop = false;
 	$post = get_post( $post_id );
@@ -770,8 +772,17 @@ function wp_save_image( $post_id ) {
 					$backup_sizes[$tag] = $meta['sizes'][$size];
 			}
 
-			$crop = $nocrop ? false : get_option("{$size}_crop");
-			$_sizes[ $size ] = array( 'width' => get_option("{$size}_size_w"), 'height' => get_option("{$size}_size_h"), 'crop' => $crop );
+			if ( isset( $_wp_additional_image_sizes[ $size ] ) ) {
+				$width  = intval( $_wp_additional_image_sizes[ $size ]['width'] );
+				$height = intval( $_wp_additional_image_sizes[ $size ]['height'] );
+				$crop   = ( $nocrop ) ? false : intval( $_wp_additional_image_sizes[ $size ]['crop'] );
+			} else {
+				$height = get_option( "{$size}_size_h" );
+				$width  = get_option( "{$size}_size_w" );
+				$crop   = ( $nocrop ) ? false : get_option( "{$size}_crop" );
+			}
+
+			$_sizes[ $size ] = array( 'width' => $width, 'height' => $height, 'crop' => $crop );
 		}
 
 		$meta['sizes'] = array_merge( $meta['sizes'], $img->multi_resize( $_sizes ) );
diff --git src/wp-includes/class-wp-editor.php src/wp-includes/class-wp-editor.php
index bda3664..99d61fc 100644
--- src/wp-includes/class-wp-editor.php
+++ src/wp-includes/class-wp-editor.php
@@ -343,9 +343,16 @@ final class _WP_Editors {
 				$suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
 				$version = 'ver=' . $GLOBALS['wp_version'];
 				$dashicons = includes_url( "css/dashicons$suffix.css?$version" );
+				$mediaelement = includes_url( "js/mediaelement/mediaelementplayer.min.css?$version" );
+				$wpmediaelement = includes_url( "js/mediaelement/wp-mediaelement.css?$version" );
 
 				// WordPress default stylesheet and dashicons
-				$mce_css = array( $dashicons, self::$baseurl . '/skins/wordpress/wp-content.css' );
+				$mce_css = array(
+					$dashicons,
+					$mediaelement,
+					$wpmediaelement,
+					self::$baseurl . '/skins/wordpress/wp-content.css'
+				);
 
 				// load editor_style.css if the current theme supports it
 				if ( ! empty( $GLOBALS['editor_styles'] ) && is_array( $GLOBALS['editor_styles'] ) ) {
diff --git src/wp-includes/js/mce-view.js src/wp-includes/js/mce-view.js
index 0881680..e018cd2 100644
--- src/wp-includes/js/mce-view.js
+++ src/wp-includes/js/mce-view.js
@@ -178,7 +178,7 @@ window.wp = window.wp || {};
 
 		/**
 		 * Refresh views after an update is made
-		 * 
+		 *
 		 * @param view {object} being refreshed
 		 * @param text {string} textual representation of the view
 		 */
@@ -204,9 +204,9 @@ window.wp = window.wp || {};
 			return instances[ encodedText ];
 		},
 
-		/** 
+		/**
 		 * render( scope )
-		 * 
+		 *
 		 * Renders any view instances inside a DOM node `scope`.
 		 *
 		 * View instances are detected by the presence of wrapper elements.
@@ -302,4 +302,96 @@ window.wp = window.wp || {};
 
 	};
 	wp.mce.views.register( 'gallery', wp.mce.gallery );
+
+	wp.mce.media = {
+		success: function(mejs) {
+			this.mejs = mejs;
+		},
+
+		bootstrap: function (node) {
+			var media = $(node), settings = {
+				success: this.success
+			};
+			if ( ! _.isUndefined( window._wpmejsSettings ) ) {
+				settings.pluginPath = _wpmejsSettings.pluginPath;
+			}
+			media = wp.media.view.MediaDetails.prepareSrc( media.get(0) );
+			this.player = new MediaElementPlayer( media, settings );
+		},
+
+		toView:  function( content ) {
+			var match = wp.shortcode.next( this.shortcode, content );
+
+			if ( ! match ) {
+				return;
+			}
+
+			return {
+				index:   match.index,
+				content: match.content,
+				options: {
+					shortcode: match.shortcode
+				}
+			};
+		},
+
+		edit: function( node ) {
+			var m = wp.media[ this.shortcode ],
+				self = this,
+				frame, data;
+
+			this.player.pause();
+
+			data = window.decodeURIComponent( $( node ).data('wpview-text') );
+			frame = m.edit( data );
+			frame.on( 'close', function () {
+				frame.detach();
+			} );
+			frame.state( this.shortcode + '-details' ).on( self.states, function( selection ) {
+				var shortcode = wp.shortcode.string( { tag: self.shortcode, attrs: selection } );
+				$( node ).attr( 'data-wpview-text', window.encodeURIComponent( shortcode ) );
+				wp.mce.views.refreshView( self, shortcode );
+				frame.detach();
+			} );
+			frame.open();
+		}
+	};
+
+	wp.mce.video = _.extend({}, wp.mce.media, {
+		shortcode: 'video',
+		states: 'update replace add-source select-poster-image add-track',
+		View: wp.mce.View.extend({
+			className: 'editor-video',
+			template:  media.template('editor-video'),
+
+			initialize: function( options ) {
+				this.shortcode = options.shortcode;
+			},
+
+			getHtml: function() {
+				var attrs = this.shortcode.attrs.named;
+				return this.template({ model: attrs });
+			}
+		})
+	});
+	wp.mce.views.register( 'video', wp.mce.video );
+
+	wp.mce.audio = _.extend({}, wp.mce.media, {
+		shortcode: 'audio',
+		states : 'update replace add-source',
+		View: wp.mce.View.extend({
+			className: 'editor-audio',
+			template:  media.template('editor-audio'),
+
+			initialize: function( options ) {
+				this.shortcode = options.shortcode;
+			},
+
+			getHtml: function() {
+				var attrs = this.shortcode.attrs.named;
+				return this.template({ model: attrs });
+			}
+		})
+	});
+	wp.mce.views.register( 'audio', wp.mce.audio );
 }(jQuery));
diff --git src/wp-includes/js/media-views.js src/wp-includes/js/media-views.js
index 36a4772..1bbebfd 100644
--- src/wp-includes/js/media-views.js
+++ src/wp-includes/js/media-views.js
@@ -6542,26 +6542,6 @@
 			}, this.options );
 		},
 
-		/**
-		 * When multiple players in the DOM contain the same src, things get weird.
-		 *
-		 * @param {HTMLElement} media
-		 * @returns {HTMLElement}
-		 */
-		prepareSrc : function (media) {
-			var i = wp.media.view.MediaDetails.instances++;
-			_.each( $(media).find('source'), function (source) {
-				source.src = [
-					source.src,
-					source.src.indexOf('?') > -1 ? '&' : '?',
-					'_=',
-					i
-				].join('');
-			});
-
-			return media;
-		},
-
 		removeSetting : function (e) {
 			var wrap = $( e.currentTarget ).parent(), setting;
 
@@ -6675,7 +6655,27 @@
 			this.$( '.embed-media-settings' ).scrollTop( 0 );
 		}
 	}, {
-		instances : 0
+		instances : 0,
+
+		/**
+		 * When multiple players in the DOM contain the same src, things get weird.
+		 *
+		 * @param {HTMLElement} media
+		 * @returns {HTMLElement}
+		 */
+		prepareSrc : function (media) {
+			var i = wp.media.view.MediaDetails.instances++;
+			_.each( $(media).find('source'), function (source) {
+				source.src = [
+					source.src,
+					source.src.indexOf('?') > -1 ? '&' : '?',
+					'_=',
+					i
+				].join('');
+			});
+
+			return media;
+		}
 	});
 
 	/**
@@ -6700,7 +6700,7 @@
 				if ( audio.is(':hidden') ) {
 					audio.show();
 				}
-				this.media = this.prepareSrc( audio.get(0) );
+				this.media = media.view.MediaDetails.prepareSrc( audio.get(0) );
 			} else {
 				audio.hide();
 				this.media = false;
@@ -6734,7 +6734,7 @@
 				}
 
 				if ( ! video.hasClass('youtube-video') ) {
-					this.media = this.prepareSrc( video.get(0) );
+					this.media = media.view.MediaDetails.prepareSrc( video.get(0) );
 				} else {
 					this.media = video.get(0);
 				}
diff --git src/wp-includes/js/tinymce/plugins/wpgallery/plugin.js src/wp-includes/js/tinymce/plugins/wpgallery/plugin.js
index d33dbca..8c2a800 100644
--- src/wp-includes/js/tinymce/plugins/wpgallery/plugin.js
+++ src/wp-includes/js/tinymce/plugins/wpgallery/plugin.js
@@ -25,8 +25,8 @@ tinymce.PluginManager.add('wpgallery', function( editor ) {
 	}
 
 	function replaceAVShortcodes( content ) {
-		var testRegex = /\[(video-playlist|audio|video|playlist)[^\]]*\]/,
-			replaceRegex = /\[(video-playlist|audio|video|playlist)[^\]]*\]([\s\S]*?\[\/\1\])?/;
+		var testRegex = /\[(video-playlist|playlist)[^\]]*\]/,
+			replaceRegex = /\[(video-playlist|playlist)[^\]]*\]([\s\S]*?\[\/\1\])?/;
 
 		while ( testRegex.test( content ) ) {
 			content = content.replace( replaceRegex, replaceCallback );
@@ -92,31 +92,6 @@ tinymce.PluginManager.add('wpgallery', function( editor ) {
 				editor.dom.setAttrib( node, 'data-wp-media', window.encodeURIComponent( shortcode ) );
 				frame.detach();
 			});
-		} else if ( editor.dom.hasClass( node, 'wp-video' ) ) {
-			frame = wp.media.video.edit( data );
-			frame.on( 'close', function () {
-				frame.detach();
-			} );
-			frame.state( 'video-details' ).on(
-				'update replace add-source select-poster-image add-track',
-				function ( selection ) {
-					var shortcode = wp.media.video.shortcode( selection );
-					editor.dom.setAttrib( node, 'data-wp-media', window.encodeURIComponent( shortcode ) );
-					frame.detach();
-				}
-			);
-			frame.open();
-		} else if ( editor.dom.hasClass( node, 'wp-audio' ) ) {
-			frame = wp.media.audio.edit( data );
-			frame.on( 'close', function () {
-				frame.detach();
-			} );
-			frame.state( 'audio-details' ).on( 'update replace add-source', function ( selection ) {
-				var shortcode = wp.media.audio.shortcode( selection );
-				editor.dom.setAttrib( node, 'data-wp-media', window.encodeURIComponent( shortcode ) );
-				frame.detach();
-			} );
-			frame.open();
 		} else {
 			// temp
 			window.console && window.console.log( 'Edit AV shortcode ' + data );
diff --git src/wp-includes/js/tinymce/skins/wordpress/wp-content.css src/wp-includes/js/tinymce/skins/wordpress/wp-content.css
index f23dfbd..b2138df 100644
--- src/wp-includes/js/tinymce/skins/wordpress/wp-content.css
+++ src/wp-includes/js/tinymce/skins/wordpress/wp-content.css
@@ -237,14 +237,29 @@ img::selection {
 /**
  * Gallery preview
  */
-.wpview-type-gallery {
+.wpview-type-gallery,
+.wpview-type-audio,
+.wpview-type-video {
     position: relative;
     padding: 0 0 12px;
     margin-bottom: 16px;
 	cursor: pointer;
 }
 
- .wpview-type-gallery:after {
+.wpview-type-audio,
+.wpview-type-video {
+    padding: 32px 0 0;
+}
+
+.wpview-type-audio audio,
+.wpview-type-video video {
+    display: inline-block;
+	max-width: 100%;
+}
+
+ .wpview-type-gallery:after,
+ .wpview-type-audio:after,
+ .wpview-type-video:after {
     content: '';
     display: block;
     height: 0;
@@ -252,11 +267,18 @@ img::selection {
     visibility: hidden;
 }
 
- .wpview-type-gallery.selected {
+.wpview-type-gallery.selected {
+	background-color: #efefef;
+}
+
+.wpview-type-audio,
+.wpview-type-video {
 	background-color: #efefef;
 }
 
-.wpview-type-gallery .toolbar {
+.wpview-type-gallery .toolbar,
+.wpview-type-audio .toolbar,
+.wpview-type-video .toolbar {
     position: absolute;
     top: 0;
     left: 0;
@@ -266,11 +288,18 @@ img::selection {
 	display: none;
 }
 
+.wpview-type-audio .toolbar,
+.wpview-type-video .toolbar {
+	display: block;
+}
+
 .wpview-type-gallery.selected .toolbar {
 	display: block;
 }
 
-.wpview-type-gallery .toolbar span {
+.wpview-type-gallery .toolbar span,
+.wpview-type-audio .toolbar span
+.wpview-type-video .toolbar span {
 	cursor: pointer;
 }
 
diff --git src/wp-includes/media-template.php src/wp-includes/media-template.php
index 8fa9afd..db3db60 100644
--- src/wp-includes/media-template.php
+++ src/wp-includes/media-template.php
@@ -8,6 +8,97 @@
  */
 
 /**
+ * Output the markup for a audio tag to be used in an Underscore template
+ *	when data.model is passed.
+ *
+ * @param boolean $onload Whether to call the parent window's bootstrap method
+ */
+function wp_underscore_audio_template( $onload = false ) {
+	$audio_types = wp_get_audio_extensions();
+?>
+<audio controls
+	class="wp-audio-shortcode" <?php echo empty( $onload ) ? '' : 'onloadstart="window.parent.wp.mce.audio.bootstrap(this)"' ?>
+	preload="{{ _.isUndefined( data.model.preload ) ? 'none' : data.model.preload }}"
+	<#
+	<?php foreach ( array( 'autoplay', 'loop' ) as $attr ):
+	?>if ( ! _.isUndefined( data.model.<?php echo $attr ?> ) && data.model.<?php echo $attr ?> ) {
+		#> <?php echo $attr ?><#
+	}
+	<?php endforeach ?>#>
+>
+	<# if ( ! _.isEmpty( data.model.src ) ) { #>
+	<source src="{{ data.model.src }}" type="{{ wp.media.view.settings.embedMimes[ data.model.src.split('.').pop() ] }}" />
+	<# } #>
+
+	<?php foreach ( $audio_types as $type ):
+	?><# if ( ! _.isEmpty( data.model.<?php echo $type ?> ) ) { #>
+	<source src="{{ data.model.<?php echo $type ?> }}" type="{{ wp.media.view.settings.embedMimes[ '<?php echo $type ?>' ] }}" />
+	<# } #>
+	<?php endforeach;
+?></audio>
+<?php
+}
+
+/**
+ * Output the markup for a video tag to be used in an Underscore template
+ *	when data.model is passed.
+ *
+ * @param boolean $onload Whether to call the parent window's bootstrap method
+ */
+function wp_underscore_video_template( $onload = false ) {
+	$video_types = wp_get_video_extensions();
+?>
+<#
+var isYouTube = ! _.isEmpty( data.model.src ) && data.model.src.match(/youtube|youtu\.be/);
+	w = ! data.model.width || data.model.width > 640 ? 640 : data.model.width,
+	h = ! data.model.height ? 360 : data.model.height;
+
+if ( data.model.width && w !== data.model.width ) {
+	h = Math.ceil( ( h * w ) / data.model.width );
+}
+#>
+<video controls <?php echo empty( $onload ) ? '' : 'oncanplay="window.parent.wp.mce.video.bootstrap(this)"' ?>
+	class="wp-video-shortcode{{ isYouTube ? ' youtube-video' : '' }}"
+	width="{{ w }}"
+	height="{{ h }}"
+	<?php
+	$props = array( 'poster' => '', 'preload' => 'metadata' );
+	foreach ( $props as $key => $value ):
+		if ( empty( $value ) ) {
+		?><#
+		if ( ! _.isUndefined( data.model.<?php echo $key ?> ) && data.model.<?php echo $key ?> ) {
+			#> <?php echo $key ?>="{{ data.model.<?php echo $key ?> }}"<#
+		} #>
+		<?php } else {
+			echo $key ?>="{{ _.isUndefined( data.model.<?php echo $key ?> ) ? '<?php echo $value ?>' : data.model.<?php echo $key ?> }}"<?php
+		}
+	endforeach;
+	?><#
+	<?php foreach ( array( 'autoplay', 'loop' ) as $attr ):
+	?> if ( ! _.isUndefined( data.model.<?php echo $attr ?> ) && data.model.<?php echo $attr ?> ) {
+		#> <?php echo $attr ?><#
+	}
+	<?php endforeach ?>#>
+>
+	<# if ( ! _.isEmpty( data.model.src ) ) {
+		if ( isYouTube ) { #>
+		<source src="{{ data.model.src }}" type="video/youtube" />
+		<# } else { #>
+		<source src="{{ data.model.src }}" type="{{ wp.media.view.settings.embedMimes[ data.model.src.split('.').pop() ] }}" />
+		<# }
+	} #>
+
+	<?php foreach ( $video_types as $type ):
+	?><# if ( data.model.<?php echo $type ?> ) { #>
+	<source src="{{ data.model.<?php echo $type ?> }}" type="{{ wp.media.view.settings.embedMimes[ '<?php echo $type ?>' ] }}" />
+	<# } #>
+	<?php endforeach; ?>
+	{{{ data.model.content }}}
+</video>
+<?php
+}
+
+/**
  * Prints the templates used in the media manager.
  *
  * @since 3.5.0
@@ -676,26 +767,7 @@ function wp_print_media_templates() {
 		<div class="media-embed media-embed-details">
 			<div class="embed-media-settings embed-audio-settings">
 				<div class="instructions media-instructions">{{{ wp.media.view.l10n.audioDetailsText }}}</div>
-				<audio controls
-					class="wp-audio-shortcode"
-					preload="{{ _.isUndefined( data.model.preload ) ? 'none' : data.model.preload }}"
-					<#
-					<?php foreach ( array( 'autoplay', 'loop' ) as $attr ):
-					?>if ( ! _.isUndefined( data.model.<?php echo $attr ?> ) && data.model.<?php echo $attr ?> ) {
-						#> <?php echo $attr ?><#
-					}
-					<?php endforeach ?>#>
-				>
-					<# if ( ! _.isEmpty( data.model.src ) ) { #>
-					<source src="{{ data.model.src }}" type="{{ wp.media.view.settings.embedMimes[ data.model.src.split('.').pop() ] }}" />
-					<# } #>
-
-					<?php foreach ( $audio_types as $type ):
-					?><# if ( ! _.isEmpty( data.model.<?php echo $type ?> ) ) { #>
-					<source src="{{ data.model.<?php echo $type ?> }}" type="{{ wp.media.view.settings.embedMimes[ '<?php echo $type ?>' ] }}" />
-					<# } #>
-					<?php endforeach;
-				?></audio>
+				<?php wp_underscore_audio_template() ?>
 				<# if ( ! _.isEmpty( data.model.src ) ) { #>
 				<label class="setting">
 					<span>SRC</span>
@@ -738,60 +810,21 @@ function wp_print_media_templates() {
 		</div>
 	</script>
 
+	<script type="text/html" id="tmpl-editor-audio">
+		<div class="toolbar">
+			<div class="dashicons dashicons-format-audio edit"></div>
+			<div class="dashicons dashicons-no-alt remove"></div>
+		</div>
+		<?php wp_underscore_audio_template( true ) ?>
+	</script>
+
 	<script type="text/html" id="tmpl-video-details">
 		<?php $video_types = wp_get_video_extensions(); ?>
 		<div class="media-embed media-embed-details">
 			<div class="embed-media-settings embed-video-settings">
 				<div class="instructions media-instructions">{{{ wp.media.view.l10n.videoDetailsText }}}</div>
 				<div class="wp-video-holder">
-				<#
-				var isYouTube = ! _.isEmpty( data.model.src ) && data.model.src.match(/youtube|youtu\.be/);
-					w = ! data.model.width || data.model.width > 640 ? 640 : data.model.width,
-					h = ! data.model.height ? 360 : data.model.height;
-
-				if ( data.model.width && w !== data.model.width ) {
-					h = Math.ceil( ( h * w ) / data.model.width );
-				}
-
-				#>
-				<video controls
-					class="wp-video-shortcode{{ isYouTube ? ' youtube-video' : '' }}"
-					width="{{ w }}"
-					height="{{ h }}"
-					<?php
-					$props = array( 'poster' => '', 'preload' => 'metadata' );
-					foreach ( $props as $key => $value ):
-						if ( empty( $value ) ) {
-						?><#
-						if ( ! _.isUndefined( data.model.<?php echo $key ?> ) && data.model.<?php echo $key ?> ) {
-							#> <?php echo $key ?>="{{ data.model.<?php echo $key ?> }}"<#
-						} #>
-						<?php } else {
-							echo $key ?>="{{ _.isUndefined( data.model.<?php echo $key ?> ) ? '<?php echo $value ?>' : data.model.<?php echo $key ?> }}"<?php
-						}
-					endforeach;
-					?><#
-					<?php foreach ( array( 'autoplay', 'loop' ) as $attr ):
-					?> if ( ! _.isUndefined( data.model.<?php echo $attr ?> ) && data.model.<?php echo $attr ?> ) {
-						#> <?php echo $attr ?><#
-					}
-					<?php endforeach ?>#>
-				>
-					<# if ( ! _.isEmpty( data.model.src ) ) {
-						if ( isYouTube ) { #>
-						<source src="{{ data.model.src }}" type="video/youtube" />
-						<# } else { #>
-						<source src="{{ data.model.src }}" type="{{ wp.media.view.settings.embedMimes[ data.model.src.split('.').pop() ] }}" />
-						<# }
-					} #>
-
-					<?php foreach ( $video_types as $type ):
-					?><# if ( data.model.<?php echo $type ?> ) { #>
-					<source src="{{ data.model.<?php echo $type ?> }}" type="{{ wp.media.view.settings.embedMimes[ '<?php echo $type ?>' ] }}" />
-					<# } #>
-					<?php endforeach; ?>
-					{{{ data.model.content }}}
-				</video>
+				<?php wp_underscore_video_template() ?>
 				<# if ( ! _.isEmpty( data.model.src ) ) { #>
 				<label class="setting">
 					<span>SRC</span>
@@ -857,6 +890,14 @@ function wp_print_media_templates() {
 			</div>
 		</div>
 	</script>
+
+	<script type="text/html" id="tmpl-editor-video">
+		<div class="toolbar">
+			<div class="dashicons dashicons-format-video edit"></div>
+			<div class="dashicons dashicons-no-alt remove"></div>
+		</div>
+		<?php wp_underscore_video_template( true ) ?>
+	</script>
 	<?php
 
 		//TODO: do we want to deal with the fact that the elements used for gallery items are filterable and can be overriden via shortcode attributes
