Archive

Posts Tagged ‘Video Streaming’

MJPEG to H.264 Streaming for Mobile with VLC

October 6th, 2011 Comments off

VLC Media PlayerDang! Its been a while since I’ve been able to get out here and post something new. We’ve been busy, busy, busy here at v4 living the dream.

Anyhow, as of recently its been tasked upon us to work with some streaming video. Now, the hardware we will be using for our client are some nice IP/H.264 compatible cameras. Well, I personally do not have one but needed a solution by which I could test and work with. I have one of those little eye ball looking cameras and found some free software (WebCamXP) that would run a simple MJPEG stream. (Yea, yea…its windows but who doesn’t have a windows box to hack and slash on? Ha!) After this is up and running you have a basic MJPEG stream that is running and accessible via http://10.0.0.99:8080/webcamp_1.cgi (or whatever your internal IP is and the port you configured in the software)

** Note: This tutorial uses iPhone references as thats what I worked with first. I’ll update with the Android version later. I am also using Linux (Ubuntu) to do the encoding and serving of the new video stream. Also assuming you have Apache or another web server up and running.

Now, this .cgi page/script ‘can’ be placed as the source of a UIWebview and works ok.

NSString *urlAddress = @"http://10.0.0.99:8080/cam_1.cgi";
NSURL *url = [NSURL URLWithString:urlAddress];
NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];
[streamWebView loadRequest:requestObj];

But, ultimately this is not what we’re looking for. We need to get a nice H.264 compatible stream rolling out so that we can play this directly to the iPhone (MPMoivePlayerController) or be able to hook into a streaming server (as we’re planning on doing) so that we can re-broadcast to several devices at once.

So…how might we convert this MJPEG (.cgi) into an H.264 compatible stream? VLC Media Player to the rescue.

On your Linux box install VLC and the x264 libraries.

# apt-get install vlc x264

A few of the tutorials you read on this all reference using the command: vlc. However, if you don’t have X11 installed on your system (as I do not) you will run into a few errors with regards to this. But, have no fear, VLC provided a command line option: cvlc.

Now what we need to do is fire up VLC with a bunch of options that will read in the MJPEG (.cgi) convert it to H.264 and then provide us with a means of accessing the stream (via the Linux server – 10.0.0.69). So, on the command prompt do something like:

cvlc --intf=rc http://10.0.0.99:8080/cam_1.cgi --sout '#transcode{fps=25,
vcodec=h264,venc=x264{aud,profile=baseline,level=30,keyint=30,
bframes=0,ref=1,nocabac},acodec=mp3,ab=56,audio-sync,deinterlace}
:standard{mux=ts,access=http,dst=10.0.0.69:8090/myStream.mp4}'

Now, on the command prompt you’ll see a bunch of stuff start scrolling by. This is what you want. Its reading in frames from the original MJPEG stream and converting them. But, you’re not done yet. In order to get this to play via MPMoviePlayerController on the iPhone, we need to setup the .m3u8 or the playlist file.

In your web server directory create a file myStream.m3u8 and put the following in and save:

#EXTM3U
#EXT-X-TARGETDURATION:10
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:10, 

http://10.0.0.69:8090/myStream.mp4

Now you’re ready for some iPhone code to show the stream.

NSURL *url = [NSURL URLWithString:@"http://10.0.0.69/myStream.m3u8"];
MPMoviePlayerController *player = [[MPMoviePlayerController alloc] initWithContentURL:url];
player.controlStyle = MPMovieControlStyleNone;
[player.view setFrame:CGRectMake(0, 120, 320 , 200)];
[self.view addSubview:player.view];
[player play];

This should basically do it. I don’t believe I left out any steps. I’ll update if I run across any missing steps or you guys let me know. When you run the app, it can sometimes take a few seconds before the video starts playing. At one point I set a background color to the mpmovieplayercontroller’s view so that I could tell where it was being

With MPMoviePlayerController there are several other options you may be interested in using/implementing.

When setting up the player you can have your containing view controller listen for some of the playback events (can help with some debugging) with:

//Defined in the above MPMoviePlayerController allocation
[[NSNotificationCenter defaultCenter] addObserver:self  selector:@selector(moviePlayerPlaybackStateDidChange:)  name:MPMoviePlayerPlaybackStateDidChangeNotification  object:nil];
//NSNotification callback function
- (void)moviePlayerPlaybackStateDidChange:(NSNotification*)notification {
     NSLog(@"playbackDidChanged");
     MPMoviePlayerController *moviePlayer = notification.object;

     MPMoviePlaybackState playbackState = moviePlayer.playbackState;

     if(playbackState == MPMoviePlaybackStateStopped) {
          NSLog(@"MPMoviePlaybackStateStopped");
     } else if(playbackState == MPMoviePlaybackStatePlaying) {
          NSLog(@"MPMoviePlaybackStatePlaying");
     } else if(playbackState == MPMoviePlaybackStatePaused) {
          NSLog(@"MPMoviePlaybackStatePaused");
     } else if(playbackState == MPMoviePlaybackStateInterrupted) {
          NSLog(@"MPMoviePlaybackStateInterrupted");
     } else if(playbackState == MPMoviePlaybackStateSeekingForward) {
          NSLog(@"MPMoviePlaybackStateSeekingForward");
     } else if(playbackState == MPMoviePlaybackStateSeekingBackward) {
          NSLog(@"MPMoviePlaybackStateSeekingBackward");
     }
}

Please let me know if I’ve left out any steps or you have any issues and I’ll be happy to help and work through it with you. This was a quick and dirty how-to with a ways to go before I push anything out to production. Just wanted to share my research and discovery. Good luck!

References:
Apple – Reference: MPMoviePlayerController
StackOverflow – HTTP stream without extension in MPMoviePlayerController