I have got some script that gets an image from the first frame of a video and returns a base64image encoding.
I am then posting this image to the server back end to be saved to the uploads directory..
It works fine on chrome on a desktop, but when I test on iPhone7 IOS10 Safari it does not work.
I have tried to use both blobs and base64image but none work on iOS and both do work on chrome desktop.
Here is the javascript I'm currently using to get the image..
$('#upload').bind('change', function(event) {
console.log("input");
var file = event.target.files[0];
var fileReader = new FileReader();
if (file.type.match('image')) {
fileReader.onload = function() {
var img = document.createElement('img');
img.src = fileReader.result;
document.getElementsByTagName('div')[0].appendChild(img);
};
fileReader.readAsDataURL(file);
} else {
fileReader.onload = function() {
var blob = new Blob([fileReader.result], {type: file.type});
var url = URL.createObjectURL(blob);
var video = document.createElement('video');
var timeupdate = function() {
if (snapImage()) {
video.removeEventListener('timeupdate', timeupdate);
video.pause();
}
};
video.addEventListener('loadeddata', function() {
if (snapImage()) {
video.removeEventListener('timeupdate', timeupdate);
}
});
var snapImage = function() {
var canvas = document.createElement('canvas');
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height);
var image = canvas.toDataURL(); // Base64Image source
var success = image.length > 100000;
if (success) {
var img = document.createElement('img');
img.src = image;
document.getElementsByTagName('div')[0].appendChild(img);
URL.revokeObjectURL(url);
$.ajax({
url : "uploadApi.php",
type: "POST",
data : {"videoThumb" : image},
success: function(data)
{
alert(data);
},
error: function (data)
{
alert(data);
}
});
console.info("image");
$('#b64image').val(image);
}
return success;
};
video.addEventListener('timeupdate', timeupdate);
video.preload = 'metadata';
video.src = url;
// Load video in Safari / IE11
video.muted = true;
video.playsInline = true;
video.play();
};
fileReader.readAsArrayBuffer(file);
}
});
uploadApi.php
var_dump($_POST["videoThumb"];
$data = $_POST["videoThumb"];
$videoId = 1;
list($type, $data) = explode(';', $data);
list(, $data) = explode(',', $data);
$data = base64_decode($data);
$fileDirSrc = "../thumbs/"vid_".$videoId."_videoThumb.png";
$fileDirSrcNoTrailingDots = "vid_".$videoId."_videoThumb.png";
file_put_contents($fileDirSrc, $data);
Wierdly, the ajax response returns the dump of the base64image in an alert when on the desktop. But on iOS safari it returns [object Object]
You can try upload a video to his js fiddle, get an mp4 video file from http://techslides.com/sample-webm-ogg-and-mp4-video-files-for-html5 first.
https://jsfiddle.net/jvftb0gt/2/
Related
i have problem with dropzone js when loading Uploaded video from server .
dropzone load picture thumbnails but video thumbnail not loaded .
check it from this link
i want to load videos from ajax request . this is my code :
this.on("error", function(file, response) {
$(file.previewElement).find('.dz-error-message').tooltip().attr('data-original-title',response);
});
$.ajax({
url: 'https://localhost/asnaf2019/userpanel/uploader.php',
type: 'post',
data: {request: 2},
dataType: 'json',
success: function(response){
$.each(response, function(key,value) {
var mockFile = { name: value.name };
myDropzone_video.emit("addedfile", mockFile);
myDropzone_video.emit("thumbnail", mockFile, value.path);
myDropzone_video.emit("complete", mockFile);
});
}
});
this.on('addedfile', function(origFile) {
var fileReader = new FileReader();
fileReader.addEventListener("load", function(event) {
var origFileIndex = myDropzone_video.files.indexOf(origFile);
myDropzone_video.files[origFileIndex].status = Dropzone.ADDED;
var blob = new Blob([fileReader.result], {type: origFile.type});
var url = URL.createObjectURL(blob);
var video = document.createElement('video');
var timeupdate = function() {
if (snapImage()) {
video.removeEventListener('timeupdate', timeupdate);
video.pause();
}
};
video.addEventListener('loadeddata', function() {
if (snapImage()) {
video.removeEventListener('timeupdate', timeupdate);
}
});
if (!origFile.type.match(/mp4|MP4/)) {
myDropzone_video.enqueueFile(origFile);
myDropzone_video.removeFile(origFile);
return;
}
var snapImage = function() {
var canvas = document.createElement('canvas');
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height);
var arrText = new Array();
var image = canvas.toDataURL();
var success = image.length > 100000;
if (success) {
var img = document.getElementsByClassName('img-preview');
var l = img.length;
$.each(img,function(){
arrText.push(image);
});
for(var i=0; i < l; i++){
var t = img[i];
myDropzone_video.emit("thumbnail", origFile, arrText[i]);
}
URL.revokeObjectURL(url);
}
return success;
};
video.addEventListener('timeupdate', timeupdate);
video.preload = 'metadata';
video.src = url;
video.muted = true;
video.playsInline = true;
video.play();
});
fileReader.readAsArrayBuffer(origFile);
});
this error shown when code run :
TypeError: Argument 1 of FileReader.readAsArrayBuffer does not
implement interface Blob.
how i can fix this problem
I used this way for the problem
$.each(response, function(key,value) {
var mockFile = { name: value.name};
if (value.type.match(/mp4|MP4/)){ // Preview video only from type mp4
myDropzone_video.options.addedfile.call(myDropzone_video, mockFile);
var src = value.path;
var video = document.createElement('video');
video.src = src;
video.addEventListener('loadeddata', function() {
var canvas = document.createElement('canvas');
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height);
var dataURI = canvas.toDataURL('image/png');
myDropzone_video.emit("thumbnail", mockFile, dataURI);
});
myDropzone_video.emit("complete", mockFile);
}
});
I have solved ,this problem in this way.
i have written this function to capture each frame for the GIF but the output is very laggy and crashes when the data increases. Any suggestions ?
Code :
function createGifFromPng(list, framerate, fileName, gifScale) {
gifshot.createGIF({
'images': list,
'gifWidth': wWidth * gifScale,
'gifHeight': wHeight * gifScale,
'interval': 1 / framerate,
}, function(obj) {
if (!obj.error) {
var image = obj.image;
var a = document.createElement('a');
document.body.append(a);
a.download = fileName;
a.href = image;
a.click();
a.remove();
}
});
}
/////////////////////////////////////////////////////////////////////////
function getGifFromCanvas(renderer, sprite, fileName, gifScale, framesCount, framerate) {
var listImgs = [];
var saving = false;
var interval = setInterval(function() {
renderer.extract.canvas(sprite).toBlob(function(b) {
if (listImgs.length >= framesCount) {
clearInterval(interval);
if (!saving) {
createGifFromPng(listImgs, framerate, fileName,gifScale);
saving = true;
}
}
else {
listImgs.push(URL.createObjectURL(b));
}
}, 'image/gif');
}, 1000 / framerate);
}
In modern browsers you can use a conjunction of the MediaRecorder API and the HTMLCanvasElement.captureStream method.
The MediaRecorder API will be able to encode a MediaStream in a video or audio media file on the fly, resulting in far less memory needed than when you grab still images.
const ctx = canvas.getContext('2d');
var x = 0;
anim();
startRecording();
function startRecording() {
const chunks = []; // here we will store our recorded media chunks (Blobs)
const stream = canvas.captureStream(); // grab our canvas MediaStream
const rec = new MediaRecorder(stream); // init the recorder
// every time the recorder has new data, we will store it in our array
rec.ondataavailable = e => chunks.push(e.data);
// only when the recorder stops, we construct a complete Blob from all the chunks
rec.onstop = e => exportVid(new Blob(chunks, {type: 'video/webm'}));
rec.start();
setTimeout(()=>rec.stop(), 3000); // stop recording in 3s
}
function exportVid(blob) {
const vid = document.createElement('video');
vid.src = URL.createObjectURL(blob);
vid.controls = true;
document.body.appendChild(vid);
const a = document.createElement('a');
a.download = 'myvid.webm';
a.href = vid.src;
a.textContent = 'download the video';
document.body.appendChild(a);
}
function anim(){
x = (x + 1) % canvas.width;
ctx.fillStyle = 'white';
ctx.fillRect(0,0,canvas.width,canvas.height);
ctx.fillStyle = 'black';
ctx.fillRect(x - 20, 0, 40, 40);
requestAnimationFrame(anim);
}
<canvas id="canvas"></canvas>
You can also use https://github.com/spite/ccapture.js/ to capture to gif or video.
I am developing a web application in which application downloads the encrypted chunks of data. And after then I have to decrypt and play the video. But I cannot let the user to wait for all decryption. Hence I am using Media Stream API. It is working. But I am getting this error after decryption of last chunk.
"Uncaught DOMException: Failed to execute 'addSourceBuffer' on 'MediaSource': This MediaSource has reached the limit of SourceBuffer objects it can handle. No additional SourceBuffer objects may be added.(…)"
<script type="text/javascript">
//////////
var no_of_files = 0;
var no_of_dlfiles = 0;
var FilesURL = [];
var files_str = 'video/vid_1.webm, video/vid_2.webm, video/vid_3.webm, video/vid_4.webm, video/vid_5.webm';
var file_counter = 0;
var mimeCodec = 'video/webm; codecs="vorbis,vp8"';
var passkey = "014bcbc0e15c4fc68b098f9b16f62bb7shahbaz.hansinfotech#gmail.com";
FilesURL = files_str.split(',');
no_of_files = FilesURL.length;
var player = document.getElementById('videoplayer');
if ('MediaSource' in window && MediaSource.isTypeSupported(mimeCodec)) {
var mediaSource = new MediaSource;
//console.log(mediaSource.readyState); // closed
player.src = URL.createObjectURL(mediaSource);
mediaSource.addEventListener('sourceopen', sourceOpen);
} else {
console.error('Unsupported MIME type or codec: ', mimeCodec);
}
//////////
function sourceOpen (_) {
console.log("start");
var mediaSource = this;
var sourceBuffer = mediaSource.addSourceBuffer(mimeCodec);
sourceBuffer.mode = "sequence";
function WriteDatatoTemp()
{
//console.log(this.readyState); // open
if(file_counter<FilesURL.length)
{
console.log(file_counter);
no_of_dlfiles++;
$("#decryptionRatio").text(no_of_dlfiles+" of "+no_of_files);
$("#decryption_status").show();
getFileObject(FilesURL[file_counter], function (fileObject) {
//
var outputFile = fileObject;
var reader = new FileReader();
reader.onloadend = function(e){
var decrypted_data = JSON.parse(CryptoJS.AES.decrypt(e.target.result, passkey, {format: CryptoJSAesJson}).toString(CryptoJS.enc.Utf8));
var byteArray = Base64Binary.decodeArrayBuffer(decrypted_data);
sourceBuffer.addEventListener('updateend', function(){
file_counter++;
// console.log(file_counter);
if(player.paused)
{
player.play();
}
if(file_counter == FilesURL.length - 1)
{
mediaSource.endOfStream();
}
WriteDatatoTemp();
});
try
{
while(!sourceBuffer.updating)
{
sourceBuffer.appendBuffer(byteArray);
}
}
catch(e)
{
console.log(e);
}
};
reader.readAsText(outputFile);
//
});
}
}
WriteDatatoTemp();
}
///
var getFileBlob = function (url, cb) {
var xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.responseType = "blob";
xhr.addEventListener('load', function() {
cb(xhr.response);
});
xhr.send();
};
var blobToFile = function (blob, name) {
blob.lastModifiedDate = new Date();
blob.name = name;
return blob;
};
var getFileObject = function(filePathOrUrl, cb) {
getFileBlob(filePathOrUrl, function (blob) {
cb(blobToFile(blob, 'vid.webm'));
});
};
</script>
I have an file input that i used to get a file and turn it into a blob. Is there anyway I can get an external image url and turn that into a blob? Here is the code I am using to do it with just a file from a <input type="file" />:
//Process the file and resize it.
function processfile(file) {
if (!(/image/i).test(file.type)) {
alert("File " + file.name + " is not an image.");
return false;
}
// read the files
var reader = new FileReader();
reader.readAsArrayBuffer(file);
reader.onload = function (event) {
// blob stuff
var blob = new Blob([event.target.result]); // create blob...
window.URL = window.URL || window.webkitURL;
var blobURL = window.URL.createObjectURL(blob); // and get it's URL
// helper Image object
var image = new Image();
image.src = blobURL;
image.onload = function () {
for (var x = 0; x < self.ThumbSizes.length; x++) {
// have to wait till it's loaded
var resized = resizeMe(image, self.ThumbSizes[x]); // send it to canvas
var resized_blob = dataURItoBlob(resized);
uploadFile(resized_blob, self.ThumbSizes[x].Name);
}
}
};
Instead of passing a file through I wanted to be able to structure this code to pass a image url and convert it into a blob.
I hope it helps you. (I didn't run it.)
function processfile(imageURL) {
var image = new Image();
var onload = function () {
var canvas = document.createElement("canvas");
canvas.width =this.width;
canvas.height =this.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(this, 0, 0);
canvas.toBlob(function(blob) {
// do stuff with blob
});
};
image.onload = onload;
image.src = imageURL;
}
I'm saving pictures in my application using the camera feature of Phonegap. When I try to get the file through its saved file_URI (that I got from the camera), the image doesn't load.
function toBase64(url) {
var canvas = document.createElement("canvas");
var ctx = canvas.getContext('2d');
var img = new Image();
img.src = url;
if ( img.height != 0 ) {
var height = img.height, width = img.width;
canvas.height = height;
canvas.width = width;
ctx.drawImage(img, 0, 0, width, height);
try {
var dataURL = canvas.toDataURL("image/jpg");
return dataURL.replace(/^data:image\/(png|jpg);base64,/, "");
}
catch (err) { console.log("ERROR " + err);}
}
else {
alert("Wrong path!");
}
}
The images are saved in the cache folder of the application (/data/data/my.app/cache)
Any ideas of where the problem could be from ?
I fixed this issue and had to use the FileReader object of Phonegap.
var base64;
function toBase64(filename) {
window.requestFileSystem(LocalFileSystem.TEMPORARY, 0, function(fileSystem) {
// Filesystem's root is the cache folder of the application: /storage/emulated/0/Android/data/com.yourcompany.whatever
fileSystem.root.getFile(filename, null, function(fileEntry) {
fileEntry.file(function(file) {
var reader = new FileReader();
reader.onloadend = function(evt) {
console.log(evt.target.result);
// Firing callback
base64 = evt.target.result;
};
reader.readAsDataURL(file);
}, fail);
}, fail);
}, fail);
// We wait until the reader was fully loaded and then we return the base64 encrypted data !
while ( base64 == "" ) {}
base64 = base64.replace(/^data:image\/(png|jpg|jpeg);base64,/, "");
return base64;
}
Don't think that the "while(base64 == "" ) {}" is a good practice though...
EDIT: I used the do_when method of this gentleman instead of the empty loop !