Tag Archives: Video

Creating an Interesting Places application – take and share media in Windows Phone 7

I wrote a new article to Nokia Developer Wiki. This code example demonstrate how to take an image, record audio or video and save these captured media files to the Isolated Storage with the location information. These Interesting Places with media files can be later viewed and shared to the server side. This code example uses PHP server as a back end of this application. All captured media files are send 500 kB chucks with RestSharp and parsed together in the server side with PHP. This application is tested with 5 min recorded video (for example), then video file size was 55 MB and sent chucks count was more than 110. Sent was tested over normal cellular network and sending takes about 8 minutes. It worked really nice in Windows Phone 7 without Background Agents.

You can read the whole article and download source codes from here: Creating an Interesting Places application - take and share media in WP7.

Flex 4.6 and SplitViewNavigator in AIR : Demo application – Finnkino Movies

Adobe Flex 4.6 includes several new and updated mobile-optimized Spark components (for example SplitViewNavigator, CallOutButton, SpinnerList, DateSpinner, Text Enhancements and ToggleSwitch).

In this example I used SplitViewNavigator to show Finnkino's Theatres in the first view of the SplitViewNavigator. Second view shows the selected Theatre's movies (what are running at this day) or all movies that are running in Finnkino's Theatres.

<s:SplitViewNavigator id="splitNavigator" width="100%" height="100%" autoHideFirstViewNavigator="true">
  <s:ViewNavigator id="areasView" width="200" height="100%" firstView="views.AreaCategory"/>
  <s:ViewNavigator id="detailView" width="100%" height="100%" firstView="views.MoviesTileView">
    <s:actionContent.portrait>
    <s:Button id="navigatorButton" label="Valitse Teatteri"
         click="splitNavigator.
         showFirstViewNavigatorInPopUp(navigatorButton);"/>
    </s:actionContent.portrait>
  </s:ViewNavigator>
</s:SplitViewNavigator>

Movies in Landscape mode

SplitViewNavigator is working very nicely and it hide's the first view in navigator when tablet is rotated to Portrait. You should add resize event handling to your application and use states in ActionContent in ViewNavigator.

<s:Application resize="resizeHandler(event);">
protected function resizeHandler(event:ResizeEvent):void {
  currentState = aspectRatio;
}
<s:states>
  <s:State name="portrait"/>
  <s:State name="landscape"/>
</s:states>

Movies in Portrait mode

List and ItemRenderers
I have used List to show all the movie items and own made ItemRenderer to display some basic information (or just movie image when all the movies are selected from the main list).

<s:List id="moviesList"
    dataProvider="{data}"
    itemRenderer="comps.MovieAreaTile"
    horizontalCenter="0"
    verticalCenter="0"
    width="100%" height="100%"
    contentBackgroundColor="#FFFFFF"
    change="moviesList_changeHandler(event)"
    >
  <s:layout>
    <s:TileLayout id="tileList"
     paddingLeft="5" paddingRight="5" paddingTop="5" paddingBottom="5" horizontalGap="5" verticalGap="5"
    columnAlign="justifyUsingWidth"
   />
  </s:layout>
</s:List>
// MovieAreaTile
<s:HGroup>
  <s:Image source="{data.Images.EventSmallImagePortrait}" />
  <s:VGroup>
    <s:Label id="title" styleName="title" text="{data.Title}" />
    <s:Label id="startTime" styleName="data" text="{data.dttmShowStart}" />
    <s:Label id="length" styleName="data" text="{data.LengthInMinutes} min" />
    <s:Label id="theatre" styleName="data" text="{data.TheatreAndAuditorium}" />
    <s:Label id="genre" styleName="data" text="{data.Genres}" />
  </s:VGroup>
</s:HGroup>

All the Movies in Finnkino's Theatres

SQLite: Automatically display same Theatre which was used in previous time
In this example I store theatreID and theatreName to SQLite database every time when a new Theatre is selected. Those values are used when application is started again.

Connection to database:

private function connect(type:Number):void {
  dbConn = new SQLConnection();
  if (type == CREATE_DB) dbConn.addEventListener(SQLEvent.OPEN, createTable);
  else dbConn.addEventListener(SQLEvent.OPEN, getTheatreData);
  dbConn.addEventListener(SQLErrorEvent.ERROR, errorHandler);
  dbConn.openAsync(dbFile);
}

Create a table:

private function createTable(event:SQLEvent):void {
  var dbStatement:SQLStatement = new SQLStatement();
  dbStatement.sqlConnection = dbConn;
  dbStatement.addEventListener(SQLEvent.RESULT, theatreTableCreated);
  dbStatement.addEventListener(SQLErrorEvent.ERROR, errorHandler);
  dbStatement.text = "CREATE TABLE IF NOT EXISTS movieTable (id INTEGER PRIMARY KEY AUTOINCREMENT, theatreID TEXT, theatreName TEXT);";
  dbStatement.execute();
}

Table is created a first time -> add some sample data to table

private function theatreTableCreated(event:SQLEvent):void {
  var dbStatement:SQLStatement = new SQLStatement();
  dbStatement.sqlConnection = dbConn;
  dbStatement.addEventListener(SQLEvent.RESULT,theatreDataAdded);
  dbStatement.addEventListener(SQLErrorEvent.ERROR,errorHandler);
  // just set default data when table is created
  theatreID = 1015;
  theatreName = "Jyväskylä";
  dbStatement.text = "INSERT INTO movieTable (theatreID, theatreName) VALUES('"+theatreID+"','"+theatreName+"');";
  dbStatement.execute();
}

Theatre (id and name) data is added first time, load events with HTTPService

<fx:Declarations>
  <s:HTTPService id="finnkinoArea" showBusyCursor="true" url="{url}"
      result="areaHandler(event)"
      fault="areaFaultHandler(event)"
   />
</fx:Declarations>

private function theatreDataAdded(event:SQLEvent):void {
  loadEvents(theatreID);
}

private function getTheatreData(event:SQLEvent):void {
  var dbStatement:SQLStatement = new SQLStatement();
  dbStatement.sqlConnection = dbConn;
  dbStatement.addEventListener(SQLEvent.RESULT,theatreResult);
  dbStatement.addEventListener(SQLErrorEvent.ERROR,errorHandler);
  dbStatement.text = "SELECT theatreID, theatreName FROM movieTable where id=1";
  dbStatement.execute();
}

TheatreID and name is loaded from SQLite, start loading XML data from Finnkino's service

private function theatreResult(event:SQLEvent):void {
  var dbResult:SQLResult = SQLStatement(event.target).getResult();
  theatreID = dbResult.data[0].theatreID;
  theatreName = dbResult.data[0].theatreName;
  // load previous used theatre
  loadEvents(theatreID);
}
public function loadEvents(theatreID:uint):void {
  // one Teatre
  if (theatreID != -1) url = urlBase + theatreID;
  // all events from Finnkino
  else url = "http://www.finnkino.fi/xml/Events/";
  // call HTTPService
  finnkinoArea.send();
}

Movie Details
Movie details are shown when user clicks MovieTile from TileView. Finnkino's Service offers a lot of information about the movie. In this example I only display some sample data and movie trailer. Movie trailer can be played in fullscreen mode too (use this only in Landscape - there a some issues in portrait mode - in this example :-)

<s:Scroller width="100%" height="100%">
  <s:VGroup width="100%">
    <s:HGroup>
      <s:Image source="{data.Images.EventLargeImagePortrait}" />
      <s:VGroup>
        <s:Label text="{data.Title} ({data.OriginalTitle})" styleName="title"/>
        <s:Label text="{data.RatingLabel}" styleName="data" />
        <s:Label id="startTime" styleName="data" text="{data.dttmShowStart}" />
        <s:Label id="length" styleName="data" text="{data.LengthInMinutes} min" />
        <s:Label id="genre" styleName="data" text="{data.Genres}" />
        <s:Label id="showUrl" styleName="dataBlue" text="{data.ShowURL} - (osta liput)" click="showUrl_clickHandler(event)" />
        <s:Label id="eventUrl" styleName="dataBlue" text="{data.EventURL} - (lisätietoa elokuvasta)" click="eventUrl_clickHandler(event)" />
     </s:VGroup>
   </s:HGroup>
   <s:Label text="{movieData.Synopsis}" width="100%" styleName="synopsis" />
   <s:VideoPlayer id="myVideo" source="{movieData.Videos.EventVideo.Location}" autoPlay="false" visible="{isVideo}" width="{this.width-20}"/>
   <s:Button label="Takaisin" id="takaisin" click="takaisin_clickHandler(event)"/>
   </s:VGroup>
</s:Scroller>

Movie details in Landscape mode

Movie details in Portrait mode

Movie trailer in fullscreen

Source codes
- Movies.fxp, Movies.zip

Note
There are a few bugs in this example (too). Sometimes the date is missing from first views, and VideoPlayer is messing up if it is in fullscreen mode in Landscape and you turn the device to portrait.. but now it is working for my purposes :-) and finally I have only tested this in Samsung Galaxy Tab 10.1 not in mobile...

This example uses Finnkino's Services

Testing KuneriLite plugins part three: Take, play and send video file from Flash Lite to server

In my earlier Flash Lite article I've tested KuneriLite Camera plugin to take picture (klMode=picture). This time I've it's video support (klMode=video) to record video and store it to mobile phone. I've modified my ActionScript source code a little and it worked very nicely on the Nokia N95. This Flash Lite test application sends videos to my server http://ptm.fi/temp/videos folder, so check you uploaded videos from there.

PTM Video pic 1 PTM Video pic 2 PTM Video pic 3

Setting up system
This time I've tested KuneriLite wizard in Microsoft Vista. I've installed Active Perl and Symbian S60 3rd edition SDK Maintenance Release as I did earlier in my Camera and Upload plugins -article. I had to make small modifications to get KuneriLite Wizard working on vista. You can find these modifications on the KuneriLite Wiki: Microsoft Vista Support.

Flash Lite application
The idea of this application is take video, play it to user and send it to a remote server (if the user wants to send it). All the ActionScript code is written to first frame of timeline. I'll describe here only needed lines to understand how to take, show and send video file to the remote server. Please see the FLA source code for more information.

Initialize application
There is one major bug in my previous example with taking picture, have you noticed it? I haven't thought on the situation where a user start to take picture and then press back when Kuneri Lite Camera plugin is active. The application is trying to make a thumbnail picture, which fails if there is no picture taken. In this video example this situation is handled with Camera plugin Status operation (klStatus).

A few variables are defined to handle video filename and KuneriLite plugin gateway errors.

var vidName:String = "";          // video name
var klError:Number = -99;         // klError number
var klStatus:String = "";         // klStatus string
var process:Number = 0;           // process number
var intervalId:Number;            // interval number
var path:String = "\\Data\\Others\\Trusted\\PTMVideo\\";

Preparing Camera
KuneriLite offers optional prepare command which prepares the camera resource and checks the presence of camera device. I'll check this first and let then user take video.

// check camera condition
process = 1;
intervalId = setInterval(checkProcess,1000);
status_txt.text = "status: preparing camera...";
loadVariables("http://127.0.0.1:1001/Basic/camera?
               klCommand=prepare&klIndex=0","");

Taking video
This stage is very similar to the sending picture example from the previous article. The only visible modification is with Video instance. I’ve added one video symbol to the library and dragged it to the timeline (instance name is video). When a user presses the device’s number one key, KuneriLite uses loadVariables()-function to call Camera plugin in order to take video. Here I just take a full size video with main camera.

//Take video
function takeVideo(){
  // videoname
  vidName = giveDateAndTimeString();
  var command:String = "";
  command += "http://127.0.0.1:1001/Basic/camera?klCommand=start";
  command += "&klMode=video";
  command += "&klPath="+path+vidName+".3gp";
  command += "&klSize=full";
  command += "&klIndex=0";
  status_txt.text = "status: taking video...";
  process = 2;
  klError = -99;
  intervalId = setInterval(checkProcess,1000);
  loadVariables(command,"");
}

Did user take video or not
As I wrote earlier, I didn’t check if the user had taken a picture in my previous example. Here I will do it after the video screen is closed in KuneriLite plugin. I have one function which checks processes to see what had happened in my application. When Kuneri Lite Camera plugin is closed, I’ll start to check if there’s a video file taken or not.

// .. part of my prosess function
// check if video is taken
case 2:
  if (klError == -99) return;
  clearInterval(intervalId);
  if (klError == 0) {
    status_txt.text += "done!";
    intervalId = setInterval(checkVideo,2000);
  }
  process = 0;
  break;
//check is video taken
function checkVideo() {
  clearInterval(intervalId);
  var command:String = "http://127.0.0.1:1001/Basic/camera?klCommand=status";
  status_txt.text = "status: checking video...";
  process = 3;
  klError = -99;
  klStatus = "";
  intervalId = setInterval(checkProcess,1000);
  loadVariables(command,"");
}

If video is available, just start to play it.

// .. part of my prosess function
// is videofile available
case 3:
  if (klError == -99) return;
  clearInterval(intervalId);
  if (klError == 0) {
    status_txt.text += "done!";
    if (klStatus == "complete") {
      intervalId = setInterval(playVideo,2000);
    } else if (klStatus == "exit") {
      status_txt.text = "status: No video!";
    }
  } else {
    status_txt.text = "status: klError = "+klError;
  }
  process = 0;
  break;

Play video
After video is taken, it will be showed to user with video instance.

// Load and play video
function playVideo(){
  clearInterval(intervalId);
  status_txt.text = "status: playing video...";
  video.play(vidName+".3gp");
}

video.onStatus = function(info){
  if (info.code=="completed") status_txt.text += "done!";
}

Sending video file to remot server
Sending is handled the same way I used in my photo example. I added upload status checking to this example. First video will be sent to server and uploading is checked with own made checking function

function checkUploading() {
  clearInterval(intervalId);
  var command:String = "http://127.0.0.1:1001/Basic/uldl?klCommand=status";
  command += "&klTrId=1234";
  process = 5;
  klError = -99;
  klStatus = "";
  intervalId = setInterval(checkProcess,1000);
  loadVariables(command,"");
}

and process function is checking what is going on with uploading. KuneriLite sends a few different status, I used only two of them: complete if uploading is successfully completed or failed if there where some problems.

case 5:
  if (klError == -99) return;
    clearInterval(intervalId);
    if (klError == 0) {
      status_txt.text = "status:" +klStatus;
      if (klStatus == "complete" || klStatus == "failed") {
        process = 0;
      } else {
        intervalId = setInterval(checkUploading,1000);
      }
    } else {
      status_txt.text = "status(5): klError = "+klError;
      process = 0;
    }
  break;

Source and SIS files
This application is designed to run 240×320 screens and for testing purposes only. It uses KuneriLite’s default generated SIS package, so if you have my other examples installed you have to remove these first.

Sources: PTMVideo.zip (Flash Lite 2.0 Application)
SIS: PTMVideo_3rd_edition_signed.sis (install it to memory card!)

Feel free to try this example and send video greetings to me with Flash Lite!

Note! I have 20MB upload limit per file with PHP at my server, so dont take too long videos!

Live Video from Linux to Flash Lite 3.0

You can't use Flash Media Encoder 2 in Linux, so you have to make your own publisher with Flash. Idea is to make own Flash application which connects to webcam and send/publish this live video to Flash Media Server 3 and then clients can connect to Flash Media Server 3 and start to view this live broadcast. Here are simple default instructions to send live video from Linux to Flash Lite 3.0 application.

Install Linux and Flash Media Server 3:

  • Install some Linux distribution (I installed Fedora Core 8 )
  • Download and install Flash Media Server 3 (you might have to use -platformWarnOnly)
  • go to your fms directory: cd /opt/adobe/fms
  • start Flash Media Server 3: ./fmsmgr server fms start

You can use command: "ps aux | grep fms" to see list of fms processes running. There should be following processes listed: fmscore, fmsedge, fmsmaster and fmsadmin. If not, there are some problems :-) in your configuration and maybe you want to read this: Flash Media Server does not start after successful installation on RedHat Linux

Creating own publisher with Flash is quite simple. Open NetConnection to Flash Media Server 3. After you get NetConnection.Connect.Success, you can start connection to your webcam and publish stream to Flash Media Server 3.

Publisher:

import flash.net.NetConnection;
import flash.net.NetStream;
import flash.net.ObjectEncoding;
import flash.media.Video;
import flash.media.Camera;
import flash.events.NetStatusEvent;
import flash.events.AsyncErrorEvent;

var nc:NetConnection;
var ns:NetStream;
var video:Video;
var camera:Camera;

// create NetConnection-object
nc = new NetConnection();
nc.objectEncoding = flash.net.ObjectEncoding.AMF0;
nc.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
nc.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncErrorHandler);

// connect FMS 3 default live application
nc.connect("rtmp://localhost/live");

// error handling
function asyncErrorHandler(event:AsyncErrorEvent):void {
  trace(event.text);
}

// if connected, start publishing
function netStatusHandler(event:NetStatusEvent):void {
  if (event.info.code == "NetConnection.Connect.Success") {
    startPublishing();
  }
}

// publish webcam's live to server
function startPublishing():void {
  ns = new NetStream(nc);
  ns.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
  camera = Camera.getCamera();
  if (camera != null){
     video = new Video();
     video.attachCamera(camera);
     ns.attachCamera(camera);
     // show video in publisher also
     addChild(video);
     ns.publish("livestream", "live");
  } else {
     trace("Please check your camera and microphone");
  }
}

Publish your live video publisher in Flash and upload it (swf, html, js) to your web server. Open your publisher in Web browser and you should see your live video in publisher. Start Flash Media Server Admin console and you should see one live application running and publishing live video.

fms admin

Next you have to make Flash Lite 3.0 application to connect your FMS 3 server and play your live stream. Create Video-object in screen and type following code in first frame in Flash.

Client:

import flash.net.ObjectEncoding;

var video:Video;
var ns:NetStream;
var nc:NetConnection = new NetConnection();
nc.objectEncoding = ObjectEncoding.AMF0;

nc.onStatus = function(info:Object):Void {
  if (info.code == "NetConnection.Connect.Success") {
    startStreaming();
  }
}

function startStreaming() {
  ns = new NetStream(nc);
  ns.setBufferTime(2);
  video.attachVideo(ns);
  ns.play("livestream",-1,-1,true);
}

status_txt.text = "Status : Connect....";
nc.connect("rtmp://your.server.ip.here:1935/live");

Note!
You might have some issues with Linux firewalls, then you must edit /etc/sysconfig/iptables to allow connect FMS ports. Add following lines to iptables to allow ports: 1111 and 1935 access from remote and restart your iptables with command: /etc/rc.d/init.d/iptables restart

# flash media server 3
-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 1111 -j ACCEPT
-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 1935 -j ACCEPT

Download sources: all

Play FLV and Live Video with Flash Lite 3.0

I have made a few test with Flash Lite 3.0 and Flash Media Server 3 and I have to say that it is pretty easy to stream FLV Video files and Live Video from local web camera to mobile phone. Here are a quick instructions how to do it in Windows (I will publish Linux version later).

Play FLV-video from Flash Media Server 3:

  • Install Flash Media Server 3 (download developer version)
  • There are a few sample FLV files in applications/vod/media folder, so you can use one of them for testing
  • Create a new Flash Lite 3.0 file in Flash
  • Add a new Video symbol to library
  • Drag this Video symbol to Stage and give instance name to it: video
  • Type following programming to timeline:
// make a new video-object
var video:Video;
// make a new NetConnection-object
var nc:NetConnection = new NetConnection();

// check connection status from server
nc.onStatus = function(info:Object):Void {
  status_txt.text=info.code;
  if (info.code == "NetConnection.Connect.Success") {
    startStreaming();
  }
}

// start streaming video to phone
function startStreaming() {
  ns = new NetStream(nc);
  ns.setBufferTime(5);
  video.attachVideo(ns);
  // play sample.flv from server
  ns.play("sample",0);
}

// show info to user
status_txt.text = "Connecting server...";

// connect FMS 3 video on demand service (default port 1935)
nc.connect("rtmp://your.server.ip.here:1935/vod");
  • Go to Publish Settings...
  • Set Local playback security: Access network only
  • Publish your SWF-file
  • Send your SWF-file to your phone
  • Test and you should see FLV-video playing in your phone

Play live video from Flash Media Server 3:

  • Install Flash Media Server 3 (download developer version)
  • Install Flash Media Encoder 2 (Windows only)
  • Start Flash Media Encoder 2
  • You should see your live camera in Input screen
  • Press Start-button to start sending live video to Flash Media Server 3
  • Create a new Flash Lite 3.0 file in Flash
  • Add Video symbol and programming as you did earlier
  • Modify your programming:
// in startStreaming()-function
// Flash Media Encoder 2 publish stream name is "livestream"
ns.play("livestream",-1,-1,true);

// start connection to Flash Media Server 3
// Flash Media Encoder 2 publishes Flash Media Server's default
// live publishing point, so connect it
nc.connect("rtmp://your.server.ip.here:1935/live");
  • Publish, test and enjoy

Download sources: all