webrtc captureStream from canvas and capture audio from video - html5-canvas

In my project I have a video displayed. On top of the video there is a canvas where some object are drawn. Therefore the video is overlayed with some drawings. Now I want to download the video file including the drawings.
I am using the webrtc mediaRecorder.
I am drawing the video to a canvas on window.requestAnimationFrame. My exported video looks good but there is no audio from the video because I captured the canvas. Is it possible to capture the audio from the video and add it to the canvasStream?
I also recorded the videostream including the audio but then I dont have my drawings on top of it. Any suggestions?

You need to create new MediaStream with input stream AudioTrack and Canvas Video Track.
Then record the new Stream, so the recorder output(blobs) will contains both audio and video.
var options = {mimeType: 'video/webm'};
var recordedBlobs = [];
var newStream = new MediaStream();
newStream.addTrack(inputStream.getAudioTracks()[0]);
newStream.addTrack(canvasStream.getVideoTracks()[0]);
mediaRecorder = new MediaRecorder(newStream, options);
mediaRecorder.ondataavailable = function (event) {
if (event.data && event.data.size > 0) {
recordedBlobs.push(event.data);
}
}
mediaRecorder.start(1000);
See my demo.

Related

How to capture screenshot from a video playing on different server

I am trying to capture a screen image from a video, which src is on a different server. So far I got to blank image, which as far as I understand is expectable, because of the tainted canvas or CORS policy error if I give the video tag 'anonymous' crossorgin property. I am using html2canvas, but also tried and with simple canvas context like this:
let ctx = canvas.getContext('2d');
ctx.drawImage( video, 0, 0, canvas.width, canvas.height );
let image = canvas.toDataURL('image/jpeg');
and with html2canvas, trying multiple combinations of options with Vue proxy configurated to the server of the video:
let el = this.$refs.videoPlayer
el.setAttribute('crossOrigin', 'anonymous')
this.output = (
await html2canvas(el, {
allowTaint: true,
useCORS: true,
proxy: '/two',
async: true,
foreignObjectRendering: true,
})
).toDataURL()
Is there any workaround around this? Because I have it working with a local video and now this is quite unfortunate. Is it possible to first download the video on the user system and then play it in order to take the screenshot?
Edit:
The only working workaround I found is to download the video as Blob via axios and then use it, which works perfectly, but uses the user cache for the video.

Skipper in SailsJS (beta) image resize before upload

I'm using SailsJS (beta). I'm trying to find a way to use graphicsmagick to take the stream parsed by Skipper in SailsJS-beta to resize the image before calling the Skipper-function req.file('inputName').upload().
My goal is to take my large, original image, and resize it before uploading it. Sails beta have introduced the Skipper-file-parser which are poorly documented (at least I don't understand it). Please help me understand how to resize the image before upload.
This works (code in my controller action):
req.file('fileName').upload('storedImage.png', function(err, files){
// File is now uploaded to storedImage.png
});
What I want is something like:
// Read the file stream into a file upload
var stream = req.file('fileName');
gm(stream).resize(200, 200).write('storedImage.png', function(err){
// File is now resized to 200x200 px and uploaded to storedImage.png
});
My problem is: how do I properly fetch the stream from req.file('fileName') to send it to gm?
This should work for you:
var Writable = require('stream').Writable;
var resize = require('image-resize-stream')(100); // Or any other resizer
// The output stream to pipe to
var output = require('fs').createWriteStream('storedImage.png');
// Let's create a custom receiver
var receiver = new Writable({objectMode: true});
receiver._write = function(file, enc, cb) {
file.pipe(resize).pipe(output);
cb();
};
Now in your action you just have to use your receiver:
req.file('fileName').upload(receiver, function(err, files){
// File is now resized to 100px width and uploaded to ./storedImage.png
});
I have a feeling that Skipper's API is going to change, a lot, but this will work for now (with v0.1.x).
UPDATE
Specifically, if using gm for resizing, it'll be something like this:
var gm = require('gm');
var Writable = require('stream').Writable;
// The output stream to pipe to
var output = require('fs').createWriteStream('storedImage.png');
// Let's create a custom receiver
var receiver = new Writable({objectMode: true});
receiver._write = function(file, enc, cb) {
gm(file).resize('200', '200').stream().pipe(output);
cb();
};
I had problems with #bredikhin solution so I dig deeper into this and found this thread very helpful: Uploading files using Skipper with Sails.js v0.10 - how to retrieve new file name
I just changed one line of his Uploader:
[...]
file.pipe(outputs);
[...]
into:
gm(file).resize(200, 200).stream().pipe(outputs);
and this does the trick.
I wrote this answer because it may be helpful for someone.

Firefox html5 video rewinds instead of playing

I am using video tag on my website. It works with every major browser, but I am running into issues with Firefox.
When I tap on the play button video scrolls to the end of video!
In order to start the video I need to rewind video to position other than start and than click on play.
Weird.
I tried to set initial position of video to 1s but it didn't help.
I still need to scroll it manually.
Any help will be appreciated.
Thank you
<video width="80% height="80%" controls id="video1">
<source src="videos/<cfoutput>#getVideo.URL#</cfoutput>.mp4" type="video/mp4">
<source src="videos/<cfoutput>#getVideo.URL#</cfoutput>.ogv" type="video/ogg">
<source src="videos/<cfoutput>#getVideo.URL#</cfoutput>.webmhd.webm" type="video/webm">
Your browser does not support the video tag.
</video>
Javascript:
V I D E O */
function setupVideo(){
if(!myVideo){
console.log("Setting up video");
myVideo=document.getElementById("video1");
timeElapsed = 0;
timer;
myVideo.addEventListener("play",videoStarted,false);
myVideo.addEventListener("pause",videoPaused,false);
myVideo.addEventListener("loadeddata",videoLoaded,false);
console.log(" Video Element is: "+myVideo);
}
else{
console.log("Video Was Already set");
playPause();
}
}
function playPause()
{
if (myVideo.paused)
myVideo.play();
else
myVideo.pause();
}
function videoLoaded(e)
{
console.log(" Video Loaded ");
myVideo.currentTime = 1;
}
function videoStarted(e)
{
console.log("Video Started");
//start the timer
timer = setInterval(videoPlaying,1000);
}
function videoPlaying(){
timeElapsed ++;
console.log("Video Playing "+myVideo.currentTime);
if(Math.ceil(myVideo.currentTime)== 10)
{
console.log(" it reached 10 now display quiz");
playPause();
}
}
function videoPaused(e)
{
clearInterval(timer);
console.log("Pause");
}
Your WebM or OGV video may have negative or invalid timestamps. Some software produces video that starts at a time slightly less than zero, particularly if the audio and video frames are not aligned to start at the same time. (That is, the video may start slightly before 0 and the audio may start at 0.)
If the video is produced with ffmpeg, try using the option -avoid_negative_ts 1.
If you have the mkvtoolnix package installed you can view the timestamps in a webm file with the command mkvinfo -s file.webm.

HTML5 FileReader API in iPhone5 not getting photo from camera

I'm building a mobile website which lets users upload photos from their camera.
I can get images from the users albums, and I can get images when the user takes a photo in iOS6 on iPhone4 and Android 4, but when the user takes a photo with an iPhone5 (also using iOS6), I get nothing. I can get the image from the users photo albums, but not when taking a photo.
here's the code and jsfiddle below
$('input#file_api').change(function(evt){
var image = evt.target.files[0];
var reader = new FileReader();
reader.onerror = (function(){alert('error reading file')});
reader.onload = (function(theFile) {
return function(e) {
// Render thumbnail.
var tempImg = new Image();
tempImg.src = reader.result;
tempImg.onload = function(){
var canvas = document.createElement('canvas');
canvas.width=tempImg.width;
canvas.height=tempImg.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(tempImg,0,0);
$('body').append(canvas);
})(image);
reader.readAsDataURL(image);
I've got an example here http://jsfiddle.net/8DJUy/4/
If you use the file picker to get a photo, it will append the photo to the page.
If you take a photo with an iPhone5, it won't append anything. But at the same time, it doesn't error out either.
Any suggestions on how to get around this?
I can't quite figure out what the problem is with grabbing the photo.
The reason I'm grabbing the photos like this is that the file sizes are quite large when uploaded directly from the phone, and the use case does not require high resolution images, so I'm using the canvas to resize the image before uploading it.
Try this instead:
ctx.drawImage(tempImg, 0, 0, canvas.width, canvas.height);

mediaelement.js multi video gallery flash fallback

Does anyone have a URL of a successful multivideo gallery using mediaelement.js where the same instance of MediaElementPlayer is reused and have it working with the Flash fallback for IE8 & 7?
I have partial success changing the setSrc as a function after the new MediaElementPlayer is created for the first time. This is robust for the HTML5 component but failing for the flash fallback. setSrc is consoling as not available in IE8 & 7. It fails to recognise the object.
Moving the setSrc to the "success" part of the new MediaElementPlayer does load the Flash fallback and HTML5 video as expected. On attempting to change the source of the player I have attempted to "destroy" and recreate the MediaElementPlayer object on the fly without success. I have not declared player using var=player so reasonably have expected to delete it but without success:
player = false;
delete player;
//make a new instance of the mediaelement video player
player = new MediaElementPlayer('#videoPlayer', {
pluginPath: ''+basePath+'_Includes/JS/',
success: function (player, node) {
//set the size (for flash otherwise no video just sound!)
if($("#rg-gallery.smallGallery").length > 0){
player.setVideoSize(400, 225);
} else{
player.setVideoSize(640, 360);
}
player.setSrc([
{ src: mp4, type: 'video/mp4' },
{ src: webm, type: 'video/webm' }
]);
player.load();
player.pause();
//if the video plays stop the slideshow
player.addEventListener('play', function () {
videoPlaying.push('playing');
stopSlideshow();
}, false);
}
});
Research both here and on the web shows that others are attempting to try this type of dynamic gallery but I am unable to find an example that shows it as technically viable.
Any example URLs where someone's cracked it would be lovely. Thanks :)
Solved.
Created a JS variable of video code:
var playerView = '<video width="640" height="360" id="videoPlayer" class="video-js vjs-default-skin" poster="" controls preload="auto"><source id="mp4" type="video/mp4" src="" /><source id="webm" type="video/webm" src="" /></video>';
On initialization removed any DOM rendering of any existing player, set it to false and deleted it:
//remove any existing video player
$(".mejs-container").remove();
player = false;
delete player;
Appended new video view to DOM:
//add a new one
$(".rg-video").append(playerView);
Created new instance of player and set src and load as normal:
//make a new instance of the mediaelement video player
player = new MediaElementPlayer('#videoPlayer', { ...
HTML5 video and Flash video fallback for IE8 & 7 now working as part of dynamic mixed media gallery.
Off for tea and medals.
:)

Resources