Decode a base64 video blob with JavaScript - javascript

I've made a video encoder that gives output in base64 encoded video.
A video player needs to play the video in the browser.
My current code doesn't works, I tried it also with responseText and not with the response as a blob.
So the server gets the video and processes it as a base64 string.
Then the browser needs to decode it and view it as a video, how can I get this done?
My code:
decodeBase64 = function(s) {
var e={},i,b=0,c,x,l=0,a,r='',w=String.fromCharCode,L=s.length;
var A="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
for(i=0;i<64;i++){e[A.charAt(i)]=i;}
for(x=0;x<L;x++){
c=e[s.charAt(x)];b=(b<<6)+c;l+=6;
while(l>=8){((a=(b>>>(l-=8))&0xff)||(x<(L-2)))&&(r+=w(a));}
}
return r;
};
var xhr = new XMLHttpRequest();
xhr.open("GET", "video");
xhr.responseType = "blob";
xhr.onload = response;
xhr.send();
function response(e) {
var URL = window.URL || window.webkitURL;
var videoUrl = URL.createObjectURL(decodeBase64(this.response));
document.querySelector("video").src = videoUrl;
}

Compare output of decodeBase64 with that of (built-in) btoa.

Related

How to combine a video with an audio in javascript?

I am coding youtube video downloader chrome extension. But youtube has separated mp4 and mp3. How can I combine the audio file and image file I received in blob type and turn it into a video with sound?
async function downloadFile(urlToSend) {
return new Promise(resolve => {
var req = new XMLHttpRequest();
req.open("GET", urlToSend, true);
req.responseType = "blob";
req.onload = function (event) {
// var blob = req.response;
// var fileName = req.getResponseHeader("fileName") //if you have the fileName header available
// var link = document.createElement('a');
// link.href = window.URL.createObjectURL(blob);
resolve(req.response)
};
req.send();
})
};
async function zfc() {
var v = await downloadFile('/videoplayback.mp4')
var a = await downloadFile('/videoplayback.weba')
let newBlob = new Blob([v, a], { type: 'video/mp4' })
var as = document.createElement('a')
as.href = window.URL.createObjectURL(newBlob)
as.download = window.URL.createObjectURL(newBlob)
console.log(as)
console.log(newBlob)
// as.click()
var c = document.createElement('video')
c.src = window.URL.createObjectURL(newBlob)
document.body.appendChild(c)
}
zfc()
I tried merging with new blob but the video still has no sound. Can you please help?
Example video link:
https://rr7---sn-u0g3uxax3-xncs.googlevideo.com/videoplayback?expire=1641956798&ei=XvHdYbG8MI2qx_AP14yRoAQ&ip=95.2.13.77&id=o-APHbyEMFJZdr7FwyLDOkQWqycmDmo9oy8bSvx7qP4z-P&itag=313&aitags=133%2C134%2C135%2C136%2C137%2C160%2C242%2C243%2C244%2C247%2C248%2C271%2C278%2C313&source=youtube&requiressl=yes&mh=YY&mm=31%2C29&mn=sn-u0g3uxax3-xncs%2Csn-hgn7yn76&ms=au%2Crdu&mv=m&mvi=7&pl=21&initcwndbps=88750&vprv=1&mime=video%2Fwebm&ns=O-4SxebNzTxani0g_ScQEtMG&gir=yes&clen=589586219&dur=347.800&lmt=1638064072881015&mt=1641934876&fvip=2&keepalive=yes&fexp=24001373%2C24007246&c=WEB&txp=4532434&n=hBnxjZJEX82hOJ&sparams=expire%2Cei%2Cip%2Cid%2Caitags%2Csource%2Crequiressl%2Cvprv%2Cmime%2Cns%2Cgir%2Cclen%2Cdur%2Clmt&sig=AOq0QJ8wRQIhAIu0SR_UsiQyUpJIkL_erKc_dElHk-1rwJMCI1486YaSAiBkH4jg8WHzRvEDsxnTTheBM_f1KsBFzqLiIUFJAIKh5w%3D%3D&lsparams=mh%2Cmm%2Cmn%2Cms%2Cmv%2Cmvi%2Cpl%2Cinitcwndbps&lsig=AG3C_xAwRAIgapuFt6YijG3nAVfbULkJq2_uAwcjOnZpd0ZNUo1h5NMCIGgJh22ksRMeMOUkhhQUlRapjqa4DhVv-KfcfnYhkW8l
Example sound link:
https://rr7---sn-u0g3uxax3-xncs.googlevideo.com/videoplayback?expire=1641956798&ei=XvHdYbG8MI2qx_AP14yRoAQ&ip=95.2.13.77&id=o-APHbyEMFJZdr7FwyLDOkQWqycmDmo9oy8bSvx7qP4z-P&itag=251&source=youtube&requiressl=yes&mh=YY&mm=31%2C29&mn=sn-u0g3uxax3-xncs%2Csn-hgn7yn76&ms=au%2Crdu&mv=m&mvi=7&pl=21&initcwndbps=88750&vprv=1&mime=audio%2Fwebm&ns=O-4SxebNzTxani0g_ScQEtMG&gir=yes&clen=5822955&dur=347.821&lmt=1638059244799001&mt=1641934876&fvip=2&keepalive=yes&fexp=24001373%2C24007246&c=WEB&txp=4532434&n=hBnxjZJEX82hOJ&sparams=expire%2Cei%2Cip%2Cid%2Citag%2Csource%2Crequiressl%2Cvprv%2Cmime%2Cns%2Cgir%2Cclen%2Cdur%2Clmt&sig=AOq0QJ8wRQIgaqKAjgRHlNms4IMVKwGJmRb2DOl7slWujc2OeIqIlSkCIQDvVhAPmxgLg0g2WvrgjB0iNNnCyDbyRQQvu5ODx4PLXA%3D%3D&lsparams=mh%2Cmm%2Cmn%2Cms%2Cmv%2Cmvi%2Cpl%2Cinitcwndbps&lsig=AG3C_xAwRAIgapuFt6YijG3nAVfbULkJq2_uAwcjOnZpd0ZNUo1h5NMCIGgJh22ksRMeMOUkhhQUlRapjqa4DhVv-KfcfnYhkW8l
I am also currently working on a YouTube video downloader extension for Firefox. If you are using ytdl-core, the response object contains a link that has both in res.player_response.streaming_data.formats[0]. However, there is only one such link, which doesn't allow for users to select their preferred resolution, so being able to merge the two would be extremely helpful.
Also if you are using youtube-dl or anything similar to such the response object should be the same or very similar to ytdl-core's

ArrayBuffer to jpeg

I am streaming ArrayBuffers from a python server and am trying to interpret each one as an image on the client side with javascript. They are being received as arraybuffers in javascript. However I cant get them to be readable by the image tags src attribute. I have tried generating them into Blob objects then using window.URL.createObjectURL(blob). That hasnt work either.
The blob url looks like this blob:null/e2836074-64b5-4959-8211-da2fc24c35a6 is that wrong?
Does any have any suggestions/know a solution.
Thanks a lot.
var arrayBuffer = new Uint8Array(stream.data);
var blob = new Blob([arrayBuffer], {type: "image/jpeg"});
var urlCreator = window.URL || window.webkitURL;
var imageUrl = urlCreator.createObjectURL( blob );
console.log(imageUrl);
img.src = imageUrl;
array buffer image
If you have any control over things, you should use the responseType of blob on your Javascript call. This will let you use the data you are getting from your server directly instead of attempting to access it via an ArrayBuffer
See the following fiddle for an example: https://jsfiddle.net/ort74gmp/
// Simulate a call to Dropbox or other service that can
// return an image as a blob
var xhr = new XMLHttpRequest();
// Use JSFiddle logo as a sample image to avoid complicating
// this example with cross-domain issues.
xhr.open( "GET", "https://fiddle.jshell.net/img/logo.png", true );
// Ask for the result as an ArrayBuffer.
xhr.responseType = "blob";
xhr.onload = function( e ) {
var blob = this.response;
var reader = new FileReader();
reader.onload = function() {
var dataURL = reader.result;
document.querySelector('#photo').src = dataURL;
}
reader.readAsDataURL(blob);
};
xhr.send();

Trim an audio file using javascript (first 3 seconds)

I have a question that can I trim my audio file that is recorded via javascript? Like I want to trim the first 3 seconds. I recorded the audio file using p5.js and merged the recorded file with karaoke audio with AudioContext() and I want to trim it because of an unpleasant sound at the start.
You will probably need to read the audio into an AudioBuffer using something like AudioContext.decodeAudioData(), plug the AudioBuffer into a AudioBufferSourceNode. Then you can skip the first 3 seconds using the offset parameter of AudioBufferSourceNode.start() and record the resulting output stream.
Example code:
var source = audioCtx.createBufferSource();
var dest = audioCtx.createMediaStreamDestination();
var mediaRecorder = new MediaRecorder(dest.stream);
var request = new XMLHttpRequest();
request.open('GET', 'your.ogg', true);
request.responseType = 'arraybuffer';
request.onload = function() {
var audioData = request.response;
audioCtx.decodeAudioData(
audioData,
function(buffer) {
source.buffer = buffer;
source.connect(dest);
mediaRecorder.start();
source.start(audioCtx.currentTime, 3);
// etc...
},
function(e){
console.log("Error with decoding audio data" + e.err);
}
);
}
request.send();

Blob image from database to Java and from Java to Javascript Image

I have Blob, which stored in db and i take it from database with java server like this:
Entity.java
#Column(name = "img")
private Blob img;
public Blob getImg() {
return img;
}
public void setImg(Blob img) {
this.img = img;
}
Repository.java
#Transactional
#Query(value = "SELECT img FROM articles WHERE category = ?", nativeQuery = true)
//Blob findP(String category);
Blob findPic(String category);
Controller.java
#RequestMapping(value="/Pic_test")
#ResponseBody
public Blob getPics() throws SQLException, IOException {
return remindRepository.findPic("Java");
}
Then I receive it with Javascript to image it:
function toDataURL(url, callback) {
var xhr = new XMLHttpRequest();
xhr.onload = function() {
var reader = new FileReader();
reader.onloadend = function() {
callback(reader.result);
}
reader.readAsDataURL(xhr.response);
};
xhr.open('GET', url);
xhr.responseType = 'blob';
xhr.send();
}
toDataURL('http://localhost:8080/articles/Pic_test', function(dataUrl) {
var display = document.getElementById('display');
var url = window.URL.createObjectURL(new Blob([dataUrl]));
var img = new Image();
img.src = url;
document.getElementById("demo").innerHTML = img.src;
})
However, if I call my "img" Blob in java code, i have an error in server, but if I call it byte[], my picture is not shown just.
I can't comment the java part since I know nothing about it, but for the javascript one, what you do is... not correct.
You don't seem to understand what is a data URL, nor what you are doing here.
So a data URL is a string, made of an header and of some file content (data:|mime/type;|file-content).
A data URL is an URL that points to itself, useful to embed data that should normally be served from network.
Quite often, the file content part is encoded as base64, because the URI scheme is limited in its set of allowed characters, and that binary data couldn't be represented in this scheme.
Now let's see what you are doing here...
You are downloading a resource as a Blob. That's good, Blob are perfect objects to deal with binary data.
Then, you read this Blob a data URL. Less good, but I can see the logic, <img> can indeed load images from data URLs.
But then from this data URL string, you create a new Blob! This is completely wrong. The Blob you just created with new Blob([dataUrl]) is a text file, not your image file in any way. So yes, the data is still hidden somewhere in the base64 data which is itself in the data URL, but what your poor <img> will see when accessing the data hooked by the Blob URI is really just text, data:image/png;base64,iVBORw0... and not at all �PNG... like its parsing algo can read.
So the solution is quite easy: get rid of the FileReader step. You don't need it.
var xhr = new XMLHttpRequest();
xhr.open('get', 'https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png');
xhr.responseType = 'blob';
xhr.onload = display;
xhr.send();
function display(evt) {
// we did set xhr.responseType = "blob"
var blob = evt.target.response; // so this is a Blob
// hence, no need for anything else than
var url = URL.createObjectURL(blob);
var img = new Image();
img.src = url;
document.body.appendChild(img);
}
And if I may, all your thing could also just be
document.getElementById('display').src = 'http://localhost:8080/articles/Pic_test';

Generate a blob with grunt which will be available to JS in var

I need to embed a Flash .swf on the page and am unable use the normal way of setting the src or data attribute to the swf url - don't ask :s. So, I'm doing an ajax request for the swf, converting to a blob and then generating a blob url which I set as the swf src. Then I realised that as I'm building with Grunt, there may be a way to just write the swf file into the code as a blob in a var, and avoid the ajax request completely. Here's the code with the ajax request:
function createFlashMovie(blobUrl){
var obj = document.createElement("object");
obj.setAttribute("width", "800");
obj.setAttribute("height", "600");
obj.setAttribute("type", "application/x-shockwave-flash");
obj.setAttribute("data", blobUrl);
document.body.appendChild(obj);
}
function onAjaxLoad(oResponse){
blobUrl = window.URL.createObjectURL(oResponse);
createFlashMovie(blobUrl);
};
//do the xhr request for a.swf
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if (this.readyState == 4 && this.status == 200){
onAjaxLoad(this.response);
}
}
xhr.open('GET', '//theserver.com/a.swf');
xhr.responseType = 'blob';
xhr.send();
...but I'm sure it must be possible to have something like this which is replaced by grunt to have the blob already available when it runs, and go straight to creating the blob url without the xhr request:
var theBlob = new Blob(["GRUNT_WRITES_THIS_IN_FROM_FILE"], {type: "application/x-shockwave-flash"});
Well, grunt is at its core just a Node program, so you can use any node command in your Gruntfile or tasks definitions. And it seems that Node's http.request would be perfect for your needs.
So:
add a custom task in your Gruntfile (http://gruntjs.com/creating-tasks#custom-tasks)
that uses http.request to download your swf (https://docs.nodejitsu.com/articles/HTTP/clients/how-to-create-a-HTTP-request)
update your code to use the local swf
I found a solution. Convert your swf file to be a base64-encoded string. At the moment I'm doing this separately and then pasting it into the source JS, but it can be automated at build time with grunt. Then in the page script create a var to store it as a dataURI:
var swfAsDataUri = "data:application/x-shockwave-flash;base64,BIG_LONG_CHUNK_OF_DATA_THAT_IS_YOUR_ENCODED_SWF_FILE__GRUNT_CAN_WRITE_THIS_IN_AT_BUILD_TIME";
Create a blob from the data url, and then create an object url from the blob:
//function taken from http://stackoverflow.com/questions/27159179/how-to-convert-blob-to-file-in-javascript
dataURLToBlob = function(dataURL) {
var BASE64_MARKER = ';base64,';
var parts = dataURL.split(BASE64_MARKER);
var contentType = parts[0].split(':')[1];
var raw = window.atob(parts[1]);
var rawLength = raw.length;
var uInt8Array = new Uint8Array(rawLength);
for (var i = 0; i < rawLength; ++i) {
uInt8Array[i] = raw.charCodeAt(i);
}
return new Blob([uInt8Array], {type: contentType});
};
var blobUrl = window.URL.createObjectURL( dataURLToBlob(swfAsDataUri) );
You can then use the object url as the src data for the flash movie's object tag when it's embedded:
function createFlashMovie(blobUrl){
var obj = document.createElement("object");
obj.setAttribute("width", "800");
obj.setAttribute("height", "600");
obj.setAttribute("type", "application/x-shockwave-flash");
obj.setAttribute("data", blobUrl); //use the object url here
document.body.appendChild(obj);
}
...and there you have it, no additional http request for the swf file.

Categories

Resources