Index: src/wp-includes/css/media-views.css
===================================================================
--- src/wp-includes/css/media-views.css	(revision 27266)
+++ src/wp-includes/css/media-views.css	(working copy)
@@ -1460,7 +1460,7 @@
 }
 
 .embed-link-settings,
-.embed-image-settings {
+.embed-media-settings {
 	position: absolute;
 	top: 60px;
 	left: 0;
@@ -1470,7 +1470,7 @@
 	overflow: auto;
 }
 
-.image-details .embed-image-settings {
+.image-details .embed-media-settings {
 	top: 0;
 }
 
@@ -1523,7 +1523,7 @@
 	margin: 2px 0;
 }
 
-.media-embed .setting input,
+.media-embed .setting input[type="text"],
 .media-embed .setting textarea {
 	display: block;
 	width: 100%;
@@ -1872,7 +1872,7 @@
 
 	/* Image From Link */
 	.embed-link-settings,
-	.embed-image-settings {
+	.embed-media-settings {
 		padding-bottom: 52px;
 	}
 
Index: src/wp-includes/js/media-editor.js
===================================================================
--- src/wp-includes/js/media-editor.js	(revision 27266)
+++ src/wp-includes/js/media-editor.js	(working copy)
@@ -593,6 +593,53 @@
 		}));
 	}());
 
+	wp.media.audio = {
+		defaults : {
+			id : wp.media.view.settings.post.id,
+			src      : '',
+			loop     : '',
+			autoplay : '',
+			preload  : 'none'
+		},
+
+		shortcode : function (shortcode) {
+ 			_.each( wp.media.audio.defaults, function( value, key ) {
+ 				if ( value === shortcode[ key ] ) {
+ 					delete shortcode[ key ];
+				}
+ 			});
+
+			return wp.shortcode.string({
+				tag:     'audio',
+				attrs:   shortcode
+			});
+		}
+	};
+
+	wp.media.video = {
+		defaults : {
+			id : wp.media.view.settings.post.id,
+			src : '',
+			poster : '',
+			loop : '',
+			autoplay : '',
+			preload : 'metadata'
+		},
+
+		shortcode : function (shortcode) {
+ 			_.each( wp.media.video.defaults, function( value, key ) {
+ 				if ( value === shortcode[ key ] ) {
+ 					delete shortcode[ key ];
+				}
+ 			});
+
+			return wp.shortcode.string({
+				tag:     'video',
+				attrs:   shortcode
+			});
+		}
+	};
+
 	/**
 	 * wp.media.featuredImage
 	 * @namespace
Index: src/wp-includes/js/media-models.js
===================================================================
--- src/wp-includes/js/media-models.js	(revision 27266)
+++ src/wp-includes/js/media-models.js	(working copy)
@@ -32,6 +32,10 @@
 			frame = new MediaFrame.Post( attributes );
 		} else if ( 'image' === attributes.frame && MediaFrame.ImageDetails ) {
 			frame = new MediaFrame.ImageDetails( attributes );
+		} else if ( 'audio' === attributes.frame && MediaFrame.AudioDetails ) {
+			frame = new MediaFrame.AudioDetails( attributes );
+		} else if ( 'video' === attributes.frame && MediaFrame.VideoDetails ) {
+			frame = new MediaFrame.VideoDetails( attributes );
 		}
 
 		delete attributes.frame;
@@ -448,6 +452,64 @@
 	});
 
 	/**
+	 * wp.media.model.PostAudio
+	 *
+	 * @constructor
+	 * @augments Backbone.Model
+	 **/
+	PostAudio = media.model.PostAudio = Backbone.Model.extend({
+		initialize: function() {
+			this.attachment = false;
+		},
+
+		changeAttachment: function( attachment, props ) {
+			var self = this;
+
+			this.attachment = attachment;
+			this.extension = attachment.get('filename' ).split('.').pop();
+
+			if ( _.contains( wp.media.view.settings.embedExts, this.extension ) ) {
+				this.set( this.extension, attachment.get( 'url' ) );
+			} else {
+				this.set( this.extension, '' );
+			}
+
+			_.each( _.without( wp.media.view.settings.embedExts, this.extension ), function (ext) {
+				self.set( ext, '' );
+			} );
+		}
+	});
+
+	/**
+	 * wp.media.model.PostVideo
+	 *
+	 * @constructor
+	 * @augments Backbone.Model
+	 **/
+	PostVideo = media.model.PostVideo = Backbone.Model.extend({
+		initialize: function() {
+			this.attachment = false;
+		},
+
+		changeAttachment: function( attachment, props ) {
+			var self = this;
+
+			this.attachment = attachment;
+			this.extension = attachment.get('filename' ).split('.').pop();
+
+			if ( _.contains( wp.media.view.settings.embedExts, this.extension ) ) {
+				this.set( this.extension, attachment.get( 'url' ) );
+			} else {
+				this.set( this.extension, '' );
+			}
+
+			_.each( _.without( wp.media.view.settings.embedExts, this.extension ), function (ext) {
+				self.set( ext, '' );
+			} );
+		}
+	});
+
+	/**
 	 * wp.media.model.Attachments
 	 *
 	 * @constructor
Index: src/wp-includes/js/media-views.js
===================================================================
--- src/wp-includes/js/media-views.js	(revision 27266)
+++ src/wp-includes/js/media-views.js	(working copy)
@@ -760,6 +760,58 @@
 	});
 
 	/**
+	 * wp.media.controller.AudioDetails
+	 *
+	 * @constructor
+	 * @augments wp.media.controller.State
+	 * @augments Backbone.Model
+	 */
+	media.controller.AudioDetails = media.controller.State.extend({
+		defaults: _.defaults({
+			id: 'audio-details',
+			toolbar: 'audio-details',
+			title: l10n.audioDetailsTitle,
+			content: 'audio-details',
+			menu: 'audio-details',
+			router: false,
+			attachment: false,
+			priority: 60,
+			editing: false
+		}, media.controller.Library.prototype.defaults ),
+
+		initialize: function( options ) {
+			this.audio = options.audio;
+			media.controller.State.prototype.initialize.apply( this, arguments );
+		}
+	});
+
+	/**
+	 * wp.media.controller.VideoDetails
+	 *
+	 * @constructor
+	 * @augments wp.media.controller.State
+	 * @augments Backbone.Model
+	 */
+	media.controller.VideoDetails = media.controller.State.extend({
+		defaults: _.defaults({
+			id: 'video-details',
+			toolbar: 'video-details',
+			title: l10n.videoDetailsTitle,
+			content: 'video-details',
+			menu: 'video-details',
+			router: false,
+			attachment: false,
+			priority: 60,
+			editing: false
+		}, media.controller.Library.prototype.defaults ),
+
+		initialize: function( options ) {
+			this.video = options.video;
+			media.controller.State.prototype.initialize.apply( this, arguments );
+		}
+	});
+
+	/**
 	 * wp.media.controller.CollectionEdit
 	 *
 	 * @static
@@ -1063,75 +1115,107 @@
 		}
 	});
 
-	/**
-	 * wp.media.controller.ReplaceImage
-	 *
-	 * Replace a selected single image
-	 *
-	 * @constructor
-	 * @augments wp.media.controller.Library
-	 * @augments wp.media.controller.State
-	 * @augments Backbone.Model
-	 */
-	media.controller.ReplaceImage = media.controller.Library.extend({
-		defaults: _.defaults({
-			id:         'replace-image',
-			filterable: 'uploaded',
-			multiple:   false,
-			toolbar:    'replace',
-			title:      l10n.replaceImageTitle,
-			priority:   60,
-			syncSelection: false
-		}, media.controller.Library.prototype.defaults ),
+	media.controller.ReplaceMedia = function (type, args) {
+		return media.controller.Library.extend({
+			defaults: _.defaults({
+				id:         'replace-' + type,
+				filterable: 'uploaded',
+				multiple:   false,
+				toolbar:    'replace',
+				title:      args.title,
+				priority:   60,
+				syncSelection: false
+			}, media.controller.Library.prototype.defaults ),
 
-		initialize: function( options ) {
-			var library, comparator;
+			initialize: function( options ) {
+				var library, comparator;
 
-			this.image = options.image;
-			// If we haven't been provided a `library`, create a `Selection`.
-			if ( ! this.get('library') ) {
-				this.set( 'library', media.query({ type: 'image' }) );
-			}
+				this[type] = options[type];
+				// If we haven't been provided a `library`, create a `Selection`.
+				if ( ! this.get('library') ) {
+					this.set( 'library', media.query({ type: type }) );
+				}
 
-			media.controller.Library.prototype.initialize.apply( this, arguments );
+				media.controller.Library.prototype.initialize.apply( this, arguments );
 
-			library    = this.get('library');
-			comparator = library.comparator;
+				library    = this.get('library');
+				comparator = library.comparator;
 
-			// Overload the library's comparator to push items that are not in
-			// the mirrored query to the front of the aggregate collection.
-			library.comparator = function( a, b ) {
-				var aInQuery = !! this.mirroring.get( a.cid ),
-					bInQuery = !! this.mirroring.get( b.cid );
+				// Overload the library's comparator to push items that are not in
+				// the mirrored query to the front of the aggregate collection.
+				library.comparator = function( a, b ) {
+					var aInQuery = !! this.mirroring.get( a.cid ),
+						bInQuery = !! this.mirroring.get( b.cid );
 
-				if ( ! aInQuery && bInQuery ) {
-					return -1;
-				} else if ( aInQuery && ! bInQuery ) {
-					return 1;
-				} else {
-					return comparator.apply( this, arguments );
-				}
-			};
+					if ( ! aInQuery && bInQuery ) {
+						return -1;
+					} else if ( aInQuery && ! bInQuery ) {
+						return 1;
+					} else {
+						return comparator.apply( this, arguments );
+					}
+				};
 
-			// Add all items in the selection to the library, so any featured
-			// images that are not initially loaded still appear.
-			library.observe( this.get('selection') );
-		},
+				// Add all items in the selection to the library, so any featured
+				// images that are not initially loaded still appear.
+				library.observe( this.get('selection') );
+			},
 
-		activate: function() {
-			this.updateSelection();
-			media.controller.Library.prototype.activate.apply( this, arguments );
-		},
+			activate: function() {
+				this.updateSelection();
+				media.controller.Library.prototype.activate.apply( this, arguments );
+			},
 
-		updateSelection: function() {
-			var selection = this.get('selection'),
-				attachment = this.image.attachment;
+			updateSelection: function() {
+				var selection = this.get('selection'),
+					attachment = this[type].attachment;
 
-			selection.reset( attachment ? [ attachment ] : [] );
-		}
-	});
+				selection.reset( attachment ? [ attachment ] : [] );
+			}
+		});
+	};
 
 	/**
+	 * wp.media.controller.ReplaceImage
+	 *
+	 * Replace a selected single image
+	 *
+	 * @constructor
+	 * @augments wp.media.controller.Library
+	 * @augments wp.media.controller.State
+	 * @augments Backbone.Model
+	 */
+	media.controller.ReplaceImage = media.controller.ReplaceMedia( 'image', {
+		title : l10n.replaceImageTitle
+	} );
+	/**
+	 * wp.media.controller.ReplaceAudio
+	 *
+	 * Replace a selected single audio
+	 *
+	 * @constructor
+	 * @augments wp.media.controller.Library
+	 * @augments wp.media.controller.State
+	 * @augments Backbone.Model
+	 */
+	media.controller.ReplaceAudio = media.controller.ReplaceMedia( 'audio', {
+		title : l10n.replaceAudioTitle
+	} );
+	/**
+	 * wp.media.controller.ReplaceVideo
+	 *
+	 * Replace a selected single video
+	 *
+	 * @constructor
+	 * @augments wp.media.controller.Library
+	 * @augments wp.media.controller.State
+	 * @augments Backbone.Model
+	 */
+	media.controller.ReplaceVideo = media.controller.ReplaceMedia( 'video', {
+		title : l10n.replaceVideoTitle
+	} );
+
+	/**
 	 * wp.media.controller.Embed
 	 *
 	 * @constructor
@@ -2348,154 +2432,194 @@
 		}
 	});
 
-	media.view.MediaFrame.ImageDetails = media.view.MediaFrame.Select.extend({
-		defaults: {
-			id:      'image',
-			url:     '',
-			menu:    'image-details',
-			content: 'image-details',
-			toolbar: 'image-details',
-			type:    'link',
-			title:    l10n.imageDetailsTitle,
-			priority: 120
-		},
+	media.view.MediaFrame.MediaDetails = function (type, args) {
+		return media.view.MediaFrame.Select.extend({
+			defaults: {
+				id:      type,
+				url:     '',
+				menu:    type + '-details',
+				content: type + '-details',
+				toolbar: type + '-details',
+				type:    'link',
+				title:    args.title,
+				priority: 120
+			},
 
-		initialize: function( options ) {
-			this.image = new media.model.PostImage( options.metadata );
-			this.options.selection = new media.model.Selection( this.image.attachment, { multiple: false } );
-			media.view.MediaFrame.Select.prototype.initialize.apply( this, arguments );
-		},
+			initialize: function( options ) {
+				this[type] = new media.model[args.model]( options.metadata );
+				this.options.selection = new media.model.Selection( this[type].attachment, { multiple: false } );
+				media.view.MediaFrame.Select.prototype.initialize.apply( this, arguments );
+			},
 
-		bindHandlers: function() {
-			media.view.MediaFrame.Select.prototype.bindHandlers.apply( this, arguments );
-			this.on( 'menu:create:image-details', this.createMenu, this );
-			this.on( 'content:render:image-details', this.renderImageDetailsContent, this );
-			this.on( 'menu:render:image-details', this.renderMenu, this );
-			this.on( 'toolbar:render:image-details', this.renderImageDetailsToolbar, this );
-			// override the select toolbar
-			this.on( 'toolbar:render:replace', this.renderReplaceImageToolbar, this );
-		},
+			bindHandlers: function() {
+				media.view.MediaFrame.Select.prototype.bindHandlers.apply( this, arguments );
+				this.on( 'menu:create:' + type + '-details', this.createMenu, this );
+				this.on( 'content:render:' + type + '-details', this.renderDetailsContent, this );
+				this.on( 'menu:render:' + type + '-details', this.renderMenu, this );
+				this.on( 'toolbar:render:' + type + '-details', this.renderDetailsToolbar, this );
+				// override the select toolbar
+				this.on( 'toolbar:render:replace', this.renderReplaceToolbar, this );
+			},
 
-		createStates: function() {
-			this.states.add([
-				new media.controller.ImageDetails({
-					image: this.image,
-					editable: false,
-					menu: 'image-details'
-				}),
-				new media.controller.ReplaceImage({
-					id: 'replace-image',
-					library:   media.query( { type: 'image' } ),
-					image: this.image,
-					multiple:  false,
-					title:     l10n.imageReplaceTitle,
-					menu: 'image-details',
-					toolbar: 'replace',
-					priority:  80,
-					displaySettings: true
-				})
-			]);
-		},
+			createStates: function() {
+				var detailsParams = {
+						editable: false,
+						menu: type + '-details'
+					},
+					replaceParams = {
+						id: 'replace-' + type,
+						library: media.query( { type: type } ),
+						image: this[type],
+						multiple: false,
+						title: args.replaceTitle,
+						menu: type + '-details',
+						toolbar: 'replace',
+						priority:  80,
+						displaySettings: true
+					};
 
-		renderImageDetailsContent: function() {
-			var view = new media.view.ImageDetails({
-				controller: this,
-				model: this.state().image,
-				attachment: this.state().image.attachment
-			}).render();
+				detailsParams[type] = this[type];
+				replaceParams[type] = this[type];
 
-			this.content.set( view );
+				this.states.add([
+					new media.controller[args.detailsController](detailsParams),
+					new media.controller[args.replaceController](replaceParams)
+				]);
+			},
 
-		},
+			renderDetailsContent: function() {
+				var view = new media.view[args.detailsView]({
+					controller: this,
+					model: this.state()[type],
+					attachment: this.state()[type].attachment
+				}).render();
 
-		renderMenu: function( view ) {
-			var lastState = this.lastState(),
-				previous = lastState && lastState.id,
-				frame = this;
+				this.content.set( view );
+			},
 
-			view.set({
-				cancel: {
-					text:     l10n.imageDetailsCancel,
-					priority: 20,
-					click:    function() {
-						if ( previous ) {
-							frame.setState( previous );
-						} else {
-							frame.close();
+			renderMenu: function( view ) {
+				var lastState = this.lastState(),
+					previous = lastState && lastState.id,
+					frame = this;
+
+				view.set({
+					cancel: {
+						text:     args.cancelText,
+						priority: 20,
+						click:    function() {
+							if ( previous ) {
+								frame.setState( previous );
+							} else {
+								frame.close();
+							}
 						}
-					}
-				},
-				separateCancel: new media.View({
-					className: 'separator',
-					priority: 40
-				})
-			});
+					},
+					separateCancel: new media.View({
+						className: 'separator',
+						priority: 40
+					})
+				});
 
-		},
+			},
 
-		renderImageDetailsToolbar: function() {
-			this.toolbar.set( new media.view.Toolbar({
-				controller: this,
-				items: {
-					select: {
-						style:    'primary',
-						text:     l10n.update,
-						priority: 80,
+			renderDetailsToolbar: function() {
+				this.toolbar.set( new media.view.Toolbar({
+					controller: this,
+					items: {
+						select: {
+							style:    'primary',
+							text:     l10n.update,
+							priority: 80,
 
-						click: function() {
-							var controller = this.controller,
-								state = controller.state();
+							click: function() {
+								var controller = this.controller,
+									state = controller.state();
 
-							controller.close();
+								controller.close();
 
-							// not sure if we want to use wp.media.string.image which will create a shortcode or
-							// perhaps wp.html.string to at least to build the <img />
-							state.trigger( 'update', controller.image.toJSON() );
+								// not sure if we want to use wp.media.string.image which will create a shortcode or
+								// perhaps wp.html.string to at least to build the <img />
+								state.trigger( 'update', controller[type].toJSON() );
 
-							// Restore and reset the default state.
-							controller.setState( controller.options.state );
-							controller.reset();
+								// Restore and reset the default state.
+								controller.setState( controller.options.state );
+								controller.reset();
+							}
 						}
 					}
-				}
-			}) );
-		},
+				}) );
+			},
 
-		renderReplaceImageToolbar: function() {
-			this.toolbar.set( new media.view.Toolbar({
-				controller: this,
-				items: {
-					replace: {
-						style:    'primary',
-						text:     l10n.replace,
-						priority: 80,
+			renderReplaceToolbar: function() {
+				this.toolbar.set( new media.view.Toolbar({
+					controller: this,
+					items: {
+						replace: {
+							style:    'primary',
+							text:     l10n.replace,
+							priority: 80,
 
-						click: function() {
-							var controller = this.controller,
-								state = controller.state(),
-								selection = state.get( 'selection' ),
-								attachment = selection.single();
+							click: function() {
+								var controller = this.controller,
+									state = controller.state(),
+									selection = state.get( 'selection' ),
+									attachment = selection.single();
 
-							controller.close();
+								if ( args.closeOnReplace ) {
+									controller.close();
+								}
 
-							controller.image.changeAttachment( attachment, state.display( attachment ) );
+								controller[type].changeAttachment( attachment, state.display( attachment ) );
 
-							// not sure if we want to use wp.media.string.image which will create a shortcode or
-							// perhaps wp.html.string to at least to build the <img />
-							state.trigger( 'replace', controller.image.toJSON() );
+								// not sure if we want to use wp.media.string.image which will create a shortcode or
+								// perhaps wp.html.string to at least to build the <img />
+								state.trigger( 'replace', controller[type].toJSON() );
 
-							// Restore and reset the default state.
-							controller.setState( controller.options.state );
-							controller.reset();
+								// Restore and reset the default state.
+								controller.setState( controller.options.state );
+								controller.reset();
+							}
 						}
 					}
-				}
-			}) );
-		}
+				}) );
+			}
 
-	});
+		});
+	};
 
+	media.view.MediaFrame.ImageDetails = media.view.MediaFrame.MediaDetails( 'image', {
+		model: 'PostImage',
+		detailsView: 'ImageDetails',
+		detailsController: 'ImageDetails',
+		replaceController: 'ReplaceImage',
+		title : l10n.imageDetailsTitle,
+		replaceTitle: l10n.imageReplaceTitle,
+		cancelText: l10n.imageDetailsCancel,
+		closeOnReplace: true
+	} );
 
+	media.view.MediaFrame.AudioDetails = media.view.MediaFrame.MediaDetails( 'audio', {
+		model: 'PostAudio',
+		detailsView: 'AudioDetails',
+		detailsController: 'AudioDetails',
+		replaceController: 'ReplaceAudio',
+		title : l10n.audioDetailsTitle,
+		replaceTitle: l10n.audioReplaceTitle,
+		cancelText: l10n.audioDetailsCancel,
+		closeOnReplace: false
+	} );
+
+	media.view.MediaFrame.VideoDetails = media.view.MediaFrame.MediaDetails( 'video', {
+		model: 'PostVideo',
+		detailsView: 'VideoDetails',
+		detailsController: 'VideoDetails',
+		replaceController: 'ReplaceVideo',
+		title : l10n.videoDetailsTitle,
+		replaceTitle: l10n.videoReplaceTitle,
+		cancelText: l10n.videoDetailsCancel,
+		closeOnReplace: false
+	} );
+
 	/**
 	 * wp.media.view.Modal
 	 *
@@ -5511,7 +5635,7 @@
 	 * @augments Backbone.View
 	 */
 	media.view.EmbedImage =  media.view.Settings.AttachmentDisplay.extend({
-		className: 'embed-image-settings',
+		className: 'embed-media-settings',
 		template:  media.template('embed-image-settings'),
 
 		initialize: function() {
@@ -5527,49 +5651,100 @@
 		}
 	});
 
-	media.view.ImageDetails = media.view.Settings.AttachmentDisplay.extend({
-		className: 'image-details',
-		template:  media.template('image-details'),
+	/**
+	 * @static
+	 * @param {string} type
+	 * @returns {wp.media.view.Settings.AttachmentDisplay}
+	 */
+	media.view.MediaDetails = function (type) {
+		/**
+		 *
+		 * @contructor
+		 * @augments wp.media.view.Settings.AttachmentDisplay
+		 * @augments wp.media.view.Settings
+		 * @augments wp.media.View
+		 * @augments wp.Backbone.View
+		 * @augments Backbone.View
+		 */
+		return media.view.Settings.AttachmentDisplay.extend({
+			className: type + '-details',
+			template:  media.template(type + '-details'),
 
-		initialize: function() {
-			// used in AttachmentDisplay.prototype.updateLinkTo
-			this.options.attachment = this.model.attachment;
-			media.view.Settings.AttachmentDisplay.prototype.initialize.apply( this, arguments );
-		},
+			initialize: function() {
+				// used in AttachmentDisplay.prototype.updateLinkTo
+				this.options.attachment = this.model.attachment;
+				media.view.Settings.AttachmentDisplay.prototype.initialize.apply( this, arguments );
+			},
 
-		prepare: function() {
-			var attachment = false;
+			prepare: function() {
+				var attachment = false;
 
-			if ( this.model.attachment ) {
-				attachment = this.model.attachment.toJSON();
-			}
-			return _.defaults({
-				model: this.model.toJSON(),
-				attachment: attachment
-			}, this.options );
-		},
+				if ( this.model.attachment ) {
+					attachment = this.model.attachment.toJSON();
+				}
+				return _.defaults({
+					model: this.model.toJSON(),
+					attachment: attachment
+				}, this.options );
+			},
 
+			render: function() {
+				var self = this,
+					args = arguments;
+				if ( this.model.attachment && this.model.dfd && 'pending' === this.model.dfd.state() ) {
+					// should instead show a spinner when the attachment is new and then add a listener that updates on change
+					this.model.dfd.done( function() {
+						media.view.Settings.AttachmentDisplay.prototype.render.apply( self, args );
+						self.resetFocus();
+					} );
+				} else {
+					media.view.Settings.AttachmentDisplay.prototype.render.apply( this, arguments );
+					setTimeout( function() { self.resetFocus(); }, 10 );
+				}
 
-		render: function() {
-			var self = this,
-				args = arguments;
-			if ( this.model.attachment && 'pending' === this.model.dfd.state() ) {
-				// should instead show a spinner when the attachment is new and then add a listener that updates on change
-				this.model.dfd.done( function() {
-					media.view.Settings.AttachmentDisplay.prototype.render.apply( self, args );
-					self.resetFocus();
-				} );
-			} else {
-				media.view.Settings.AttachmentDisplay.prototype.render.apply( this, arguments );
-				setTimeout( function() { self.resetFocus(); }, 10 );
+				return this;
+			},
+
+			resetFocus: function() {
+				this.$( '.caption textarea' ).focus();
+				this.$( '.embed-media-settings' ).scrollTop( 0 );
 			}
+		} );
+	};
 
-			return this;
-		},
+	/**
+	 * wp.media.view.ImageDetails
+	 *
+	 * @contructor
+	 * @augments wp.media.view.Settings.AttachmentDisplay
+	 * @augments wp.media.view.Settings
+	 * @augments wp.media.View
+	 * @augments wp.Backbone.View
+	 * @augments Backbone.View
+	 */
+	media.view.ImageDetails = media.view.MediaDetails( 'image' );
 
-		resetFocus: function() {
-			this.$( '.caption textarea' ).focus();
-			this.$( '.embed-image-settings' ).scrollTop( 0 );
-		}
-	});
+	/**
+	 * wp.media.view.AudioDetails
+	 *
+	 * @contructor
+	 * @augments wp.media.view.Settings.AttachmentDisplay
+	 * @augments wp.media.view.Settings
+	 * @augments wp.media.View
+	 * @augments wp.Backbone.View
+	 * @augments Backbone.View
+	 */
+	media.view.AudioDetails = media.view.MediaDetails( 'audio' );
+
+	/**
+	 * wp.media.view.VideoDetails
+	 *
+	 * @contructor
+	 * @augments wp.media.view.Settings.AttachmentDisplay
+	 * @augments wp.media.view.Settings
+	 * @augments wp.media.View
+	 * @augments wp.Backbone.View
+	 * @augments Backbone.View
+	 */
+	media.view.VideoDetails = media.view.MediaDetails( 'video' );
 }(jQuery));
Index: src/wp-includes/js/tinymce/plugins/wpgallery/plugin.js
===================================================================
--- src/wp-includes/js/tinymce/plugins/wpgallery/plugin.js	(revision 27266)
+++ src/wp-includes/js/tinymce/plugins/wpgallery/plugin.js	(working copy)
@@ -53,7 +53,7 @@
 	}
 
 	function editMedia( node ) {
-		var gallery, frame, data;
+		var gallery, frame, data, shortcode;
 
 		if ( node.nodeName !== 'IMG' ) {
 			return;
@@ -64,10 +64,11 @@
 			return;
 		}
 
+		data = window.decodeURIComponent( editor.dom.getAttrib( node, 'data-wp-media' ) );
+
 		// Make sure we've selected a gallery node.
 		if ( editor.dom.hasClass( node, 'wp-gallery' ) && wp.media.gallery ) {
 			gallery = wp.media.gallery;
-			data = window.decodeURIComponent( editor.dom.getAttrib( node, 'data-wp-media' ) );
 			frame = gallery.edit( data );
 
 			frame.state('gallery-edit').on( 'update', function( selection ) {
@@ -75,7 +76,6 @@
 				editor.dom.setAttrib( node, 'data-wp-media', window.encodeURIComponent( shortcode ) );
 			});
 		} else if ( editor.dom.hasClass( node, 'wp-playlist' ) && wp.media.playlist ) {
-			data = window.decodeURIComponent( editor.dom.getAttrib( node, 'data-wp-media' ) );
 			frame = wp.media.playlist.edit( data );
 
 			frame.state('playlist-edit').on( 'update', function( selection ) {
@@ -83,7 +83,6 @@
 				editor.dom.setAttrib( node, 'data-wp-media', window.encodeURIComponent( shortcode ) );
 			});
 		} else if ( editor.dom.hasClass( node, 'wp-video-playlist' ) && wp.media['video-playlist'] ) {
-			data = window.decodeURIComponent( editor.dom.getAttrib( node, 'data-wp-media' ) );
 			frame = wp.media['video-playlist'].edit( data );
 
 			frame.state('video-playlist-edit').on( 'update', function( selection ) {
@@ -90,9 +89,39 @@
 				var shortcode = wp.media['video-playlist'].shortcode( selection ).string();
 				editor.dom.setAttrib( node, 'data-wp-media', window.encodeURIComponent( shortcode ) );
 			});
+		} else if ( editor.dom.hasClass( node, 'wp-video' ) ) {
+			shortcode = wp.shortcode.next( 'video', data ).shortcode;
+			frame = wp.media({
+				frame: 'video',
+				state: 'video-details',
+				metadata: _.defaults(
+					shortcode.attrs.named,
+					wp.media.video.defaults
+				)
+			} );
+			frame.state( 'video-details' ).on( 'update replace', function ( selection ) {
+				var shortcode = wp.media.video.shortcode( selection );
+				editor.dom.setAttrib( node, 'data-wp-media', window.encodeURIComponent( shortcode ) );
+			} );
+			frame.open();
+		} else if ( editor.dom.hasClass( node, 'wp-audio' ) ) {
+			shortcode = wp.shortcode.next( 'audio', data ).shortcode;
+			frame = wp.media({
+				frame: 'audio',
+				state: 'audio-details',
+				metadata: _.defaults(
+					shortcode.attrs.named,
+					wp.media.audio.defaults
+				)
+			});
+			frame.state( 'audio-details' ).on( 'update replace', function ( selection ) {
+				var shortcode = wp.media.audio.shortcode( selection );
+				editor.dom.setAttrib( node, 'data-wp-media', window.encodeURIComponent( shortcode ) );
+			} );
+			frame.open();
 		} else {
 			// temp
-			window.console && window.console.log( 'Edit AV shortcode ' + window.decodeURIComponent( editor.dom.getAttrib( node, 'data-wp-media' ) ) );
+			window.console && window.console.log( 'Edit AV shortcode ' + data );
 		}
 	}
 
Index: src/wp-includes/media-template.php
===================================================================
--- src/wp-includes/media-template.php	(revision 27266)
+++ src/wp-includes/media-template.php	(working copy)
@@ -556,7 +556,7 @@
 	<script type="text/html" id="tmpl-image-details">
 		<?php // reusing .media-embed to pick up the styles for now ?>
 		<div class="media-embed">
-			<div class="embed-image-settings">
+			<div class="embed-media-settings">
 				<div class="thumbnail">
 					<img src="{{ data.model.url }}" draggable="false" />
 				</div>
@@ -649,6 +649,106 @@
 			</div>
 		</div>
 	</script>
+
+	<script type="text/html" id="tmpl-audio-details">
+		<?php // reusing .media-embed to pick up the styles for now ?>
+		<div class="media-embed">
+			<div class="embed-media-settings">
+				<# if ( data.model.src ) { #>
+				<label class="setting">
+					<span>SRC</span>
+					<input type="text" disabled="disabled" data-setting="src" value="{{{ data.model.src }}}" />
+				</label>
+				<# } #>
+				<?php
+				$default_types = wp_get_audio_extensions();
+
+				foreach ( $default_types as $type ): ?>
+				<# if ( data.model.<?php echo $type ?> ) { #>
+				<label class="setting">
+					<span><?php echo strtoupper( $type ) ?></span>
+					<input type="text" disabled="disabled" data-setting="<?php echo $type ?>" value="{{{ data.model.<?php echo $type ?> }}}" />
+				</label>
+				<# } #>
+				<?php endforeach ?>
+
+				<div class="setting preload">
+					<span><?php _e( 'Preload' ); ?></span>
+					<div class="button-group button-large" data-setting="preload">
+						<button class="button" value="auto">
+							<?php esc_attr_e( 'Auto' ); ?>
+						</button>
+						<button class="button" value="metadata">
+							<?php esc_attr_e( 'Metadata' ); ?>
+						</button>
+						<button class="button active" value="none">
+							<?php esc_attr_e( 'None' ); ?>
+						</button>
+					</div>
+				</div>
+
+				<label class="setting">
+					<span><?php _e( 'Autoplay' ); ?></span>
+					<input type="checkbox" data-setting="autoplay" />
+				</label>
+
+				<label class="setting">
+					<span><?php _e( 'Loop' ); ?></span>
+					<input type="checkbox" data-setting="loop" />
+				</label>
+			</div>
+		</div>
+	</script>
+
+	<script type="text/html" id="tmpl-video-details">
+		<?php // reusing .media-embed to pick up the styles for now ?>
+		<div class="media-embed">
+			<div class="embed-media-settings">
+				<# if ( data.model.src ) { #>
+				<label class="setting">
+					<span>SRC</span>
+					<input type="text" disabled="disabled" data-setting="src" value="{{{ data.model.src }}}" />
+				</label>
+				<# } #>
+				<?php
+				$default_types = wp_get_video_extensions();
+
+				foreach ( $default_types as $type ): ?>
+				<# if ( data.model.<?php echo $type ?> ) { #>
+				<label class="setting">
+					<span><?php echo strtoupper( $type ) ?></span>
+					<input type="text" disabled="disabled" data-setting="<?php echo $type ?>" value="{{{ data.model.<?php echo $type ?> }}}" />
+				</label>
+				<# } #>
+				<?php endforeach ?>
+
+				<div class="setting preload">
+					<span><?php _e( 'Preload' ); ?></span>
+					<div class="button-group button-large" data-setting="preload">
+						<button class="button" value="auto">
+							<?php esc_attr_e( 'Auto' ); ?>
+						</button>
+						<button class="button" value="metadata">
+							<?php esc_attr_e( 'Metadata' ); ?>
+						</button>
+						<button class="button active" value="none">
+							<?php esc_attr_e( 'None' ); ?>
+						</button>
+					</div>
+				</div>
+
+				<label class="setting">
+					<span><?php _e( 'Autoplay' ); ?></span>
+					<input type="checkbox" data-setting="autoplay" />
+				</label>
+
+				<label class="setting">
+					<span><?php _e( 'Loop' ); ?></span>
+					<input type="checkbox" data-setting="loop" />
+				</label>
+			</div>
+		</div>
+	</script>
 	<?php
 
 	/**
Index: src/wp-includes/media.php
===================================================================
--- src/wp-includes/media.php	(revision 27266)
+++ src/wp-includes/media.php	(working copy)
@@ -2341,6 +2341,16 @@
 		'imageReplaceTitle'     => __( 'Replace Image' ),
 		'imageDetailsCancel'    => __( 'Cancel Edit' ),
 
+		// Edit Image
+		'audioDetailsTitle'     => __( 'Audio Details' ),
+		'audioReplaceTitle'     => __( 'Replace Audio' ),
+		'audioDetailsCancel'    => __( 'Cancel Edit' ),
+
+		// Edit Image
+		'videoDetailsTitle'     => __( 'Video Details' ),
+		'videoReplaceTitle'     => __( 'Replace Video' ),
+		'videoDetailsCancel'    => __( 'Cancel Edit' ),
+
  		// Playlist
  		'playlistDragInfo'    => __( 'Drag and drop to reorder tracks.' ),
  		'createPlaylistTitle' => __( 'Create Playlist' ),
