Robert Whitman’s ‘Passport,’ in Two States at Once – NYTimes.com

Nice article in the Times about Whitman’s latest piece.  I built and ran the video network that connected the two locations for the performance.  Scenes from each location were transmitted and shown live in the other location.

Robert Whitman’s ‘Passport,’ in Two States at Once – NYTimes.com.

The Secure Smart Camera App for Human Rights Video : Video For Change :: A WITNESS blog

Bryan at WITNESS put up a blog post concerning the app that I am working on along with other Guardian folks.

The Secure Smart Camera App for Human Rights Video : Video For Change :: A WITNESS blog.

It’s worth a look if you are interested in the intersection of human rights, mobile technology and citizen media. It’s an open source Android project too!

AnDevCon – Developing Media Applications

Just finished a day long workshop in San Francisco at Andevcon. It went well and hopefully the participants found it useful.

Here are the slides and examples:
Camera via Intent
Custom Camera
Custom Camera with Parameters
Custom Audio Player
Audio Recorder
Video Capture

Of course, similar examples plus more can be found in my book, Pro Android Media and the source for the examples in the book is available

Announcing: Android Media Developers

I decided it was high time that we had a listserv just for Android developers working with media (audio, video, images, sharing, streaming, capture and so on) so I created a Google Group: http://groups.google.com/group/android-media-developers

In addition, it will serve as a good place where folks reading Pro Android Media can come to ask questions, get support and so on.

Open for Business

Walking Productions provides software development and consulting services. Appealing projects are those that deal with online and mobile media (audio/video). Get in touch: vanevery@walking-productions.com

Android Application Development
Flash Video Players, including P2P (Adobe Stratus)
Wowza Media Server Plugin/Module Development
Flash Media Server Development
Development related to Axis IP Cameras
QuickTime/Darwin Streaming Solutions
Audio and Video Encoding/Transcoding Pipelines
iPhone Application Development
JME/J2ME Application Development
Asterisk and VoIP Application Development
Phone call to streaming applications
Voicemail to Blog/CMS
Podcasting Systems
Mobile and Microblogging Solutions
SMS Campaign Management Software
2 Screen Interactive Television Applications (Enhanced TV)
EBIF iTV Application Development
HTML 5 Video Player Development
Media Asset Management Systems
AJAX/JavaScript/DHTML Development
LAMP Application Development (Linux, MySQL, PHP)
Java Desktop Application Development
Mobile Video Capture, Sharing and Playback Applications
Live Mobile Video Streaming
Computer Vision Applications in Java and Flash
Flash Video Capture
Location Aware Mobile Applications
Video Indexing, Searching, Recommendation Engine and Presentation Systems
Network Controlled Devices
WordPress and Drupal Plugin/Module Development
Flash Lite Application Development
AIR/ActionScript 3 Application Development
WebService Integration and Development (XML-RPC, SOAP, REST)
Podcasting (Audio/Video) Solutions
MP3 Streaming Servers
MMS Gateway Solutions
Java and AJAX Chat Application Development
Interactive Whiteboard Applications

Live iPhone Video

I recently read about an app for the iPhone called Knocking Video. It is apparently the first app that allows live streams from an iPhone (any iPhone model) that has been approved by Apple. The story I read went on to describe the saga of it’s struggle for approval and it seems was given the thumbs up from none other than Steve Jobs.

A great story and I love the concept of the app. Unfortunately I think it is doomed to failure. There are just too many barriers in it that are needlessly going to turn off potential users.

The first problem has to do with the sign-up portion of the app. It asks for first name, last name and email. The problem is that it’s error checking is just too aggressive and bug filled. For instance my last name is two words and that wasn’t allowed. Good luck people who want to find me on the app, you won’t be able to because I had to use a last name that isn’t correct. Perhaps you could try to find me via my email address? Guess again, it didn’t allow a dash in my domain name so again I had to use an alternate.

Second, once you join you have to figure out somehow if any of your friends are already using it. There is no way to test the app (as far as I can tell) without a friend “knocking”. They should at least have an echo or testing user that people could try it with.

Since I have no way to evaluate the app, I am not going to send emails to my friends asking them to join..

Ooh yeah, I went to the help and about screens to figure out how to let the company know my issues but the email address they list doesn’t exist.. Guess this blog post will have to suffice, perhaps they’ll read it.

Flash Media Server Sending Images

One of my students in my live web class is developing an interesting application that sends screenshots to other people. I put together some sample code to help him along and thought this would be of general interest.

Using the Flash Media Server with Remote Shared Objects this can be built. Here is a walk through of the code:

First of all, this uses the JPGEncoder class from the AS3CoreLib so you probably want to grab that and import it.

	import com.adobe.images.JPGEncoder;

This example uses a SharedObject, a NetConnection and NetStreams for sending the video as well as the screen shots. Once the NetConnection is established, the SharedObject can be setup:

        // Listener for connection
        private function connectionHandler (e:NetStatusEvent):void 
        { 
        	// If we are connected
             if (e.info.code == "NetConnection.Connect.Success") 
             {
				// Set up the shared object
				// We'll call it SimpleSO, pass in the app url and not make it persistent
				sharedObject = SharedObject.getRemote("SimpleSO",nc.uri,false);
				
				// Tell the shared object to call methods in this class if requested
				sharedObject.client = this;				
				
				// Add a listener for when shared object is changed
			   	sharedObject.addEventListener (SyncEvent.SYNC,syncEventCallBack); 

				// Connect the shared object to our netConnection
				sharedObject.connect(nc);
				
				// All of the video streaming setup
				doEverything();
				
				// Register mouseclicks, how we'll determine when to send a frame
				stage.addEventListener(MouseEvent.MOUSE_DOWN, saveFrame);
             } 
        }

Here is the method that is called when the mouse is clicked. It creates a bitmapdata object, encodes as a JPEG and sends that as a bytearray through the shared object:

        private function saveFrame(e:MouseEvent):void
        {        
        	// Save the frame to the bitmapdata object
        	var bmpd:BitmapData = new BitmapData(320,240);
        	bmpd.draw(videoIn1);
                	
        	// First encode as JPEG so it is smaller
			var jpgEncoder:JPGEncoder = new JPGEncoder(100);
			var jpgByteArray:ByteArray = jpgEncoder.encode(bmpd);
			
			// Send it via the shared object
			sharedObject.send("newBitmap",jpgByteArray);
        }

The SharedObject.send method calls the function “newBitmap” on everyone who is connected and passes in the jpgByteArray. The newBitmap function uses the Loader to uncompress the JPG and when it is done calls “gotBitmapData”:

		public function newBitmap(jpgByteArray:ByteArray):void
		{
			var loader:Loader = new Loader();
			loader.contentLoaderInfo.addEventListener(Event.COMPLETE, gotBitmapData)
			loader.loadBytes(jpgByteArray);
		}

gotBitmap data just creates a regular Bitmap and displays it:

	private function gotBitmapData(e:Event):void
	{
		var decodedBitmapData:BitmapData = Bitmap(e.target.content).bitmapData

        	// Create the bitmap image
        	var bmp:Bitmap = new Bitmap(decodedBitmapData);
        	
        	// Add it to the stage
        	bmp.x = 0;
        	bmp.y = 240;
        	addChild(bmp);			
	}

Here is the full AS3 class (it could be improved but it works):

package
{
	// Import JPEGEncoder Class from: http://code.google.com/p/as3corelib/
	import com.adobe.images.JPGEncoder;

	import flash.display.Sprite; 
	import flash.display.MovieClip; 
	import flash.events.NetStatusEvent; 
	import flash.net.NetConnection; 
	import flash.net.NetStream; 
	import flash.media.Camera; 
	import flash.media.Microphone; 
	import flash.media.Video; 
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.events.MouseEvent;
	import flash.utils.ByteArray;
	import flash.net.SharedObject; 
  	import flash.events.SyncEvent; 
  	import flash.events.Event;
	import flash.display.Loader;

	public class VideoCapture extends Sprite
	{
		// Shared Object for communication
   		private var sharedObject:SharedObject;

 		// Overall NetConnection for communicating with FMS
        private var nc:NetConnection; 
        
        // RTMP URL, same as directory on FMS
        private var rtmpURL:String = "rtmp://xxxx/webcam";
         
        // NetStreams for each stream 
        private var netStreamOut:NetStream; 
        private var netStreamIn1:NetStream; 
        
        // Camera
        private var camera:Camera; 
        // Microphone
        private var microphone:Microphone; 
                
        // My Video
        private var videoOut:Video; 
        
        // Video Components
        private var videoIn1:Video; 
        
        // Stream Names
        private var outStream:String; 
        private var inStream1:String; 

        public function VideoCapture() 
        { 
        	// Construct NetConnection and connect to server
             nc = new NetConnection(); 
             nc.connect(rtmpURL); 
             
             // Add a listener for connection
             nc.addEventListener (NetStatusEvent.NET_STATUS,connectionHandler); 
        } 
        
        
        // Listener for connection
        private function connectionHandler (e:NetStatusEvent):void 
        { 
        	// If we are connected
             if (e.info.code == "NetConnection.Connect.Success") 
             {

				// Set up the shared object
				// We'll call it SimpleSO, pass in the app url and not make it persistent
				sharedObject = SharedObject.getRemote("SimpleSO",nc.uri,false);
				
				// Tell the shared object to call methods in this class if requested
				sharedObject.client = this;				
				
				// Connect the shared object to our netConnection
				sharedObject.connect(nc);
				
				// All of the video streaming
				doEverything();
				
				// Register mouseclicks, how we'll determine when to send a frame
				stage.addEventListener(MouseEvent.MOUSE_DOWN, saveFrame);
             } 
        }
        
        // Gets the results from the server
        private function doEverything():void 
        { 
        	// Name of streams
			outStream="one"; 
			inStream1="one"; 
        
			// Setup the camera        
			camera = Camera.getCamera(); 

			// setup the microphone             
			microphone = Microphone.getMicrophone(); 

			// Video components
			videoOut = new Video(); 
    		videoIn1 = new Video();

			// Set positions 
			videoOut.x = 0;
			videoOut.y = 0;
			videoIn1.x = 320;
			videoIn1.y = 0;

			// Add them to the screen
			addChild(videoOut);
			addChild(videoIn1);

            // Publish our stream
            netStreamOut = new NetStream(nc); 
            netStreamOut.attachAudio(microphone); 
            netStreamOut.attachCamera(camera); 
            netStreamOut.publish(outStream, "live"); 
             
            // Attach camera to our video 
            videoOut.attachCamera(camera); 
             
            //Play incoming streamed video 
            netStreamIn1 = new NetStream(nc); 

			videoIn1.attachNetStream(netStreamIn1);

			netStreamIn1.play(inStream1);
        }
        
        private function saveFrame(e:MouseEvent):void
        {        
        	// Save the frame to the bitmapdata object
        	var bmpd:BitmapData = new BitmapData(320,240);
        	bmpd.draw(videoIn1);
                	
        	// First encode as JPEG so it is smaller
			var jpgEncoder:JPGEncoder = new JPGEncoder(100);
			var jpgByteArray:ByteArray = jpgEncoder.encode(bmpd);
			
			// Send it via the shared object
			sharedObject.send("newBitmap",jpgByteArray);
        }
        
		
		public function newBitmap(jpgByteArray:ByteArray):void
		{
			var loader:Loader = new Loader();
			loader.contentLoaderInfo.addEventListener(Event.COMPLETE, gotBitmapData)
			loader.loadBytes(jpgByteArray);
		}
		
		private function gotBitmapData(e:Event):void
		{
			var decodedBitmapData:BitmapData = Bitmap(e.target.content).bitmapData

        	// Create the bitmap image
        	var bmp:Bitmap = new Bitmap(decodedBitmapData);
        	
        	// Add it to the stage
        	bmp.x = 0;
        	bmp.y = 240;
        	addChild(bmp);			
		}
	} 
}

Major League Baseball and the Live Web

Some time ago, I cut the cord.. disconnected from cable. Some time after that, I got rid of the antenna as well.

I still watch television content, just not over the air or via cable; rather with a Mac Mini hooked up to my TV via the internet.

For the most part this works out just fine. I have no lack of video available due to a Netflix plan for both DVD and streaming (I use the streaming service waaaaaaaaay more than the DVD service), Hulu, ABC.com and NBC.com streaming, video podcasts and BitTorrent. (I am by no means alone, many people I know have a similar setup.)

The one part that doesn’t work out so well is when I want to watch a live televised event. TV it turns out is a pretty good medium for dissemination of live events. It is on these occasions that I generally miss having cable or an antenna hooked up to my TV.

Specifically during the last election I had a hard time watching the returns come in via streaming stations, during the last Superbowl I actually ran a long coax cable out to my yard hooked up to an antenna to watch the commercials.

Last week, I decided that I wanted to watch some of the baseball playoffs (this week it is the World Series). Being able to go out and watch the game at a bar is an option, I did so the first night but I can’t do that for every game. For the next game, I decided that I would try to watch it live online.

I noticed at first that the MLB did have some kind of streaming service but I wasn’t ready to plop almost $30 for a subscription..

Instead, I checked for the game on Justin.TV and UStream. Unsurprisingly, it was there (and a lot of people were watching). MLB it seems doesn’t have the resources to shut down (through DMCA takedown notices) pirate streams very quickly. I loved the chat room on the one that I was watching. It was a bit like being at a bar but actually talking when I liked and ignoring when I didn’t (which is a bit hard when the drunk next to you decides to talk to you in a bar).
ustream baseball

The best version I found was a stream of an ESPN broadcast from India. I was watching the game with people from all over the US and the world. It was fun, people were chatting, talking about where they are from, which teams they like and so on. It was also kind of fun to watch the commercials from India especially since I didn’t know what half of the products/companies were. The quality of the stream wasn’t that great, it stuttered at times, it was pixelated, definitely wasn’t good enough to watch full screen and so on..

Unfortunately, being the internet, the chat at times would turn ugly. The trolls showed unfortunately showed up and did everything possible to incite anger in those there to simply watch and talk about the game.

Shortly after that, the stream was shut down due to a DMCA takedown.

This seemed pretty ridiculous to me. The broadcast I was watching was a low quality version of what was already on TV. The commercials were in place, MLB or Fox wasn’t paying for the bandwidth and so on. It was just opening up the game to an audience that couldn’t ordinarily watch it on TV due to where they live or not having a television available. I do understand copyright and the law and I know that this is illegal but I still don’t see the point is doing anything about it. Perhaps if MLB or Fox just made it available they could make a bit of money showing some relevant commercials..

In any case, it was time to go back to MLB.com and have a look see. After trying to figure out if I could even watch mlb.tv if I paid for it (it seemed I couldn’t since there was a “National Blackout”), I decided to try out the alternate service: postseason.tv. I thought that it was actually just a way to watch the playoffs rather than the full MLB.tv service and it seemed it didn’t have the same blackout restrictions.

Unfortunately (or fortunately, depending on your perspective) that isn’t precisely what you get when you sign up for postseason.tv. What you get is a pretty slick service where you can pick and choose which cameras (up to 4 at once) you want to watch. You get the live audio from the TV broadcast. The cameras you can choose from are the same ones they have available for TV (blimp, slow motion and dugout included).
Picture10_new
What you don’t get is the actual switching that occurs for the live TV broadcast. This is somewhat problematic since you can only see a portion of the action at any given time and many of the cameras when they aren’t live on air are moving around quite a bit, setting up the next shot and so on. It is actually very difficult to watch a game like baseball in this form.

What was also unfortunate is that the cameras weren’t in-sync. I realize that can be a bit difficult to accomplish but, come-on.. They could have tried to at least make them close. Even if you clicked the “Sync” button on the top of the screen never seemed to match up.

This service while technically interesting had a lot of possibilities but instead it just made me ache for a normal television broadcast. I have some new found respect for live event directors, switching between all of those cams for 4 plus hours of a baseball game is definitely a hard job.