html display video file binary buffer - javascript

I am working on an example of ffmpeg-wasm which will accept 3 files as input [song1.mp3, song2.mp3, image.png] and combine them into a video file [cool-output-video.mkv] which I want to be displayed as a playable video for the user in the html webpage.
https://github.com/MartinBarker/ffmpeg-wasm-node
My code is hosted in the above repo, right now I have a placeholder video element, which I want to change to the finished video after the user uploads the 3 files and clicks the render button.
inside server.js, I have the route app.post('/render' , which will render the video using ffmpeg, and return the video using the line res.end(Buffer.from(outputData, 'binary'));
outputData = ffmpeg.FS('readFile', outputFileName);
ffmpeg.FS('unlink', outputFileName);
res.writeHead(200, {
'Content-Type': 'image/png',
'Content-Disposition': `attachment;filename=${outputFileName}`,
'Content-Length': outputData.length
});
//res.end(btoa(Buffer.from(outputData, 'binary')));
//res.end(outputData)
res.end(Buffer.from(outputData, 'binary'));
I can see in my node server console log that the ffmpeg command finished and successfully renders the mkv video file
and inside client.js is where my code recieves the binary buffer for my outputted video file, and tries to make it appear on the webpage by changing the src attribute for the html video element, but no matter what code I try, I cant get the video file to appear on the html page
<video width="320" height="240" controls>
<source id='mp4source' src="" type="video/mp4">
Your browser does not support the video tag.
</video>
...
const mp4source = document.querySelector('#mp4source')
...
console.log('call renderVideo()')
const renderResult = await renderVideo(files);
console.log('renderVideo() finished. renderResult=',renderResult)
mp4source.src = renderResult
I can see in my html file in my chrome webpage devtools console, that data is being returned and gets printed out, I'm just not sure how to handle this string data for my video file to make it appear on the webpage:
renderVideo() finished. renderResult= data:image/png;base64,GkXfo6NChoEBQveBAULygQRC84EIQoKIbWF0cm9za2FCh4EEQoWBAhhTgGcBAAAAC0APWxFNm3TCv4T+wiwATbuLU6uEFUmpZlOsgaFNu4tTq4QWVK5rU6yB8U27jFOrhBJUw2dTrIIB1E27jlOrhBxTu2tTrIQLQA797AEAAAAAAABRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFUmpZsu/hLA0O5Qq17GDD0JATYCNTGF2ZjU4LjQ1LjEwMFdBjUxhdmY1OC40NS4xMDBzpJAgTn1WHXX52GUlw+lW90wkRImIQRzeoAAAAAAWVK5rQN2/hEsGuLSuAQAAAAAAAD3XgQFzxYjtk28iSHTlJJyBACK1nIN1bmSGj............. long text was truncated etc
EDIT changed my ffmpeg command to export an mp4 video, changed header to be video/mp4, and verified it is getting added to the html src element but the video still does not appear

solved by reading the comment on this post:
Base64 value is not working with video tag?
had to move src tag from the element to the element instead and now it works!

Related

Reload video if src file changes on server to another video with the same name

How to reload video on page if I change src file on disk?
For example, I have
<video controls="controls" id="myVideo">
<source id="source" src="~/videos/Intro.mp4" type=video/mp4 />
</video>
On disk I replace file Intro.mp4 to another video with same name.
If I use $("#myVideo").load() , it happens nothing. When I refresh page, in Opera my video does not changes, in Edge it reloads. I need to reload video without refresh page.
UPD: In some reasons I cannot use files with different names, I need to use only Intro.mp4 name
If you're only changing the file and keeping the same file name it is very likely that the browser is caching the old video. If you want to change the video without reloading you will need both videos on the disk in the same location. ~/videos/Intro1.mp4 and ~/videos/Intro2.mp4 for example.
The you can change the source of the video using JQuery.
$('#myVideo source').attr('src', '~/videos/Intro2.mp4');
Once the source is changed you can run $("#myVideo")[0].load(); to change the video playing without reloading the page.
I am reloading the video on error. When the replacing takes place, and i change the frame of the video an error occurs (e.g. Error 3; details: PIPELINE_ERROR_DECODE: VDA Error 4), so this is when i reload the video.
var video = $('#myVideo')[0];
var hadError = false;
video.onerror = function () {
console.log('Error ' + video.error.code + '; details: ' + video.error.message);
hadError = true;
video.load();
};
video.addEventListener('loadeddata', function() {
if(hadError) { video.onerror = null; }
});

How to properly insert <video> tag into html with javascript?

I'm just getting started here with javascript and have made this.
I have made a codepen that shows the two issues I am having
1) there are two duplicate videos being loaded in, when I delete one of the video tags it prevents the randomize button from working or any video from loading up. I am only trying to have one video load in.
2) In the codepen I have a button that clicks to randomize but instead I am trying to have the video wrapped with an tag so that the video can be clicked to initiate the randomize. Whenever I try and do this I get an undefined error or the videos will not load in =/
Play video
<div class="video-label"></div> <!-- loads in top video (only want one video) -->
<video loop autoplay> <!-- loads in bottom video (only want one video) -->
Your browser does not support the <code>video</code> element.
</video>
If you click on the codepen you will hopefully be able to see where the two videos are being loaded in and where the click tag is. Any help is greatly appreciated!! I've been trying to figure it out all night :/
Here is the codepen
Codepen
Thanks in advance!
You can create a html5 video tag using javascript by following this logic:
var videoelement = document.createElement("video");
videoelement.setAttribute("id", "video1");
var sourceMP4 = document.createElement("source");
sourceMP4.type = "video/mp4";
sourceMP4.src = "http://zippy.gfycat.com/SpottedDefensiveAbalone.mp4";
videoelement.appendChild(sourceMP4);
var sourceWEBM = document.createElement("source");
sourceWEBM.type = "video/webm";
sourceWEBM.src = "http://zippy.gfycat.com/MinorGregariousGrub.webm";
videoelement.appendChild(sourceWEBM);
$('.video-label').html(videoelement);
var video = document.getElementById("video1");
video.play();
This code is creating a video tag and including it into your div (.video-label), then the video starts automatically. This is working without the random stuff (the same url is used everytime), so you can update it at your convenience. Try to remove the video in you html file, it works now:
<video loop autoplay>
Your browser does not support the <code>video</code> element.
</video>
Here is a link where you can download your code updated with working solution (without randomization):
http://tests.krown.ch/Codepen.zip
Also when you click on your video div (.video-label), the video tag will be deleted and created back (but with same url, you just need to update video url with your randomize stuff)
In this line you find any video tags on the page and try to copy it's content into div:
var $video = $('video');
...
$('.video-label').html($video.get(0).outerHTML);
But if you delete video from the page there will be nothing to copy. You need to move video tag inside div in first place. Or create it dynamically, not by copying, when user clicks link.

VIDEO.JS - Player still streaming after the pause / stop command

I'm trying to embed a video.js video player on my website. I'm running a debian 7.5 / chrome / IceWeasel (thunderbird) station with jquery-1.10.2 for the test.
Awaited features
Playing a video from a list index.
I list the video files contained in a directory, setup the hyperlink for each of them as :
<a class="IndexItem" href="#" id="404467" type="video/mime-type" data-video="video-file_name.mp4">My video #1</a>
....
The click event is managed BY the javascript code.
when a video index is clicked, the corresponding source tag is dynamically created and the video player loaded.
Issue
The video is loaded and played succesfully but when I click the player stop button, the progress bar still move forward until the end of the stream is reached.
How can I fixed that ?
Code excerpt
html
<video class="video-js vjs-default-skin" height="480" id="video-player" width="640" poster="/images/bubble-logo.png">
<source src="/path/to/my/video" type="video/mime-type"/>
<h3>Your browser does not support the video tag</h3>
</video>
the video/mime_type can be video/mp4, video/webm or video/ogg
javascript
$(document).ready(function() {
//---------------------
// Edit click event
//---------------------
$.each($(".IndexItem"), function(){
$(this).click(function(event){
event.preventDefault();
// href data-video attribute contains the video file name
// href type attribute contains the video mime-type
var filename = $(this).attr("data-video");
var mime = $(this).attr("type");
// removing previous sources
$('#video-player').empty();
playVideo(filename, mime);
});
});
});
function playVideo(filename, mime) {
// set set html source tag inside the video player div
loadSource(filename, mime);
videojs("video-player", {"controls":true}, function(){
// Player (this) is initialized and ready.
});
}
function loadSource(filename, mime){
var source = $('<source src="/videos/' + filename + '" type="' + mime + '"/>');
$('#video-player').append(source);
var warning = $('<h3>Your browser does not support the video tag</h3>');
$('#video-player').append(warning);
console.log("Creating new source :" + source);
}
Perhaps my method is not the right one as I create a video player instance for each request (Doesn't seem to be really clean ...). Assuming it's not, the problem regarding my issue is still relevant as it raised the first time I try to open a video after having the page reloaded.
Thanks in advance for your help.
Fix
It's an encoding issue of my video files with ffmpeg, frankly I don't remenber what was exactly the problem but now everything works fine !
First thing: to ensure the widest compliance it's advised to encode your original video in three different format :
mp4
webm
ogg (ogv extension)
and then declaring them in the html tags as
<video height="480" id="video-1" width="640" poster="/images/video-1.jpg" controls="true" preload="true"><source src="/videos/video-1.ogv" type="video/ogg"/><source src="/videos/video-1.webm" type="video/webm/><source src="/videos/video-1.mp4" type="video/mp4"/><h3>Your browser does not support the video tag</h3></video>
/videos must be a static web server mapping to /path/to/ (see bellow)
The more difficult thing to do is to encode the video with the correct ffmpeg options. The video bit rate must not exceed the link capacity and the video display must be as smooth as possible.
I found out this settings after several days of testing that finally fit my needs ... and also perharps yours.
I use .mp4 format as input as that's providen by my Contour Camera but ffmpeg should convert any other known format.
To check the available formable type in:
$ ffmpeg -formats
To encode my video with multiple outputs, I run
$ ffmpeg -i camvideo.mp4 -c:v libvpx -c:a libvorbis -s 4cif -b:v 256K -f webm /path/to/video-1.webm
$ ffmpeg -i camvideo.mp4 -c:v libx264 -s 4cif -preset slow -bufsize 4M -maxrate 256K -tune fastdecode,zerolatency -c:a copy -b:a 16K -f mp4 path/to/video-1.mp4
$ ffmpeg -y -i $1 -codec:v libtheora -s 4cif -qscale:v 7 -codec:a libvorbis -qscale:a 3 -f ogg /path/to/video-1.ogv
Note that my environment is Debian 7.5 with ffmpeg 2.2.2 (compiled from sources) and that the result may differ regarding your ffmpeg version ... I think.
Note : the mp4 source is also re-encoded to make it usable by web browser plugins and Be patient .. encoding is a huge CPU task.
Hope that helps.

m3u8 video with dynamically generated <video> tag

In a HTML5/JS app (backbone.js / jQuery) i'm having trouble embedding a m3u8 video stream delivered by a wowza media server.
The app is supposed to run in mobile safari only, so the format would be allright.
The video gets embedded with a tag, generated by Javascript.
<video src="http://someotherdomain.net:[customport]/path/playlist.m3u8" controls>
</video>
When embedding the video tag with a test stream-URL in a static test page, the video works perfectly up and down all tested iOS Versions.
The Problem is when generating the tag with JS, the video stalls in loading state.
Desktop Safari however plays the video just fine.
I couldn't figure out what's causing this so far. Could this be some security restriction on the mobile browser?
UPDATE
as this is some closed and rather complex app i'm unfortunately not able to provide a non-working example, but this is the method that renders the video tag into the page:
/**
* add <video> tag and add source
*
* #param src
*/
loadVideoSource: function (src) {
this.$el.find('video').remove();
$('<video/>')
.attr('src', src)
.prop('autoplay', true)
.prop('controls', true)
.css('width', '100%')
.css('height', '60%')
.appendTo(this.$el.find('div.video'));
}
that port does work and renders the following markup:
<video
src="https://somedomain.com.tr:1935/live/12345678/playlist.m3u8"
autoplay
controls
style="width: 100%; height: 60%;"
></video>
i also tried initially having the video tag in the page an just adding the src attribute or <source> child.
I also tried to call load() and play() explicitly on the video element but that didn't help either...
Hi i am posting a small snippet which i always use for video..
videoElement = document.createElement('video'); // this audioelement is used to create an audio tag
$(videoElement )
.attr('id', 'video');
function videoElement_Int_fn(currentPos) {
var src = currentPos+'.mp4';
videoElement .setAttribute('src', src);
videoElement .load();
videoElement .play();
}
ok, after hours of debugging it simply turned out to be a CSS bug :P
Since you have to start a video explicitly in iOS, you'll have to press the play button in the video after loading the markup.
Strangely enough, this was prevented by
-webkit-overflow-scrolling: touch;
...which was used on the parent container of the video, and prevented the native play button of the video element to be clickable.

Get video first frame in javascript

How can I get the first frame of a video file in javascript as an image?
It can be done with HTML 5 video and canvas tags:
HTML:
<input type="file" id="file" name="file">
<video id="main-video" controls>
<source type="video/mp4">
</video>
<canvas id="video-canvas"></canvas>
Javascript:
var _CANVAS = document.querySelector("#video-canvas");
var _CTX = _CANVAS.getContext("2d");
var _VIDEO = document.querySelector("#main-video");
document.querySelector("#file").addEventListener('change', function() {
// Object Url as the video source
document.querySelector("#main-video source").setAttribute('src', URL.createObjectURL(document.querySelector("#file").files[0]));
// Load the video and show it
_VIDEO.load();
// Load metadata of the video to get video duration and dimensions
_VIDEO.addEventListener('loadedmetadata', function() {
// Set canvas dimensions same as video dimensions
_CANVAS.width = _VIDEO.videoWidth;
_CANVAS.height = _VIDEO.videoHeight;
});
_VIDEO.addEventListener('canplay', function() {
_CANVAS.style.display = 'inline';
_CTX.drawImage(_VIDEO, 0, 0, _VIDEO.videoWidth, _VIDEO.videoHeight);
});
});
View demo
Just add the video tag to the page with no controls and no auto-play.
<video width="96" height="54" class="clip-thumbnail"> ... </video>
Drawback is that users can play the video by right clicking the thumbnail and selecting "play" in the context-menu. To avoid that you'd need a little javascript listening for click events and cancelling them (removing context-menu from thumbnails).
As mentioned, Javascript is not able to do this.
If you want to create thumbnails for your videos you have to create the thumbnail server side and then simply serve up the image on the client as you would any other image.
My method of choice for accomplishing this is the ffmpeg decoder. It can handle a multitude of file formats and is able to do what you want. So if you have a video named hello.avi, you might do:
ffmpeg -itsoffset -1 -i /path/to/hello.avi -vcodec mjpeg -vframes 1 -an -f rawvideo -s 200x150 /path/to/hello.jpg
You can run this command (fixing the paths and dimensions...) with whatever server-side language you are using and it would create a thumbnail of the video file.
Javascript is not capable of doing this.
It may be possible if the video is a file selected by the user into an <input type="file">, you can get the base-64 video data using the FileReader API:
https://developer.mozilla.org/en-US/docs/DOM/FileReader
From there you're just left with the extremely intractable problem of decoding the video and somehow picking out and rendering a single frame, in javascript. Alternatively, you could just include the entire video as the "thumbnail preview" (I assume that's why you're doing this?), as demonstrated here:
http://hacks.mozilla.org/2009/12/file-drag-and-drop-in-firefox-3-6/
Not sure about the compatability of that last example though, or how well it work with larger video files (I hear you can easily bump up against URL length restrictions)

Categories

Resources