All Posts

Exporting Unity frames as Animated GIFs

Recently I discovered a Unity-compatible library that allows exporting Unity textures into animated GIFs. This library is extremely easy to use and platform independent. It is called GifEncoder, which is based on NGif, an older C# based project for encoding GIFs.

To use it, just copy the GifEncoder folder to your Assets directory, point a camera at what you would like to record, and in each frame send the pixels from the camera’s render target to the encoder:

public void Update()
{
   renderCamera.Render();
   RenderTexture.active = renderTexture;
   var frameTexture = new Texture2D(renderTexture.width, renderTexture.height, TextureFormat.RGB24, false);
   frameTexture.ReadPixels(new Rect(0, 0, renderTexture.width, renderTexture.height), 0, 0);
   gifEncoder.AddFrame(frameTexture);
   UnityEngine.Object.Destroy(frameTexture);
}

In this example, renderCamera is a public field, and the camera should be assigned to it, renderTexture is a temporary RenderTexture that the camera renders into, and gifEncoder is the encoder object. These are initialized as below:

public void Start()
{
   renderTexture = new RenderTexture(800, 480, 24); //GIF Resolution
   renderCamera.enabled = false;
   renderCamera.targetTexture = renderTexture;
   gifEncoder = new AnimatedGifEncoder(@"C:\Gifs\MyGif.gif");
   gifEncoder.SetDelay(1000 / 30);
}

First wave of Uptred products released!

During the past few weeks, my team has been working on Uptred, a highly ambitious project that aims to give its users a set of tools that help them to manage and upload their videos from any of their devices to their favorite online providers. The first stage of this project finished last month with the releases of the first versions of Uptred Source and Uptred Shell on the Xamarin Component Store and on the Uptred website.

Uptred Shell

Uptred Shell is a portable multi-platform command line application that allows users to upload their videos to Vimeo and YouTube by running a simple command from their terminals. Uptred Shell can be integrated into the existing video distribution pipelines to automate the upload process for studios producing a high volume of videos.

Uptred Source

Uptred Source is a package containing all the source codes for the backend tools as well as the client side applications and code samples and the SDK that allows C# developers to authorize, manage and upload their videos to Vimeo and YouTube. This SDK works on Windows through .NET, and also on the iOS, Android, OS X and Linux through Xamarin and Mono runtime libraries.

Uptred Source is currently the most complete C# based SDK that works with the Vimeo Advanced API and is fully compatible with Xamarin and Mono. One of the main advantages of Uptred Source is that as Xamarin and Mono currently have many incompatibilities with .NET and issues with certain modules of the .NET framework such as JSON Serializers and HTTP Web Requests, custom implementations of such functionalities have been included in the SDK to ensure that the SDK works perfect and as robust as possible, regardless of the platform. Moreover, The VimeoHook class of Uptred Source implements more than a hundred methods that each correspond to an endpoint on Vimeo API. These methods, together with our resumable upload framework provide developers the easiest and most powerful C# based SDK for accessing Vimeo. The same resumable upload framework also works as well for YouTube and we plan to add more providers in the future.

Uptred Queue for Desktop

We are also releasing a public beta of Uptred Queue for Desktop, which is basicallythe must-have video uploader for Vimeo and YouTube users who work on Windows. Built on top of the robust framework of Uptred Source, Uptred Queue for Desktop currently includes the following features:

  • Resumable uploads for Vimeo and YouTube.
  • Ability to set basic video metadata such as Title, Description and Tags.
  • Ability to set Vimeo specific metadata including Privacy settings, Passwords, Review links, Download links, Comments privacy, and allowing others to add the video to collections.
  • Ability to set YouTube specific metadata including Privacy settings and Category.
  • Watch folders for automatic uploads. Multiple watch folders can be defined, each with their own upload policy and providers.
  • Upload Scheduler, which allows uploads to be paused and limited to only a specific timespan during the day.
  • Integration with Windows Explorer’s ‘Send To’ menu, allowing videos to be uploaded quickly by right clicking on them and choosing Uptred from the Send To menu.
  • Integration into the command prompt: Uploads can be queued from the command line by typing Uptred add "path_to_file". Option for automatically starting Uptred Queue on system startup. These main features will make Uptred Queue for Desktop, the most powerful desktop uploader for Vimeo and YouTube. For a limited time you can download Uptred Queue for Desktop Beta for free via this link! Use it and let us know how you feel about it!

Download Uptred Queue for Desktop

Accessing Vimeo and YouTube APIs with Xamarin.iOS

The Uptred Source library allows you to build C# based applications for iOS that use Vimeo and YouTube APIs. You can easily authorize a Vimeo or YouTube account, and afterwards query data from the server or even have resumable uploads. This post covers the basics of using Uptred Source to build an application that communicates with Vimeo Advanced API and YouTube API using Xamarin.iOS.

First, you need to create a blank Xamarin.iOS project and add Uptred as a component. You can get Uptred Source either from the Xamarin Component Store, or from the Uptred website. Modify the AppDelegate.cs file to create a new view of type MainViewController:

public override bool FinishedLaunching (UIApplication application, NSDictionary launchOptions)
{
    // create a new window instance based on the screen size
    Window = new UIWindow (UIScreen.MainScreen.Bounds);
    var mainView = new MainViewController ();
    var navigationController = new UINavigationController (mainView);
    Window.RootViewController = navigationController;
    Window.MakeKeyAndVisible ();
    return true;
}

The MainViewController class defines two buttons, one to authorize a Vimeo account and another to authorize a YouTube account. Pushing these buttons simply redirects the user to a scene containing a UIWebView (i.e. AuthViewController) that loads the login page for Vimeo or YouTube.

partial class MainViewController : UIViewController
{
    void BtnAuthVimeo_TouchUpInside (object sender, EventArgs e)
    {
        switchToAuth("Vimeo", VimeoHook.GetLoginURL(
            clientId: Constants.VimeoAPIKey,
            redirect: Constants.VimeoRedirectURL));
    }
    void BtnAuthYouTube_TouchUpInside (object sender, EventArgs e)
    {
        switchToAuth("YouTube", YouTubeHook.GetLoginURL(
            clientId: Constants.YouTubeAPIKey,
            redirect: Constants.YouTubeRedirectURL));
    }
    void switchToAuth(string provider, string url)
    {
        var webScreen = new AuthViewController ();
        webScreen.Provider = provider;
        webScreen.NavigateUrl = url;
        NavigationController.PushViewController(webScreen, true);
    }
}

The AuthViewController scene responds to a URL that contains the code parameter in its query string. In case such page is loaded, the application uses this parameter to authorize the Vimeo or YouTube account. After the account is authorized, the UIWebView is removed from the parent, and the user’s display name is shown on the screen.

if (Provider == "Vimeo") {
    var hook = VimeoHook.Authorize (
        authCode: code,
        clientId: Constants.VimeoAPIKey,
        secret: Constants.VimeoAPISecret,
        redirect: Constants.VimeoRedirectURL);
    InvokeOnMainThread( delegate {
        text.Text = string.Format ("Logged in as {0}!", hook.User ["name"].Value);
    });
}
else if (Provider == "YouTube") {
    var hook = YouTubeHook.Authorize(
        authCode: code,
        clientId: Constants.YouTubeAPIKey,
        secret: Constants.YouTubeAPISecret,
        redirect: Constants.YouTubeRedirectURL);
    InvokeOnMainThread( delegate {
        text.Text = string.Format ("Logged in as {0}!", hook.DisplayName);
    });
}

From this point on, VimeoHook or YouTubeHook classes can be used to send API requests. The Upload method in each class can be used to upload a video file, as explained in the Uptred Source documentation.

You can download the full source code from GitHub!

Mono Frustrations: WebRequest

The WebRequest class has many issues, especially in Mono. A major problem occurs when the response code is an HTTP error (e.g. 4xx), for which the class throws an Exception, causing a Runtime Error if it goes unhandled. This is not a big deal in .NET, because the request.GetResponse() call can be surrounded by a try/catch block that catches the thrown WebException, which still contains the response in its Response property. However, a bug in Mono makes it impossible to retrieve the response from a WebException, as the Response property is always null.

Solution: It is a better idea to use a TcpClient instead and manually generate an HTTP request using it.

Mono Frustrations: JSON Deserializer and Booleans

The JavaScriptSerializer of Mono requires boolean values to be surrounded with quotes in order for the JSON strings to be deserialized; which is not the case in .NET framework.

Example:

{"isDefault": true} //Invalid in Mono. Valid in .NET
{"isDefault": "true"} //Valid in Mono.

Mono Frustrations: "The authentication or decryption has failed."

Often calling the AuthenticateAsClient method of an SslStream results in the “The authentication or decryption has failed.” error, because Mono cannot verify the certificate. As a last resort, the error can be circumvented by disabling the certificate validation by adding the following line to the code:

ServicePointManager.ServerCertificateValidationCallback += (o, certificate, chain, errors) => true;

If you are creating the SslStream in a using block, you can do this instead:

using (SslStream s = new SslStream(tcpClient.GetStream(), false, new RemoteCertificateValidationCallback((o, certificate, chain, errors) => true)))
{
    s.AuthenticateAsClient(uri.Host, null, SslProtocols.Tls, false);
    ...
}

Collaborative Whiteboard Tutorial, Part Two

Part one of this tutorial focused on the description of the project and the server-side code. In this part, we write the client side code that is supposed to handle the drawing operations on an HTML canvas element.

As previously discussed, our web service is supposed to handle multiple separate whiteboards (which we call rooms). Therefore the client needs to know which room it is working on. To specify this, we pass the room name via a query string parameter, room. This parameter can then be read using a simple function (taken from the web via a quick Google search) that extracts the value of a parameter in the query string:

function get_param(name) {
    var url = location.href;
    name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
    var regexS = "[\\?&]" + name + "=([^&#]*)";
    var regex = new RegExp(regexS);
    var results = regex.exec(url);
    return results == null ? null : results[1];
}

The client side needs to store variables such as the room name, brush color, brush radius, and other objects in the memory for later use:

var ROOM = "0";
var COLOR = "black";
var RADIUS = 5;
var socket, canvas, context;

The layout of the app is fairly basic. It is made out of a full screen canvas with virtual dimensions of 1000×1000, a button for sending a clear signal, and a few buttons to change the brush color:

<canvas id="canvas" width="1000" height="1000"></canvas>
<div id="panel_tools">
<center>
<button class="action_button" onclick="clear_room();">Wipe</button>
<button class="color_button" style="background-color:black" onclick="change_color('black');">&nbsp;</button>
<button class="color_button" style="background-color:white" onclick="change_color('white');">&nbsp;</button>
<button class="color_button" style="background-color:green" onclick="change_color('green');">&nbsp;</button>
<button class="color_button" style="background-color:red" onclick="change_color('red');">&nbsp;</button>
<button class="color_button" style="background-color:blue" onclick="change_color('blue');">&nbsp;</button>
<button class="color_button" style="background-color:purple" onclick="change_color('purple');">&nbsp;</button>
<button class="color_button" style="background-color:orange" onclick="change_color('orange');">&nbsp;</button>
</center>
</div>

The color buttons simply call the change_color function with the specified color, which sets the brush color to the chosen one:

function change_color(color)
{
    COLOR = color;
}

The wipe button calls the clear_room function which sends a clear signal to the server:

function clear_room() {
    socket.emit("message", {
        "room": ROOM,
        "command": "clear"
    });
}

As a response to the clear command, the server also sends its own clear command to all clients, telling them to wipe their canvas if they belong to this room:

function get_clear() {
    context.clearRect(0, 0, canvas.width, canvas.height);
}

The first time the page is loaded, the client sends the server a join command, resulting in the server sending the client a snapshot of the room. This message is handled by the get_room function, which iterates through the room data and draws everything in the room:

function get_room(room_data)
{
    room_data.forEach(function (e, i) {
        get_draw(e);
    });
}

Also whenever someone draws, the server sends the clients the information of that brush. So to summarize, here are the commands that are handled by the clients:

if (msg["command"] == "draw") get_draw(msg["data"]);
if (msg["command"] == "clear") get_clear();
if (msg["command"] == "send_room") get_room(msg["data"]);

The get_draw function is responsible for drawing on the canvas. It assumes that the drawing data contains information such as the position of the object (in percentages, i.e. between 0.0 and 1.0), the radius of the brush, its color and the shape. Currently we only support circle for the shape:

function get_draw(draw_data)
{
    if (draw_data["shape"] == "circle")
    {
        draw_data["x"] = (draw_data["x"] / 1000.0) * canvas.width;
        draw_data["y"] = (draw_data["y"] / 1000.0) * canvas.height;
        context.beginPath();
        context.arc(draw_data["x"], draw_data["y"], draw_data["radius"], 0, 2 * Math.PI, false);
        context.fillStyle = draw_data["color"];
        context.fill();
    }
}

Now we need to map the mouse event handlers to functions that will allow the client to send draw messages to the server. The user can enable draw mode by clicking the mouse button, and disable it by releasing the mouse button. Draw signals containing brush data and click position in percentages are sent to the server on mouse move:

var draw_enabled = false;
function mouse_paint(event)
{
    if (!draw_enabled) return;
    var rect = canvas.getBoundingClientRect();
    var x = event.x - rect.left;
    var y = event.y - rect.top;
    socket.emit("message", {
        "room": ROOM,
        "command": "draw",
        "data": {
        "shape": "circle",
        "x": 1000.0 * (x / rect.width),
        "y": 1000.0 * (y / rect.height),
        "radius": RADIUS,
        "color": COLOR
        },
    });
}

function mouse_down(event)
{
    draw_enabled = true;
    mouse_paint(event);
}

function mouse_move(event)
{
    mouse_paint(event);
}

function mouse_up(event)
{
    draw_enabled = false;
}

The last step is to initialize everything and send a join message to begin the session:

function initialize() {
    ROOM = get_param("room");
    canvas = document.getElementById("canvas");
    context = canvas.getContext("2d");

    canvas.addEventListener("mousedown", mouse_down, false);
    canvas.addEventListener("mousemove", mouse_move, false);
    canvas.addEventListener("mouseup", mouse_up, false);

    socket = io();
    socket.on("servermessage", handle_message);
    socket.emit("message", {
    "room": ROOM,
    "command": "join"
    });
}
window.addEventListener("load", initialize);

Collaborative Whiteboard Tutorial, Part One

This tutorial aims to demonstrate how to build a real-time communication channel between one server and multiple clients (i.e. browsers), simply by using JavaScript. This project uses Node.js for its server-side backend, and targets Google Chrome for the client side. However, the outcome also works well on other browsers, including Internet Explorer. We call this application QuickDraw.

The end result is supposed to be a web service that stores multiple whiteboards in different rooms, and each client can simply type in a room name and observe or modify the contents of the whiteboard. In case a room does not exist, it will be created automatically.

This tutorial is split into different steps. First, I will show how to create a simple communication channel between the server and clients, and afterwards we transmit user input to the server and receive drawing data from the server to the clients.

The Web Server

We use Node.js on the server side as a web server to send static HTML files as well as the client side JavaScript files, and also to handle the main logic of the program. The express library is used to power the web server and send the files in the client folder to the clients. All the code regarding the web server is stored in the server/web.js folder. Here we do not plan to explain how to run a web server with Node.js, and will simply use this file to start a web server on port 8081:

var web = require("./server/web.js");
web.start(8081);

web.js automatically creates a Socket.io object which is later used to power the communications between the server and clients.

The Communication Protocol

The server is responsible for storing whiteboards (rooms) and their content, and also broadcasting their data to the clients upon request. Therefore it needs to hold a list of rooms, their names and their content.

var rooms = [];
var roomIds = {};
function getRoom(roomId)
{
    if (!(roomId in roomIds))
    {
        roomIds[roomId] = rooms.length;
        rooms.push([]);
    }
    return rooms[roomIds[roomId]];
}

function sendRoom(roomId)
{
    web.io.emit("servermessage", {
        "room": roomId,
        "command": "send_room",
        "data": getRoom(roomId)
    });
}

The sendRoom function receives a room name (according to the diagram above,) and sends the data associated with that room to the clients. This function can be called every time a client joins in order to receive a copy of what is currently on the whiteboard. We handle incoming messages on the server in the handleMessage function, so we can hook sendRoom to a join message:

function handleMessage(msg)
{
    if (msg["command"] == "join") join(msg);
}

Now we need to handle the actual drawing task. Once a user clicks on their canvas, the client side sends the drawing data which contains information such as the position of touch, the brush color and the brush radius, in JSON format. The server side receives this data with a draw command, and adds this information to the room data. After storing the information, it rebroadcasts the same data so that every client receives this drawing information:

function draw(msg)
{
    var room = getRoom(msg["room"]);
    room.push(msg["data"]);
    web.io.emit("servermessage", {
        "room": msg["room"],
        "command": "draw",
        "data": msg["data"]
    });
}

The draw method needs to be hooked to the draw command handled by the handleMessage function:

function handleMessage(msg)
{
    if (msg["command"] == "join") join(msg);
    if (msg["command"] == "draw") draw(msg);
}

Finally, the users should be able to clear a room. This is done by sending a clear command to the server. The server erases all the data stored in that room, and tells all clients to do the same on their canvas:

function clear(msg)
{
    var room = getRoom(msg["room"]);
    while (room.length) room.pop();
    web.io.emit("servermessage", {
        "room": msg["room"],
        "command": "clear"
    });
}

Again, we need to connect this method to the handleMessage function. To prevent crashes due to unknown commands, we surround our code with a try/catch block:

function handleMessage(msg)
{
    try
    {
        //check if message is valid
        if (!("room" in msg && "command" in msg))
            return;

        if (msg["command"] == "draw") draw(msg);
        if (msg["command"] == "join") join(msg);
        if (msg["command"] == "clear") clear(msg);
    }
    catch (err)
    {
        console.log(err);
    }
}

And lastly, we need to tell Socket.io to call handleMessage every time a message arrives from a client:

web.io.on('connection', function (socket) {
    console.log((new Date()) + ' Connection established.');
    socket.on("message", handleMessage);
});

The server side code of our collaborative whiteboard project is done. You can study the full code on QuickDraw’s GitHub repository. The next post will cover the client side code which deals with mouse clicks as input, and draws received data from the server!

Relocating Outlook Data Files

Outlook 2013 data files (ost, pst) can be really huge, especially if you use emails too much, or have a lot of attachments in your accounts. By default, Outlook keeps these files in the APPDATA folder, and even if you move your home folder to another drive, it still uses the old folder in the original APPDATA path. There is no direct way to move this folder, and this can be quite annoying if the files are saved on a low capacity SSD.

Here I will show you how to move the data files to another path:

  1. First, close Outlook and find where its data files are stored. You should be able to find them in C:\Users\USERNAME\AppData\Local\Microsoft\Outlook.
  2. Move the Outlook folder to your desired destination. (Let’s assume it’s D:\Outlook).
  3. Open a Command Prompt with Administrator access and make a junction (symbolic link) that points to the new folder:

    mklink /j C:\Users\USERNAME\AppData\Local\Microsoft\Outlook D:\Outlook
  4. Start Outlook. It now reads data files from the new destination.

Magnetic Interaction with Mobile Games

I have been working on this for a while now, but now it’s time to finally reveal it.

In these videos, you can see the novel mobile interaction method I invented, called the “Magnetic Joystick”. The algorithm allows different objects to be used to wirelessly control mobile games like a joystick. For details, you can refer to our publication at NORDICHI 2014: http://dl.acm.org/citation.cfm?id=2670186

[embed]https://www.youtube.com/watch?v=ykfMi4W83MI[/embed]

[embed]https://www.youtube.com/watch?v=vFnE_MRCyAQ[/embed]