Video Player Refinements

Last week, we presented a method for playing videos that supports external monitors (like the Apple VGA Adapter). But we left out a few finishing touches.

Recall that the big idea was to use a UIWebView to display the video, rather than an MPMoviePlayerController, because Apple has already equipped the web view to support external monitors. We just needed a simple modal view that contained a UIWebView, wrap our video reference in a bit of HTML, and show it.

 

The biggest problem was that, with the wrapper code shown last week, the video would not properly scale to fit the screen in both landscape and portrait modes. That's a bummer because iPhone and iPad users that don't have an external monitor have become accustomed to switching to landscape mode to zoom in on a video.

Fixing this required some fairly intensive fiddling around with the HTML and CSS. It got too long to comfortably put in the ObjC code as a string constant, so we instead made a little HTML file and dragged that into the project as well. That file contains this:

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="utf-8">
		<meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, user-scalable=no, width=device-width">
		<meta name="apple-mobile-web-app-capable" content="yes">
		<style>
			body, html {height: 100%; background:#000000; }
		</style>
	</head>
	<body bgcolor="#000000">
		<div style="position:relative; margin:0; width:100%; height:100%">
			<video src="%@" width="100%" height="100%" controls autoplay style="margin:0; position:absolute;"></video>
		</div>
	</body>
</html>

Key bits here are the meta tags that tell WebKit how and when to scale the view; the height style applied to the body and html tags; the size and position styles on the div containing the video; and the 100% width and height attributes of the video tag itself. All those are necessary to make the magic happen, and with them, the video will properly fill the screen as you switch between portrait and landscape mode.

Note the "%@" for the source of the video; that gets substituted with the name (or relative path) of the actual video file. The Cocoa code loading it all now looks like this:

	NSBundle *mainBundle = [NSBundle mainBundle];
	NSString *generalHTML = [NSString stringWithContentsOfFile:[mainBundle pathForResource:@"LoadMovie" ofType:@"html"] encoding:NSUTF8StringEncoding error:nil];
	
	NSString *videoHTML = [NSString stringWithFormat:generalHTML, videoName];
	
	[webView loadHTMLString:videoHTML baseURL:[mainBundle resourceURL]];

The other problem we stumbled upon was a bug in UIWebView on iPad: even after the view containing it is torn down, the audio stream continues to play in the background. We followed this StackOverflow suggestion, to blank out the web view before we dismiss it. So our dismissView method (the action of the "Done" button) now looks like this:

- (void)dismissView:(id)sender {
	[webView loadHTMLString:@"about:blank" baseURL:nil];  
    [self dismissModalViewControllerAnimated:YES];
}

Those refinements put the finishing touches on the video player, making a well-behaved little class that's easy to reuse in any project.