Archive
Convert Quicktime (MOV) to Mpeg4 (MP4) in C#
I came across CloudConvert today, and I think this is the coolest thing since sliced bread. If at one point sliced bread was cool.
With a couple of lines of code you can convert a MOV (Quicktime) video to the more ubiquitous Mpeg 4 (Mp4) format, and then drop the file back to Amazon S3 for playback.
WebClient wc = new WebClient();
string strUrl = “https://api.cloudconvert.org/convert?”;
strUrl += “apikey=[YOUR KEY HERE]”;
strUrl += “&input=download”;
strUrl += “&output[s3][accesskeyid]=[YOUR KEY HERE]”;
strUrl += “&output[s3][secretaccesskey]=[YOUR KEY HERE]”;
strUrl += “&output[s3][bucket]=video”;
strUrl += “&output[s3][region]=eu-west-1”;
strUrl += “&output[s3][acl]=private”;
strUrl += “&download=inline”;
strUrl += “&inputformat=mov”;
strUrl += “&outputformat=mp4”;
strUrl += “&file=http%3A%2F%2Fiyourserver.com%2Fvideoupload%2Fsomevideo.mov” ;
wc.DownloadString(strUrl);
Once the call returns, then the video will have been placed in your S3 Bucket ready to be played back.
No more Apple-only videos!
Upload video from Phonegap to ASP.NET
If you’re uploading an image from Phonegap to a server, then it’s perhaps ok to just Base64 encode the image data and post it to the server, but when you you are dealing with Video, then you need something a little more efficient, which is where I started to take a look at the FileTransfer feature of Phonegap.
The best lesson I learned from this process, is to start with uploading an image from the photo gallery first, rather than diving headlong into the Video upload process. This is because you can run through the process in the simulator, giving you access to the debug console, so you can see any error details coming back from the server, otherwise, you can’t really see what’s going on.
So, let’s start with the server side, here’s my ASMX webservice:
<%@ WebService Language=”C#” Class=”WebService” %>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.IO;
[WebService(Namespace = “http://tempuri.org/”)]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class WebService : System.Web.Services.WebService {
public WebService () {}
[WebMethod]
public string UploadFile() {
string lreturn = “success”;
try
{
HttpPostedFile file = HttpContext.Current.Request.Files[“file”];
string saveFile = file.FileName;
string realPhysicalPath = Path.Combine(Server.MapPath(“videoUpload”), saveFile);
file.SaveAs(realPhysicalPath);
}
catch (Exception ex)
{
lreturn = “fail. ” + ex.Message;
}
return lreturn ;
}
}
The web.config configuration for this service is quite important, as follows:
<system.web>
<compilation debug=”true”/>
<customErrors mode=”Off”/>
<webServices>
<protocols>
<add name=”HttpGet”/>
<add name=”HttpPost”/>
</protocols>
</webServices>
</system.web>
<system.webServer>
<httpProtocol>
<customHeaders>
<add name=”Access-Control-Allow-Origin” value=”*” />
</customHeaders>
</httpProtocol>
</system.webServer>
This allows the webservice to be called with GET and POST, and the CORS support helps cross-domain access.
Then, the fun part of writing the app to upload video as follows (Slightly adapted from official docs)
<!DOCTYPE html>
<html>
<head>
<title>Capture Video</title><script type=”text/javascript” charset=”utf-8″ src=”cordova.js”></script>
<!–<script type=”text/javascript” charset=”utf-8″ src=”json2.js”></script>–>
<script type=”text/javascript” charset=”utf-8″>// Called when capture operation is finished
//
function captureSuccess(mediaFiles) {
var i, len;
for (i = 0, len = mediaFiles.length; i < len; i += 1) {
uploadFile(mediaFiles[i]);
}
}// Called if something bad happens.
//
function captureError(error) {
var msg = ‘An error occurred during capture: ‘ + error.code;
alert(msg, null, ‘Uh oh!’);
}// A button will call this function
//
function captureVideo() {
// Launch device video recording application,
// allowing user to capture up to 2 video clips
navigator.device.capture.captureVideo(captureSuccess, captureError, {limit: 2});
}// Upload files to server
function uploadFile(mediaFile) {var ft = new FileTransfer(),
path = mediaFile.fullPath,
name = mediaFile.name;
alert(“Attempting to upload:” + path);var op;
op = new FileUploadOptions();
op.fileName = name;
op.fileKey = “file”;ft.upload(path,
“http://yourserver.com/videoUpload.asmx/UploadFile”,
function(result) {
alert(‘Upload success: ‘ + result.responseCode);
alert(result.bytesSent + ‘ bytes sent’);},
function(error) {
alert(‘Error uploading file ‘ + path + ‘: ‘ + error.code);
},
op);
}</script>
</head>
<body>
<button onclick=”captureVideo();”>Capture Video</button> <br></body>
</html>
Now, the fun part, is that I just see that iOS uploads in Quicktime (MOV) format, which is not supported in-browser by Android.
webOS App Store closing November 1st, 2014
![]() |
| webOS Cloud Services to end January 15, 2015 |
| Cloud services support for webOS devices will end on January 15, 2015. We appreciate the effort that our developer community has contributed to the webOS platform. However, it has been more than three (3) years since the last device was sold. Since only a small fraction of the devices are still connecting to our cloud, the time has come to close the services.
The remaining webOS devices will continue to run after the cloud services are terminated. However, they will no longer be able to:
What this means to developers
|
Microsoft no longer routing it’s sales through Luxembourg
NOTICE – European Union VAT Changes Coming 1/1/2015
Tax laws in the European Union (EU), which govern the Value Added Tax (VAT) rate applied to business-to-consumer digital goods, are changing on 1/1/2015. This affects the VAT rate on content offered in the Windows and Windows Phone Stores. You may want to start thinking about how this change could impact your EU pricing decisions.
Beginning on 1/1/2015, the applicable VAT rate for paid business-to-consumer transactions for digital goods will change from 15% to the country-specific VAT rate.
All EU countries are Microsoft tax remit, which means the price you select in Dev Center for your app and/or in-app purchase is the final sale price to the customer and already includes applicable taxes. Microsoft then subtracts the taxes from the price prior to payout, and remits them on your behalf.
The table below shows the new VAT rates that will go in to effect on 1/1/2015.
|
Note: Tax rates are subject to change at any time. Microsoft cannot guarantee the accuracy of these rates. For definitive information, consult official EU sources.
Issue: Assembly outside lib folder. (NuGet)
NuGet seems to be a great way to get windows developers to use your code, it makes it easy to package up an assembly to be used in another project. Seconds after uploading, I started to get developers downloading my code.
Here was a problem that I hit when I tried to package my assembly, there may be a better solution, but this worked for me.
I created a boiler-plate NuSpec file from my DLL by running
nuget spec MyAssembly.dll
I had to open the nuspec file in notepad, and edited the fairly obvious fields, like URL description, etc. Then, I went to pack the nuspec and dll together with this command:
NuGet Pack YourPackage.nuspec
However, I then got a warning:
WARNING: 1 issue(s) found with package ‘xxxx.dll’.
Issue: Assembly outside lib folder.
Description: The assembly ‘xxx.dll’ is not inside the ‘lib’ folder
and hence it won’t be added as reference when the package is installed into a project.
Solution: Move it into the ‘lib’ folder if it should be referenced.
The nupkg file was created, and I uploaded it to nuget.org, however, when I tried to download this again, using
PM> Install-Package xxxxx.dll
Installing ‘xxxxx.dll 1.0.0’.
Successfully installed ‘xxxx.dll 1.0.0’.
There was no reference added to my project, so, I couldn’t access the assembly.
So, after reading a bit, I edited my nuspec file, and added this node in the metadata
<references>
<reference file=”xxxx.dll” />
</references>
created a lib folder, and copied the dll into it. – and changed the version number
I repacked, and re-uploaded the nupkg, and when I downloaded it again, I got a reference automatically added to my test project.
And it’s all live on https://www.nuget.org/packages/OfflineAdvertsLib.dll
Could not load type ‘System.Action’ from assembly ‘mscorlib, Version=3.7.0.0, Culture=neutral, PublicKeyToken=969DB8053D3322AC’.
When porting some code from Silverlight 4 to Windows Phone 7.1, I got an unusual error “Could not load type ‘System.Action’ from assembly ‘mscorlib, Version=3.7.0.0, Culture=neutral, PublicKeyToken=969DB8053D3322AC’.” – At this bit of code:
Deployment.Current.Dispatcher.BeginInvoke(someMethod);
The code is designed to run “someMethod” on the main UI Thread, so you don’t an illegal cross thread exception.
Invoking Dispatcher.BeginInvoke with a function name like this, is interpreted as an Action, rather than a delegate, so the solution is to use a delegate as follows:
private delegate void someMethodDelegate();
private static void SomeMethodCalledByBackgroundThread()
{
someMethodDelegate action = someMethod;
Deployment.Current.Dispatcher.BeginInvoke(action);
}
Although a little less easy to read, and it appears to have an extra level of indirection, this code works in both SL4 and WP7
Display Data URI Image in Silverlight (Windows Phone)
The data uri is a string based representation of an image, which is base-64 encoded, so it’s easy to store in Javascript, and pass it in Post data. It bloats the image size, so it isn’t an efficient format, but it’s certainly easy to handle.
Here is an example of how to render a image from a data URI in Silverlight – which should also be suitable for Windows Phone 7, 8, and 8.1 (Silverlight).
Here’s my XAML:
<Grid x:Name=”LayoutRoot” Background=”White” Loaded=”LayoutRoot_Loaded”>
<Image x:Name=”imgDisplay”></Image>
</Grid>
And this is the underlying C# code:
public static BitmapSource BitmapSourceForDataUri(Uri dataUri)
{
var dataString = dataUri.OriginalString;
var b64Start = dataString.IndexOf(“,”, StringComparison.Ordinal);
if (b64Start == -1) return null;
var base64 = dataString.Substring(b64Start + 1);
Stream stream = new MemoryStream(Convert.FromBase64String(base64));
var image = new BitmapImage();
image.SetSource(stream);
return image;
}private void LayoutRoot_Loaded(object sender, RoutedEventArgs e)
{
const string strDataUri =
“data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==”;
var bmp = BitmapSourceForDataUri(new Uri(strDataUri));
imgDisplay.Source = bmp;
imgDisplay.Width = bmp.PixelWidth;
imgDisplay.Height = bmp.PixelHeight;
}
Using Google Analytics in Phonegap apps.
If you use Phonegap, and want to know how many people use your app regularly, and where they come from, then Google Analytics, with a small modification, is great for this purpose. – But you need a slight modifiction to the normal tracking code.
Firstly, download the ga.js file from http://www.google-analytics.com/ga.js – open it in a text editor and look for the word file:, and replace it with _file then stick it into your www folder. make a reference to it from every page you want to track, then use the script:
<script type="text/javascript" src="ga.js"></script>
<script>
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-YOUR_ID_HERE']);
_gaq.push(['_setDomainName', 'none']);
_gaq.push(['_trackPageview', 'NAME_OF_PAGE']);
</script>
To get your UA-ID then you have to go to Google Analytics, create a new property – selecting “WEBSITE” not “APP”, and pick it out of the code.
To test it, then you run the app, and look at Google Analytics “Real time”, if you see activity appearing, then it’s working!
Select outbound IP address on multi-homed server for HTTP requests
If your server has multiple IP addresses, you can specify which IP address to make a HTTP request from in C#. This is useful if you want to need to ensure that requests do or do not originate from a particular IP address. This little console application demonstrates this, by listing available IP addresses, then making a request to an external website to reveal the outbound IP address as visible to the outside world.
private static IPAddress selectedIP;
static void Main(string[] args)
{
var ips = LocalIPAddress();
Console.WriteLine(“Select an IP Address”);
for (var i = 0; i < ips.Count(); i++)
{
Console.WriteLine(i + “. ” + ips[i]);
}
var choice = Console.Read() – 48 ;
selectedIP = ips[choice];
const string strUrl = “http://myexternalip.com/raw”;
var http = GetWebRequest(new Uri(strUrl));
var stream = http.GetResponse().GetResponseStream();
if (stream != null)
{
var sr = new StreamReader(stream);
Console.WriteLine(sr.ReadToEnd());
}
Console.ReadLine();
}protected static WebRequest GetWebRequest(Uri uri)
{
var request = (HttpWebRequest)WebRequest.Create(uri);
request.ServicePoint.BindIPEndPointDelegate = BindIPEndPointCallback;
request.Proxy = null;
return (request);
}public static IPEndPoint BindIPEndPointCallback(ServicePoint servicePoint, IPEndPoint remoteEndPoint, int retryCount)
{
return new IPEndPoint(selectedIP, 0);
}private static List<IPAddress> LocalIPAddress()
{
if (!System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable())
{
return null;
}
var host = Dns.GetHostEntry(Dns.GetHostName());
return host
.AddressList
.Where(ip => ip.AddressFamily == AddressFamily.InterNetwork).ToList();
}
To see it, you’ll need to run this on a multi-homed machine, type the number beside the required IP address, and see the external IP appear momentarily afterwards.
Javascript file handling
The FileReader object is a new feature of HTML5, and it allows handling of file-data on the client side of a web-application, so for instance, you could provide extra validation on an uploaded file before sending it to the server.
Here’s a simple example of it’s use:
<html>
<head>
<script src=”http://code.jquery.com/jquery-1.11.0.min.js”></script>
<script language=”javascript”>
$(init);
function init()
{
console.log(“Good to go!”);
$(“#myFile”).change(myFile_change);
}
function myFile_change(evt)
{
console.log(“myFile_change”);
console.log(evt.target.files[0]);
var f = evt.target.files[0];
reader = new FileReader();
reader.readAsDataURL(f);
reader.onload = function(e) {
console.log(reader.result);
$(“#imgUpload”).attr(“src”,reader.result);
}
}
</script>
</head>
<body>
<input type=”file” id=”myFile”>
<img id=”imgUpload”>
</body>
</html>
