Introduction
Using this application, you can upload video in any format (.mov, .avi, .wav, flv). If you do not upload
a video file in flv format, then it will be converted to an flv file using ffmpeg for progressive streaming.
An ASP.NET handler is used for pseudo-streaming and a flowplayer is used to show
the flv files. You can also play MPEG-4 H.264 (.mp4) formatted file using flawplayer. I will
also discuss progressive streaming of .mp4 here.
Implementation
In my previous blog here, you can see the implementation of an ASP.NET handler for uploading
a file using valums AJAX upload and I am using this file upload handler for uploading video and audio files. As flv is the best format for websites,
the video file is converted to flv format after upload.
Uploading Video File and Converting to Flash Video (flv) Format
In my previous article, I have shown how to upload an image file using valum's
AJAX upload using ASP.NET handler. I am using the same valum’s upload control for uploading
the video/audio file. This supports multiple uploads by default but you can set params to upload single files only by setting
the parameter multiple:false.
Also I have given restrictions in allowed extensions.
var uploader = new qq.FileUploader({
element: document.getElementById('file-uploader-demo1'),
action: 'FileUpload.ashx',
template: '<div class="qq-uploader">' +
'<div class="qq-upload-drop-area"><span>Drop files here to upload
</span></div>' +
'<div class="qq-upload-button">Upload a video</div>' +
'<ul class="qq-upload-list"></ul>' +
'</div>',
multiple: false,
allowedExtensions: ['flv', 'mov', 'mp4', 'avi', '3gp', 'mgp', 'wmv'],
debug: true,
onComplete: function (id, fileName, responseJSON) {
if (responseJSON.success)
$("#videoContainer").append("<div class='player'
style='display:block;width:400px;height:400px;
background-image:url(" + responseJSON.image + ");
' href='" + responseJSON.path + "'>
<img src='images/play_large.png' alt='Play this video' />
</div>");
flowplayer("div.player", "Scripts/flowplayer/flowplayer-3.2.7.swf", {
clip: {
autoPlay: false,
autoBuffering: true
}
});
}
});
In the above code snippet, valum’s upload options are changed to support single upload and only video files. I have also changed
the template of the upload button. I will discuss the OnComplete
code later.
As the user is watching the progressive stream of flv files, when the user is uploading an flv file, only
a thumbnail is created from that file. But when the user uploads other a formatted file like .mov, avi, mpeg or .wav, then
a video file is converted to flv format. FFMPEG is a very lovely tool for converting video files. Using this tool, you can extract audio from video and also generate
a thumbnail from a video file specific frame.
I am not familiar with the ffmpeg command arguments so I used standard options for Flash Video (flv). The format I have got from WinFF is:
"ffmpeg.exe" -i "sample.avi" -vcodec flv -f flv -r 29.97
-s 320x240 -aspect 4:3 -b 300k -g 160 -cmp dct -subcmp dct
-mbd 2 -flags +aic+cbp+mv0+mv4 -trellis 1 -ac 1 -ar 22050 -ab 56k "sample.flv"
Using this code snippet, I have converted my 25MB .wav file to an 1.4M flv file. You will not
be able to run the ffmpeg command using ASP.NET basic authentication. So for
running ffmpeg.exe, you need to impersonate a specific user account. Here, you can see how to impersonate a specific user in code.
if (Path.GetExtension(phyicalFilePath).Equals(".flv")) return phyicalFilePath;
if (AuthenticationHelper.ImpersonateValidUser("user", ".", "*******"))
{
var argument = string.Format("-i {0} -vcodec flv -f flv -r 29.97
-s 320x240 -aspect 4:3 -b 300k -g 160 -cmp dct -subcmp dct
-mbd 2 -flags +aic+cbp+mv0+mv4 -trellis 1 -ac 1 -ar 22050
-ab 56k {1}", phyicalFilePath,
Path.ChangeExtension(phyicalFilePath, "flv"));
-vcodec libx264 -acodec libfaac -ar 48000 -ab 128k
-coder 1 -flags +loop -cmp +chroma -partitions
+parti4x4+partp8x8+partb8x8 -me_method hex -subq 6 -me_range 16
-g 250 -keyint_min 25 -sc_threshold 40 -i_qfactor 0.71
-b_strategy 1 -threads 0 {1}", phyicalFilePath,
Path.ChangeExtension(phyicalFilePath, "mp4"));
ProcessStartInfo process = new ProcessStartInfo(ffmpegPhysicalPath, argument);
Process proc = new Process();
proc.StartInfo = process;
proc.Start();
proc.WaitForExit();
AuthenticationHelper.UndoImpersonation();
return Path.ChangeExtension(phyicalFilePath, "flv");
Here you can see the command for converting a video file into Flash video (flv) format. When you use my code, you have to set
the ffmpegPhysicalPath
field variable with the physical path of
the ffmpeg.exe file.
You can send the flv file path to the client when the flv conversion is completed and
the flowplayer will ask the ASP.NET handler for streaming the video. But I also want to show a thumbnail splash image so that user can understand that
the video is uploaded. And on clicking the splash image, the ASP.NET handler will be called and
the user can see the video using flawplayer.
Generating a thumbnail image from the video file is very easy using ffmpeg. In
the flawplayer forum, you can see the details of generating a thumbnail from the video: http://flowplayer.org/tutorials/generating-thumbs.html.
After completing these steps, I send a JSON response to contain the flv location and image location.
var flvpath = ConvertToFLV(phyicalFilePath);
var tumbnail = CreateThumbnail(phyicalFilePath);
context.Response.Write("{success:true, name:\"" +
filename + "\", path:\"" + path + "/" +
Path.GetFileName(flvpath) + "\", image:\"" +
path + "/" + Path.GetFileName(tumbnail) + "\"}");
Uploading a Large File
You might fail to upload large files as by default IIS supports content length
up to 30000000 bytes.
You also need to set maxRequestLength
in web.config otherwise you will get an exception while fetching
a large file. Suppose I support a maximum 2 GB size file in my site. My web.config settings are:
<system.web>
<compilation debug="true" targetFramework="4.0" />
<httpRuntime maxRequestLength="4124672" requestValidationMode="2.0" />
</system.web>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="4223664128"></requestLimits>
</requestFiltering>
</security>
<handlers>
<add name="MP3Streaming" path="*.mp3" verb="*" type="MP3Streaming"
resourceType="Unspecified" preCondition="integratedMode" />
<add name="flvStreaming" path="*.flv" verb="*" type="FLVStreaming"
resourceType="Unspecified" preCondition="integratedMode" />
</handlers>
</system.webServer>
Here maxRequestLength
is in KB and maxAllowedContentLength
is in byte format. Now you can upload
a maximum 2G file using Valum's upload control.
Watching Progressive Streaming Video using ASP.NET Handler
Flowplayer forum http://flowplayer.org/forum/5/14702#post-14702 discusses
the steps to implement progressive streaming using an ASP.NET handler very well so for IIS settings you can read
information there. I have just copy pasted and used the same code in my handler. So when flowplayer requests to
the server to get an flv file, the FLVStreaming
handler will be called which will provide
the flv file progressively.
You can download flowplayer SWF file from the FlowPlayer site. A thumbnail of
the video and flv location is sent after uploading using Valum's control. So here OnComplete
function code is:
onComplete: function (id, fileName, responseJSON) {
if (responseJSON.success)
$("#videoContainer").append("<div class='player'
style='display:block;width:400px;height:400px;
background-image:url(" + responseJSON.image + ");
' href='" + responseJSON.path + "'>
<img src='images/play_large.png' alt='Play this video' />
</div>");
flowplayer("div.player",
"Scripts/flowplayer/flowplayer-3.2.7.swf", {
clip: {
autoPlay: false,
autoBuffering: true
}
});
}
});
You can see here the thumbnail image is set as the background and a play image
is displayed in the middle. After clicking on the image, the flowplayer script will be called and
a request for the flv file is send to the server and then the FLVStreaming
handler will be called.
Streaming MP4 Video
FlowPlayer also supports H.264 mp4 video format. You can also use the JW Player.
Converting Video File into MP4 Formatted Video File
The ffmpeg command for converting a video file into a h264 MP4 formatted video file is:
var argument = string.Format("-i {0} -crf 35.0 -vcodec libx264
-acodec libfaac -ar 48000 -ab 128k -coder 1 -flags +loop
-cmp +chroma -partitions +parti4x4+partp8x8+partb8x8
-me_method hex -subq 6 -me_range 16 -g 250 -keyint_min 25
-sc_threshold 40 -i_qfactor 0.71 -b_strategy 1 -threads 0 {1}",
phyicalFilePath, Path.ChangeExtension(phyicalFilePath, "mp4"));
The implementation of the andler for MP4 can be found here. You can see
that the client type is different for MP4. You can also use the JW Player. But I do not want to mix two implementations here, so I did not provide
the MP4 handler here.
Streaming an MP3 Audio
The handler for MP3 audio is the same as for the flv player but just the content-type
is different.
context.Response.AppendHeader("Content-Type", "audio/mp3");
context.Response.AppendHeader("Content-Length", fs.Length.ToString());
Flowplayer also supports MP3 files. We can change the configuration of FlowPlayer
using the following script:
var uploader = new qq.FileUploader({
element: document.getElementById('file-uploader-demo2'),
action: 'AudioUpload.ashx',
multiple: false,
template: '<div class="qq-uploader">' +
'<div class="qq-upload-drop-area"><span>Drop files here to upload
</span></div>' +
'<div class="qq-upload-button">Upload a mp3</div>' +
'<ul style="display:none" class="qq-upload-list"></ul>' +
'</div>',
allowedExtensions: ['mp3'],
debug: true,
onComplete: function (id, fileName, responseJSON) {
if (responseJSON.success)
$("#audioContainer").append("<a id='audioPlayer'
style='display:block;height:30px;' href='" + responseJSON.path + "'/>");
$f("audioPlayer", "Scripts/flowplayer/flowplayer-3.2.7.swf", {
plugins: {
controls: {
fullscreen: false,
height: 30,
autoHide: false
}
},
clip: {
autoPlay: false,
onBeforeBegin: function () {
$f("player").close();
}
}
});
}
});
After the upload is complete, flowplayer will be displayed like this. And clicking on
the Play button, it will call the MP3 streaming handler and run the MP3 in a progressing manner.