Click here to Skip to main content
Click here to Skip to main content

Streaming over HTTP with JavaScript: AJAX video player

By , 24 Oct 2006
 

Contents

Introduction

Streaming is mostly referred as a delivery system for media content or dynamic data where it is beneficial to begin processing while data is being delivered. In reality, HTTP was not designed for data streaming. HTTP communications are stateless, and they take place over TCP/IP where there is no continuous connection between the ends. Usually, HTTP responses are buffered rather than streamed. HTTP 1.1 added support for streaming through keep-alive header so data could be streamed, but yet for performance proposes, the majority of implementations including ASP.NET tend to buffer the content, send it, and close the connection. As a result, there are few real world applications that use HTTP for streaming data, and normally, an additional protocol is built on top of HTTP for reconnection and error detection. However, this does not pose a problem because there are other UDP-based protocols that can be used for streaming where it is needed.

So, why would we need data streaming over HTTP? Because, we build our web applications over HTTP. Playing video clips, displaying RSS fields, and updating time sensitive data are considered common features of a webpage nowadays, but yet, we are bounded to HTTP capabilities. Here is where the browsers make use of plug-ins to overcome these boundaries, and also add new troubles!

Plug-ins are executed outside of your application’s context. Unlike Hyper Text Markup Language or JavaScript, plug-ins are mainly compiled binaries and they are difficult to customize. This is not to mention security, accessibility, platform independency, and web standards issues that are involved in pages that use plug-ins. While using plug-ins seems to be inevitable for pages with rich contents, AJAX has created high hopes in my opinion. Even though JavaScript language, as the version of today (the latest 1.7 in Firefox 2), is not fully capable of performing the tasks associated with plug-ins, I believe the future versions can offer enough browser integration and supporting libraries which eliminate the need of using complied plug-ins. I know this sounds very abstract, that is why I decided to write an AJAX application that does the most common task associated with plug-ins: video player. This AJAX video player is a scripted prototype-based video player that runs in JavaScript enabled HTML browsers that support Base64 encoded images (almost all modern browsers but IE). The AJAX video player can broadcast live (using an XML service) or cached video streams (XML file) to a variety of users on different platforms and browsers.

Live sample: Watch the Snoopi at pumpkin patch from AJAX Video Player!

Using the code

Background

A video is a sequence of framed images that are displayed at a rate one after another. If we had all frames of a video clip in our browser, we could display them one after another at a frame rate and there we had our video playing! This sounds like a plan, let us see how we can translate this into an actual web application. From what we planned, we divide our efforts into smaller steps:

Step 1: Getting the frames, frame rate and other necessary information from a video file or a live stream

Step 2: Transport our frames over HTTP to the client’s browser.

Step 3: Animate the frames at the client, response to user interaction and request for more frames if needed.

Step 1: Getting the frames, frame rate and other attributes of video clip

If you have experience with writing applications in Microsoft DirectShow Editing Services (codename Dexter), this will sound very familiar to you. In the Windows environment, traditionally capturing still frames has been done using C++ and Dexter Type Library to access DirectShow COM objects. To do this in .NET Framework, you can make an Interop assembly of DexterLib which is listed under COM References in VS 2005. However it takes you a good amount of work to figure out how to convert your code from C++ to C# .NET. The problem occurs when you need to pass in a pointer reference as an argument to a native function, CLR does not directly support pointers as the memory position can change after each garbage collection cycle. You can find many articles on how to use DirectShow on the CodeProject or other places and we try to keep it simple. Here our goal is to convert a video file into an array of Bitmaps and I tried to keep this as short as possible, of course you can write your own code to get the Bitmaps out of a live stream and buffer them shortly before you send them.

Basically we have two option for using the DirectShow for converting our video file to frames in .NET:

  • Edit the Interop assembly and change the type references from pointer to C# .NET types.
  • Use pointers with unsafe keyword.

We chose the unsafe (read fast) method. It means that we extract our frames outside of .NET managed scope. It is important to mention that managed does not always mean better and unsafe does not really mean unsafe!

MediaDetClass mediaClass = new MediaDetClass(); 
_AMMediaType mediaType; 
... //load the video file
int outputStreams = mediaClass.OutputStreams;
outFrameRate=0.0; 
for (int i = 0; i < outputStreams; i++) 
{ 
  mediaClass.CurrentStream = i; 
  try{ 
     //If it can the get the framerate, it's enough,
     //we accept the video file otherwise it throws an exception here
     outFrameRate = mediaClass.FrameRate; 
       .......
     //get the attributes here
        .....
  
     }catch 
    { // Not a valid meddia type? go to the next outputstream } 
} 
// No frame rate? 
if (outFrameRate==0.0)
    throw new NotSupportedException( " The program is unable" + 
                                     " to read the video file."); 
// we have a framerate? move on... 
... 
//Create an array to hold Bitmaps and intilize 
//other objects to store information...

unsafe { 
    ... 
    // create a byte pointer to store the BitmapBits   
    ...
   while (currentStreamPos < endPosition) 
   { 
      mediaClass.GetBitmapBits(currentStreamPos, ref bufferSize, 
                               ref *ptrRefFramesBuffer, 
                               outClipSize.Width, outClipSize.Height); 
   ...  
   //add frame Bitmap to the frameArray
    ...
  }
}
...

Step 2: Transfer extracted data over HTTP

So far we have converted our video to an array of Bitmap frames. The next step is to transfer our frames over HTTP all the way to the client’s browser. It would be nice if we could just send our Bitmap bits down to the client but we cannot. HTTP is designed to transport text characters which mean your browser only reads characters that are defined in the HTML page character set. Anything else out of this encoding cannot be directly displayed. 

To accomplish this step, we use Base64 encoding to convert our Bitmap to ASCII characters. Traditionally, Base64 encoding has been used to embed objects in emails. Almost all modern browsers including Gecko browsers, Opera, Safari, and KDE (not IE!) support data: URI scheme standard to display Base64 encoded images. Great! Now, we have our frames ready to be transferred over HTTP.

System.IO.MemoryStream memory = new System.IO.MemoryStream();
while (currentStreamPos < endPosition) 
{
  ...
  // Save the Bitmpas somewhere in the (managed) memory 
  vdeoBitmaps.Save(memory, System.Drawing.Imaging.ImageFormat.Jpeg); 
  //Convert it to Base64
  strFrameArray[frameCount] = System.Convert.ToBase64String(memory.ToArray()); 
 //Get ready for the next one
  memory.Seek(0, System.IO.SeekOrigin.Begin); 
 }
memory.Close();
...

But we cannot just send out the encoded frames as a giant string. We create an XML document that holds our frames and other information about the video and then send it to the client. This way the browser can receive our frames as a DOM XML object and easily navigate through them. Just imagine how easy it is to edit a video that is stored in XML format:

<?xml version="1.0" encoding="utf-8"?>
  <Clip name="Snoopi">
     <Frame_Rate>14.9850224700412</Frame_Rate>
        <Clip_Size>{Width=160, Height=120}</Clip_Size>
        <Stream_Length>6.4731334</Stream_Length>
     <Frame ID="96">/9j/4AAQSkZJRgABAQEAYAB.... </Frame>
     ....
  </Clip>

This format also has its own drawbacks. The videos that are converted to Base64 encoded XML files are somewhere between 10% (mostly AVI files) to 300 % or more (some WMV files) bigger than their binary equivalent.

Figure 1 shows the data flow in our AJAX Video Player application.

Figure 1: Data flow in AJAX Video Player

If you are using an XML file, you even don't need a web server , you can open the HTML from a local directory and it should work! I included an executable in the article's download file that can convert your video file to XML document which later can be shown in the browser. However using big files and high resolution videos is not a good idea!

OK, now we can send out our “Base64 encoded video” XML document as we would do with any other type of XML files. Who says XML files always have to be boring record sets anyway?!

Step 3: Animate the frames at the client

Figure 2 shows the application flow in the JavaScript VideoPlayer object. I tried to comment the code as much as possible. You can view the source code in the download provided with this article.

Figure 2: Application flow in AJAX Video Player

Conclusion

In this article, we simulated data streaming with JavaScript and  talked about its great potentials to perform the tasks associated with plugins, although it will be a while until it can replace them in real world applications.  A more featured JavaScript with better OOP support is beneficial to everybody. When it comes to developing JavaScript features many conservative precautions have been considered just to open the door for all sort of plug-ins! Java to JavaScript compliers have already started to squeeze as much as possible out of JavaScript. Google (GWT) and Mozilla (here) have released great compliers to convert your Java code to JavaScript.

Some time in the future :) in another article we talk about how JavaScript can improve the MVC design pattern of a web application by loosely coupling viewers (HTML pages) and controllers (classes in an XML Service). In some scenarios JavaScript can completely replace your web controls and save you from going through ASPX page life cycle.

Appendix - Related Links

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Shahin__
Web Developer
United States United States
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
Questionframes to video output file?membersurbob15 Feb '13 - 19:47 
Hi all,
I want to produce a video using base64 images . Here you converted video into frames .Is there any method to generate a video file from the sequence of base64 images in the controller side in mvc4 application.
Please help me.
Thanks
Suribabu
QuestionDoubt in video datamemberMuthukumar002313 Dec '11 - 16:56 
Hi Sir/Madam..
if one or more server responds the single client,it is possible or not?
GeneralVideo StreamingmemberPrerna Sancheti27 Feb '11 - 8:52 
How to stream video using rtsp protocol in java?
QuestionWhat is author's mail id ??membernarendra.sisodiya23 Aug '08 - 11:03 
I searched on internet a lot and in zip file but Shahlin's email is not working and not his domain also.
I want to contact him for my FOSS project.
mine is : narendra DOT sisodiya AT gmail DOT com
AnswerRe: What is author's mail id ??membersoulsouw18 May '12 - 10:13 
I need the real author name for a paper because I cite this work. Please respond with your name to correctly cite.
 
Thank you!
Questionvedio streamingmemberamoon1081 Apr '08 - 10:49 
hi...
i want to send vedio streaming capture freo cammera connected to computer and then receive it in my mobile remote its possible or not?
Thx
Questionseeking help on video streamingmemberpunk grunge19 Dec '07 - 0:01 
hi, i need help on video streaming. could some one help me on the source codes. i plan to use windows media player and i have bought an IP camera.perhaps to use c# on the language. i just have no idea to do it as im so new into video streaming. thanx in advance.
Questionall about setting server for this appmemberrikkududut30 Nov '07 - 0:18 
hi again... I wanna ask some question.... just in case, i want to set my computer as an server, I use IIS for the web server, then I wanna access the video player using another computer. can I do that? what should I prepare for this? and, if that so, where the video file stored? in server or client? thx.
Generalgood workmemberachalshah24 Jan '07 - 0:48 
hi,
i m achal shah, working as software eng., and i have seen the code u have wrote.
i must say u r good, so keep going Smile | :)
QuestionEnhancement for IE?memberLiang Yu8 Dec '06 - 17:38 
I saw a Base64 image solution for IE at link:
http://dean.edwards.name/weblog/2005/06/base64-sexy/
Will it be possible to enhance your video player to support IE using similar method?

AnswerRe: Enhancement for IE?memberDiabolus Hell26 Apr '07 - 22:19 
Hi
Try to remove the two following lines at the line 211 in the file AJAXtream.html. :
 
AJAXVideoPlayer.writeStatus( 'CANNOT RUN IN I.E. TRY A BROWSER THAT SUPPORTS DATA: URI SCHEME SUCH AS FIREFOX');
return;
 

and change the comment line 210 :
// AJAXVideoPlayer.request = new ActiveXObject("Microsoft.XMLHTTP"); //IE
 
to :
 
AJAXVideoPlayer.request = new ActiveXObject("Microsoft.XMLHTTP"); //IE
 
as a normal line (not a comment).
 
I did not test it, but if there is only that it should work.

Questionhow bout divide the xml?memberrikkududut29 Nov '06 - 21:05 
you say the video file must be small, but, how small is it? then, how bout idea to divide the file? example: you extracted the frame and convert it to xml file every 1MB. thats mean if your video about 20 MB, then you have 20 XML file.
AnswerRe: how bout divide the xml?memberShahin__29 Nov '06 - 21:34 
That is a valid approach. you can have no XML files and just store the XML stream in the memory with the AJAX caller. In fact the browser can start playing while it is dowloading every stream segment (instant play)
 
Shahin
 
Rebuild all succeeded!

QuestionCapturing soundmemberAdnan Siddiqi21 Nov '06 - 23:14 
will it play a video with a sound as well? I didn't hear any sound in sample avi.
AnswerRe: Capturing soundmemberShahin__22 Nov '06 - 15:11 
No it does not. Don't forget this is JavaScript and cannot magically play sound. I am currently busy at work but eventually I will write an XPCOM to play the split sound in FF, something similar to Foxy tune plus a Bas64 decoder.
About your question on different platforms and Linux, the answer is yes, it works on Linux. Remember that XML and Javascript are platform independent and as long as your platform supports HTML and Javascript 1.2 or higher, it should be able to run AJAX Video Player.
 
Cheers!

 
Rebuild all succeeded!

GeneralRe: Capturing soundmemberAdnan Siddiqi22 Nov '06 - 19:40 
My question was that ,is it the limitation of your system that it didn't encode sound as well or its the limitation of the technology?
QuestionCachingmemberAdnan Siddiqi19 Nov '06 - 18:50 
No doubt this is a intresting method however I would like to know that whether it caches the already downloaded frame on browser or not? Also what was the video format at server end which is being streamed here? are you usnig some special streaming arrangments at your end?
 
-does it work on Opera or on wab browsers?
 
Thanks
 
-adnan
AnswerRe: CachingmemberShahin__19 Nov '06 - 21:39 
Yes, the XML document is cached in the browser. As far as browsers, any browser that implements RFC 2397 will be able to play the video clips including Opera. I think IE is the only browser that cannot display data: URI Scheme images.
 
Rebuild all succeeded!

Questioncomparison with flash and xMPP etcmemberAdnan Siddiqi20 Nov '06 - 9:07 
How do you compare it with Jabber's XmPP protocol which is also xml based and it's audio extension "Jingle" is being developed by Google and being used in Gtalk messenger.
 
-Is your method more efficient then flash option that is, flash can convert files into flv which often loads fast even on smal devices. While I don't know whether you tested your application on any mobile based browsers.
 
- can your soltion be ported on non-Windows based machines?
Questionwhat method you used here?memberrikkududut17 Nov '06 - 2:43 
sory, my english is bad, but I would like to ask you, what method you used here? the step you create, is that some kind of method? and the read fast method, is that the method you create yourself? thanks for your reply, I like this concept Smile | :)
AnswerRe: what method you used here?memberShahin__19 Nov '06 - 21:31 
The methodology used in here is the basis of problem solving in software engineering which is dividing your problem into smaller modules. Also “Read Fast” is not a method, by read fast I meant the unsafe keyword does not really mean unsafe, usually the code within the unsafe block runs faster than the managed code.
 
Cheers!
 

 
Rebuild all succeeded!

GeneralRe: what method you used here?memberrikkududut23 Nov '06 - 14:15 
hmmm... if you don't mind, i wanna ask you one question, the step you use to convert video to arrays of bitmaps, is it kind of some method? can u give me short explanation about it? i kinda confused ^_^,, and, why you use HTML? why not ASP.NET? since you use C#? thx
AnswerRe: what method you used here?memberShahin__27 Nov '06 - 17:28 
To understand step 2 , you would need a basic familiarity with Directshow. I understand your confusion! As a matter of fact “ It is often regarded as one of Microsoft's most complex development libraries/APIs.” About your question on why .HTM and not ASPX read here:
 
http://www.codeproject.com/useritems/AJAX_MVC.asp
 
Cheers!
 
Rebuild all succeeded!

GeneralRe: what method you used here?memberrikkududut28 Nov '06 - 17:43 
whoah! i'm getting understand (lil'bit ^^) then how about the decoding stuff? at first you encoded the array of bitmaps, how long it will take? 1 minute for 1 video file? or? then it decode in the client right? how long it will take? can it really animate? i mean, here i cant try the sample you give because the connection is very bad... Frown | :(
 
by the way, in the first step, is the sound exctracted too? if so, then it wouldn't be array of bitmaps right?
 
thank you very much for your attention. i really apreciate it and i really excited with your ideas!
GeneralSuggestion of another approachmembervarnk31 Oct '06 - 3:31 

Your article peaked my interest since I had already done something similar to this.
 
The main difference in my approach vs. the approach documented here is that my method does work in IE, although I am not sure if it works in other browsers.
 
The approach that I take is similar to your own. The main difference is that instead of requested base64 encoded XML data, I use an array of XML Data Island objects to initiate a request to a HTTPModule Handler.
 
The process is as follows (Excuse my crudeness since I am throwing this together rather quickly):
 
1. In JavaScript, build an array of XML Data Island objects. Each object will be called with an htttp module handler url that will be processed on the ASP.NET server side code. Using an XML Data Island allows both data and image to be passed to the client browser so that data and respective images can be displayed together to bound DHTML objects.
 
2. Databind an array of hidden IMG objects to each respective XML Data Island object. Each IMG object is positioned at the same location on the client browser.
 
3. Setup both arrays to be a circular buffer that is processed continuously while the player is active. As it comes time to display each image, the IMG objects are processed (as long as loadcomplete is signaled). This basically involves hiding the current IMG object and then unhiding the next one on the circular buffer and setting the XML Data Island's URL to the HTTPModule Handler's URL.
 
4. On the server side, the HttpModule Handler is responsible for streaming each image request back to the requesting client through the module handler. Since the IMG object is databound to the XML Data Island, it will automatically containe the streamed image when it is ready to be displayed.
 

I have built an ASP.NET control around this logic and it works pretty well. I have been wanting to post an article about this in CodeProject, but have not had the time to put together the article.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130516.1 | Last Updated 25 Oct 2006
Article Copyright 2006 by Shahin__
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid