HTML5: Play video from stored binary string - javascript

I am trying to read the contents of a video file as a binary string using the FileReader.readAsBinaryString(Blob|File) as shown in the example http://www.html5rocks.com/en/tutorials/file/dndfiles/#toc-reading-files and then store and play the video.
I tried it using the below (with a webm video file),but get a "Video format or MIME type not supported."
function readBlob (file, startByte, endByte, callback) {
console.log('readBlob():', file, startByte, endByte);
var reader = new FileReader();
reader.onloadend = function (evt) {
if (evt.target.readyState == FileReader.DONE) {
callback(evt.target.result);
var player = document.getElementById('player');
player.src = "data:video/webm;base64,"+evt.target.result;
player.load();
player.play();
}
}
var blob = file.slice(startByte, endByte);
reader.readAsBinaryString(blob);
}
Does anyone know if it is possible to read a video file (one supported by the browser being used) as a binary string and play it in the browser HTML5 video player?
TIA

Your problem might be with the player.src
player.src = "data:video/webm;base64,"+evt.target.result;
It is expecting the data to be in base64 but you're giving it a binary string.
Try encoding it to base64 using btoa
player.src = "data:video/webm;base64,"+btoa(evt.target.result);

How about FileReader.readAsDataURL(Blob|File) ?
It is explained in your html5rocks-link as well.

Related

Not able to create seekable video blobs from mediarecorder using EBML.js - MediaRecorder API - Chrome

Using media recorder, I am able to upload and append the video blobs on azure. But combined video is not seekable on download with following code -
var chunks =[];
var mediaRecorder = new MediaRecorder(stream, 'video/x-matroska;codecs=vp8,opus');
mediaRecorder.ondataavailable = function(event) {
if(event.data && event.data.size > 0) {
chunks.push(event.data);
appendBlockToAzure(chunks);
}
};
mediaRecorder.start(10000);
I tried using EBML.js, if I use the following code then I get the seekable video file. This approach needs the file to be processed at the end. Therefore, final file could be of 1GB in size which will take very long time to upload.
var chunks =[];
var mediaRecorder = new MediaRecorder(stream, 'video/x-matroska;codecs=vp8,opus');
mediaRecorder.ondataavailable = function(event) {
if(event.data && event.data.size > 0) {
chunks.push(event.data);
if(mediaRecorder.state == "inactive") { //if media recorder is stopped
var combined = new Blob(chunks, { type: event.data.type });
getSeekableBlob(combined, function (seekableBlob) {
saveCombinedVideoToAzure(seekableBlob);
});
}
}
};
mediaRecorder.start(10000);
That's the reason I want to upload simultaneously to the azure. If I use the following code, then it logs unknown tag warnings and then length error. Also, the video file is not playable.
var seekablechunks =[];
var mediaRecorder = new MediaRecorder(stream, 'video/x-matroska;codecs=vp8,opus');
mediaRecorder.ondataavailable = function(event) {
if(event.data && event.data.size > 0) {
getSeekableBlob(event.data, function (seekableBlob) {
seekablechunks.push(seekableBlob);
saveCombinedVideoToAzure(seekablechunks);
});
}
};
mediaRecorder.start(10000);
Function 'getSeekableBlob':
function getSeekableBlob(inputBlob, callback) {
// EBML.js copyrights goes to: https://github.com/legokichi/ts-ebml
if(typeof EBML === 'undefined') {
throw new Error('Please link: https://www.webrtc- experiment.com/EBML.js');
}
var reader = new EBML.Reader();
var decoder = new EBML.Decoder();
var tools = EBML.tools;
var fileReader = new FileReader();
fileReader.onload = function (e) {
var ebmlElms = decoder.decode(this.result);
ebmlElms.forEach(function (element) {
reader.read(element);
});
reader.stop();
var refinedMetadataBuf = tools.makeMetadataSeekable(reader.metadatas, reader.duration, reader.cues);
var body = this.result.slice(reader.metadataSize);
var newBlob = new Blob([refinedMetadataBuf, body], {
type: 'video/webm'
});
callback(newBlob);
};
fileReader.readAsArrayBuffer(inputBlob);
}
Is there a way to get seekable blobs and upload them to azure?
It's a challenge for an open-ended streaming source for media (for example MediaRecorder) to create a file with SeekHead elements in it. The Seek elements in a SeekHead element contain byte offsets to elements in the file.
MediaRecorder doesn't create segments or SeekHead elements as you have discovered. To do so it would need to be able to see the future to know how big future compressed video and audio elements will be in the file.
A good way for you to handle this problem might be to post-process your uploaded files on a server. You can use ts-ebml to do this in a streaming fashion on a server when a file is completely uploaded.
It's possible, I suppose, to create Javascript software in your browser that can transform the stream of data emitted by MediaRecorder so it's seekable, on the fly. To make your stream seekeable you'd need to insert SeekHead elements every so often. You'd buffer up multiple seconds of the stream, then locate the Cluster elements in each buffer, then write a SeekHead element pointing to some of them. (Chrome's MediaRecorder outputs Clusters beginning with video key frames.) If you succeed in doing this you'll know a lot about Matroska / webm.
Suddenly, our Face on camera web-cam recorder component stopped saving webm blob.
In the console there were warnings about {EBML_ID: "55b0", type: "unknown", ...} during reader.read(element) and then
"Uncaught (in promise) Error: No schema entry found for unknown" in EBMLEncoder.js" at tools.makeMetadataSeekable(...) call.
Ignoring unknown elements from the decoder workarounded the issue:
...
var ebmlElms = decoder.decode(this.result);
ebmlElms.forEach(function (element) {
if (element.type !== 'unknown') {
reader.read(element);
}
});
reader.stop();
...
Related issue on ts-ebml npm package https://github.com/legokichi/ts-ebml/issues/33 with similar workaround

What's the best way to get an audio buffer into a blob that can be played by an audio element?

I have an AudioBuffer stored as a variable, and I would like to have it be played by an Audio element. Here is my current non-functioning code:
const blob = new Blob(audioBuffer.getChannelData(1), { type: "audio/wav" });
const url = window.URL.createObjectURL(blob);
audioElement.src = url;
When I try to play audioElement, I get the following error:
Uncaught (in promise) DOMException: The element has no supported sources.
Does anyone have any ideas on how to solve this? Thanks in advance!
AudioBuffer is PCM data, not encoded as WAV yet. If you need WAV you should get a library to do the encoding for you, such as https://www.npmjs.com/package/audiobuffer-to-wav
After including above code (you can just copy the audioBufferToWav function and the functions it calls below it out of index.js).
const blob = new Blob([audioBufferToWav(audioBuffer.getChannelData(1))], { type: "audio/wav" });
const url = window.URL.createObjectURL(blob);
audioElement.src = url;
Below using Web Audio API to playback the PCM AudioBuffer directly.
var myArrayBuffer = audioBuffer;
var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
var source = audioCtx.createBufferSource();
source.buffer = myArrayBuffer;
source.connect(audioCtx.destination);
source.start();

Converting MediaRecorder audio to base64

I am using the MediaRecorder API to record audio on my page.
I need to convert this audio to base64.
Have a look at this example.
Each time new data is available, it pushes that data to an array, like this:
function handleDataAvailable(event) {
if (event.data && event.data.size > 0) {
recordedBlobs.push(event.data);
}
}
Then, it combines all that data like this:
var superBuffer = new Blob(recordedBlobs, {type: 'video/webm'});
So how would I convert this superBuffer to base64?
You can do this using FileReader Object.
var reader = new window.FileReader();
reader.readAsDataURL(superBuffer);
reader.onloadend = function() {
base64 = reader.result;
base64 = base64.split(',')[1];
console.log(base64 );
}
Answer referred from Convert blob to base64.
Read more about FileReader for better understanding.

Concatenating audio blobs

I tried concatenating audio blobs using Web RTC experiment by Muaz Khan, but when I play the concatenated audio, the HTML audio element does not show the full length of the audio file and also if you download and play, the issue will persist. I used ffmpeg to concate these blobs, though is there a way which can be used for concatenating audio blobs using the Web RTC js experiment by Muaz Khan. A similar attempt which also did not work out : Combine two audio blob recordings
The best way is to convert the blobs into AudioBuffers (Convert blob into ArrayBuffer using FileReader and then decode those arrayBuffers into AudioBuffers). You can then merge/combine more than one AudioBuffers and get the resultant.
Following code will work in such situation:
var blob="YOUR AUDIO BLOB";
var f = new FileReader();
f.onload = function (e) {
audioContext.decodeAudioData(e.target.result, function (buffer) {
arrayBuffer.push(buffer);
if (arrayBuffer.length > 1) {
resultantbuffer = appendBuffer(arrayBuffer[0], arrayBuffer[1]);
arrayBuffer = [];
arrayBuffer.push(resultantbuffer);
}
else {
resultantbuffer = buffer;
}
}, function (e) {
console.warn(e);
});
};
f.readAsArrayBuffer(blob);
This code read the blob and convert into arrayBuffer (e.target.result) and decode those buffers into AudioBuffers (buffer). I used appendBuffer method for appending more than one audioBuffers. Here is the method:
function appendBuffer(buffer1, buffer2) {
///Using AudioBuffer
var numberOfChannels = Math.min(buffer1.numberOfChannels, buffer2.numberOfChannels);
var tmp = recordingAudioContext.createBuffer(numberOfChannels, (buffer1.length + buffer2.length), buffer1.sampleRate);
for (var i = 0; i < numberOfChannels; i++) {
var channel = tmp.getChannelData(i);
channel.set(buffer1.getChannelData(i), 0);
channel.set(buffer2.getChannelData(i), buffer1.length);
}
return tmp;
}
Do let me know if you face any problem.

Decode Base 64 audio file Mp3 into playable Mp3

I am converting the audio MP3 file and storing it as base64 in database using WEB API, now I am fetching the base64 file using ajax and I am getting the base64, the problem is how can I convert the base64 file back to mp3 file and play it using JavaScript.
This if for demo I am using input file, I am getting base64 file from server
<input type='file' onchange='openFile(event)' id="EdituserProfileImage">
var fileName;
var filetype;
var filesize;
var VoiceBase64;
var openFile = function (event) {
var input = event.target;
fileName = input.files[0].name;
filetype = input.files[0].type;
filesize = input.files[0].size;
console.log(input);
console.log(fileName);
var reader = new FileReader();
reader.onload = function (evt) {
var voiceInBinay = evt.target.result;
VoiceBase64 = btoa(voiceInBinay);
contvertBase64toBinaray(VoiceBase64);
};
reader.readAsBinaryString(input.files[0]);
};
This function "contvertBase64toBinaray" using for converting base64 to Binary, I have binary file, need to save as mp3 from this below binary
function contvertBase64toBinaray(VoiceBase64) {
var audiofile = atob(VoiceBase64)
};
Use window.atob function to decode your base 64 data.
This question shows you how you can play the mp3 in JS.

Categories

Resources