2

Is it possible to encode video from gif (or a sequence of images) and some sounds files using "javascript" or any "web client" method?

Specifically I want to dynamically create a video file on the client side from some source images and sound files. I then want to allow the user to download the resulting video.

I know I can use ffmpeg with PHP to create video from images and mp3 on the server side, but I don't want to use this method because that will cause huge server CPU usage and data transfer.

RobV
  • 28,022
  • 11
  • 77
  • 119
Howard
  • 601
  • 1
  • 11
  • 15
  • 1
    A file is just a sequence of bits -- you *can* take the bits of some image files (using a `canvas`, for example), then do a lot of complex bit manipulations, and finally create a sequence of bits that are playable as a video file. This would be extraordinarily difficult to do without a video-processing library, and as far as I know no such library exists for JavaScript. You could write such a library yourself (after extensive study of image and video file specifications) or hire someone to write it for you. – apsillers Dec 31 '12 at 20:27
  • 1
    Close voters: The 'duplicate' is about displaying a sequence of images to achieve the effect of animation; this question is about actually encoding video client-side. – josh3736 Jan 03 '13 at 20:44

4 Answers4

3

You have several problems to solve to achieve this.

  • Getting the raw pixels of the GIF.

    <canvas> is probably the best way to do this, but I don't think it will play nicely with an animated GIF. You could certainly read a series of images.

  • Converting the frames into a video stream.

    While there are JavaScript implementations of MPEG audio codecs, I'm not aware of a video codec in pure JS. You could take a look at the ffmpeg source and try porting it.

    In addition to implementing the video compression codec itself (such as MPEG-1, -2, H.264, and so on), you'd also have to write to a container format of some kind (For example, a MPEG PS.)

  • Handling binary data.

    The output of any video codec is binary data, and JavaScript by its nature doesn't deal well with raw binary data. Recent browsers have added typed arrays exactly to address this shortcoming in a memory-efficient manner.

  • Delivering the video file to the user.

    I know this sounds silly since all of the above would technically happen on the user's computer, but they happen in the browser sandbox. You now have to get the data out of the browser and into a file that the user can save to their file system.

    Someone else suggested using a data: URI (base64-encoded data), but this is a terrible idea from a memory standpoint, especially since you'll be dealing with video data, which is relatively large. At this point, you'll have your video stream in a typed array. Create a new Blob from the typed array and pass that Blob to window.URL.createObjectURL. This way, the data needn't be duplicated in memory; instead, the browser will "download" from the typed array to the file system.

Of course, all of this assumes that the user's machine will have enough memory (RAM). Unlike normal video compression implementations, you can't stream the output data to disk; you have to keep the entire file in memory. You'll likely run out of memory faster than you'd think.

So while this may be theoretically possible, it's not a good idea. If it works, it will be very slow and freeze the browser while it encodes the video (since JS and the browser UI share the same, single thread). I suppose you could bring web workers in to the mix to get around that, though.

At this point in time, you'll pretty much have to roll your own server-side solution or use some kind of service that will do the heavy lifting for you.


Alternatively, you may be able to leverage Google's NaCl (native client) in Chrome to actually do the video encoding. NaCl allows you to run native (C/C++) code in the browser.

It looks like there's a ffmpeg port, and there are APIs to do file I/O.

Obviously, this does only work in Chrome. Firefox, Safari, and IE won't support NaCl.

josh3736
  • 139,160
  • 33
  • 216
  • 263
  • 2
    Data URIs are also very limited in length in many browsers - chances that a whole video can be held by them are very low. – Oded Dec 31 '12 at 21:18
1

Sure.

Use setInterval to call a function on a schedule, changing the source of the image to the next one in sequence.

You may want to preload the images so there is no wait when the image source changes.


Update:

You possibly can create a video file from a sequence of images using JavaScript alone, but this is unlikely to be easy or work well. I would recommend you use some server side processing to produce such a video and incorporate audio into it (perhaps using ffmpeg).

Community
  • 1
  • 1
Oded
  • 489,969
  • 99
  • 883
  • 1,009
  • I think (but I may be wrong) that OP actually wants to generate a downloadable video *file*, not merely simulare a video in the browser. – apsillers Dec 31 '12 at 20:23
  • @Oded, I actually [disagree](http://stackoverflow.com/a/14106076/201952) that it is technically impossible to create a video using JS alone -- not that it's a good idea by any stretch of the imagination. – josh3736 Dec 31 '12 at 21:15
1

You've noticed that a C-language program written for exactly this purpose consumes vast names of CPU cycles. What would make you think that a scripted language designed for another purpose entirely could do it?

No, Javascript on the browser does not have access to the individual pixels directly, and certainly cannot create binary files. If you have the frames as separate images, it might be possible to load them into a canvas tag, access the pixels that way, calculate the MPEG version as a integer array and post that back to a server (which would convert the array into a binary file), but wow, would that be slow. At least 1000x slower than ffmpeg.

EDIT

The comments point out that I am in fact totally wrong. Nonetheless, I stand by my original conclusion that this is a terrible idea.

Michael Lorton
  • 43,060
  • 26
  • 103
  • 144
  • 2
    To be fair, there are [JS MP3 codec implementations](https://www.google.com/search?q=javascript+mpeg+codec), and you [can handle binary data with a typed array](https://developer.mozilla.org/en-US/docs/JavaScript/Typed_arrays), so a MPEG video codec is *technically* possible. Also, to deliver the data to the user, you don't even have to send it back to a server; create a [`Blob`](https://developer.mozilla.org/en-US/docs/DOM/Blob) from the typed array and pass that `Blob` to [`window.URL.createObjectURL`](https://developer.mozilla.org/en-US/docs/DOM/window.URL.createObjectURL). – josh3736 Dec 31 '12 at 20:46
  • +1, but the server isn't technically needed at all; you can simply redirect the page to a base64-encoded `data:` URI to perform the binary download. That said, I agree 100% that this is not a good idea. – apsillers Dec 31 '12 at 20:50
  • It's possible and it's viable (speed-/resource consumption-wise). See my answer. – CWSpear Oct 12 '14 at 18:04
1

It's late 2014 now, and I don't know at what point it was made possible, but it is indeed now possible to turn a video into a gif: http://jnordberg.github.io/gif.js/tests/video.html

Via the library by the same person who made that demo: https://github.com/jnordberg/gif.js

Works great in Chrome 38, and I believe any other browsers that support Web Workers, File API and Typed Arrays.

CWSpear
  • 3,230
  • 1
  • 28
  • 34